diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-01 12:11:39 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-01 12:11:39 -0700 |
commit | def7cb8cd4e3258db88050eaaca5438bcc3dafca (patch) | |
tree | 23fcf90ddc98acec07bb115c2f7740c21cf44a84 | |
parent | 06d2fe153b9b35e57221e35831a26918f462db68 (diff) | |
parent | e1878957b4676a17cf398f7f5723b365e9a2ca48 (diff) |
Merge tag 'staging-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging
Pull staging tree update from Greg Kroah-Hartman:
"Here is the big staging tree update for the 3.7-rc1 merge window.
There are a few patches in here that are outside of the staging area,
namely HID and IIO patches, but all of them have been acked by the
relevant subsystem maintainers. The IIO stuff is still coming in
through this tree as it hasn't entirely moved out of the staging tree,
but is almost there.
Other than that, there wa a ton of work on the comedi drivers to make
them more readable and the correct style. Doing that removed a lot of
code, but we added a new driver to the staging tree, so we didn't end
up with a net reduction this time around:
662 files changed, 51649 insertions(+), 26582 deletions(-)
All of these patches have been in the linux-next tree already.
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>"
* tag 'staging-3.6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (1094 commits)
staging: comedi: jr3_pci: fix iomem dereference
staging: comedi: drivers: use comedi_fc.h cmdtest helpers
Staging: winbond: usb_free_urb(NULL) is safe
Staging: winbond: checkpatch cleanup
Staging: winbond: Removed undesired spaces, lines and tabs
Staging: winbond: Typo corrections in comments
Staging: winbond: Changed c99 comments to c89 comments
staging: r8712u: Do not queue cloned skb
staging: comedi: ni_mio_common: always lock in ni_ai_poll()
staging: comedi: s626: add FIXME comment
staging: comedi: s626: don't dereference insn->data
staging: comedi: s526: fix if() check in s526_gpct_winsn()
staging: comedi: s626: cleanup comments in s626_initialize()
staging: comedi: s626: remove clear of kzalloc'ed data
staging: comedi: s626: remove 'WDInterval' from private data
staging: comedi: s626: remove 'ChargeEnabled' from private data
staging: comedi: s626: remove 'IsBoardRevA' comment
staging: comedi: s626: #if 0 out the "SAA7146 BUG WORKAROUND"
staging: comedi: s626: remove 'allocatedBuf' from private data
staging: comedi: s626: add final attach message
...
662 files changed, 51589 insertions, 26522 deletions
diff --git a/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt new file mode 100644 index 000000000000..801d58cb6d4d --- /dev/null +++ b/Documentation/devicetree/bindings/staging/iio/adc/mxs-lradc.txt @@ -0,0 +1,15 @@ +* Freescale i.MX28 LRADC device driver + +Required properties: +- compatible: Should be "fsl,imx28-lradc" +- reg: Address and length of the register set for the device +- interrupts: Should contain the LRADC interrupts + +Examples: + + lradc@80050000 { + compatible = "fsl,imx28-lradc"; + reg = <0x80050000 0x2000>; + interrupts = <10 14 15 16 17 18 19 + 20 21 22 23 24 25>; + }; diff --git a/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt new file mode 100644 index 000000000000..07654f0338b6 --- /dev/null +++ b/Documentation/devicetree/bindings/staging/imx-drm/fsl-imx-drm.txt @@ -0,0 +1,41 @@ +Freescale i.MX IPUv3 +==================== + +Required properties: +- compatible: Should be "fsl,<chip>-ipu" +- reg: should be register base and length as documented in the + datasheet +- interrupts: Should contain sync interrupt and error interrupt, + in this order. +- #crtc-cells: 1, See below + +example: + +ipu: ipu@18000000 { + #crtc-cells = <1>; + compatible = "fsl,imx53-ipu"; + reg = <0x18000000 0x080000000>; + interrupts = <11 10>; +}; + +Parallel display support +======================== + +Required properties: +- compatible: Should be "fsl,imx-parallel-display" +- crtc: the crtc this display is connected to, see below +Optional properties: +- interface_pix_fmt: How this display is connected to the + crtc. Currently supported types: "rgb24", "rgb565" +- edid: verbatim EDID data block describing attached display. +- ddc: phandle describing the i2c bus handling the display data + channel + +example: + +display@di0 { + compatible = "fsl,imx-parallel-display"; + edid = [edid-data]; + crtc = <&ipu 0>; + interface-pix-fmt = "rgb24"; +}; diff --git a/Documentation/hid/hid-sensor.txt b/Documentation/hid/hid-sensor.txt new file mode 100755 index 000000000000..948b0989c433 --- /dev/null +++ b/Documentation/hid/hid-sensor.txt @@ -0,0 +1,140 @@ + +HID Sensors Framework +====================== +HID sensor framework provides necessary interfaces to implement sensor drivers, +which are connected to a sensor hub. The sensor hub is a HID device and it provides +a report descriptor conforming to HID 1.12 sensor usage tables. + +Description from the HID 1.12 "HID Sensor Usages" specification: +"Standardization of HID usages for sensors would allow (but not require) sensor +hardware vendors to provide a consistent Plug And Play interface at the USB boundary, +thereby enabling some operating systems to incorporate common device drivers that +could be reused between vendors, alleviating any need for the vendors to provide +the drivers themselves." + +This specification describes many usage IDs, which describe the type of sensor +and also the individual data fields. Each sensor can have variable number of +data fields. The length and order is specified in the report descriptor. For +example a part of report descriptor can look like: + + INPUT(1)[INPUT] + .. + Field(2) + Physical(0020.0073) + Usage(1) + 0020.045f + Logical Minimum(-32767) + Logical Maximum(32767) + Report Size(8) + Report Count(1) + Report Offset(16) + Flags(Variable Absolute) +.. +.. + +The report is indicating "sensor page (0x20)" contains an accelerometer-3D (0x73). +This accelerometer-3D has some fields. Here for example field 2 is motion intensity +(0x045f) with a logical minimum value of -32767 and logical maximum of 32767. The +order of fields and length of each field is important as the input event raw +data will use this format. + + +Implementation +================= + +This specification defines many different types of sensors with different sets of +data fields. It is difficult to have a common input event to user space applications, +for different sensors. For example an accelerometer can send X,Y and Z data, whereas +an ambient light sensor can send illumination data. +So the implementation has two parts: +- Core hid driver +- Individual sensor processing part (sensor drivers) + +Core driver +----------- +The core driver registers (hid-sensor-hub) registers as a HID driver. It parses +report descriptors and identifies all the sensors present. It adds an MFD device +with name HID-SENSOR-xxxx (where xxxx is usage id from the specification). +For example +HID-SENSOR-200073 is registered for an Accelerometer 3D driver. +So if any driver with this name is inserted, then the probe routine for that +function will be called. So an accelerometer processing driver can register +with this name and will be probed if there is an accelerometer-3D detected. + +The core driver provides a set of APIs which can be used by the processing +drivers to register and get events for that usage id. Also it provides parsing +functions, which get and set each input/feature/output report. + +Individual sensor processing part (sensor drivers) +----------- +The processing driver will use an interface provided by the core driver to parse +the report and get the indexes of the fields and also can get events. This driver +can use IIO interface to use the standard ABI defined for a type of sensor. + + +Core driver Interface +===================== + +Callback structure: +Each processing driver can use this structure to set some callbacks. + int (*suspend)(..): Callback when HID suspend is received + int (*resume)(..): Callback when HID resume is received + int (*capture_sample)(..): Capture a sample for one of its data fields + int (*send_event)(..): One complete event is received which can have + multiple data fields. + +Registration functions: +int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev, + u32 usage_id, + struct hid_sensor_hub_callbacks *usage_callback): + +Registers callbacks for an usage id. The callback functions are not allowed +to sleep. + + +int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev, + u32 usage_id): + +Removes callbacks for an usage id. + + +Parsing function: +int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev, + u8 type, + u32 usage_id, u32 attr_usage_id, + struct hid_sensor_hub_attribute_info *info); + +A processing driver can look for some field of interest and check if it exists +in a report descriptor. If it exists it will store necessary information +so that fields can be set or get individually. +These indexes avoid searching every time and getting field index to get or set. + + +Set Feature report +int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, + u32 field_index, s32 value); + +This interface is used to set a value for a field in feature report. For example +if there is a field report_interval, which is parsed by a call to +sensor_hub_input_get_attribute_info before, then it can directly set that individual +field. + + +int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, + u32 field_index, s32 *value); + +This interface is used to get a value for a field in input report. For example +if there is a field report_interval, which is parsed by a call to +sensor_hub_input_get_attribute_info before, then it can directly get that individual +field value. + + +int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev, + u32 usage_id, + u32 attr_usage_id, u32 report_id); + +This is used to get a particular field value through input reports. For example +accelerometer wants to poll X axis value, then it can call this function with +the usage id of X axis. HID sensors can provide events, so this is not necessary +to poll for any field. If there is some new sample, the core driver will call +registered callback function to process the sample. diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 2af774ad1060..1630150ad2b1 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -708,6 +708,20 @@ config HID_ZYDACRON ---help--- Support for Zydacron remote control. +config HID_SENSOR_HUB + tristate "HID Sensors framework support" + depends on USB_HID + select MFD_CORE + default n + -- help--- + Support for HID Sensor framework. This creates a MFD instance + for a sensor hub and identifies all the sensors connected to it. + Each sensor is registered as a MFD cell, so that sensor specific + processing can be done in a separate driver. Each sensor + drivers can use the service provided by this driver to register + for events and handle data streams. Each sensor driver can format + data and present to user mode using input or IIO interface. + endmenu endif # HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 5a3690ff9bf2..cef68ca859d3 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -112,6 +112,7 @@ obj-$(CONFIG_HID_ZYDACRON) += hid-zydacron.o obj-$(CONFIG_HID_WACOM) += hid-wacom.o obj-$(CONFIG_HID_WALTOP) += hid-waltop.o obj-$(CONFIG_HID_WIIMOTE) += hid-wiimote.o +obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o obj-$(CONFIG_USB_HID) += usbhid/ obj-$(CONFIG_USB_MOUSE) += usbhid/ diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 2cd6880b6b17..bd3971bf31bf 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1568,6 +1568,10 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) }, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) }, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) }, + { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086, USB_DEVICE_ID_SENSOR_HUB_1020) }, + { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086, USB_DEVICE_ID_SENSOR_HUB_09FA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087, USB_DEVICE_ID_SENSOR_HUB_1020) }, + { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087, USB_DEVICE_ID_SENSOR_HUB_09FA) }, { HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) }, { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) }, @@ -1665,6 +1669,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) }, + { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_SENSOR_HUB_7014) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index ca4d83e6e387..269b50912a4a 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -429,6 +429,11 @@ #define USB_VENDOR_ID_IMATION 0x0718 #define USB_DEVICE_ID_DISC_STAKKA 0xd000 +#define USB_VENDOR_ID_INTEL_8086 0x8086 +#define USB_VENDOR_ID_INTEL_8087 0x8087 +#define USB_DEVICE_ID_SENSOR_HUB_1020 0x1020 +#define USB_DEVICE_ID_SENSOR_HUB_09FA 0x09FA + #define USB_VENDOR_ID_IRTOUCHSYSTEMS 0x6615 #define USB_DEVICE_ID_IRTOUCH_INFRARED_USB 0x0070 @@ -706,6 +711,7 @@ #define USB_VENDOR_ID_STANTUM_STM 0x0483 #define USB_DEVICE_ID_MTP_STM 0x3261 +#define USB_DEVICE_ID_SENSOR_HUB_7014 0x7014 #define USB_VENDOR_ID_STANTUM_SITRONIX 0x1403 #define USB_DEVICE_ID_MTP_SITRONIX 0x5001 diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c new file mode 100644 index 000000000000..d9d73e9163eb --- /dev/null +++ b/drivers/hid/hid-sensor-hub.c @@ -0,0 +1,680 @@ +/* + * HID Sensors Driver + * Copyright (c) 2012, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#include <linux/device.h> +#include <linux/hid.h> +#include <linux/usb.h> +#include "usbhid/usbhid.h" +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/mfd/core.h> +#include <linux/list.h> +#include <linux/hid-sensor-ids.h> +#include <linux/hid-sensor-hub.h> +#include "hid-ids.h" + +/** + * struct sensor_hub_pending - Synchronous read pending information + * @status: Pending status true/false. + * @ready: Completion synchronization data. + * @usage_id: Usage id for physical device, E.g. Gyro usage id. + * @attr_usage_id: Usage Id of a field, E.g. X-AXIS for a gyro. + * @raw_size: Response size for a read request. + * @raw_data: Place holder for received response. + */ +struct sensor_hub_pending { + bool status; + struct completion ready; + u32 usage_id; + u32 attr_usage_id; + int raw_size; + u8 *raw_data; +}; + +/** + * struct sensor_hub_data - Hold a instance data for a HID hub device + * @hsdev: Stored hid instance for current hub device. + * @mutex: Mutex to serialize synchronous request. + * @lock: Spin lock to protect pending request structure. + * @pending: Holds information of pending sync read request. + * @dyn_callback_list: Holds callback function + * @dyn_callback_lock: spin lock to protect callback list + * @hid_sensor_hub_client_devs: Stores all MFD cells for a hub instance. + * @hid_sensor_client_cnt: Number of MFD cells, (no of sensors attached). + */ +struct sensor_hub_data { + struct hid_sensor_hub_device *hsdev; + struct mutex mutex; + spinlock_t lock; + struct sensor_hub_pending pending; + struct list_head dyn_callback_list; + spinlock_t dyn_callback_lock; + struct mfd_cell *hid_sensor_hub_client_devs; + int hid_sensor_client_cnt; +}; + +/** + * struct hid_sensor_hub_callbacks_list - Stores callback list + * @list: list head. + * @usage_id: usage id for a physical device. + * @usage_callback: Stores registered callback functions. + * @priv: Private data for a physical device. + */ +struct hid_sensor_hub_callbacks_list { + struct list_head list; + u32 usage_id; + struct hid_sensor_hub_callbacks *usage_callback; + void *priv; +}; + +static int sensor_hub_check_for_sensor_page(struct hid_device *hdev) +{ + int i; + int ret = -EINVAL; + + for (i = 0; i < hdev->maxcollection; i++) { + struct hid_collection *col = &hdev->collection[i]; + if (col->type == HID_COLLECTION_PHYSICAL && + (col->usage & HID_USAGE_PAGE) == HID_UP_SENSOR) { + ret = 0; + break; + } + } + + return ret; +} + +static struct hid_report *sensor_hub_report(int id, struct hid_device *hdev, + int dir) +{ + struct hid_report *report; + + list_for_each_entry(report, &hdev->report_enum[dir].report_list, list) { + if (report->id == id) + return report; + } + hid_warn(hdev, "No report with id 0x%x found\n", id); + + return NULL; +} + +static int sensor_hub_get_physical_device_count( + struct hid_report_enum *report_enum) +{ + struct hid_report *report; + struct hid_field *field; + int cnt = 0; + + list_for_each_entry(report, &report_enum->report_list, list) { + field = report->field[0]; + if (report->maxfield && field && + field->physical) + cnt++; + } + + return cnt; +} + +static void sensor_hub_fill_attr_info( + struct hid_sensor_hub_attribute_info *info, + s32 index, s32 report_id, s32 units, s32 unit_expo, s32 size) +{ + info->index = index; + info->report_id = report_id; + info->units = units; + info->unit_expo = unit_expo; + info->size = size/8; +} + +static struct hid_sensor_hub_callbacks *sensor_hub_get_callback( + struct hid_device *hdev, + u32 usage_id, void **priv) +{ + struct hid_sensor_hub_callbacks_list *callback; + struct sensor_hub_data *pdata = hid_get_drvdata(hdev); + + spin_lock(&pdata->dyn_callback_lock); + list_for_each_entry(callback, &pdata->dyn_callback_list, list) + if (callback->usage_id == usage_id) { + *priv = callback->priv; + spin_unlock(&pdata->dyn_callback_lock); + return callback->usage_callback; + } + spin_unlock(&pdata->dyn_callback_lock); + + return NULL; +} + +int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev, + u32 usage_id, + struct hid_sensor_hub_callbacks *usage_callback) +{ + struct hid_sensor_hub_callbacks_list *callback; + struct sensor_hub_data *pdata = hid_get_drvdata(hsdev->hdev); + + spin_lock(&pdata->dyn_callback_lock); + list_for_each_entry(callback, &pdata->dyn_callback_list, list) + if (callback->usage_id == usage_id) { + spin_unlock(&pdata->dyn_callback_lock); + return -EINVAL; + } + callback = kzalloc(sizeof(*callback), GFP_ATOMIC); + if (!callback) { + spin_unlock(&pdata->dyn_callback_lock); + return -ENOMEM; + } + callback->usage_callback = usage_callback; + callback->usage_id = usage_id; + callback->priv = NULL; + list_add_tail(&callback->list, &pdata->dyn_callback_list); + spin_unlock(&pdata->dyn_callback_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(sensor_hub_register_callback); + +int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev, + u32 usage_id) +{ + struct hid_sensor_hub_callbacks_list *callback; + struct sensor_hub_data *pdata = hid_get_drvdata(hsdev->hdev); + + spin_lock(&pdata->dyn_callback_lock); + list_for_each_entry(callback, &pdata->dyn_callback_list, list) + if (callback->usage_id == usage_id) { + list_del(&callback->list); + kfree(callback); + break; + } + spin_unlock(&pdata->dyn_callback_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(sensor_hub_remove_callback); + +int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, + u32 field_index, s32 value) +{ + struct hid_report *report; + struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); + int ret = 0; + + mutex_lock(&data->mutex); + report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT); + if (!report || (field_index >= report->maxfield)) { + ret = -EINVAL; + goto done_proc; + } + hid_set_field(report->field[field_index], 0, value); + usbhid_submit_report(hsdev->hdev, report, USB_DIR_OUT); + usbhid_wait_io(hsdev->hdev); + +done_proc: + mutex_unlock(&data->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(sensor_hub_set_feature); + +int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, + u32 field_index, s32 *value) +{ + struct hid_report *report; + struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); + int ret = 0; + + mutex_lock(&data->mutex); + report = sensor_hub_report(report_id, hsdev->hdev, HID_FEATURE_REPORT); + if (!report || (field_index >= report->maxfield)) { + ret = -EINVAL; + goto done_proc; + } + usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN); + usbhid_wait_io(hsdev->hdev); + *value = report->field[field_index]->value[0]; + +done_proc: + mutex_unlock(&data->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(sensor_hub_get_feature); + + +int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev, + u32 usage_id, + u32 attr_usage_id, u32 report_id) +{ + struct sensor_hub_data *data = hid_get_drvdata(hsdev->hdev); + unsigned long flags; + struct hid_report *report; + int ret_val = 0; + + mutex_lock(&data->mutex); + memset(&data->pending, 0, sizeof(data->pending)); + init_completion(&data->pending.ready); + data->pending.usage_id = usage_id; + data->pending.attr_usage_id = attr_usage_id; + data->pending.raw_size = 0; + + spin_lock_irqsave(&data->lock, flags); + data->pending.status = true; + report = sensor_hub_report(report_id, hsdev->hdev, HID_INPUT_REPORT); + if (!report) { + spin_unlock_irqrestore(&data->lock, flags); + goto err_free; + } + usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN); + spin_unlock_irqrestore(&data->lock, flags); + wait_for_completion_interruptible_timeout(&data->pending.ready, HZ*5); + switch (data->pending.raw_size) { + case 1: + ret_val = *(u8 *)data->pending.raw_data; + break; + case 2: + ret_val = *(u16 *)data->pending.raw_data; + break; + case 4: + ret_val = *(u32 *)data->pending.raw_data; + break; + default: + ret_val = 0; + } + kfree(data->pending.raw_data); + +err_free: + data->pending.status = false; + mutex_unlock(&data->mutex); + + return ret_val; +} +EXPORT_SYMBOL_GPL(sensor_hub_input_attr_get_raw_value); + +int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev, + u8 type, + u32 usage_id, + u32 attr_usage_id, + struct hid_sensor_hub_attribute_info *info) +{ + int ret = -1; + int i, j; + int collection_index = -1; + struct hid_report *report; + struct hid_field *field; + struct hid_report_enum *report_enum; + struct hid_device *hdev = hsdev->hdev; + + /* Initialize with defaults */ + info->usage_id = usage_id; + info->attrib_id = attr_usage_id; + info->report_id = -1; + info->index = -1; + info->units = -1; + info->unit_expo = -1; + + for (i = 0; i < hdev->maxcollection; ++i) { + struct hid_collection *collection = &hdev->collection[i]; + if (usage_id == collection->usage) { + collection_index = i; + break; + } + } + if (collection_index == -1) + goto err_ret; + + report_enum = &hdev->report_enum[type]; + list_for_each_entry(report, &report_enum->report_list, list) { + for (i = 0; i < report->maxfield; ++i) { + field = report->field[i]; + if (field->physical == usage_id && + field->logical == attr_usage_id) { + sensor_hub_fill_attr_info(info, i, report->id, + field->unit, field->unit_exponent, + field->report_size); + ret = 0; + } else { + for (j = 0; j < field->maxusage; ++j) { + if (field->usage[j].hid == + attr_usage_id && + field->usage[j].collection_index == + collection_index) { + sensor_hub_fill_attr_info(info, + i, report->id, + field->unit, + field->unit_exponent, + field->report_size); + ret = 0; + break; + } + } + } + if (ret == 0) + break; + } + } + +err_ret: + return ret; +} +EXPORT_SYMBOL_GPL(sensor_hub_input_get_attribute_info); + +#ifdef CONFIG_PM +static int sensor_hub_suspend(struct hid_device *hdev, pm_message_t message) +{ + struct sensor_hub_data *pdata = hid_get_drvdata(hdev); + struct hid_sensor_hub_callbacks_list *callback; + + hid_dbg(hdev, " sensor_hub_suspend\n"); + spin_lock(&pdata->dyn_callback_lock); + list_for_each_entry(callback, &pdata->dyn_callback_list, list) { + if (callback->usage_callback->suspend) + callback->usage_callback->suspend( + pdata->hsdev, callback->priv); + } + spin_unlock(&pdata->dyn_callback_lock); + + return 0; +} + +static int sensor_hub_resume(struct hid_device *hdev) +{ + struct sensor_hub_data *pdata = hid_get_drvdata(hdev); + struct hid_sensor_hub_callbacks_list *callback; + + hid_dbg(hdev, " sensor_hub_resume\n"); + spin_lock(&pdata->dyn_callback_lock); + list_for_each_entry(callback, &pdata->dyn_callback_list, list) { + if (callback->usage_callback->resume) + callback->usage_callback->resume( + pdata->hsdev, callback->priv); + } + spin_unlock(&pdata->dyn_callback_lock); + + return 0; +} + +static int sensor_hub_reset_resume(struct hid_device *hdev) +{ + return 0; +} +#endif +/* + * Handle raw report as sent by device + */ +static int sensor_hub_raw_event(struct hid_device *hdev, + struct hid_report *report, u8 *raw_data, int size) +{ + int i; + u8 *ptr; + int sz; + struct sensor_hub_data *pdata = hid_get_drvdata(hdev); + unsigned long flags; + struct hid_sensor_hub_callbacks *callback = NULL; + struct hid_collection *collection = NULL; + void *priv = NULL; + + hid_dbg(hdev, "sensor_hub_raw_event report id:0x%x size:%d type:%d\n", + report->id, size, report->type); + hid_dbg(hdev, "maxfield:%d\n", report->maxfield); + if (report->type != HID_INPUT_REPORT) + return 1; + + ptr = raw_data; + ptr++; /*Skip report id*/ + + if (!report) + goto err_report; + + spin_lock_irqsave(&pdata->lock, flags); + + for (i = 0; i < report->maxfield; ++i) { + + hid_dbg(hdev, "%d collection_index:%x hid:%x sz:%x\n", + i, report->field[i]->usage->collection_index, + report->field[i]->usage->hid, + report->field[i]->report_size/8); + + sz = report->field[i]->report_size/8; + if (pdata->pending.status && pdata->pending.attr_usage_id == + report->field[i]->usage->hid) { + hid_dbg(hdev, "data was pending ...\n"); + pdata->pending.raw_data = kmalloc(sz, GFP_ATOMIC); + if (pdata->pending.raw_data) { + memcpy(pdata->pending.raw_data, ptr, sz); + pdata->pending.raw_size = sz; + } else + pdata->pending.raw_size = 0; + complete(&pdata->pending.ready); + } + collection = &hdev->collection[ + report->field[i]->usage->collection_index]; + hid_dbg(hdev, "collection->usage %x\n", + collection->usage); + callback = sensor_hub_get_callback(pdata->hsdev->hdev, + report->field[i]->physical, + &priv); + if (callback && callback->capture_sample) { + if (report->field[i]->logical) + callback->capture_sample(pdata->hsdev, + report->field[i]->logical, sz, ptr, + callback->pdev); + else + callback->capture_sample(pdata->hsdev, + report->field[i]->usage->hid, sz, ptr, + callback->pdev); + } + ptr += sz; + } + if (callback && collection && callback->send_event) + callback->send_event(pdata->hsdev, collection->usage, + callback->pdev); + spin_unlock_irqrestore(&pdata->lock, flags); + +err_report: + return 1; +} + +static int sensor_hub_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + int ret; + struct sensor_hub_data *sd; + int i; + char *name; + struct hid_report *report; + struct hid_report_enum *report_enum; + struct hid_field *field; + int dev_cnt; + + sd = kzalloc(sizeof(struct sensor_hub_data), GFP_KERNEL); + if (!sd) { + hid_err(hdev, "cannot allocate Sensor data\n"); + return -ENOMEM; + } + sd->hsdev = kzalloc(sizeof(struct hid_sensor_hub_device), GFP_KERNEL); + if (!sd->hsdev) { + hid_err(hdev, "cannot allocate hid_sensor_hub_device\n"); + ret = -ENOMEM; + goto err_free_hub; + } + hid_set_drvdata(hdev, sd); + sd->hsdev->hdev = hdev; + sd->hsdev->vendor_id = hdev->vendor; + sd->hsdev->product_id = hdev->product; + spin_lock_init(&sd->lock); + spin_lock_init(&sd->dyn_callback_lock); + mutex_init(&sd->mutex); + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "parse failed\n"); + goto err_free; + } + if (sensor_hub_check_for_sensor_page(hdev) < 0) { + hid_err(hdev, "sensor page not found\n"); + goto err_free; + } + INIT_LIST_HEAD(&hdev->inputs); + + ret = hid_hw_start(hdev, 0); + if (ret) { + hid_err(hdev, "hw start failed\n"); + goto err_free; + } + ret = hid_hw_open(hdev); + if (ret) { + hid_err(hdev, "failed to open input interrupt pipe\n"); + goto err_stop_hw; + } + + INIT_LIST_HEAD(&sd->dyn_callback_list); + sd->hid_sensor_client_cnt = 0; + report_enum = &hdev->report_enum[HID_INPUT_REPORT]; + + dev_cnt = sensor_hub_get_physical_device_count(report_enum); + if (dev_cnt > HID_MAX_PHY_DEVICES) { + hid_err(hdev, "Invalid Physical device count\n"); + ret = -EINVAL; + goto err_close; + } + sd->hid_sensor_hub_client_devs = kzalloc(dev_cnt * + sizeof(struct mfd_cell), + GFP_KERNEL); + if (sd->hid_sensor_hub_client_devs == NULL) { + hid_err(hdev, "Failed to allocate memory for mfd cells\n"); + ret = -ENOMEM; + goto err_close; + } + list_for_each_entry(report, &report_enum->report_list, list) { + hid_dbg(hdev, "Report id:%x\n", report->id); + field = report->field[0]; + if (report->maxfield && field && + field->physical) { + name = kasprintf(GFP_KERNEL, "HID-SENSOR-%x", + field->physical); + if (name == NULL) { + hid_err(hdev, "Failed MFD device name\n"); + ret = -ENOMEM; + goto err_free_names; + } + sd->hid_sensor_hub_client_devs[ + sd->hid_sensor_client_cnt].name = name; + sd->hid_sensor_hub_client_devs[ + sd->hid_sensor_client_cnt].platform_data = + sd->hsdev; + sd->hid_sensor_hub_client_devs[ + sd->hid_sensor_client_cnt].pdata_size = + sizeof(*sd->hsdev); + hid_dbg(hdev, "Adding %s:%p\n", name, sd); + sd->hid_sensor_client_cnt++; + } + } + ret = mfd_add_devices(&hdev->dev, 0, sd->hid_sensor_hub_client_devs, + sd->hid_sensor_client_cnt, NULL, 0, NULL); + if (ret < 0) + goto err_free_names; + + return ret; + +err_free_names: + for (i = 0; i < sd->hid_sensor_client_cnt ; ++i) + kfree(sd->hid_sensor_hub_client_devs[i].name); + kfree(sd->hid_sensor_hub_client_devs); +err_close: + hid_hw_close(hdev); +err_stop_hw: + hid_hw_stop(hdev); +err_free: + kfree(sd->hsdev); +err_free_hub: + kfree(sd); + + return ret; +} + +static void sensor_hub_remove(struct hid_device *hdev) +{ + struct sensor_hub_data *data = hid_get_drvdata(hdev); + unsigned long flags; + int i; + + hid_dbg(hdev, " hardware removed\n"); + hid_hw_close(hdev); + hid_hw_stop(hdev); + spin_lock_irqsave(&data->lock, flags); + if (data->pending.status) + complete(&data->pending.ready); + spin_unlock_irqrestore(&data->lock, flags); + mfd_remove_devices(&hdev->dev); + for (i = 0; i < data->hid_sensor_client_cnt ; ++i) + kfree(data->hid_sensor_hub_client_devs[i].name); + kfree(data->hid_sensor_hub_client_devs); + hid_set_drvdata(hdev, NULL); + mutex_destroy(&data->mutex); + kfree(data->hsdev); + kfree(data); +} + +static const struct hid_device_id sensor_hub_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086, + USB_DEVICE_ID_SENSOR_HUB_1020) }, + { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087, + USB_DEVICE_ID_SENSOR_HUB_1020) }, + { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8086, + USB_DEVICE_ID_SENSOR_HUB_09FA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_INTEL_8087, + USB_DEVICE_ID_SENSOR_HUB_09FA) }, + { HID_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, + USB_DEVICE_ID_SENSOR_HUB_7014) }, + { } +}; +MODULE_DEVICE_TABLE(hid, sensor_hub_devices); + +static const struct hid_usage_id sensor_hub_grabbed_usages[] = { + { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID }, + { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1 } +}; + +static struct hid_driver sensor_hub_driver = { + .name = "hid-sensor-hub", + .id_table = sensor_hub_devices, + .probe = sensor_hub_probe, + .remove = sensor_hub_remove, + .raw_event = sensor_hub_raw_event, +#ifdef CONFIG_PM + .suspend = sensor_hub_suspend, + .resume = sensor_hub_resume, + .reset_resume = sensor_hub_reset_resume, +#endif +}; + +static int __init sensor_hub_init(void) +{ + return hid_register_driver(&sensor_hub_driver); +} + +static void __exit sensor_hub_exit(void) +{ + hid_unregister_driver(&sensor_hub_driver); +} + +module_init(sensor_hub_init); +module_exit(sensor_hub_exit); + +MODULE_DESCRIPTION("HID Sensor Hub driver"); +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig index d4984c8be973..6e3f143fc71d 100644 --- a/drivers/iio/Kconfig +++ b/drivers/iio/Kconfig @@ -1,5 +1,5 @@ # -# Industrial I/O subsytem configuration +# Industrial I/O subsystem configuration # menuconfig IIO @@ -54,10 +54,15 @@ config IIO_CONSUMERS_PER_TRIGGER This value controls the maximum number of consumers that a given trigger may handle. Default is 2. +source "drivers/iio/accel/Kconfig" source "drivers/iio/adc/Kconfig" source "drivers/iio/amplifiers/Kconfig" source "drivers/iio/light/Kconfig" source "drivers/iio/frequency/Kconfig" source "drivers/iio/dac/Kconfig" +source "drivers/iio/common/Kconfig" +source "drivers/iio/gyro/Kconfig" +source "drivers/iio/light/Kconfig" +source "drivers/iio/magnetometer/Kconfig" endif # IIO diff --git a/drivers/iio/Makefile b/drivers/iio/Makefile index 34309abb7979..f7fa3c0867b4 100644 --- a/drivers/iio/Makefile +++ b/drivers/iio/Makefile @@ -10,8 +10,13 @@ industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o obj-$(CONFIG_IIO_TRIGGERED_BUFFER) += industrialio-triggered-buffer.o obj-$(CONFIG_IIO_KFIFO_BUF) += kfifo_buf.o +obj-y += accel/ obj-y += adc/ obj-y += amplifiers/ obj-y += light/ obj-y += frequency/ obj-y += dac/ +obj-y += common/ +obj-y += gyro/ +obj-y += light/ +obj-y += magnetometer/ diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig new file mode 100644 index 000000000000..b2510c4d9a5a --- /dev/null +++ b/drivers/iio/accel/Kconfig @@ -0,0 +1,16 @@ +# +# Accelerometer drivers +# +menu "Accelerometers" + +config HID_SENSOR_ACCEL_3D + depends on HID_SENSOR_HUB + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + select HID_SENSOR_IIO_COMMON + tristate "HID Acelerometers 3D" + help + Say yes here to build support for the HID SENSOR + accelerometers 3D. + +endmenu diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile new file mode 100644 index 000000000000..5bc6855a973e --- /dev/null +++ b/drivers/iio/accel/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for industrial I/O accelerometer drivers +# + +obj-$(CONFIG_HID_SENSOR_ACCEL_3D) += hid-sensor-accel-3d.o diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c new file mode 100644 index 000000000000..314a4057879e --- /dev/null +++ b/drivers/iio/accel/hid-sensor-accel-3d.c @@ -0,0 +1,418 @@ +/* + * HID Sensors Driver + * Copyright (c) 2012, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#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-attributes.h" +#include "../common/hid-sensors/hid-sensor-trigger.h" + +/*Format: HID-SENSOR-usage_id_in_hex*/ +/*Usage ID from spec for Accelerometer-3D: 0x200073*/ +#define DRIVER_NAME "HID-SENSOR-200073" + +enum accel_3d_channel { + CHANNEL_SCAN_INDEX_X, + CHANNEL_SCAN_INDEX_Y, + CHANNEL_SCAN_INDEX_Z, + ACCEL_3D_CHANNEL_MAX, +}; + +struct accel_3d_state { + struct hid_sensor_hub_callbacks callbacks; + struct hid_sensor_iio_common common_attributes; + struct hid_sensor_hub_attribute_info accel[ACCEL_3D_CHANNEL_MAX]; + u32 accel_val[ACCEL_3D_CHANNEL_MAX]; +}; + +static const u32 accel_3d_addresses[ACCEL_3D_CHANNEL_MAX] = { + HID_USAGE_SENSOR_ACCEL_X_AXIS, + HID_USAGE_SENSOR_ACCEL_Y_AXIS, + HID_USAGE_SENSOR_ACCEL_Z_AXIS +}; + +/* Channel definitions */ +static const struct iio_chan_spec accel_3d_channels[] = { + { + .type = IIO_ACCEL, + .modified = 1, + .channel2 = IIO_MOD_X, + .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT | + IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT, + .scan_index = CHANNEL_SCAN_INDEX_X, + }, { + .type = IIO_ACCEL, + .modified = 1, + .channel2 = IIO_MOD_Y, + .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT | + IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT, + .scan_index = CHANNEL_SCAN_INDEX_Y, + }, { + .type = IIO_ACCEL, + .modified = 1, + .channel2 = IIO_MOD_Z, + .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT | + IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT, + .scan_index = CHANNEL_SCAN_INDEX_Z, + } +}; + +/* Adjust channel real bits based on report descriptor */ +static void accel_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels, + int channel, int size) +{ + channels[channel].scan_type.sign = 's'; + /* Real storage bits will change based on the report desc. */ + channels[channel].scan_type.realbits = size * 8; + /* Maximum size of a sample to capture is u32 */ + channels[channel].scan_type.storagebits = sizeof(u32) * 8; +} + +/* Channel read_raw handler */ +static int accel_3d_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, + long mask) +{ + struct accel_3d_state *accel_state = iio_priv(indio_dev); + int report_id = -1; + u32 address; + int ret; + int ret_type; + + *val = 0; + *val2 = 0; + switch (mask) { + case 0: + 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); + else { + *val = 0; + return -EINVAL; + } + 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; + break; + case IIO_CHAN_INFO_OFFSET: + *val = hid_sensor_convert_exponent( + accel_state->accel[CHANNEL_SCAN_INDEX_X].unit_expo); + ret_type = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = hid_sensor_read_samp_freq_value( + &accel_state->common_attributes, val, val2); + ret_type = IIO_VAL_INT_PLUS_MICRO; + break; + case IIO_CHAN_INFO_HYSTERESIS: + ret = hid_sensor_read_raw_hyst_value( + &accel_state->common_attributes, val, val2); + ret_type = IIO_VAL_INT_PLUS_MICRO; + break; + default: + ret_type = -EINVAL; + break; + } + + return ret_type; +} + +/* Channel write_raw handler */ +static int accel_3d_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct accel_3d_state *accel_state = iio_priv(indio_dev); + int ret = 0; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + ret = hid_sensor_write_samp_freq_value( + &accel_state->common_attributes, val, val2); + break; + case IIO_CHAN_INFO_HYSTERESIS: + ret = hid_sensor_write_raw_hyst_value( + &accel_state->common_attributes, val, val2); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int accel_3d_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + return IIO_VAL_INT_PLUS_MICRO; +} + +static const struct iio_info accel_3d_info = { + .driver_module = THIS_MODULE, + .read_raw = &accel_3d_read_raw, + .write_raw = &accel_3d_write_raw, + .write_raw_get_fmt = &accel_3d_write_raw_get_fmt, +}; + +/* Function to push data to buffer */ +static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len) +{ + struct iio_buffer *buffer = indio_dev->buffer; + int datum_sz; + + dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); + if (!buffer) { + dev_err(&indio_dev->dev, "Buffer == NULL\n"); + return; + } + datum_sz = buffer->access->get_bytes_per_datum(buffer); + if (len > datum_sz) { + dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len, + datum_sz); + return; + } + iio_push_to_buffer(buffer, (u8 *)data); +} + +/* Callback handler to send event after all samples are received and captured */ +static int accel_3d_proc_event(struct hid_sensor_hub_device *hsdev, + unsigned usage_id, + void *priv) +{ + 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) + hid_sensor_push_data(indio_dev, + (u8 *)accel_state->accel_val, + sizeof(accel_state->accel_val)); + + return 0; +} + +/* Capture samples in local storage */ +static int accel_3d_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 accel_3d_state *accel_state = iio_priv(indio_dev); + int offset; + int ret = -EINVAL; + + switch (usage_id) { + case HID_USAGE_SENSOR_ACCEL_X_AXIS: + case HID_USAGE_SENSOR_ACCEL_Y_AXIS: + case HID_USAGE_SENSOR_ACCEL_Z_AXIS: + offset = usage_id - HID_USAGE_SENSOR_ACCEL_X_AXIS; + accel_state->accel_val[CHANNEL_SCAN_INDEX_X + offset] = + *(u32 *)raw_data; + ret = 0; + break; + default: + break; + } + + return ret; +} + +/* Parse report which is specific to an usage id*/ +static int accel_3d_parse_report(struct platform_device *pdev, + struct hid_sensor_hub_device *hsdev, + struct iio_chan_spec *channels, + unsigned usage_id, + struct accel_3d_state *st) +{ + int ret; + int i; + + for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) { + ret = sensor_hub_input_get_attribute_info(hsdev, + HID_INPUT_REPORT, + usage_id, + HID_USAGE_SENSOR_ACCEL_X_AXIS + i, + &st->accel[CHANNEL_SCAN_INDEX_X + i]); + if (ret < 0) + break; + accel_3d_adjust_channel_bit_mask(channels, + CHANNEL_SCAN_INDEX_X + i, + st->accel[CHANNEL_SCAN_INDEX_X + i].size); + } + dev_dbg(&pdev->dev, "accel_3d %x:%x, %x:%x, %x:%x\n", + st->accel[0].index, + st->accel[0].report_id, + st->accel[1].index, st->accel[1].report_id, + st->accel[2].index, st->accel[2].report_id); + + return ret; +} + +/* Function to initialize the processing for usage id */ +static int __devinit hid_accel_3d_probe(struct platform_device *pdev) +{ + int ret = 0; + static const char *name = "accel_3d"; + struct iio_dev *indio_dev; + struct accel_3d_state *accel_state; + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct iio_chan_spec *channels; + + indio_dev = iio_device_alloc(sizeof(struct accel_3d_state)); + if (indio_dev == NULL) { + ret = -ENOMEM; + goto error_ret; + } + platform_set_drvdata(pdev, indio_dev); + + accel_state = iio_priv(indio_dev); + accel_state->common_attributes.hsdev = hsdev; + accel_state->common_attributes.pdev = pdev; + + ret = hid_sensor_parse_common_attributes(hsdev, + HID_USAGE_SENSOR_ACCEL_3D, + &accel_state->common_attributes); + if (ret) { + dev_err(&pdev->dev, "failed to setup common attributes\n"); + goto error_free_dev; + } + + channels = kmemdup(accel_3d_channels, + sizeof(accel_3d_channels), + GFP_KERNEL); + if (!channels) { + dev_err(&pdev->dev, "failed to duplicate channels\n"); + goto error_free_dev; + } + + ret = accel_3d_parse_report(pdev, hsdev, channels, + HID_USAGE_SENSOR_ACCEL_3D, accel_state); + if (ret) { + dev_err(&pdev->dev, "failed to setup attributes\n"); + goto error_free_dev_mem; + } + + indio_dev->channels = channels; + indio_dev->num_channels = ARRAY_SIZE(accel_3d_channels); + indio_dev->dev.parent = &pdev->dev; + indio_dev->info = &accel_3d_info; + indio_dev->name = name; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + NULL, NULL); + if (ret) { + dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); + goto error_free_dev_mem; + } + accel_state->common_attributes.data_ready = false; + ret = hid_sensor_setup_trigger(indio_dev, name, + &accel_state->common_attributes); + if (ret < 0) { + 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; + } + + accel_state->callbacks.send_event = accel_3d_proc_event; + accel_state->callbacks.capture_sample = accel_3d_capture_sample; + accel_state->callbacks.pdev = pdev; + ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_ACCEL_3D, + &accel_state->callbacks); + if (ret < 0) { + dev_err(&pdev->dev, "callback reg failed\n"); + goto error_iio_unreg; + } + + return ret; + +error_iio_unreg: + iio_device_unregister(indio_dev); +error_remove_trigger: + hid_sensor_remove_trigger(indio_dev); +error_unreg_buffer_funcs: + iio_triggered_buffer_cleanup(indio_dev); +error_free_dev_mem: + kfree(indio_dev->channels); +error_free_dev: + iio_device_free(indio_dev); +error_ret: + return ret; +} + +/* Function to deinitialize the processing for usage id */ +static int __devinit hid_accel_3d_remove(struct platform_device *pdev) +{ + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ACCEL_3D); + iio_device_unregister(indio_dev); + hid_sensor_remove_trigger(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + kfree(indio_dev->channels); + iio_device_free(indio_dev); + + return 0; +} + +static struct platform_driver hid_accel_3d_platform_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = hid_accel_3d_probe, + .remove = hid_accel_3d_remove, +}; +module_platform_driver(hid_accel_3d_platform_driver); + +MODULE_DESCRIPTION("HID Sensor Accel 3D"); +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig index 8a78b4f3ef58..492758120338 100644 --- a/drivers/iio/adc/Kconfig +++ b/drivers/iio/adc/Kconfig @@ -3,6 +3,11 @@ # menu "Analog to digital converters" +config AD_SIGMA_DELTA + tristate + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + config AD7266 tristate "Analog Devices AD7265/AD7266 ADC driver" depends on SPI_MASTER @@ -13,6 +18,33 @@ config AD7266 Say yes here to build support for Analog Devices AD7265 and AD7266 ADCs. +config AD7791 + tristate "Analog Devices AD7791 ADC driver" + depends on SPI + select AD_SIGMA_DELTA + help + Say yes here to build support for Analog Devices AD7787, AD7788, AD7789, + AD7790 and AD7791 SPI analog to digital converters (ADC). If unsure, say + N (but it is safe to say "Y"). + + To compile this driver as a module, choose M here: the module will be + called ad7791. + +config AD7476 + tristate "Analog Devices AD7476 and similar 1-channel ADCs driver" + depends on SPI + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for Analog Devices AD7273, AD7274, AD7276, + AD7277, AD7278, AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468, + AD7495, AD7910, AD7920, AD7920 SPI analog to digital converters (ADC). + + If unsure, say N (but it's safe to say "Y"). + + To compile this driver as a module, choose M here: the + module will be called ad7476. + config AT91_ADC tristate "Atmel AT91 ADC" depends on ARCH_AT91 @@ -22,4 +54,10 @@ config AT91_ADC help Say yes here to build support for Atmel AT91 ADC. +config LP8788_ADC + bool "LP8788 ADC driver" + depends on MFD_LP8788 + help + Say yes here to build support for TI LP8788 ADC. + endmenu diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile index 52eec254c38c..900995d5e179 100644 --- a/drivers/iio/adc/Makefile +++ b/drivers/iio/adc/Makefile @@ -2,5 +2,9 @@ # Makefile for IIO ADC drivers # +obj-$(CONFIG_AD_SIGMA_DELTA) += ad_sigma_delta.o obj-$(CONFIG_AD7266) += ad7266.o +obj-$(CONFIG_AD7476) += ad7476.o +obj-$(CONFIG_AD7791) += ad7791.o obj-$(CONFIG_AT91_ADC) += at91_adc.o +obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o diff --git a/drivers/iio/adc/ad7266.c b/drivers/iio/adc/ad7266.c index 5c3f1ba5a06d..b11f214779a2 100644 --- a/drivers/iio/adc/ad7266.c +++ b/drivers/iio/adc/ad7266.c @@ -99,7 +99,7 @@ static irqreturn_t ad7266_trigger_handler(int irq, void *p) if (ret == 0) { if (indio_dev->scan_timestamp) ((s64 *)st->data)[1] = pf->timestamp; - iio_push_to_buffer(buffer, (u8 *)st->data, pf->timestamp); + iio_push_to_buffer(buffer, (u8 *)st->data); } iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/staging/iio/adc/ad7476_core.c b/drivers/iio/adc/ad7476.c index 4d30a798ba0d..7f2f45a0a48d 100644 --- a/drivers/staging/iio/adc/ad7476_core.c +++ b/drivers/iio/adc/ad7476.c @@ -18,8 +18,76 @@ #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 "ad7476.h" +#define RES_MASK(bits) ((1 << (bits)) - 1) + +struct ad7476_state; + +struct ad7476_chip_info { + unsigned int int_vref_uv; + struct iio_chan_spec channel[2]; + void (*reset)(struct ad7476_state *); +}; + +struct ad7476_state { + struct spi_device *spi; + const struct ad7476_chip_info *chip_info; + struct regulator *reg; + struct spi_transfer xfer; + struct spi_message msg; + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + * Make the buffer large enough for one 16 bit sample and one 64 bit + * aligned 64 bit timestamp. + */ + unsigned char data[ALIGN(2, sizeof(s64)) + sizeof(s64)] + ____cacheline_aligned; +}; + +enum ad7476_supported_device_ids { + ID_AD7091R, + ID_AD7276, + ID_AD7277, + ID_AD7278, + ID_AD7466, + ID_AD7467, + ID_AD7468, + ID_AD7495, + ID_AD7940, +}; + +static irqreturn_t ad7476_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ad7476_state *st = iio_priv(indio_dev); + s64 time_ns; + int b_sent; + + b_sent = spi_sync(st->spi, &st->msg); + if (b_sent < 0) + goto done; + + time_ns = iio_get_time_ns(); + + if (indio_dev->scan_timestamp) + ((s64 *)st->data)[1] = time_ns; + + iio_push_to_buffer(indio_dev->buffer, st->data); +done: + iio_trigger_notify_done(indio_dev->trig); + + return IRQ_HANDLED; +} + +static void ad7091_reset(struct ad7476_state *st) +{ + /* Any transfers with 8 scl cycles will reset the device */ + spi_read(st->spi, st->data, 1); +} static int ad7476_scan_direct(struct ad7476_state *st) { @@ -29,7 +97,7 @@ static int ad7476_scan_direct(struct ad7476_state *st) if (ret) return ret; - return (st->data[0] << 8) | st->data[1]; + return be16_to_cpup((__be16 *)st->data); } static int ad7476_read_raw(struct iio_dev *indio_dev, @@ -40,7 +108,7 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, { int ret; struct ad7476_state *st = iio_priv(indio_dev); - unsigned int scale_uv; + int scale_uv; switch (m) { case IIO_CHAN_INFO_RAW: @@ -57,62 +125,80 @@ static int ad7476_read_raw(struct iio_dev *indio_dev, RES_MASK(st->chip_info->channel[0].scan_type.realbits); return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: - scale_uv = (st->int_vref_mv * 1000) - >> st->chip_info->channel[0].scan_type.realbits; - *val = scale_uv/1000; - *val2 = (scale_uv%1000)*1000; + if (!st->chip_info->int_vref_uv) { + scale_uv = regulator_get_voltage(st->reg); + if (scale_uv < 0) + return scale_uv; + } else { + scale_uv = st->chip_info->int_vref_uv; + } + scale_uv >>= chan->scan_type.realbits; + *val = scale_uv / 1000; + *val2 = (scale_uv % 1000) * 1000; return IIO_VAL_INT_PLUS_MICRO; } return -EINVAL; } -#define AD7476_CHAN(bits) \ +#define _AD7476_CHAN(bits, _shift, _info_mask) \ { \ .type = IIO_VOLTAGE, \ .indexed = 1, \ - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + .info_mask = _info_mask | \ IIO_CHAN_INFO_SCALE_SHARED_BIT, \ .scan_type = { \ .sign = 'u', \ - .realbits = bits, \ + .realbits = (bits), \ .storagebits = 16, \ - .shift = 12 - bits, \ + .shift = (_shift), \ + .endianness = IIO_BE, \ }, \ } +#define AD7476_CHAN(bits) _AD7476_CHAN((bits), 13 - (bits), \ + IIO_CHAN_INFO_RAW_SEPARATE_BIT) +#define AD7940_CHAN(bits) _AD7476_CHAN((bits), 15 - (bits), \ + IIO_CHAN_INFO_RAW_SEPARATE_BIT) +#define AD7091R_CHAN(bits) _AD7476_CHAN((bits), 16 - (bits), 0) + static const struct ad7476_chip_info ad7476_chip_info_tbl[] = { - [ID_AD7466] = { - .channel[0] = AD7476_CHAN(12), + [ID_AD7091R] = { + .channel[0] = AD7091R_CHAN(12), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), + .reset = ad7091_reset, }, - [ID_AD7467] = { - .channel[0] = AD7476_CHAN(10), + [ID_AD7276] = { + .channel[0] = AD7940_CHAN(12), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, - [ID_AD7468] = { - .channel[0] = AD7476_CHAN(8), + [ID_AD7277] = { + .channel[0] = AD7940_CHAN(10), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, - [ID_AD7475] = { - .channel[0] = AD7476_CHAN(12), + [ID_AD7278] = { + .channel[0] = AD7940_CHAN(8), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, - [ID_AD7476] = { + [ID_AD7466] = { .channel[0] = AD7476_CHAN(12), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, - [ID_AD7477] = { + [ID_AD7467] = { .channel[0] = AD7476_CHAN(10), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, - [ID_AD7478] = { + [ID_AD7468] = { .channel[0] = AD7476_CHAN(8), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, [ID_AD7495] = { .channel[0] = AD7476_CHAN(12), .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), - .int_vref_mv = 2500, + .int_vref_uv = 2500000, + }, + [ID_AD7940] = { + .channel[0] = AD7940_CHAN(14), + .channel[1] = IIO_CHAN_SOFT_TIMESTAMP(1), }, }; @@ -123,10 +209,9 @@ static const struct iio_info ad7476_info = { static int __devinit ad7476_probe(struct spi_device *spi) { - struct ad7476_platform_data *pdata = spi->dev.platform_data; struct ad7476_state *st; struct iio_dev *indio_dev; - int ret, voltage_uv = 0; + int ret; indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) { @@ -134,25 +219,18 @@ static int __devinit ad7476_probe(struct spi_device *spi) goto error_ret; } st = iio_priv(indio_dev); - st->reg = regulator_get(&spi->dev, "vcc"); - if (!IS_ERR(st->reg)) { - ret = regulator_enable(st->reg); - if (ret) - goto error_put_reg; - - voltage_uv = regulator_get_voltage(st->reg); - } st->chip_info = &ad7476_chip_info_tbl[spi_get_device_id(spi)->driver_data]; - if (st->chip_info->int_vref_mv) - st->int_vref_mv = st->chip_info->int_vref_mv; - else if (pdata && pdata->vref_mv) - st->int_vref_mv = pdata->vref_mv; - else if (voltage_uv) - st->int_vref_mv = voltage_uv / 1000; - else - dev_warn(&spi->dev, "reference voltage unspecified\n"); + st->reg = regulator_get(&spi->dev, "vcc"); + if (IS_ERR(st->reg)) { + ret = PTR_ERR(st->reg); + goto error_free_dev; + } + + ret = regulator_enable(st->reg); + if (ret) + goto error_put_reg; spi_set_drvdata(spi, indio_dev); @@ -173,57 +251,67 @@ static int __devinit ad7476_probe(struct spi_device *spi) spi_message_init(&st->msg); spi_message_add_tail(&st->xfer, &st->msg); - ret = ad7476_register_ring_funcs_and_init(indio_dev); + ret = iio_triggered_buffer_setup(indio_dev, NULL, + &ad7476_trigger_handler, NULL); if (ret) goto error_disable_reg; + if (st->chip_info->reset) + st->chip_info->reset(st); + ret = iio_device_register(indio_dev); if (ret) goto error_ring_unregister; return 0; error_ring_unregister: - ad7476_ring_cleanup(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); error_disable_reg: - if (!IS_ERR(st->reg)) - regulator_disable(st->reg); + regulator_disable(st->reg); error_put_reg: - if (!IS_ERR(st->reg)) - regulator_put(st->reg); + regulator_put(st->reg); +error_free_dev: iio_device_free(indio_dev); error_ret: return ret; } -static int ad7476_remove(struct spi_device *spi) +static int __devexit ad7476_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct ad7476_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); - ad7476_ring_cleanup(indio_dev); - if (!IS_ERR(st->reg)) { - regulator_disable(st->reg); - regulator_put(st->reg); - } + iio_triggered_buffer_cleanup(indio_dev); + regulator_disable(st->reg); + regulator_put(st->reg); iio_device_free(indio_dev); return 0; } static const struct spi_device_id ad7476_id[] = { + {"ad7091r", ID_AD7091R}, + {"ad7273", ID_AD7277}, + {"ad7274", ID_AD7276}, + {"ad7276", ID_AD7276}, + {"ad7277", ID_AD7277}, + {"ad7278", ID_AD7278}, {"ad7466", ID_AD7466}, {"ad7467", ID_AD7467}, {"ad7468", ID_AD7468}, - {"ad7475", ID_AD7475}, - {"ad7476", ID_AD7476}, - {"ad7476a", ID_AD7476}, - {"ad7477", ID_AD7477}, - {"ad7477a", ID_AD7477}, - {"ad7478", ID_AD7478}, - {"ad7478a", ID_AD7478}, + {"ad7475", ID_AD7466}, + {"ad7476", ID_AD7466}, + {"ad7476a", ID_AD7466}, + {"ad7477", ID_AD7467}, + {"ad7477a", ID_AD7467}, + {"ad7478", ID_AD7468}, + {"ad7478a", ID_AD7468}, {"ad7495", ID_AD7495}, + {"ad7910", ID_AD7467}, + {"ad7920", ID_AD7466}, + {"ad7940", ID_AD7940}, {} }; MODULE_DEVICE_TABLE(spi, ad7476_id); @@ -240,5 +328,5 @@ static struct spi_driver ad7476_driver = { module_spi_driver(ad7476_driver); MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); -MODULE_DESCRIPTION("Analog Devices AD7475/6/7/8(A) AD7466/7/8 ADC"); +MODULE_DESCRIPTION("Analog Devices AD7476 and similar 1-channel ADCs"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/ad7791.c b/drivers/iio/adc/ad7791.c new file mode 100644 index 000000000000..e93740843b2b --- /dev/null +++ b/drivers/iio/adc/ad7791.c @@ -0,0 +1,460 @@ +/* + * AD7787/AD7788/AD7789/AD7790/AD7791 SPI ADC driver + * + * Copyright 2012 Analog Devices Inc. + * Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Licensed under the GPL-2. + */ + +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/sysfs.h> +#include <linux/spi/spi.h> +#include <linux/regulator/consumer.h> +#include <linux/err.h> +#include <linux/sched.h> +#include <linux/delay.h> +#include <linux/module.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/iio/adc/ad_sigma_delta.h> + +#include <linux/platform_data/ad7791.h> + +#define AD7791_REG_COMM 0x0 /* For writes */ +#define AD7791_REG_STATUS 0x0 /* For reads */ +#define AD7791_REG_MODE 0x1 +#define AD7791_REG_FILTER 0x2 +#define AD7791_REG_DATA 0x3 + +#define AD7791_MODE_CONTINUOUS 0x00 +#define AD7791_MODE_SINGLE 0x02 +#define AD7791_MODE_POWERDOWN 0x03 + +#define AD7791_CH_AIN1P_AIN1N 0x00 +#define AD7791_CH_AIN2 0x01 +#define AD7791_CH_AIN1N_AIN1N 0x02 +#define AD7791_CH_AVDD_MONITOR 0x03 + +#define AD7791_FILTER_CLK_DIV_1 (0x0 << 4) +#define AD7791_FILTER_CLK_DIV_2 (0x1 << 4) +#define AD7791_FILTER_CLK_DIV_4 (0x2 << 4) +#define AD7791_FILTER_CLK_DIV_8 (0x3 << 4) +#define AD7791_FILTER_CLK_MASK (0x3 << 4) +#define AD7791_FILTER_RATE_120 0x0 +#define AD7791_FILTER_RATE_100 0x1 +#define AD7791_FILTER_RATE_33_3 0x2 +#define AD7791_FILTER_RATE_20 0x3 +#define AD7791_FILTER_RATE_16_6 0x4 +#define AD7791_FILTER_RATE_16_7 0x5 +#define AD7791_FILTER_RATE_13_3 0x6 +#define AD7791_FILTER_RATE_9_5 0x7 +#define AD7791_FILTER_RATE_MASK 0x7 + +#define AD7791_MODE_BUFFER BIT(1) +#define AD7791_MODE_UNIPOLAR BIT(2) +#define AD7791_MODE_BURNOUT BIT(3) +#define AD7791_MODE_SEL_MASK (0x3 << 6) +#define AD7791_MODE_SEL(x) ((x) << 6) + +#define DECLARE_AD7787_CHANNELS(name, bits, storagebits) \ +const struct iio_chan_spec name[] = { \ + AD_SD_DIFF_CHANNEL(0, 0, 0, AD7791_CH_AIN1P_AIN1N, \ + (bits), (storagebits), 0), \ + AD_SD_CHANNEL(1, 1, AD7791_CH_AIN2, (bits), (storagebits), 0), \ + AD_SD_SHORTED_CHANNEL(2, 0, AD7791_CH_AIN1N_AIN1N, \ + (bits), (storagebits), 0), \ + AD_SD_SUPPLY_CHANNEL(3, 2, AD7791_CH_AVDD_MONITOR, \ + (bits), (storagebits), 0), \ + IIO_CHAN_SOFT_TIMESTAMP(4), \ +} + +#define DECLARE_AD7791_CHANNELS(name, bits, storagebits) \ +const struct iio_chan_spec name[] = { \ + AD_SD_DIFF_CHANNEL(0, 0, 0, AD7791_CH_AIN1P_AIN1N, \ + (bits), (storagebits), 0), \ + AD_SD_SHORTED_CHANNEL(1, 0, AD7791_CH_AIN1N_AIN1N, \ + (bits), (storagebits), 0), \ + AD_SD_SUPPLY_CHANNEL(2, 1, AD7791_CH_AVDD_MONITOR, \ + (bits), (storagebits), 0), \ + IIO_CHAN_SOFT_TIMESTAMP(3), \ +} + +static DECLARE_AD7787_CHANNELS(ad7787_channels, 24, 32); +static DECLARE_AD7791_CHANNELS(ad7790_channels, 16, 16); +static DECLARE_AD7791_CHANNELS(ad7791_channels, 24, 32); + +enum { + AD7787, + AD7788, + AD7789, + AD7790, + AD7791, +}; + +enum ad7791_chip_info_flags { + AD7791_FLAG_HAS_FILTER = (1 << 0), + AD7791_FLAG_HAS_BUFFER = (1 << 1), + AD7791_FLAG_HAS_UNIPOLAR = (1 << 2), + AD7791_FLAG_HAS_BURNOUT = (1 << 3), +}; + +struct ad7791_chip_info { + const struct iio_chan_spec *channels; + unsigned int num_channels; + enum ad7791_chip_info_flags flags; +}; + +static const struct ad7791_chip_info ad7791_chip_infos[] = { + [AD7787] = { + .channels = ad7787_channels, + .num_channels = ARRAY_SIZE(ad7787_channels), + .flags = AD7791_FLAG_HAS_FILTER | AD7791_FLAG_HAS_BUFFER | + AD7791_FLAG_HAS_UNIPOLAR | AD7791_FLAG_HAS_BURNOUT, + }, + [AD7788] = { + .channels = ad7790_channels, + .num_channels = ARRAY_SIZE(ad7790_channels), + .flags = AD7791_FLAG_HAS_UNIPOLAR, + }, + [AD7789] = { + .channels = ad7791_channels, + .num_channels = ARRAY_SIZE(ad7791_channels), + .flags = AD7791_FLAG_HAS_UNIPOLAR, + }, + [AD7790] = { + .channels = ad7790_channels, + .num_channels = ARRAY_SIZE(ad7790_channels), + .flags = AD7791_FLAG_HAS_FILTER | AD7791_FLAG_HAS_BUFFER | + AD7791_FLAG_HAS_BURNOUT, + }, + [AD7791] = { + .channels = ad7791_channels, + .num_channels = ARRAY_SIZE(ad7791_channels), + .flags = AD7791_FLAG_HAS_FILTER | AD7791_FLAG_HAS_BUFFER | + AD7791_FLAG_HAS_UNIPOLAR | AD7791_FLAG_HAS_BURNOUT, + }, +}; + +struct ad7791_state { + struct ad_sigma_delta sd; + uint8_t mode; + uint8_t filter; + + struct regulator *reg; + const struct ad7791_chip_info *info; +}; + +static struct ad7791_state *ad_sigma_delta_to_ad7791(struct ad_sigma_delta *sd) +{ + return container_of(sd, struct ad7791_state, sd); +} + +static int ad7791_set_channel(struct ad_sigma_delta *sd, unsigned int channel) +{ + ad_sd_set_comm(sd, channel); + + return 0; +} + +static int ad7791_set_mode(struct ad_sigma_delta *sd, + enum ad_sigma_delta_mode mode) +{ + struct ad7791_state *st = ad_sigma_delta_to_ad7791(sd); + + switch (mode) { + case AD_SD_MODE_CONTINUOUS: + mode = AD7791_MODE_CONTINUOUS; + break; + case AD_SD_MODE_SINGLE: + mode = AD7791_MODE_SINGLE; + break; + case AD_SD_MODE_IDLE: + case AD_SD_MODE_POWERDOWN: + mode = AD7791_MODE_POWERDOWN; + break; + } + + st->mode &= ~AD7791_MODE_SEL_MASK; + st->mode |= AD7791_MODE_SEL(mode); + + return ad_sd_write_reg(sd, AD7791_REG_MODE, sizeof(st->mode), st->mode); +} + +static const struct ad_sigma_delta_info ad7791_sigma_delta_info = { + .set_channel = ad7791_set_channel, + .set_mode = ad7791_set_mode, + .has_registers = true, + .addr_shift = 4, + .read_mask = BIT(3), +}; + +static int ad7791_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, int *val, int *val2, long info) +{ + struct ad7791_state *st = iio_priv(indio_dev); + bool unipolar = !!(st->mode & AD7791_MODE_UNIPOLAR); + unsigned long long scale_pv; + + switch (info) { + case IIO_CHAN_INFO_RAW: + return ad_sigma_delta_single_conversion(indio_dev, chan, val); + case IIO_CHAN_INFO_OFFSET: + /** + * Unipolar: 0 to VREF + * Bipolar -VREF to VREF + **/ + if (unipolar) + *val = 0; + else + *val = -(1 << (chan->scan_type.realbits - 1)); + return IIO_VAL_INT; + case IIO_CHAN_INFO_SCALE: + /* The monitor channel uses an internal reference. */ + if (chan->address == AD7791_CH_AVDD_MONITOR) { + scale_pv = 5850000000000ULL; + } else { + int voltage_uv; + + voltage_uv = regulator_get_voltage(st->reg); + if (voltage_uv < 0) + return voltage_uv; + scale_pv = (unsigned long long)voltage_uv * 1000000; + } + if (unipolar) + scale_pv >>= chan->scan_type.realbits; + else + scale_pv >>= chan->scan_type.realbits - 1; + *val2 = do_div(scale_pv, 1000000000); + *val = scale_pv; + + return IIO_VAL_INT_PLUS_NANO; + } + + return -EINVAL; +} + +static const char * const ad7791_sample_freq_avail[] = { + [AD7791_FILTER_RATE_120] = "120", + [AD7791_FILTER_RATE_100] = "100", + [AD7791_FILTER_RATE_33_3] = "33.3", + [AD7791_FILTER_RATE_20] = "20", + [AD7791_FILTER_RATE_16_6] = "16.6", + [AD7791_FILTER_RATE_16_7] = "16.7", + [AD7791_FILTER_RATE_13_3] = "13.3", + [AD7791_FILTER_RATE_9_5] = "9.5", +}; + +static ssize_t ad7791_read_frequency(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct ad7791_state *st = iio_priv(indio_dev); + unsigned int rate = st->filter & AD7791_FILTER_RATE_MASK; + + return sprintf(buf, "%s\n", ad7791_sample_freq_avail[rate]); +} + +static ssize_t ad7791_write_frequency(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct ad7791_state *st = iio_priv(indio_dev); + int i, ret; + + mutex_lock(&indio_dev->mlock); + if (iio_buffer_enabled(indio_dev)) { + mutex_unlock(&indio_dev->mlock); + return -EBUSY; + } + mutex_unlock(&indio_dev->mlock); + + ret = -EINVAL; + + for (i = 0; i < ARRAY_SIZE(ad7791_sample_freq_avail); i++) { + if (sysfs_streq(ad7791_sample_freq_avail[i], buf)) { + + mutex_lock(&indio_dev->mlock); + st->filter &= ~AD7791_FILTER_RATE_MASK; + st->filter |= i; + ad_sd_write_reg(&st->sd, AD7791_REG_FILTER, + sizeof(st->filter), st->filter); + mutex_unlock(&indio_dev->mlock); + ret = 0; + break; + } + } + + return ret ? ret : len; +} + +static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, + ad7791_read_frequency, + ad7791_write_frequency); + +static IIO_CONST_ATTR_SAMP_FREQ_AVAIL("120 100 33.3 20 16.7 16.6 13.3 9.5"); + +static struct attribute *ad7791_attributes[] = { + &iio_dev_attr_sampling_frequency.dev_attr.attr, + &iio_const_attr_sampling_frequency_available.dev_attr.attr, + NULL +}; + +static const struct attribute_group ad7791_attribute_group = { + .attrs = ad7791_attributes, +}; + +static const struct iio_info ad7791_info = { + .read_raw = &ad7791_read_raw, + .attrs = &ad7791_attribute_group, + .validate_trigger = ad_sd_validate_trigger, + .driver_module = THIS_MODULE, +}; + +static const struct iio_info ad7791_no_filter_info = { + .read_raw = &ad7791_read_raw, + .validate_trigger = ad_sd_validate_trigger, + .driver_module = THIS_MODULE, +}; + +static int __devinit ad7791_setup(struct ad7791_state *st, + struct ad7791_platform_data *pdata) +{ + /* Set to poweron-reset default values */ + st->mode = AD7791_MODE_BUFFER; + st->filter = AD7791_FILTER_RATE_16_6; + + if (!pdata) + return 0; + + if ((st->info->flags & AD7791_FLAG_HAS_BUFFER) && !pdata->buffered) + st->mode &= ~AD7791_MODE_BUFFER; + + if ((st->info->flags & AD7791_FLAG_HAS_BURNOUT) && + pdata->burnout_current) + st->mode |= AD7791_MODE_BURNOUT; + + if ((st->info->flags & AD7791_FLAG_HAS_UNIPOLAR) && pdata->unipolar) + st->mode |= AD7791_MODE_UNIPOLAR; + + return ad_sd_write_reg(&st->sd, AD7791_REG_MODE, sizeof(st->mode), + st->mode); +} + +static int __devinit ad7791_probe(struct spi_device *spi) +{ + struct ad7791_platform_data *pdata = spi->dev.platform_data; + struct iio_dev *indio_dev; + struct ad7791_state *st; + int ret; + + if (!spi->irq) { + dev_err(&spi->dev, "Missing IRQ.\n"); + return -ENXIO; + } + + indio_dev = iio_device_alloc(sizeof(*st)); + if (!indio_dev) + return -ENOMEM; + + st = iio_priv(indio_dev); + + st->reg = regulator_get(&spi->dev, "refin"); + if (IS_ERR(st->reg)) { + ret = PTR_ERR(st->reg); + goto err_iio_free; + } + + ret = regulator_enable(st->reg); + if (ret) + goto error_put_reg; + + st->info = &ad7791_chip_infos[spi_get_device_id(spi)->driver_data]; + ad_sd_init(&st->sd, indio_dev, spi, &ad7791_sigma_delta_info); + + spi_set_drvdata(spi, indio_dev); + + indio_dev->dev.parent = &spi->dev; + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->channels = st->info->channels; + indio_dev->num_channels = st->info->num_channels; + if (st->info->flags & AD7791_FLAG_HAS_FILTER) + indio_dev->info = &ad7791_info; + else + indio_dev->info = &ad7791_no_filter_info; + + ret = ad_sd_setup_buffer_and_trigger(indio_dev); + if (ret) + goto error_disable_reg; + + ret = ad7791_setup(st, pdata); + if (ret) + goto error_remove_trigger; + + ret = iio_device_register(indio_dev); + if (ret) + goto error_remove_trigger; + + return 0; + +error_remove_trigger: + ad_sd_cleanup_buffer_and_trigger(indio_dev); +error_disable_reg: + regulator_disable(st->reg); +error_put_reg: + regulator_put(st->reg); +err_iio_free: + iio_device_free(indio_dev); + + return ret; +} + +static int __devexit ad7791_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct ad7791_state *st = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + ad_sd_cleanup_buffer_and_trigger(indio_dev); + + regulator_disable(st->reg); + regulator_put(st->reg); + + iio_device_free(indio_dev); + + return 0; +} + +static const struct spi_device_id ad7791_spi_ids[] = { + { "ad7787", AD7787 }, + { "ad7788", AD7788 }, + { "ad7789", AD7789 }, + { "ad7790", AD7790 }, + { "ad7791", AD7791 }, + {} +}; +MODULE_DEVICE_TABLE(spi, ad7791_spi_ids); + +static struct spi_driver ad7791_driver = { + .driver = { + .name = "ad7791", + .owner = THIS_MODULE, + }, + .probe = ad7791_probe, + .remove = __devexit_p(ad7791_remove), + .id_table = ad7791_spi_ids, +}; +module_spi_driver(ad7791_driver); + +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("Analog Device AD7787/AD7788/AD7789/AD7790/AD7791 ADC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/ad_sigma_delta.c b/drivers/iio/adc/ad_sigma_delta.c new file mode 100644 index 000000000000..67baa1363d7a --- /dev/null +++ b/drivers/iio/adc/ad_sigma_delta.c @@ -0,0 +1,558 @@ +/* + * Support code for Analog Devices Sigma-Delta ADCs + * + * Copyright 2012 Analog Devices Inc. + * Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Licensed under the GPL-2. + */ + +#include <linux/interrupt.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/spi/spi.h> +#include <linux/err.h> +#include <linux/module.h> + +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> +#include <linux/iio/adc/ad_sigma_delta.h> + +#include <asm/unaligned.h> + + +#define AD_SD_COMM_CHAN_MASK 0x3 + +#define AD_SD_REG_COMM 0x00 +#define AD_SD_REG_DATA 0x03 + +/** + * ad_sd_set_comm() - Set communications register + * + * @sigma_delta: The sigma delta device + * @comm: New value for the communications register + */ +void ad_sd_set_comm(struct ad_sigma_delta *sigma_delta, uint8_t comm) +{ + /* Some variants use the lower two bits of the communications register + * to select the channel */ + sigma_delta->comm = comm & AD_SD_COMM_CHAN_MASK; +} +EXPORT_SYMBOL_GPL(ad_sd_set_comm); + +/** + * ad_sd_write_reg() - Write a register + * + * @sigma_delta: The sigma delta device + * @reg: Address of the register + * @size: Size of the register (0-3) + * @val: Value to write to the register + * + * Returns 0 on success, an error code otherwise. + **/ +int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg, + unsigned int size, unsigned int val) +{ + uint8_t *data = sigma_delta->data; + struct spi_transfer t = { + .tx_buf = data, + .len = size + 1, + .cs_change = sigma_delta->bus_locked, + }; + struct spi_message m; + int ret; + + data[0] = (reg << sigma_delta->info->addr_shift) | sigma_delta->comm; + + switch (size) { + case 3: + data[1] = val >> 16; + data[2] = val >> 8; + data[3] = val; + break; + case 2: + put_unaligned_be16(val, &data[1]); + break; + case 1: + data[1] = val; + break; + case 0: + break; + default: + return -EINVAL; + } + + spi_message_init(&m); + spi_message_add_tail(&t, &m); + + if (sigma_delta->bus_locked) + ret = spi_sync_locked(sigma_delta->spi, &m); + else + ret = spi_sync(sigma_delta->spi, &m); + + return ret; +} +EXPORT_SYMBOL_GPL(ad_sd_write_reg); + +static int ad_sd_read_reg_raw(struct ad_sigma_delta *sigma_delta, + unsigned int reg, unsigned int size, uint8_t *val) +{ + uint8_t *data = sigma_delta->data; + int ret; + struct spi_transfer t[] = { + { + .tx_buf = data, + .len = 1, + }, { + .rx_buf = val, + .len = size, + .cs_change = sigma_delta->bus_locked, + }, + }; + struct spi_message m; + + spi_message_init(&m); + + if (sigma_delta->info->has_registers) { + data[0] = reg << sigma_delta->info->addr_shift; + data[0] |= sigma_delta->info->read_mask; + spi_message_add_tail(&t[0], &m); + } + spi_message_add_tail(&t[1], &m); + + if (sigma_delta->bus_locked) + ret = spi_sync_locked(sigma_delta->spi, &m); + else + ret = spi_sync(sigma_delta->spi, &m); + + return ret; +} + +/** + * ad_sd_read_reg() - Read a register + * + * @sigma_delta: The sigma delta device + * @reg: Address of the register + * @size: Size of the register (1-4) + * @val: Read value + * + * Returns 0 on success, an error code otherwise. + **/ +int ad_sd_read_reg(struct ad_sigma_delta *sigma_delta, + unsigned int reg, unsigned int size, unsigned int *val) +{ + int ret; + + ret = ad_sd_read_reg_raw(sigma_delta, reg, size, sigma_delta->data); + if (ret < 0) + goto out; + + switch (size) { + case 4: + *val = get_unaligned_be32(sigma_delta->data); + break; + case 3: + *val = (sigma_delta->data[0] << 16) | + (sigma_delta->data[1] << 8) | + sigma_delta->data[2]; + break; + case 2: + *val = get_unaligned_be16(sigma_delta->data); + break; + case 1: + *val = sigma_delta->data[0]; + break; + default: + ret = -EINVAL; + break; + } + +out: + return ret; +} +EXPORT_SYMBOL_GPL(ad_sd_read_reg); + +static int ad_sd_calibrate(struct ad_sigma_delta *sigma_delta, + unsigned int mode, unsigned int channel) +{ + int ret; + + ret = ad_sigma_delta_set_channel(sigma_delta, channel); + if (ret) + return ret; + + spi_bus_lock(sigma_delta->spi->master); + sigma_delta->bus_locked = true; + INIT_COMPLETION(sigma_delta->completion); + + ret = ad_sigma_delta_set_mode(sigma_delta, mode); + if (ret < 0) + goto out; + + sigma_delta->irq_dis = false; + enable_irq(sigma_delta->spi->irq); + ret = wait_for_completion_timeout(&sigma_delta->completion, 2*HZ); + if (ret == 0) { + sigma_delta->irq_dis = true; + disable_irq_nosync(sigma_delta->spi->irq); + ret = -EIO; + } else { + ret = 0; + } +out: + sigma_delta->bus_locked = false; + spi_bus_unlock(sigma_delta->spi->master); + ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); + + return ret; +} + +/** + * ad_sd_calibrate_all() - Performs channel calibration + * @sigma_delta: The sigma delta device + * @cb: Array of channels and calibration type to perform + * @n: Number of items in cb + * + * Returns 0 on success, an error code otherwise. + **/ +int ad_sd_calibrate_all(struct ad_sigma_delta *sigma_delta, + const struct ad_sd_calib_data *cb, unsigned int n) +{ + unsigned int i; + int ret; + + for (i = 0; i < n; i++) { + ret = ad_sd_calibrate(sigma_delta, cb[i].mode, cb[i].channel); + if (ret) + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(ad_sd_calibrate_all); + +/** + * ad_sigma_delta_single_conversion() - Performs a single data conversion + * @indio_dev: The IIO device + * @chan: The conversion is done for this channel + * @val: Pointer to the location where to store the read value + * + * Returns: 0 on success, an error value otherwise. + */ +int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, int *val) +{ + struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); + unsigned int sample, raw_sample; + int ret = 0; + + if (iio_buffer_enabled(indio_dev)) + return -EBUSY; + + mutex_lock(&indio_dev->mlock); + ad_sigma_delta_set_channel(sigma_delta, chan->address); + + spi_bus_lock(sigma_delta->spi->master); + sigma_delta->bus_locked = true; + INIT_COMPLETION(sigma_delta->completion); + + ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_SINGLE); + + sigma_delta->irq_dis = false; + enable_irq(sigma_delta->spi->irq); + ret = wait_for_completion_interruptible_timeout( + &sigma_delta->completion, HZ); + + sigma_delta->bus_locked = false; + spi_bus_unlock(sigma_delta->spi->master); + + if (ret == 0) + ret = -EIO; + if (ret < 0) + goto out; + + ret = ad_sd_read_reg(sigma_delta, AD_SD_REG_DATA, + DIV_ROUND_UP(chan->scan_type.realbits + chan->scan_type.shift, 8), + &raw_sample); + +out: + if (!sigma_delta->irq_dis) { + disable_irq_nosync(sigma_delta->spi->irq); + sigma_delta->irq_dis = true; + } + + ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); + mutex_unlock(&indio_dev->mlock); + + if (ret) + return ret; + + sample = raw_sample >> chan->scan_type.shift; + sample &= (1 << chan->scan_type.realbits) - 1; + *val = sample; + + ret = ad_sigma_delta_postprocess_sample(sigma_delta, raw_sample); + if (ret) + return ret; + + return IIO_VAL_INT; +} +EXPORT_SYMBOL_GPL(ad_sigma_delta_single_conversion); + +static int ad_sd_buffer_postenable(struct iio_dev *indio_dev) +{ + struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); + unsigned int channel; + int ret; + + ret = iio_triggered_buffer_postenable(indio_dev); + if (ret < 0) + return ret; + + channel = find_first_bit(indio_dev->active_scan_mask, + indio_dev->masklength); + ret = ad_sigma_delta_set_channel(sigma_delta, + indio_dev->channels[channel].address); + if (ret) + goto err_predisable; + + spi_bus_lock(sigma_delta->spi->master); + sigma_delta->bus_locked = true; + ret = ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_CONTINUOUS); + if (ret) + goto err_unlock; + + sigma_delta->irq_dis = false; + enable_irq(sigma_delta->spi->irq); + + return 0; + +err_unlock: + spi_bus_unlock(sigma_delta->spi->master); +err_predisable: + + return ret; +} + +static int ad_sd_buffer_postdisable(struct iio_dev *indio_dev) +{ + struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); + + INIT_COMPLETION(sigma_delta->completion); + wait_for_completion_timeout(&sigma_delta->completion, HZ); + + if (!sigma_delta->irq_dis) { + disable_irq_nosync(sigma_delta->spi->irq); + sigma_delta->irq_dis = true; + } + + ad_sigma_delta_set_mode(sigma_delta, AD_SD_MODE_IDLE); + + sigma_delta->bus_locked = false; + return spi_bus_unlock(sigma_delta->spi->master); +} + +static irqreturn_t ad_sd_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *indio_dev = pf->indio_dev; + struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); + unsigned int reg_size; + uint8_t data[16]; + int ret; + + memset(data, 0x00, 16); + + /* Guaranteed to be aligned with 8 byte boundary */ + if (indio_dev->scan_timestamp) + ((s64 *)data)[1] = pf->timestamp; + + reg_size = indio_dev->channels[0].scan_type.realbits + + indio_dev->channels[0].scan_type.shift; + reg_size = DIV_ROUND_UP(reg_size, 8); + + switch (reg_size) { + case 4: + case 2: + case 1: + ret = ad_sd_read_reg_raw(sigma_delta, AD_SD_REG_DATA, + reg_size, &data[0]); + break; + case 3: + /* We store 24 bit samples in a 32 bit word. Keep the upper + * byte set to zero. */ + ret = ad_sd_read_reg_raw(sigma_delta, AD_SD_REG_DATA, + reg_size, &data[1]); + break; + } + + iio_push_to_buffer(indio_dev->buffer, (uint8_t *)data); + + iio_trigger_notify_done(indio_dev->trig); + sigma_delta->irq_dis = false; + enable_irq(sigma_delta->spi->irq); + + return IRQ_HANDLED; +} + +static const struct iio_buffer_setup_ops ad_sd_buffer_setup_ops = { + .preenable = &iio_sw_buffer_preenable, + .postenable = &ad_sd_buffer_postenable, + .predisable = &iio_triggered_buffer_predisable, + .postdisable = &ad_sd_buffer_postdisable, + .validate_scan_mask = &iio_validate_scan_mask_onehot, +}; + +static irqreturn_t ad_sd_data_rdy_trig_poll(int irq, void *private) +{ + struct ad_sigma_delta *sigma_delta = private; + + complete(&sigma_delta->completion); + disable_irq_nosync(irq); + sigma_delta->irq_dis = true; + iio_trigger_poll(sigma_delta->trig, iio_get_time_ns()); + + return IRQ_HANDLED; +} + +/** + * ad_sd_validate_trigger() - validate_trigger callback for ad_sigma_delta devices + * @indio_dev: The IIO device + * @trig: The new trigger + * + * Returns: 0 if the 'trig' matches the trigger registered by the ad_sigma_delta + * device, -EINVAL otherwise. + */ +int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig) +{ + struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); + + if (sigma_delta->trig != trig) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL_GPL(ad_sd_validate_trigger); + +static const struct iio_trigger_ops ad_sd_trigger_ops = { + .owner = THIS_MODULE, +}; + +static int ad_sd_probe_trigger(struct iio_dev *indio_dev) +{ + struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); + int ret; + + sigma_delta->trig = iio_trigger_alloc("%s-dev%d", indio_dev->name, + indio_dev->id); + if (sigma_delta->trig == NULL) { + ret = -ENOMEM; + goto error_ret; + } + sigma_delta->trig->ops = &ad_sd_trigger_ops; + init_completion(&sigma_delta->completion); + + ret = request_irq(sigma_delta->spi->irq, + ad_sd_data_rdy_trig_poll, + IRQF_TRIGGER_LOW, + indio_dev->name, + sigma_delta); + if (ret) + goto error_free_trig; + + if (!sigma_delta->irq_dis) { + sigma_delta->irq_dis = true; + disable_irq_nosync(sigma_delta->spi->irq); + } + sigma_delta->trig->dev.parent = &sigma_delta->spi->dev; + sigma_delta->trig->private_data = sigma_delta; + + ret = iio_trigger_register(sigma_delta->trig); + if (ret) + goto error_free_irq; + + /* select default trigger */ + indio_dev->trig = sigma_delta->trig; + + return 0; + +error_free_irq: + free_irq(sigma_delta->spi->irq, sigma_delta); +error_free_trig: + iio_trigger_free(sigma_delta->trig); +error_ret: + return ret; +} + +static void ad_sd_remove_trigger(struct iio_dev *indio_dev) +{ + struct ad_sigma_delta *sigma_delta = iio_device_get_drvdata(indio_dev); + + iio_trigger_unregister(sigma_delta->trig); + free_irq(sigma_delta->spi->irq, sigma_delta); + iio_trigger_free(sigma_delta->trig); +} + +/** + * ad_sd_setup_buffer_and_trigger() - + * @indio_dev: The IIO device + */ +int ad_sd_setup_buffer_and_trigger(struct iio_dev *indio_dev) +{ + int ret; + + ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + &ad_sd_trigger_handler, &ad_sd_buffer_setup_ops); + if (ret) + return ret; + + ret = ad_sd_probe_trigger(indio_dev); + if (ret) { + iio_triggered_buffer_cleanup(indio_dev); + return ret; + } + + return 0; +} +EXPORT_SYMBOL_GPL(ad_sd_setup_buffer_and_trigger); + +/** + * ad_sd_cleanup_buffer_and_trigger() - + * @indio_dev: The IIO device + */ +void ad_sd_cleanup_buffer_and_trigger(struct iio_dev *indio_dev) +{ + ad_sd_remove_trigger(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); +} +EXPORT_SYMBOL_GPL(ad_sd_cleanup_buffer_and_trigger); + +/** + * ad_sd_init() - Initializes a ad_sigma_delta struct + * @sigma_delta: The ad_sigma_delta device + * @indio_dev: The IIO device which the Sigma Delta device is used for + * @spi: The SPI device for the ad_sigma_delta device + * @info: Device specific callbacks and options + * + * This function needs to be called before any other operations are performed on + * the ad_sigma_delta struct. + */ +int ad_sd_init(struct ad_sigma_delta *sigma_delta, struct iio_dev *indio_dev, + struct spi_device *spi, const struct ad_sigma_delta_info *info) +{ + sigma_delta->spi = spi; + sigma_delta->info = info; + iio_device_set_drvdata(indio_dev, sigma_delta); + + return 0; +} +EXPORT_SYMBOL_GPL(ad_sd_init); + +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("Analog Devices Sigma-Delta ADCs"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c index 3bd5540238a7..3ed94bf80596 100644 --- a/drivers/iio/adc/at91_adc.c +++ b/drivers/iio/adc/at91_adc.c @@ -82,7 +82,7 @@ static irqreturn_t at91_adc_trigger_handler(int irq, void *p) *timestamp = pf->timestamp; } - buffer->access->store_to(buffer, (u8 *)st->buffer, pf->timestamp); + buffer->access->store_to(buffer, (u8 *)st->buffer); iio_trigger_notify_done(idev->trig); st->irq_enabled = true; @@ -545,13 +545,6 @@ static int __devinit at91_adc_probe(struct platform_device *pdev) goto error_free_device; } - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - dev_err(&pdev->dev, "No resource defined\n"); - ret = -ENXIO; - goto error_ret; - } - platform_set_drvdata(pdev, idev); idev->dev.parent = &pdev->dev; @@ -566,18 +559,12 @@ static int __devinit at91_adc_probe(struct platform_device *pdev) goto error_free_device; } - if (!request_mem_region(res->start, resource_size(res), - "AT91 adc registers")) { - dev_err(&pdev->dev, "Resources are unavailable.\n"); - ret = -EBUSY; - goto error_free_device; - } + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - st->reg_base = ioremap(res->start, resource_size(res)); + st->reg_base = devm_request_and_ioremap(&pdev->dev, res); if (!st->reg_base) { - dev_err(&pdev->dev, "Failed to map registers.\n"); ret = -ENOMEM; - goto error_release_mem; + goto error_free_device; } /* @@ -592,45 +579,35 @@ static int __devinit at91_adc_probe(struct platform_device *pdev) idev); if (ret) { dev_err(&pdev->dev, "Failed to allocate IRQ.\n"); - goto error_unmap_reg; + goto error_free_device; } - st->clk = clk_get(&pdev->dev, "adc_clk"); + st->clk = devm_clk_get(&pdev->dev, "adc_clk"); if (IS_ERR(st->clk)) { dev_err(&pdev->dev, "Failed to get the clock.\n"); ret = PTR_ERR(st->clk); goto error_free_irq; } - ret = clk_prepare(st->clk); + ret = clk_prepare_enable(st->clk); if (ret) { - dev_err(&pdev->dev, "Could not prepare the clock.\n"); - goto error_free_clk; - } - - ret = clk_enable(st->clk); - if (ret) { - dev_err(&pdev->dev, "Could not enable the clock.\n"); - goto error_unprepare_clk; + dev_err(&pdev->dev, + "Could not prepare or enable the clock.\n"); + goto error_free_irq; } - st->adc_clk = clk_get(&pdev->dev, "adc_op_clk"); + st->adc_clk = devm_clk_get(&pdev->dev, "adc_op_clk"); if (IS_ERR(st->adc_clk)) { dev_err(&pdev->dev, "Failed to get the ADC clock.\n"); ret = PTR_ERR(st->adc_clk); goto error_disable_clk; } - ret = clk_prepare(st->adc_clk); + ret = clk_prepare_enable(st->adc_clk); if (ret) { - dev_err(&pdev->dev, "Could not prepare the ADC clock.\n"); - goto error_free_adc_clk; - } - - ret = clk_enable(st->adc_clk); - if (ret) { - dev_err(&pdev->dev, "Could not enable the ADC clock.\n"); - goto error_unprepare_adc_clk; + dev_err(&pdev->dev, + "Could not prepare or enable the ADC clock.\n"); + goto error_disable_clk; } /* @@ -694,23 +671,11 @@ error_remove_triggers: error_unregister_buffer: at91_adc_buffer_remove(idev); error_disable_adc_clk: - clk_disable(st->adc_clk); -error_unprepare_adc_clk: - clk_unprepare(st->adc_clk); -error_free_adc_clk: - clk_put(st->adc_clk); + clk_disable_unprepare(st->adc_clk); error_disable_clk: - clk_disable(st->clk); -error_unprepare_clk: - clk_unprepare(st->clk); -error_free_clk: - clk_put(st->clk); + clk_disable_unprepare(st->clk); error_free_irq: free_irq(st->irq, idev); -error_unmap_reg: - iounmap(st->reg_base); -error_release_mem: - release_mem_region(res->start, resource_size(res)); error_free_device: iio_device_free(idev); error_ret: @@ -720,20 +685,14 @@ error_ret: static int __devexit at91_adc_remove(struct platform_device *pdev) { struct iio_dev *idev = platform_get_drvdata(pdev); - struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0); struct at91_adc_state *st = iio_priv(idev); iio_device_unregister(idev); at91_adc_trigger_remove(idev); at91_adc_buffer_remove(idev); clk_disable_unprepare(st->adc_clk); - clk_put(st->adc_clk); - clk_disable(st->clk); - clk_unprepare(st->clk); - clk_put(st->clk); + clk_disable_unprepare(st->clk); free_irq(st->irq, idev); - iounmap(st->reg_base); - release_mem_region(res->start, resource_size(res)); iio_device_free(idev); return 0; diff --git a/drivers/iio/adc/lp8788_adc.c b/drivers/iio/adc/lp8788_adc.c new file mode 100644 index 000000000000..a93aaf0bb841 --- /dev/null +++ b/drivers/iio/adc/lp8788_adc.c @@ -0,0 +1,264 @@ +/* + * TI LP8788 MFD - ADC driver + * + * Copyright 2012 Texas Instruments + * + * Author: Milo(Woogyom) Kim <milo.kim@ti.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#include <linux/delay.h> +#include <linux/iio/iio.h> +#include <linux/iio/driver.h> +#include <linux/iio/machine.h> +#include <linux/mfd/lp8788.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/platform_device.h> +#include <linux/slab.h> + +/* register address */ +#define LP8788_ADC_CONF 0x60 +#define LP8788_ADC_RAW 0x61 +#define LP8788_ADC_DONE 0x63 + +#define ADC_CONV_START 1 + +struct lp8788_adc { + struct lp8788 *lp; + struct iio_map *map; + struct mutex lock; +}; + +static const int lp8788_scale[LPADC_MAX] = { + [LPADC_VBATT_5P5] = 1343101, + [LPADC_VIN_CHG] = 3052503, + [LPADC_IBATT] = 610500, + [LPADC_IC_TEMP] = 61050, + [LPADC_VBATT_6P0] = 1465201, + [LPADC_VBATT_5P0] = 1221001, + [LPADC_ADC1] = 610500, + [LPADC_ADC2] = 610500, + [LPADC_VDD] = 1025641, + [LPADC_VCOIN] = 757020, + [LPADC_ADC3] = 610500, + [LPADC_ADC4] = 610500, +}; + +static int lp8788_get_adc_result(struct lp8788_adc *adc, enum lp8788_adc_id id, + int *val) +{ + unsigned int msb; + unsigned int lsb; + unsigned int result; + u8 data; + u8 rawdata[2]; + int size = ARRAY_SIZE(rawdata); + int retry = 5; + int ret; + + data = (id << 1) | ADC_CONV_START; + ret = lp8788_write_byte(adc->lp, LP8788_ADC_CONF, data); + if (ret) + goto err_io; + + /* retry until adc conversion is done */ + data = 0; + while (retry--) { + usleep_range(100, 200); + + ret = lp8788_read_byte(adc->lp, LP8788_ADC_DONE, &data); + if (ret) + goto err_io; + + /* conversion done */ + if (data) + break; + } + + ret = lp8788_read_multi_bytes(adc->lp, LP8788_ADC_RAW, rawdata, size); + if (ret) + goto err_io; + + msb = (rawdata[0] << 4) & 0x00000ff0; + lsb = (rawdata[1] >> 4) & 0x0000000f; + result = msb | lsb; + *val = result; + + return 0; + +err_io: + return ret; +} + +static int lp8788_adc_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, long mask) +{ + struct lp8788_adc *adc = iio_priv(indio_dev); + enum lp8788_adc_id id = chan->channel; + int ret; + + mutex_lock(&adc->lock); + + switch (mask) { + case IIO_CHAN_INFO_RAW: + ret = lp8788_get_adc_result(adc, id, val) ? -EIO : IIO_VAL_INT; + break; + case IIO_CHAN_INFO_SCALE: + *val = lp8788_scale[id] / 1000000; + *val2 = lp8788_scale[id] % 1000000; + ret = IIO_VAL_INT_PLUS_MICRO; + break; + default: + ret = -EINVAL; + break; + } + + mutex_unlock(&adc->lock); + + return ret; +} + +static const struct iio_info lp8788_adc_info = { + .read_raw = &lp8788_adc_read_raw, + .driver_module = THIS_MODULE, +}; + +#define LP8788_CHAN(_id, _type) { \ + .type = _type, \ + .indexed = 1, \ + .channel = LPADC_##_id, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ + .datasheet_name = #_id, \ +} + +static const struct iio_chan_spec lp8788_adc_channels[] = { + [LPADC_VBATT_5P5] = LP8788_CHAN(VBATT_5P5, IIO_VOLTAGE), + [LPADC_VIN_CHG] = LP8788_CHAN(VIN_CHG, IIO_VOLTAGE), + [LPADC_IBATT] = LP8788_CHAN(IBATT, IIO_CURRENT), + [LPADC_IC_TEMP] = LP8788_CHAN(IC_TEMP, IIO_TEMP), + [LPADC_VBATT_6P0] = LP8788_CHAN(VBATT_6P0, IIO_VOLTAGE), + [LPADC_VBATT_5P0] = LP8788_CHAN(VBATT_5P0, IIO_VOLTAGE), + [LPADC_ADC1] = LP8788_CHAN(ADC1, IIO_VOLTAGE), + [LPADC_ADC2] = LP8788_CHAN(ADC2, IIO_VOLTAGE), + [LPADC_VDD] = LP8788_CHAN(VDD, IIO_VOLTAGE), + [LPADC_VCOIN] = LP8788_CHAN(VCOIN, IIO_VOLTAGE), + [LPADC_ADC3] = LP8788_CHAN(ADC3, IIO_VOLTAGE), + [LPADC_ADC4] = LP8788_CHAN(ADC4, IIO_VOLTAGE), +}; + +/* default maps used by iio consumer (lp8788-charger driver) */ +static struct iio_map lp8788_default_iio_maps[] = { + { + .consumer_dev_name = "lp8788-charger", + .consumer_channel = "lp8788_vbatt_5p0", + .adc_channel_label = "VBATT_5P0", + }, + { + .consumer_dev_name = "lp8788-charger", + .consumer_channel = "lp8788_adc1", + .adc_channel_label = "ADC1", + }, + { } +}; + +static int lp8788_iio_map_register(struct iio_dev *indio_dev, + struct lp8788_platform_data *pdata, + struct lp8788_adc *adc) +{ + struct iio_map *map; + int ret; + + map = (!pdata || !pdata->adc_pdata) ? + lp8788_default_iio_maps : pdata->adc_pdata; + + ret = iio_map_array_register(indio_dev, map); + if (ret) { + dev_err(adc->lp->dev, "iio map err: %d\n", ret); + return ret; + } + + adc->map = map; + return 0; +} + +static inline void lp8788_iio_map_unregister(struct iio_dev *indio_dev, + struct lp8788_adc *adc) +{ + iio_map_array_unregister(indio_dev, adc->map); +} + +static int __devinit lp8788_adc_probe(struct platform_device *pdev) +{ + struct lp8788 *lp = dev_get_drvdata(pdev->dev.parent); + struct iio_dev *indio_dev; + struct lp8788_adc *adc; + int ret; + + indio_dev = iio_device_alloc(sizeof(*adc)); + if (!indio_dev) + return -ENOMEM; + + adc = iio_priv(indio_dev); + adc->lp = lp; + platform_set_drvdata(pdev, indio_dev); + + ret = lp8788_iio_map_register(indio_dev, lp->pdata, adc); + if (ret) + goto err_iio_map; + + mutex_init(&adc->lock); + + indio_dev->dev.parent = lp->dev; + indio_dev->name = pdev->name; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->info = &lp8788_adc_info; + indio_dev->channels = lp8788_adc_channels; + indio_dev->num_channels = ARRAY_SIZE(lp8788_adc_channels); + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(lp->dev, "iio dev register err: %d\n", ret); + goto err_iio_device; + } + + return 0; + +err_iio_device: + lp8788_iio_map_unregister(indio_dev, adc); +err_iio_map: + iio_device_free(indio_dev); + return ret; +} + +static int __devexit lp8788_adc_remove(struct platform_device *pdev) +{ + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + struct lp8788_adc *adc = iio_priv(indio_dev); + + iio_device_unregister(indio_dev); + lp8788_iio_map_unregister(indio_dev, adc); + iio_device_free(indio_dev); + + return 0; +} + +static struct platform_driver lp8788_adc_driver = { + .probe = lp8788_adc_probe, + .remove = __devexit_p(lp8788_adc_remove), + .driver = { + .name = LP8788_DEV_ADC, + .owner = THIS_MODULE, + }, +}; +module_platform_driver(lp8788_adc_driver); + +MODULE_DESCRIPTION("Texas Instruments LP8788 ADC Driver"); +MODULE_AUTHOR("Milo Kim"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:lp8788-adc"); diff --git a/drivers/iio/common/Kconfig b/drivers/iio/common/Kconfig new file mode 100644 index 000000000000..ed45ee54500c --- /dev/null +++ b/drivers/iio/common/Kconfig @@ -0,0 +1,5 @@ +# +# IIO common modules +# + +source "drivers/iio/common/hid-sensors/Kconfig" diff --git a/drivers/iio/common/Makefile b/drivers/iio/common/Makefile new file mode 100644 index 000000000000..81584009b21b --- /dev/null +++ b/drivers/iio/common/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for the IIO common modules. +# Common modules contains modules, which can be shared among multiple +# IIO modules. For example if the trigger processing is common for +# multiple IIO modules then this can be moved to a common module +# instead of duplicating in each module. +# + +obj-y += hid-sensors/ diff --git a/drivers/iio/common/hid-sensors/Kconfig b/drivers/iio/common/hid-sensors/Kconfig new file mode 100644 index 000000000000..8e63d81d652a --- /dev/null +++ b/drivers/iio/common/hid-sensors/Kconfig @@ -0,0 +1,26 @@ +# +# Hid Sensor common modules +# +menu "Hid Sensor IIO Common" + +config HID_SENSOR_IIO_COMMON + tristate "Common modules for all HID Sensor IIO drivers" + depends on HID_SENSOR_HUB + select IIO_TRIGGER if IIO_BUFFER + help + Say yes here to build support for HID sensor to use + HID sensor common processing for attributes and IIO triggers. + There are many attributes which can be shared among multiple + HID sensor drivers, this module contains processing for those + attributes. + +config HID_SENSOR_ENUM_BASE_QUIRKS + tristate "ENUM base quirks for HID Sensor IIO drivers" + depends on HID_SENSOR_IIO_COMMON + help + Say yes here to build support for sensor hub FW using + enumeration, which is using 1 as base instead of 0. + Since logical minimum is still set 0 instead of 1, + there is no easy way to differentiate. + +endmenu diff --git a/drivers/iio/common/hid-sensors/Makefile b/drivers/iio/common/hid-sensors/Makefile new file mode 100644 index 000000000000..1f463e00c242 --- /dev/null +++ b/drivers/iio/common/hid-sensors/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the Hid sensor common modules. +# + +obj-$(CONFIG_HID_SENSOR_IIO_COMMON) += hid-sensor-iio-common.o +hid-sensor-iio-common-y := hid-sensor-attributes.o hid-sensor-trigger.o diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.c b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c new file mode 100644 index 000000000000..75374955caba --- /dev/null +++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.c @@ -0,0 +1,250 @@ +/* + * HID Sensors Driver + * Copyright (c) 2012, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#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 "hid-sensor-attributes.h" + +static int pow_10(unsigned power) +{ + int i; + int ret = 1; + for (i = 0; i < power; ++i) + ret = ret * 10; + + return ret; +} + +static void simple_div(int dividend, int divisor, int *whole, + int *micro_frac) +{ + int rem; + int exp = 0; + + *micro_frac = 0; + if (divisor == 0) { + *whole = 0; + return; + } + *whole = dividend/divisor; + rem = dividend % divisor; + if (rem) { + while (rem <= divisor) { + rem *= 10; + exp++; + } + *micro_frac = (rem / divisor) * pow_10(6-exp); + } +} + +static void split_micro_fraction(unsigned int no, int exp, int *val1, int *val2) +{ + *val1 = no/pow_10(exp); + *val2 = no%pow_10(exp) * pow_10(6-exp); +} + +/* +VTF format uses exponent and variable size format. +For example if the size is 2 bytes +0x0067 with VTF16E14 format -> +1.03 +To convert just change to 0x67 to decimal and use two decimal as E14 stands +for 10^-2. +Negative numbers are 2's complement +*/ +static void convert_from_vtf_format(u32 value, int size, int exp, + int *val1, int *val2) +{ + int sign = 1; + + if (value & BIT(size*8 - 1)) { + value = ((1LL << (size * 8)) - value); + sign = -1; + } + exp = hid_sensor_convert_exponent(exp); + if (exp >= 0) { + *val1 = sign * value * pow_10(exp); + *val2 = 0; + } else { + split_micro_fraction(value, -exp, val1, val2); + if (*val1) + *val1 = sign * (*val1); + else + *val2 = sign * (*val2); + } +} + +static u32 convert_to_vtf_format(int size, int exp, int val1, int val2) +{ + u32 value; + int sign = 1; + + if (val1 < 0 || val2 < 0) + sign = -1; + exp = hid_sensor_convert_exponent(exp); + if (exp < 0) { + value = abs(val1) * pow_10(-exp); + value += abs(val2) / pow_10(6+exp); + } else + value = abs(val1) / pow_10(exp); + if (sign < 0) + value = ((1LL << (size * 8)) - value); + + return value; +} + +int hid_sensor_read_samp_freq_value(struct hid_sensor_iio_common *st, + int *val1, int *val2) +{ + s32 value; + int ret; + + ret = sensor_hub_get_feature(st->hsdev, + st->poll.report_id, + st->poll.index, &value); + if (ret < 0 || value < 0) { + *val1 = *val2 = 0; + return -EINVAL; + } else { + if (st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND) + simple_div(1000, value, val1, val2); + else if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND) + simple_div(1, value, val1, val2); + else { + *val1 = *val2 = 0; + return -EINVAL; + } + } + + return IIO_VAL_INT_PLUS_MICRO; +} +EXPORT_SYMBOL(hid_sensor_read_samp_freq_value); + +int hid_sensor_write_samp_freq_value(struct hid_sensor_iio_common *st, + int val1, int val2) +{ + s32 value; + int ret; + + if (val1 < 0 || val2 < 0) + ret = -EINVAL; + + value = val1 * pow_10(6) + val2; + if (value) { + if (st->poll.units == HID_USAGE_SENSOR_UNITS_MILLISECOND) + value = pow_10(9)/value; + else if (st->poll.units == HID_USAGE_SENSOR_UNITS_SECOND) + value = pow_10(6)/value; + else + value = 0; + } + ret = sensor_hub_set_feature(st->hsdev, + st->poll.report_id, + st->poll.index, value); + if (ret < 0 || value < 0) + ret = -EINVAL; + + return ret; +} +EXPORT_SYMBOL(hid_sensor_write_samp_freq_value); + +int hid_sensor_read_raw_hyst_value(struct hid_sensor_iio_common *st, + int *val1, int *val2) +{ + s32 value; + int ret; + + ret = sensor_hub_get_feature(st->hsdev, + st->sensitivity.report_id, + st->sensitivity.index, &value); + if (ret < 0 || value < 0) { + *val1 = *val2 = 0; + return -EINVAL; + } else { + convert_from_vtf_format(value, st->sensitivity.size, + st->sensitivity.unit_expo, + val1, val2); + } + + return IIO_VAL_INT_PLUS_MICRO; +} +EXPORT_SYMBOL(hid_sensor_read_raw_hyst_value); + +int hid_sensor_write_raw_hyst_value(struct hid_sensor_iio_common *st, + int val1, int val2) +{ + s32 value; + int ret; + + value = convert_to_vtf_format(st->sensitivity.size, + st->sensitivity.unit_expo, + val1, val2); + ret = sensor_hub_set_feature(st->hsdev, + st->sensitivity.report_id, + st->sensitivity.index, value); + if (ret < 0 || value < 0) + ret = -EINVAL; + + return ret; +} +EXPORT_SYMBOL(hid_sensor_write_raw_hyst_value); + +int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, + u32 usage_id, + struct hid_sensor_iio_common *st) +{ + + sensor_hub_input_get_attribute_info(hsdev, + HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_PROP_REPORT_INTERVAL, + &st->poll); + + sensor_hub_input_get_attribute_info(hsdev, + HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_PROP_REPORT_STATE, + &st->report_state); + + sensor_hub_input_get_attribute_info(hsdev, + HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_PROY_POWER_STATE, + &st->power_state); + + sensor_hub_input_get_attribute_info(hsdev, + HID_FEATURE_REPORT, usage_id, + HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS, + &st->sensitivity); + + hid_dbg(hsdev->hdev, "common attributes: %x:%x, %x:%x, %x:%x %x:%x\n", + st->poll.index, st->poll.report_id, + st->report_state.index, st->report_state.report_id, + st->power_state.index, st->power_state.report_id, + st->sensitivity.index, st->sensitivity.report_id); + + return 0; +} +EXPORT_SYMBOL(hid_sensor_parse_common_attributes); + +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>"); +MODULE_DESCRIPTION("HID Sensor common attribute processing"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/common/hid-sensors/hid-sensor-attributes.h b/drivers/iio/common/hid-sensors/hid-sensor-attributes.h new file mode 100644 index 000000000000..a4676a0c3de5 --- /dev/null +++ b/drivers/iio/common/hid-sensors/hid-sensor-attributes.h @@ -0,0 +1,57 @@ +/* + * HID Sensors Driver + * Copyright (c) 2012, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#ifndef _HID_SENSORS_ATTRIBUTES_H +#define _HID_SENSORS_ATTRIBUTES_H + +/* Common hid sensor iio structure */ +struct hid_sensor_iio_common { + struct hid_sensor_hub_device *hsdev; + struct platform_device *pdev; + unsigned usage_id; + bool data_ready; + struct hid_sensor_hub_attribute_info poll; + struct hid_sensor_hub_attribute_info report_state; + struct hid_sensor_hub_attribute_info power_state; + struct hid_sensor_hub_attribute_info sensitivity; +}; + +/*Convert from hid unit expo to regular exponent*/ +static inline int hid_sensor_convert_exponent(int unit_expo) +{ + if (unit_expo < 0x08) + return unit_expo; + else if (unit_expo <= 0x0f) + return -(0x0f-unit_expo+1); + else + return 0; +} + +int hid_sensor_parse_common_attributes(struct hid_sensor_hub_device *hsdev, + u32 usage_id, + struct hid_sensor_iio_common *st); +int hid_sensor_write_raw_hyst_value(struct hid_sensor_iio_common *st, + int val1, int val2); +int hid_sensor_read_raw_hyst_value(struct hid_sensor_iio_common *st, + int *val1, int *val2); +int hid_sensor_write_samp_freq_value(struct hid_sensor_iio_common *st, + int val1, int val2); +int hid_sensor_read_samp_freq_value(struct hid_sensor_iio_common *st, + int *val1, int *val2); + +#endif diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c new file mode 100644 index 000000000000..d4b790d18efb --- /dev/null +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c @@ -0,0 +1,103 @@ +/* + * HID Sensors Driver + * Copyright (c) 2012, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#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/trigger.h> +#include <linux/iio/sysfs.h> +#include "hid-sensor-attributes.h" +#include "hid-sensor-trigger.h" + +static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig, + bool state) +{ + struct hid_sensor_iio_common *st = trig->private_data; + int state_val; + + state_val = state ? 1 : 0; +#if (defined CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS) || \ + (defined CONFIG_HID_SENSOR_ENUM_BASE_QUIRKS_MODULE) + ++state_val; +#endif + st->data_ready = state; + sensor_hub_set_feature(st->hsdev, st->power_state.report_id, + st->power_state.index, + (s32)state_val); + + sensor_hub_set_feature(st->hsdev, st->report_state.report_id, + st->report_state.index, + (s32)state_val); + + return 0; +} + +void hid_sensor_remove_trigger(struct iio_dev *indio_dev) +{ + iio_trigger_unregister(indio_dev->trig); + iio_trigger_free(indio_dev->trig); + indio_dev->trig = NULL; +} +EXPORT_SYMBOL(hid_sensor_remove_trigger); + +static const struct iio_trigger_ops hid_sensor_trigger_ops = { + .owner = THIS_MODULE, + .set_trigger_state = &hid_sensor_data_rdy_trigger_set_state, +}; + +int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, + struct hid_sensor_iio_common *attrb) +{ + int ret; + struct iio_trigger *trig; + + trig = iio_trigger_alloc("%s-dev%d", name, indio_dev->id); + if (trig == NULL) { + dev_err(&indio_dev->dev, "Trigger Allocate Failed\n"); + ret = -ENOMEM; + goto error_ret; + } + + trig->dev.parent = indio_dev->dev.parent; + trig->private_data = attrb; + trig->ops = &hid_sensor_trigger_ops; + ret = iio_trigger_register(trig); + + if (ret) { + dev_err(&indio_dev->dev, "Trigger Register Failed\n"); + goto error_free_trig; + } + indio_dev->trig = trig; + + return ret; + +error_free_trig: + iio_trigger_free(trig); +error_ret: + return ret; +} +EXPORT_SYMBOL(hid_sensor_setup_trigger); + +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>"); +MODULE_DESCRIPTION("HID Sensor trigger processing"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h new file mode 100644 index 000000000000..fd982971b1b8 --- /dev/null +++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h @@ -0,0 +1,26 @@ +/* + * HID Sensors Driver + * Copyright (c) 2012, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#ifndef _HID_SENSOR_TRIGGER_H +#define _HID_SENSOR_TRIGGER_H + +int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name, + struct hid_sensor_iio_common *attrb); +void hid_sensor_remove_trigger(struct iio_dev *indio_dev); + +#endif diff --git a/drivers/iio/dac/Kconfig b/drivers/iio/dac/Kconfig index 1be15fa9d618..b1c0ee5294ca 100644 --- a/drivers/iio/dac/Kconfig +++ b/drivers/iio/dac/Kconfig @@ -57,11 +57,12 @@ config AD5624R_SPI config AD5446 tristate "Analog Devices AD5446 and similar single channel DACs driver" - depends on SPI + depends on (SPI_MASTER || I2C) help - Say yes here to build support for Analog Devices AD5444, AD5446, AD5450, - AD5451, AD5452, AD5453, AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5601, - AD5611, AD5620, AD5621, AD5640, AD5660, AD5662 DACs. + Say yes here to build support for Analog Devices AD5300, AD5301, AD5310, + AD5311, AD5320, AD5321, AD5444, AD5446, AD5450, AD5451, AD5452, AD5453, + AD5512A, AD5541A, AD5542A, AD5543, AD5553, AD5601, AD5602, AD5611, AD5612, + AD5620, AD5621, AD5622, AD5640, AD5660, AD5662 DACs. To compile this driver as a module, choose M here: the module will be called ad5446. @@ -76,6 +77,17 @@ config AD5504 To compile this driver as a module, choose M here: the module will be called ad5504. +config AD5755 + tristate "Analog Devices AD5755/AD5755-1/AD5757/AD5735/AD5737 DAC driver" + depends on SPI_MASTER + help + Say yes here to build support for Analog Devices AD5755, AD5755-1, + AD5757, AD5735, AD5737 quad channel Digital to + Analog Converter. + + To compile this driver as a module, choose M here: the + module will be called ad5755. + config AD5764 tristate "Analog Devices AD5764/64R/44/44R DAC driver" depends on SPI_MASTER diff --git a/drivers/iio/dac/Makefile b/drivers/iio/dac/Makefile index 9ea3ceeefc07..c0d333b23ba3 100644 --- a/drivers/iio/dac/Makefile +++ b/drivers/iio/dac/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_AD5624R_SPI) += ad5624r_spi.o obj-$(CONFIG_AD5064) += ad5064.o obj-$(CONFIG_AD5504) += ad5504.o obj-$(CONFIG_AD5446) += ad5446.o +obj-$(CONFIG_AD5755) += ad5755.o obj-$(CONFIG_AD5764) += ad5764.o obj-$(CONFIG_AD5791) += ad5791.o obj-$(CONFIG_AD5686) += ad5686.o diff --git a/drivers/iio/dac/ad5446.c b/drivers/iio/dac/ad5446.c index 2ca5059ef89e..3310cbbd41e7 100644 --- a/drivers/iio/dac/ad5446.c +++ b/drivers/iio/dac/ad5446.c @@ -14,6 +14,7 @@ #include <linux/sysfs.h> #include <linux/list.h> #include <linux/spi/spi.h> +#include <linux/i2c.h> #include <linux/regulator/consumer.h> #include <linux/err.h> #include <linux/module.h> @@ -21,24 +22,40 @@ #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> -#include "ad5446.h" +#define MODE_PWRDWN_1k 0x1 +#define MODE_PWRDWN_100k 0x2 +#define MODE_PWRDWN_TRISTATE 0x3 -static int ad5446_write(struct ad5446_state *st, unsigned val) -{ - __be16 data = cpu_to_be16(val); - return spi_write(st->spi, &data, sizeof(data)); -} +/** + * struct ad5446_state - driver instance specific data + * @spi: spi_device + * @chip_info: chip model specific constants, available modes etc + * @reg: supply regulator + * @vref_mv: actual reference voltage used + */ -static int ad5660_write(struct ad5446_state *st, unsigned val) -{ - uint8_t data[3]; +struct ad5446_state { + struct device *dev; + const struct ad5446_chip_info *chip_info; + struct regulator *reg; + unsigned short vref_mv; + unsigned cached_val; + unsigned pwr_down_mode; + unsigned pwr_down; +}; - data[0] = (val >> 16) & 0xFF; - data[1] = (val >> 8) & 0xFF; - data[2] = val & 0xFF; +/** + * struct ad5446_chip_info - chip specific information + * @channel: channel spec for the DAC + * @int_vref_mv: AD5620/40/60: the internal reference voltage + * @write: chip specific helper function to write to the register + */ - return spi_write(st->spi, data, sizeof(data)); -} +struct ad5446_chip_info { + struct iio_chan_spec channel; + u16 int_vref_mv; + int (*write)(struct ad5446_state *st, unsigned val); +}; static const char * const ad5446_powerdown_modes[] = { "1kohm_to_gnd", "100kohm_to_gnd", "three_state" @@ -110,7 +127,7 @@ static ssize_t ad5446_write_dac_powerdown(struct iio_dev *indio_dev, return ret ? ret : len; } -static const struct iio_chan_spec_ext_info ad5064_ext_info_powerdown[] = { +static const struct iio_chan_spec_ext_info ad5446_ext_info_powerdown[] = { { .name = "powerdown", .read = ad5446_read_dac_powerdown, @@ -136,84 +153,7 @@ static const struct iio_chan_spec_ext_info ad5064_ext_info_powerdown[] = { _AD5446_CHANNEL(bits, storage, shift, NULL) #define AD5446_CHANNEL_POWERDOWN(bits, storage, shift) \ - _AD5446_CHANNEL(bits, storage, shift, ad5064_ext_info_powerdown) - -static const struct ad5446_chip_info ad5446_chip_info_tbl[] = { - [ID_AD5444] = { - .channel = AD5446_CHANNEL(12, 16, 2), - .write = ad5446_write, - }, - [ID_AD5446] = { - .channel = AD5446_CHANNEL(14, 16, 0), - .write = ad5446_write, - }, - [ID_AD5450] = { - .channel = AD5446_CHANNEL(8, 16, 6), - .write = ad5446_write, - }, - [ID_AD5451] = { - .channel = AD5446_CHANNEL(10, 16, 4), - .write = ad5446_write, - }, - [ID_AD5541A] = { - .channel = AD5446_CHANNEL(16, 16, 0), - .write = ad5446_write, - }, - [ID_AD5512A] = { - .channel = AD5446_CHANNEL(12, 16, 4), - .write = ad5446_write, - }, - [ID_AD5553] = { - .channel = AD5446_CHANNEL(14, 16, 0), - .write = ad5446_write, - }, - [ID_AD5601] = { - .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 6), - .write = ad5446_write, - }, - [ID_AD5611] = { - .channel = AD5446_CHANNEL_POWERDOWN(10, 16, 4), - .write = ad5446_write, - }, - [ID_AD5621] = { - .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2), - .write = ad5446_write, - }, - [ID_AD5620_2500] = { - .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2), - .int_vref_mv = 2500, - .write = ad5446_write, - }, - [ID_AD5620_1250] = { - .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2), - .int_vref_mv = 1250, - .write = ad5446_write, - }, - [ID_AD5640_2500] = { - .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0), - .int_vref_mv = 2500, - .write = ad5446_write, - }, - [ID_AD5640_1250] = { - .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0), - .int_vref_mv = 1250, - .write = ad5446_write, - }, - [ID_AD5660_2500] = { - .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0), - .int_vref_mv = 2500, - .write = ad5660_write, - }, - [ID_AD5660_1250] = { - .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0), - .int_vref_mv = 1250, - .write = ad5660_write, - }, - [ID_AD5662] = { - .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0), - .write = ad5660_write, - }, -}; + _AD5446_CHANNEL(bits, storage, shift, ad5446_ext_info_powerdown) static int ad5446_read_raw(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, @@ -272,14 +212,15 @@ static const struct iio_info ad5446_info = { .driver_module = THIS_MODULE, }; -static int __devinit ad5446_probe(struct spi_device *spi) +static int __devinit ad5446_probe(struct device *dev, const char *name, + const struct ad5446_chip_info *chip_info) { struct ad5446_state *st; struct iio_dev *indio_dev; struct regulator *reg; int ret, voltage_uv = 0; - reg = regulator_get(&spi->dev, "vcc"); + reg = regulator_get(dev, "vcc"); if (!IS_ERR(reg)) { ret = regulator_enable(reg); if (ret) @@ -294,16 +235,15 @@ static int __devinit ad5446_probe(struct spi_device *spi) goto error_disable_reg; } st = iio_priv(indio_dev); - st->chip_info = - &ad5446_chip_info_tbl[spi_get_device_id(spi)->driver_data]; + st->chip_info = chip_info; - spi_set_drvdata(spi, indio_dev); + dev_set_drvdata(dev, indio_dev); st->reg = reg; - st->spi = spi; + st->dev = dev; - /* Establish that the iio_dev is a child of the spi device */ - indio_dev->dev.parent = &spi->dev; - indio_dev->name = spi_get_device_id(spi)->name; + /* Establish that the iio_dev is a child of the device */ + indio_dev->dev.parent = dev; + indio_dev->name = name; indio_dev->info = &ad5446_info; indio_dev->modes = INDIO_DIRECT_MODE; indio_dev->channels = &st->chip_info->channel; @@ -316,7 +256,7 @@ static int __devinit ad5446_probe(struct spi_device *spi) else if (voltage_uv) st->vref_mv = voltage_uv / 1000; else - dev_warn(&spi->dev, "reference voltage unspecified\n"); + dev_warn(dev, "reference voltage unspecified\n"); ret = iio_device_register(indio_dev); if (ret) @@ -336,9 +276,9 @@ error_put_reg: return ret; } -static int ad5446_remove(struct spi_device *spi) +static int ad5446_remove(struct device *dev) { - struct iio_dev *indio_dev = spi_get_drvdata(spi); + struct iio_dev *indio_dev = dev_get_drvdata(dev); struct ad5446_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); @@ -351,7 +291,151 @@ static int ad5446_remove(struct spi_device *spi) return 0; } -static const struct spi_device_id ad5446_id[] = { +#if IS_ENABLED(CONFIG_SPI_MASTER) + +static int ad5446_write(struct ad5446_state *st, unsigned val) +{ + struct spi_device *spi = to_spi_device(st->dev); + __be16 data = cpu_to_be16(val); + + return spi_write(spi, &data, sizeof(data)); +} + +static int ad5660_write(struct ad5446_state *st, unsigned val) +{ + struct spi_device *spi = to_spi_device(st->dev); + uint8_t data[3]; + + data[0] = (val >> 16) & 0xFF; + data[1] = (val >> 8) & 0xFF; + data[2] = val & 0xFF; + + return spi_write(spi, data, sizeof(data)); +} + +/** + * ad5446_supported_spi_device_ids: + * The AD5620/40/60 parts are available in different fixed internal reference + * voltage options. The actual part numbers may look differently + * (and a bit cryptic), however this style is used to make clear which + * parts are supported here. + */ +enum ad5446_supported_spi_device_ids { + ID_AD5300, + ID_AD5310, + ID_AD5320, + ID_AD5444, + ID_AD5446, + ID_AD5450, + ID_AD5451, + ID_AD5541A, + ID_AD5512A, + ID_AD5553, + ID_AD5601, + ID_AD5611, + ID_AD5621, + ID_AD5620_2500, + ID_AD5620_1250, + ID_AD5640_2500, + ID_AD5640_1250, + ID_AD5660_2500, + ID_AD5660_1250, + ID_AD5662, +}; + +static const struct ad5446_chip_info ad5446_spi_chip_info[] = { + [ID_AD5300] = { + .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 4), + .write = ad5446_write, + }, + [ID_AD5310] = { + .channel = AD5446_CHANNEL_POWERDOWN(10, 16, 2), + .write = ad5446_write, + }, + [ID_AD5320] = { + .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 0), + .write = ad5446_write, + }, + [ID_AD5444] = { + .channel = AD5446_CHANNEL(12, 16, 2), + .write = ad5446_write, + }, + [ID_AD5446] = { + .channel = AD5446_CHANNEL(14, 16, 0), + .write = ad5446_write, + }, + [ID_AD5450] = { + .channel = AD5446_CHANNEL(8, 16, 6), + .write = ad5446_write, + }, + [ID_AD5451] = { + .channel = AD5446_CHANNEL(10, 16, 4), + .write = ad5446_write, + }, + [ID_AD5541A] = { + .channel = AD5446_CHANNEL(16, 16, 0), + .write = ad5446_write, + }, + [ID_AD5512A] = { + .channel = AD5446_CHANNEL(12, 16, 4), + .write = ad5446_write, + }, + [ID_AD5553] = { + .channel = AD5446_CHANNEL(14, 16, 0), + .write = ad5446_write, + }, + [ID_AD5601] = { + .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 6), + .write = ad5446_write, + }, + [ID_AD5611] = { + .channel = AD5446_CHANNEL_POWERDOWN(10, 16, 4), + .write = ad5446_write, + }, + [ID_AD5621] = { + .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2), + .write = ad5446_write, + }, + [ID_AD5620_2500] = { + .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2), + .int_vref_mv = 2500, + .write = ad5446_write, + }, + [ID_AD5620_1250] = { + .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 2), + .int_vref_mv = 1250, + .write = ad5446_write, + }, + [ID_AD5640_2500] = { + .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0), + .int_vref_mv = 2500, + .write = ad5446_write, + }, + [ID_AD5640_1250] = { + .channel = AD5446_CHANNEL_POWERDOWN(14, 16, 0), + .int_vref_mv = 1250, + .write = ad5446_write, + }, + [ID_AD5660_2500] = { + .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0), + .int_vref_mv = 2500, + .write = ad5660_write, + }, + [ID_AD5660_1250] = { + .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0), + .int_vref_mv = 1250, + .write = ad5660_write, + }, + [ID_AD5662] = { + .channel = AD5446_CHANNEL_POWERDOWN(16, 16, 0), + .write = ad5660_write, + }, +}; + +static const struct spi_device_id ad5446_spi_ids[] = { + {"ad5300", ID_AD5300}, + {"ad5310", ID_AD5310}, + {"ad5320", ID_AD5320}, {"ad5444", ID_AD5444}, {"ad5446", ID_AD5446}, {"ad5450", ID_AD5450}, @@ -375,18 +459,160 @@ static const struct spi_device_id ad5446_id[] = { {"ad5662", ID_AD5662}, {} }; -MODULE_DEVICE_TABLE(spi, ad5446_id); +MODULE_DEVICE_TABLE(spi, ad5446_spi_ids); + +static int __devinit ad5446_spi_probe(struct spi_device *spi) +{ + const struct spi_device_id *id = spi_get_device_id(spi); -static struct spi_driver ad5446_driver = { + return ad5446_probe(&spi->dev, id->name, + &ad5446_spi_chip_info[id->driver_data]); +} + +static int __devexit ad5446_spi_remove(struct spi_device *spi) +{ + return ad5446_remove(&spi->dev); +} + +static struct spi_driver ad5446_spi_driver = { .driver = { .name = "ad5446", .owner = THIS_MODULE, }, - .probe = ad5446_probe, - .remove = __devexit_p(ad5446_remove), - .id_table = ad5446_id, + .probe = ad5446_spi_probe, + .remove = __devexit_p(ad5446_spi_remove), + .id_table = ad5446_spi_ids, }; -module_spi_driver(ad5446_driver); + +static int __init ad5446_spi_register_driver(void) +{ + return spi_register_driver(&ad5446_spi_driver); +} + +static void ad5446_spi_unregister_driver(void) +{ + spi_unregister_driver(&ad5446_spi_driver); +} + +#else + +static inline int ad5446_spi_register_driver(void) { return 0; } +static inline void ad5446_spi_unregister_driver(void) { } + +#endif + +#if IS_ENABLED(CONFIG_I2C) + +static int ad5622_write(struct ad5446_state *st, unsigned val) +{ + struct i2c_client *client = to_i2c_client(st->dev); + __be16 data = cpu_to_be16(val); + + return i2c_master_send(client, (char *)&data, sizeof(data)); +} + +/** + * ad5446_supported_i2c_device_ids: + * The AD5620/40/60 parts are available in different fixed internal reference + * voltage options. The actual part numbers may look differently + * (and a bit cryptic), however this style is used to make clear which + * parts are supported here. + */ +enum ad5446_supported_i2c_device_ids { + ID_AD5602, + ID_AD5612, + ID_AD5622, +}; + +static const struct ad5446_chip_info ad5446_i2c_chip_info[] = { + [ID_AD5602] = { + .channel = AD5446_CHANNEL_POWERDOWN(8, 16, 4), + .write = ad5622_write, + }, + [ID_AD5612] = { + .channel = AD5446_CHANNEL_POWERDOWN(10, 16, 2), + .write = ad5622_write, + }, + [ID_AD5622] = { + .channel = AD5446_CHANNEL_POWERDOWN(12, 16, 0), + .write = ad5622_write, + }, +}; + +static int __devinit ad5446_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + return ad5446_probe(&i2c->dev, id->name, + &ad5446_i2c_chip_info[id->driver_data]); +} + +static int __devexit ad5446_i2c_remove(struct i2c_client *i2c) +{ + return ad5446_remove(&i2c->dev); +} + +static const struct i2c_device_id ad5446_i2c_ids[] = { + {"ad5301", ID_AD5602}, + {"ad5311", ID_AD5612}, + {"ad5321", ID_AD5622}, + {"ad5602", ID_AD5602}, + {"ad5612", ID_AD5612}, + {"ad5622", ID_AD5622}, + {} +}; +MODULE_DEVICE_TABLE(i2c, ad5446_i2c_ids); + +static struct i2c_driver ad5446_i2c_driver = { + .driver = { + .name = "ad5446", + .owner = THIS_MODULE, + }, + .probe = ad5446_i2c_probe, + .remove = __devexit_p(ad5446_i2c_remove), + .id_table = ad5446_i2c_ids, +}; + +static int __init ad5446_i2c_register_driver(void) +{ + return i2c_add_driver(&ad5446_i2c_driver); +} + +static void __exit ad5446_i2c_unregister_driver(void) +{ + i2c_del_driver(&ad5446_i2c_driver); +} + +#else + +static inline int ad5446_i2c_register_driver(void) { return 0; } +static inline void ad5446_i2c_unregister_driver(void) { } + +#endif + +static int __init ad5446_init(void) +{ + int ret; + + ret = ad5446_spi_register_driver(); + if (ret) + return ret; + + ret = ad5446_i2c_register_driver(); + if (ret) { + ad5446_spi_unregister_driver(); + return ret; + } + + return 0; +} +module_init(ad5446_init); + +static void __exit ad5446_exit(void) +{ + ad5446_i2c_unregister_driver(); + ad5446_spi_unregister_driver(); +} +module_exit(ad5446_exit); MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); MODULE_DESCRIPTION("Analog Devices AD5444/AD5446 DAC"); diff --git a/drivers/iio/dac/ad5446.h b/drivers/iio/dac/ad5446.h deleted file mode 100644 index 2934269a56d5..000000000000 --- a/drivers/iio/dac/ad5446.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * AD5446 SPI DAC driver - * - * Copyright 2010 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ -#ifndef IIO_DAC_AD5446_H_ -#define IIO_DAC_AD5446_H_ - -/* DAC Control Bits */ - -#define AD5446_LOAD (0x0 << 14) /* Load and update */ -#define AD5446_SDO_DIS (0x1 << 14) /* Disable SDO */ -#define AD5446_NOP (0x2 << 14) /* No operation */ -#define AD5446_CLK_RISING (0x3 << 14) /* Clock data on rising edge */ - -#define AD5620_LOAD (0x0 << 14) /* Load and update Norm Operation*/ -#define AD5620_PWRDWN_1k (0x1 << 14) /* Power-down: 1kOhm to GND */ -#define AD5620_PWRDWN_100k (0x2 << 14) /* Power-down: 100kOhm to GND */ -#define AD5620_PWRDWN_TRISTATE (0x3 << 14) /* Power-down: Three-state */ - -#define AD5660_LOAD (0x0 << 16) /* Load and update Norm Operation*/ -#define AD5660_PWRDWN_1k (0x1 << 16) /* Power-down: 1kOhm to GND */ -#define AD5660_PWRDWN_100k (0x2 << 16) /* Power-down: 100kOhm to GND */ -#define AD5660_PWRDWN_TRISTATE (0x3 << 16) /* Power-down: Three-state */ - -#define MODE_PWRDWN_1k 0x1 -#define MODE_PWRDWN_100k 0x2 -#define MODE_PWRDWN_TRISTATE 0x3 - -/** - * struct ad5446_state - driver instance specific data - * @spi: spi_device - * @chip_info: chip model specific constants, available modes etc - * @reg: supply regulator - * @vref_mv: actual reference voltage used - */ - -struct ad5446_state { - struct spi_device *spi; - const struct ad5446_chip_info *chip_info; - struct regulator *reg; - unsigned short vref_mv; - unsigned cached_val; - unsigned pwr_down_mode; - unsigned pwr_down; -}; - -/** - * struct ad5446_chip_info - chip specific information - * @channel: channel spec for the DAC - * @int_vref_mv: AD5620/40/60: the internal reference voltage - * @write: chip specific helper function to write to the register - */ - -struct ad5446_chip_info { - struct iio_chan_spec channel; - u16 int_vref_mv; - int (*write)(struct ad5446_state *st, unsigned val); -}; - -/** - * ad5446_supported_device_ids: - * The AD5620/40/60 parts are available in different fixed internal reference - * voltage options. The actual part numbers may look differently - * (and a bit cryptic), however this style is used to make clear which - * parts are supported here. - */ - -enum ad5446_supported_device_ids { - ID_AD5444, - ID_AD5446, - ID_AD5450, - ID_AD5451, - ID_AD5541A, - ID_AD5512A, - ID_AD5553, - ID_AD5601, - ID_AD5611, - ID_AD5621, - ID_AD5620_2500, - ID_AD5620_1250, - ID_AD5640_2500, - ID_AD5640_1250, - ID_AD5660_2500, - ID_AD5660_1250, - ID_AD5662, -}; - -#endif /* IIO_DAC_AD5446_H_ */ diff --git a/drivers/iio/dac/ad5755.c b/drivers/iio/dac/ad5755.c new file mode 100644 index 000000000000..5db3506034c5 --- /dev/null +++ b/drivers/iio/dac/ad5755.c @@ -0,0 +1,650 @@ +/* + * AD5755, AD5755-1, AD5757, AD5735, AD5737 Digital to analog converters driver + * + * Copyright 2012 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ + +#include <linux/device.h> +#include <linux/err.h> +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/spi/spi.h> +#include <linux/slab.h> +#include <linux/sysfs.h> +#include <linux/delay.h> +#include <linux/iio/iio.h> +#include <linux/iio/sysfs.h> +#include <linux/platform_data/ad5755.h> + +#define AD5755_NUM_CHANNELS 4 + +#define AD5755_ADDR(x) ((x) << 16) + +#define AD5755_WRITE_REG_DATA(chan) (chan) +#define AD5755_WRITE_REG_GAIN(chan) (0x08 | (chan)) +#define AD5755_WRITE_REG_OFFSET(chan) (0x10 | (chan)) +#define AD5755_WRITE_REG_CTRL(chan) (0x1c | (chan)) + +#define AD5755_READ_REG_DATA(chan) (chan) +#define AD5755_READ_REG_CTRL(chan) (0x4 | (chan)) +#define AD5755_READ_REG_GAIN(chan) (0x8 | (chan)) +#define AD5755_READ_REG_OFFSET(chan) (0xc | (chan)) +#define AD5755_READ_REG_CLEAR(chan) (0x10 | (chan)) +#define AD5755_READ_REG_SLEW(chan) (0x14 | (chan)) +#define AD5755_READ_REG_STATUS 0x18 +#define AD5755_READ_REG_MAIN 0x19 +#define AD5755_READ_REG_DC_DC 0x1a + +#define AD5755_CTRL_REG_SLEW 0x0 +#define AD5755_CTRL_REG_MAIN 0x1 +#define AD5755_CTRL_REG_DAC 0x2 +#define AD5755_CTRL_REG_DC_DC 0x3 +#define AD5755_CTRL_REG_SW 0x4 + +#define AD5755_READ_FLAG 0x800000 + +#define AD5755_NOOP 0x1CE000 + +#define AD5755_DAC_INT_EN BIT(8) +#define AD5755_DAC_CLR_EN BIT(7) +#define AD5755_DAC_OUT_EN BIT(6) +#define AD5755_DAC_INT_CURRENT_SENSE_RESISTOR BIT(5) +#define AD5755_DAC_DC_DC_EN BIT(4) +#define AD5755_DAC_VOLTAGE_OVERRANGE_EN BIT(3) + +#define AD5755_DC_DC_MAXV 0 +#define AD5755_DC_DC_FREQ_SHIFT 2 +#define AD5755_DC_DC_PHASE_SHIFT 4 +#define AD5755_EXT_DC_DC_COMP_RES BIT(6) + +#define AD5755_SLEW_STEP_SIZE_SHIFT 0 +#define AD5755_SLEW_RATE_SHIFT 3 +#define AD5755_SLEW_ENABLE BIT(12) + +/** + * struct ad5755_chip_info - chip specific information + * @channel_template: channel specification + * @calib_shift: shift for the calibration data registers + * @has_voltage_out: whether the chip has voltage outputs + */ +struct ad5755_chip_info { + const struct iio_chan_spec channel_template; + unsigned int calib_shift; + bool has_voltage_out; +}; + +/** + * struct ad5755_state - driver instance specific data + * @spi: spi device the driver is attached to + * @chip_info: chip model specific constants, available modes etc + * @pwr_down: bitmask which contains hether a channel is powered down or not + * @ctrl: software shadow of the channel ctrl registers + * @channels: iio channel spec for the device + * @data: spi transfer buffers + */ +struct ad5755_state { + struct spi_device *spi; + const struct ad5755_chip_info *chip_info; + unsigned int pwr_down; + unsigned int ctrl[AD5755_NUM_CHANNELS]; + struct iio_chan_spec channels[AD5755_NUM_CHANNELS]; + + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + + union { + u32 d32; + u8 d8[4]; + } data[2] ____cacheline_aligned; +}; + +enum ad5755_type { + ID_AD5755, + ID_AD5757, + ID_AD5735, + ID_AD5737, +}; + +static int ad5755_write_unlocked(struct iio_dev *indio_dev, + unsigned int reg, unsigned int val) +{ + struct ad5755_state *st = iio_priv(indio_dev); + + st->data[0].d32 = cpu_to_be32((reg << 16) | val); + + return spi_write(st->spi, &st->data[0].d8[1], 3); +} + +static int ad5755_write_ctrl_unlocked(struct iio_dev *indio_dev, + unsigned int channel, unsigned int reg, unsigned int val) +{ + return ad5755_write_unlocked(indio_dev, + AD5755_WRITE_REG_CTRL(channel), (reg << 13) | val); +} + +static int ad5755_write(struct iio_dev *indio_dev, unsigned int reg, + unsigned int val) +{ + int ret; + + mutex_lock(&indio_dev->mlock); + ret = ad5755_write_unlocked(indio_dev, reg, val); + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static int ad5755_write_ctrl(struct iio_dev *indio_dev, unsigned int channel, + unsigned int reg, unsigned int val) +{ + int ret; + + mutex_lock(&indio_dev->mlock); + ret = ad5755_write_ctrl_unlocked(indio_dev, channel, reg, val); + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static int ad5755_read(struct iio_dev *indio_dev, unsigned int addr) +{ + struct ad5755_state *st = iio_priv(indio_dev); + struct spi_message m; + int ret; + struct spi_transfer t[] = { + { + .tx_buf = &st->data[0].d8[1], + .len = 3, + .cs_change = 1, + }, { + .tx_buf = &st->data[1].d8[1], + .rx_buf = &st->data[1].d8[1], + .len = 3, + }, + }; + + spi_message_init(&m); + spi_message_add_tail(&t[0], &m); + spi_message_add_tail(&t[1], &m); + + mutex_lock(&indio_dev->mlock); + + st->data[0].d32 = cpu_to_be32(AD5755_READ_FLAG | (addr << 16)); + st->data[1].d32 = cpu_to_be32(AD5755_NOOP); + + ret = spi_sync(st->spi, &m); + if (ret >= 0) + ret = be32_to_cpu(st->data[1].d32) & 0xffff; + + mutex_unlock(&indio_dev->mlock); + + return ret; +} + +static int ad5755_update_dac_ctrl(struct iio_dev *indio_dev, + unsigned int channel, unsigned int set, unsigned int clr) +{ + struct ad5755_state *st = iio_priv(indio_dev); + int ret; + + st->ctrl[channel] |= set; + st->ctrl[channel] &= ~clr; + + ret = ad5755_write_ctrl_unlocked(indio_dev, channel, + AD5755_CTRL_REG_DAC, st->ctrl[channel]); + + return ret; +} + +static int ad5755_set_channel_pwr_down(struct iio_dev *indio_dev, + unsigned int channel, bool pwr_down) +{ + struct ad5755_state *st = iio_priv(indio_dev); + unsigned int mask = BIT(channel); + + mutex_lock(&indio_dev->mlock); + + if ((bool)(st->pwr_down & mask) == pwr_down) + goto out_unlock; + + if (!pwr_down) { + st->pwr_down &= ~mask; + ad5755_update_dac_ctrl(indio_dev, channel, + AD5755_DAC_INT_EN | AD5755_DAC_DC_DC_EN, 0); + udelay(200); + ad5755_update_dac_ctrl(indio_dev, channel, + AD5755_DAC_OUT_EN, 0); + } else { + st->pwr_down |= mask; + ad5755_update_dac_ctrl(indio_dev, channel, + 0, AD5755_DAC_INT_EN | AD5755_DAC_OUT_EN | + AD5755_DAC_DC_DC_EN); + } + +out_unlock: + mutex_unlock(&indio_dev->mlock); + + return 0; +} + +static const int ad5755_min_max_table[][2] = { + [AD5755_MODE_VOLTAGE_0V_5V] = { 0, 5000 }, + [AD5755_MODE_VOLTAGE_0V_10V] = { 0, 10000 }, + [AD5755_MODE_VOLTAGE_PLUSMINUS_5V] = { -5000, 5000 }, + [AD5755_MODE_VOLTAGE_PLUSMINUS_10V] = { -10000, 10000 }, + [AD5755_MODE_CURRENT_4mA_20mA] = { 4, 20 }, + [AD5755_MODE_CURRENT_0mA_20mA] = { 0, 20 }, + [AD5755_MODE_CURRENT_0mA_24mA] = { 0, 24 }, +}; + +static void ad5755_get_min_max(struct ad5755_state *st, + struct iio_chan_spec const *chan, int *min, int *max) +{ + enum ad5755_mode mode = st->ctrl[chan->channel] & 7; + *min = ad5755_min_max_table[mode][0]; + *max = ad5755_min_max_table[mode][1]; +} + +static inline int ad5755_get_offset(struct ad5755_state *st, + struct iio_chan_spec const *chan) +{ + int min, max; + + ad5755_get_min_max(st, chan, &min, &max); + return (min * (1 << chan->scan_type.realbits)) / (max - min); +} + +static inline int ad5755_get_scale(struct ad5755_state *st, + struct iio_chan_spec const *chan) +{ + int min, max; + + ad5755_get_min_max(st, chan, &min, &max); + return ((max - min) * 1000000000ULL) >> chan->scan_type.realbits; +} + +static int ad5755_chan_reg_info(struct ad5755_state *st, + struct iio_chan_spec const *chan, long info, bool write, + unsigned int *reg, unsigned int *shift, unsigned int *offset) +{ + switch (info) { + case IIO_CHAN_INFO_RAW: + if (write) + *reg = AD5755_WRITE_REG_DATA(chan->address); + else + *reg = AD5755_READ_REG_DATA(chan->address); + *shift = chan->scan_type.shift; + *offset = 0; + break; + case IIO_CHAN_INFO_CALIBBIAS: + if (write) + *reg = AD5755_WRITE_REG_OFFSET(chan->address); + else + *reg = AD5755_READ_REG_OFFSET(chan->address); + *shift = st->chip_info->calib_shift; + *offset = 32768; + break; + case IIO_CHAN_INFO_CALIBSCALE: + if (write) + *reg = AD5755_WRITE_REG_GAIN(chan->address); + else + *reg = AD5755_READ_REG_GAIN(chan->address); + *shift = st->chip_info->calib_shift; + *offset = 0; + break; + default: + return -EINVAL; + } + + return 0; +} + +static int ad5755_read_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, int *val, int *val2, long info) +{ + struct ad5755_state *st = iio_priv(indio_dev); + unsigned int reg, shift, offset; + int ret; + + switch (info) { + case IIO_CHAN_INFO_SCALE: + *val = 0; + *val2 = ad5755_get_scale(st, chan); + return IIO_VAL_INT_PLUS_NANO; + case IIO_CHAN_INFO_OFFSET: + *val = ad5755_get_offset(st, chan); + return IIO_VAL_INT; + default: + ret = ad5755_chan_reg_info(st, chan, info, false, + ®, &shift, &offset); + if (ret) + return ret; + + ret = ad5755_read(indio_dev, reg); + if (ret < 0) + return ret; + + *val = (ret - offset) >> shift; + + return IIO_VAL_INT; + } + + return -EINVAL; +} + +static int ad5755_write_raw(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, int val, int val2, long info) +{ + struct ad5755_state *st = iio_priv(indio_dev); + unsigned int shift, reg, offset; + int ret; + + ret = ad5755_chan_reg_info(st, chan, info, true, + ®, &shift, &offset); + if (ret) + return ret; + + val <<= shift; + val += offset; + + if (val < 0 || val > 0xffff) + return -EINVAL; + + return ad5755_write(indio_dev, reg, val); +} + +static ssize_t ad5755_read_powerdown(struct iio_dev *indio_dev, uintptr_t priv, + const struct iio_chan_spec *chan, char *buf) +{ + struct ad5755_state *st = iio_priv(indio_dev); + + return sprintf(buf, "%d\n", + (bool)(st->pwr_down & (1 << chan->channel))); +} + +static ssize_t ad5755_write_powerdown(struct iio_dev *indio_dev, uintptr_t priv, + struct iio_chan_spec const *chan, const char *buf, size_t len) +{ + bool pwr_down; + int ret; + + ret = strtobool(buf, &pwr_down); + if (ret) + return ret; + + ret = ad5755_set_channel_pwr_down(indio_dev, chan->channel, pwr_down); + return ret ? ret : len; +} + +static const struct iio_info ad5755_info = { + .read_raw = ad5755_read_raw, + .write_raw = ad5755_write_raw, + .driver_module = THIS_MODULE, +}; + +static const struct iio_chan_spec_ext_info ad5755_ext_info[] = { + { + .name = "powerdown", + .read = ad5755_read_powerdown, + .write = ad5755_write_powerdown, + }, + { }, +}; + +#define AD5755_CHANNEL(_bits) { \ + .indexed = 1, \ + .output = 1, \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SEPARATE_BIT | \ + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT | \ + IIO_CHAN_INFO_CALIBSCALE_SEPARATE_BIT | \ + IIO_CHAN_INFO_CALIBBIAS_SEPARATE_BIT, \ + .scan_type = IIO_ST('u', (_bits), 16, 16 - (_bits)), \ + .ext_info = ad5755_ext_info, \ +} + +static const struct ad5755_chip_info ad5755_chip_info_tbl[] = { + [ID_AD5735] = { + .channel_template = AD5755_CHANNEL(14), + .has_voltage_out = true, + .calib_shift = 4, + }, + [ID_AD5737] = { + .channel_template = AD5755_CHANNEL(14), + .has_voltage_out = false, + .calib_shift = 4, + }, + [ID_AD5755] = { + .channel_template = AD5755_CHANNEL(16), + .has_voltage_out = true, + .calib_shift = 0, + }, + [ID_AD5757] = { + .channel_template = AD5755_CHANNEL(16), + .has_voltage_out = false, + .calib_shift = 0, + }, +}; + +static bool ad5755_is_valid_mode(struct ad5755_state *st, enum ad5755_mode mode) +{ + switch (mode) { + case AD5755_MODE_VOLTAGE_0V_5V: + case AD5755_MODE_VOLTAGE_0V_10V: + case AD5755_MODE_VOLTAGE_PLUSMINUS_5V: + case AD5755_MODE_VOLTAGE_PLUSMINUS_10V: + return st->chip_info->has_voltage_out; + case AD5755_MODE_CURRENT_4mA_20mA: + case AD5755_MODE_CURRENT_0mA_20mA: + case AD5755_MODE_CURRENT_0mA_24mA: + return true; + default: + return false; + } +} + +static int __devinit ad5755_setup_pdata(struct iio_dev *indio_dev, + const struct ad5755_platform_data *pdata) +{ + struct ad5755_state *st = iio_priv(indio_dev); + unsigned int val; + unsigned int i; + int ret; + + if (pdata->dc_dc_phase > AD5755_DC_DC_PHASE_90_DEGREE || + pdata->dc_dc_freq > AD5755_DC_DC_FREQ_650kHZ || + pdata->dc_dc_maxv > AD5755_DC_DC_MAXV_29V5) + return -EINVAL; + + val = pdata->dc_dc_maxv << AD5755_DC_DC_MAXV; + val |= pdata->dc_dc_freq << AD5755_DC_DC_FREQ_SHIFT; + val |= pdata->dc_dc_phase << AD5755_DC_DC_PHASE_SHIFT; + if (pdata->ext_dc_dc_compenstation_resistor) + val |= AD5755_EXT_DC_DC_COMP_RES; + + ret = ad5755_write_ctrl(indio_dev, 0, AD5755_CTRL_REG_DC_DC, val); + if (ret < 0) + return ret; + + for (i = 0; i < ARRAY_SIZE(pdata->dac); ++i) { + val = pdata->dac[i].slew.step_size << + AD5755_SLEW_STEP_SIZE_SHIFT; + val |= pdata->dac[i].slew.rate << + AD5755_SLEW_RATE_SHIFT; + if (pdata->dac[i].slew.enable) + val |= AD5755_SLEW_ENABLE; + + ret = ad5755_write_ctrl(indio_dev, i, + AD5755_CTRL_REG_SLEW, val); + if (ret < 0) + return ret; + } + + for (i = 0; i < ARRAY_SIZE(pdata->dac); ++i) { + if (!ad5755_is_valid_mode(st, pdata->dac[i].mode)) + return -EINVAL; + + val = 0; + if (!pdata->dac[i].ext_current_sense_resistor) + val |= AD5755_DAC_INT_CURRENT_SENSE_RESISTOR; + if (pdata->dac[i].enable_voltage_overrange) + val |= AD5755_DAC_VOLTAGE_OVERRANGE_EN; + val |= pdata->dac[i].mode; + + ret = ad5755_update_dac_ctrl(indio_dev, i, val, 0); + if (ret < 0) + return ret; + } + + return 0; +} + +static bool __devinit ad5755_is_voltage_mode(enum ad5755_mode mode) +{ + switch (mode) { + case AD5755_MODE_VOLTAGE_0V_5V: + case AD5755_MODE_VOLTAGE_0V_10V: + case AD5755_MODE_VOLTAGE_PLUSMINUS_5V: + case AD5755_MODE_VOLTAGE_PLUSMINUS_10V: + return true; + default: + return false; + } +} + +static int __devinit ad5755_init_channels(struct iio_dev *indio_dev, + const struct ad5755_platform_data *pdata) +{ + struct ad5755_state *st = iio_priv(indio_dev); + struct iio_chan_spec *channels = st->channels; + unsigned int i; + + for (i = 0; i < AD5755_NUM_CHANNELS; ++i) { + channels[i] = st->chip_info->channel_template; + channels[i].channel = i; + channels[i].address = i; + if (pdata && ad5755_is_voltage_mode(pdata->dac[i].mode)) + channels[i].type = IIO_VOLTAGE; + else + channels[i].type = IIO_CURRENT; + } + + indio_dev->channels = channels; + + return 0; +} + +#define AD5755_DEFAULT_DAC_PDATA { \ + .mode = AD5755_MODE_CURRENT_4mA_20mA, \ + .ext_current_sense_resistor = true, \ + .enable_voltage_overrange = false, \ + .slew = { \ + .enable = false, \ + .rate = AD5755_SLEW_RATE_64k, \ + .step_size = AD5755_SLEW_STEP_SIZE_1, \ + }, \ + } + +static const struct ad5755_platform_data ad5755_default_pdata = { + .ext_dc_dc_compenstation_resistor = false, + .dc_dc_phase = AD5755_DC_DC_PHASE_ALL_SAME_EDGE, + .dc_dc_freq = AD5755_DC_DC_FREQ_410kHZ, + .dc_dc_maxv = AD5755_DC_DC_MAXV_23V, + .dac = { + [0] = AD5755_DEFAULT_DAC_PDATA, + [1] = AD5755_DEFAULT_DAC_PDATA, + [2] = AD5755_DEFAULT_DAC_PDATA, + [3] = AD5755_DEFAULT_DAC_PDATA, + }, +}; + +static int __devinit ad5755_probe(struct spi_device *spi) +{ + enum ad5755_type type = spi_get_device_id(spi)->driver_data; + const struct ad5755_platform_data *pdata = dev_get_platdata(&spi->dev); + struct iio_dev *indio_dev; + struct ad5755_state *st; + int ret; + + indio_dev = iio_device_alloc(sizeof(*st)); + if (indio_dev == NULL) { + dev_err(&spi->dev, "Failed to allocate iio device\n"); + return -ENOMEM; + } + + st = iio_priv(indio_dev); + spi_set_drvdata(spi, indio_dev); + + st->chip_info = &ad5755_chip_info_tbl[type]; + st->spi = spi; + st->pwr_down = 0xf; + + indio_dev->dev.parent = &spi->dev; + indio_dev->name = spi_get_device_id(spi)->name; + indio_dev->info = &ad5755_info; + indio_dev->modes = INDIO_DIRECT_MODE; + indio_dev->num_channels = AD5755_NUM_CHANNELS; + + if (!pdata) + pdata = &ad5755_default_pdata; + + ret = ad5755_init_channels(indio_dev, pdata); + if (ret) + goto error_free; + + ret = ad5755_setup_pdata(indio_dev, pdata); + if (ret) + goto error_free; + + ret = iio_device_register(indio_dev); + if (ret) { + dev_err(&spi->dev, "Failed to register iio device: %d\n", ret); + goto error_free; + } + + return 0; + +error_free: + iio_device_free(indio_dev); + + return ret; +} + +static int __devexit ad5755_remove(struct spi_device *spi) +{ + struct iio_dev *indio_dev = spi_get_drvdata(spi); + + iio_device_unregister(indio_dev); + iio_device_free(indio_dev); + + return 0; +} + +static const struct spi_device_id ad5755_id[] = { + { "ad5755", ID_AD5755 }, + { "ad5755-1", ID_AD5755 }, + { "ad5757", ID_AD5757 }, + { "ad5735", ID_AD5735 }, + { "ad5737", ID_AD5737 }, + {} +}; +MODULE_DEVICE_TABLE(spi, ad5755_id); + +static struct spi_driver ad5755_driver = { + .driver = { + .name = "ad5755", + .owner = THIS_MODULE, + }, + .probe = ad5755_probe, + .remove = __devexit_p(ad5755_remove), + .id_table = ad5755_id, +}; +module_spi_driver(ad5755_driver); + +MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>"); +MODULE_DESCRIPTION("Analog Devices AD5755/55-1/57/35/37 DAC"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/iio/gyro/Kconfig b/drivers/iio/gyro/Kconfig new file mode 100644 index 000000000000..21e27e2fc68c --- /dev/null +++ b/drivers/iio/gyro/Kconfig @@ -0,0 +1,16 @@ +# +# IIO Digital Gyroscope Sensor drivers configuration +# +menu "Digital gyroscope sensors" + +config HID_SENSOR_GYRO_3D + depends on HID_SENSOR_HUB + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + select HID_SENSOR_IIO_COMMON + tristate "HID Gyroscope 3D" + help + Say yes here to build support for the HID SENSOR + Gyroscope 3D. + +endmenu diff --git a/drivers/iio/gyro/Makefile b/drivers/iio/gyro/Makefile new file mode 100644 index 000000000000..8a895d9fcbce --- /dev/null +++ b/drivers/iio/gyro/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for industrial I/O gyroscope sensor drivers +# + +obj-$(CONFIG_HID_SENSOR_GYRO_3D) += hid-sensor-gyro-3d.o diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c new file mode 100644 index 000000000000..4c56ada51c39 --- /dev/null +++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c @@ -0,0 +1,418 @@ +/* + * HID Sensors Driver + * Copyright (c) 2012, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#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-attributes.h" +#include "../common/hid-sensors/hid-sensor-trigger.h" + +/*Format: HID-SENSOR-usage_id_in_hex*/ +/*Usage ID from spec for Gyro-3D: 0x200076*/ +#define DRIVER_NAME "HID-SENSOR-200076" + +enum gyro_3d_channel { + CHANNEL_SCAN_INDEX_X, + CHANNEL_SCAN_INDEX_Y, + CHANNEL_SCAN_INDEX_Z, + GYRO_3D_CHANNEL_MAX, +}; + +struct gyro_3d_state { + struct hid_sensor_hub_callbacks callbacks; + struct hid_sensor_iio_common common_attributes; + struct hid_sensor_hub_attribute_info gyro[GYRO_3D_CHANNEL_MAX]; + u32 gyro_val[GYRO_3D_CHANNEL_MAX]; +}; + +static const u32 gyro_3d_addresses[GYRO_3D_CHANNEL_MAX] = { + HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS, + HID_USAGE_SENSOR_ANGL_VELOCITY_Y_AXIS, + HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS +}; + +/* Channel definitions */ +static const struct iio_chan_spec gyro_3d_channels[] = { + { + .type = IIO_ANGL_VEL, + .modified = 1, + .channel2 = IIO_MOD_X, + .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT | + IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT, + .scan_index = CHANNEL_SCAN_INDEX_X, + }, { + .type = IIO_ANGL_VEL, + .modified = 1, + .channel2 = IIO_MOD_Y, + .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT | + IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT, + .scan_index = CHANNEL_SCAN_INDEX_Y, + }, { + .type = IIO_ANGL_VEL, + .modified = 1, + .channel2 = IIO_MOD_Z, + .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT | + IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT, + .scan_index = CHANNEL_SCAN_INDEX_Z, + } +}; + +/* Adjust channel real bits based on report descriptor */ +static void gyro_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels, + int channel, int size) +{ + channels[channel].scan_type.sign = 's'; + /* Real storage bits will change based on the report desc. */ + channels[channel].scan_type.realbits = size * 8; + /* Maximum size of a sample to capture is u32 */ + channels[channel].scan_type.storagebits = sizeof(u32) * 8; +} + +/* Channel read_raw handler */ +static int gyro_3d_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, + long mask) +{ + struct gyro_3d_state *gyro_state = iio_priv(indio_dev); + int report_id = -1; + u32 address; + int ret; + int ret_type; + + *val = 0; + *val2 = 0; + switch (mask) { + case 0: + 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); + else { + *val = 0; + return -EINVAL; + } + 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; + break; + case IIO_CHAN_INFO_OFFSET: + *val = hid_sensor_convert_exponent( + gyro_state->gyro[CHANNEL_SCAN_INDEX_X].unit_expo); + ret_type = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = hid_sensor_read_samp_freq_value( + &gyro_state->common_attributes, val, val2); + ret_type = IIO_VAL_INT_PLUS_MICRO; + break; + case IIO_CHAN_INFO_HYSTERESIS: + ret = hid_sensor_read_raw_hyst_value( + &gyro_state->common_attributes, val, val2); + ret_type = IIO_VAL_INT_PLUS_MICRO; + break; + default: + ret_type = -EINVAL; + break; + } + + return ret_type; +} + +/* Channel write_raw handler */ +static int gyro_3d_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct gyro_3d_state *gyro_state = iio_priv(indio_dev); + int ret = 0; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + ret = hid_sensor_write_samp_freq_value( + &gyro_state->common_attributes, val, val2); + break; + case IIO_CHAN_INFO_HYSTERESIS: + ret = hid_sensor_write_raw_hyst_value( + &gyro_state->common_attributes, val, val2); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int gyro_3d_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + return IIO_VAL_INT_PLUS_MICRO; +} + +static const struct iio_info gyro_3d_info = { + .driver_module = THIS_MODULE, + .read_raw = &gyro_3d_read_raw, + .write_raw = &gyro_3d_write_raw, + .write_raw_get_fmt = &gyro_3d_write_raw_get_fmt, +}; + +/* Function to push data to buffer */ +static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len) +{ + struct iio_buffer *buffer = indio_dev->buffer; + int datum_sz; + + dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); + if (!buffer) { + dev_err(&indio_dev->dev, "Buffer == NULL\n"); + return; + } + datum_sz = buffer->access->get_bytes_per_datum(buffer); + if (len > datum_sz) { + dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len, + datum_sz); + return; + } + iio_push_to_buffer(buffer, (u8 *)data); +} + +/* Callback handler to send event after all samples are received and captured */ +static int gyro_3d_proc_event(struct hid_sensor_hub_device *hsdev, + unsigned usage_id, + void *priv) +{ + 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) + hid_sensor_push_data(indio_dev, + (u8 *)gyro_state->gyro_val, + sizeof(gyro_state->gyro_val)); + + return 0; +} + +/* Capture samples in local storage */ +static int gyro_3d_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 gyro_3d_state *gyro_state = iio_priv(indio_dev); + int offset; + int ret = -EINVAL; + + switch (usage_id) { + case HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS: + case HID_USAGE_SENSOR_ANGL_VELOCITY_Y_AXIS: + case HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS: + offset = usage_id - HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS; + gyro_state->gyro_val[CHANNEL_SCAN_INDEX_X + offset] = + *(u32 *)raw_data; + ret = 0; + break; + default: + break; + } + + return ret; +} + +/* Parse report which is specific to an usage id*/ +static int gyro_3d_parse_report(struct platform_device *pdev, + struct hid_sensor_hub_device *hsdev, + struct iio_chan_spec *channels, + unsigned usage_id, + struct gyro_3d_state *st) +{ + int ret; + int i; + + for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) { + ret = sensor_hub_input_get_attribute_info(hsdev, + HID_INPUT_REPORT, + usage_id, + HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS + i, + &st->gyro[CHANNEL_SCAN_INDEX_X + i]); + if (ret < 0) + break; + gyro_3d_adjust_channel_bit_mask(channels, + CHANNEL_SCAN_INDEX_X + i, + st->gyro[CHANNEL_SCAN_INDEX_X + i].size); + } + dev_dbg(&pdev->dev, "gyro_3d %x:%x, %x:%x, %x:%x\n", + st->gyro[0].index, + st->gyro[0].report_id, + st->gyro[1].index, st->gyro[1].report_id, + st->gyro[2].index, st->gyro[2].report_id); + + return ret; +} + +/* Function to initialize the processing for usage id */ +static int __devinit hid_gyro_3d_probe(struct platform_device *pdev) +{ + int ret = 0; + static const char *name = "gyro_3d"; + struct iio_dev *indio_dev; + struct gyro_3d_state *gyro_state; + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct iio_chan_spec *channels; + + indio_dev = iio_device_alloc(sizeof(struct gyro_3d_state)); + if (indio_dev == NULL) { + ret = -ENOMEM; + goto error_ret; + } + platform_set_drvdata(pdev, indio_dev); + + gyro_state = iio_priv(indio_dev); + gyro_state->common_attributes.hsdev = hsdev; + gyro_state->common_attributes.pdev = pdev; + + ret = hid_sensor_parse_common_attributes(hsdev, + HID_USAGE_SENSOR_GYRO_3D, + &gyro_state->common_attributes); + if (ret) { + dev_err(&pdev->dev, "failed to setup common attributes\n"); + goto error_free_dev; + } + + channels = kmemdup(gyro_3d_channels, + sizeof(gyro_3d_channels), + GFP_KERNEL); + if (!channels) { + dev_err(&pdev->dev, "failed to duplicate channels\n"); + goto error_free_dev; + } + + ret = gyro_3d_parse_report(pdev, hsdev, channels, + HID_USAGE_SENSOR_GYRO_3D, gyro_state); + if (ret) { + dev_err(&pdev->dev, "failed to setup attributes\n"); + goto error_free_dev_mem; + } + + indio_dev->channels = channels; + indio_dev->num_channels = ARRAY_SIZE(gyro_3d_channels); + indio_dev->dev.parent = &pdev->dev; + indio_dev->info = &gyro_3d_info; + indio_dev->name = name; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + NULL, NULL); + if (ret) { + dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); + goto error_free_dev_mem; + } + gyro_state->common_attributes.data_ready = false; + ret = hid_sensor_setup_trigger(indio_dev, name, + &gyro_state->common_attributes); + if (ret < 0) { + 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; + } + + gyro_state->callbacks.send_event = gyro_3d_proc_event; + gyro_state->callbacks.capture_sample = gyro_3d_capture_sample; + gyro_state->callbacks.pdev = pdev; + ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D, + &gyro_state->callbacks); + if (ret < 0) { + dev_err(&pdev->dev, "callback reg failed\n"); + goto error_iio_unreg; + } + + return ret; + +error_iio_unreg: + iio_device_unregister(indio_dev); +error_remove_trigger: + hid_sensor_remove_trigger(indio_dev); +error_unreg_buffer_funcs: + iio_triggered_buffer_cleanup(indio_dev); +error_free_dev_mem: + kfree(indio_dev->channels); +error_free_dev: + iio_device_free(indio_dev); +error_ret: + return ret; +} + +/* Function to deinitialize the processing for usage id */ +static int __devinit hid_gyro_3d_remove(struct platform_device *pdev) +{ + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_GYRO_3D); + iio_device_unregister(indio_dev); + hid_sensor_remove_trigger(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + kfree(indio_dev->channels); + iio_device_free(indio_dev); + + return 0; +} + +static struct platform_driver hid_gyro_3d_platform_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = hid_gyro_3d_probe, + .remove = hid_gyro_3d_remove, +}; +module_platform_driver(hid_gyro_3d_platform_driver); + +MODULE_DESCRIPTION("HID Sensor Gyroscope 3D"); +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index 4add9bb40eeb..d4ad37455a67 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c @@ -422,7 +422,7 @@ ssize_t iio_buffer_store_enable(struct device *dev, ret = indio_dev->setup_ops->preenable(indio_dev); if (ret) { printk(KERN_ERR - "Buffer not started:" + "Buffer not started: " "buffer preenable failed\n"); goto error_ret; } @@ -431,12 +431,12 @@ ssize_t iio_buffer_store_enable(struct device *dev, ret = buffer->access->request_update(buffer); if (ret) { printk(KERN_INFO - "Buffer not started:" + "Buffer not started: " "buffer parameter update failed\n"); goto error_ret; } } - /* Definitely possible for devices to support both of these.*/ + /* Definitely possible for devices to support both of these. */ if (indio_dev->modes & INDIO_BUFFER_TRIGGERED) { if (!indio_dev->trig) { printk(KERN_INFO @@ -456,7 +456,7 @@ ssize_t iio_buffer_store_enable(struct device *dev, ret = indio_dev->setup_ops->postenable(indio_dev); if (ret) { printk(KERN_INFO - "Buffer not started:" + "Buffer not started: " "postenable failed\n"); indio_dev->currentmode = previous_mode; if (indio_dev->setup_ops->postdisable) @@ -657,7 +657,7 @@ EXPORT_SYMBOL_GPL(iio_scan_mask_query); /** * struct iio_demux_table() - table describing demux memcpy ops * @from: index to copy from - * @to: index to copy to + * @to: index to copy to * @length: how many bytes to copy * @l: list head used for management */ @@ -682,12 +682,11 @@ static unsigned char *iio_demux(struct iio_buffer *buffer, return buffer->demux_bounce; } -int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data, - s64 timestamp) +int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data) { unsigned char *dataout = iio_demux(buffer, data); - return buffer->access->store_to(buffer, dataout, timestamp); + return buffer->access->store_to(buffer, dataout); } EXPORT_SYMBOL_GPL(iio_push_to_buffer); diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c index 2ec266ef41a3..6eb24dbc081e 100644 --- a/drivers/iio/industrialio-core.c +++ b/drivers/iio/industrialio-core.c @@ -29,7 +29,7 @@ #include <linux/iio/sysfs.h> #include <linux/iio/events.h> -/* IDA to assign each registered device a unique id*/ +/* IDA to assign each registered device a unique id */ static DEFINE_IDA(iio_ida); static dev_t iio_devt; @@ -99,6 +99,7 @@ static const char * const iio_chan_info_postfix[] = { [IIO_CHAN_INFO_FREQUENCY] = "frequency", [IIO_CHAN_INFO_PHASE] = "phase", [IIO_CHAN_INFO_HARDWAREGAIN] = "hardwaregain", + [IIO_CHAN_INFO_HYSTERESIS] = "hysteresis", }; const struct iio_chan_spec @@ -365,6 +366,7 @@ 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); + unsigned long long tmp; int val, val2; bool scale_db = false; int ret = indio_dev->info->read_raw(indio_dev, this_attr->c, @@ -390,6 +392,11 @@ static ssize_t iio_read_channel_info(struct device *dev, return sprintf(buf, "-%d.%09u\n", val, -val2); else return sprintf(buf, "%d.%09u\n", val, val2); + 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); default: return 0; } @@ -729,7 +736,7 @@ static int iio_device_register_sysfs(struct iio_dev *indio_dev) attrcount = attrcount_orig; /* * New channel registration method - relies on the fact a group does - * not need to be initialized if it is name is NULL. + * not need to be initialized if its name is NULL. */ if (indio_dev->channels) for (i = 0; i < indio_dev->num_channels; i++) { @@ -980,6 +987,6 @@ EXPORT_SYMBOL(iio_device_unregister); subsys_initcall(iio_init); module_exit(iio_exit); -MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>"); +MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); MODULE_DESCRIPTION("Industrial I/O core"); MODULE_LICENSE("GPL"); diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c index b5afc2ff34fd..f2b78d4fe457 100644 --- a/drivers/iio/inkern.c +++ b/drivers/iio/inkern.c @@ -111,6 +111,7 @@ struct iio_channel *iio_channel_get(const char *name, const char *channel_name) { struct iio_map_internal *c_i = NULL, *c = NULL; struct iio_channel *channel; + int err; if (name == NULL && channel_name == NULL) return ERR_PTR(-ENODEV); @@ -130,18 +131,32 @@ struct iio_channel *iio_channel_get(const char *name, const char *channel_name) if (c == NULL) return ERR_PTR(-ENODEV); - channel = kmalloc(sizeof(*channel), GFP_KERNEL); - if (channel == NULL) - return ERR_PTR(-ENOMEM); + channel = kzalloc(sizeof(*channel), GFP_KERNEL); + if (channel == NULL) { + err = -ENOMEM; + goto error_no_mem; + } channel->indio_dev = c->indio_dev; - if (c->map->adc_channel_label) + if (c->map->adc_channel_label) { channel->channel = iio_chan_spec_from_name(channel->indio_dev, c->map->adc_channel_label); + if (channel->channel == NULL) { + err = -EINVAL; + goto error_no_chan; + } + } + return channel; + +error_no_chan: + kfree(channel); +error_no_mem: + iio_device_put(c->indio_dev); + return ERR_PTR(err); } EXPORT_SYMBOL_GPL(iio_channel_get); @@ -229,9 +244,21 @@ void iio_channel_release_all(struct iio_channel *channels) } EXPORT_SYMBOL_GPL(iio_channel_release_all); +static int iio_channel_read(struct iio_channel *chan, int *val, int *val2, + enum iio_chan_info_enum info) +{ + int unused; + + if (val2 == NULL) + val2 = &unused; + + return chan->indio_dev->info->read_raw(chan->indio_dev, chan->channel, + val, val2, info); +} + int iio_read_channel_raw(struct iio_channel *chan, int *val) { - int val2, ret; + int ret; mutex_lock(&chan->indio_dev->info_exist_lock); if (chan->indio_dev->info == NULL) { @@ -239,8 +266,7 @@ int iio_read_channel_raw(struct iio_channel *chan, int *val) goto err_unlock; } - ret = chan->indio_dev->info->read_raw(chan->indio_dev, chan->channel, - val, &val2, 0); + ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW); err_unlock: mutex_unlock(&chan->indio_dev->info_exist_lock); @@ -248,6 +274,100 @@ err_unlock: } EXPORT_SYMBOL_GPL(iio_read_channel_raw); +static int iio_convert_raw_to_processed_unlocked(struct iio_channel *chan, + int raw, int *processed, unsigned int scale) +{ + int scale_type, scale_val, scale_val2, offset; + s64 raw64 = raw; + int ret; + + ret = iio_channel_read(chan, &offset, NULL, IIO_CHAN_INFO_SCALE); + if (ret == 0) + raw64 += offset; + + scale_type = iio_channel_read(chan, &scale_val, &scale_val2, + IIO_CHAN_INFO_SCALE); + if (scale_type < 0) + return scale_type; + + switch (scale_type) { + case IIO_VAL_INT: + *processed = raw64 * scale_val; + break; + case IIO_VAL_INT_PLUS_MICRO: + if (scale_val2 < 0) + *processed = -raw64 * scale_val; + else + *processed = raw64 * scale_val; + *processed += div_s64(raw64 * (s64)scale_val2 * scale, + 1000000LL); + break; + case IIO_VAL_INT_PLUS_NANO: + if (scale_val2 < 0) + *processed = -raw64 * scale_val; + else + *processed = raw64 * scale_val; + *processed += div_s64(raw64 * (s64)scale_val2 * scale, + 1000000000LL); + break; + case IIO_VAL_FRACTIONAL: + *processed = div_s64(raw64 * (s64)scale_val * scale, + scale_val2); + break; + default: + return -EINVAL; + } + + return 0; +} + +int iio_convert_raw_to_processed(struct iio_channel *chan, int raw, + int *processed, unsigned int scale) +{ + int ret; + + mutex_lock(&chan->indio_dev->info_exist_lock); + if (chan->indio_dev->info == NULL) { + ret = -ENODEV; + goto err_unlock; + } + + ret = iio_convert_raw_to_processed_unlocked(chan, raw, processed, + scale); +err_unlock: + mutex_unlock(&chan->indio_dev->info_exist_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(iio_convert_raw_to_processed); + +int iio_read_channel_processed(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; + } + + if (iio_channel_has_info(chan->channel, IIO_CHAN_INFO_PROCESSED)) { + ret = iio_channel_read(chan, val, NULL, + IIO_CHAN_INFO_PROCESSED); + } else { + ret = iio_channel_read(chan, val, NULL, IIO_CHAN_INFO_RAW); + if (ret < 0) + goto err_unlock; + ret = iio_convert_raw_to_processed_unlocked(chan, *val, val, 1); + } + +err_unlock: + mutex_unlock(&chan->indio_dev->info_exist_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(iio_read_channel_processed); + int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2) { int ret; @@ -258,10 +378,7 @@ int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2) goto err_unlock; } - ret = chan->indio_dev->info->read_raw(chan->indio_dev, - chan->channel, - val, val2, - IIO_CHAN_INFO_SCALE); + ret = iio_channel_read(chan, val, val2, IIO_CHAN_INFO_SCALE); err_unlock: mutex_unlock(&chan->indio_dev->info_exist_lock); diff --git a/drivers/iio/kfifo_buf.c b/drivers/iio/kfifo_buf.c index 6bf9d05f4841..5bc5c860e9ca 100644 --- a/drivers/iio/kfifo_buf.c +++ b/drivers/iio/kfifo_buf.c @@ -6,6 +6,7 @@ #include <linux/kfifo.h> #include <linux/mutex.h> #include <linux/iio/kfifo_buf.h> +#include <linux/sched.h> struct iio_kfifo { struct iio_buffer buffer; @@ -22,7 +23,8 @@ static inline int __iio_allocate_kfifo(struct iio_kfifo *buf, return -EINVAL; __iio_update_buffer(&buf->buffer, bytes_per_datum, length); - return kfifo_alloc(&buf->kf, bytes_per_datum*length, GFP_KERNEL); + return __kfifo_alloc((struct __kfifo *)&buf->kf, length, + bytes_per_datum, GFP_KERNEL); } static int iio_request_update_kfifo(struct iio_buffer *r) @@ -35,6 +37,7 @@ static int iio_request_update_kfifo(struct iio_buffer *r) kfifo_free(&buf->kf); ret = __iio_allocate_kfifo(buf, buf->buffer.bytes_per_datum, buf->buffer.length); + r->stufftoread = false; error_ret: return ret; } @@ -81,6 +84,9 @@ static int iio_set_bytes_per_datum_kfifo(struct iio_buffer *r, size_t bpd) static int iio_set_length_kfifo(struct iio_buffer *r, int length) { + /* Avoid an invalid state */ + if (length < 2) + length = 2; if (r->length != length) { r->length = length; iio_mark_update_needed_kfifo(r); @@ -89,14 +95,16 @@ static int iio_set_length_kfifo(struct iio_buffer *r, int length) } static int iio_store_to_kfifo(struct iio_buffer *r, - u8 *data, - s64 timestamp) + u8 *data) { int ret; struct iio_kfifo *kf = iio_to_kfifo(r); - ret = kfifo_in(&kf->kf, data, r->bytes_per_datum); - if (ret != r->bytes_per_datum) + ret = kfifo_in(&kf->kf, data, 1); + if (ret != 1) return -EBUSY; + r->stufftoread = true; + wake_up_interruptible(&r->pollq); + return 0; } @@ -106,11 +114,18 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r, int ret, copied; struct iio_kfifo *kf = iio_to_kfifo(r); - if (n < r->bytes_per_datum) + if (n < r->bytes_per_datum || r->bytes_per_datum == 0) return -EINVAL; - n = rounddown(n, r->bytes_per_datum); ret = kfifo_to_user(&kf->kf, buf, n, &copied); + if (ret < 0) + return ret; + + if (kfifo_is_empty(&kf->kf)) + r->stufftoread = false; + /* verify it is still empty to avoid race */ + if (!kfifo_is_empty(&kf->kf)) + r->stufftoread = true; return copied; } @@ -136,7 +151,7 @@ struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev) iio_buffer_init(&kf->buffer); kf->buffer.attrs = &iio_kfifo_attribute_group; kf->buffer.access = &kfifo_access_funcs; - + kf->buffer.length = 2; return &kf->buffer; } EXPORT_SYMBOL(iio_kfifo_allocate); diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig index 91d15d2f694f..1763c9bcb98a 100644 --- a/drivers/iio/light/Kconfig +++ b/drivers/iio/light/Kconfig @@ -42,4 +42,14 @@ config VCNL4000 To compile this driver as a module, choose M here: the module will be called vcnl4000. +config HID_SENSOR_ALS + depends on HID_SENSOR_HUB + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + select HID_SENSOR_IIO_COMMON + tristate "HID ALS" + help + Say yes here to build support for the HID SENSOR + Ambient light sensor. + endmenu diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile index 13f8a782d292..21a8f0df1407 100644 --- a/drivers/iio/light/Makefile +++ b/drivers/iio/light/Makefile @@ -5,3 +5,4 @@ obj-$(CONFIG_ADJD_S311) += adjd_s311.o obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o obj-$(CONFIG_VCNL4000) += vcnl4000.o +obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o diff --git a/drivers/iio/light/adjd_s311.c b/drivers/iio/light/adjd_s311.c index 9a99f43094f0..164b62b91a4b 100644 --- a/drivers/iio/light/adjd_s311.c +++ b/drivers/iio/light/adjd_s311.c @@ -187,7 +187,7 @@ static irqreturn_t adjd_s311_trigger_handler(int irq, void *p) if (indio_dev->scan_timestamp) *(s64 *)((u8 *)data->buffer + ALIGN(len, sizeof(s64))) = time_ns; - iio_push_to_buffer(buffer, (u8 *)data->buffer, time_ns); + iio_push_to_buffer(buffer, (u8 *)data->buffer); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c new file mode 100644 index 000000000000..96e3691e42c4 --- /dev/null +++ b/drivers/iio/light/hid-sensor-als.c @@ -0,0 +1,385 @@ +/* + * HID Sensors Driver + * Copyright (c) 2012, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#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-attributes.h" +#include "../common/hid-sensors/hid-sensor-trigger.h" + +/*Format: HID-SENSOR-usage_id_in_hex*/ +/*Usage ID from spec for Accelerometer-3D: 0x200041*/ +#define DRIVER_NAME "HID-SENSOR-200041" + +#define CHANNEL_SCAN_INDEX_ILLUM 0 + +struct als_state { + struct hid_sensor_hub_callbacks callbacks; + struct hid_sensor_iio_common common_attributes; + struct hid_sensor_hub_attribute_info als_illum; + u32 illum; +}; + +/* Channel definitions */ +static const struct iio_chan_spec als_channels[] = { + { + .type = IIO_INTENSITY, + .modified = 1, + .channel2 = IIO_MOD_LIGHT_BOTH, + .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT | + IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT, + .scan_index = CHANNEL_SCAN_INDEX_ILLUM, + } +}; + +/* Adjust channel real bits based on report descriptor */ +static void als_adjust_channel_bit_mask(struct iio_chan_spec *channels, + int channel, int size) +{ + channels[channel].scan_type.sign = 's'; + /* Real storage bits will change based on the report desc. */ + channels[channel].scan_type.realbits = size * 8; + /* Maximum size of a sample to capture is u32 */ + channels[channel].scan_type.storagebits = sizeof(u32) * 8; +} + +/* Channel read_raw handler */ +static int als_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, + long mask) +{ + struct als_state *als_state = iio_priv(indio_dev); + int report_id = -1; + u32 address; + int ret; + int ret_type; + + *val = 0; + *val2 = 0; + switch (mask) { + case 0: + switch (chan->scan_index) { + case CHANNEL_SCAN_INDEX_ILLUM: + report_id = als_state->als_illum.report_id; + address = + HID_USAGE_SENSOR_LIGHT_ILLUM; + break; + default: + report_id = -1; + break; + } + if (report_id >= 0) + *val = sensor_hub_input_attr_get_raw_value( + als_state->common_attributes.hsdev, + HID_USAGE_SENSOR_ALS, address, + report_id); + 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; + break; + case IIO_CHAN_INFO_OFFSET: + *val = hid_sensor_convert_exponent( + als_state->als_illum.unit_expo); + ret_type = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = hid_sensor_read_samp_freq_value( + &als_state->common_attributes, val, val2); + ret_type = IIO_VAL_INT_PLUS_MICRO; + break; + case IIO_CHAN_INFO_HYSTERESIS: + ret = hid_sensor_read_raw_hyst_value( + &als_state->common_attributes, val, val2); + ret_type = IIO_VAL_INT_PLUS_MICRO; + break; + default: + ret_type = -EINVAL; + break; + } + + return ret_type; +} + +/* Channel write_raw handler */ +static int als_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct als_state *als_state = iio_priv(indio_dev); + int ret = 0; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + ret = hid_sensor_write_samp_freq_value( + &als_state->common_attributes, val, val2); + break; + case IIO_CHAN_INFO_HYSTERESIS: + ret = hid_sensor_write_raw_hyst_value( + &als_state->common_attributes, val, val2); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int als_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + return IIO_VAL_INT_PLUS_MICRO; +} + +static const struct iio_info als_info = { + .driver_module = THIS_MODULE, + .read_raw = &als_read_raw, + .write_raw = &als_write_raw, + .write_raw_get_fmt = &als_write_raw_get_fmt, +}; + +/* Function to push data to buffer */ +static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len) +{ + struct iio_buffer *buffer = indio_dev->buffer; + int datum_sz; + + dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); + if (!buffer) { + dev_err(&indio_dev->dev, "Buffer == NULL\n"); + return; + } + datum_sz = buffer->access->get_bytes_per_datum(buffer); + if (len > datum_sz) { + dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len, + datum_sz); + return; + } + iio_push_to_buffer(buffer, (u8 *)data); +} + +/* Callback handler to send event after all samples are received and captured */ +static int als_proc_event(struct hid_sensor_hub_device *hsdev, + unsigned usage_id, + void *priv) +{ + 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) + hid_sensor_push_data(indio_dev, + (u8 *)&als_state->illum, + sizeof(als_state->illum)); + + return 0; +} + +/* Capture samples in local storage */ +static int als_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 als_state *als_state = iio_priv(indio_dev); + int ret = -EINVAL; + + switch (usage_id) { + case HID_USAGE_SENSOR_LIGHT_ILLUM: + als_state->illum = *(u32 *)raw_data; + ret = 0; + break; + default: + break; + } + + return ret; +} + +/* Parse report which is specific to an usage id*/ +static int als_parse_report(struct platform_device *pdev, + struct hid_sensor_hub_device *hsdev, + struct iio_chan_spec *channels, + unsigned usage_id, + struct als_state *st) +{ + int ret; + + ret = sensor_hub_input_get_attribute_info(hsdev, HID_INPUT_REPORT, + usage_id, + HID_USAGE_SENSOR_LIGHT_ILLUM, + &st->als_illum); + if (ret < 0) + return ret; + als_adjust_channel_bit_mask(channels, CHANNEL_SCAN_INDEX_ILLUM, + st->als_illum.size); + + dev_dbg(&pdev->dev, "als %x:%x\n", st->als_illum.index, + st->als_illum.report_id); + + return ret; +} + +/* Function to initialize the processing for usage id */ +static int __devinit hid_als_probe(struct platform_device *pdev) +{ + int ret = 0; + static const char *name = "als"; + struct iio_dev *indio_dev; + struct als_state *als_state; + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct iio_chan_spec *channels; + + indio_dev = iio_device_alloc(sizeof(struct als_state)); + if (indio_dev == NULL) { + ret = -ENOMEM; + goto error_ret; + } + platform_set_drvdata(pdev, indio_dev); + + als_state = iio_priv(indio_dev); + als_state->common_attributes.hsdev = hsdev; + als_state->common_attributes.pdev = pdev; + + ret = hid_sensor_parse_common_attributes(hsdev, HID_USAGE_SENSOR_ALS, + &als_state->common_attributes); + if (ret) { + dev_err(&pdev->dev, "failed to setup common attributes\n"); + goto error_free_dev; + } + + channels = kmemdup(als_channels, + sizeof(als_channels), + GFP_KERNEL); + if (!channels) { + dev_err(&pdev->dev, "failed to duplicate channels\n"); + goto error_free_dev; + } + + ret = als_parse_report(pdev, hsdev, channels, + HID_USAGE_SENSOR_ALS, als_state); + if (ret) { + dev_err(&pdev->dev, "failed to setup attributes\n"); + goto error_free_dev_mem; + } + + indio_dev->channels = channels; + indio_dev->num_channels = + ARRAY_SIZE(als_channels); + indio_dev->dev.parent = &pdev->dev; + indio_dev->info = &als_info; + indio_dev->name = name; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + NULL, NULL); + if (ret) { + dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); + goto error_free_dev_mem; + } + als_state->common_attributes.data_ready = false; + ret = hid_sensor_setup_trigger(indio_dev, name, + &als_state->common_attributes); + if (ret < 0) { + 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; + } + + als_state->callbacks.send_event = als_proc_event; + als_state->callbacks.capture_sample = als_capture_sample; + als_state->callbacks.pdev = pdev; + ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_ALS, + &als_state->callbacks); + if (ret < 0) { + dev_err(&pdev->dev, "callback reg failed\n"); + goto error_iio_unreg; + } + + return ret; + +error_iio_unreg: + iio_device_unregister(indio_dev); +error_remove_trigger: + hid_sensor_remove_trigger(indio_dev); +error_unreg_buffer_funcs: + iio_triggered_buffer_cleanup(indio_dev); +error_free_dev_mem: + kfree(indio_dev->channels); +error_free_dev: + iio_device_free(indio_dev); +error_ret: + return ret; +} + +/* Function to deinitialize the processing for usage id */ +static int __devinit hid_als_remove(struct platform_device *pdev) +{ + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_ALS); + iio_device_unregister(indio_dev); + hid_sensor_remove_trigger(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + kfree(indio_dev->channels); + iio_device_free(indio_dev); + + return 0; +} + +static struct platform_driver hid_als_platform_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = hid_als_probe, + .remove = hid_als_remove, +}; +module_platform_driver(hid_als_platform_driver); + +MODULE_DESCRIPTION("HID Sensor ALS"); +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig new file mode 100644 index 000000000000..c1f0cdd57037 --- /dev/null +++ b/drivers/iio/magnetometer/Kconfig @@ -0,0 +1,16 @@ +# +# Magnetometer sensors +# +menu "Magnetometer sensors" + +config HID_SENSOR_MAGNETOMETER_3D + depends on HID_SENSOR_HUB + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + select HID_SENSOR_IIO_COMMON + tristate "HID Magenetometer 3D" + help + Say yes here to build support for the HID SENSOR + Magnetometer 3D. + +endmenu diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile new file mode 100644 index 000000000000..60dc4f2b1963 --- /dev/null +++ b/drivers/iio/magnetometer/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for industrial I/O Magnetometer sensor drivers +# + +obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c new file mode 100644 index 000000000000..c4f0d274f577 --- /dev/null +++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c @@ -0,0 +1,419 @@ +/* + * HID Sensors Driver + * Copyright (c) 2012, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#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-attributes.h" +#include "../common/hid-sensors/hid-sensor-trigger.h" + +/*Format: HID-SENSOR-usage_id_in_hex*/ +/*Usage ID from spec for Magnetometer-3D: 0x200083*/ +#define DRIVER_NAME "HID-SENSOR-200083" + +enum magn_3d_channel { + CHANNEL_SCAN_INDEX_X, + CHANNEL_SCAN_INDEX_Y, + CHANNEL_SCAN_INDEX_Z, + MAGN_3D_CHANNEL_MAX, +}; + +struct magn_3d_state { + struct hid_sensor_hub_callbacks callbacks; + struct hid_sensor_iio_common common_attributes; + struct hid_sensor_hub_attribute_info magn[MAGN_3D_CHANNEL_MAX]; + u32 magn_val[MAGN_3D_CHANNEL_MAX]; +}; + +static const u32 magn_3d_addresses[MAGN_3D_CHANNEL_MAX] = { + HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS, + HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS, + HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS +}; + +/* Channel definitions */ +static const struct iio_chan_spec magn_3d_channels[] = { + { + .type = IIO_MAGN, + .modified = 1, + .channel2 = IIO_MOD_X, + .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT | + IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT, + .scan_index = CHANNEL_SCAN_INDEX_X, + }, { + .type = IIO_MAGN, + .modified = 1, + .channel2 = IIO_MOD_Y, + .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT | + IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT, + .scan_index = CHANNEL_SCAN_INDEX_Y, + }, { + .type = IIO_MAGN, + .modified = 1, + .channel2 = IIO_MOD_Z, + .info_mask = IIO_CHAN_INFO_OFFSET_SHARED_BIT | + IIO_CHAN_INFO_SCALE_SHARED_BIT | + IIO_CHAN_INFO_SAMP_FREQ_SHARED_BIT | + IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT, + .scan_index = CHANNEL_SCAN_INDEX_Z, + } +}; + +/* Adjust channel real bits based on report descriptor */ +static void magn_3d_adjust_channel_bit_mask(struct iio_chan_spec *channels, + int channel, int size) +{ + channels[channel].scan_type.sign = 's'; + /* Real storage bits will change based on the report desc. */ + channels[channel].scan_type.realbits = size * 8; + /* Maximum size of a sample to capture is u32 */ + channels[channel].scan_type.storagebits = sizeof(u32) * 8; +} + +/* Channel read_raw handler */ +static int magn_3d_read_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int *val, int *val2, + long mask) +{ + struct magn_3d_state *magn_state = iio_priv(indio_dev); + int report_id = -1; + u32 address; + int ret; + int ret_type; + + *val = 0; + *val2 = 0; + switch (mask) { + case 0: + report_id = + magn_state->magn[chan->scan_index].report_id; + address = magn_3d_addresses[chan->scan_index]; + if (report_id >= 0) + *val = sensor_hub_input_attr_get_raw_value( + magn_state->common_attributes.hsdev, + HID_USAGE_SENSOR_COMPASS_3D, address, + report_id); + else { + *val = 0; + return -EINVAL; + } + 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; + break; + case IIO_CHAN_INFO_OFFSET: + *val = hid_sensor_convert_exponent( + magn_state->magn[CHANNEL_SCAN_INDEX_X].unit_expo); + ret_type = IIO_VAL_INT; + break; + case IIO_CHAN_INFO_SAMP_FREQ: + ret = hid_sensor_read_samp_freq_value( + &magn_state->common_attributes, val, val2); + ret_type = IIO_VAL_INT_PLUS_MICRO; + break; + case IIO_CHAN_INFO_HYSTERESIS: + ret = hid_sensor_read_raw_hyst_value( + &magn_state->common_attributes, val, val2); + ret_type = IIO_VAL_INT_PLUS_MICRO; + break; + default: + ret_type = -EINVAL; + break; + } + + return ret_type; +} + +/* Channel write_raw handler */ +static int magn_3d_write_raw(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + int val, + int val2, + long mask) +{ + struct magn_3d_state *magn_state = iio_priv(indio_dev); + int ret = 0; + + switch (mask) { + case IIO_CHAN_INFO_SAMP_FREQ: + ret = hid_sensor_write_samp_freq_value( + &magn_state->common_attributes, val, val2); + break; + case IIO_CHAN_INFO_HYSTERESIS: + ret = hid_sensor_write_raw_hyst_value( + &magn_state->common_attributes, val, val2); + break; + default: + ret = -EINVAL; + } + + return ret; +} + +static int magn_3d_write_raw_get_fmt(struct iio_dev *indio_dev, + struct iio_chan_spec const *chan, + long mask) +{ + return IIO_VAL_INT_PLUS_MICRO; +} + +static const struct iio_info magn_3d_info = { + .driver_module = THIS_MODULE, + .read_raw = &magn_3d_read_raw, + .write_raw = &magn_3d_write_raw, + .write_raw_get_fmt = &magn_3d_write_raw_get_fmt, +}; + +/* Function to push data to buffer */ +static void hid_sensor_push_data(struct iio_dev *indio_dev, u8 *data, int len) +{ + struct iio_buffer *buffer = indio_dev->buffer; + int datum_sz; + + dev_dbg(&indio_dev->dev, "hid_sensor_push_data\n"); + if (!buffer) { + dev_err(&indio_dev->dev, "Buffer == NULL\n"); + return; + } + datum_sz = buffer->access->get_bytes_per_datum(buffer); + if (len > datum_sz) { + dev_err(&indio_dev->dev, "Datum size mismatch %d:%d\n", len, + datum_sz); + return; + } + iio_push_to_buffer(buffer, (u8 *)data); +} + +/* Callback handler to send event after all samples are received and captured */ +static int magn_3d_proc_event(struct hid_sensor_hub_device *hsdev, + unsigned usage_id, + void *priv) +{ + 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) + hid_sensor_push_data(indio_dev, + (u8 *)magn_state->magn_val, + sizeof(magn_state->magn_val)); + + return 0; +} + +/* Capture samples in local storage */ +static int magn_3d_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 magn_3d_state *magn_state = iio_priv(indio_dev); + int offset; + int ret = -EINVAL; + + switch (usage_id) { + case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS: + case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS: + case HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS: + offset = usage_id - HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS; + magn_state->magn_val[CHANNEL_SCAN_INDEX_X + offset] = + *(u32 *)raw_data; + ret = 0; + break; + default: + break; + } + + return ret; +} + +/* Parse report which is specific to an usage id*/ +static int magn_3d_parse_report(struct platform_device *pdev, + struct hid_sensor_hub_device *hsdev, + struct iio_chan_spec *channels, + unsigned usage_id, + struct magn_3d_state *st) +{ + int ret; + int i; + + for (i = 0; i <= CHANNEL_SCAN_INDEX_Z; ++i) { + ret = sensor_hub_input_get_attribute_info(hsdev, + HID_INPUT_REPORT, + usage_id, + HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS + i, + &st->magn[CHANNEL_SCAN_INDEX_X + i]); + if (ret < 0) + break; + magn_3d_adjust_channel_bit_mask(channels, + CHANNEL_SCAN_INDEX_X + i, + st->magn[CHANNEL_SCAN_INDEX_X + i].size); + } + dev_dbg(&pdev->dev, "magn_3d %x:%x, %x:%x, %x:%x\n", + st->magn[0].index, + st->magn[0].report_id, + st->magn[1].index, st->magn[1].report_id, + st->magn[2].index, st->magn[2].report_id); + + return ret; +} + +/* Function to initialize the processing for usage id */ +static int __devinit hid_magn_3d_probe(struct platform_device *pdev) +{ + int ret = 0; + static char *name = "magn_3d"; + struct iio_dev *indio_dev; + struct magn_3d_state *magn_state; + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct iio_chan_spec *channels; + + indio_dev = iio_device_alloc(sizeof(struct magn_3d_state)); + if (indio_dev == NULL) { + ret = -ENOMEM; + goto error_ret; + } + platform_set_drvdata(pdev, indio_dev); + + magn_state = iio_priv(indio_dev); + magn_state->common_attributes.hsdev = hsdev; + magn_state->common_attributes.pdev = pdev; + + ret = hid_sensor_parse_common_attributes(hsdev, + HID_USAGE_SENSOR_COMPASS_3D, + &magn_state->common_attributes); + if (ret) { + dev_err(&pdev->dev, "failed to setup common attributes\n"); + goto error_free_dev; + } + + channels = kmemdup(magn_3d_channels, + sizeof(magn_3d_channels), + GFP_KERNEL); + if (!channels) { + dev_err(&pdev->dev, "failed to duplicate channels\n"); + goto error_free_dev; + } + + ret = magn_3d_parse_report(pdev, hsdev, channels, + HID_USAGE_SENSOR_COMPASS_3D, magn_state); + if (ret) { + dev_err(&pdev->dev, "failed to setup attributes\n"); + goto error_free_dev_mem; + } + + indio_dev->channels = channels; + indio_dev->num_channels = ARRAY_SIZE(magn_3d_channels); + indio_dev->dev.parent = &pdev->dev; + indio_dev->info = &magn_3d_info; + indio_dev->name = name; + indio_dev->modes = INDIO_DIRECT_MODE; + + ret = iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, + NULL, NULL); + if (ret) { + dev_err(&pdev->dev, "failed to initialize trigger buffer\n"); + goto error_free_dev_mem; + } + magn_state->common_attributes.data_ready = false; + ret = hid_sensor_setup_trigger(indio_dev, name, + &magn_state->common_attributes); + if (ret < 0) { + 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; + } + + magn_state->callbacks.send_event = magn_3d_proc_event; + magn_state->callbacks.capture_sample = magn_3d_capture_sample; + magn_state->callbacks.pdev = pdev; + ret = sensor_hub_register_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D, + &magn_state->callbacks); + if (ret < 0) { + dev_err(&pdev->dev, "callback reg failed\n"); + goto error_iio_unreg; + } + + return ret; + +error_iio_unreg: + iio_device_unregister(indio_dev); +error_remove_trigger: + hid_sensor_remove_trigger(indio_dev); +error_unreg_buffer_funcs: + iio_triggered_buffer_cleanup(indio_dev); +error_free_dev_mem: + kfree(indio_dev->channels); +error_free_dev: + iio_device_free(indio_dev); +error_ret: + return ret; +} + +/* Function to deinitialize the processing for usage id */ +static int __devinit hid_magn_3d_remove(struct platform_device *pdev) +{ + struct hid_sensor_hub_device *hsdev = pdev->dev.platform_data; + struct iio_dev *indio_dev = platform_get_drvdata(pdev); + + sensor_hub_remove_callback(hsdev, HID_USAGE_SENSOR_COMPASS_3D); + iio_device_unregister(indio_dev); + hid_sensor_remove_trigger(indio_dev); + iio_triggered_buffer_cleanup(indio_dev); + kfree(indio_dev->channels); + iio_device_free(indio_dev); + + return 0; +} + +static struct platform_driver hid_magn_3d_platform_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + }, + .probe = hid_magn_3d_probe, + .remove = hid_magn_3d_remove, +}; +module_platform_driver(hid_magn_3d_platform_driver); + +MODULE_DESCRIPTION("HID Sensor Magnetometer 3D"); +MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index c1892f321c46..80978196aae8 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -29,6 +29,13 @@ config APM_POWER Say Y here to enable support APM status emulation using battery class devices. +config GENERIC_ADC_BATTERY + tristate "Generic battery support using IIO" + depends on IIO + help + Say Y here to enable support for the generic battery driver + which uses IIO framework to read adc. + config MAX8925_POWER tristate "MAX8925 battery charger support" depends on MFD_MAX8925 diff --git a/drivers/power/Makefile b/drivers/power/Makefile index ee58afb1e71f..e0b4d4284e1d 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -5,6 +5,7 @@ power_supply-$(CONFIG_SYSFS) += power_supply_sysfs.o power_supply-$(CONFIG_LEDS_TRIGGERS) += power_supply_leds.o obj-$(CONFIG_POWER_SUPPLY) += power_supply.o +obj-$(CONFIG_GENERIC_ADC_BATTERY) += generic-adc-battery.o obj-$(CONFIG_PDA_POWER) += pda_power.o obj-$(CONFIG_APM_POWER) += apm_power.o diff --git a/drivers/power/generic-adc-battery.c b/drivers/power/generic-adc-battery.c new file mode 100644 index 000000000000..9bdf44470396 --- /dev/null +++ b/drivers/power/generic-adc-battery.c @@ -0,0 +1,422 @@ +/* + * Generic battery driver code using IIO + * Copyright (C) 2012, Anish Kumar <anish198519851985@gmail.com> + * based on jz4740-battery.c + * based on s3c_adc_battery.c + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + */ +#include <linux/interrupt.h> +#include <linux/platform_device.h> +#include <linux/power_supply.h> +#include <linux/gpio.h> +#include <linux/err.h> +#include <linux/timer.h> +#include <linux/jiffies.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/iio/consumer.h> +#include <linux/iio/types.h> +#include <linux/power/generic-adc-battery.h> + +#define JITTER_DEFAULT 10 /* hope 10ms is enough */ + +enum gab_chan_type { + GAB_VOLTAGE = 0, + GAB_CURRENT, + GAB_POWER, + GAB_MAX_CHAN_TYPE +}; + +/* + * gab_chan_name suggests the standard channel names for commonly used + * channel types. + */ +static const char *const gab_chan_name[] = { + [GAB_VOLTAGE] = "voltage", + [GAB_CURRENT] = "current", + [GAB_POWER] = "power", +}; + +struct gab { + struct power_supply psy; + struct iio_channel *channel[GAB_MAX_CHAN_TYPE]; + struct gab_platform_data *pdata; + struct delayed_work bat_work; + int level; + int status; + bool cable_plugged; +}; + +static struct gab *to_generic_bat(struct power_supply *psy) +{ + return container_of(psy, struct gab, psy); +} + +static void gab_ext_power_changed(struct power_supply *psy) +{ + struct gab *adc_bat = to_generic_bat(psy); + + schedule_delayed_work(&adc_bat->bat_work, msecs_to_jiffies(0)); +} + +static const enum power_supply_property gab_props[] = { + POWER_SUPPLY_PROP_STATUS, + POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN, + POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN, + POWER_SUPPLY_PROP_CHARGE_NOW, + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_TECHNOLOGY, + POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, + POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN, + POWER_SUPPLY_PROP_MODEL_NAME, +}; + +/* + * This properties are set based on the received platform data and this + * should correspond one-to-one with enum chan_type. + */ +static const enum power_supply_property gab_dyn_props[] = { + POWER_SUPPLY_PROP_VOLTAGE_NOW, + POWER_SUPPLY_PROP_CURRENT_NOW, + POWER_SUPPLY_PROP_POWER_NOW, +}; + +static bool gab_charge_finished(struct gab *adc_bat) +{ + struct gab_platform_data *pdata = adc_bat->pdata; + bool ret = gpio_get_value(pdata->gpio_charge_finished); + bool inv = pdata->gpio_inverted; + + if (!gpio_is_valid(pdata->gpio_charge_finished)) + return false; + return ret ^ inv; +} + +static int gab_get_status(struct gab *adc_bat) +{ + struct gab_platform_data *pdata = adc_bat->pdata; + struct power_supply_info *bat_info; + + bat_info = &pdata->battery_info; + if (adc_bat->level == bat_info->charge_full_design) + return POWER_SUPPLY_STATUS_FULL; + return adc_bat->status; +} + +static enum gab_chan_type gab_prop_to_chan(enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_POWER_NOW: + return GAB_POWER; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + return GAB_VOLTAGE; + case POWER_SUPPLY_PROP_CURRENT_NOW: + return GAB_CURRENT; + default: + WARN_ON(1); + break; + } + return GAB_POWER; +} + +static int read_channel(struct gab *adc_bat, enum power_supply_property psp, + int *result) +{ + int ret; + int chan_index; + + chan_index = gab_prop_to_chan(psp); + ret = iio_read_channel_processed(adc_bat->channel[chan_index], + result); + if (ret < 0) + pr_err("read channel error\n"); + return ret; +} + +static int gab_get_property(struct power_supply *psy, + enum power_supply_property psp, union power_supply_propval *val) +{ + struct gab *adc_bat; + struct gab_platform_data *pdata; + struct power_supply_info *bat_info; + int result = 0; + int ret = 0; + + adc_bat = to_generic_bat(psy); + if (!adc_bat) { + dev_err(psy->dev, "no battery infos ?!\n"); + return -EINVAL; + } + pdata = adc_bat->pdata; + bat_info = &pdata->battery_info; + + switch (psp) { + case POWER_SUPPLY_PROP_STATUS: + gab_get_status(adc_bat); + break; + case POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN: + val->intval = 0; + break; + case POWER_SUPPLY_PROP_CHARGE_NOW: + val->intval = pdata->cal_charge(result); + break; + case POWER_SUPPLY_PROP_VOLTAGE_NOW: + case POWER_SUPPLY_PROP_CURRENT_NOW: + case POWER_SUPPLY_PROP_POWER_NOW: + ret = read_channel(adc_bat, psp, &result); + if (ret < 0) + goto err; + val->intval = result; + break; + case POWER_SUPPLY_PROP_TECHNOLOGY: + val->intval = bat_info->technology; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: + val->intval = bat_info->voltage_min_design; + break; + case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: + val->intval = bat_info->voltage_max_design; + break; + case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: + val->intval = bat_info->charge_full_design; + break; + case POWER_SUPPLY_PROP_MODEL_NAME: + val->strval = bat_info->name; + break; + default: + return -EINVAL; + } +err: + return ret; +} + +static void gab_work(struct work_struct *work) +{ + struct gab *adc_bat; + struct gab_platform_data *pdata; + struct delayed_work *delayed_work; + bool is_plugged; + int status; + + delayed_work = container_of(work, struct delayed_work, work); + adc_bat = container_of(delayed_work, struct gab, bat_work); + pdata = adc_bat->pdata; + status = adc_bat->status; + + is_plugged = power_supply_am_i_supplied(&adc_bat->psy); + adc_bat->cable_plugged = is_plugged; + + if (!is_plugged) + adc_bat->status = POWER_SUPPLY_STATUS_DISCHARGING; + else if (gab_charge_finished(adc_bat)) + adc_bat->status = POWER_SUPPLY_STATUS_NOT_CHARGING; + else + adc_bat->status = POWER_SUPPLY_STATUS_CHARGING; + + if (status != adc_bat->status) + power_supply_changed(&adc_bat->psy); +} + +static irqreturn_t gab_charged(int irq, void *dev_id) +{ + struct gab *adc_bat = dev_id; + struct gab_platform_data *pdata = adc_bat->pdata; + int delay; + + delay = pdata->jitter_delay ? pdata->jitter_delay : JITTER_DEFAULT; + schedule_delayed_work(&adc_bat->bat_work, + msecs_to_jiffies(delay)); + return IRQ_HANDLED; +} + +static int __devinit gab_probe(struct platform_device *pdev) +{ + struct gab *adc_bat; + struct power_supply *psy; + struct gab_platform_data *pdata = pdev->dev.platform_data; + enum power_supply_property *properties; + int ret = 0; + int chan; + int index = 0; + + adc_bat = devm_kzalloc(&pdev->dev, sizeof(*adc_bat), GFP_KERNEL); + if (!adc_bat) { + dev_err(&pdev->dev, "failed to allocate memory\n"); + return -ENOMEM; + } + + psy = &adc_bat->psy; + psy->name = pdata->battery_info.name; + + /* bootup default values for the battery */ + adc_bat->cable_plugged = false; + adc_bat->status = POWER_SUPPLY_STATUS_DISCHARGING; + psy->type = POWER_SUPPLY_TYPE_BATTERY; + psy->get_property = gab_get_property; + psy->external_power_changed = gab_ext_power_changed; + adc_bat->pdata = pdata; + + /* calculate the total number of channels */ + chan = ARRAY_SIZE(gab_chan_name); + + /* + * copying the static properties and allocating extra memory for holding + * the extra configurable properties received from platform data. + */ + psy->properties = kcalloc(ARRAY_SIZE(gab_props) + + ARRAY_SIZE(gab_chan_name), + sizeof(*psy->properties), GFP_KERNEL); + if (!psy->properties) { + ret = -ENOMEM; + goto first_mem_fail; + } + + memcpy(psy->properties, gab_props, sizeof(gab_props)); + properties = psy->properties + sizeof(gab_props); + + /* + * getting channel from iio and copying the battery properties + * based on the channel supported by consumer device. + */ + for (chan = 0; chan < ARRAY_SIZE(gab_chan_name); chan++) { + adc_bat->channel[chan] = iio_channel_get(dev_name(&pdev->dev), + gab_chan_name[chan]); + if (IS_ERR(adc_bat->channel[chan])) { + ret = PTR_ERR(adc_bat->channel[chan]); + } else { + /* copying properties for supported channels only */ + memcpy(properties + sizeof(*(psy->properties)) * index, + &gab_dyn_props[chan], + sizeof(gab_dyn_props[chan])); + index++; + } + } + + /* none of the channels are supported so let's bail out */ + if (index == ARRAY_SIZE(gab_chan_name)) + goto second_mem_fail; + + /* + * Total number of properties is equal to static properties + * plus the dynamic properties.Some properties may not be set + * as come channels may be not be supported by the device.So + * we need to take care of that. + */ + psy->num_properties = ARRAY_SIZE(gab_props) + index; + + ret = power_supply_register(&pdev->dev, psy); + if (ret) + goto err_reg_fail; + + INIT_DELAYED_WORK(&adc_bat->bat_work, gab_work); + + if (gpio_is_valid(pdata->gpio_charge_finished)) { + int irq; + ret = gpio_request(pdata->gpio_charge_finished, "charged"); + if (ret) + goto gpio_req_fail; + + irq = gpio_to_irq(pdata->gpio_charge_finished); + ret = request_any_context_irq(irq, gab_charged, + IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, + "battery charged", adc_bat); + if (ret) + goto err_gpio; + } + + platform_set_drvdata(pdev, adc_bat); + + /* Schedule timer to check current status */ + schedule_delayed_work(&adc_bat->bat_work, + msecs_to_jiffies(0)); + return 0; + +err_gpio: + gpio_free(pdata->gpio_charge_finished); +gpio_req_fail: + power_supply_unregister(psy); +err_reg_fail: + for (chan = 0; ARRAY_SIZE(gab_chan_name); chan++) + iio_channel_release(adc_bat->channel[chan]); +second_mem_fail: + kfree(psy->properties); +first_mem_fail: + return ret; +} + +static int __devexit gab_remove(struct platform_device *pdev) +{ + int chan; + struct gab *adc_bat = platform_get_drvdata(pdev); + struct gab_platform_data *pdata = adc_bat->pdata; + + power_supply_unregister(&adc_bat->psy); + + if (gpio_is_valid(pdata->gpio_charge_finished)) { + free_irq(gpio_to_irq(pdata->gpio_charge_finished), adc_bat); + gpio_free(pdata->gpio_charge_finished); + } + + for (chan = 0; ARRAY_SIZE(gab_chan_name); chan++) + iio_channel_release(adc_bat->channel[chan]); + + kfree(adc_bat->psy.properties); + cancel_delayed_work(&adc_bat->bat_work); + return 0; +} + +#ifdef CONFIG_PM +static int gab_suspend(struct device *dev) +{ + struct gab *adc_bat = dev_get_drvdata(dev); + + cancel_delayed_work_sync(&adc_bat->bat_work); + adc_bat->status = POWER_SUPPLY_STATUS_UNKNOWN; + return 0; +} + +static int gab_resume(struct device *dev) +{ + struct gab *adc_bat = dev_get_drvdata(dev); + struct gab_platform_data *pdata = adc_bat->pdata; + int delay; + + delay = pdata->jitter_delay ? pdata->jitter_delay : JITTER_DEFAULT; + + /* Schedule timer to check current status */ + schedule_delayed_work(&adc_bat->bat_work, + msecs_to_jiffies(delay)); + return 0; +} + +static const struct dev_pm_ops gab_pm_ops = { + .suspend = gab_suspend, + .resume = gab_resume, +}; + +#define GAB_PM_OPS (&gab_pm_ops) +#else +#define GAB_PM_OPS (NULL) +#endif + +static struct platform_driver gab_driver = { + .driver = { + .name = "generic-adc-battery", + .owner = THIS_MODULE, + .pm = GAB_PM_OPS + }, + .probe = gab_probe, + .remove = __devexit_p(gab_remove), +}; +module_platform_driver(gab_driver); + +MODULE_AUTHOR("anish kumar <anish198519851985@gmail.com>"); +MODULE_DESCRIPTION("generic battery driver using IIO"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index e3402d5644dd..0f51a158ef70 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -122,8 +122,6 @@ source "drivers/staging/android/Kconfig" source "drivers/staging/telephony/Kconfig" -source "drivers/staging/ramster/Kconfig" - source "drivers/staging/ozwpan/Kconfig" source "drivers/staging/ccg/Kconfig" @@ -136,4 +134,12 @@ source "drivers/staging/csr/Kconfig" source "drivers/staging/omap-thermal/Kconfig" +source "drivers/staging/ramster/Kconfig" + +source "drivers/staging/silicom/Kconfig" + +source "drivers/staging/ced1401/Kconfig" + +source "drivers/staging/imx-drm/Kconfig" + endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 3be59d02cae4..f4b2bc41f1d1 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -54,9 +54,12 @@ obj-$(CONFIG_MFD_NVEC) += nvec/ obj-$(CONFIG_DRM_OMAP) += omapdrm/ obj-$(CONFIG_ANDROID) += android/ obj-$(CONFIG_PHONE) += telephony/ -obj-$(CONFIG_RAMSTER) += ramster/ obj-$(CONFIG_USB_WPAN_HCD) += ozwpan/ obj-$(CONFIG_USB_G_CCG) += ccg/ obj-$(CONFIG_WIMAX_GDM72XX) += gdm72xx/ obj-$(CONFIG_CSR_WIFI) += csr/ obj-$(CONFIG_OMAP_BANDGAP) += omap-thermal/ +obj-$(CONFIG_ZCACHE2) += ramster/ +obj-$(CONFIG_NET_VENDOR_SILICOM) += silicom/ +obj-$(CONFIG_CED1401) += ced1401/ +obj-$(CONFIG_DRM_IMX) += imx-drm/ diff --git a/drivers/staging/android/alarm-dev.c b/drivers/staging/android/alarm-dev.c index 5b7064005188..a9b293ff3cc8 100644 --- a/drivers/staging/android/alarm-dev.c +++ b/drivers/staging/android/alarm-dev.c @@ -67,10 +67,8 @@ static struct devalarm alarms[ANDROID_ALARM_TYPE_COUNT]; static int is_wakeup(enum android_alarm_type type) { - if (type == ANDROID_ALARM_RTC_WAKEUP || - type == ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP) - return 1; - return 0; + return (type == ANDROID_ALARM_RTC_WAKEUP || + type == ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP); } @@ -85,12 +83,9 @@ static void devalarm_start(struct devalarm *alrm, ktime_t exp) static int devalarm_try_to_cancel(struct devalarm *alrm) { - int ret; if (is_wakeup(alrm->type)) - ret = alarm_try_to_cancel(&alrm->u.alrm); - else - ret = hrtimer_try_to_cancel(&alrm->u.hrt); - return ret; + return alarm_try_to_cancel(&alrm->u.alrm); + return hrtimer_try_to_cancel(&alrm->u.hrt); } static void devalarm_cancel(struct devalarm *alrm) @@ -223,10 +218,12 @@ from_old_alarm_set: case ANDROID_ALARM_ELAPSED_REALTIME: get_monotonic_boottime(&tmp_time); break; - case ANDROID_ALARM_TYPE_COUNT: case ANDROID_ALARM_SYSTEMTIME: ktime_get_ts(&tmp_time); break; + default: + rv = -EINVAL; + goto err1; } if (copy_to_user((void __user *)arg, &tmp_time, sizeof(tmp_time))) { diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c index 69cf2db1d69c..94a740d2883d 100644 --- a/drivers/staging/android/ashmem.c +++ b/drivers/staging/android/ashmem.c @@ -1,20 +1,20 @@ /* mm/ashmem.c -** -** Anonymous Shared Memory Subsystem, ashmem -** -** Copyright (C) 2008 Google, Inc. -** -** Robert Love <rlove@google.com> -** -** 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. -*/ + * + * Anonymous Shared Memory Subsystem, ashmem + * + * Copyright (C) 2008 Google, Inc. + * + * Robert Love <rlove@google.com> + * + * 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. + */ #define pr_fmt(fmt) "ashmem: " fmt diff --git a/drivers/staging/android/binder.c b/drivers/staging/android/binder.c index 574e99210c36..a807129c7b5a 100644 --- a/drivers/staging/android/binder.c +++ b/drivers/staging/android/binder.c @@ -365,7 +365,7 @@ binder_defer_work(struct binder_proc *proc, enum binder_deferred_state defer); /* * copied from get_unused_fd_flags */ -int task_get_unused_fd_flags(struct binder_proc *proc, int flags) +static int task_get_unused_fd_flags(struct binder_proc *proc, int flags) { struct files_struct *files = proc->files; int fd, error; @@ -415,13 +415,13 @@ repeat: else __clear_close_on_exec(fd, fdt); files->next_fd = fd + 1; -#if 1 + /* Sanity check */ if (fdt->fd[fd] != NULL) { pr_warn("get_unused_fd: slot %d not NULL!\n", fd); fdt->fd[fd] = NULL; } -#endif + error = fd; out: diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c index f7b8237d5be7..1d5ed475364b 100644 --- a/drivers/staging/android/logger.c +++ b/drivers/staging/android/logger.c @@ -32,38 +32,50 @@ #include <asm/ioctls.h> -/* +/** * struct logger_log - represents a specific log, such as 'main' or 'radio' + * @buffer: The actual ring buffer + * @misc: The "misc" device representing the log + * @wq: The wait queue for @readers + * @readers: This log's readers + * @mutex: The mutex that protects the @buffer + * @w_off: The current write head offset + * @head: The head, or location that readers start reading at. + * @size: The size of the log + * @logs: The list of log channels * * This structure lives from module insertion until module removal, so it does * not need additional reference counting. The structure is protected by the * mutex 'mutex'. */ struct logger_log { - unsigned char *buffer;/* the ring buffer itself */ - struct miscdevice misc; /* misc device representing the log */ - wait_queue_head_t wq; /* wait queue for readers */ - struct list_head readers; /* this log's readers */ - struct mutex mutex; /* mutex protecting buffer */ - size_t w_off; /* current write head offset */ - size_t head; /* new readers start here */ - size_t size; /* size of the log */ - struct list_head logs; /* list of log channels (myself)*/ + unsigned char *buffer; + struct miscdevice misc; + wait_queue_head_t wq; + struct list_head readers; + struct mutex mutex; + size_t w_off; + size_t head; + size_t size; + struct list_head logs; }; static LIST_HEAD(log_list); -/* +/** * struct logger_reader - a logging device open for reading + * @log: The associated log + * @list: The associated entry in @logger_log's list + * @r_off: The current read head offset. * * This object lives from open to release, so we don't need additional * reference counting. The structure is protected by log->mutex. */ struct logger_reader { - struct logger_log *log; /* associated log */ - struct list_head list; /* entry in logger_log's list */ - size_t r_off; /* current read head offset */ + struct logger_log *log; + struct list_head list; + size_t r_off; }; /* logger_offset - returns index 'n' into the log via (optimized) modulus */ diff --git a/drivers/staging/android/logger.h b/drivers/staging/android/logger.h index 2cb06e9d8f98..9b929a8c7468 100644 --- a/drivers/staging/android/logger.h +++ b/drivers/staging/android/logger.h @@ -20,14 +20,24 @@ #include <linux/types.h> #include <linux/ioctl.h> +/** + * struct logger_entry - defines a single entry that is given to a logger + * @len: The length of the payload + * @__pad: Two bytes of padding that appear to be required + * @pid: The generating process' process ID + * @tid: The generating process' thread ID + * @sec: The number of seconds that have elapsed since the Epoch + * @nsec: The number of nanoseconds that have elapsed since @sec + * @msg: The message that is to be logged + */ struct logger_entry { - __u16 len; /* length of the payload */ - __u16 __pad; /* no matter what, we get 2 bytes of padding */ - __s32 pid; /* generating process's pid */ - __s32 tid; /* generating process's tid */ - __s32 sec; /* seconds since Epoch */ - __s32 nsec; /* nanoseconds */ - char msg[0]; /* the entry's payload */ + __u16 len; + __u16 __pad; + __s32 pid; + __s32 tid; + __s32 sec; + __s32 nsec; + char msg[0]; }; #define LOGGER_LOG_RADIO "log_radio" /* radio-related messages */ diff --git a/drivers/staging/android/timed_gpio.c b/drivers/staging/android/timed_gpio.c index 45c522cbe784..e81451425c01 100644 --- a/drivers/staging/android/timed_gpio.c +++ b/drivers/staging/android/timed_gpio.c @@ -161,18 +161,7 @@ static struct platform_driver timed_gpio_driver = { }, }; -static int __init timed_gpio_init(void) -{ - return platform_driver_register(&timed_gpio_driver); -} - -static void __exit timed_gpio_exit(void) -{ - platform_driver_unregister(&timed_gpio_driver); -} - -module_init(timed_gpio_init); -module_exit(timed_gpio_exit); +module_platform_driver(timed_gpio_driver); MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>"); MODULE_DESCRIPTION("timed gpio driver"); diff --git a/drivers/staging/asus_oled/asus_oled.c b/drivers/staging/asus_oled/asus_oled.c index f63c1d3aeb64..00185478647a 100644 --- a/drivers/staging/asus_oled/asus_oled.c +++ b/drivers/staging/asus_oled/asus_oled.c @@ -42,8 +42,6 @@ #define ASUS_OLED_NAME "asus-oled" #define ASUS_OLED_UNDERSCORE_NAME "asus_oled" -#define ASUS_OLED_ERROR "Asus OLED Display Error: " - #define ASUS_OLED_STATIC 's' #define ASUS_OLED_ROLL 'r' #define ASUS_OLED_FLASH 'f' @@ -57,8 +55,9 @@ #define USB_DEVICE_ID_ASUS_LCM2 0x175b MODULE_AUTHOR("Jakub Schmidtke, sjakub@gmail.com"); -MODULE_DESCRIPTION("Asus OLED Driver v" ASUS_OLED_VERSION); +MODULE_DESCRIPTION("Asus OLED Driver"); MODULE_LICENSE("GPL"); +MODULE_VERSION(ASUS_OLED_VERSION); static struct class *oled_class; static int oled_num; @@ -138,6 +137,7 @@ struct asus_oled_dev { size_t buf_size; char *buf; uint8_t enabled; + uint8_t enabled_post_resume; struct device *dev; }; @@ -383,13 +383,13 @@ static int append_values(struct asus_oled_dev *odev, uint8_t val, size_t count) default: i = 0; - printk(ASUS_OLED_ERROR "Unknown OLED Pack Mode: %d!\n", + dev_err(odev->dev, "Unknown OLED Pack Mode: %d!\n", odev->pack_mode); break; } if (i >= odev->buf_size) { - printk(ASUS_OLED_ERROR "Buffer overflow! Report a bug:" + dev_err(odev->dev, "Buffer overflow! Report a bug:" "offs: %d >= %d i: %d (x: %d y: %d)\n", (int) odev->buf_offs, (int) odev->buf_size, (int) i, (int) x, (int) y); @@ -435,7 +435,7 @@ static ssize_t odev_set_picture(struct asus_oled_dev *odev, odev->buf = kmalloc(odev->buf_size, GFP_KERNEL); if (odev->buf == NULL) { odev->buf_size = 0; - printk(ASUS_OLED_ERROR "Out of memory!\n"); + dev_err(odev->dev, "Out of memory!\n"); return -ENOMEM; } @@ -473,7 +473,7 @@ static ssize_t odev_set_picture(struct asus_oled_dev *odev, odev->pic_mode = buf[1]; break; default: - printk(ASUS_OLED_ERROR "Wrong picture mode: '%c'.\n", + dev_err(odev->dev, "Wrong picture mode: '%c'.\n", buf[1]); return -EIO; break; @@ -533,7 +533,7 @@ static ssize_t odev_set_picture(struct asus_oled_dev *odev, if (odev->buf == NULL) { odev->buf_size = 0; - printk(ASUS_OLED_ERROR "Out of memory!\n"); + dev_err(odev->dev, "Out of memory!\n"); return -ENOMEM; } @@ -593,15 +593,15 @@ static ssize_t odev_set_picture(struct asus_oled_dev *odev, return count; error_width: - printk(ASUS_OLED_ERROR "Wrong picture width specified.\n"); + dev_err(odev->dev, "Wrong picture width specified.\n"); return -EIO; error_height: - printk(ASUS_OLED_ERROR "Wrong picture height specified.\n"); + dev_err(odev->dev, "Wrong picture height specified.\n"); return -EIO; error_header: - printk(ASUS_OLED_ERROR "Wrong picture header.\n"); + dev_err(odev->dev, "Wrong picture header.\n"); return -EIO; } @@ -766,11 +766,45 @@ static void asus_oled_disconnect(struct usb_interface *interface) dev_info(&interface->dev, "Disconnected Asus OLED device\n"); } +#ifdef CONFIG_PM +static int asus_oled_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct asus_oled_dev *odev; + + odev = usb_get_intfdata(intf); + if (!odev) + return -ENODEV; + + odev->enabled_post_resume = odev->enabled; + enable_oled(odev, 0); + + return 0; +} + +static int asus_oled_resume(struct usb_interface *intf) +{ + struct asus_oled_dev *odev; + + odev = usb_get_intfdata(intf); + if (!odev) + return -ENODEV; + + enable_oled(odev, odev->enabled_post_resume); + + return 0; +} +#else +#define asus_oled_suspend NULL +#define asus_oled_resume NULL +#endif + static struct usb_driver oled_driver = { .name = ASUS_OLED_NAME, .probe = asus_oled_probe, .disconnect = asus_oled_disconnect, .id_table = id_table, + .suspend = asus_oled_suspend, + .resume = asus_oled_resume, }; static CLASS_ATTR_STRING(version, S_IRUGO, diff --git a/drivers/staging/bcm/Bcmchar.c b/drivers/staging/bcm/Bcmchar.c index cf411d1706b1..3d02c2ebfb8d 100644 --- a/drivers/staging/bcm/Bcmchar.c +++ b/drivers/staging/bcm/Bcmchar.c @@ -820,6 +820,7 @@ cntrlEnd: if (copy_from_user(psFwInfo, IoBuffer.InputBuffer, IoBuffer.InputLength)) { up(&Adapter->fw_download_sema); + kfree(psFwInfo); return -EFAULT; } @@ -829,6 +830,7 @@ cntrlEnd: BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Something else is wrong %lu\n", psFwInfo->u32FirmwareLength); up(&Adapter->fw_download_sema); + kfree(psFwInfo); Status = -EINVAL; return Status; } diff --git a/drivers/staging/bcm/CmHost.c b/drivers/staging/bcm/CmHost.c index b54ec974477f..325b592fd41f 100644 --- a/drivers/staging/bcm/CmHost.c +++ b/drivers/staging/bcm/CmHost.c @@ -235,7 +235,7 @@ void ClearTargetDSXBuffer(struct bcm_mini_adapter *Adapter, B_UINT16 TID, BOOLEA * @ingroup ctrl_pkt_functions * copy classifier rule into the specified SF index */ -static inline VOID CopyClassifierRuleToSF(struct bcm_mini_adapter *Adapter, stConvergenceSLTypes *psfCSType, UINT uiSearchRuleIndex, UINT nClassifierIndex) +static inline VOID CopyClassifierRuleToSF(struct bcm_mini_adapter *Adapter, struct bcm_convergence_types *psfCSType, UINT uiSearchRuleIndex, UINT nClassifierIndex) { struct bcm_classifier_rule *pstClassifierEntry = NULL; /* VOID *pvPhsContext = NULL; */ @@ -428,7 +428,7 @@ VOID DeleteAllClassifiersForSF(struct bcm_mini_adapter *Adapter, UINT uiSearchRu * @ingroup ctrl_pkt_functions */ static VOID CopyToAdapter(register struct bcm_mini_adapter *Adapter, /* <Pointer to the Adapter structure */ - register pstServiceFlowParamSI psfLocalSet, /* <Pointer to the ServiceFlowParamSI structure */ + register struct bcm_connect_mgr_params *psfLocalSet, /* Pointer to the connection manager parameters structure */ register UINT uiSearchRuleIndex, /* <Index of Queue, to which this data belongs */ register UCHAR ucDsxType, stLocalSFAddIndicationAlt *pstAddIndication) { @@ -439,7 +439,7 @@ static VOID CopyToAdapter(register struct bcm_mini_adapter *Adapter, /* <Pointer enum E_CLASSIFIER_ACTION eClassifierAction = eInvalidClassifierAction; B_UINT16 u16PacketClassificationRuleIndex = 0; int i; - stConvergenceSLTypes *psfCSType = NULL; + struct bcm_convergence_types *psfCSType = NULL; S_PHS_RULE sPhsRule; USHORT uVCID = Adapter->PackInfo[uiSearchRuleIndex].usVCID_Value; UINT UGIValue = 0; @@ -915,7 +915,7 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) if (!pstAddIndication->sfAuthorizedSet.bValid) pstAddIndication->sfAuthorizedSet.bValid = 1; for (nIndex = 0; nIndex < nCurClassifierCnt; nIndex++) { - stConvergenceSLTypes *psfCSType = NULL; + struct bcm_convergence_types *psfCSType = NULL; psfCSType = &pstAddIndication->sfAuthorizedSet.cConvergenceSLTypes[nIndex]; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "psfCSType = %p", psfCSType); @@ -999,13 +999,10 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) #ifdef VERSION_D5 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPv6FlowLableLength: 0x%X ", psfCSType->cCPacketClassificationRule.u8IPv6FlowLableLength); - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPv6FlowLable[6]: 0x %02X %02X %02X %02X %02X %02X ", - psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[0], - psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[1], - psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[2], - psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[3], - psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[4], - psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[5]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, "u8IPv6FlowLable[6]: 0x%*ph ", + 6, psfCSType->cCPacketClassificationRule. + u8IPv6FlowLable); #endif } @@ -1015,13 +1012,9 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16CID: 0x%X", pstAddIndication->sfAdmittedSet.u16CID); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceClassNameLength: 0x%X", pstAddIndication->sfAdmittedSet.u8ServiceClassNameLength); - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceClassName: 0x %02X %02X %02X %02X %02X %02X", - pstAddIndication->sfAdmittedSet.u8ServiceClassName[0], - pstAddIndication->sfAdmittedSet.u8ServiceClassName[1], - pstAddIndication->sfAdmittedSet.u8ServiceClassName[2], - pstAddIndication->sfAdmittedSet.u8ServiceClassName[3], - pstAddIndication->sfAdmittedSet.u8ServiceClassName[4], - pstAddIndication->sfAdmittedSet.u8ServiceClassName[5]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, + "u8ServiceClassName: 0x%*ph", + 6, pstAddIndication->sfAdmittedSet.u8ServiceClassName); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8MBSService: 0x%02X", pstAddIndication->sfAdmittedSet.u8MBSService); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8QosParamSet: 0x%02X", pstAddIndication->sfAdmittedSet.u8QosParamSet); @@ -1066,7 +1059,7 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) nCurClassifierCnt = MAX_CLASSIFIERS_IN_SF; for (nIndex = 0; nIndex < nCurClassifierCnt; nIndex++) { - stConvergenceSLTypes *psfCSType = NULL; + struct bcm_convergence_types *psfCSType = NULL; psfCSType = &pstAddIndication->sfAdmittedSet.cConvergenceSLTypes[nIndex]; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " CCPacketClassificationRuleSI====>"); @@ -1074,10 +1067,10 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) psfCSType->cCPacketClassificationRule.u8ClassifierRulePriority); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPTypeOfServiceLength: 0x%02X", psfCSType->cCPacketClassificationRule.u8IPTypeOfServiceLength); - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPTypeOfService[3]: 0x%02X %02X %02X", - psfCSType->cCPacketClassificationRule.u8IPTypeOfService[0], - psfCSType->cCPacketClassificationRule.u8IPTypeOfService[1], - psfCSType->cCPacketClassificationRule.u8IPTypeOfService[2]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, "u8IPTypeOfService[3]: 0x%*ph", + 3, psfCSType->cCPacketClassificationRule. + u8IPTypeOfService); for (uiLoopIndex = 0; uiLoopIndex < 1; uiLoopIndex++) BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8Protocol: 0x%02X ", psfCSType->cCPacketClassificationRule.u8Protocol); @@ -1098,20 +1091,20 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolSourcePortRangeLength: 0x%02X ", psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRangeLength); - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolSourcePortRange[4]: 0x %02X %02X %02X %02X ", - psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[0], - psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[1], - psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[2], - psfCSType->cCPacketClassificationRule.u8ProtocolSourcePortRange[3]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, "u8ProtocolSourcePortRange[4]: " + "0x%*ph ", 4, psfCSType-> + cCPacketClassificationRule. + u8ProtocolSourcePortRange); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolDestPortRangeLength: 0x%02X ", psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRangeLength); - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ProtocolDestPortRange[4]: 0x %02X %02X %02X %02X ", - psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[0], - psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[1], - psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[2], - psfCSType->cCPacketClassificationRule.u8ProtocolDestPortRange[3]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, "u8ProtocolDestPortRange[4]: " + "0x%*ph ", 4, psfCSType-> + cCPacketClassificationRule. + u8ProtocolDestPortRange); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthernetDestMacAddressLength: 0x%02X ", psfCSType->cCPacketClassificationRule.u8EthernetDestMacAddressLength); @@ -1130,10 +1123,10 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) u8EthernetSourceMACAddress); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8EthertypeLength: 0x%02X ", psfCSType->cCPacketClassificationRule.u8EthertypeLength); - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8Ethertype[3]: 0x%02X %02X %02X", - psfCSType->cCPacketClassificationRule.u8Ethertype[0], - psfCSType->cCPacketClassificationRule.u8Ethertype[1], - psfCSType->cCPacketClassificationRule.u8Ethertype[2]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, "u8Ethertype[3]: 0x%*ph", + 3, psfCSType->cCPacketClassificationRule. + u8Ethertype); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16UserPriority: 0x%X ", psfCSType->cCPacketClassificationRule.u16UserPriority); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16VLANID: 0x%X ", psfCSType->cCPacketClassificationRule.u16VLANID); @@ -1147,13 +1140,10 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) #ifdef VERSION_D5 BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPv6FlowLableLength: 0x%X ", psfCSType->cCPacketClassificationRule.u8IPv6FlowLableLength); - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8IPv6FlowLable[6]: 0x %02X %02X %02X %02X %02X %02X ", - psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[0], - psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[1], - psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[2], - psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[3], - psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[4], - psfCSType->cCPacketClassificationRule.u8IPv6FlowLable[5]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, + DBG_LVL_ALL, "u8IPv6FlowLable[6]: 0x%*ph ", + 6, psfCSType->cCPacketClassificationRule. + u8IPv6FlowLable); #endif } @@ -1162,13 +1152,9 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u32SFID: 0x%X", pstAddIndication->sfActiveSet.u32SFID); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u16CID: 0x%X", pstAddIndication->sfActiveSet.u16CID); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceClassNameLength: 0x%X", pstAddIndication->sfActiveSet.u8ServiceClassNameLength); - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8ServiceClassName: 0x %02X %02X %02X %02X %02X %02X", - pstAddIndication->sfActiveSet.u8ServiceClassName[0], - pstAddIndication->sfActiveSet.u8ServiceClassName[1], - pstAddIndication->sfActiveSet.u8ServiceClassName[2], - pstAddIndication->sfActiveSet.u8ServiceClassName[3], - pstAddIndication->sfActiveSet.u8ServiceClassName[4], - pstAddIndication->sfActiveSet.u8ServiceClassName[5]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, + "u8ServiceClassName: 0x%*ph", + 6, pstAddIndication->sfActiveSet.u8ServiceClassName); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8MBSService: 0x%02X", pstAddIndication->sfActiveSet.u8MBSService); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, "u8QosParamSet: 0x%02X", pstAddIndication->sfActiveSet.u8QosParamSet); @@ -1212,7 +1198,7 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) nCurClassifierCnt = MAX_CLASSIFIERS_IN_SF; for (nIndex = 0; nIndex < nCurClassifierCnt; nIndex++) { - stConvergenceSLTypes *psfCSType = NULL; + struct bcm_convergence_types *psfCSType = NULL; psfCSType = &pstAddIndication->sfActiveSet.cConvergenceSLTypes[nIndex]; BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_CONTROL, DBG_LVL_ALL, " CCPacketClassificationRuleSI====>"); @@ -1314,7 +1300,7 @@ static VOID DumpCmControlPacket(PVOID pvBuffer) static inline ULONG RestoreSFParam(struct bcm_mini_adapter *Adapter, ULONG ulAddrSFParamSet, PUCHAR pucDestBuffer) { - UINT nBytesToRead = sizeof(stServiceFlowParamSI); + UINT nBytesToRead = sizeof(struct bcm_connect_mgr_params); if (ulAddrSFParamSet == 0 || NULL == pucDestBuffer) { BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Got Param address as 0!!"); @@ -1331,7 +1317,7 @@ static inline ULONG RestoreSFParam(struct bcm_mini_adapter *Adapter, ULONG ulAdd static ULONG StoreSFParam(struct bcm_mini_adapter *Adapter, PUCHAR pucSrcBuffer, ULONG ulAddrSFParamSet) { - UINT nBytesToWrite = sizeof(stServiceFlowParamSI); + UINT nBytesToWrite = sizeof(struct bcm_connect_mgr_params); int ret = 0; if (ulAddrSFParamSet == 0 || NULL == pucSrcBuffer) @@ -1348,8 +1334,8 @@ static ULONG StoreSFParam(struct bcm_mini_adapter *Adapter, PUCHAR pucSrcBuffer, ULONG StoreCmControlResponseMessage(struct bcm_mini_adapter *Adapter, PVOID pvBuffer, UINT *puBufferLength) { stLocalSFAddIndicationAlt *pstAddIndicationAlt = NULL; - stLocalSFAddIndication *pstAddIndication = NULL; - stLocalSFDeleteRequest *pstDeletionRequest; + struct bcm_add_indication *pstAddIndication = NULL; + struct bcm_del_request *pstDeletionRequest; UINT uiSearchRuleIndex; ULONG ulSFID; @@ -1360,7 +1346,7 @@ ULONG StoreCmControlResponseMessage(struct bcm_mini_adapter *Adapter, PVOID pvBu * we can stop the further classifying the pkt for this SF. */ if (pstAddIndicationAlt->u8Type == DSD_REQ) { - pstDeletionRequest = (stLocalSFDeleteRequest *)pvBuffer; + pstDeletionRequest = (struct bcm_del_request *)pvBuffer; ulSFID = ntohl(pstDeletionRequest->u32SFID); uiSearchRuleIndex = SearchSfid(Adapter, ulSFID); @@ -1379,12 +1365,12 @@ ULONG StoreCmControlResponseMessage(struct bcm_mini_adapter *Adapter, PVOID pvBu } /* For DSA_REQ, only up to "psfAuthorizedSet" parameter should be accessed by driver! */ - pstAddIndication = kmalloc(sizeof(*pstAddIndication), GFP_KERNEL); + pstAddIndication = kmalloc(sizeof(struct bcm_add_indication), GFP_KERNEL); if (pstAddIndication == NULL) return 0; /* AUTHORIZED SET */ - pstAddIndication->psfAuthorizedSet = (stServiceFlowParamSI *) + pstAddIndication->psfAuthorizedSet = (struct bcm_connect_mgr_params *) GetNextTargetBufferLocation(Adapter, pstAddIndicationAlt->u16TID); if (!pstAddIndication->psfAuthorizedSet) { kfree(pstAddIndication); @@ -1398,10 +1384,10 @@ ULONG StoreCmControlResponseMessage(struct bcm_mini_adapter *Adapter, PVOID pvBu } /* this can't possibly be right */ - pstAddIndication->psfAuthorizedSet = (stServiceFlowParamSI *)ntohl((ULONG)pstAddIndication->psfAuthorizedSet); + pstAddIndication->psfAuthorizedSet = (struct bcm_connect_mgr_params *)ntohl((ULONG)pstAddIndication->psfAuthorizedSet); if (pstAddIndicationAlt->u8Type == DSA_REQ) { - stLocalSFAddRequest AddRequest; + struct bcm_add_request AddRequest; AddRequest.u8Type = pstAddIndicationAlt->u8Type; AddRequest.eConnectionDir = pstAddIndicationAlt->u8Direction; @@ -1409,8 +1395,8 @@ ULONG StoreCmControlResponseMessage(struct bcm_mini_adapter *Adapter, PVOID pvBu AddRequest.u16CID = pstAddIndicationAlt->u16CID; AddRequest.u16VCID = pstAddIndicationAlt->u16VCID; AddRequest.psfParameterSet = pstAddIndication->psfAuthorizedSet; - (*puBufferLength) = sizeof(stLocalSFAddRequest); - memcpy(pvBuffer, &AddRequest, sizeof(stLocalSFAddRequest)); + (*puBufferLength) = sizeof(struct bcm_add_request); + memcpy(pvBuffer, &AddRequest, sizeof(struct bcm_add_request)); kfree(pstAddIndication); return 1; } @@ -1426,7 +1412,7 @@ ULONG StoreCmControlResponseMessage(struct bcm_mini_adapter *Adapter, PVOID pvBu pstAddIndication->u8CC = pstAddIndicationAlt->u8CC; /* ADMITTED SET */ - pstAddIndication->psfAdmittedSet = (stServiceFlowParamSI *) + pstAddIndication->psfAdmittedSet = (struct bcm_connect_mgr_params *) GetNextTargetBufferLocation(Adapter, pstAddIndicationAlt->u16TID); if (!pstAddIndication->psfAdmittedSet) { kfree(pstAddIndication); @@ -1437,10 +1423,10 @@ ULONG StoreCmControlResponseMessage(struct bcm_mini_adapter *Adapter, PVOID pvBu return 0; } - pstAddIndication->psfAdmittedSet = (stServiceFlowParamSI *)ntohl((ULONG)pstAddIndication->psfAdmittedSet); + pstAddIndication->psfAdmittedSet = (struct bcm_connect_mgr_params *)ntohl((ULONG)pstAddIndication->psfAdmittedSet); /* ACTIVE SET */ - pstAddIndication->psfActiveSet = (stServiceFlowParamSI *) + pstAddIndication->psfActiveSet = (struct bcm_connect_mgr_params *) GetNextTargetBufferLocation(Adapter, pstAddIndicationAlt->u16TID); if (!pstAddIndication->psfActiveSet) { kfree(pstAddIndication); @@ -1451,10 +1437,10 @@ ULONG StoreCmControlResponseMessage(struct bcm_mini_adapter *Adapter, PVOID pvBu return 0; } - pstAddIndication->psfActiveSet = (stServiceFlowParamSI *)ntohl((ULONG)pstAddIndication->psfActiveSet); + pstAddIndication->psfActiveSet = (struct bcm_connect_mgr_params *)ntohl((ULONG)pstAddIndication->psfActiveSet); - (*puBufferLength) = sizeof(stLocalSFAddIndication); - *(stLocalSFAddIndication *)pvBuffer = *pstAddIndication; + (*puBufferLength) = sizeof(struct bcm_add_indication); + *(struct bcm_add_indication *)pvBuffer = *pstAddIndication; kfree(pstAddIndication); return 1; } @@ -1463,10 +1449,10 @@ static inline stLocalSFAddIndicationAlt *RestoreCmControlResponseMessage(register struct bcm_mini_adapter *Adapter, register PVOID pvBuffer) { ULONG ulStatus = 0; - stLocalSFAddIndication *pstAddIndication = NULL; + struct bcm_add_indication *pstAddIndication = NULL; stLocalSFAddIndicationAlt *pstAddIndicationDest = NULL; - pstAddIndication = (stLocalSFAddIndication *)(pvBuffer); + pstAddIndication = (struct bcm_add_indication *)(pvBuffer); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "=====>"); if ((pstAddIndication->u8Type == DSD_REQ) || (pstAddIndication->u8Type == DSD_RSP) || @@ -1553,7 +1539,7 @@ ULONG SetUpTargetDsxBuffers(struct bcm_mini_adapter *Adapter) if (Adapter->astTargetDsxBuffer[0].ulTargetDsxBuffer) return 1; - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Size of Each DSX Buffer(Also size of ServiceFlowParamSI): %zx ", sizeof(stServiceFlowParamSI)); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Size of Each DSX Buffer(Also size of connection manager parameters): %zx ", sizeof(struct bcm_connect_mgr_params)); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Reading DSX buffer From Target location %x ", DSX_MESSAGE_EXCHANGE_BUFFER); Status = rdmalt(Adapter, DSX_MESSAGE_EXCHANGE_BUFFER, (PUINT)&ulTargetDsxBuffersBase, sizeof(UINT)); @@ -1564,7 +1550,7 @@ ULONG SetUpTargetDsxBuffers(struct bcm_mini_adapter *Adapter) BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Base Address Of DSX Target Buffer : 0x%lx", ulTargetDsxBuffersBase); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "Tgt Buffer is Now %lx :", ulTargetDsxBuffersBase); - ulCntTargetBuffers = DSX_MESSAGE_EXCHANGE_BUFFER_SIZE / sizeof(stServiceFlowParamSI); + ulCntTargetBuffers = DSX_MESSAGE_EXCHANGE_BUFFER_SIZE / sizeof(struct bcm_connect_mgr_params); Adapter->ulTotalTargetBuffersAvailable = ulCntTargetBuffers > MAX_TARGET_DSX_BUFFERS ? @@ -1576,7 +1562,7 @@ ULONG SetUpTargetDsxBuffers(struct bcm_mini_adapter *Adapter) Adapter->astTargetDsxBuffer[i].ulTargetDsxBuffer = ulTargetDsxBuffersBase; Adapter->astTargetDsxBuffer[i].valid = 1; Adapter->astTargetDsxBuffer[i].tid = 0; - ulTargetDsxBuffersBase += sizeof(stServiceFlowParamSI); + ulTargetDsxBuffersBase += sizeof(struct bcm_connect_mgr_params); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, " Target DSX Buffer %lx setup at 0x%lx", i, Adapter->astTargetDsxBuffer[i].ulTargetDsxBuffer); } @@ -1647,7 +1633,7 @@ int FreeAdapterDsxBuffer(struct bcm_mini_adapter *Adapter) BOOLEAN CmControlResponseMessage(struct bcm_mini_adapter *Adapter, /* <Pointer to the Adapter structure */ PVOID pvBuffer /* Starting Address of the Buffer, that contains the AddIndication Data */) { - stServiceFlowParamSI *psfLocalSet = NULL; + struct bcm_connect_mgr_params *psfLocalSet = NULL; stLocalSFAddIndicationAlt *pstAddIndication = NULL; stLocalSFChangeIndicationAlt *pstChangeIndication = NULL; struct bcm_leader *pLeader = NULL; @@ -1658,7 +1644,7 @@ BOOLEAN CmControlResponseMessage(struct bcm_mini_adapter *Adapter, /* <Pointer */ pstAddIndication = RestoreCmControlResponseMessage(Adapter, pvBuffer); if (pstAddIndication == NULL) { - ClearTargetDSXBuffer(Adapter, ((stLocalSFAddIndication *)pvBuffer)->u16TID, FALSE); + ClearTargetDSXBuffer(Adapter, ((struct bcm_add_indication *)pvBuffer)->u16TID, FALSE); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_PRINTK, 0, 0, "Error in restoring Service Flow param structure from DSx message"); return FALSE; } @@ -1870,10 +1856,10 @@ BOOLEAN CmControlResponseMessage(struct bcm_mini_adapter *Adapter, /* <Pointer UINT uiSearchRuleIndex; ULONG ulSFID; - pLeader->PLength = sizeof(stLocalSFDeleteIndication); - *((stLocalSFDeleteIndication *)&(Adapter->caDsxReqResp[LEADER_SIZE])) = *((stLocalSFDeleteIndication *)pstAddIndication); + pLeader->PLength = sizeof(struct bcm_del_indication); + *((struct bcm_del_indication *)&(Adapter->caDsxReqResp[LEADER_SIZE])) = *((struct bcm_del_indication *)pstAddIndication); - ulSFID = ntohl(((stLocalSFDeleteIndication *)pstAddIndication)->u32SFID); + ulSFID = ntohl(((struct bcm_del_indication *)pstAddIndication)->u32SFID); uiSearchRuleIndex = SearchSfid(Adapter, ulSFID); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "DSD - Removing connection %x", uiSearchRuleIndex); @@ -1884,7 +1870,7 @@ BOOLEAN CmControlResponseMessage(struct bcm_mini_adapter *Adapter, /* <Pointer } BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, CONN_MSG, DBG_LVL_ALL, "SENDING DSD RESPONSE TO MAC"); - ((stLocalSFDeleteIndication *)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSD_RSP; + ((struct bcm_del_indication *)&(Adapter->caDsxReqResp[LEADER_SIZE]))->u8Type = DSD_RSP; CopyBufferToControlPacket(Adapter, (PVOID)Adapter->caDsxReqResp); } case DSD_RSP: @@ -1927,7 +1913,7 @@ int get_dsx_sf_data_to_application(struct bcm_mini_adapter *Adapter, UINT uiSFId VOID OverrideServiceFlowParams(struct bcm_mini_adapter *Adapter, PUINT puiBuffer) { B_UINT32 u32NumofSFsinMsg = ntohl(*(puiBuffer + 1)); - stIM_SFHostNotify *pHostInfo = NULL; + struct bcm_stim_sfhostnotify *pHostInfo = NULL; UINT uiSearchRuleIndex = 0; ULONG ulSFID = 0; @@ -1936,7 +1922,7 @@ VOID OverrideServiceFlowParams(struct bcm_mini_adapter *Adapter, PUINT puiBuffer while (u32NumofSFsinMsg != 0 && u32NumofSFsinMsg < NO_OF_QUEUES) { u32NumofSFsinMsg--; - pHostInfo = (stIM_SFHostNotify *)puiBuffer; + pHostInfo = (struct bcm_stim_sfhostnotify *)puiBuffer; puiBuffer = (PUINT)(pHostInfo + 1); ulSFID = ntohl(pHostInfo->SFID); diff --git a/drivers/staging/bcm/CmHost.h b/drivers/staging/bcm/CmHost.h index 4cc6f93f2321..1c5a07c7bbe2 100644 --- a/drivers/staging/bcm/CmHost.h +++ b/drivers/staging/bcm/CmHost.h @@ -35,8 +35,7 @@ typedef struct stLocalSFAddRequestAlt{ B_UINT16 u16VCID; - /// \brief structure ParameterSet - stServiceFlowParamSI sfParameterSet; + struct bcm_connect_mgr_params sfParameterSet; //USE_MEMORY_MANAGER(); }stLocalSFAddRequestAlt; @@ -50,12 +49,9 @@ typedef struct stLocalSFAddIndicationAlt{ B_UINT16 u16CID; /// \brief 16bitVCID B_UINT16 u16VCID; - /// \brief structure AuthorizedSet - stServiceFlowParamSI sfAuthorizedSet; - /// \brief structure AdmittedSet - stServiceFlowParamSI sfAdmittedSet; - /// \brief structure ActiveSet - stServiceFlowParamSI sfActiveSet; + struct bcm_connect_mgr_params sfAuthorizedSet; + struct bcm_connect_mgr_params sfAdmittedSet; + struct bcm_connect_mgr_params sfActiveSet; B_UINT8 u8CC; /**< Confirmation Code*/ B_UINT8 u8Padd; /**< 8-bit Padding */ @@ -72,12 +68,9 @@ typedef struct stLocalSFAddConfirmationAlt{ B_UINT16 u16CID; /// \brief 16bitVCID B_UINT16 u16VCID; - /// \brief structure AuthorizedSet - stServiceFlowParamSI sfAuthorizedSet; - /// \brief structure AdmittedSet - stServiceFlowParamSI sfAdmittedSet; - /// \brief structure ActiveSet - stServiceFlowParamSI sfActiveSet; + struct bcm_connect_mgr_params sfAuthorizedSet; + struct bcm_connect_mgr_params sfAdmittedSet; + struct bcm_connect_mgr_params sfActiveSet; }stLocalSFAddConfirmationAlt; @@ -91,16 +84,13 @@ typedef struct stLocalSFChangeRequestAlt{ /// \brief 16bitVCID B_UINT16 u16VCID; /* - //Pointer location at which following Service Flow param Structure can be read - //from the target. We get only the address location and we need to read out the - //entire SF param structure at the given location on target + //Pointer location at which following connection manager param Structure can be read + //from the target. We only get the address location and we need to read out the + //entire connection manager param structure at the given location on target */ - /// \brief structure AuthorizedSet - stServiceFlowParamSI sfAuthorizedSet; - /// \brief structure AdmittedSet - stServiceFlowParamSI sfAdmittedSet; - /// \brief structure ParameterSet - stServiceFlowParamSI sfActiveSet; + struct bcm_connect_mgr_params sfAuthorizedSet; + struct bcm_connect_mgr_params sfAdmittedSet; + struct bcm_connect_mgr_params sfActiveSet; B_UINT8 u8CC; /**< Confirmation Code*/ B_UINT8 u8Padd; /**< 8-bit Padding */ @@ -117,12 +107,9 @@ typedef struct stLocalSFChangeConfirmationAlt{ B_UINT16 u16CID; /// \brief 16bitVCID B_UINT16 u16VCID; - /// \brief structure AuthorizedSet - stServiceFlowParamSI sfAuthorizedSet; - /// \brief structure AdmittedSet - stServiceFlowParamSI sfAdmittedSet; - /// \brief structure ActiveSet - stServiceFlowParamSI sfActiveSet; + struct bcm_connect_mgr_params sfAuthorizedSet; + struct bcm_connect_mgr_params sfAdmittedSet; + struct bcm_connect_mgr_params sfActiveSet; }stLocalSFChangeConfirmationAlt; @@ -135,12 +122,9 @@ typedef struct stLocalSFChangeIndicationAlt{ B_UINT16 u16CID; /// \brief 16bitVCID B_UINT16 u16VCID; - /// \brief structure AuthorizedSet - stServiceFlowParamSI sfAuthorizedSet; - /// \brief structure AdmittedSet - stServiceFlowParamSI sfAdmittedSet; - /// \brief structure ActiveSet - stServiceFlowParamSI sfActiveSet; + struct bcm_connect_mgr_params sfAuthorizedSet; + struct bcm_connect_mgr_params sfAdmittedSet; + struct bcm_connect_mgr_params sfActiveSet; B_UINT8 u8CC; /**< Confirmation Code*/ B_UINT8 u8Padd; /**< 8-bit Padding */ diff --git a/drivers/staging/bcm/InterfaceInit.c b/drivers/staging/bcm/InterfaceInit.c index 8f85de6a57ba..b05f5f73548c 100644 --- a/drivers/staging/bcm/InterfaceInit.c +++ b/drivers/staging/bcm/InterfaceInit.c @@ -8,6 +8,7 @@ static struct usb_device_id InterfaceUsbtable[] = { { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_226) }, { USB_DEVICE(BCM_USB_VENDOR_ID_FOXCONN, BCM_USB_PRODUCT_ID_1901) }, { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_TU25) }, + { USB_DEVICE(BCM_USB_VENDOR_ID_ZTE, BCM_USB_PRODUCT_ID_ZTE_226) }, { } }; MODULE_DEVICE_TABLE(usb, InterfaceUsbtable); @@ -669,16 +670,24 @@ struct class *bcm_class; static __init int bcm_init(void) { - printk(KERN_INFO "%s: %s, %s\n", DRV_NAME, DRV_DESCRIPTION, DRV_VERSION); - printk(KERN_INFO "%s\n", DRV_COPYRIGHT); + int retval; + + pr_info("%s: %s, %s\n", DRV_NAME, DRV_DESCRIPTION, DRV_VERSION); + pr_info("%s\n", DRV_COPYRIGHT); bcm_class = class_create(THIS_MODULE, DRV_NAME); if (IS_ERR(bcm_class)) { - printk(KERN_ERR DRV_NAME ": could not create class\n"); + pr_err(DRV_NAME ": could not create class\n"); return PTR_ERR(bcm_class); } - return usb_register(&usbbcm_driver); + retval = usb_register(&usbbcm_driver); + if (retval < 0) { + pr_err(DRV_NAME ": could not register usb driver\n"); + class_destroy(bcm_class); + return retval; + } + return 0; } static __exit void bcm_exit(void) diff --git a/drivers/staging/bcm/InterfaceInit.h b/drivers/staging/bcm/InterfaceInit.h index 058315a64c05..866924e35f9c 100644 --- a/drivers/staging/bcm/InterfaceInit.h +++ b/drivers/staging/bcm/InterfaceInit.h @@ -1,27 +1,26 @@ #ifndef _INTERFACE_INIT_H #define _INTERFACE_INIT_H -#define BCM_USB_VENDOR_ID_T3 0x198f -#define BCM_USB_VENDOR_ID_FOXCONN 0x0489 -#define BCM_USB_VENDOR_ID_ZTE 0x19d2 +#define BCM_USB_VENDOR_ID_T3 0x198f +#define BCM_USB_VENDOR_ID_FOXCONN 0x0489 +#define BCM_USB_VENDOR_ID_ZTE 0x19d2 -#define BCM_USB_PRODUCT_ID_T3 0x0300 -#define BCM_USB_PRODUCT_ID_T3B 0x0210 -#define BCM_USB_PRODUCT_ID_T3L 0x0220 -#define BCM_USB_PRODUCT_ID_SM250 0xbccd -#define BCM_USB_PRODUCT_ID_SYM 0x15E -#define BCM_USB_PRODUCT_ID_1901 0xe017 -#define BCM_USB_PRODUCT_ID_226 0x0132 -#define BCM_USB_PRODUCT_ID_ZTE_TU25 0x0007 +#define BCM_USB_PRODUCT_ID_T3 0x0300 +#define BCM_USB_PRODUCT_ID_T3B 0x0210 +#define BCM_USB_PRODUCT_ID_T3L 0x0220 +#define BCM_USB_PRODUCT_ID_SM250 0xbccd +#define BCM_USB_PRODUCT_ID_SYM 0x15E +#define BCM_USB_PRODUCT_ID_1901 0xe017 +#define BCM_USB_PRODUCT_ID_226 0x0132 /* not sure if this is valid */ +#define BCM_USB_PRODUCT_ID_ZTE_226 0x172 +#define BCM_USB_PRODUCT_ID_ZTE_TU25 0x0007 -#define BCM_USB_MINOR_BASE 192 +#define BCM_USB_MINOR_BASE 192 +int InterfaceInitialize(void); -INT InterfaceInitialize(void); +int InterfaceExit(void); -INT InterfaceExit(void); - -INT usbbcm_worker_thread(PS_INTERFACE_ADAPTER psIntfAdapter); +int usbbcm_worker_thread(PS_INTERFACE_ADAPTER psIntfAdapter); #endif - diff --git a/drivers/staging/bcm/Kconfig b/drivers/staging/bcm/Kconfig index 96adb1026c4f..83c9752504d4 100644 --- a/drivers/staging/bcm/Kconfig +++ b/drivers/staging/bcm/Kconfig @@ -1,6 +1,6 @@ config BCM_WIMAX tristate "Beceem BCS200/BCS220-3 and BCSM250 wimax support" - depends on USB && NET && EXPERIMENTAL + depends on USB && NET default N help This is an experimental driver for the Beceem WIMAX chipset used diff --git a/drivers/staging/bcm/Misc.c b/drivers/staging/bcm/Misc.c index f545716c666d..f13a9582a82f 100644 --- a/drivers/staging/bcm/Misc.c +++ b/drivers/staging/bcm/Misc.c @@ -752,7 +752,10 @@ VOID DumpPackInfo(struct bcm_mini_adapter *Adapter) BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "AuthzSet: %x\n", Adapter->PackInfo[uiLoopIndex].bAuthorizedSet); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "ClassifyPrority: %x\n", Adapter->PackInfo[uiLoopIndex].bClassifierPriority); BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiMaxLatency: %x\n", Adapter->PackInfo[uiLoopIndex].uiMaxLatency); - BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "ServiceClassName: %x %x %x %x\n", Adapter->PackInfo[uiLoopIndex].ucServiceClassName[0], Adapter->PackInfo[uiLoopIndex].ucServiceClassName[1], Adapter->PackInfo[uiLoopIndex].ucServiceClassName[2], Adapter->PackInfo[uiLoopIndex].ucServiceClassName[3]); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_OTHERS, DUMP_INFO, + DBG_LVL_ALL, "ServiceClassName: %*ph\n", + 4, Adapter->PackInfo[uiLoopIndex]. + ucServiceClassName); /* BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "bHeaderSuppressionEnabled :%X\n", Adapter->PackInfo[uiLoopIndex].bHeaderSuppressionEnabled); * BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiTotalTxBytes:%X\n", Adapter->PackInfo[uiLoopIndex].uiTotalTxBytes); * BCM_DEBUG_PRINT (Adapter, DBG_TYPE_OTHERS, DUMP_INFO, DBG_LVL_ALL, "uiTotalRxBytes:%X\n", Adapter->PackInfo[uiLoopIndex].uiTotalRxBytes); diff --git a/drivers/staging/bcm/PHSModule.c b/drivers/staging/bcm/PHSModule.c index 479574234e4c..6dc0bbcfeab0 100644 --- a/drivers/staging/bcm/PHSModule.c +++ b/drivers/staging/bcm/PHSModule.c @@ -66,7 +66,7 @@ Input parameters: IN struct bcm_mini_adapter *Adapter - Miniport Adapte BOOLEAN bHeaderSuppressionEnabled - indicates if header suprression is enabled for SF. Return: STATUS_SUCCESS - If the send was successful. - Other - If an error occured. + Other - If an error occurred. */ int PHSTransmit(struct bcm_mini_adapter *Adapter, @@ -346,7 +346,7 @@ int phs_init(PPHS_DEVICE_EXTENSION pPhsdeviceExtension, struct bcm_mini_adapter - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\n phs_init Successfull"); + BCM_DEBUG_PRINT(Adapter,DBG_TYPE_OTHERS, PHS_DISPATCH, DBG_LVL_ALL, "\n phs_init Successful"); return STATUS_SUCCESS; } diff --git a/drivers/staging/bcm/Prototypes.h b/drivers/staging/bcm/Prototypes.h index 3c8cc5ba2e2e..3ec8f800a5b0 100644 --- a/drivers/staging/bcm/Prototypes.h +++ b/drivers/staging/bcm/Prototypes.h @@ -95,7 +95,7 @@ void beceem_parse_target_struct(struct bcm_mini_adapter *Adapter); int bcm_ioctl_fw_download(struct bcm_mini_adapter *Adapter, struct bcm_firmware_info *psFwInfo); void CopyMIBSExtendedSFParameters(struct bcm_mini_adapter *Adapter, - CServiceFlowParamSI *psfLocalSet, UINT uiSearchRuleIndex); + struct bcm_connect_mgr_params *psfLocalSet, UINT uiSearchRuleIndex); VOID ResetCounters(struct bcm_mini_adapter *Adapter); diff --git a/drivers/staging/bcm/Transmit.c b/drivers/staging/bcm/Transmit.c index 5e603ce76fea..27e8c890777b 100644 --- a/drivers/staging/bcm/Transmit.c +++ b/drivers/staging/bcm/Transmit.c @@ -1,162 +1,149 @@ /** -@file Transmit.c -@defgroup tx_functions Transmission -@section Queueing -@dot -digraph transmit1 { -node[shape=box] -edge[weight=5;color=red] - -bcm_transmit->GetPacketQueueIndex[label="IP Packet"] -GetPacketQueueIndex->IpVersion4[label="IPV4"] -GetPacketQueueIndex->IpVersion6[label="IPV6"] -} - -@enddot - -@section De-Queueing -@dot -digraph transmit2 { -node[shape=box] -edge[weight=5;color=red] -interrupt_service_thread->transmit_packets -tx_pkt_hdler->transmit_packets -transmit_packets->CheckAndSendPacketFromIndex -transmit_packets->UpdateTokenCount -CheckAndSendPacketFromIndex->PruneQueue -CheckAndSendPacketFromIndex->IsPacketAllowedForFlow -CheckAndSendPacketFromIndex->SendControlPacket[label="control pkt"] -SendControlPacket->bcm_cmd53 -CheckAndSendPacketFromIndex->SendPacketFromQueue[label="data pkt"] -SendPacketFromQueue->SetupNextSend->bcm_cmd53 -} -@enddot -*/ + * @file Transmit.c + * @defgroup tx_functions Transmission + * @section Queueing + * @dot + * digraph transmit1 { + * node[shape=box] + * edge[weight=5;color=red] + * + * bcm_transmit->GetPacketQueueIndex[label="IP Packet"] + * GetPacketQueueIndex->IpVersion4[label="IPV4"] + * GetPacketQueueIndex->IpVersion6[label="IPV6"] + * } + * + * @enddot + * + * @section De-Queueing + * @dot + * digraph transmit2 { + * node[shape=box] + * edge[weight=5;color=red] + * interrupt_service_thread->transmit_packets + * tx_pkt_hdler->transmit_packets + * transmit_packets->CheckAndSendPacketFromIndex + * transmit_packets->UpdateTokenCount + * CheckAndSendPacketFromIndex->PruneQueue + * CheckAndSendPacketFromIndex->IsPacketAllowedForFlow + * CheckAndSendPacketFromIndex->SendControlPacket[label="control pkt"] + * SendControlPacket->bcm_cmd53 + * CheckAndSendPacketFromIndex->SendPacketFromQueue[label="data pkt"] + * SendPacketFromQueue->SetupNextSend->bcm_cmd53 + * } + * @enddot + */ #include "headers.h" - /** -@ingroup ctrl_pkt_functions -This function dispatches control packet to the h/w interface -@return zero(success) or -ve value(failure) -*/ -INT SendControlPacket(struct bcm_mini_adapter *Adapter, char *pControlPacket) + * @ingroup ctrl_pkt_functions + * This function dispatches control packet to the h/w interface + * @return zero(success) or -ve value(failure) + */ +int SendControlPacket(struct bcm_mini_adapter *Adapter, char *pControlPacket) { struct bcm_leader *PLeader = (struct bcm_leader *)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, "Tx"); + if (!pControlPacket || !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"); 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"); - return STATUS_FAILURE; - } /* Update the netdevice statistics */ /* Dump Packet */ - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader Status: %x", PLeader->Status); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader VCID: %x",PLeader->Vcid); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader Length: %x",PLeader->PLength); - if(Adapter->device_removed) + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader Status: %x", PLeader->Status); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader VCID: %x", PLeader->Vcid); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "Leader Length: %x", PLeader->PLength); + if (Adapter->device_removed) return 0; if (netif_msg_pktdata(Adapter)) print_hex_dump(KERN_DEBUG, PFX "tx control: ", DUMP_PREFIX_NONE, - 16, 1, pControlPacket, PLeader->PLength + LEADER_SIZE, 0); + 16, 1, pControlPacket, PLeader->PLength + LEADER_SIZE, 0); Adapter->interface_transmit(Adapter->pvInterfaceAdapter, - pControlPacket, (PLeader->PLength + LEADER_SIZE)); + pControlPacket, (PLeader->PLength + LEADER_SIZE)); atomic_dec(&Adapter->CurrNumFreeTxDesc); - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "<========="); + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, TX_CONTROL, DBG_LVL_ALL, "<========="); return STATUS_SUCCESS; } /** -@ingroup tx_functions -This function despatches the IP packets with the given vcid -to the target via the host h/w interface. -@return zero(success) or -ve value(failure) -*/ -INT SetupNextSend(struct bcm_mini_adapter *Adapter, struct sk_buff *Packet, USHORT Vcid) + * @ingroup tx_functions + * This function despatches the IP packets with the given vcid + * to the target via the host h/w interface. + * @return zero(success) or -ve value(failure) + */ +int SetupNextSend(struct bcm_mini_adapter *Adapter, struct sk_buff *Packet, USHORT Vcid) { - int status=0; - BOOLEAN bHeaderSupressionEnabled = FALSE; - B_UINT16 uiClassifierRuleID; + int status = 0; + BOOLEAN bHeaderSupressionEnabled = FALSE; + B_UINT16 uiClassifierRuleID; u16 QueueIndex = skb_get_queue_mapping(Packet); - struct bcm_leader Leader={0}; + struct bcm_leader Leader = {0}; - if(Packet->len > MAX_DEVICE_DESC_SIZE) - { + if (Packet->len > MAX_DEVICE_DESC_SIZE) { status = STATUS_FAILURE; goto errExit; } /* Get the Classifier Rule ID */ - uiClassifierRuleID = *((UINT32*) (Packet->cb)+SKB_CB_CLASSIFICATION_OFFSET); + uiClassifierRuleID = *((UINT32 *) (Packet->cb) + SKB_CB_CLASSIFICATION_OFFSET); bHeaderSupressionEnabled = Adapter->PackInfo[QueueIndex].bHeaderSuppressionEnabled & Adapter->bPHSEnabled; - if(Adapter->device_removed) - { + if (Adapter->device_removed) { status = STATUS_FAILURE; goto errExit; - } + } status = PHSTransmit(Adapter, &Packet, Vcid, uiClassifierRuleID, bHeaderSupressionEnabled, - (UINT *)&Packet->len, Adapter->PackInfo[QueueIndex].bEthCSSupport); + (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"); + if (status != STATUS_SUCCESS) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "PHS Transmit failed..\n"); goto errExit; } - Leader.Vcid = Vcid; + Leader.Vcid = Vcid; - if(TCP_ACK == *((UINT32*) (Packet->cb) + SKB_CB_TCPACK_OFFSET )) + if (TCP_ACK == *((UINT32 *) (Packet->cb) + SKB_CB_TCPACK_OFFSET)) Leader.Status = LEADER_STATUS_TCP_ACK; else Leader.Status = LEADER_STATUS; - if(Adapter->PackInfo[QueueIndex].bEthCSSupport) - { + if (Adapter->PackInfo[QueueIndex].bEthCSSupport) { Leader.PLength = Packet->len; - if(skb_headroom(Packet) < LEADER_SIZE) - { - if((status = skb_cow(Packet,LEADER_SIZE))) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL,"bcm_transmit : Failed To Increase headRoom\n"); + if (skb_headroom(Packet) < LEADER_SIZE) { + status = skb_cow(Packet, LEADER_SIZE); + if (status) { + BCM_DEBUG_PRINT(Adapter, DBG_TYPE_TX, NEXT_SEND, DBG_LVL_ALL, "bcm_transmit : Failed To Increase headRoom\n"); goto errExit; } } skb_push(Packet, LEADER_SIZE); memcpy(Packet->data, &Leader, LEADER_SIZE); - } - else - { + } else { Leader.PLength = Packet->len - ETH_HLEN; memcpy((struct bcm_leader *)skb_pull(Packet, (ETH_HLEN - LEADER_SIZE)), &Leader, LEADER_SIZE); } status = Adapter->interface_transmit(Adapter->pvInterfaceAdapter, - Packet->data, (Leader.PLength + LEADER_SIZE)); - if(status) - { + Packet->data, (Leader.PLength + LEADER_SIZE)); + if (status) { ++Adapter->dev->stats.tx_errors; if (netif_msg_tx_err(Adapter)) pr_info(PFX "%s: transmit error %d\n", Adapter->dev->name, status); - } - else - { + } else { struct net_device_stats *netstats = &Adapter->dev->stats; Adapter->PackInfo[QueueIndex].uiTotalTxBytes += Leader.PLength; @@ -175,7 +162,6 @@ INT SetupNextSend(struct bcm_mini_adapter *Adapter, struct sk_buff *Packet, USH atomic_dec(&Adapter->CurrNumFreeTxDesc); errExit: - dev_kfree_skb(Packet); return status; } @@ -188,73 +174,65 @@ static int tx_pending(struct bcm_mini_adapter *Adapter) } /** -@ingroup tx_functions -Transmit thread -*/ -int tx_pkt_handler(struct bcm_mini_adapter *Adapter /**< pointer to adapter object*/ - ) + * @ingroup tx_functions + * Transmit thread + */ +int tx_pkt_handler(struct bcm_mini_adapter *Adapter /**< pointer to adapter object*/) { int status = 0; - while(! kthread_should_stop()) { + while (!kthread_should_stop()) { /* FIXME - the timeout looks like workaround for racey usage of TxPktAvail */ - if(Adapter->LinkUpStatus) + if (Adapter->LinkUpStatus) wait_event_timeout(Adapter->tx_packet_wait_queue, - tx_pending(Adapter), msecs_to_jiffies(10)); + tx_pending(Adapter), msecs_to_jiffies(10)); else wait_event_interruptible(Adapter->tx_packet_wait_queue, - tx_pending(Adapter)); + tx_pending(Adapter)); if (Adapter->device_removed) break; - if(Adapter->downloadDDR == 1) - { - Adapter->downloadDDR +=1; + if (Adapter->downloadDDR == 1) { + Adapter->downloadDDR += 1; status = download_ddr_settings(Adapter); - if(status) + if (status) pr_err(PFX "DDR DOWNLOAD FAILED! %d\n", status); continue; } - //Check end point for halt/stall. - if(Adapter->bEndPointHalted == TRUE) - { + /* Check end point for halt/stall. */ + if (Adapter->bEndPointHalted == TRUE) { Bcm_clear_halt_of_endpoints(Adapter); Adapter->bEndPointHalted = FALSE; StartInterruptUrb((PS_INTERFACE_ADAPTER)(Adapter->pvInterfaceAdapter)); } - if(Adapter->LinkUpStatus && !Adapter->IdleMode) - { - if(atomic_read(&Adapter->TotalPacketCount)) - { + if (Adapter->LinkUpStatus && !Adapter->IdleMode) { + if (atomic_read(&Adapter->TotalPacketCount)) update_per_sf_desc_cnts(Adapter); - } } - if( atomic_read(&Adapter->CurrNumFreeTxDesc) && + if (atomic_read(&Adapter->CurrNumFreeTxDesc) && Adapter->LinkStatus == SYNC_UP_REQUEST && - !Adapter->bSyncUpRequestSent) - { - BCM_DEBUG_PRINT(Adapter,DBG_TYPE_TX, TX_PACKETS, DBG_LVL_ALL, "Calling LinkMessage"); + !Adapter->bSyncUpRequestSent) { + + 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"); - Adapter->usIdleModePattern = ABORT_IDLE_MODE; - Adapter->bWakeUpDevice = TRUE; - wake_up(&Adapter->process_rx_cntrlpkt); + 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"); + Adapter->usIdleModePattern = ABORT_IDLE_MODE; + Adapter->bWakeUpDevice = TRUE; + wake_up(&Adapter->process_rx_cntrlpkt); } transmit_packets(Adapter); - 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; } diff --git a/drivers/staging/bcm/cntrl_SignalingInterface.h b/drivers/staging/bcm/cntrl_SignalingInterface.h index 7619e4b819bd..990e809e9680 100644 --- a/drivers/staging/bcm/cntrl_SignalingInterface.h +++ b/drivers/staging/bcm/cntrl_SignalingInterface.h @@ -1,423 +1,311 @@ #ifndef CNTRL_SIGNALING_INTERFACE_ #define CNTRL_SIGNALING_INTERFACE_ - - - -#define DSA_REQ 11 -#define DSA_RSP 12 -#define DSA_ACK 13 -#define DSC_REQ 14 -#define DSC_RSP 15 -#define DSC_ACK 16 -#define DSD_REQ 17 -#define DSD_RSP 18 -#define DSD_ACK 19 -#define MAX_CLASSIFIERS_IN_SF 4 - - -#define MAX_STRING_LEN 20 -#define MAX_PHS_LENGTHS 255 -#define VENDOR_PHS_PARAM_LENGTH 10 -#define MAX_NUM_ACTIVE_BS 10 -#define AUTH_TOKEN_LENGTH 10 -#define NUM_HARQ_CHANNELS 16 //Changed from 10 to 16 to accommodate all HARQ channels -#define VENDOR_CLASSIFIER_PARAM_LENGTH 1 //Changed the size to 1 byte since we dnt use it -#define VENDOR_SPECIF_QOS_PARAM 1 -#define VENDOR_PHS_PARAM_LENGTH 10 -#define MBS_CONTENTS_ID_LENGTH 10 -#define GLOBAL_SF_CLASSNAME_LENGTH 6 - -#define TYPE_OF_SERVICE_LENGTH 3 -#define IP_MASKED_SRC_ADDRESS_LENGTH 32 -#define IP_MASKED_DEST_ADDRESS_LENGTH 32 -#define PROTOCOL_SRC_PORT_RANGE_LENGTH 4 -#define PROTOCOL_DEST_PORT_RANGE_LENGTH 4 -#define ETHERNET_DEST_MAC_ADDR_LENGTH 12 -#define ETHERNET_SRC_MAC_ADDR_LENGTH 12 -#define NUM_ETHERTYPE_BYTES 3 -#define NUM_IPV6_FLOWLABLE_BYTES 3 - - -//////////////////////////////////////////////////////////////////////////////// -////////////////////////structure Definitions/////////////////////////////////// -//////////////////////////////////////////////////////////////////////////////// -/// \brief class cCPacketClassificationRule -struct _stCPacketClassificationRuleSI{ - - /** 16bit UserPriority Of The Service Flow*/ - B_UINT16 u16UserPriority; - /** 16bit VLANID Of The Service Flow*/ - B_UINT16 u16VLANID; - /** 16bit Packet Classification RuleIndex Of The Service Flow*/ - B_UINT16 u16PacketClassificationRuleIndex; - /** 8bit Classifier Rule Priority Of The Service Flow*/ - B_UINT8 u8ClassifierRulePriority; - /** Length of IP TypeOfService field*/ - B_UINT8 u8IPTypeOfServiceLength; - /** 3bytes IP TypeOfService */ - B_UINT8 u8IPTypeOfService[TYPE_OF_SERVICE_LENGTH]; - /** Protocol used in classification of Service Flow*/ - B_UINT8 u8Protocol; - /** Length of IP Masked Source Address */ - B_UINT8 u8IPMaskedSourceAddressLength; - /** IP Masked Source Address used in classification for the Service Flow*/ - B_UINT8 u8IPMaskedSourceAddress[IP_MASKED_SRC_ADDRESS_LENGTH]; - /** Length of IP Destination Address */ - B_UINT8 u8IPDestinationAddressLength; - /** IP Destination Address used in classification for the Service Flow*/ - B_UINT8 u8IPDestinationAddress[IP_MASKED_DEST_ADDRESS_LENGTH]; - /** Length of Protocol Source Port Range */ - B_UINT8 u8ProtocolSourcePortRangeLength; - /** Protocol Source Port Range used in the Service Flow*/ - B_UINT8 u8ProtocolSourcePortRange[PROTOCOL_SRC_PORT_RANGE_LENGTH]; - /** Length of Protocol Dest Port Range */ - B_UINT8 u8ProtocolDestPortRangeLength; - /** Protocol Dest Port Range used in the Service Flow*/ - B_UINT8 u8ProtocolDestPortRange[PROTOCOL_DEST_PORT_RANGE_LENGTH]; - /** Length of Ethernet Destination MAC Address */ - B_UINT8 u8EthernetDestMacAddressLength; - /** Ethernet Destination MAC Address used in classification of the Service Flow*/ - B_UINT8 u8EthernetDestMacAddress[ETHERNET_DEST_MAC_ADDR_LENGTH]; - /** Length of Ethernet Source MAC Address */ - B_UINT8 u8EthernetSourceMACAddressLength; - /** Ethernet Source MAC Address used in classification of the Service Flow*/ - B_UINT8 u8EthernetSourceMACAddress[ETHERNET_SRC_MAC_ADDR_LENGTH]; - /** Length of Ethertype */ - B_UINT8 u8EthertypeLength; - /** 3bytes Ethertype Of The Service Flow*/ - B_UINT8 u8Ethertype[NUM_ETHERTYPE_BYTES]; - /** 8bit Associated PHSI Of The Service Flow*/ - B_UINT8 u8AssociatedPHSI; - /** Length of Vendor Specific Classifier Param length Of The Service Flow*/ - B_UINT8 u8VendorSpecificClassifierParamLength; - /** Vendor Specific Classifier Param Of The Service Flow*/ - B_UINT8 u8VendorSpecificClassifierParam[VENDOR_CLASSIFIER_PARAM_LENGTH]; - /** Length Of IPv6 Flow Lable of the Service Flow*/ - B_UINT8 u8IPv6FlowLableLength; - /** IPv6 Flow Lable Of The Service Flow*/ - B_UINT8 u8IPv6FlowLable[NUM_IPV6_FLOWLABLE_BYTES]; - /** Action associated with the classifier rule*/ - B_UINT8 u8ClassifierActionRule; - B_UINT16 u16ValidityBitMap; +#define DSA_REQ 11 +#define DSA_RSP 12 +#define DSA_ACK 13 +#define DSC_REQ 14 +#define DSC_RSP 15 +#define DSC_ACK 16 +#define DSD_REQ 17 +#define DSD_RSP 18 +#define DSD_ACK 19 +#define MAX_CLASSIFIERS_IN_SF 4 + +#define MAX_STRING_LEN 20 +#define MAX_PHS_LENGTHS 255 +#define VENDOR_PHS_PARAM_LENGTH 10 +#define MAX_NUM_ACTIVE_BS 10 +#define AUTH_TOKEN_LENGTH 10 +#define NUM_HARQ_CHANNELS 16 /* Changed from 10 to 16 to accommodate all HARQ channels */ +#define VENDOR_CLASSIFIER_PARAM_LENGTH 1 /* Changed the size to 1 byte since we dnt use it */ +#define VENDOR_SPECIF_QOS_PARAM 1 +#define VENDOR_PHS_PARAM_LENGTH 10 +#define MBS_CONTENTS_ID_LENGTH 10 +#define GLOBAL_SF_CLASSNAME_LENGTH 6 + +#define TYPE_OF_SERVICE_LENGTH 3 +#define IP_MASKED_SRC_ADDRESS_LENGTH 32 +#define IP_MASKED_DEST_ADDRESS_LENGTH 32 +#define PROTOCOL_SRC_PORT_RANGE_LENGTH 4 +#define PROTOCOL_DEST_PORT_RANGE_LENGTH 4 +#define ETHERNET_DEST_MAC_ADDR_LENGTH 12 +#define ETHERNET_SRC_MAC_ADDR_LENGTH 12 +#define NUM_ETHERTYPE_BYTES 3 +#define NUM_IPV6_FLOWLABLE_BYTES 3 + +struct bcm_packet_class_rules { + /* 16bit UserPriority Of The Service Flow */ + B_UINT16 u16UserPriority; + /* 16bit VLANID Of The Service Flow */ + B_UINT16 u16VLANID; + /* 16bit Packet Classification RuleIndex Of The Service Flow */ + B_UINT16 u16PacketClassificationRuleIndex; + /* 8bit Classifier Rule Priority Of The Service Flow */ + B_UINT8 u8ClassifierRulePriority; + /* Length of IP TypeOfService field */ + B_UINT8 u8IPTypeOfServiceLength; + /* 3bytes IP TypeOfService */ + B_UINT8 u8IPTypeOfService[TYPE_OF_SERVICE_LENGTH]; + /* Protocol used in classification of Service Flow */ + B_UINT8 u8Protocol; + /* Length of IP Masked Source Address */ + B_UINT8 u8IPMaskedSourceAddressLength; + /* IP Masked Source Address used in classification for the Service Flow */ + B_UINT8 u8IPMaskedSourceAddress[IP_MASKED_SRC_ADDRESS_LENGTH]; + /* Length of IP Destination Address */ + B_UINT8 u8IPDestinationAddressLength; + /* IP Destination Address used in classification for the Service Flow */ + B_UINT8 u8IPDestinationAddress[IP_MASKED_DEST_ADDRESS_LENGTH]; + /* Length of Protocol Source Port Range */ + B_UINT8 u8ProtocolSourcePortRangeLength; + /* Protocol Source Port Range used in the Service Flow */ + B_UINT8 u8ProtocolSourcePortRange[PROTOCOL_SRC_PORT_RANGE_LENGTH]; + /* Length of Protocol Dest Port Range */ + B_UINT8 u8ProtocolDestPortRangeLength; + /* Protocol Dest Port Range used in the Service Flow */ + B_UINT8 u8ProtocolDestPortRange[PROTOCOL_DEST_PORT_RANGE_LENGTH]; + /* Length of Ethernet Destination MAC Address */ + B_UINT8 u8EthernetDestMacAddressLength; + /* Ethernet Destination MAC Address used in classification of the Service Flow */ + B_UINT8 u8EthernetDestMacAddress[ETHERNET_DEST_MAC_ADDR_LENGTH]; + /* Length of Ethernet Source MAC Address */ + B_UINT8 u8EthernetSourceMACAddressLength; + /* Ethernet Source MAC Address used in classification of the Service Flow */ + B_UINT8 u8EthernetSourceMACAddress[ETHERNET_SRC_MAC_ADDR_LENGTH]; + /* Length of Ethertype */ + B_UINT8 u8EthertypeLength; + /* 3bytes Ethertype Of The Service Flow */ + B_UINT8 u8Ethertype[NUM_ETHERTYPE_BYTES]; + /* 8bit Associated PHSI Of The Service Flow */ + B_UINT8 u8AssociatedPHSI; + /* Length of Vendor Specific Classifier Param length Of The Service Flow */ + B_UINT8 u8VendorSpecificClassifierParamLength; + /* Vendor Specific Classifier Param Of The Service Flow */ + B_UINT8 u8VendorSpecificClassifierParam[VENDOR_CLASSIFIER_PARAM_LENGTH]; + /* Length Of IPv6 Flow Lable of the Service Flow */ + B_UINT8 u8IPv6FlowLableLength; + /* IPv6 Flow Lable Of The Service Flow */ + B_UINT8 u8IPv6FlowLable[NUM_IPV6_FLOWLABLE_BYTES]; + /* Action associated with the classifier rule */ + B_UINT8 u8ClassifierActionRule; + B_UINT16 u16ValidityBitMap; }; -typedef struct _stCPacketClassificationRuleSI CCPacketClassificationRuleSI,stCPacketClassificationRuleSI, *pstCPacketClassificationRuleSI; - -/// \brief class CPhsRuleSI -typedef struct _stPhsRuleSI { - /** 8bit PHS Index Of The Service Flow*/ - B_UINT8 u8PHSI; - /** PHSF Length Of The Service Flow*/ - B_UINT8 u8PHSFLength; - /** String of bytes containing header information to be suppressed by the sending CS and reconstructed by the receiving CS*/ - B_UINT8 u8PHSF[MAX_PHS_LENGTHS]; - /** PHSM Length Of The Service Flow*/ - B_UINT8 u8PHSMLength; - /** PHS Mask for the SF*/ - B_UINT8 u8PHSM[MAX_PHS_LENGTHS]; - /** 8bit Total number of bytes to be suppressed for the Service Flow*/ - B_UINT8 u8PHSS; - /** 8bit Indicates whether or not Packet Header contents need to be verified prior to suppression */ - B_UINT8 u8PHSV; - /** Vendor Specific PHS param Length Of The Service Flow*/ - B_UINT8 u8VendorSpecificPHSParamsLength; - /** Vendor Specific PHS param Of The Service Flow*/ - B_UINT8 u8VendorSpecificPHSParams[VENDOR_PHS_PARAM_LENGTH]; - - B_UINT8 u8Padding[2]; -}stPhsRuleSI,*pstPhsRuleSI; -typedef stPhsRuleSI CPhsRuleSI; -/// \brief structure cConvergenceSLTypes -struct _stConvergenceSLTypes{ - /** 8bit Phs Classfier Action Of The Service Flow*/ - B_UINT8 u8ClassfierDSCAction; - /** 8bit Phs DSC Action Of The Service Flow*/ - B_UINT8 u8PhsDSCAction; - /** 16bit Padding */ - B_UINT8 u8Padding[2]; - /// \brief class cCPacketClassificationRule - stCPacketClassificationRuleSI cCPacketClassificationRule; - /// \brief class CPhsRuleSI - struct _stPhsRuleSI cPhsRule; +struct bcm_phs_rules { + /* 8bit PHS Index Of The Service Flow */ + B_UINT8 u8PHSI; + /* PHSF Length Of The Service Flow */ + B_UINT8 u8PHSFLength; + /* String of bytes containing header information to be suppressed by the sending CS and reconstructed by the receiving CS */ + B_UINT8 u8PHSF[MAX_PHS_LENGTHS]; + /* PHSM Length Of The Service Flow */ + B_UINT8 u8PHSMLength; + /* PHS Mask for the SF */ + B_UINT8 u8PHSM[MAX_PHS_LENGTHS]; + /* 8bit Total number of bytes to be suppressed for the Service Flow */ + B_UINT8 u8PHSS; + /* 8bit Indicates whether or not Packet Header contents need to be verified prior to suppression */ + B_UINT8 u8PHSV; + /* Vendor Specific PHS param Length Of The Service Flow */ + B_UINT8 u8VendorSpecificPHSParamsLength; + /* Vendor Specific PHS param Of The Service Flow */ + B_UINT8 u8VendorSpecificPHSParams[VENDOR_PHS_PARAM_LENGTH]; + B_UINT8 u8Padding[2]; }; -typedef struct _stConvergenceSLTypes stConvergenceSLTypes,CConvergenceSLTypes, *pstConvergenceSLTypes; - - -/// \brief structure CServiceFlowParamSI -typedef struct _stServiceFlowParamSI{ - - /** 32bitSFID Of The Service Flow*/ - B_UINT32 u32SFID; - - /** 32bit Maximum Sustained Traffic Rate of the Service Flow*/ - B_UINT32 u32MaxSustainedTrafficRate; - - /** 32bit Maximum Traffic Burst allowed for the Service Flow*/ - B_UINT32 u32MaxTrafficBurst; - - /** 32bit Minimum Reserved Traffic Rate of the Service Flow*/ - B_UINT32 u32MinReservedTrafficRate; - - /** 32bit Tolerated Jitter of the Service Flow*/ - B_UINT32 u32ToleratedJitter; - - /** 32bit Maximum Latency of the Service Flow*/ - B_UINT32 u32MaximumLatency; - - /** 16bitCID Of The Service Flow*/ - B_UINT16 u16CID; - - /** 16bit SAID on which the service flow being set up shall be mapped*/ - B_UINT16 u16TargetSAID; - - /** 16bit ARQ window size negotiated*/ - B_UINT16 u16ARQWindowSize; - - /** 16bit Total Tx delay incl sending, receiving & processing delays */ - B_UINT16 u16ARQRetryTxTimeOut; - - /** 16bit Total Rx delay incl sending, receiving & processing delays */ - B_UINT16 u16ARQRetryRxTimeOut; - - /** 16bit ARQ block lifetime */ - B_UINT16 u16ARQBlockLifeTime; - - /** 16bit ARQ Sync loss timeout*/ - B_UINT16 u16ARQSyncLossTimeOut; - - /** 16bit ARQ Purge timeout */ - B_UINT16 u16ARQRxPurgeTimeOut; -//TODO::Remove this once we move to a new CORR2 driver - /// \brief Size of an ARQ block - B_UINT16 u16ARQBlockSize; - -//#endif - /** 16bit Nominal interval b/w consecutive SDU arrivals at MAC SAP*/ - B_UINT16 u16SDUInterArrivalTime; - - /** 16bit Specifies the time base for rate measurement */ - B_UINT16 u16TimeBase; - - /** 16bit Interval b/w Successive Grant oppurtunities*/ - B_UINT16 u16UnsolicitedGrantInterval; - - /** 16bit Interval b/w Successive Polling grant oppurtunities*/ - B_UINT16 u16UnsolicitedPollingInterval; - - /** internal var to get the overhead */ - B_UINT16 u16MacOverhead; - - /** MBS contents Identifier*/ - B_UINT16 u16MBSContentsID[MBS_CONTENTS_ID_LENGTH]; - - /** MBS contents Identifier length*/ - B_UINT8 u8MBSContentsIDLength; - - /** ServiceClassName Length Of The Service Flow*/ - B_UINT8 u8ServiceClassNameLength; - - /** 32bytes ServiceClassName Of The Service Flow*/ - B_UINT8 u8ServiceClassName[32]; - - /** 8bit Indicates whether or not MBS service is requested for this Serivce Flow*/ - B_UINT8 u8MBSService; - - /** 8bit QOS Parameter Set specifies proper application of QoS paramters to Provisioned, Admitted and Active sets*/ - B_UINT8 u8QosParamSet; - - /** 8bit Traffic Priority Of the Service Flow */ - B_UINT8 u8TrafficPriority; - - /** 8bit Uplink Grant Scheduling Type of The Service Flow */ - B_UINT8 u8ServiceFlowSchedulingType; - - /** 8bit Request transmission Policy of the Service Flow*/ - B_UINT8 u8RequesttransmissionPolicy; - - /** 8bit Specifies whether SDUs for this Service flow are of FixedLength or Variable length */ - B_UINT8 u8FixedLengthVSVariableLengthSDUIndicator; - - /** 8bit Length of the SDU for a fixed length SDU service flow*/ - B_UINT8 u8SDUSize; - /** 8bit Indicates whether or not ARQ is requested for this connection*/ - B_UINT8 u8ARQEnable; - - /**< 8bit Indicates whether or not data has tobe delivered in order to higher layer*/ - B_UINT8 u8ARQDeliverInOrder; - - /** 8bit Receiver ARQ ACK processing time */ - B_UINT8 u8RxARQAckProcessingTime; - - /** 8bit Convergence Sublayer Specification Of The Service Flow*/ - B_UINT8 u8CSSpecification; - - /** 8 bit Type of data delivery service*/ - B_UINT8 u8TypeOfDataDeliveryService; - - /** 8bit Specifies whether a service flow may generate Paging */ - B_UINT8 u8PagingPreference; - - /** 8bit Indicates the MBS Zone through which the connection or virtual connection is valid */ - B_UINT8 u8MBSZoneIdentifierassignment; - - /** 8bit Specifies whether traffic on SF should generate MOB_TRF_IND to MS in sleep mode*/ - B_UINT8 u8TrafficIndicationPreference; - - /** 8bit Speciifes the length of predefined Global QoS parameter set encoding for this SF */ - B_UINT8 u8GlobalServicesClassNameLength; - - /** 6 byte Speciifes the predefined Global QoS parameter set encoding for this SF */ - B_UINT8 u8GlobalServicesClassName[GLOBAL_SF_CLASSNAME_LENGTH]; - - /** 8bit Indicates whether or not SN feedback is enabled for the conn */ - B_UINT8 u8SNFeedbackEnabled; - - /** Indicates the size of the Fragment Sequence Number for the connection */ - B_UINT8 u8FSNSize; - - /** 8bit Number of CIDs in active BS list */ - B_UINT8 u8CIDAllocation4activeBSsLength; - - /** CIDs of BS in the active list */ - B_UINT8 u8CIDAllocation4activeBSs[MAX_NUM_ACTIVE_BS]; - - /** Specifies if PDU extended subheader should be applied on every PDU on this conn*/ - B_UINT8 u8PDUSNExtendedSubheader4HarqReordering; - - /** 8bit Specifies whether the connection uses HARQ or not */ - B_UINT8 u8HARQServiceFlows; - - /** Specifies the length of Authorization token*/ - B_UINT8 u8AuthTokenLength; - - /** Specifies the Authorization token*/ - B_UINT8 u8AuthToken[AUTH_TOKEN_LENGTH]; - - /** specifes Number of HARQ channels used to carry data length*/ - B_UINT8 u8HarqChannelMappingLength; - - /** specifes HARQ channels used to carry data*/ - B_UINT8 u8HARQChannelMapping[NUM_HARQ_CHANNELS]; - - /** 8bit Length of Vendor Specific QoS Params */ - B_UINT8 u8VendorSpecificQoSParamLength; - - /** 1byte Vendor Specific QoS Param Of The Service Flow*/ - B_UINT8 u8VendorSpecificQoSParam[VENDOR_SPECIF_QOS_PARAM]; - - // indicates total classifiers in the SF - B_UINT8 u8TotalClassifiers; /**< Total number of valid classifiers*/ - B_UINT8 bValid; /**< Validity flag */ - B_UINT8 u8Padding; /**< Padding byte*/ - -/** -Structure for Convergence SubLayer Types with a maximum of 4 classifiers -*/ - stConvergenceSLTypes cConvergenceSLTypes[MAX_CLASSIFIERS_IN_SF]; - -} stServiceFlowParamSI, *pstServiceFlowParamSI; -typedef stServiceFlowParamSI CServiceFlowParamSI; - -/** -structure stLocalSFAddRequest -*/ -typedef struct _stLocalSFAddRequest{ - - B_UINT8 u8Type; /**< Type*/ - B_UINT8 eConnectionDir; /**< Connection direction*/ - /// \brief 16 bit TID - B_UINT16 u16TID; /**< 16bit TID*/ - /// \brief 16bitCID - B_UINT16 u16CID; /**< 16bit CID*/ - /// \brief 16bitVCID - B_UINT16 u16VCID; /**< 16bit VCID*/ - /// \brief structure ParameterSet - - stServiceFlowParamSI *psfParameterSet; /**< structure ParameterSet*/ - -}stLocalSFAddRequest, *pstLocalSFAddRequest; - - -/** -structure stLocalSFAddIndication -*/ -typedef struct _stLocalSFAddIndication{ - - B_UINT8 u8Type; /**< Type*/ - B_UINT8 eConnectionDir; /**< Connection Direction*/ - /// \brief 16 bit TID - B_UINT16 u16TID; /**< TID*/ - /// \brief 16bitCID - B_UINT16 u16CID; /**< 16bitCID*/ - /// \brief 16bitVCID - B_UINT16 u16VCID; /**< 16bitVCID*/ - - - /// \brief structure AuthorizedSet - /// \brief structure AuthorizedSet - stServiceFlowParamSI *psfAuthorizedSet; /**< AuthorizedSet of type stServiceFlowParamSI*/ - /// \brief structure AdmittedSet - stServiceFlowParamSI *psfAdmittedSet; /**< AdmittedSet of type stServiceFlowParamSI*/ - /// \brief structure ActiveSet - stServiceFlowParamSI *psfActiveSet; /**< sfActiveSet of type stServiceFlowParamSI*/ - B_UINT8 u8CC; /**< Confirmation Code*/ - B_UINT8 u8Padd; /**< 8-bit Padding */ - - B_UINT16 u16Padd; /**< 16 bit Padding */ - -}stLocalSFAddIndication; +struct bcm_convergence_types { + /* 8bit Phs Classfier Action Of The Service Flow */ + B_UINT8 u8ClassfierDSCAction; + /* 8bit Phs DSC Action Of The Service Flow */ + B_UINT8 u8PhsDSCAction; + /* 16bit Padding */ + B_UINT8 u8Padding[2]; + /* Packet classification rules structure */ + struct bcm_packet_class_rules cCPacketClassificationRule; + /* Payload header suppression rules structure */ + struct bcm_phs_rules cPhsRule; +}; +struct bcm_connect_mgr_params { + /* 32bitSFID Of The Service Flow */ + B_UINT32 u32SFID; + /* 32bit Maximum Sustained Traffic Rate of the Service Flow */ + B_UINT32 u32MaxSustainedTrafficRate; + /* 32bit Maximum Traffic Burst allowed for the Service Flow */ + B_UINT32 u32MaxTrafficBurst; + /* 32bit Minimum Reserved Traffic Rate of the Service Flow */ + B_UINT32 u32MinReservedTrafficRate; + /* 32bit Tolerated Jitter of the Service Flow */ + B_UINT32 u32ToleratedJitter; + /* 32bit Maximum Latency of the Service Flow */ + B_UINT32 u32MaximumLatency; + /* 16bitCID Of The Service Flow */ + B_UINT16 u16CID; + /* 16bit SAID on which the service flow being set up shall be mapped */ + B_UINT16 u16TargetSAID; + /* 16bit ARQ window size negotiated */ + B_UINT16 u16ARQWindowSize; + /* 16bit Total Tx delay incl sending, receiving & processing delays */ + B_UINT16 u16ARQRetryTxTimeOut; + /* 16bit Total Rx delay incl sending, receiving & processing delays */ + B_UINT16 u16ARQRetryRxTimeOut; + /* 16bit ARQ block lifetime */ + B_UINT16 u16ARQBlockLifeTime; + /* 16bit ARQ Sync loss timeout */ + B_UINT16 u16ARQSyncLossTimeOut; + /* 16bit ARQ Purge timeout */ + B_UINT16 u16ARQRxPurgeTimeOut; + /* TODO::Remove this once we move to a new CORR2 driver + * brief Size of an ARQ block + */ + B_UINT16 u16ARQBlockSize; + /* #endif */ + /* 16bit Nominal interval b/w consecutive SDU arrivals at MAC SAP */ + B_UINT16 u16SDUInterArrivalTime; + /* 16bit Specifies the time base for rate measurement */ + B_UINT16 u16TimeBase; + /* 16bit Interval b/w Successive Grant oppurtunities */ + B_UINT16 u16UnsolicitedGrantInterval; + /* 16bit Interval b/w Successive Polling grant oppurtunities */ + B_UINT16 u16UnsolicitedPollingInterval; + /* internal var to get the overhead */ + B_UINT16 u16MacOverhead; + /* MBS contents Identifier */ + B_UINT16 u16MBSContentsID[MBS_CONTENTS_ID_LENGTH]; + /* MBS contents Identifier length */ + B_UINT8 u8MBSContentsIDLength; + /* ServiceClassName Length Of The Service Flow */ + B_UINT8 u8ServiceClassNameLength; + /* 32bytes ServiceClassName Of The Service Flow */ + B_UINT8 u8ServiceClassName[32]; + /* 8bit Indicates whether or not MBS service is requested for this Serivce Flow */ + B_UINT8 u8MBSService; + /* 8bit QOS Parameter Set specifies proper application of QoS parameters to Provisioned, Admitted and Active sets */ + B_UINT8 u8QosParamSet; + /* 8bit Traffic Priority Of the Service Flow */ + B_UINT8 u8TrafficPriority; + /* 8bit Uplink Grant Scheduling Type of The Service Flow */ + B_UINT8 u8ServiceFlowSchedulingType; + /* 8bit Request transmission Policy of the Service Flow */ + B_UINT8 u8RequesttransmissionPolicy; + /* 8bit Specifies whether SDUs for this Service flow are of FixedLength or Variable length */ + B_UINT8 u8FixedLengthVSVariableLengthSDUIndicator; + /* 8bit Length of the SDU for a fixed length SDU service flow */ + B_UINT8 u8SDUSize; + /* 8bit Indicates whether or not ARQ is requested for this connection */ + B_UINT8 u8ARQEnable; + /* < 8bit Indicates whether or not data has tobe delivered in order to higher layer */ + B_UINT8 u8ARQDeliverInOrder; + /* 8bit Receiver ARQ ACK processing time */ + B_UINT8 u8RxARQAckProcessingTime; + /* 8bit Convergence Sublayer Specification Of The Service Flow */ + B_UINT8 u8CSSpecification; + /* 8 bit Type of data delivery service */ + B_UINT8 u8TypeOfDataDeliveryService; + /* 8bit Specifies whether a service flow may generate Paging */ + B_UINT8 u8PagingPreference; + /* 8bit Indicates the MBS Zone through which the connection or virtual connection is valid */ + B_UINT8 u8MBSZoneIdentifierassignment; + /* 8bit Specifies whether traffic on SF should generate MOB_TRF_IND to MS in sleep mode */ + B_UINT8 u8TrafficIndicationPreference; + /* 8bit Speciifes the length of predefined Global QoS parameter set encoding for this SF */ + B_UINT8 u8GlobalServicesClassNameLength; + /* 6 byte Speciifes the predefined Global QoS parameter set encoding for this SF */ + B_UINT8 u8GlobalServicesClassName[GLOBAL_SF_CLASSNAME_LENGTH]; + /* 8bit Indicates whether or not SN feedback is enabled for the conn */ + B_UINT8 u8SNFeedbackEnabled; + /* Indicates the size of the Fragment Sequence Number for the connection */ + B_UINT8 u8FSNSize; + /* 8bit Number of CIDs in active BS list */ + B_UINT8 u8CIDAllocation4activeBSsLength; + /* CIDs of BS in the active list */ + B_UINT8 u8CIDAllocation4activeBSs[MAX_NUM_ACTIVE_BS]; + /* Specifies if PDU extended subheader should be applied on every PDU on this conn */ + B_UINT8 u8PDUSNExtendedSubheader4HarqReordering; + /* 8bit Specifies whether the connection uses HARQ or not */ + B_UINT8 u8HARQServiceFlows; + /* Specifies the length of Authorization token */ + B_UINT8 u8AuthTokenLength; + /* Specifies the Authorization token */ + B_UINT8 u8AuthToken[AUTH_TOKEN_LENGTH]; + /* specifes Number of HARQ channels used to carry data length */ + B_UINT8 u8HarqChannelMappingLength; + /* specifes HARQ channels used to carry data */ + B_UINT8 u8HARQChannelMapping[NUM_HARQ_CHANNELS]; + /* 8bit Length of Vendor Specific QoS Params */ + B_UINT8 u8VendorSpecificQoSParamLength; + /* 1byte Vendor Specific QoS Param Of The Service Flow */ + B_UINT8 u8VendorSpecificQoSParam[VENDOR_SPECIF_QOS_PARAM]; + /* indicates total classifiers in the SF */ + B_UINT8 u8TotalClassifiers; /* < Total number of valid classifiers */ + B_UINT8 bValid; /* < Validity flag */ + B_UINT8 u8Padding; /* < Padding byte */ + /* + * Structure for Convergence SubLayer Types with a maximum of 4 classifiers + */ + struct bcm_convergence_types cConvergenceSLTypes[MAX_CLASSIFIERS_IN_SF]; +}; -typedef struct _stLocalSFAddIndication *pstLocalSFAddIndication; -/** -structure stLocalSFChangeRequest is same as structure stLocalSFAddIndication -*/ -typedef struct _stLocalSFAddIndication stLocalSFChangeRequest, *pstLocalSFChangeRequest; -/** -structure stLocalSFChangeIndication is same as structure stLocalSFAddIndication -*/ -typedef struct _stLocalSFAddIndication stLocalSFChangeIndication, *pstLocalSFChangeIndication; +struct bcm_add_request { + B_UINT8 u8Type; /* < Type */ + B_UINT8 eConnectionDir; /* < Connection direction */ + /* brief 16 bit TID */ + B_UINT16 u16TID; /* < 16bit TID */ + /* brief 16bitCID */ + B_UINT16 u16CID; /* < 16bit CID */ + /* brief 16bitVCID */ + B_UINT16 u16VCID; /* < 16bit VCID */ + struct bcm_connect_mgr_params *psfParameterSet; /* < connection manager parameters */ +}; -/** -structure stLocalSFDeleteRequest -*/ -typedef struct _stLocalSFDeleteRequest{ - B_UINT8 u8Type; /**< Type*/ - B_UINT8 u8Padding; /**< Padding byte*/ - B_UINT16 u16TID; /**< TID*/ - /// \brief 32bitSFID - B_UINT32 u32SFID; /**< SFID*/ -}stLocalSFDeleteRequest, *pstLocalSFDeleteRequest; +struct bcm_add_indication { + B_UINT8 u8Type; /* < Type */ + B_UINT8 eConnectionDir; /* < Connection Direction */ + /* brief 16 bit TID */ + B_UINT16 u16TID; /* < TID */ + /* brief 16bitCID */ + B_UINT16 u16CID; /* < 16bitCID */ + /* brief 16bitVCID */ + B_UINT16 u16VCID; /* < 16bitVCID */ + struct bcm_connect_mgr_params *psfAuthorizedSet; /* Authorized set of connection manager parameters */ + struct bcm_connect_mgr_params *psfAdmittedSet; /* Admitted set of connection manager parameters */ + struct bcm_connect_mgr_params *psfActiveSet; /* Activeset of connection manager parameters */ + B_UINT8 u8CC; /* <Confirmation Code */ + B_UINT8 u8Padd; /* < 8-bit Padding */ + B_UINT16 u16Padd; /* < 16 bit Padding */ +}; -/** -structure stLocalSFDeleteIndication -*/ -typedef struct stLocalSFDeleteIndication{ - B_UINT8 u8Type; /**< Type */ - B_UINT8 u8Padding; /**< Padding */ - B_UINT16 u16TID; /**< TID */ - /// \brief 16bitCID - B_UINT16 u16CID; /**< CID */ - /// \brief 16bitVCID - B_UINT16 u16VCID; /**< VCID */ - /// \brief 32bitSFID - B_UINT32 u32SFID; /**< SFID */ - /// \brief 8bit Confirmation code - B_UINT8 u8ConfirmationCode; /**< Confirmation code */ - B_UINT8 u8Padding1[3]; /**< 3 byte Padding */ -}stLocalSFDeleteIndication; +struct bcm_del_request { + B_UINT8 u8Type; /* < Type */ + B_UINT8 u8Padding; /* < Padding byte */ + B_UINT16 u16TID; /* < TID */ + /* brief 32bitSFID */ + B_UINT32 u32SFID; /* < SFID */ +}; -typedef struct _stIM_SFHostNotify -{ - B_UINT32 SFID; //SFID of the service flow - B_UINT16 newCID; //the new/changed CID - B_UINT16 VCID; //Get new Vcid if the flow has been made active in CID update TLV, but was inactive earlier or the orig vcid - B_UINT8 RetainSF; //Indication to Host if the SF is to be retained or deleted; if TRUE-retain else delete - B_UINT8 QoSParamSet; //QoS paramset of the retained SF - B_UINT16 u16reserved; //For byte alignment +struct bcm_del_indication { + B_UINT8 u8Type; /* < Type */ + B_UINT8 u8Padding; /* < Padding */ + B_UINT16 u16TID; /* < TID */ + /* brief 16bitCID */ + B_UINT16 u16CID; /* < CID */ + /* brief 16bitVCID */ + B_UINT16 u16VCID; /* < VCID */ + /* brief 32bitSFID */ + B_UINT32 u32SFID; /* < SFID */ + /* brief 8bit Confirmation code */ + B_UINT8 u8ConfirmationCode; /* < Confirmation code */ + B_UINT8 u8Padding1[3]; /* < 3 byte Padding */ +}; -} stIM_SFHostNotify; +struct bcm_stim_sfhostnotify { + B_UINT32 SFID; /* SFID of the service flow */ + B_UINT16 newCID; /* the new/changed CID */ + B_UINT16 VCID; /* Get new Vcid if the flow has been made active in CID update TLV, but was inactive earlier or the orig vcid */ + B_UINT8 RetainSF; /* Indication to Host if the SF is to be retained or deleted; if TRUE-retain else delete */ + B_UINT8 QoSParamSet; /* QoS paramset of the retained SF */ + B_UINT16 u16reserved; /* For byte alignment */ +}; #endif diff --git a/drivers/staging/bcm/hostmibs.c b/drivers/staging/bcm/hostmibs.c index 08d13a4dfd70..10361bb35059 100644 --- a/drivers/staging/bcm/hostmibs.c +++ b/drivers/staging/bcm/hostmibs.c @@ -101,7 +101,7 @@ VOID GetDroppedAppCntrlPktMibs(S_MIBS_HOST_STATS_MIBS *pstHostMibs, struct bcm_t sizeof(S_MIBS_DROPPED_APP_CNTRL_MESSAGES)); } -VOID CopyMIBSExtendedSFParameters(struct bcm_mini_adapter *Adapter, CServiceFlowParamSI *psfLocalSet, UINT uiSearchRuleIndex) +VOID CopyMIBSExtendedSFParameters(struct bcm_mini_adapter *Adapter, struct bcm_connect_mgr_params *psfLocalSet, UINT uiSearchRuleIndex) { S_MIBS_EXTSERVICEFLOW_PARAMETERS *t = &Adapter->PackInfo[uiSearchRuleIndex].stMibsExtServiceFlowTable; diff --git a/drivers/staging/bcm/nvm.c b/drivers/staging/bcm/nvm.c index b179dbab93b5..b034eb5fa6b1 100644 --- a/drivers/staging/bcm/nvm.c +++ b/drivers/staging/bcm/nvm.c @@ -577,7 +577,7 @@ static int FlashSectorErase(struct bcm_mini_adapter *Adapter, * the sector erase cycle is 500 ms to 40000 msec. hence sleeping 10 ms * won't hamper performance in any case. */ - udelay(10000); + mdelay(10); } while ((uiStatus & 0x1) && (iRetries < 400)); if (uiStatus & 0x1) { @@ -3932,7 +3932,7 @@ int validateFlash2xReadWrite(struct bcm_mini_adapter *Adapter, PFLASH2X_READWRIT BcmGetSectionValStartOffset(Adapter, ISO_IMAGE2_PART3); } - /* since this uiSectEndoffset is the size of iso Image. hence for calculating the vitual endoffset + /* since this uiSectEndoffset is the size of iso Image. hence for calculating the virtual endoffset * it should be added in startoffset. so that check done in last of this function can be valued. */ uiSectEndOffset = uiSectStartOffset + uiSectEndOffset; diff --git a/drivers/staging/bcm/target_params.h b/drivers/staging/bcm/target_params.h index 14876388b879..ad7ec0054938 100644 --- a/drivers/staging/bcm/target_params.h +++ b/drivers/staging/bcm/target_params.h @@ -32,7 +32,7 @@ typedef struct _TARGET_PARAMS B_UINT32 m_u32PowerSavingModesEnable; //bit 1: 1 Idlemode enable; bit2: 1 Sleepmode Enable /* PowerSaving Mode Options: bit 0 = 1: CPE mode - to keep pcmcia if alive; - bit 1 = 1: CINR reporing in Idlemode Msg + bit 1 = 1: CINR reporting in Idlemode Msg bit 2 = 1: Default PSC Enable in sleepmode*/ B_UINT32 m_u32PowerSavingModeOptions; diff --git a/drivers/staging/ccg/Kconfig b/drivers/staging/ccg/Kconfig index 1f00d701da25..8598111eb0b1 100644 --- a/drivers/staging/ccg/Kconfig +++ b/drivers/staging/ccg/Kconfig @@ -2,7 +2,7 @@ if USB_GADGET config USB_G_CCG tristate "Configurable Composite Gadget (STAGING)" - depends on STAGING && BLOCK && !USB_ZERO && !USB_ZERO_HNPTEST && !USB_AUDIO && !GADGET_UAC1 && !USB_ETH && !USB_ETH_RNDIS && !USB_ETH_EEM && !USB_G_NCM && !USB_GADGETFS && !USB_FUNCTIONFS && !USB_FUNCTIONFS_ETH && !USB_FUNCTIONFS_RNDIS && !USB_FUNCTIONFS_GENERIC && !USB_FILE_STORAGE && !USB_FILE_STORAGE_TEST && !USB_MASS_STORAGE && !USB_G_SERIAL && !USB_MIDI_GADGET && !USB_G_PRINTER && !USB_CDC_COMPOSITE && !USB_G_NOKIA && !USB_G_ACM_MS && !USB_G_MULTI && !USB_G_MULTI_RNDIS && !USB_G_MULTI_CDC && !USB_G_HID && !USB_G_DBGP && !USB_G_WEBCAM + depends on STAGING && BLOCK && NET && !USB_ZERO && !USB_ZERO_HNPTEST && !USB_AUDIO && !GADGET_UAC1 && !USB_ETH && !USB_ETH_RNDIS && !USB_ETH_EEM && !USB_G_NCM && !USB_GADGETFS && !USB_FUNCTIONFS && !USB_FUNCTIONFS_ETH && !USB_FUNCTIONFS_RNDIS && !USB_FUNCTIONFS_GENERIC && !USB_FILE_STORAGE && !USB_FILE_STORAGE_TEST && !USB_MASS_STORAGE && !USB_G_SERIAL && !USB_MIDI_GADGET && !USB_G_PRINTER && !USB_CDC_COMPOSITE && !USB_G_NOKIA && !USB_G_ACM_MS && !USB_G_MULTI && !USB_G_MULTI_RNDIS && !USB_G_MULTI_CDC && !USB_G_HID && !USB_G_DBGP && !USB_G_WEBCAM help The Configurable Composite Gadget supports multiple USB functions: acm, mass storage, rndis and FunctionFS. diff --git a/drivers/staging/ccg/ccg.c b/drivers/staging/ccg/ccg.c index 6a7aab8d9bf5..3fbb300cbe30 100644 --- a/drivers/staging/ccg/ccg.c +++ b/drivers/staging/ccg/ccg.c @@ -728,7 +728,7 @@ static int mass_storage_function_init(struct ccg_usb_function *f, struct fsg_common *common; int err; - memset(&fsg, 0, sizeof fsg); + memset(&fsg, 0, sizeof(fsg)); fsg.nluns = 1; fsg.luns[0].removable = 1; fsg.vendor_name = iManufacturer; @@ -1101,13 +1101,7 @@ static struct device_attribute *ccg_usb_attributes[] = { static int ccg_bind_config(struct usb_configuration *c) { struct ccg_dev *dev = _ccg_dev; - int ret = 0; - - ret = ccg_bind_enabled_functions(dev, c); - if (ret) - return ret; - - return 0; + return ccg_bind_enabled_functions(dev, c); } static void ccg_unbind_config(struct usb_configuration *c) @@ -1254,8 +1248,10 @@ static int __init init(void) return PTR_ERR(ccg_class); dev = kzalloc(sizeof(*dev), GFP_KERNEL); - if (!dev) + if (!dev) { + class_destroy(ccg_class); return -ENOMEM; + } dev->functions = supported_functions; INIT_LIST_HEAD(&dev->enabled_functions); diff --git a/drivers/staging/ced1401/Kconfig b/drivers/staging/ced1401/Kconfig new file mode 100644 index 000000000000..ae36d1b2ba99 --- /dev/null +++ b/drivers/staging/ced1401/Kconfig @@ -0,0 +1,6 @@ +config CED1401 + tristate "Cambridge Electronic Design 1401 USB support" + depends on USB + help + This driver supports the Cambridge Electronic Design 1401 USB device + (whatever that is.) diff --git a/drivers/staging/ced1401/Makefile b/drivers/staging/ced1401/Makefile new file mode 100644 index 000000000000..f0c114b2b4b9 --- /dev/null +++ b/drivers/staging/ced1401/Makefile @@ -0,0 +1,3 @@ + +obj-$(CONFIG_CED1401) := cedusb.o +cedusb-objs := usb1401.o ced_ioc.o diff --git a/drivers/staging/ced1401/TODO b/drivers/staging/ced1401/TODO new file mode 100644 index 000000000000..9fd5630bdf4d --- /dev/null +++ b/drivers/staging/ced1401/TODO @@ -0,0 +1,10 @@ +TODO: + - coding syle fixes + - build warning fixups + - ioctl auditing + - usb api auditing + - proper USB minor number (it's stomping on an existing one right now.) + +Please send patches to Greg Kroah-Hartman <gregkh@linuxfoundation.org> and Cc: +Alois Schlögl <alois.schloegl@ist.ac.at> + diff --git a/drivers/staging/ced1401/ced_ioc.c b/drivers/staging/ced1401/ced_ioc.c new file mode 100644 index 000000000000..c9492edaaddb --- /dev/null +++ b/drivers/staging/ced1401/ced_ioc.c @@ -0,0 +1,1515 @@ +/* ced_ioc.c + ioctl part of the 1401 usb device driver for linux. + Copyright (C) 2010 Cambridge Electronic Design Ltd + Author Greg P Smith (greg@ced.co.uk) + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/kref.h> +#include <linux/uaccess.h> +#include <linux/usb.h> +#include <linux/mutex.h> +#include <linux/page-flags.h> +#include <linux/pagemap.h> +#include <linux/jiffies.h> + +#include "usb1401.h" + +/**************************************************************************** +** FlushOutBuff +** +** Empties the Output buffer and sets int lines. Used from user level only +****************************************************************************/ +void FlushOutBuff(DEVICE_EXTENSION * pdx) +{ + dev_dbg(&pdx->interface->dev, "%s currentState=%d", __func__, + pdx->sCurrentState); + if (pdx->sCurrentState == U14ERR_TIME) /* Do nothing if hardware in trouble */ + return; +// CharSend_Cancel(pdx); /* Kill off any pending I/O */ + spin_lock_irq(&pdx->charOutLock); + pdx->dwNumOutput = 0; + pdx->dwOutBuffGet = 0; + pdx->dwOutBuffPut = 0; + spin_unlock_irq(&pdx->charOutLock); +} + +/**************************************************************************** +** +** FlushInBuff +** +** Empties the input buffer and sets int lines +****************************************************************************/ +void FlushInBuff(DEVICE_EXTENSION * pdx) +{ + dev_dbg(&pdx->interface->dev, "%s currentState=%d", __func__, + pdx->sCurrentState); + if (pdx->sCurrentState == U14ERR_TIME) /* Do nothing if hardware in trouble */ + return; +// CharRead_Cancel(pDevObject); /* Kill off any pending I/O */ + spin_lock_irq(&pdx->charInLock); + pdx->dwNumInput = 0; + pdx->dwInBuffGet = 0; + pdx->dwInBuffPut = 0; + spin_unlock_irq(&pdx->charInLock); +} + +/**************************************************************************** +** PutChars +** +** Utility routine to copy chars into the output buffer and fire them off. +** called from user mode, holds charOutLock. +****************************************************************************/ +static int PutChars(DEVICE_EXTENSION * pdx, const char *pCh, + unsigned int uCount) +{ + int iReturn; + spin_lock_irq(&pdx->charOutLock); // get the output spin lock + if ((OUTBUF_SZ - pdx->dwNumOutput) >= uCount) { + unsigned int u; + for (u = 0; u < uCount; u++) { + pdx->outputBuffer[pdx->dwOutBuffPut++] = pCh[u]; + if (pdx->dwOutBuffPut >= OUTBUF_SZ) + pdx->dwOutBuffPut = 0; + } + pdx->dwNumOutput += uCount; + spin_unlock_irq(&pdx->charOutLock); + iReturn = SendChars(pdx); // ...give a chance to transmit data + } else { + iReturn = U14ERR_NOOUT; // no room at the out (ha-ha) + spin_unlock_irq(&pdx->charOutLock); + } + return iReturn; +} + +/***************************************************************************** +** Add the data in pData (local pointer) of length n to the output buffer, and +** trigger an output transfer if this is appropriate. User mode. +** Holds the io_mutex +*****************************************************************************/ +int SendString(DEVICE_EXTENSION * pdx, const char __user * pData, + unsigned int n) +{ + int iReturn = U14ERR_NOERROR; // assume all will be well + char buffer[OUTBUF_SZ + 1]; // space in our address space for characters + if (n > OUTBUF_SZ) // check space in local buffer... + return U14ERR_NOOUT; // ...too many characters + if (copy_from_user(buffer, pData, n)) + return -EFAULT; + buffer[n] = 0; // terminate for debug purposes + + mutex_lock(&pdx->io_mutex); // Protect disconnect from new i/o + if (n > 0) // do nothing if nowt to do! + { + dev_dbg(&pdx->interface->dev, "%s n=%d>%s<", __func__, n, + buffer); + iReturn = PutChars(pdx, buffer, n); + } + + Allowi(pdx, false); // make sure we have input int + mutex_unlock(&pdx->io_mutex); + + return iReturn; +} + +/**************************************************************************** +** SendChar +** +** Sends a single character to the 1401. User mode, holds io_mutex. +****************************************************************************/ +int SendChar(DEVICE_EXTENSION * pdx, char c) +{ + int iReturn; + mutex_lock(&pdx->io_mutex); // Protect disconnect from new i/o + iReturn = PutChars(pdx, &c, 1); + dev_dbg(&pdx->interface->dev, "SendChar >%c< (0x%02x)", c, c); + Allowi(pdx, false); // Make sure char reads are running + mutex_unlock(&pdx->io_mutex); + return iReturn; +} + +/*************************************************************************** +** +** Get1401State +** +** Retrieves state information from the 1401, adjusts the 1401 state held +** in the device extension to indicate the current 1401 type. +** +** *state is updated with information about the 1401 state as returned by the +** 1401. The low byte is a code for what 1401 is doing: +** +** 0 normal 1401 operation +** 1 sending chars to host +** 2 sending block data to host +** 3 reading block data from host +** 4 sending an escape sequence to the host +** 0x80 1401 is executing self-test, in which case the upper word +** is the last error code seen (or zero for no new error). +** +** *error is updated with error information if a self-test error code +** is returned in the upper word of state. +** +** both state and error are set to -1 if there are comms problems, and +** to zero if there is a simple failure. +** +** return error code (U14ERR_NOERROR for OK) +*/ +int Get1401State(DEVICE_EXTENSION * pdx, __u32 * state, __u32 * error) +{ + int nGot; + dev_dbg(&pdx->interface->dev, "Get1401State() entry"); + + *state = 0xFFFFFFFF; // Start off with invalid state + nGot = usb_control_msg(pdx->udev, usb_rcvctrlpipe(pdx->udev, 0), + GET_STATUS, (D_TO_H | VENDOR | DEVREQ), 0, 0, + pdx->statBuf, sizeof(pdx->statBuf), HZ); + if (nGot != sizeof(pdx->statBuf)) { + dev_err(&pdx->interface->dev, + "Get1401State() FAILED, return code %d", nGot); + pdx->sCurrentState = U14ERR_TIME; // Indicate that things are very wrong indeed + *state = 0; // Force status values to a known state + *error = 0; + } else { + int nDevice; + dev_dbg(&pdx->interface->dev, + "Get1401State() Success, state: 0x%x, 0x%x", + pdx->statBuf[0], pdx->statBuf[1]); + + *state = pdx->statBuf[0]; // Return the state values to the calling code + *error = pdx->statBuf[1]; + + nDevice = pdx->udev->descriptor.bcdDevice >> 8; // 1401 type code value + switch (nDevice) // so we can clean up current state + { + case 0: + pdx->sCurrentState = U14ERR_U1401; + break; + + default: // allow lots of device codes for future 1401s + if ((nDevice >= 1) && (nDevice <= 23)) + pdx->sCurrentState = (short)(nDevice + 6); + else + pdx->sCurrentState = U14ERR_ILL; + break; + } + } + + return pdx->sCurrentState >= 0 ? U14ERR_NOERROR : pdx->sCurrentState; +} + +/**************************************************************************** +** ReadWrite_Cancel +** +** Kills off staged read\write request from the USB if one is pending. +****************************************************************************/ +int ReadWrite_Cancel(DEVICE_EXTENSION * pdx) +{ + dev_dbg(&pdx->interface->dev, "ReadWrite_Cancel entry %d", + pdx->bStagedUrbPending); +#ifdef NOT_WRITTEN_YET + int ntStatus = STATUS_SUCCESS; + bool bResult = false; + unsigned int i; + // We can fill this in when we know how we will implement the staged transfer stuff + spin_lock_irq(&pdx->stagedLock); + + if (pdx->bStagedUrbPending) // anything to be cancelled? May need more... + { + dev_info(&pdx->interface - dev, + "ReadWrite_Cancel about to cancel Urb"); + + // KeClearEvent(&pdx->StagingDoneEvent); // Clear the staging done flag + USB_ASSERT(pdx->pStagedIrp != NULL); + + // Release the spinlock first otherwise the completion routine may hang + // on the spinlock while this function hands waiting for the event. + spin_unlock_irq(&pdx->stagedLock); + bResult = IoCancelIrp(pdx->pStagedIrp); // Actually do the cancel + if (bResult) { + LARGE_INTEGER timeout; + timeout.QuadPart = -10000000; // Use a timeout of 1 second + dev_info(&pdx->interface - dev, + "ReadWrite_Cancel about to wait till done"); + ntStatus = + KeWaitForSingleObject(&pdx->StagingDoneEvent, + Executive, KernelMode, FALSE, + &timeout); + } else { + dev_info(&pdx->interface - dev, + "ReadWrite_Cancel, cancellation failed"); + ntStatus = U14ERR_FAIL; + } + USB_KdPrint(DBGLVL_DEFAULT, + ("ReadWrite_Cancel ntStatus = 0x%x decimal %d\n", + ntStatus, ntStatus)); + } else + spin_unlock_irq(&pdx->stagedLock); + + dev_info(&pdx->interface - dev, "ReadWrite_Cancel done"); + return ntStatus; +#else + return U14ERR_NOERROR; +#endif + +} + +/*************************************************************************** +** InSelfTest - utility to check in self test. Return 1 for ST, 0 for not or +** a -ve error code if we failed for some reason. +***************************************************************************/ +static int InSelfTest(DEVICE_EXTENSION * pdx, unsigned int *pState) +{ + unsigned int state, error; + int iReturn = Get1401State(pdx, &state, &error); // see if in self-test + if (iReturn == U14ERR_NOERROR) // if all still OK + iReturn = (state == (unsigned int)-1) || // TX problem or... + ((state & 0xff) == 0x80); // ...self test + *pState = state; // return actual state + return iReturn; +} + +/*************************************************************************** +** Is1401 - ALWAYS CALLED HOLDING THE io_mutex +** +** Tests for the current state of the 1401. Sets sCurrentState: +** +** U14ERR_NOIF 1401 i/f card not installed (not done here) +** U14ERR_OFF 1401 apparently not switched on +** U14ERR_NC 1401 appears to be not connected +** U14ERR_ILL 1401 if it is there its not very well at all +** U14ERR_TIME 1401 appears OK, but doesn't communicate - very bad +** U14ERR_STD 1401 OK and ready for use +** U14ERR_PLUS 1401+ OK and ready for use +** U14ERR_U1401 Micro1401 OK and ready for use +** U14ERR_POWER Power1401 OK and ready for use +** U14ERR_U14012 Micro1401 mkII OK and ready for use +** +** Returns TRUE if a 1401 detected and OK, else FALSE +****************************************************************************/ +bool Is1401(DEVICE_EXTENSION * pdx) +{ + int iReturn; + dev_dbg(&pdx->interface->dev, "%s", __func__); + + ced_draw_down(pdx); // wait for, then kill outstanding Urbs + FlushInBuff(pdx); // Clear out input buffer & pipe + FlushOutBuff(pdx); // Clear output buffer & pipe + + // The next call returns 0 if OK, but has returned 1 in the past, meaning that + // usb_unlock_device() is needed... now it always is + iReturn = usb_lock_device_for_reset(pdx->udev, pdx->interface); + + // release the io_mutex because if we don't, we will deadlock due to system + // calls back into the driver. + mutex_unlock(&pdx->io_mutex); // locked, so we will not get system calls + if (iReturn >= 0) // if we failed + { + iReturn = usb_reset_device(pdx->udev); // try to do the reset + usb_unlock_device(pdx->udev); // undo the lock + } + + mutex_lock(&pdx->io_mutex); // hold stuff off while we wait + pdx->dwDMAFlag = MODE_CHAR; // Clear DMA mode flag regardless! + if (iReturn == 0) // if all is OK still + { + unsigned int state; + iReturn = InSelfTest(pdx, &state); // see if likely in self test + if (iReturn > 0) // do we need to wait for self-test? + { + unsigned long ulTimeOut = jiffies + 30 * HZ; // when to give up + while ((iReturn > 0) && time_before(jiffies, ulTimeOut)) { + schedule(); // let other stuff run + iReturn = InSelfTest(pdx, &state); // see if done yet + } + } + + if (iReturn == 0) // if all is OK... + iReturn = state == 0; // then sucess is that the state is 0 + } else + iReturn = 0; // we failed + pdx->bForceReset = false; // Clear forced reset flag now + + return iReturn > 0; +} + +/**************************************************************************** +** QuickCheck - ALWAYS CALLED HOLDING THE io_mutex +** This is used to test for a 1401. It will try to do a quick check if all is +** OK, that is the 1401 was OK the last time it was asked, and there is no DMA +** in progress, and if the bTestBuff flag is set, the character buffers must be +** empty too. If the quick check shows that the state is still the same, then +** all is OK. +** +** If any of the above conditions are not met, or if the state or type of the +** 1401 has changed since the previous test, the full Is1401 test is done, but +** only if bCanReset is also TRUE. +** +** The return value is TRUE if a useable 1401 is found, FALSE if not +*/ +bool QuickCheck(DEVICE_EXTENSION * pdx, bool bTestBuff, bool bCanReset) +{ + bool bRet = false; // assume it will fail and we will reset + bool bShortTest; + + bShortTest = ((pdx->dwDMAFlag == MODE_CHAR) && // no DMA running + (!pdx->bForceReset) && // Not had a real reset forced + (pdx->sCurrentState >= U14ERR_STD)); // No 1401 errors stored + + dev_dbg(&pdx->interface->dev, + "%s DMAFlag:%d, state:%d, force:%d, testBuff:%d, short:%d", + __func__, pdx->dwDMAFlag, pdx->sCurrentState, pdx->bForceReset, + bTestBuff, bShortTest); + + if ((bTestBuff) && // Buffer check requested, and... + (pdx->dwNumInput || pdx->dwNumOutput)) // ...characters were in the buffer? + { + bShortTest = false; // Then do the full test + dev_dbg(&pdx->interface->dev, + "%s will reset as buffers not empty", __func__); + } + + if (bShortTest || !bCanReset) // Still OK to try the short test? + { // Always test if no reset - we want state update + unsigned int state, error; + dev_dbg(&pdx->interface->dev, "%s->Get1401State", __func__); + if (Get1401State(pdx, &state, &error) == U14ERR_NOERROR) // Check on the 1401 state + { + if ((state & 0xFF) == 0) // If call worked, check the status value + bRet = true; // If that was zero, all is OK, no reset needed + } + } + + if (!bRet && bCanReset) // If all not OK, then + { + dev_info(&pdx->interface->dev, "%s->Is1401 %d %d %d %d", + __func__, bShortTest, pdx->sCurrentState, bTestBuff, + pdx->bForceReset); + bRet = Is1401(pdx); // do full test + } + + return bRet; +} + +/**************************************************************************** +** Reset1401 +** +** Resets the 1401 and empties the i/o buffers +*****************************************************************************/ +int Reset1401(DEVICE_EXTENSION * pdx) +{ + mutex_lock(&pdx->io_mutex); // Protect disconnect from new i/o + dev_dbg(&pdx->interface->dev, "ABout to call QuickCheck"); + QuickCheck(pdx, true, true); // Check 1401, reset if not OK + mutex_unlock(&pdx->io_mutex); + return U14ERR_NOERROR; +} + +/**************************************************************************** +** GetChar +** +** Gets a single character from the 1401 +****************************************************************************/ +int GetChar(DEVICE_EXTENSION * pdx) +{ + int iReturn = U14ERR_NOIN; // assume we will get nothing + mutex_lock(&pdx->io_mutex); // Protect disconnect from new i/o + + dev_dbg(&pdx->interface->dev, "GetChar"); + + Allowi(pdx, false); // Make sure char reads are running + SendChars(pdx); // and send any buffered chars + + spin_lock_irq(&pdx->charInLock); + if (pdx->dwNumInput > 0) // worth looking + { + iReturn = pdx->inputBuffer[pdx->dwInBuffGet++]; + if (pdx->dwInBuffGet >= INBUF_SZ) + pdx->dwInBuffGet = 0; + pdx->dwNumInput--; + } else + iReturn = U14ERR_NOIN; // no input data to read + spin_unlock_irq(&pdx->charInLock); + + Allowi(pdx, false); // Make sure char reads are running + + mutex_unlock(&pdx->io_mutex); // Protect disconnect from new i/o + return iReturn; +} + +/**************************************************************************** +** GetString +** +** Gets a string from the 1401. Returns chars up to the next CR or when +** there are no more to read or nowhere to put them. CR is translated to +** 0 and counted as a character. If the string does not end in a 0, we will +** add one, if there is room, but it is not counted as a character. +** +** returns the count of characters (including the terminator, or 0 if none +** or a negative error code. +****************************************************************************/ +int GetString(DEVICE_EXTENSION * pdx, char __user * pUser, int n) +{ + int nAvailable; // character in the buffer + int iReturn = U14ERR_NOIN; + if (n <= 0) + return -ENOMEM; + + mutex_lock(&pdx->io_mutex); // Protect disconnect from new i/o + Allowi(pdx, false); // Make sure char reads are running + SendChars(pdx); // and send any buffered chars + + spin_lock_irq(&pdx->charInLock); + nAvailable = pdx->dwNumInput; // characters available now + if (nAvailable > n) // read max of space in pUser... + nAvailable = n; // ...or input characters + + if (nAvailable > 0) // worth looking? + { + char buffer[INBUF_SZ + 1]; // space for a linear copy of data + int nGot = 0; + int nCopyToUser; // number to copy to user + char cData; + do { + cData = pdx->inputBuffer[pdx->dwInBuffGet++]; + if (cData == CR_CHAR) // replace CR with zero + cData = (char)0; + + if (pdx->dwInBuffGet >= INBUF_SZ) + pdx->dwInBuffGet = 0; // wrap buffer pointer + + buffer[nGot++] = cData; // save the output + } + while ((nGot < nAvailable) && cData); + + nCopyToUser = nGot; // what to copy... + if (cData) // do we need null + { + buffer[nGot] = (char)0; // make it tidy + if (nGot < n) // if space in user buffer... + ++nCopyToUser; // ...copy the 0 as well. + } + + pdx->dwNumInput -= nGot; + spin_unlock_irq(&pdx->charInLock); + + dev_dbg(&pdx->interface->dev, + "GetString read %d characters >%s<", nGot, buffer); + if (copy_to_user(pUser, buffer, nCopyToUser)) + iReturn = -EFAULT; + else + iReturn = nGot; // report characters read + } else + spin_unlock_irq(&pdx->charInLock); + + Allowi(pdx, false); // Make sure char reads are running + mutex_unlock(&pdx->io_mutex); // Protect disconnect from new i/o + + return iReturn; +} + +/******************************************************************************* +** Get count of characters in the inout buffer. +*******************************************************************************/ +int Stat1401(DEVICE_EXTENSION * pdx) +{ + int iReturn; + mutex_lock(&pdx->io_mutex); // Protect disconnect from new i/o + Allowi(pdx, false); // make sure we allow pending chars + SendChars(pdx); // in both directions + iReturn = pdx->dwNumInput; // no lock as single read + mutex_unlock(&pdx->io_mutex); // Protect disconnect from new i/o + return iReturn; +} + +/**************************************************************************** +** LineCount +** +** Returns the number of newline chars in the buffer. There is no need for +** any fancy interlocks as we only read the interrupt routine data, and the +** system is arranged so nothing can be destroyed. +****************************************************************************/ +int LineCount(DEVICE_EXTENSION * pdx) +{ + int iReturn = 0; // will be count of line ends + + mutex_lock(&pdx->io_mutex); // Protect disconnect from new i/o + Allowi(pdx, false); // Make sure char reads are running + SendChars(pdx); // and send any buffered chars + spin_lock_irq(&pdx->charInLock); // Get protection + + if (pdx->dwNumInput > 0) // worth looking? + { + unsigned int dwIndex = pdx->dwInBuffGet; // start at first available + unsigned int dwEnd = pdx->dwInBuffPut; // Position for search end + do { + if (pdx->inputBuffer[dwIndex++] == CR_CHAR) + ++iReturn; // inc count if CR + + if (dwIndex >= INBUF_SZ) // see if we fall off buff + dwIndex = 0; + } + while (dwIndex != dwEnd); // go to last avaliable + } + + spin_unlock_irq(&pdx->charInLock); + dev_dbg(&pdx->interface->dev, "LineCount returned %d", iReturn); + mutex_unlock(&pdx->io_mutex); // Protect disconnect from new i/o + return iReturn; +} + +/**************************************************************************** +** GetOutBufSpace +** +** Gets the space in the output buffer. Called from user code. +*****************************************************************************/ +int GetOutBufSpace(DEVICE_EXTENSION * pdx) +{ + int iReturn; + mutex_lock(&pdx->io_mutex); // Protect disconnect from new i/o + SendChars(pdx); // send any buffered chars + iReturn = (int)(OUTBUF_SZ - pdx->dwNumOutput); // no lock needed for single read + dev_dbg(&pdx->interface->dev, "OutBufSpace %d", iReturn); + mutex_unlock(&pdx->io_mutex); // Protect disconnect from new i/o + return iReturn; +} + +/**************************************************************************** +** +** ClearArea +** +** Clears up a transfer area. This is always called in the context of a user +** request, never from a call-back. +****************************************************************************/ +int ClearArea(DEVICE_EXTENSION * pdx, int nArea) +{ + int iReturn = U14ERR_NOERROR; + + if ((nArea < 0) || (nArea >= MAX_TRANSAREAS)) { + iReturn = U14ERR_BADAREA; + dev_err(&pdx->interface->dev, "%s Attempt to clear area %d", + __func__, nArea); + } else { + TRANSAREA *pTA = &pdx->rTransDef[nArea]; // to save typing + if (!pTA->bUsed) // if not used... + iReturn = U14ERR_NOTSET; // ...nothing to be done + else { + // We must save the memory we return as we shouldn't mess with memory while + // holding a spin lock. + struct page **pPages = 0; // save page address list + int nPages = 0; // and number of pages + int np; + + dev_dbg(&pdx->interface->dev, "%s area %d", __func__, + nArea); + spin_lock_irq(&pdx->stagedLock); + if ((pdx->StagedId == nArea) + && (pdx->dwDMAFlag > MODE_CHAR)) { + iReturn = U14ERR_UNLOCKFAIL; // cannot delete as in use + dev_err(&pdx->interface->dev, + "%s call on area %d while active", + __func__, nArea); + } else { + pPages = pTA->pPages; // save page address list + nPages = pTA->nPages; // and page count + if (pTA->dwEventSz) // if events flagging in use + wake_up_interruptible(&pTA->wqEvent); // release anything that was waiting + + if (pdx->bXFerWaiting + && (pdx->rDMAInfo.wIdent == nArea)) + pdx->bXFerWaiting = false; // Cannot have pending xfer if area cleared + + // Clean out the TRANSAREA except for the wait queue, which is at the end + // This sets bUsed to false and dwEventSz to 0 to say area not used and no events. + memset(pTA, 0, + sizeof(TRANSAREA) - + sizeof(wait_queue_head_t)); + } + spin_unlock_irq(&pdx->stagedLock); + + if (pPages) // if we decided to release the memory + { + // Now we must undo the pinning down of the pages. We will assume the worst and mark + // all the pages as dirty. Don't be tempted to move this up above as you must not be + // holding a spin lock to do this stuff as it is not atomic. + dev_dbg(&pdx->interface->dev, "%s nPages=%d", + __func__, nPages); + + for (np = 0; np < nPages; ++np) { + if (pPages[np]) { + SetPageDirty(pPages[np]); + page_cache_release(pPages[np]); + } + } + + kfree(pPages); + dev_dbg(&pdx->interface->dev, + "%s kfree(pPages) done", __func__); + } + } + } + + return iReturn; +} + +/**************************************************************************** +** SetArea +** +** Sets up a transfer area - the functional part. Called by both +** SetTransfer and SetCircular. +****************************************************************************/ +static int SetArea(DEVICE_EXTENSION * pdx, int nArea, char __user * puBuf, + unsigned int dwLength, bool bCircular, bool bCircToHost) +{ + // Start by working out the page aligned start of the area and the size + // of the area in pages, allowing for the start not being aligned and the + // end needing to be rounded up to a page boundary. + unsigned long ulStart = ((unsigned long)puBuf) & PAGE_MASK; + unsigned int ulOffset = ((unsigned long)puBuf) & (PAGE_SIZE - 1); + int len = (dwLength + ulOffset + PAGE_SIZE - 1) >> PAGE_SHIFT; + + TRANSAREA *pTA = &pdx->rTransDef[nArea]; // to save typing + struct page **pPages = 0; // space for page tables + int nPages = 0; // and number of pages + + int iReturn = ClearArea(pdx, nArea); // see if OK to use this area + if ((iReturn != U14ERR_NOTSET) && // if not area unused and... + (iReturn != U14ERR_NOERROR)) // ...not all OK, then... + return iReturn; // ...we cannot use this area + + if (!access_ok(VERIFY_WRITE, puBuf, dwLength)) // if we cannot access the memory... + return -EFAULT; // ...then we are done + + // Now allocate space to hold the page pointer and virtual address pointer tables + pPages = + (struct page **)kmalloc(len * sizeof(struct page *), GFP_KERNEL); + if (!pPages) { + iReturn = U14ERR_NOMEMORY; + goto error; + } + dev_dbg(&pdx->interface->dev, "%s %p, length=%06x, circular %d", + __func__, puBuf, dwLength, bCircular); + + // To pin down user pages we must first acquire the mapping semaphore. + down_read(¤t->mm->mmap_sem); // get memory map semaphore + nPages = + get_user_pages(current, current->mm, ulStart, len, 1, 0, pPages, 0); + up_read(¤t->mm->mmap_sem); // release the semaphore + dev_dbg(&pdx->interface->dev, "%s nPages = %d", __func__, nPages); + + if (nPages > 0) // if we succeeded + { + // If you are tempted to use page_address (form LDD3), forget it. You MUST use + // kmap() or kmap_atomic() to get a virtual address. page_address will give you + // (null) or at least it does in this context with an x86 machine. + spin_lock_irq(&pdx->stagedLock); + pTA->lpvBuff = puBuf; // keep start of region (user address) + pTA->dwBaseOffset = ulOffset; // save offset in first page to start of xfer + pTA->dwLength = dwLength; // Size if the region in bytes + pTA->pPages = pPages; // list of pages that are used by buffer + pTA->nPages = nPages; // number of pages + + pTA->bCircular = bCircular; + pTA->bCircToHost = bCircToHost; + + pTA->aBlocks[0].dwOffset = 0; + pTA->aBlocks[0].dwSize = 0; + pTA->aBlocks[1].dwOffset = 0; + pTA->aBlocks[1].dwSize = 0; + pTA->bUsed = true; // This is now a used block + + spin_unlock_irq(&pdx->stagedLock); + iReturn = U14ERR_NOERROR; // say all was well + } else { + iReturn = U14ERR_LOCKFAIL; + goto error; + } + + return iReturn; + +error: + kfree(pPages); + return iReturn; +} + +/**************************************************************************** +** SetTransfer +** +** Sets up a transfer area record. If the area is already set, we attempt to +** unset it. Unsetting will fail if the area is booked, and a transfer to that +** area is in progress. Otherwise, we will release the area and re-assign it. +****************************************************************************/ +int SetTransfer(DEVICE_EXTENSION * pdx, TRANSFERDESC __user * pTD) +{ + int iReturn; + TRANSFERDESC td; + + if (copy_from_user(&td, pTD, sizeof(td))) + return -EFAULT; + + mutex_lock(&pdx->io_mutex); + dev_dbg(&pdx->interface->dev, "%s area:%d, size:%08x", __func__, + td.wAreaNum, td.dwLength); + // The strange cast is done so that we don't get warnings in 32-bit linux about the size of the + // pointer. The pointer is always passed as a 64-bit object so that we don't have problems using + // a 32-bit program on a 64-bit system. unsigned long is 64-bits on a 64-bit system. + iReturn = + SetArea(pdx, td.wAreaNum, + (char __user *)((unsigned long)td.lpvBuff), td.dwLength, + false, false); + mutex_unlock(&pdx->io_mutex); + return iReturn; +} + +/**************************************************************************** +** UnSetTransfer +** Erases a transfer area record +****************************************************************************/ +int UnsetTransfer(DEVICE_EXTENSION * pdx, int nArea) +{ + int iReturn; + mutex_lock(&pdx->io_mutex); + iReturn = ClearArea(pdx, nArea); + mutex_unlock(&pdx->io_mutex); + return iReturn; +} + +/**************************************************************************** +** SetEvent +** Creates an event that we can test for based on a transfer to/from an area. +** The area must be setup for a transfer. We attempt to simulate the Windows +** driver behavior for events (as we don't actually use them), which is to +** pretend that whatever the user asked for was achieved, so we return 1 if +** try to create one, and 0 if they ask to remove (assuming all else was OK). +****************************************************************************/ +int SetEvent(DEVICE_EXTENSION * pdx, TRANSFEREVENT __user * pTE) +{ + int iReturn = U14ERR_NOERROR; + TRANSFEREVENT te; + + // get a local copy of the data + if (copy_from_user(&te, pTE, sizeof(te))) + return -EFAULT; + + if (te.wAreaNum >= MAX_TRANSAREAS) // the area must exist + return U14ERR_BADAREA; + else { + TRANSAREA *pTA = &pdx->rTransDef[te.wAreaNum]; + mutex_lock(&pdx->io_mutex); // make sure we have no competitor + spin_lock_irq(&pdx->stagedLock); + if (pTA->bUsed) // area must be in use + { + pTA->dwEventSt = te.dwStart; // set area regions + pTA->dwEventSz = te.dwLength; // set size (0 cancels it) + pTA->bEventToHost = te.wFlags & 1; // set the direction + pTA->iWakeUp = 0; // zero the wake up count + } else + iReturn = U14ERR_NOTSET; + spin_unlock_irq(&pdx->stagedLock); + mutex_unlock(&pdx->io_mutex); + } + return iReturn == + U14ERR_NOERROR ? (te.iSetEvent ? 1 : U14ERR_NOERROR) : iReturn; +} + +/**************************************************************************** +** WaitEvent +** Sleep the process with a timeout waiting for an event. Returns the number +** of times that a block met the event condition since we last cleared it or +** 0 if timed out, or -ve error (bad area or not set, or signal). +****************************************************************************/ +int WaitEvent(DEVICE_EXTENSION * pdx, int nArea, int msTimeOut) +{ + int iReturn; + if ((unsigned)nArea >= MAX_TRANSAREAS) + return U14ERR_BADAREA; + else { + int iWait; + TRANSAREA *pTA = &pdx->rTransDef[nArea]; + msTimeOut = (msTimeOut * HZ + 999) / 1000; // convert timeout to jiffies + + // We cannot wait holding the mutex, but we check the flags while holding + // it. This may well be pointless as another thread could get in between + // releasing it and the wait call. However, this would have to clear the + // iWakeUp flag. However, the !pTA-bUsed may help us in this case. + mutex_lock(&pdx->io_mutex); // make sure we have no competitor + if (!pTA->bUsed || !pTA->dwEventSz) // check something to wait for... + return U14ERR_NOTSET; // ...else we do nothing + mutex_unlock(&pdx->io_mutex); + + if (msTimeOut) + iWait = + wait_event_interruptible_timeout(pTA->wqEvent, + pTA->iWakeUp + || !pTA->bUsed, + msTimeOut); + else + iWait = + wait_event_interruptible(pTA->wqEvent, pTA->iWakeUp + || !pTA->bUsed); + if (iWait) + iReturn = -ERESTARTSYS; // oops - we have had a SIGNAL + else + iReturn = pTA->iWakeUp; // else the wakeup count + + spin_lock_irq(&pdx->stagedLock); + pTA->iWakeUp = 0; // clear the flag + spin_unlock_irq(&pdx->stagedLock); + } + return iReturn; +} + +/**************************************************************************** +** TestEvent +** Test the event to see if a WaitEvent would return immediately. Returns the +** number of times a block completed since the last call, or 0 if none or a +** negative error. +****************************************************************************/ +int TestEvent(DEVICE_EXTENSION * pdx, int nArea) +{ + int iReturn; + if ((unsigned)nArea >= MAX_TRANSAREAS) + iReturn = U14ERR_BADAREA; + else { + TRANSAREA *pTA = &pdx->rTransDef[nArea]; + mutex_lock(&pdx->io_mutex); // make sure we have no competitor + spin_lock_irq(&pdx->stagedLock); + iReturn = pTA->iWakeUp; // get wakeup count since last call + pTA->iWakeUp = 0; // clear the count + spin_unlock_irq(&pdx->stagedLock); + mutex_unlock(&pdx->io_mutex); + } + return iReturn; +} + +/**************************************************************************** +** GetTransferInfo +** Puts the current state of the 1401 in a TGET_TX_BLOCK. +*****************************************************************************/ +int GetTransfer(DEVICE_EXTENSION * pdx, TGET_TX_BLOCK __user * pTX) +{ + int iReturn = U14ERR_NOERROR; + unsigned int dwIdent; + + mutex_lock(&pdx->io_mutex); + dwIdent = pdx->StagedId; // area ident for last xfer + if (dwIdent >= MAX_TRANSAREAS) + iReturn = U14ERR_BADAREA; + else { + // Return the best information we have - we don't have physical addresses + TGET_TX_BLOCK tx; + memset(&tx, 0, sizeof(tx)); // clean out local work structure + tx.size = pdx->rTransDef[dwIdent].dwLength; + tx.linear = (long long)((long)pdx->rTransDef[dwIdent].lpvBuff); + tx.avail = GET_TX_MAXENTRIES; // how many blocks we could return + tx.used = 1; // number we actually return + tx.entries[0].physical = + (long long)(tx.linear + pdx->StagedOffset); + tx.entries[0].size = tx.size; + + if (copy_to_user(pTX, &tx, sizeof(tx))) + iReturn = -EFAULT; + } + mutex_unlock(&pdx->io_mutex); + return iReturn; +} + +/**************************************************************************** +** KillIO1401 +** +** Empties the host i/o buffers +****************************************************************************/ +int KillIO1401(DEVICE_EXTENSION * pdx) +{ + dev_dbg(&pdx->interface->dev, "%s", __func__); + mutex_lock(&pdx->io_mutex); + FlushOutBuff(pdx); + FlushInBuff(pdx); + mutex_unlock(&pdx->io_mutex); + return U14ERR_NOERROR; +} + +/**************************************************************************** +** BlkTransState +** Returns a 0 or a 1 for whether DMA is happening. No point holding a mutex +** for this as it only does one read. +*****************************************************************************/ +int BlkTransState(DEVICE_EXTENSION * pdx) +{ + int iReturn = pdx->dwDMAFlag != MODE_CHAR; + dev_dbg(&pdx->interface->dev, "%s = %d", __func__, iReturn); + return iReturn; +} + +/**************************************************************************** +** StateOf1401 +** +** Puts the current state of the 1401 in the Irp return buffer. +*****************************************************************************/ +int StateOf1401(DEVICE_EXTENSION * pdx) +{ + int iReturn; + mutex_lock(&pdx->io_mutex); + + QuickCheck(pdx, false, false); // get state up to date, no reset + iReturn = pdx->sCurrentState; + + mutex_unlock(&pdx->io_mutex); + dev_dbg(&pdx->interface->dev, "%s = %d", __func__, iReturn); + + return iReturn; +} + +/**************************************************************************** +** StartSelfTest +** +** Initiates a self-test cycle. The assumption is that we have no interrupts +** active, so we should make sure that this is the case. +*****************************************************************************/ +int StartSelfTest(DEVICE_EXTENSION * pdx) +{ + int nGot; + mutex_lock(&pdx->io_mutex); + dev_dbg(&pdx->interface->dev, "%s", __func__); + + ced_draw_down(pdx); // wait for, then kill outstanding Urbs + FlushInBuff(pdx); // Clear out input buffer & pipe + FlushOutBuff(pdx); // Clear output buffer & pipe +// ReadWrite_Cancel(pDeviceObject); /* so things stay tidy */ + pdx->dwDMAFlag = MODE_CHAR; /* Clear DMA mode flags here */ + + nGot = usb_control_msg(pdx->udev, usb_rcvctrlpipe(pdx->udev, 0), DB_SELFTEST, (H_TO_D | VENDOR | DEVREQ), 0, 0, 0, 0, HZ); // allow 1 second timeout + pdx->ulSelfTestTime = jiffies + HZ * 30; // 30 seconds into the future + + mutex_unlock(&pdx->io_mutex); + if (nGot < 0) + dev_err(&pdx->interface->dev, "%s err=%d", __func__, nGot); + return nGot < 0 ? U14ERR_FAIL : U14ERR_NOERROR; +} + +/**************************************************************************** +** CheckSelfTest +** +** Check progress of a self-test cycle +****************************************************************************/ +int CheckSelfTest(DEVICE_EXTENSION * pdx, TGET_SELFTEST __user * pGST) +{ + unsigned int state, error; + int iReturn; + TGET_SELFTEST gst; // local work space + memset(&gst, 0, sizeof(gst)); // clear out the space (sets code 0) + + mutex_lock(&pdx->io_mutex); + + dev_dbg(&pdx->interface->dev, "%s", __func__); + iReturn = Get1401State(pdx, &state, &error); + if (iReturn == U14ERR_NOERROR) // Only accept zero if it happens twice + iReturn = Get1401State(pdx, &state, &error); + + if (iReturn != U14ERR_NOERROR) // Self-test can cause comms errors + { // so we assume still testing + dev_err(&pdx->interface->dev, + "%s Get1401State=%d, assuming still testing", __func__, + iReturn); + state = 0x80; // Force still-testing, no error + error = 0; + iReturn = U14ERR_NOERROR; + } + + if ((state == -1) && (error == -1)) // If Get1401State had problems + { + dev_err(&pdx->interface->dev, + "%s Get1401State failed, assuming still testing", + __func__); + state = 0x80; // Force still-testing, no error + error = 0; + } + + if ((state & 0xFF) == 0x80) // If we are still in self-test + { + if (state & 0x00FF0000) // Have we got an error? + { + gst.code = (state & 0x00FF0000) >> 16; // read the error code + gst.x = error & 0x0000FFFF; // Error data X + gst.y = (error & 0xFFFF0000) >> 16; // and data Y + dev_dbg(&pdx->interface->dev, "Self-test error code %d", + gst.code); + } else // No error, check for timeout + { + unsigned long ulNow = jiffies; // get current time + if (time_after(ulNow, pdx->ulSelfTestTime)) { + gst.code = -2; // Flag the timeout + dev_dbg(&pdx->interface->dev, + "Self-test timed-out"); + } else + dev_dbg(&pdx->interface->dev, + "Self-test on-going"); + } + } else { + gst.code = -1; // Flag the test is done + dev_dbg(&pdx->interface->dev, "Self-test done"); + } + + if (gst.code < 0) // If we have a problem or finished + { // If using the 2890 we should reset properly + if ((pdx->nPipes == 4) && (pdx->s1401Type <= TYPEPOWER)) + Is1401(pdx); // Get 1401 reset and OK + else + QuickCheck(pdx, true, true); // Otherwise check without reset unless problems + } + mutex_unlock(&pdx->io_mutex); + + if (copy_to_user(pGST, &gst, sizeof(gst))) + return -EFAULT; + + return iReturn; +} + +/**************************************************************************** +** TypeOf1401 +** +** Returns code for standard, plus, micro1401, power1401 or none +****************************************************************************/ +int TypeOf1401(DEVICE_EXTENSION * pdx) +{ + int iReturn = TYPEUNKNOWN; + mutex_lock(&pdx->io_mutex); + dev_dbg(&pdx->interface->dev, "%s", __func__); + + switch (pdx->s1401Type) { + case TYPE1401: + iReturn = U14ERR_STD; + break; // Handle these types directly + case TYPEPLUS: + iReturn = U14ERR_PLUS; + break; + case TYPEU1401: + iReturn = U14ERR_U1401; + break; + default: + if ((pdx->s1401Type >= TYPEPOWER) && (pdx->s1401Type <= 25)) + iReturn = pdx->s1401Type + 4; // We can calculate types + else // for up-coming 1401 designs + iReturn = TYPEUNKNOWN; // Don't know or not there + } + dev_dbg(&pdx->interface->dev, "%s %d", __func__, iReturn); + mutex_unlock(&pdx->io_mutex); + + return iReturn; +} + +/**************************************************************************** +** TransferFlags +** +** Returns flags on block transfer abilities +****************************************************************************/ +int TransferFlags(DEVICE_EXTENSION * pdx) +{ + int iReturn = U14TF_MULTIA | U14TF_DIAG | // we always have multiple DMA area + U14TF_NOTIFY | U14TF_CIRCTH; // diagnostics, notify and circular + dev_dbg(&pdx->interface->dev, "%s", __func__); + mutex_lock(&pdx->io_mutex); + if (pdx->bIsUSB2) // Set flag for USB2 if appropriate + iReturn |= U14TF_USB2; + mutex_unlock(&pdx->io_mutex); + + return iReturn; +} + +/*************************************************************************** +** DbgCmd1401 +** Issues a debug\diagnostic command to the 1401 along with a 32-bit datum +** This is a utility command used for dbg operations. +*/ +static int DbgCmd1401(DEVICE_EXTENSION * pdx, unsigned char cmd, + unsigned int data) +{ + int iReturn; + dev_dbg(&pdx->interface->dev, "%s entry", __func__); + iReturn = usb_control_msg(pdx->udev, usb_sndctrlpipe(pdx->udev, 0), cmd, (H_TO_D | VENDOR | DEVREQ), (unsigned short)data, (unsigned short)(data >> 16), 0, 0, HZ); // allow 1 second timeout + if (iReturn < 0) + dev_err(&pdx->interface->dev, "%s fail code=%d", __func__, + iReturn); + + return iReturn; +} + +/**************************************************************************** +** DbgPeek +** +** Execute the diagnostic peek operation. Uses address, width and repeats. +****************************************************************************/ +int DbgPeek(DEVICE_EXTENSION * pdx, TDBGBLOCK __user * pDB) +{ + int iReturn; + TDBGBLOCK db; + + if (copy_from_user(&db, pDB, sizeof(db))) + return -EFAULT; + + mutex_lock(&pdx->io_mutex); + dev_dbg(&pdx->interface->dev, "%s @ %08x", __func__, db.iAddr); + + iReturn = DbgCmd1401(pdx, DB_SETADD, db.iAddr); + if (iReturn == U14ERR_NOERROR) + iReturn = DbgCmd1401(pdx, DB_WIDTH, db.iWidth); + if (iReturn == U14ERR_NOERROR) + iReturn = DbgCmd1401(pdx, DB_REPEATS, db.iRepeats); + if (iReturn == U14ERR_NOERROR) + iReturn = DbgCmd1401(pdx, DB_PEEK, 0); + mutex_unlock(&pdx->io_mutex); + + return iReturn; +} + +/**************************************************************************** +** DbgPoke +** +** Execute the diagnostic poke operation. Parameters are in the CSBLOCK struct +** in order address, size, repeats and value to poke. +****************************************************************************/ +int DbgPoke(DEVICE_EXTENSION * pdx, TDBGBLOCK __user * pDB) +{ + int iReturn; + TDBGBLOCK db; + + if (copy_from_user(&db, pDB, sizeof(db))) + return -EFAULT; + + mutex_lock(&pdx->io_mutex); + dev_dbg(&pdx->interface->dev, "%s @ %08x", __func__, db.iAddr); + + iReturn = DbgCmd1401(pdx, DB_SETADD, db.iAddr); + if (iReturn == U14ERR_NOERROR) + iReturn = DbgCmd1401(pdx, DB_WIDTH, db.iWidth); + if (iReturn == U14ERR_NOERROR) + iReturn = DbgCmd1401(pdx, DB_REPEATS, db.iRepeats); + if (iReturn == U14ERR_NOERROR) + iReturn = DbgCmd1401(pdx, DB_POKE, db.iData); + mutex_unlock(&pdx->io_mutex); + + return iReturn; +} + +/**************************************************************************** +** DbgRampData +** +** Execute the diagnostic ramp data operation. Parameters are in the CSBLOCK struct +** in order address, default, enable mask, size and repeats. +****************************************************************************/ +int DbgRampData(DEVICE_EXTENSION * pdx, TDBGBLOCK __user * pDB) +{ + int iReturn; + TDBGBLOCK db; + + if (copy_from_user(&db, pDB, sizeof(db))) + return -EFAULT; + + mutex_lock(&pdx->io_mutex); + dev_dbg(&pdx->interface->dev, "%s @ %08x", __func__, db.iAddr); + + iReturn = DbgCmd1401(pdx, DB_SETADD, db.iAddr); + if (iReturn == U14ERR_NOERROR) + iReturn = DbgCmd1401(pdx, DB_SETDEF, db.iDefault); + if (iReturn == U14ERR_NOERROR) + iReturn = DbgCmd1401(pdx, DB_SETMASK, db.iMask); + if (iReturn == U14ERR_NOERROR) + iReturn = DbgCmd1401(pdx, DB_WIDTH, db.iWidth); + if (iReturn == U14ERR_NOERROR) + iReturn = DbgCmd1401(pdx, DB_REPEATS, db.iRepeats); + if (iReturn == U14ERR_NOERROR) + iReturn = DbgCmd1401(pdx, DB_RAMPD, 0); + mutex_unlock(&pdx->io_mutex); + + return iReturn; +} + +/**************************************************************************** +** DbgRampAddr +** +** Execute the diagnostic ramp address operation +****************************************************************************/ +int DbgRampAddr(DEVICE_EXTENSION * pdx, TDBGBLOCK __user * pDB) +{ + int iReturn; + TDBGBLOCK db; + + if (copy_from_user(&db, pDB, sizeof(db))) + return -EFAULT; + + mutex_lock(&pdx->io_mutex); + dev_dbg(&pdx->interface->dev, "%s", __func__); + + iReturn = DbgCmd1401(pdx, DB_SETDEF, db.iDefault); + if (iReturn == U14ERR_NOERROR) + iReturn = DbgCmd1401(pdx, DB_SETMASK, db.iMask); + if (iReturn == U14ERR_NOERROR) + iReturn = DbgCmd1401(pdx, DB_WIDTH, db.iWidth); + if (iReturn == U14ERR_NOERROR) + iReturn = DbgCmd1401(pdx, DB_REPEATS, db.iRepeats); + if (iReturn == U14ERR_NOERROR) + iReturn = DbgCmd1401(pdx, DB_RAMPA, 0); + mutex_unlock(&pdx->io_mutex); + + return iReturn; +} + +/**************************************************************************** +** DbgGetData +** +** Retrieve the data resulting from the last debug Peek operation +****************************************************************************/ +int DbgGetData(DEVICE_EXTENSION * pdx, TDBGBLOCK __user * pDB) +{ + int iReturn; + TDBGBLOCK db; + memset(&db, 0, sizeof(db)); // fill returned block with 0s + + mutex_lock(&pdx->io_mutex); + dev_dbg(&pdx->interface->dev, "%s", __func__); + + // Read back the last peeked value from the 1401. + iReturn = usb_control_msg(pdx->udev, usb_rcvctrlpipe(pdx->udev, 0), + DB_DATA, (D_TO_H | VENDOR | DEVREQ), 0, 0, + &db.iData, sizeof(db.iData), HZ); + if (iReturn == sizeof(db.iData)) { + if (copy_to_user(pDB, &db, sizeof(db))) + iReturn = -EFAULT; + else + iReturn = U14ERR_NOERROR; + } else + dev_err(&pdx->interface->dev, "%s failed, code %d", __func__, + iReturn); + + mutex_unlock(&pdx->io_mutex); + + return iReturn; +} + +/**************************************************************************** +** DbgStopLoop +** +** Stop any never-ending debug loop, we just call Get1401State for USB +** +****************************************************************************/ +int DbgStopLoop(DEVICE_EXTENSION * pdx) +{ + int iReturn; + unsigned int uState, uErr; + + mutex_lock(&pdx->io_mutex); + dev_dbg(&pdx->interface->dev, "%s", __func__); + iReturn = Get1401State(pdx, &uState, &uErr); + mutex_unlock(&pdx->io_mutex); + + return iReturn; +} + +/**************************************************************************** +** SetCircular +** +** Sets up a transfer area record for circular transfers. If the area is +** already set, we attempt to unset it. Unsetting will fail if the area is +** booked and a transfer to that area is in progress. Otherwise, we will +** release the area and re-assign it. +****************************************************************************/ +int SetCircular(DEVICE_EXTENSION * pdx, TRANSFERDESC __user * pTD) +{ + int iReturn; + bool bToHost; + TRANSFERDESC td; + + if (copy_from_user(&td, pTD, sizeof(td))) + return -EFAULT; + + mutex_lock(&pdx->io_mutex); + dev_dbg(&pdx->interface->dev, "%s area:%d, size:%08x", __func__, + td.wAreaNum, td.dwLength); + bToHost = td.eSize != 0; // this is used as the tohost flag + + // The strange cast is done so that we don't get warnings in 32-bit linux about the size of the + // pointer. The pointer is always passed as a 64-bit object so that we don't have problems using + // a 32-bit program on a 64-bit system. unsigned long is 64-bits on a 64-bit system. + iReturn = + SetArea(pdx, td.wAreaNum, + (char __user *)((unsigned long)td.lpvBuff), td.dwLength, + true, bToHost); + mutex_unlock(&pdx->io_mutex); + return iReturn; +} + +/**************************************************************************** +** GetCircBlock +** +** Return the next available block of circularly-transferred data. +****************************************************************************/ +int GetCircBlock(DEVICE_EXTENSION * pdx, TCIRCBLOCK __user * pCB) +{ + int iReturn = U14ERR_NOERROR; + unsigned int nArea; + TCIRCBLOCK cb; + + dev_dbg(&pdx->interface->dev, "%s", __func__); + + if (copy_from_user(&cb, pCB, sizeof(cb))) + return -EFAULT; + + mutex_lock(&pdx->io_mutex); + + nArea = cb.nArea; // Retrieve parameters first + cb.dwOffset = 0; // set default result (nothing) + cb.dwSize = 0; + + if (nArea < MAX_TRANSAREAS) // The area number must be OK + { + TRANSAREA *pArea = &pdx->rTransDef[nArea]; // Pointer to relevant info + spin_lock_irq(&pdx->stagedLock); // Lock others out + + if ((pArea->bUsed) && (pArea->bCircular) && // Must be circular area + (pArea->bCircToHost)) // For now at least must be to host + { + if (pArea->aBlocks[0].dwSize > 0) // Got anything? + { + cb.dwOffset = pArea->aBlocks[0].dwOffset; + cb.dwSize = pArea->aBlocks[0].dwSize; + dev_dbg(&pdx->interface->dev, + "%s return block 0: %d bytes at %d", + __func__, cb.dwSize, cb.dwOffset); + } + } else + iReturn = U14ERR_NOTSET; + + spin_unlock_irq(&pdx->stagedLock); + } else + iReturn = U14ERR_BADAREA; + + if (copy_to_user(pCB, &cb, sizeof(cb))) + iReturn = -EFAULT; + + mutex_unlock(&pdx->io_mutex); + return iReturn; +} + +/**************************************************************************** +** FreeCircBlock +** +** Frees a block of circularly-transferred data and returns the next one. +****************************************************************************/ +int FreeCircBlock(DEVICE_EXTENSION * pdx, TCIRCBLOCK __user * pCB) +{ + int iReturn = U14ERR_NOERROR; + unsigned int nArea, uStart, uSize; + TCIRCBLOCK cb; + + dev_dbg(&pdx->interface->dev, "%s", __func__); + + if (copy_from_user(&cb, pCB, sizeof(cb))) + return -EFAULT; + + mutex_lock(&pdx->io_mutex); + + nArea = cb.nArea; // Retrieve parameters first + uStart = cb.dwOffset; + uSize = cb.dwSize; + cb.dwOffset = 0; // then set default result (nothing) + cb.dwSize = 0; + + if (nArea < MAX_TRANSAREAS) // The area number must be OK + { + TRANSAREA *pArea = &pdx->rTransDef[nArea]; // Pointer to relevant info + spin_lock_irq(&pdx->stagedLock); // Lock others out + + if ((pArea->bUsed) && (pArea->bCircular) && // Must be circular area + (pArea->bCircToHost)) // For now at least must be to host + { + bool bWaiting = false; + + if ((pArea->aBlocks[0].dwSize >= uSize) && // Got anything? + (pArea->aBlocks[0].dwOffset == uStart)) // Must be legal data + { + pArea->aBlocks[0].dwSize -= uSize; + pArea->aBlocks[0].dwOffset += uSize; + if (pArea->aBlocks[0].dwSize == 0) // Have we emptied this block? + { + if (pArea->aBlocks[1].dwSize) // Is there a second block? + { + pArea->aBlocks[0] = pArea->aBlocks[1]; // Copy down block 2 data + pArea->aBlocks[1].dwSize = 0; // and mark the second block as unused + pArea->aBlocks[1].dwOffset = 0; + } else + pArea->aBlocks[0].dwOffset = 0; + } + + dev_dbg(&pdx->interface->dev, + "%s free %d bytes at %d, return %d bytes at %d, wait=%d", + __func__, uSize, uStart, + pArea->aBlocks[0].dwSize, + pArea->aBlocks[0].dwOffset, + pdx->bXFerWaiting); + + // Return the next available block of memory as well + if (pArea->aBlocks[0].dwSize > 0) // Got anything? + { + cb.dwOffset = + pArea->aBlocks[0].dwOffset; + cb.dwSize = pArea->aBlocks[0].dwSize; + } + + bWaiting = pdx->bXFerWaiting; + if (bWaiting && pdx->bStagedUrbPending) { + dev_err(&pdx->interface->dev, + "%s ERROR: waiting xfer and staged Urb pending!", + __func__); + bWaiting = false; + } + } else { + dev_err(&pdx->interface->dev, + "%s ERROR: freeing %d bytes at %d, block 0 is %d bytes at %d", + __func__, uSize, uStart, + pArea->aBlocks[0].dwSize, + pArea->aBlocks[0].dwOffset); + iReturn = U14ERR_NOMEMORY; + } + + // If we have one, kick off pending transfer + if (bWaiting) // Got a block xfer waiting? + { + int RWMStat = + ReadWriteMem(pdx, !pdx->rDMAInfo.bOutWard, + pdx->rDMAInfo.wIdent, + pdx->rDMAInfo.dwOffset, + pdx->rDMAInfo.dwSize); + if (RWMStat != U14ERR_NOERROR) + dev_err(&pdx->interface->dev, + "%s rw setup failed %d", + __func__, RWMStat); + } + } else + iReturn = U14ERR_NOTSET; + + spin_unlock_irq(&pdx->stagedLock); + } else + iReturn = U14ERR_BADAREA; + + if (copy_to_user(pCB, &cb, sizeof(cb))) + return -EFAULT; + + mutex_unlock(&pdx->io_mutex); + return iReturn; +} diff --git a/drivers/staging/ced1401/ced_ioctl.h b/drivers/staging/ced1401/ced_ioctl.h new file mode 100644 index 000000000000..0895c9414b4f --- /dev/null +++ b/drivers/staging/ced1401/ced_ioctl.h @@ -0,0 +1,345 @@ +/* + * IOCTL calls for the CED1401 driver + * Copyright (C) 2010 Cambridge Electronic Design Ltd + * Author Greg P Smith (greg@ced.co.uk) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#ifndef __CED_IOCTL_H__ +#define __CED_IOCTL_H__ + +#include <linux/ioctl.h> + +/* dma modes, only MODE_CHAR and MODE_LINEAR are used in this driver */ +#define MODE_CHAR 0 +#define MODE_LINEAR 1 + +/**************************************************************************** +** TypeDefs +*****************************************************************************/ + +typedef unsigned short TBLOCKENTRY; /* index the blk transfer table 0-7 */ + +typedef struct TransferDesc { + long long lpvBuff; /* address of transfer area (for 64 or 32 bit) */ + unsigned int dwLength; /* length of the area */ + TBLOCKENTRY wAreaNum; /* number of transfer area to set up */ + short eSize; /* element size - is tohost flag for circular */ +} TRANSFERDESC; + +typedef TRANSFERDESC * LPTRANSFERDESC; + +typedef struct TransferEvent { + unsigned int dwStart; /* offset into the area */ + unsigned int dwLength; /* length of the region */ + unsigned short wAreaNum; /* the area number */ + unsigned short wFlags; /* bit 0 set for toHost */ + int iSetEvent; /* could be dummy in LINUX */ +} TRANSFEREVENT; + +#define MAX_TRANSFER_SIZE 0x4000 /* Maximum data bytes per IRP */ +#define MAX_AREA_LENGTH 0x100000 /* Maximum size of transfer area */ +#define MAX_TRANSAREAS 8 /* definitions for dma set up */ + +typedef struct TGetSelfTest { + int code; /* self-test error code */ + int x, y; /* additional information */ +} TGET_SELFTEST; + +/* Debug block used for several commands. Not all fields are used for all commands. */ +typedef struct TDbgBlock { + int iAddr; /* the address in the 1401 */ + int iRepeats; /* number of repeats */ + int iWidth; /* width in bytes 1, 2, 4 */ + int iDefault; /* default value */ + int iMask; /* mask to apply */ + int iData; /* data for poke, result for peek */ +} TDBGBLOCK; + +/* Used to collect information about a circular block from the device driver */ +typedef struct TCircBlock { + unsigned int nArea; /* the area to collect information from */ + unsigned int dwOffset; /* offset into the area to the available block */ + unsigned int dwSize; /* size of the area */ +} TCIRCBLOCK; + +/* Used to clollect the 1401 status */ +typedef struct TCSBlock { + unsigned int uiState; + unsigned int uiError; +} TCSBLOCK; + +/* + * As seen by the user, an ioctl call looks like: int ioctl(int fd, unsigned + * long cmd, char* argp); We will then have all sorts of variants on this that + * can be used to pass stuff to our driver. We will generate macros for each + * type of call so as to provide some sort of type safety in the calling: + */ +#define CED_MAGIC_IOC 0xce + +/* NBNB: READ and WRITE are from the point of view of the device, not user. */ +typedef struct ced_ioc_string { + int nChars; + char buffer[256]; +} CED_IOC_STRING; + +#define IOCTL_CED_SENDSTRING(n) _IOC(_IOC_WRITE, CED_MAGIC_IOC, 2, n) + +#define IOCTL_CED_RESET1401 _IO(CED_MAGIC_IOC, 3) +#define IOCTL_CED_GETCHAR _IO(CED_MAGIC_IOC, 4) +#define IOCTL_CED_SENDCHAR _IO(CED_MAGIC_IOC, 5) +#define IOCTL_CED_STAT1401 _IO(CED_MAGIC_IOC, 6) +#define IOCTL_CED_LINECOUNT _IO(CED_MAGIC_IOC, 7) +#define IOCTL_CED_GETSTRING(nMax) _IOC(_IOC_READ, CED_MAGIC_IOC, 8, nMax) + +#define IOCTL_CED_SETTRANSFER _IOW(CED_MAGIC_IOC, 11, TRANSFERDESC) +#define IOCTL_CED_UNSETTRANSFER _IO(CED_MAGIC_IOC, 12) +#define IOCTL_CED_SETEVENT _IOW(CED_MAGIC_IOC, 13, TRANSFEREVENT) +#define IOCTL_CED_GETOUTBUFSPACE _IO(CED_MAGIC_IOC, 14) +#define IOCTL_CED_GETBASEADDRESS _IO(CED_MAGIC_IOC, 15) +#define IOCTL_CED_GETDRIVERREVISION _IO(CED_MAGIC_IOC, 16) + +#define IOCTL_CED_GETTRANSFER _IOR(CED_MAGIC_IOC, 17, TGET_TX_BLOCK) +#define IOCTL_CED_KILLIO1401 _IO(CED_MAGIC_IOC, 18) +#define IOCTL_CED_BLKTRANSSTATE _IO(CED_MAGIC_IOC, 19) + +#define IOCTL_CED_STATEOF1401 _IO(CED_MAGIC_IOC, 23) +#define IOCTL_CED_GRAB1401 _IO(CED_MAGIC_IOC, 25) +#define IOCTL_CED_FREE1401 _IO(CED_MAGIC_IOC, 26) +#define IOCTL_CED_STARTSELFTEST _IO(CED_MAGIC_IOC, 31) +#define IOCTL_CED_CHECKSELFTEST _IOR(CED_MAGIC_IOC, 32, TGET_SELFTEST) +#define IOCTL_CED_TYPEOF1401 _IO(CED_MAGIC_IOC, 33) +#define IOCTL_CED_TRANSFERFLAGS _IO(CED_MAGIC_IOC, 34) + +#define IOCTL_CED_DBGPEEK _IOW(CED_MAGIC_IOC, 35, TDBGBLOCK) +#define IOCTL_CED_DBGPOKE _IOW(CED_MAGIC_IOC, 36, TDBGBLOCK) +#define IOCTL_CED_DBGRAMPDATA _IOW(CED_MAGIC_IOC, 37, TDBGBLOCK) +#define IOCTL_CED_DBGRAMPADDR _IOW(CED_MAGIC_IOC, 38, TDBGBLOCK) +#define IOCTL_CED_DBGGETDATA _IOR(CED_MAGIC_IOC, 39, TDBGBLOCK) +#define IOCTL_CED_DBGSTOPLOOP _IO(CED_MAGIC_IOC, 40) +#define IOCTL_CED_FULLRESET _IO(CED_MAGIC_IOC, 41) +#define IOCTL_CED_SETCIRCULAR _IOW(CED_MAGIC_IOC, 42, TRANSFERDESC) +#define IOCTL_CED_GETCIRCBLOCK _IOWR(CED_MAGIC_IOC, 43, TCIRCBLOCK) +#define IOCTL_CED_FREECIRCBLOCK _IOWR(CED_MAGIC_IOC, 44, TCIRCBLOCK) +#define IOCTL_CED_WAITEVENT _IO(CED_MAGIC_IOC, 45) +#define IOCTL_CED_TESTEVENT _IO(CED_MAGIC_IOC, 46) + +#ifndef __KERNEL__ +/* + * If nothing said about return value, it is a U14ERR_... error code + * (U14ERR_NOERROR for none) + */ +inline int CED_SendString(int fh, const char *szText, int n) +{ + return ioctl(fh, IOCTL_CED_SENDSTRING(n), szText); +} + +inline int CED_Reset1401(int fh) +{ + return ioctl(fh, IOCTL_CED_RESET1401); +} + +/* Return the singe character or a -ve error code. */ +inline int CED_GetChar(int fh) +{ + return ioctl(fh, IOCTL_CED_GETCHAR); +} + +/* Return character count in input buffer */ +inline int CED_Stat1401(int fh) +{ + return ioctl(fh, IOCTL_CED_STAT1401); +} + +inline int CED_SendChar(int fh, char c) +{ + return ioctl(fh, IOCTL_CED_SENDCHAR, c); +} + +inline int CED_LineCount(int fh) +{ + return ioctl(fh, IOCTL_CED_LINECOUNT); +} + +/* + * return the count of characters returned. If the string was terminated by CR + * or 0, then the 0 is part of the count. Otherwise, we will add a zero if + * there is room, but it is not included in the count. The return value is 0 + * if there was nothing to read. + */ +inline int CED_GetString(int fh, char *szText, int nMax) +{ + return ioctl(fh, IOCTL_CED_GETSTRING(nMax), szText); +} + +/* returns space in the output buffer. */ +inline int CED_GetOutBufSpace(int fh) +{ + return ioctl(fh, IOCTL_CED_GETOUTBUFSPACE); +} + +/* This always returns -1 as not implemented. */ +inline int CED_GetBaseAddress(int fh) +{ + return ioctl(fh, IOCTL_CED_GETBASEADDRESS); +} + +/* returns the major revision <<16 | minor revision. */ +inline int CED_GetDriverRevision(int fh) +{ + return ioctl(fh, IOCTL_CED_GETDRIVERREVISION); +} + +inline int CED_SetTransfer(int fh, TRANSFERDESC *pTD) +{ + return ioctl(fh, IOCTL_CED_SETTRANSFER, pTD); +} + +inline int CED_UnsetTransfer(int fh, int nArea) +{ + return ioctl(fh, IOCTL_CED_UNSETTRANSFER, nArea); +} + +inline int CED_SetEvent(int fh, TRANSFEREVENT *pTE) +{ + return ioctl(fh, IOCTL_CED_SETEVENT, pTE); +} + +inline int CED_GetTransfer(int fh, TGET_TX_BLOCK *pTX) +{ + return ioctl(fh, IOCTL_CED_GETTRANSFER, pTX); +} + +inline int CED_KillIO1401(int fh) +{ + return ioctl(fh, IOCTL_CED_KILLIO1401); +} + +/* returns 0 if no active DMA, 1 if active */ +inline int CED_BlkTransState(int fh) +{ + return ioctl(fh, IOCTL_CED_BLKTRANSSTATE); +} + +inline int CED_StateOf1401(int fh) +{ + return ioctl(fh, IOCTL_CED_STATEOF1401); +} + +inline int CED_Grab1401(int fh) +{ + return ioctl(fh, IOCTL_CED_GRAB1401); +} + +inline int CED_Free1401(int fh) +{ + return ioctl(fh, IOCTL_CED_FREE1401); +} + +inline int CED_StartSelfTest(int fh) +{ + return ioctl(fh, IOCTL_CED_STARTSELFTEST); +} + +inline int CED_CheckSelfTest(int fh, TGET_SELFTEST *pGST) +{ + return ioctl(fh, IOCTL_CED_CHECKSELFTEST, pGST); +} + +inline int CED_TypeOf1401(int fh) +{ + return ioctl(fh, IOCTL_CED_TYPEOF1401); +} + +inline int CED_TransferFlags(int fh) +{ + return ioctl(fh, IOCTL_CED_TRANSFERFLAGS); +} + +inline int CED_DbgPeek(int fh, TDBGBLOCK *pDB) +{ + return ioctl(fh, IOCTL_CED_DBGPEEK, pDB); +} + +inline int CED_DbgPoke(int fh, TDBGBLOCK *pDB) +{ + return ioctl(fh, IOCTL_CED_DBGPOKE, pDB); +} + +inline int CED_DbgRampData(int fh, TDBGBLOCK *pDB) +{ + return ioctl(fh, IOCTL_CED_DBGRAMPDATA, pDB); +} + +inline int CED_DbgRampAddr(int fh, TDBGBLOCK *pDB) +{ + return ioctl(fh, IOCTL_CED_DBGRAMPADDR, pDB); +} + +inline int CED_DbgGetData(int fh, TDBGBLOCK *pDB) +{ + return ioctl(fh, IOCTL_CED_DBGGETDATA, pDB); +} + +inline int CED_DbgStopLoop(int fh) +{ + return ioctl(fh, IOCTL_CED_DBGSTOPLOOP); +} + +inline int CED_FullReset(int fh) +{ + return ioctl(fh, IOCTL_CED_FULLRESET); +} + +inline int CED_SetCircular(int fh, TRANSFERDESC *pTD) +{ + return ioctl(fh, IOCTL_CED_SETCIRCULAR, pTD); +} + +inline int CED_GetCircBlock(int fh, TCIRCBLOCK *pCB) +{ + return ioctl(fh, IOCTL_CED_GETCIRCBLOCK, pCB); +} + +inline int CED_FreeCircBlock(int fh, TCIRCBLOCK *pCB) +{ + return ioctl(fh, IOCTL_CED_FREECIRCBLOCK, pCB); +} + +inline int CED_WaitEvent(int fh, int nArea, int msTimeOut) +{ + return ioctl(fh, IOCTL_CED_WAITEVENT, (nArea & 0xff)|(msTimeOut << 8)); +} + +inline int CED_TestEvent(int fh, int nArea) +{ + return ioctl(fh, IOCTL_CED_TESTEVENT, nArea); +} +#endif + +#ifdef NOTWANTEDYET +#define IOCTL_CED_REGCALLBACK _IO(CED_MAGIC_IOC, 9) /* Not used */ +#define IOCTL_CED_GETMONITORBUF _IO(CED_MAGIC_IOC, 10) /* Not used */ + +#define IOCTL_CED_BYTECOUNT _IO(CED_MAGIC_IOC, 20) /* Not used */ +#define IOCTL_CED_ZEROBLOCKCOUNT _IO(CED_MAGIC_IOC, 21) /* Not used */ +#define IOCTL_CED_STOPCIRCULAR _IO(CED_MAGIC_IOC, 22) /* Not used */ + +#define IOCTL_CED_REGISTERS1401 _IO(CED_MAGIC_IOC, 24) /* Not used */ +#define IOCTL_CED_STEP1401 _IO(CED_MAGIC_IOC, 27) /* Not used */ +#define IOCTL_CED_SET1401REGISTERS _IO(CED_MAGIC_IOC, 28) /* Not used */ +#define IOCTL_CED_STEPTILL1401 _IO(CED_MAGIC_IOC, 29) /* Not used */ +#define IOCTL_CED_SETORIN _IO(CED_MAGIC_IOC, 30) /* Not used */ + +#endif + +/* __CED_IOCTL_H__ */ +#endif diff --git a/drivers/staging/ced1401/machine.h b/drivers/staging/ced1401/machine.h new file mode 100644 index 000000000000..af073790b942 --- /dev/null +++ b/drivers/staging/ced1401/machine.h @@ -0,0 +1,127 @@ +/***************************************************************************** +** +** machine.h +** +** Copyright (c) Cambridge Electronic Design Limited 1991,1992,2010 +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +** +** Contact CED: Cambridge Electronic Design Limited, Science Park, Milton Road +** Cambridge, CB6 0FE. +** www.ced.co.uk +** greg@ced.co.uk +** +** This file is included at the start of 'C' or 'C++' source file to define +** things for cross-platform/compiler interoperability. This used to deal with +** MSDOS/16-bit stuff, but this was all removed in Decemeber 2010. There are +** three things to consider: Windows, LINUX, mac OSX (BSD Unix) and 32 vs 64 +** bit. At the time of writing (DEC 2010) there is a consensus on the following +** and their unsigned equivalents: +** +** type bits +** char 8 +** short 16 +** int 32 +** long long 64 +** +** long is a problem as it is always 64 bits on linux/unix and is always 32 bits +** on windows. +** On windows, we define _IS_WINDOWS_ and one of WIN32 or WIN64. +** On linux we define LINUX +** On Max OSX we define MACOSX +** +*/ + +#ifndef __MACHINE_H__ +#define __MACHINE_H__ +#ifndef __KERNEL__ +#include <float.h> +#include <limits.h> +#endif + +/* +** The initial section is to identify the operating system +*/ +#if (defined(__linux__) || defined(_linux) || defined(__linux)) && !defined(LINUX) +#define LINUX 1 +#endif + +#if (defined(__WIN32__) || defined(_WIN32)) && !defined(WIN32) +#define WIN32 1 +#endif + +#if defined(__APPLE__) +#define MACOSX +#endif + +#if defined(_WIN64) +#undef WIN32 +#undef WIN64 +#define WIN64 1 +#endif + +#if defined(WIN32) || defined(WIN64) +#define _IS_WINDOWS_ 1 +#endif + +#if defined(LINUX) || defined(MAXOSX) + #define FAR + + typedef int BOOL; // To match Windows + typedef char * LPSTR; + typedef const char * LPCSTR; + typedef unsigned short WORD; + typedef unsigned int DWORD; + typedef unsigned char BYTE; + typedef BYTE BOOLEAN; + typedef unsigned char UCHAR; + #define __packed __attribute__((packed)) + typedef BYTE * LPBYTE; + #define HIWORD(x) (WORD)(((x)>>16) & 0xffff) + #define LOWORD(x) (WORD)((x) & 0xffff) +#endif + +#ifdef _IS_WINDOWS_ +#include <windows.h> +#define __packed +#endif + +/* +** Sort out the DllExport and DllImport macros. The GCC compiler has its own +** syntax for this, though it also supports the MS specific __declspec() as +** a synonym. +*/ +#ifdef GNUC + #define DllExport __attribute__((dllexport)) + #define DllImport __attribute__((dllimport)) +#endif + +#ifndef DllExport +#ifdef _IS_WINDOWS_ + #define DllExport __declspec(dllexport) + #define DllImport __declspec(dllimport) +#else + #define DllExport + #define DllImport +#endif +#endif /* _IS_WINDOWS_ */ + + +#ifndef TRUE + #define TRUE 1 + #define FALSE 0 +#endif + +#endif diff --git a/drivers/staging/ced1401/usb1401.c b/drivers/staging/ced1401/usb1401.c new file mode 100644 index 000000000000..6ba0ef652561 --- /dev/null +++ b/drivers/staging/ced1401/usb1401.c @@ -0,0 +1,1637 @@ +/*********************************************************************************** + CED1401 usb driver. This basic loading is based on the usb-skeleton.c code that is: + Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com) + Copyright (C) 2012 Alois Schloegl <alois.schloegl@ist.ac.at> + There is not a great deal of the skeleton left. + + All the remainder dealing specifically with the CED1401 is based on drivers written + by CED for other systems (mainly Windows) and is: + Copyright (C) 2010 Cambridge Electronic Design Ltd + Author Greg P Smith (greg@ced.co.uk) + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +Endpoints +********* +There are 4 endpoints plus the control endpoint in the standard interface +provided by most 1401s. The control endpoint is used for standard USB requests, +plus various CED-specific transactions such as start self test, debug and get +the 1401 status. The other endpoints are: + + 1 Characters to the 1401 + 2 Characters from the 1401 + 3 Block data to the 1401 + 4 Block data to the host. + +inside the driver these are indexed as an array from 0 to 3, transactions +over the control endpoint are carried out using a separate mechanism. The +use of the endpoints is mostly straightforward, with the driver issuing +IO request packets (IRPs) as required to transfer data to and from the 1401. +The handling of endpoint 2 is different because it is used for characters +from the 1401, which can appear spontaneously and without any other driver +activity - for example to repeatedly request DMA transfers in Spike2. The +desired effect is achieved by using an interrupt endpoint which can be +polled to see if it has data available, and writing the driver so that it +always maintains a pending read IRP from that endpoint which will read the +character data and terminate as soon as the 1401 makes data available. This +works very well, some care is taken with when you kick off this character +read IRP to avoid it being active when it is not wanted but generally it +is running all the time. + +In the 2270, there are only three endpoints plus the control endpoint. In +addition to the transactions mentioned above, the control endpoint is used +to transfer character data to the 1401. The other endpoints are used as: + + 1 Characters from the 1401 + 2 Block data to the 1401 + 3 Block data to the host. + +The type of interface available is specified by the interface subclass field +in the interface descriptor provided by the 1401. See the USB_INT_ constants +for the values that this field can hold. + +**************************************************************************** +Linux implementation + +Although Linux Device Drivers (3rd Edition) was a major source of information, +it is very out of date. A lot of information was gleaned from the latest +usb_skeleton.c code (you need to download the kernel sources to get this). + +To match the Windows version, everything is done using ioctl calls. All the +device state is held in the DEVICE_EXTENSION (named to match Windows use). +Block transfers are done by using get_user_pages() to pin down a list of +pages that we hold a pointer to in the device driver. We also allocate a +coherent transfer buffer of size STAGED_SZ (this must be a multiple of the +bulk endpoint size so that the 1401 does not realise that we break large +transfers down into smaller pieces). We use kmap_atomic() to get a kernel +va for each page, as it is required, for copying; see CopyUserSpace(). + +All character and data transfers are done using asynchronous IO. All Urbs are +tracked by anchoring them. Status and debug ioctls are implemented with the +synchronous non-Urb based transfers. +*/ + +#include <linux/kernel.h> +#include <linux/errno.h> +#include <linux/usb.h> +#include <linux/mutex.h> +#include <linux/mm.h> +#include <linux/highmem.h> +#include <linux/version.h> +#if ( LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35) ) +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/module.h> +#include <linux/kref.h> +#include <linux/uaccess.h> +#endif + +#include "usb1401.h" + +/* Define these values to match your devices */ +#define USB_CED_VENDOR_ID 0x0525 +#define USB_CED_PRODUCT_ID 0xa0f0 + +/* table of devices that work with this driver */ +static const struct usb_device_id ced_table[] = { + {USB_DEVICE(USB_CED_VENDOR_ID, USB_CED_PRODUCT_ID)}, + {} /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(usb, ced_table); + +/* Get a minor range for your devices from the usb maintainer */ +#define USB_CED_MINOR_BASE 192 + +/* our private defines. if this grows any larger, use your own .h file */ +#define MAX_TRANSFER (PAGE_SIZE - 512) +/* MAX_TRANSFER is chosen so that the VM is not stressed by + allocations > PAGE_SIZE and the number of packets in a page + is an integer 512 is the largest possible packet on EHCI */ +#define WRITES_IN_FLIGHT 8 +/* arbitrarily chosen */ + +/* +The cause for these errors is that the driver makes use of the functions usb_buffer_alloc() and usb_buffer_free() which got renamed in kernel 2.6.35. This is stated in the Changelog: USB: rename usb_buffer_alloc() and usb_buffer_free() users + For more clearance what the functions actually do, + usb_buffer_alloc() is renamed to usb_alloc_coherent() + usb_buffer_free() is renamed to usb_free_coherent() + This is needed on Debian 2.6.32-5-amd64 +*/ +#if ( LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) ) +#define usb_alloc_coherent usb_buffer_alloc +#define usb_free_coherent usb_buffer_free +#define noop_llseek NULL +#endif + +static struct usb_driver ced_driver; + +static void ced_delete(struct kref *kref) +{ + DEVICE_EXTENSION *pdx = to_DEVICE_EXTENSION(kref); + + // Free up the output buffer, then free the output urb. Note that the interface member + // of pdx will probably be NULL, so cannot be used to get to dev. + usb_free_coherent(pdx->udev, OUTBUF_SZ, pdx->pCoherCharOut, + pdx->pUrbCharOut->transfer_dma); + usb_free_urb(pdx->pUrbCharOut); + + // Do the same for chan input + usb_free_coherent(pdx->udev, INBUF_SZ, pdx->pCoherCharIn, + pdx->pUrbCharIn->transfer_dma); + usb_free_urb(pdx->pUrbCharIn); + + // Do the same for the block transfers + usb_free_coherent(pdx->udev, STAGED_SZ, pdx->pCoherStagedIO, + pdx->pStagedUrb->transfer_dma); + usb_free_urb(pdx->pStagedUrb); + + usb_put_dev(pdx->udev); + kfree(pdx); +} + +// This is the driver end of the open() call from user space. +static int ced_open(struct inode *inode, struct file *file) +{ + DEVICE_EXTENSION *pdx; + int retval = 0; + int subminor = iminor(inode); + struct usb_interface *interface = + usb_find_interface(&ced_driver, subminor); + if (!interface) { + pr_err("%s - error, can't find device for minor %d", __func__, + subminor); + retval = -ENODEV; + goto exit; + } + + pdx = usb_get_intfdata(interface); + if (!pdx) { + retval = -ENODEV; + goto exit; + } + + dev_dbg(&interface->dev, "%s got pdx", __func__); + + /* increment our usage count for the device */ + kref_get(&pdx->kref); + + /* lock the device to allow correctly handling errors + * in resumption */ + mutex_lock(&pdx->io_mutex); + + if (!pdx->open_count++) { + retval = usb_autopm_get_interface(interface); + if (retval) { + pdx->open_count--; + mutex_unlock(&pdx->io_mutex); + kref_put(&pdx->kref, ced_delete); + goto exit; + } + } else { //uncomment this block if you want exclusive open + dev_err(&interface->dev, "%s fail: already open", __func__); + retval = -EBUSY; + pdx->open_count--; + mutex_unlock(&pdx->io_mutex); + kref_put(&pdx->kref, ced_delete); + goto exit; + } + /* prevent the device from being autosuspended */ + + /* save our object in the file's private structure */ + file->private_data = pdx; + mutex_unlock(&pdx->io_mutex); + +exit: + return retval; +} + +static int ced_release(struct inode *inode, struct file *file) +{ + DEVICE_EXTENSION *pdx = file->private_data; + if (pdx == NULL) + return -ENODEV; + + dev_dbg(&pdx->interface->dev, "%s called", __func__); + mutex_lock(&pdx->io_mutex); + if (!--pdx->open_count && pdx->interface) // Allow autosuspend + usb_autopm_put_interface(pdx->interface); + mutex_unlock(&pdx->io_mutex); + + kref_put(&pdx->kref, ced_delete); // decrement the count on our device + return 0; +} + +static int ced_flush(struct file *file, fl_owner_t id) +{ + int res; + DEVICE_EXTENSION *pdx = file->private_data; + if (pdx == NULL) + return -ENODEV; + + dev_dbg(&pdx->interface->dev, "%s char in pend=%d", __func__, + pdx->bReadCharsPending); + + /* wait for io to stop */ + mutex_lock(&pdx->io_mutex); + dev_dbg(&pdx->interface->dev, "%s got io_mutex", __func__); + ced_draw_down(pdx); + + /* read out errors, leave subsequent opens a clean slate */ + spin_lock_irq(&pdx->err_lock); + res = pdx->errors ? (pdx->errors == -EPIPE ? -EPIPE : -EIO) : 0; + pdx->errors = 0; + spin_unlock_irq(&pdx->err_lock); + + mutex_unlock(&pdx->io_mutex); + dev_dbg(&pdx->interface->dev, "%s exit reached", __func__); + + return res; +} + +/*************************************************************************** +** CanAcceptIoRequests +** If the device is removed, interface is set NULL. We also clear our pointer +** from the interface, so we should make sure that pdx is not NULL. This will +** not help with a device extension held by a file. +** return true if can accept new io requests, else false +*/ +static bool CanAcceptIoRequests(DEVICE_EXTENSION * pdx) +{ + return pdx && pdx->interface; // Can we accept IO requests +} + +/**************************************************************************** +** Callback routine to complete writes. This may need to fire off another +** urb to complete the transfer. +****************************************************************************/ +static void ced_writechar_callback(struct urb *pUrb) +{ + DEVICE_EXTENSION *pdx = pUrb->context; + int nGot = pUrb->actual_length; // what we transferred + + if (pUrb->status) { // sync/async unlink faults aren't errors + if (! + (pUrb->status == -ENOENT || pUrb->status == -ECONNRESET + || pUrb->status == -ESHUTDOWN)) { + dev_err(&pdx->interface->dev, + "%s - nonzero write bulk status received: %d", + __func__, pUrb->status); + } + + spin_lock(&pdx->err_lock); + pdx->errors = pUrb->status; + spin_unlock(&pdx->err_lock); + nGot = 0; // and tidy up again if so + + spin_lock(&pdx->charOutLock); // already at irq level + pdx->dwOutBuffGet = 0; // Reset the output buffer + pdx->dwOutBuffPut = 0; + pdx->dwNumOutput = 0; // Clear the char count + pdx->bPipeError[0] = 1; // Flag an error for later + pdx->bSendCharsPending = false; // Allow other threads again + spin_unlock(&pdx->charOutLock); // already at irq level + dev_dbg(&pdx->interface->dev, + "%s - char out done, 0 chars sent", __func__); + } else { + dev_dbg(&pdx->interface->dev, + "%s - char out done, %d chars sent", __func__, nGot); + spin_lock(&pdx->charOutLock); // already at irq level + pdx->dwNumOutput -= nGot; // Now adjust the char send buffer + pdx->dwOutBuffGet += nGot; // to match what we did + if (pdx->dwOutBuffGet >= OUTBUF_SZ) // Can't do this any earlier as data could be overwritten + pdx->dwOutBuffGet = 0; + + if (pdx->dwNumOutput > 0) // if more to be done... + { + int nPipe = 0; // The pipe number to use + int iReturn; + char *pDat = &pdx->outputBuffer[pdx->dwOutBuffGet]; + unsigned int dwCount = pdx->dwNumOutput; // maximum to send + if ((pdx->dwOutBuffGet + dwCount) > OUTBUF_SZ) // does it cross buffer end? + dwCount = OUTBUF_SZ - pdx->dwOutBuffGet; + spin_unlock(&pdx->charOutLock); // we are done with stuff that changes + memcpy(pdx->pCoherCharOut, pDat, dwCount); // copy output data to the buffer + usb_fill_bulk_urb(pdx->pUrbCharOut, pdx->udev, + usb_sndbulkpipe(pdx->udev, + pdx->epAddr[0]), + pdx->pCoherCharOut, dwCount, + ced_writechar_callback, pdx); + pdx->pUrbCharOut->transfer_flags |= + URB_NO_TRANSFER_DMA_MAP; + usb_anchor_urb(pdx->pUrbCharOut, &pdx->submitted); // in case we need to kill it + iReturn = usb_submit_urb(pdx->pUrbCharOut, GFP_ATOMIC); + dev_dbg(&pdx->interface->dev, "%s n=%d>%s<", __func__, + dwCount, pDat); + spin_lock(&pdx->charOutLock); // grab lock for errors + if (iReturn) { + pdx->bPipeError[nPipe] = 1; // Flag an error to be handled later + pdx->bSendCharsPending = false; // Allow other threads again + usb_unanchor_urb(pdx->pUrbCharOut); + dev_err(&pdx->interface->dev, + "%s usb_submit_urb() returned %d", + __func__, iReturn); + } + } else + pdx->bSendCharsPending = false; // Allow other threads again + spin_unlock(&pdx->charOutLock); // already at irq level + } +} + +/**************************************************************************** +** SendChars +** Transmit the characters in the output buffer to the 1401. This may need +** breaking down into multiple transfers. +****************************************************************************/ +int SendChars(DEVICE_EXTENSION * pdx) +{ + int iReturn = U14ERR_NOERROR; + + spin_lock_irq(&pdx->charOutLock); // Protect ourselves + + if ((!pdx->bSendCharsPending) && // Not currently sending + (pdx->dwNumOutput > 0) && // has characters to output + (CanAcceptIoRequests(pdx))) // and current activity is OK + { + unsigned int dwCount = pdx->dwNumOutput; // Get a copy of the character count + pdx->bSendCharsPending = true; // Set flag to lock out other threads + + dev_dbg(&pdx->interface->dev, + "Send %d chars to 1401, EP0 flag %d\n", dwCount, + pdx->nPipes == 3); + // If we have only 3 end points we must send the characters to the 1401 using EP0. + if (pdx->nPipes == 3) { + // For EP0 character transmissions to the 1401, we have to hang about until they + // are gone, as otherwise without more character IO activity they will never go. + unsigned int count = dwCount; // Local char counter + unsigned int index = 0; // The index into the char buffer + + spin_unlock_irq(&pdx->charOutLock); // Free spinlock as we call USBD + + while ((count > 0) && (iReturn == U14ERR_NOERROR)) { + // We have to break the transfer up into 64-byte chunks because of a 2270 problem + int n = count > 64 ? 64 : count; // Chars for this xfer, max of 64 + int nSent = usb_control_msg(pdx->udev, + usb_sndctrlpipe(pdx->udev, 0), // use end point 0 + DB_CHARS, // bRequest + (H_TO_D | VENDOR | DEVREQ), // to the device, vendor request to the device + 0, 0, // value and index are both 0 + &pdx->outputBuffer[index], // where to send from + n, // how much to send + 1000); // timeout in jiffies + if (nSent <= 0) { + iReturn = nSent ? nSent : -ETIMEDOUT; // if 0 chars says we timed out + dev_err(&pdx->interface->dev, + "Send %d chars by EP0 failed: %d", + n, iReturn); + } else { + dev_dbg(&pdx->interface->dev, + "Sent %d chars by EP0", n); + count -= nSent; + index += nSent; + } + } + + spin_lock_irq(&pdx->charOutLock); // Protect pdx changes, released by general code + pdx->dwOutBuffGet = 0; // so reset the output buffer + pdx->dwOutBuffPut = 0; + pdx->dwNumOutput = 0; // and clear the buffer count + pdx->bSendCharsPending = false; // Allow other threads again + } else { // Here for sending chars normally - we hold the spin lock + int nPipe = 0; // The pipe number to use + char *pDat = &pdx->outputBuffer[pdx->dwOutBuffGet]; + + if ((pdx->dwOutBuffGet + dwCount) > OUTBUF_SZ) // does it cross buffer end? + dwCount = OUTBUF_SZ - pdx->dwOutBuffGet; + spin_unlock_irq(&pdx->charOutLock); // we are done with stuff that changes + memcpy(pdx->pCoherCharOut, pDat, dwCount); // copy output data to the buffer + usb_fill_bulk_urb(pdx->pUrbCharOut, pdx->udev, + usb_sndbulkpipe(pdx->udev, + pdx->epAddr[0]), + pdx->pCoherCharOut, dwCount, + ced_writechar_callback, pdx); + pdx->pUrbCharOut->transfer_flags |= + URB_NO_TRANSFER_DMA_MAP; + usb_anchor_urb(pdx->pUrbCharOut, &pdx->submitted); + iReturn = usb_submit_urb(pdx->pUrbCharOut, GFP_KERNEL); + spin_lock_irq(&pdx->charOutLock); // grab lock for errors + if (iReturn) { + pdx->bPipeError[nPipe] = 1; // Flag an error to be handled later + pdx->bSendCharsPending = false; // Allow other threads again + usb_unanchor_urb(pdx->pUrbCharOut); // remove from list of active urbs + } + } + } else if (pdx->bSendCharsPending && (pdx->dwNumOutput > 0)) + dev_dbg(&pdx->interface->dev, + "SendChars bSendCharsPending:true"); + + dev_dbg(&pdx->interface->dev, "SendChars exit code: %d", iReturn); + spin_unlock_irq(&pdx->charOutLock); // Now let go of the spinlock + return iReturn; +} + +/*************************************************************************** +** CopyUserSpace +** This moves memory between pinned down user space and the pCoherStagedIO +** memory buffer we use for transfers. Copy n bytes in the directions that +** is defined by pdx->StagedRead. The user space is determined by the area +** in pdx->StagedId and the offset in pdx->StagedDone. The user +** area may well not start on a page boundary, so allow for that. +** +** We have a table of physical pages that describe the area, so we can use +** this to get a virtual address that the kernel can use. +** +** pdx Is our device extension which holds all we know about the transfer. +** n The number of bytes to move one way or the other. +***************************************************************************/ +static void CopyUserSpace(DEVICE_EXTENSION * pdx, int n) +{ + unsigned int nArea = pdx->StagedId; + if (nArea < MAX_TRANSAREAS) { + TRANSAREA *pArea = &pdx->rTransDef[nArea]; // area to be used + unsigned int dwOffset = + pdx->StagedDone + pdx->StagedOffset + pArea->dwBaseOffset; + char *pCoherBuf = pdx->pCoherStagedIO; // coherent buffer + if (!pArea->bUsed) { + dev_err(&pdx->interface->dev, "%s area %d unused", + __func__, nArea); + return; + } + + while (n) { + int nPage = dwOffset >> PAGE_SHIFT; // page number in table + if (nPage < pArea->nPages) { + char *pvAddress = + (char *)kmap_atomic(pArea->pPages[nPage]); + if (pvAddress) { + unsigned int uiPageOff = dwOffset & (PAGE_SIZE - 1); // offset into the page + size_t uiXfer = PAGE_SIZE - uiPageOff; // max to transfer on this page + if (uiXfer > n) // limit byte count if too much + uiXfer = n; // for the page + if (pdx->StagedRead) + memcpy(pvAddress + uiPageOff, + pCoherBuf, uiXfer); + else + memcpy(pCoherBuf, + pvAddress + uiPageOff, + uiXfer); + kunmap_atomic(pvAddress); + dwOffset += uiXfer; + pCoherBuf += uiXfer; + n -= uiXfer; + } else { + dev_err(&pdx->interface->dev, + "%s did not map page %d", + __func__, nPage); + return; + } + + } else { + dev_err(&pdx->interface->dev, + "%s exceeded pages %d", __func__, + nPage); + return; + } + } + } else + dev_err(&pdx->interface->dev, "%s bad area %d", __func__, + nArea); +} + +// Forward declarations for stuff used circularly +static int StageChunk(DEVICE_EXTENSION * pdx); +/*************************************************************************** +** ReadWrite_Complete +** +** Completion routine for our staged read/write Irps +*/ +static void staged_callback(struct urb *pUrb) +{ + DEVICE_EXTENSION *pdx = pUrb->context; + unsigned int nGot = pUrb->actual_length; // what we transferred + bool bCancel = false; + bool bRestartCharInput; // used at the end + + spin_lock(&pdx->stagedLock); // stop ReadWriteMem() action while this routine is running + pdx->bStagedUrbPending = false; // clear the flag for staged IRP pending + + if (pUrb->status) { // sync/async unlink faults aren't errors + if (! + (pUrb->status == -ENOENT || pUrb->status == -ECONNRESET + || pUrb->status == -ESHUTDOWN)) { + dev_err(&pdx->interface->dev, + "%s - nonzero write bulk status received: %d", + __func__, pUrb->status); + } else + dev_info(&pdx->interface->dev, + "%s - staged xfer cancelled", __func__); + + spin_lock(&pdx->err_lock); + pdx->errors = pUrb->status; + spin_unlock(&pdx->err_lock); + nGot = 0; // and tidy up again if so + bCancel = true; + } else { + dev_dbg(&pdx->interface->dev, "%s %d chars xferred", __func__, + nGot); + if (pdx->StagedRead) // if reading, save to user space + CopyUserSpace(pdx, nGot); // copy from buffer to user + if (nGot == 0) + dev_dbg(&pdx->interface->dev, "%s ZLP", __func__); + } + + // Update the transfer length based on the TransferBufferLength value in the URB + pdx->StagedDone += nGot; + + dev_dbg(&pdx->interface->dev, "%s, done %d bytes of %d", __func__, + pdx->StagedDone, pdx->StagedLength); + + if ((pdx->StagedDone == pdx->StagedLength) || // If no more to do + (bCancel)) // or this IRP was cancelled + { + TRANSAREA *pArea = &pdx->rTransDef[pdx->StagedId]; // Transfer area info + dev_dbg(&pdx->interface->dev, + "%s transfer done, bytes %d, cancel %d", __func__, + pdx->StagedDone, bCancel); + + // Here is where we sort out what to do with this transfer if using a circular buffer. We have + // a completed transfer that can be assumed to fit into the transfer area. We should be able to + // add this to the end of a growing block or to use it to start a new block unless the code + // that calculates the offset to use (in ReadWriteMem) is totally duff. + if ((pArea->bCircular) && (pArea->bCircToHost) && (!bCancel) && // Time to sort out circular buffer info? + (pdx->StagedRead)) // Only for tohost transfers for now + { + if (pArea->aBlocks[1].dwSize > 0) // If block 1 is in use we must append to it + { + if (pdx->StagedOffset == + (pArea->aBlocks[1].dwOffset + + pArea->aBlocks[1].dwSize)) { + pArea->aBlocks[1].dwSize += + pdx->StagedLength; + dev_dbg(&pdx->interface->dev, + "RWM_Complete, circ block 1 now %d bytes at %d", + pArea->aBlocks[1].dwSize, + pArea->aBlocks[1].dwOffset); + } else { + // Here things have gone very, very, wrong, but I cannot see how this can actually be achieved + pArea->aBlocks[1].dwOffset = + pdx->StagedOffset; + pArea->aBlocks[1].dwSize = + pdx->StagedLength; + dev_err(&pdx->interface->dev, + "%s ERROR, circ block 1 re-started %d bytes at %d", + __func__, + pArea->aBlocks[1].dwSize, + pArea->aBlocks[1].dwOffset); + } + } else // If block 1 is not used, we try to add to block 0 + { + if (pArea->aBlocks[0].dwSize > 0) // Got stored block 0 information? + { // Must append onto the existing block 0 + if (pdx->StagedOffset == + (pArea->aBlocks[0].dwOffset + + pArea->aBlocks[0].dwSize)) { + pArea->aBlocks[0].dwSize += pdx->StagedLength; // Just add this transfer in + dev_dbg(&pdx->interface->dev, + "RWM_Complete, circ block 0 now %d bytes at %d", + pArea->aBlocks[0]. + dwSize, + pArea->aBlocks[0]. + dwOffset); + } else // If it doesn't append, put into new block 1 + { + pArea->aBlocks[1].dwOffset = + pdx->StagedOffset; + pArea->aBlocks[1].dwSize = + pdx->StagedLength; + dev_dbg(&pdx->interface->dev, + "RWM_Complete, circ block 1 started %d bytes at %d", + pArea->aBlocks[1]. + dwSize, + pArea->aBlocks[1]. + dwOffset); + } + } else // No info stored yet, just save in block 0 + { + pArea->aBlocks[0].dwOffset = + pdx->StagedOffset; + pArea->aBlocks[0].dwSize = + pdx->StagedLength; + dev_dbg(&pdx->interface->dev, + "RWM_Complete, circ block 0 started %d bytes at %d", + pArea->aBlocks[0].dwSize, + pArea->aBlocks[0].dwOffset); + } + } + } + + if (!bCancel) // Don't generate an event if cancelled + { + dev_dbg(&pdx->interface->dev, + "RWM_Complete, bCircular %d, bToHost %d, eStart %d, eSize %d", + pArea->bCircular, pArea->bEventToHost, + pArea->dwEventSt, pArea->dwEventSz); + if ((pArea->dwEventSz) && // Set a user-mode event... + (pdx->StagedRead == pArea->bEventToHost)) // ...on transfers in this direction? + { + int iWakeUp = 0; // assume + // If we have completed the right sort of DMA transfer then set the event to notify + // the user code to wake up anyone that is waiting. + if ((pArea->bCircular) && // Circular areas use a simpler test + (pArea->bCircToHost)) // only in supported direction + { // Is total data waiting up to size limit? + unsigned int dwTotal = + pArea->aBlocks[0].dwSize + + pArea->aBlocks[1].dwSize; + iWakeUp = (dwTotal >= pArea->dwEventSz); + } else { + unsigned int transEnd = + pdx->StagedOffset + + pdx->StagedLength; + unsigned int eventEnd = + pArea->dwEventSt + pArea->dwEventSz; + iWakeUp = (pdx->StagedOffset < eventEnd) + && (transEnd > pArea->dwEventSt); + } + + if (iWakeUp) { + dev_dbg(&pdx->interface->dev, + "About to set event to notify app"); + wake_up_interruptible(&pArea->wqEvent); // wake up waiting processes + ++pArea->iWakeUp; // increment wakeup count + } + } + } + + pdx->dwDMAFlag = MODE_CHAR; // Switch back to char mode before ReadWriteMem call + + if (!bCancel) // Don't look for waiting transfer if cancelled + { + // If we have a transfer waiting, kick it off + if (pdx->bXFerWaiting) // Got a block xfer waiting? + { + int iReturn; + dev_info(&pdx->interface->dev, + "*** RWM_Complete *** pending transfer will now be set up!!!"); + iReturn = + ReadWriteMem(pdx, !pdx->rDMAInfo.bOutWard, + pdx->rDMAInfo.wIdent, + pdx->rDMAInfo.dwOffset, + pdx->rDMAInfo.dwSize); + + if (iReturn) + dev_err(&pdx->interface->dev, + "RWM_Complete rw setup failed %d", + iReturn); + } + } + + } else // Here for more to do + StageChunk(pdx); // fire off the next bit + + // While we hold the stagedLock, see if we should reallow character input ints + // Don't allow if cancelled, or if a new block has started or if there is a waiting block. + // This feels wrong as we should ask which spin lock protects dwDMAFlag. + bRestartCharInput = !bCancel && (pdx->dwDMAFlag == MODE_CHAR) + && !pdx->bXFerWaiting; + + spin_unlock(&pdx->stagedLock); // Finally release the lock again + + // This is not correct as dwDMAFlag is protected by the staged lock, but it is treated + // in Allowi as if it were protected by the char lock. In any case, most systems will + // not be upset by char input during DMA... sigh. Needs sorting out. + if (bRestartCharInput) // may be out of date, but... + Allowi(pdx, true); // ...Allowi tests a lock too. + dev_dbg(&pdx->interface->dev, "%s done", __func__); +} + +/**************************************************************************** +** StageChunk +** +** Generates the next chunk of data making up a staged transfer. +** +** The calling code must have acquired the staging spinlock before calling +** this function, and is responsible for releasing it. We are at callback level. +****************************************************************************/ +static int StageChunk(DEVICE_EXTENSION * pdx) +{ + int iReturn = U14ERR_NOERROR; + unsigned int ChunkSize; + int nPipe = pdx->StagedRead ? 3 : 2; // The pipe number to use for reads or writes + if (pdx->nPipes == 3) + nPipe--; // Adjust for the 3-pipe case + if (nPipe < 0) // and trap case that should never happen + return U14ERR_FAIL; + + if (!CanAcceptIoRequests(pdx)) // got sudden remove? + { + dev_info(&pdx->interface->dev, "%s sudden remove, giving up", + __func__); + return U14ERR_FAIL; // could do with a better error + } + + ChunkSize = (pdx->StagedLength - pdx->StagedDone); // transfer length remaining + if (ChunkSize > STAGED_SZ) // make sure to keep legal + ChunkSize = STAGED_SZ; // limit to max allowed + + if (!pdx->StagedRead) // if writing... + CopyUserSpace(pdx, ChunkSize); // ...copy data into the buffer + + usb_fill_bulk_urb(pdx->pStagedUrb, pdx->udev, + pdx->StagedRead ? usb_rcvbulkpipe(pdx->udev, + pdx-> + epAddr[nPipe]) : + usb_sndbulkpipe(pdx->udev, pdx->epAddr[nPipe]), + pdx->pCoherStagedIO, ChunkSize, staged_callback, pdx); + pdx->pStagedUrb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; + usb_anchor_urb(pdx->pStagedUrb, &pdx->submitted); // in case we need to kill it + iReturn = usb_submit_urb(pdx->pStagedUrb, GFP_ATOMIC); + if (iReturn) { + usb_unanchor_urb(pdx->pStagedUrb); // kill it + pdx->bPipeError[nPipe] = 1; // Flag an error to be handled later + dev_err(&pdx->interface->dev, "%s submit urb failed, code %d", + __func__, iReturn); + } else + pdx->bStagedUrbPending = true; // Set the flag for staged URB pending + dev_dbg(&pdx->interface->dev, "%s done so far:%d, this size:%d", + __func__, pdx->StagedDone, ChunkSize); + + return iReturn; +} + +/*************************************************************************** +** ReadWriteMem +** +** This routine is used generally for block read and write operations. +** Breaks up a read or write in to specified sized chunks, as specified by pipe +** information on maximum transfer size. +** +** Any code that calls this must be holding the stagedLock +** +** Arguments: +** DeviceObject - pointer to our FDO (Functional Device Object) +** Read - TRUE for read, FALSE for write. This is from POV of the driver +** wIdent - the transfer area number - defines memory area and more. +** dwOffs - the start offset within the transfer area of the start of this +** transfer. +** dwLen - the number of bytes to transfer. +*/ +int ReadWriteMem(DEVICE_EXTENSION * pdx, bool Read, unsigned short wIdent, + unsigned int dwOffs, unsigned int dwLen) +{ + TRANSAREA *pArea = &pdx->rTransDef[wIdent]; // Transfer area info + + if (!CanAcceptIoRequests(pdx)) // Are we in a state to accept new requests? + { + dev_err(&pdx->interface->dev, "%s can't accept requests", + __func__); + return U14ERR_FAIL; + } + + dev_dbg(&pdx->interface->dev, + "%s xfer %d bytes to %s, offset %d, area %d", __func__, dwLen, + Read ? "host" : "1401", dwOffs, wIdent); + + // Amazingly, we can get an escape sequence back before the current staged Urb is done, so we + // have to check for this situation and, if so, wait until all is OK. + if (pdx->bStagedUrbPending) { + pdx->bXFerWaiting = true; // Flag we are waiting + dev_info(&pdx->interface->dev, + "%s xfer is waiting, as previous staged pending", + __func__); + return U14ERR_NOERROR; + } + + if (dwLen == 0) // allow 0-len read or write; just return success + { + dev_dbg(&pdx->interface->dev, + "%s OK; zero-len read/write request", __func__); + return U14ERR_NOERROR; + } + + if ((pArea->bCircular) && // Circular transfer? + (pArea->bCircToHost) && (Read)) // In a supported direction + { // If so, we sort out offset ourself + bool bWait = false; // Flag for transfer having to wait + + dev_dbg(&pdx->interface->dev, + "Circular buffers are %d at %d and %d at %d", + pArea->aBlocks[0].dwSize, pArea->aBlocks[0].dwOffset, + pArea->aBlocks[1].dwSize, pArea->aBlocks[1].dwOffset); + if (pArea->aBlocks[1].dwSize > 0) // Using the second block already? + { + dwOffs = pArea->aBlocks[1].dwOffset + pArea->aBlocks[1].dwSize; // take offset from that + bWait = (dwOffs + dwLen) > pArea->aBlocks[0].dwOffset; // Wait if will overwrite block 0? + bWait |= (dwOffs + dwLen) > pArea->dwLength; // or if it overflows the buffer + } else // Area 1 not in use, try to use area 0 + { + if (pArea->aBlocks[0].dwSize == 0) // Reset block 0 if not in use + pArea->aBlocks[0].dwOffset = 0; + dwOffs = + pArea->aBlocks[0].dwOffset + + pArea->aBlocks[0].dwSize; + if ((dwOffs + dwLen) > pArea->dwLength) // Off the end of the buffer? + { + pArea->aBlocks[1].dwOffset = 0; // Set up to use second block + dwOffs = 0; + bWait = (dwOffs + dwLen) > pArea->aBlocks[0].dwOffset; // Wait if will overwrite block 0? + bWait |= (dwOffs + dwLen) > pArea->dwLength; // or if it overflows the buffer + } + } + + if (bWait) // This transfer will have to wait? + { + pdx->bXFerWaiting = true; // Flag we are waiting + dev_dbg(&pdx->interface->dev, + "%s xfer waiting for circular buffer space", + __func__); + return U14ERR_NOERROR; + } + + dev_dbg(&pdx->interface->dev, + "%s circular xfer, %d bytes starting at %d", __func__, + dwLen, dwOffs); + } + // Save the parameters for the read\write transfer + pdx->StagedRead = Read; // Save the parameters for this read + pdx->StagedId = wIdent; // ID allows us to get transfer area info + pdx->StagedOffset = dwOffs; // The area within the transfer area + pdx->StagedLength = dwLen; + pdx->StagedDone = 0; // Initialise the byte count + pdx->dwDMAFlag = MODE_LINEAR; // Set DMA mode flag at this point + pdx->bXFerWaiting = false; // Clearly not a transfer waiting now + +// KeClearEvent(&pdx->StagingDoneEvent); // Clear the transfer done event + StageChunk(pdx); // fire off the first chunk + + return U14ERR_NOERROR; +} + +/**************************************************************************** +** +** ReadChar +** +** Reads a character a buffer. If there is no more +** data we return FALSE. Used as part of decoding a DMA request. +** +****************************************************************************/ +static bool ReadChar(unsigned char *pChar, char *pBuf, unsigned int *pdDone, + unsigned int dGot) +{ + bool bRead = false; + unsigned int dDone = *pdDone; + + if (dDone < dGot) // If there is more data + { + *pChar = (unsigned char)pBuf[dDone]; // Extract the next char + dDone++; // Increment the done count + *pdDone = dDone; + bRead = true; // and flag success + } + + return bRead; +} + +#ifdef NOTUSED +/**************************************************************************** +** +** ReadWord +** +** Reads a word from the 1401, just uses ReadChar twice; passes on any error +** +*****************************************************************************/ +static bool ReadWord(unsigned short *pWord, char *pBuf, unsigned int *pdDone, + unsigned int dGot) +{ + if (ReadChar((unsigned char *)pWord, pBuf, pdDone, dGot)) + return ReadChar(((unsigned char *)pWord) + 1, pBuf, pdDone, + dGot); + else + return false; +} +#endif + +/**************************************************************************** +** ReadHuff +** +** Reads a coded number in and returns it, Code is: +** If data is in range 0..127 we recieve 1 byte. If data in range 128-16383 +** we recieve two bytes, top bit of first indicates another on its way. If +** data in range 16383-4194303 we get three bytes, top two bits of first set +** to indicate three byte total. +** +*****************************************************************************/ +static bool ReadHuff(volatile unsigned int *pDWord, char *pBuf, + unsigned int *pdDone, unsigned int dGot) +{ + unsigned char ucData; /* for each read to ReadChar */ + bool bReturn = true; /* assume we will succeed */ + unsigned int dwData = 0; /* Accumulator for the data */ + + if (ReadChar(&ucData, pBuf, pdDone, dGot)) { + dwData = ucData; /* copy the data */ + if ((dwData & 0x00000080) != 0) { /* Bit set for more data ? */ + dwData &= 0x0000007F; /* Clear the relevant bit */ + if (ReadChar(&ucData, pBuf, pdDone, dGot)) { + dwData = (dwData << 8) | ucData; + if ((dwData & 0x00004000) != 0) { /* three byte sequence ? */ + dwData &= 0x00003FFF; /* Clear the relevant bit */ + if (ReadChar + (&ucData, pBuf, pdDone, dGot)) + dwData = (dwData << 8) | ucData; + else + bReturn = false; + } + } else + bReturn = false; /* couldn't read data */ + } + } else + bReturn = false; + + *pDWord = dwData; /* return the data */ + return bReturn; +} + +/*************************************************************************** +** +** ReadDMAInfo +** +** Tries to read info about the dma request from the 1401 and decode it into +** the dma descriptor block. We have at this point had the escape character +** from the 1401 and now we must read in the rest of the information about +** the transfer request. Returns FALSE if 1401 fails to respond or obselete +** code from 1401 or bad parameters. +** +** The pBuf char pointer does not include the initial escape character, so +** we start handling the data at offset zero. +** +*****************************************************************************/ +static bool ReadDMAInfo(volatile DMADESC * pDmaDesc, DEVICE_EXTENSION * pdx, + char *pBuf, unsigned int dwCount) +{ + bool bResult = false; // assume we won't succeed + unsigned char ucData; + unsigned int dDone = 0; // We haven't parsed anything so far + + dev_dbg(&pdx->interface->dev, "%s", __func__); + + if (ReadChar(&ucData, pBuf, &dDone, dwCount)) { + unsigned char ucTransCode = (ucData & 0x0F); // get code for transfer type + unsigned short wIdent = ((ucData >> 4) & 0x07); // and area identifier + + // fill in the structure we were given + pDmaDesc->wTransType = ucTransCode; // type of transfer + pDmaDesc->wIdent = wIdent; // area to use + pDmaDesc->dwSize = 0; // initialise other bits + pDmaDesc->dwOffset = 0; + + dev_dbg(&pdx->interface->dev, "%s type: %d ident: %d", __func__, + pDmaDesc->wTransType, pDmaDesc->wIdent); + + pDmaDesc->bOutWard = (ucTransCode != TM_EXTTOHOST); // set transfer direction + + switch (ucTransCode) { + case TM_EXTTOHOST: // Extended linear transfer modes (the only ones!) + case TM_EXTTO1401: + { + bResult = + ReadHuff(&(pDmaDesc->dwOffset), pBuf, + &dDone, dwCount) + && ReadHuff(&(pDmaDesc->dwSize), pBuf, + &dDone, dwCount); + if (bResult) { + dev_dbg(&pdx->interface->dev, + "%s xfer offset & size %d %d", + __func__, pDmaDesc->dwOffset, + pDmaDesc->dwSize); + + if ((wIdent >= MAX_TRANSAREAS) || // Illegal area number, or... + (!pdx->rTransDef[wIdent].bUsed) || // area not set up, or... + (pDmaDesc->dwOffset > pdx->rTransDef[wIdent].dwLength) || // range/size + ((pDmaDesc->dwOffset + + pDmaDesc->dwSize) > + (pdx->rTransDef[wIdent]. + dwLength))) { + bResult = false; // bad parameter(s) + dev_dbg(&pdx->interface->dev, + "%s bad param - id %d, bUsed %d, offset %d, size %d, area length %d", + __func__, wIdent, + pdx->rTransDef[wIdent]. + bUsed, + pDmaDesc->dwOffset, + pDmaDesc->dwSize, + pdx->rTransDef[wIdent]. + dwLength); + } + } + break; + } + default: + break; + } + } else + bResult = false; + + if (!bResult) // now check parameters for validity + dev_err(&pdx->interface->dev, "%s error reading Esc sequence", + __func__); + + return bResult; +} + +/**************************************************************************** +** +** Handle1401Esc +** +** Deals with an escape sequence coming from the 1401. This can either be +** a DMA transfer request of various types or a response to an escape sequence +** sent to the 1401. This is called from a callback. +** +** Parameters are +** +** dwCount - the number of characters in the device extension char in buffer, +** this is known to be at least 2 or we will not be called. +** +****************************************************************************/ +static int Handle1401Esc(DEVICE_EXTENSION * pdx, char *pCh, + unsigned int dwCount) +{ + int iReturn = U14ERR_FAIL; + + // I have no idea what this next test is about. '?' is 0x3f, which is area 3, code + // 15. At the moment, this is not used, so it does no harm, but unless someone can + // tell me what this is for, it should be removed from this and the Windows driver. + if (pCh[0] == '?') // Is this an information response + { // Parse and save the information + } else { + spin_lock(&pdx->stagedLock); // Lock others out + + if (ReadDMAInfo(&pdx->rDMAInfo, pdx, pCh, dwCount)) // Get DMA parameters + { + unsigned short wTransType = pdx->rDMAInfo.wTransType; // check transfer type + + dev_dbg(&pdx->interface->dev, + "%s xfer to %s, offset %d, length %d", __func__, + pdx->rDMAInfo.bOutWard ? "1401" : "host", + pdx->rDMAInfo.dwOffset, pdx->rDMAInfo.dwSize); + + if (pdx->bXFerWaiting) // Check here for badly out of kilter... + { // This can never happen, really + dev_err(&pdx->interface->dev, + "ERROR: DMA setup while transfer still waiting"); + spin_unlock(&pdx->stagedLock); + } else { + if ((wTransType == TM_EXTTOHOST) + || (wTransType == TM_EXTTO1401)) { + iReturn = + ReadWriteMem(pdx, + !pdx->rDMAInfo. + bOutWard, + pdx->rDMAInfo.wIdent, + pdx->rDMAInfo.dwOffset, + pdx->rDMAInfo.dwSize); + if (iReturn != U14ERR_NOERROR) + dev_err(&pdx->interface->dev, + "%s ReadWriteMem() failed %d", + __func__, iReturn); + } else // This covers non-linear transfer setup + dev_err(&pdx->interface->dev, + "%s Unknown block xfer type %d", + __func__, wTransType); + } + } else // Failed to read parameters + dev_err(&pdx->interface->dev, "%s ReadDMAInfo() fail", + __func__); + + spin_unlock(&pdx->stagedLock); // OK here + } + + dev_dbg(&pdx->interface->dev, "%s returns %d", __func__, iReturn); + + return iReturn; +} + +/**************************************************************************** +** Callback for the character read complete or error +****************************************************************************/ +static void ced_readchar_callback(struct urb *pUrb) +{ + DEVICE_EXTENSION *pdx = pUrb->context; + int nGot = pUrb->actual_length; // what we transferred + + if (pUrb->status) // Do we have a problem to handle? + { + int nPipe = pdx->nPipes == 4 ? 1 : 0; // The pipe number to use for error + // sync/async unlink faults aren't errors... just saying device removed or stopped + if (! + (pUrb->status == -ENOENT || pUrb->status == -ECONNRESET + || pUrb->status == -ESHUTDOWN)) { + dev_err(&pdx->interface->dev, + "%s - nonzero write bulk status received: %d", + __func__, pUrb->status); + } else + dev_dbg(&pdx->interface->dev, + "%s - 0 chars pUrb->status=%d (shutdown?)", + __func__, pUrb->status); + + spin_lock(&pdx->err_lock); + pdx->errors = pUrb->status; + spin_unlock(&pdx->err_lock); + nGot = 0; // and tidy up again if so + + spin_lock(&pdx->charInLock); // already at irq level + pdx->bPipeError[nPipe] = 1; // Flag an error for later + } else { + if ((nGot > 1) && ((pdx->pCoherCharIn[0] & 0x7f) == 0x1b)) // Esc sequence? + { + Handle1401Esc(pdx, &pdx->pCoherCharIn[1], nGot - 1); // handle it + spin_lock(&pdx->charInLock); // already at irq level + } else { + spin_lock(&pdx->charInLock); // already at irq level + if (nGot > 0) { + unsigned int i; + if (nGot < INBUF_SZ) { + pdx->pCoherCharIn[nGot] = 0; // tidy the string + dev_dbg(&pdx->interface->dev, + "%s got %d chars >%s<", + __func__, nGot, + pdx->pCoherCharIn); + } + // We know that whatever we read must fit in the input buffer + for (i = 0; i < nGot; i++) { + pdx->inputBuffer[pdx->dwInBuffPut++] = + pdx->pCoherCharIn[i] & 0x7F; + if (pdx->dwInBuffPut >= INBUF_SZ) + pdx->dwInBuffPut = 0; + } + + if ((pdx->dwNumInput + nGot) <= INBUF_SZ) + pdx->dwNumInput += nGot; // Adjust the buffer count accordingly + } else + dev_dbg(&pdx->interface->dev, "%s read ZLP", + __func__); + } + } + + pdx->bReadCharsPending = false; // No longer have a pending read + spin_unlock(&pdx->charInLock); // already at irq level + + Allowi(pdx, true); // see if we can do the next one +} + +/**************************************************************************** +** Allowi +** +** This is used to make sure that there is always a pending input transfer so +** we can pick up any inward transfers. This can be called in multiple contexts +** so we use the irqsave version of the spinlock. +****************************************************************************/ +int Allowi(DEVICE_EXTENSION * pdx, bool bInCallback) +{ + int iReturn = U14ERR_NOERROR; + unsigned long flags; + spin_lock_irqsave(&pdx->charInLock, flags); // can be called in multiple contexts + + // We don't want char input running while DMA is in progress as we know that this + // can cause sequencing problems for the 2270. So don't. It will also allow the + // ERR response to get back to the host code too early on some PCs, even if there + // is no actual driver failure, so we don't allow this at all. + if (!pdx->bInDrawDown && // stop input if + !pdx->bReadCharsPending && // If no read request outstanding + (pdx->dwNumInput < (INBUF_SZ / 2)) && // and there is some space + (pdx->dwDMAFlag == MODE_CHAR) && // not doing any DMA + (!pdx->bXFerWaiting) && // no xfer waiting to start + (CanAcceptIoRequests(pdx))) // and activity is generally OK + { // then off we go + unsigned int nMax = INBUF_SZ - pdx->dwNumInput; // max we could read + int nPipe = pdx->nPipes == 4 ? 1 : 0; // The pipe number to use + + dev_dbg(&pdx->interface->dev, "%s %d chars in input buffer", + __func__, pdx->dwNumInput); + + usb_fill_int_urb(pdx->pUrbCharIn, pdx->udev, + usb_rcvintpipe(pdx->udev, pdx->epAddr[nPipe]), + pdx->pCoherCharIn, nMax, ced_readchar_callback, + pdx, pdx->bInterval); + pdx->pUrbCharIn->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; // short xfers are OK by default + usb_anchor_urb(pdx->pUrbCharIn, &pdx->submitted); // in case we need to kill it + iReturn = + usb_submit_urb(pdx->pUrbCharIn, + bInCallback ? GFP_ATOMIC : GFP_KERNEL); + if (iReturn) { + usb_unanchor_urb(pdx->pUrbCharIn); // remove from list of active Urbs + pdx->bPipeError[nPipe] = 1; // Flag an error to be handled later + dev_err(&pdx->interface->dev, + "%s submit urb failed: %d", __func__, iReturn); + } else + pdx->bReadCharsPending = true; // Flag that we are active here + } + + spin_unlock_irqrestore(&pdx->charInLock, flags); + + return iReturn; + +} + +/***************************************************************************** +** The ioctl entry point to the driver that is used by us to talk to it. +** inode The device node (no longer in 3.0.0 kernels) +** file The file that is open, which holds our pdx pointer +** ulArg The argument passed in. Note that long is 64-bits in 64-bit system, i.e. it is big +** enough for a 64-bit pointer. +*****************************************************************************/ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) +static long ced_ioctl(struct file *file, unsigned int cmd, unsigned long ulArg) +#else +static int ced_ioctl(struct inode *node, struct file *file, unsigned int cmd, + unsigned long ulArg) +#endif +{ + int err = 0; + DEVICE_EXTENSION *pdx = file->private_data; + if (!CanAcceptIoRequests(pdx)) // check we still exist + return -ENODEV; + + // Check that access is allowed, where is is needed. Anything that would have an indeterminate + // size will be checked by the specific command. + if (_IOC_DIR(cmd) & _IOC_READ) // read from point of view of user... + err = !access_ok(VERIFY_WRITE, (void __user *)ulArg, _IOC_SIZE(cmd)); // is kernel write + else if (_IOC_DIR(cmd) & _IOC_WRITE) // and write from point of view of user... + err = !access_ok(VERIFY_READ, (void __user *)ulArg, _IOC_SIZE(cmd)); // is kernel read + if (err) + return -EFAULT; + + switch (_IOC_NR(cmd)) { + case _IOC_NR(IOCTL_CED_SENDSTRING(0)): + return SendString(pdx, (const char __user *)ulArg, + _IOC_SIZE(cmd)); + + case _IOC_NR(IOCTL_CED_RESET1401): + return Reset1401(pdx); + + case _IOC_NR(IOCTL_CED_GETCHAR): + return GetChar(pdx); + + case _IOC_NR(IOCTL_CED_SENDCHAR): + return SendChar(pdx, (char)ulArg); + + case _IOC_NR(IOCTL_CED_STAT1401): + return Stat1401(pdx); + + case _IOC_NR(IOCTL_CED_LINECOUNT): + return LineCount(pdx); + + case _IOC_NR(IOCTL_CED_GETSTRING(0)): + return GetString(pdx, (char __user *)ulArg, _IOC_SIZE(cmd)); + + case _IOC_NR(IOCTL_CED_SETTRANSFER): + return SetTransfer(pdx, (TRANSFERDESC __user *) ulArg); + + case _IOC_NR(IOCTL_CED_UNSETTRANSFER): + return UnsetTransfer(pdx, (int)ulArg); + + case _IOC_NR(IOCTL_CED_SETEVENT): + return SetEvent(pdx, (TRANSFEREVENT __user *) ulArg); + + case _IOC_NR(IOCTL_CED_GETOUTBUFSPACE): + return GetOutBufSpace(pdx); + + case _IOC_NR(IOCTL_CED_GETBASEADDRESS): + return -1; + + case _IOC_NR(IOCTL_CED_GETDRIVERREVISION): + return (2 << 24) | (DRIVERMAJREV << 16) | DRIVERMINREV; // USB | MAJOR | MINOR + + case _IOC_NR(IOCTL_CED_GETTRANSFER): + return GetTransfer(pdx, (TGET_TX_BLOCK __user *) ulArg); + + case _IOC_NR(IOCTL_CED_KILLIO1401): + return KillIO1401(pdx); + + case _IOC_NR(IOCTL_CED_STATEOF1401): + return StateOf1401(pdx); + + case _IOC_NR(IOCTL_CED_GRAB1401): + case _IOC_NR(IOCTL_CED_FREE1401): + return U14ERR_NOERROR; + + case _IOC_NR(IOCTL_CED_STARTSELFTEST): + return StartSelfTest(pdx); + + case _IOC_NR(IOCTL_CED_CHECKSELFTEST): + return CheckSelfTest(pdx, (TGET_SELFTEST __user *) ulArg); + + case _IOC_NR(IOCTL_CED_TYPEOF1401): + return TypeOf1401(pdx); + + case _IOC_NR(IOCTL_CED_TRANSFERFLAGS): + return TransferFlags(pdx); + + case _IOC_NR(IOCTL_CED_DBGPEEK): + return DbgPeek(pdx, (TDBGBLOCK __user *) ulArg); + + case _IOC_NR(IOCTL_CED_DBGPOKE): + return DbgPoke(pdx, (TDBGBLOCK __user *) ulArg); + + case _IOC_NR(IOCTL_CED_DBGRAMPDATA): + return DbgRampData(pdx, (TDBGBLOCK __user *) ulArg); + + case _IOC_NR(IOCTL_CED_DBGRAMPADDR): + return DbgRampAddr(pdx, (TDBGBLOCK __user *) ulArg); + + case _IOC_NR(IOCTL_CED_DBGGETDATA): + return DbgGetData(pdx, (TDBGBLOCK __user *) ulArg); + + case _IOC_NR(IOCTL_CED_DBGSTOPLOOP): + return DbgStopLoop(pdx); + + case _IOC_NR(IOCTL_CED_FULLRESET): + pdx->bForceReset = true; // Set a flag for a full reset + break; + + case _IOC_NR(IOCTL_CED_SETCIRCULAR): + return SetCircular(pdx, (TRANSFERDESC __user *) ulArg); + + case _IOC_NR(IOCTL_CED_GETCIRCBLOCK): + return GetCircBlock(pdx, (TCIRCBLOCK __user *) ulArg); + + case _IOC_NR(IOCTL_CED_FREECIRCBLOCK): + return FreeCircBlock(pdx, (TCIRCBLOCK __user *) ulArg); + + case _IOC_NR(IOCTL_CED_WAITEVENT): + return WaitEvent(pdx, (int)(ulArg & 0xff), (int)(ulArg >> 8)); + + case _IOC_NR(IOCTL_CED_TESTEVENT): + return TestEvent(pdx, (int)ulArg); + + default: + return U14ERR_NO_SUCH_FN; + } + return U14ERR_NOERROR; +} + +static const struct file_operations ced_fops = { + .owner = THIS_MODULE, + .open = ced_open, + .release = ced_release, + .flush = ced_flush, + .llseek = noop_llseek, +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36) + .unlocked_ioctl = ced_ioctl, +#else + .ioctl = ced_ioctl, +#endif +}; + +/* + * usb class driver info in order to get a minor number from the usb core, + * and to have the device registered with the driver core + */ +static struct usb_class_driver ced_class = { + .name = "cedusb%d", + .fops = &ced_fops, + .minor_base = USB_CED_MINOR_BASE, +}; + +// Check that the device that matches a 1401 vendor and product ID is OK to use and +// initialise our DEVICE_EXTENSION. +static int ced_probe(struct usb_interface *interface, + const struct usb_device_id *id) +{ + DEVICE_EXTENSION *pdx; + struct usb_host_interface *iface_desc; + struct usb_endpoint_descriptor *endpoint; + int i, bcdDevice; + int retval = -ENOMEM; + + // allocate memory for our device extension and initialize it + pdx = kzalloc(sizeof(*pdx), GFP_KERNEL); + if (!pdx) { + dev_err(&interface->dev, "Out of memory\n"); + goto error; + } + + for (i = 0; i < MAX_TRANSAREAS; ++i) // Initialise the wait queues + { + init_waitqueue_head(&pdx->rTransDef[i].wqEvent); + } + + // Put initialises for our stuff here. Note that all of *pdx is zero, so + // no need to explicitly zero it. + spin_lock_init(&pdx->charOutLock); + spin_lock_init(&pdx->charInLock); + spin_lock_init(&pdx->stagedLock); + + // Initialises from the skeleton stuff + kref_init(&pdx->kref); + mutex_init(&pdx->io_mutex); + spin_lock_init(&pdx->err_lock); + init_usb_anchor(&pdx->submitted); + + pdx->udev = usb_get_dev(interface_to_usbdev(interface)); + pdx->interface = interface; + + // Attempt to identify the device + bcdDevice = pdx->udev->descriptor.bcdDevice; + i = (bcdDevice >> 8); + if (i == 0) + pdx->s1401Type = TYPEU1401; + else if ((i >= 1) && (i <= 23)) + pdx->s1401Type = i + 2; + else { + dev_err(&interface->dev, "%s Unknown device. bcdDevice = %d", + __func__, bcdDevice); + goto error; + } + // set up the endpoint information. We only care about the number of EP as + // we know that we are dealing with a 1401 device. + iface_desc = interface->cur_altsetting; + pdx->nPipes = iface_desc->desc.bNumEndpoints; + dev_info(&interface->dev, "1401Type=%d with %d End Points", + pdx->s1401Type, pdx->nPipes); + if ((pdx->nPipes < 3) || (pdx->nPipes > 4)) + goto error; + + // Allocate the URBs we hold for performing transfers + pdx->pUrbCharOut = usb_alloc_urb(0, GFP_KERNEL); // character output URB + pdx->pUrbCharIn = usb_alloc_urb(0, GFP_KERNEL); // character input URB + pdx->pStagedUrb = usb_alloc_urb(0, GFP_KERNEL); // block transfer URB + if (!pdx->pUrbCharOut || !pdx->pUrbCharIn || !pdx->pStagedUrb) { + dev_err(&interface->dev, "%s URB alloc failed", __func__); + goto error; + } + + pdx->pCoherStagedIO = + usb_alloc_coherent(pdx->udev, STAGED_SZ, GFP_KERNEL, + &pdx->pStagedUrb->transfer_dma); + pdx->pCoherCharOut = + usb_alloc_coherent(pdx->udev, OUTBUF_SZ, GFP_KERNEL, + &pdx->pUrbCharOut->transfer_dma); + pdx->pCoherCharIn = + usb_alloc_coherent(pdx->udev, INBUF_SZ, GFP_KERNEL, + &pdx->pUrbCharIn->transfer_dma); + if (!pdx->pCoherCharOut || !pdx->pCoherCharIn || !pdx->pCoherStagedIO) { + dev_err(&interface->dev, "%s Coherent buffer alloc failed", + __func__); + goto error; + } + + for (i = 0; i < pdx->nPipes; ++i) { + endpoint = &iface_desc->endpoint[i].desc; + pdx->epAddr[i] = endpoint->bEndpointAddress; + dev_info(&interface->dev, "Pipe %d, ep address %02x", i, + pdx->epAddr[i]); + if (((pdx->nPipes == 3) && (i == 0)) || // if char input end point + ((pdx->nPipes == 4) && (i == 1))) { + pdx->bInterval = endpoint->bInterval; // save the endpoint interrupt interval + dev_info(&interface->dev, "Pipe %d, bInterval = %d", i, + pdx->bInterval); + } + // Detect USB2 by checking last ep size (64 if USB1) + if (i == pdx->nPipes - 1) // if this is the last ep (bulk) + { + pdx->bIsUSB2 = + le16_to_cpu(endpoint->wMaxPacketSize) > 64; + dev_info(&pdx->interface->dev, "USB%d", + pdx->bIsUSB2 + 1); + } + } + + /* save our data pointer in this interface device */ + usb_set_intfdata(interface, pdx); + + /* we can register the device now, as it is ready */ + retval = usb_register_dev(interface, &ced_class); + if (retval) { + /* something prevented us from registering this driver */ + dev_err(&interface->dev, + "Not able to get a minor for this device.\n"); + usb_set_intfdata(interface, NULL); + goto error; + } + + /* let the user know what node this device is now attached to */ + dev_info(&interface->dev, + "USB CEDUSB device now attached to cedusb #%d", + interface->minor); + return 0; + +error: + if (pdx) + kref_put(&pdx->kref, ced_delete); // frees allocated memory + return retval; +} + +static void ced_disconnect(struct usb_interface *interface) +{ + DEVICE_EXTENSION *pdx = usb_get_intfdata(interface); + int minor = interface->minor; // save for message at the end + int i; + + usb_set_intfdata(interface, NULL); // remove the pdx from the interface + usb_deregister_dev(interface, &ced_class); // give back our minor device number + + mutex_lock(&pdx->io_mutex); // stop more I/O starting while... + ced_draw_down(pdx); // ...wait for then kill any io + for (i = 0; i < MAX_TRANSAREAS; ++i) { + int iErr = ClearArea(pdx, i); // ...release any used memory + if (iErr == U14ERR_UNLOCKFAIL) + dev_err(&pdx->interface->dev, "%s Area %d was in used", + __func__, i); + } + pdx->interface = NULL; // ...we kill off link to interface + mutex_unlock(&pdx->io_mutex); + + usb_kill_anchored_urbs(&pdx->submitted); + + kref_put(&pdx->kref, ced_delete); // decrement our usage count + + dev_info(&interface->dev, "USB cedusb #%d now disconnected", minor); +} + +// Wait for all the urbs we know of to be done with, then kill off any that +// are left. NBNB we will need to have a mechanism to stop circular xfers +// from trying to fire off more urbs. We will wait up to 3 seconds for Urbs +// to be done. +void ced_draw_down(DEVICE_EXTENSION * pdx) +{ + int time; + dev_dbg(&pdx->interface->dev, "%s called", __func__); + + pdx->bInDrawDown = true; + time = usb_wait_anchor_empty_timeout(&pdx->submitted, 3000); + if (!time) // if we timed out we kill the urbs + { + usb_kill_anchored_urbs(&pdx->submitted); + dev_err(&pdx->interface->dev, "%s timed out", __func__); + } + pdx->bInDrawDown = false; +} + +static int ced_suspend(struct usb_interface *intf, pm_message_t message) +{ + DEVICE_EXTENSION *pdx = usb_get_intfdata(intf); + if (!pdx) + return 0; + ced_draw_down(pdx); + + dev_dbg(&pdx->interface->dev, "%s called", __func__); + return 0; +} + +static int ced_resume(struct usb_interface *intf) +{ + DEVICE_EXTENSION *pdx = usb_get_intfdata(intf); + if (!pdx) + return 0; + dev_dbg(&pdx->interface->dev, "%s called", __func__); + return 0; +} + +static int ced_pre_reset(struct usb_interface *intf) +{ + DEVICE_EXTENSION *pdx = usb_get_intfdata(intf); + dev_dbg(&pdx->interface->dev, "%s", __func__); + mutex_lock(&pdx->io_mutex); + ced_draw_down(pdx); + return 0; +} + +static int ced_post_reset(struct usb_interface *intf) +{ + DEVICE_EXTENSION *pdx = usb_get_intfdata(intf); + dev_dbg(&pdx->interface->dev, "%s", __func__); + + /* we are sure no URBs are active - no locking needed */ + pdx->errors = -EPIPE; + mutex_unlock(&pdx->io_mutex); + + return 0; +} + +static struct usb_driver ced_driver = { + .name = "cedusb", + .probe = ced_probe, + .disconnect = ced_disconnect, + .suspend = ced_suspend, + .resume = ced_resume, + .pre_reset = ced_pre_reset, + .post_reset = ced_post_reset, + .id_table = ced_table, + .supports_autosuspend = 1, +}; + +module_usb_driver(ced_driver); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/ced1401/usb1401.h b/drivers/staging/ced1401/usb1401.h new file mode 100644 index 000000000000..331ca9859829 --- /dev/null +++ b/drivers/staging/ced1401/usb1401.h @@ -0,0 +1,249 @@ +/* usb1401.h + Header file for the CED 1401 USB device driver for Linux + Copyright (C) 2010 Cambridge Electronic Design Ltd + Author Greg P Smith (greg@ced.co.uk) + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ +#ifndef __USB1401_H__ +#define __USB1401_H__ +#include "use1401.h" +#include "ced_ioctl.h" + +#ifndef UINT +#define UINT unsigned int +#endif + +/// Device type codes, but these don't need to be extended - a succession is assumed +/// These are set for usb from the bcdDevice field (suitably mangled). Future devices +/// will be added in order of device creation to the list, so the names here are just +/// to help use remember which device is which. The U14ERR_... values follow the same +/// pattern for modern devices. +#define TYPEUNKNOWN -1 // dont know +#define TYPE1401 0 // standard 1401 +#define TYPEPLUS 1 // 1401 plus +#define TYPEU1401 2 // u1401 +#define TYPEPOWER 3 // Power1401 +#define TYPEU14012 4 // u1401 mkII +#define TYPEPOWER2 5 // Power1401 mk II +#define TYPEMICRO3 6 // Micro1401-3 +#define TYPEPOWER3 7 // Power1401-3 + +/// Some useful defines of constants. DONT FORGET to change the version in the +/// resources whenever you change it here!. +#define DRIVERMAJREV 2 // driver revision level major (match windows) +#define DRIVERMINREV 0 // driver revision level minor + +/// Definitions of the various block transfer command codes +#define TM_EXTTOHOST 8 // extended tohost +#define TM_EXTTO1401 9 // extended to1401 + +/// Definitions of values in usbReqtype. Used in sorting out setup actions +#define H_TO_D 0x00 +#define D_TO_H 0x80 +#define VENDOR 0x40 +#define DEVREQ 0x00 +#define INTREQ 0x01 +#define ENDREQ 0x02 + +/// Definition of values in usbRequest, again used to sort out setup +#define GET_STATUS 0x00 +#define CLEAR_FEATURE 0x01 +#define SET_FEATURE 0x03 +#define SET_ADDRESS 0x05 +#define GET_DESC 0x06 +#define SET_DESC 0x07 +#define GET_CONF 0x08 +#define SET_CONF 0x09 +#define GET_INTERFACE 0x0a +#define SET_INTERFACE 0x0b +#define SYNCH_FRAME 0x0c + +/// Definitions of the various debug command codes understood by the 1401. These +/// are used in various vendor-specific commands to achieve the desired effect +#define DB_GRAB 0x50 /* Grab is a NOP for USB */ +#define DB_FREE 0x51 /* Free is a NOP for the USB */ +#define DB_SETADD 0x52 /* Set debug address (double) */ +#define DB_SELFTEST 0x53 /* Start self test */ +#define DB_SETMASK 0x54 /* Set enable mask (double) */ +#define DB_SETDEF 0x55 /* Set default mask (double) */ +#define DB_PEEK 0x56 /* Peek address, save result */ +#define DB_POKE 0x57 /* Poke address with data (double) */ +#define DB_RAMPD 0x58 /* Ramp data at debug address */ +#define DB_RAMPA 0x59 /* Ramp address bus */ +#define DB_REPEATS 0x5A /* Set repeats for operations (double) */ +#define DB_WIDTH 0x5B /* Set width for operations (byte) */ +#define DB_DATA 0x5C /* Get 4-byte data read by PEEK */ +#define DB_CHARS 0x5D /* Send chars via EP0 control write */ + +#define CR_CHAR 0x0D /* The carriage return character */ +#define CR_CHAR_80 0x8d /* and with bit 7 set */ + +/// A structure holding information about a block of memory for use in circular transfers +typedef struct circBlk +{ + volatile UINT dwOffset; /* Offset within area of block start */ + volatile UINT dwSize; /* Size of the block, in bytes (0 = unused) */ +} CIRCBLK; + +/// A structure holding all of the information about a transfer area - an area of +/// memory set up for use either as a source or destination in DMA transfers. +typedef struct transarea +{ + void* lpvBuff; // User address of xfer area saved for completeness + UINT dwBaseOffset; // offset to start of xfer area in first page + UINT dwLength; // Length of xfer area, in bytes + struct page **pPages; // Points at array of locked down pages + int nPages; // number of pages that are locked down + bool bUsed; // Is this structure in use? + bool bCircular; // Is this area for circular transfers? + bool bCircToHost; // Flag for direction of circular transfer + bool bEventToHost; // Set event on transfer to host? + int iWakeUp; // Set 1 on event, cleared by TestEvent() + UINT dwEventSt; // Defines section within xfer area for... + UINT dwEventSz; // ...notification by the event SZ is 0 if unset + CIRCBLK aBlocks[2]; // Info on a pair of circular blocks + wait_queue_head_t wqEvent; // The wait queue for events in this area MUST BE LAST +} TRANSAREA; + +/// The DMADESC structure is used to hold information on the transfer in progress. It +/// is set up by ReadDMAInfo, using information sent by the 1401 in an escape sequence. +typedef struct dmadesc +{ + unsigned short wTransType; /* transfer type as TM_xxx above */ + unsigned short wIdent; /* identifier word */ + unsigned int dwSize; /* bytes to transfer */ + unsigned int dwOffset; /* offset into transfer area for trans */ + bool bOutWard; /* true when data is going TO 1401 */ +} DMADESC; + +#define INBUF_SZ 256 /* input buffer size */ +#define OUTBUF_SZ 256 /* output buffer size */ +#define STAGED_SZ 0x10000 // size of coherent buffer for staged transfers + +/// Structure to hold all of our device specific stuff. We are making this as similar as we +/// can to the Windows driver to help in our understanding of what is going on. +typedef struct _DEVICE_EXTENSION +{ + char inputBuffer[INBUF_SZ]; /* The two buffers */ + char outputBuffer[OUTBUF_SZ]; /* accessed by the host functions */ + volatile unsigned int dwNumInput; /* num of chars in input buffer */ + volatile unsigned int dwInBuffGet; /* where to get from input buffer */ + volatile unsigned int dwInBuffPut; /* where to put into input buffer */ + volatile unsigned int dwNumOutput; /* num of chars in output buffer */ + volatile unsigned int dwOutBuffGet; /* where to get from output buffer*/ + volatile unsigned int dwOutBuffPut; /* where to put into output buffer*/ + + volatile bool bSendCharsPending; /* Flag to indicate sendchar active */ + volatile bool bReadCharsPending; /* Flag to indicate a read is primed */ + char* pCoherCharOut; /* special aligned buffer for chars to 1401 */ + struct urb* pUrbCharOut; /* urb used for chars to 1401 */ + char* pCoherCharIn; /* special aligned buffer for chars to host */ + struct urb* pUrbCharIn; /* urb used for chars to host */ + + spinlock_t charOutLock; /* to protect the outputBuffer and outputting */ + spinlock_t charInLock; /* to protect the inputBuffer and char reads */ + __u8 bInterval; /* Interrupt end point interval */ + + volatile unsigned int dwDMAFlag; /* state of DMA */ + TRANSAREA rTransDef[MAX_TRANSAREAS];/* transfer area info */ + volatile DMADESC rDMAInfo; // info on current DMA transfer + volatile bool bXFerWaiting; // Flag set if DMA transfer stalled + volatile bool bInDrawDown; // Flag that we want to halt transfers + + // Parameters relating to a block read\write that is in progress. Some of these values + // are equivalent to values in rDMAInfo. The values here are those in use, while those + // in rDMAInfo are those recieved from the 1401 via an escape sequence. If another + // escape sequence arrives before the previous xfer ends, rDMAInfo values are updated while these + // are used to finish off the current transfer. + volatile short StagedId; // The transfer area id for this transfer + volatile bool StagedRead; // Flag TRUE for read from 1401, FALSE for write + volatile unsigned int StagedLength; // Total length of this transfer + volatile unsigned int StagedOffset; // Offset within memory area for transfer start + volatile unsigned int StagedDone; // Bytes transferred so far + volatile bool bStagedUrbPending; // Flag to indicate active + char* pCoherStagedIO; // buffer used for block transfers + struct urb* pStagedUrb; // The URB to use + spinlock_t stagedLock; // protects ReadWriteMem() and circular buffer stuff + + short s1401Type; // type of 1401 attached + short sCurrentState; // current error state + bool bIsUSB2; // type of the interface we connect to + bool bForceReset; // Flag to make sure we get a real reset + __u32 statBuf[2]; // buffer for 1401 state info + + unsigned long ulSelfTestTime; // used to timeout self test + + int nPipes; // Should be 3 or 4 depending on 1401 usb chip + int bPipeError[4]; // set non-zero if an error on one of the pipe + __u8 epAddr[4]; // addresses of the 3/4 end points + + struct usb_device *udev; // the usb device for this device + struct usb_interface *interface; // the interface for this device, NULL if removed + struct usb_anchor submitted; // in case we need to retract our submissions + struct mutex io_mutex; // synchronize I/O with disconnect, one user-mode caller at a time + + int errors; // the last request tanked + int open_count; // count the number of openers + spinlock_t err_lock; // lock for errors + struct kref kref; +}DEVICE_EXTENSION, *PDEVICE_EXTENSION; +#define to_DEVICE_EXTENSION(d) container_of(d, DEVICE_EXTENSION, kref) + +/// Definitions of routimes used between compilation object files +// in usb1401.c +extern int Allowi(DEVICE_EXTENSION* pdx, bool bInCallback); +extern int SendChars(DEVICE_EXTENSION* pdx); +extern void ced_draw_down(DEVICE_EXTENSION *pdx); +extern int ReadWriteMem(DEVICE_EXTENSION *pdx, bool Read, unsigned short wIdent, + unsigned int dwOffs, unsigned int dwLen); + +// in ced_ioc.c +extern int ClearArea(DEVICE_EXTENSION *pdx, int nArea); +extern int SendString(DEVICE_EXTENSION* pdx, const char __user* pData, unsigned int n); +extern int SendChar(DEVICE_EXTENSION *pdx, char c); +extern int Get1401State(DEVICE_EXTENSION* pdx, __u32* state, __u32* error); +extern int ReadWrite_Cancel(DEVICE_EXTENSION *pdx); +extern bool Is1401(DEVICE_EXTENSION* pdx); +extern bool QuickCheck(DEVICE_EXTENSION* pdx, bool bTestBuff, bool bCanReset); +extern int Reset1401(DEVICE_EXTENSION *pdx); +extern int GetChar(DEVICE_EXTENSION *pdx); +extern int GetString(DEVICE_EXTENSION *pdx, char __user* pUser, int n); +extern int SetTransfer(DEVICE_EXTENSION *pdx, TRANSFERDESC __user *pTD); +extern int UnsetTransfer(DEVICE_EXTENSION *pdx, int nArea); +extern int SetEvent(DEVICE_EXTENSION *pdx, TRANSFEREVENT __user*pTE); +extern int Stat1401(DEVICE_EXTENSION *pdx); +extern int LineCount(DEVICE_EXTENSION *pdx); +extern int GetOutBufSpace(DEVICE_EXTENSION *pdx); +extern int GetTransfer(DEVICE_EXTENSION *pdx, TGET_TX_BLOCK __user *pGTB); +extern int KillIO1401(DEVICE_EXTENSION *pdx); +extern int BlkTransState(DEVICE_EXTENSION *pdx); +extern int StateOf1401(DEVICE_EXTENSION *pdx); +extern int StartSelfTest(DEVICE_EXTENSION *pdx); +extern int CheckSelfTest(DEVICE_EXTENSION *pdx, TGET_SELFTEST __user *pGST); +extern int TypeOf1401(DEVICE_EXTENSION *pdx); +extern int TransferFlags(DEVICE_EXTENSION *pdx); +extern int DbgPeek(DEVICE_EXTENSION *pdx, TDBGBLOCK __user* pDB); +extern int DbgPoke(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB); +extern int DbgRampData(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB); +extern int DbgRampAddr(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB); +extern int DbgGetData(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB); +extern int DbgStopLoop(DEVICE_EXTENSION *pdx); +extern int SetCircular(DEVICE_EXTENSION *pdx, TRANSFERDESC __user *pTD); +extern int GetCircBlock(DEVICE_EXTENSION *pdx, TCIRCBLOCK __user* pCB); +extern int FreeCircBlock(DEVICE_EXTENSION *pdx, TCIRCBLOCK __user* pCB); +extern int WaitEvent(DEVICE_EXTENSION *pdx, int nArea, int msTimeOut); +extern int TestEvent(DEVICE_EXTENSION *pdx, int nArea); +#endif diff --git a/drivers/staging/ced1401/use1401.h b/drivers/staging/ced1401/use1401.h new file mode 100644 index 000000000000..86294e21db0c --- /dev/null +++ b/drivers/staging/ced1401/use1401.h @@ -0,0 +1,287 @@ +/**************************************************************************** +** use1401.h +** Copyright (C) Cambridge Electronic Design Ltd, 1992-2010 +** Authors: Paul Cox, Tim Bergel, Greg Smith +** See CVS for revisions. +** +** Because the size of a long is different between 32-bit and 64-bit on some +** systems, we avoid this in this interface. +****************************************************************************/ +#ifndef __USE1401_H__ +#define __USE1401_H__ +#include "machine.h" + +// Some definitions to make things compatible. If you want to use Use1401 directly +// from a Windows program you should define U14_NOT_DLL, in which case you also +// MUST make sure that your application startup code calls U14InitLib(). +// DLL_USE1401 is defined when you are building the Use1401 dll, not otherwise. +#ifdef _IS_WINDOWS_ +#ifndef U14_NOT_DLL +#ifdef DLL_USE1401 +#define U14API(retType) retType DllExport __stdcall +#else +#define U14API(retType) retType DllImport __stdcall +#endif +#endif + +#define U14ERRBASE -500 +#define U14LONG long +#endif + +#ifdef LINUX +#define U14ERRBASE -1000 +#define U14LONG int +#endif + +#ifdef _QT +#ifndef U14_NOT_DLL +#undef U14API +#define U14API(retType) retType __declspec(dllimport) __stdcall +#endif +#undef U14LONG +#define U14LONG int +#endif + +#ifndef U14API +#define U14API(retType) retType +#endif + +#ifndef U14LONG +#define U14LONG long +#endif + +/// Error codes: We need them here as user space can see them. +#define U14ERR_NOERROR 0 // no problems + +/// Device error codes, but these don't need to be extended - a succession is assumed +#define U14ERR_STD 4 // standard 1401 connected +#define U14ERR_U1401 5 // u1401 connected +#define U14ERR_PLUS 6 // 1401 plus connected +#define U14ERR_POWER 7 // Power1401 connected +#define U14ERR_U14012 8 // u1401 mkII connected +#define U14ERR_POWER2 9 +#define U14ERR_U14013 10 +#define U14ERR_POWER3 11 + +/// NBNB Error numbers need shifting as some linux error codes start at 512 +#define U14ERR(n) (n+U14ERRBASE) +#define U14ERR_OFF U14ERR(0) /* 1401 there but switched off */ +#define U14ERR_NC U14ERR(-1) /* 1401 not connected */ +#define U14ERR_ILL U14ERR(-2) /* if present it is ill */ +#define U14ERR_NOIF U14ERR(-3) /* I/F card missing */ +#define U14ERR_TIME U14ERR(-4) /* 1401 failed to come ready */ +#define U14ERR_BADSW U14ERR(-5) /* I/F card bad switches */ +#define U14ERR_PTIME U14ERR(-6) /* 1401plus failed to come ready */ +#define U14ERR_NOINT U14ERR(-7) /* couldn't grab the int vector */ +#define U14ERR_INUSE U14ERR(-8) /* 1401 is already in use */ +#define U14ERR_NODMA U14ERR(-9) /* couldn't get DMA channel */ +#define U14ERR_BADHAND U14ERR(-10) /* handle provided was bad */ +#define U14ERR_BAD1401NUM U14ERR(-11) /* 1401 number provided was bad */ + +#define U14ERR_NO_SUCH_FN U14ERR(-20) /* no such function */ +#define U14ERR_NO_SUCH_SUBFN U14ERR(-21) /* no such sub function */ +#define U14ERR_NOOUT U14ERR(-22) /* no room in output buffer */ +#define U14ERR_NOIN U14ERR(-23) /* no input in buffer */ +#define U14ERR_STRLEN U14ERR(-24) /* string longer than buffer */ +#define U14ERR_ERR_STRLEN U14ERR(-24) /* string longer than buffer */ +#define U14ERR_LOCKFAIL U14ERR(-25) /* failed to lock memory */ +#define U14ERR_UNLOCKFAIL U14ERR(-26) /* failed to unlock memory */ +#define U14ERR_ALREADYSET U14ERR(-27) /* area already set up */ +#define U14ERR_NOTSET U14ERR(-28) /* area not set up */ +#define U14ERR_BADAREA U14ERR(-29) /* illegal area number */ +#define U14ERR_FAIL U14ERR(-30) /* we failed for some other reason*/ + +#define U14ERR_NOFILE U14ERR(-40) /* command file not found */ +#define U14ERR_READERR U14ERR(-41) /* error reading command file */ +#define U14ERR_UNKNOWN U14ERR(-42) /* unknown command */ +#define U14ERR_HOSTSPACE U14ERR(-43) /* not enough host space to load */ +#define U14ERR_LOCKERR U14ERR(-44) /* could not lock resource/command*/ +#define U14ERR_CLOADERR U14ERR(-45) /* CLOAD command failed */ + +#define U14ERR_TOXXXERR U14ERR(-60) /* tohost/1401 failed */ +#define U14ERR_NO386ENH U14ERR(-80) /* not 386 enhanced mode */ +#define U14ERR_NO1401DRIV U14ERR(-81) /* no device driver */ +#define U14ERR_DRIVTOOOLD U14ERR(-82) /* device driver too old */ + +#define U14ERR_TIMEOUT U14ERR(-90) /* timeout occurred */ + +#define U14ERR_BUFF_SMALL U14ERR(-100) /* buffer for getstring too small */ +#define U14ERR_CBALREADY U14ERR(-101) /* there is already a callback */ +#define U14ERR_BADDEREG U14ERR(-102) /* bad parameter to deregcallback */ +#define U14ERR_NOMEMORY U14ERR(-103) /* no memory for allocation */ + +#define U14ERR_DRIVCOMMS U14ERR(-110) /* failed talking to driver */ +#define U14ERR_OUTOFMEMORY U14ERR(-111) /* needed memory and couldnt get it*/ + +/// 1401 type codes. +#define U14TYPE1401 0 /* standard 1401 */ +#define U14TYPEPLUS 1 /* 1401 plus */ +#define U14TYPEU1401 2 /* u1401 */ +#define U14TYPEPOWER 3 /* power1401 */ +#define U14TYPEU14012 4 /* u1401 mk II */ +#define U14TYPEPOWER2 5 /* power1401 mk II */ +#define U14TYPEU14013 6 /* u1401-3 */ +#define U14TYPEPOWER3 7 /* power1401-3 */ +#define U14TYPEUNKNOWN -1 /* dont know */ + +/// Transfer flags to allow driver capabilities to be interrogated + +/// Constants for transfer flags +#define U14TF_USEDMA 1 /* Transfer flag for use DMA */ +#define U14TF_MULTIA 2 /* Transfer flag for multi areas */ +#define U14TF_FIFO 4 /* for FIFO interface card */ +#define U14TF_USB2 8 /* for USB2 interface and 1401 */ +#define U14TF_NOTIFY 16 /* for event notifications */ +#define U14TF_SHORT 32 /* for PCI can short cycle */ +#define U14TF_PCI2 64 /* for new PCI card 1401-70 */ +#define U14TF_CIRCTH 128 /* Circular-mode to host */ +#define U14TF_DIAG 256 /* Diagnostics/debug functions */ +#define U14TF_CIRC14 512 /* Circular-mode to 1401 */ + +/// Definitions of element sizes for DMA transfers - to allow byte-swapping +#define ESZBYTES 0 /* BYTE element size value */ +#define ESZWORDS 1 /* WORD element size value */ +#define ESZLONGS 2 /* long element size value */ +#define ESZUNKNOWN 0 /* unknown element size value */ + +/// These define required access types for the debug/diagnostics function +#define BYTE_SIZE 1 /* 8-bit access */ +#define WORD_SIZE 2 /* 16-bit access */ +#define LONG_SIZE 3 /* 32-bit access */ + +/// Stuff used by U14_GetTransfer +#define GET_TX_MAXENTRIES 257 /* (max length / page size + 1) */ + +#ifdef _IS_WINDOWS_ +#pragma pack(1) + +typedef struct /* used for U14_GetTransfer results */ +{ /* Info on a single mapped block */ + U14LONG physical; + U14LONG size; +} TXENTRY; + +typedef struct TGetTxBlock /* used for U14_GetTransfer results */ +{ /* matches structure in VXD */ + U14LONG size; + U14LONG linear; + short seg; + short reserved; + short avail; /* number of available entries */ + short used; /* number of used entries */ + TXENTRY entries[GET_TX_MAXENTRIES]; /* Array of mapped block info */ +} TGET_TX_BLOCK; + +typedef TGET_TX_BLOCK *LPGET_TX_BLOCK; + +#pragma pack() +#endif + +#ifdef LINUX +typedef struct /* used for U14_GetTransfer results */ +{ /* Info on a single mapped block */ + long long physical; + long size; +} TXENTRY; + +typedef struct TGetTxBlock /* used for U14_GetTransfer results */ +{ /* matches structure in VXD */ + long long linear; /* linear address */ + long size; /* total size of the mapped area, holds id when called */ + short seg; /* segment of the address for Win16 */ + short reserved; + short avail; /* number of available entries */ + short used; /* number of used entries */ + TXENTRY entries[GET_TX_MAXENTRIES]; /* Array of mapped block info */ +} TGET_TX_BLOCK; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +U14API(int) U14WhenToTimeOut(short hand); // when to timeout in ms +U14API(short) U14PassedTime(int iTime); // non-zero if iTime passed + +U14API(short) U14LastErrCode(short hand); + +U14API(short) U14Open1401(short n1401); +U14API(short) U14Close1401(short hand); +U14API(short) U14Reset1401(short hand); +U14API(short) U14ForceReset(short hand); +U14API(short) U14TypeOf1401(short hand); +U14API(short) U14NameOf1401(short hand, char* pBuf, WORD wMax); + +U14API(short) U14Stat1401(short hand); +U14API(short) U14CharCount(short hand); +U14API(short) U14LineCount(short hand); + +U14API(short) U14SendString(short hand, const char* pString); +U14API(short) U14GetString(short hand, char* pBuffer, WORD wMaxLen); +U14API(short) U14SendChar(short hand, char cChar); +U14API(short) U14GetChar(short hand, char* pcChar); + +U14API(short) U14LdCmd(short hand, const char* command); +U14API(DWORD) U14Ld(short hand, const char* vl, const char* str); + +U14API(short) U14SetTransArea(short hand, WORD wArea, void *pvBuff, + DWORD dwLength, short eSz); +U14API(short) U14UnSetTransfer(short hand, WORD wArea); +U14API(short) U14SetTransferEvent(short hand, WORD wArea, BOOL bEvent, + BOOL bToHost, DWORD dwStart, DWORD dwLength); +U14API(int) U14TestTransferEvent(short hand, WORD wArea); +U14API(int) U14WaitTransferEvent(short hand, WORD wArea, int msTimeOut); +U14API(short) U14GetTransfer(short hand, TGET_TX_BLOCK *pTransBlock); + +U14API(short) U14ToHost(short hand, char* pAddrHost,DWORD dwSize,DWORD dw1401, + short eSz); +U14API(short) U14To1401(short hand, const char* pAddrHost,DWORD dwSize,DWORD dw1401, + short eSz); + +U14API(short) U14SetCircular(short hand, WORD wArea, BOOL bToHost, void *pvBuff, + DWORD dwLength); + +U14API(int) U14GetCircBlk(short hand, WORD wArea, DWORD *pdwOffs); +U14API(int) U14FreeCircBlk(short hand, WORD wArea, DWORD dwOffs, DWORD dwSize, + DWORD *pdwOffs); + +U14API(short) U14StrToLongs(const char* pszBuff, U14LONG *palNums, short sMaxLongs); +U14API(short) U14LongsFrom1401(short hand, U14LONG *palBuff, short sMaxLongs); + +U14API(void) U14SetTimeout(short hand, int lTimeout); +U14API(int) U14GetTimeout(short hand); +U14API(short) U14OutBufSpace(short hand); +U14API(int) U14BaseAddr1401(short hand); +U14API(int) U14DriverVersion(short hand); +U14API(int) U14DriverType(short hand); +U14API(short) U14DriverName(short hand, char* pBuf, WORD wMax); +U14API(short) U14GetUserMemorySize(short hand, DWORD *pMemorySize); +U14API(short) U14KillIO1401(short hand); + +U14API(short) U14BlkTransState(short hand); +U14API(short) U14StateOf1401(short hand); + +U14API(short) U14Grab1401(short hand); +U14API(short) U14Free1401(short hand); +U14API(short) U14Peek1401(short hand, DWORD dwAddr, int nSize, int nRepeats); +U14API(short) U14Poke1401(short hand, DWORD dwAddr, DWORD dwValue, int nSize, int nRepeats); +U14API(short) U14Ramp1401(short hand, DWORD dwAddr, DWORD dwDef, DWORD dwEnable, int nSize, int nRepeats); +U14API(short) U14RampAddr(short hand, DWORD dwDef, DWORD dwEnable, int nSize, int nRepeats); +U14API(short) U14StopDebugLoop(short hand); +U14API(short) U14GetDebugData(short hand, U14LONG *plValue); + +U14API(short) U14StartSelfTest(short hand); +U14API(short) U14CheckSelfTest(short hand, U14LONG *pData); +U14API(short) U14TransferFlags(short hand); +U14API(void) U14GetErrorString(short nErr, char* pStr, WORD wMax); +U14API(int) U14MonitorRev(short hand); +U14API(void) U14CloseAll(void); + +U14API(short) U14WorkingSet(DWORD dwMinKb, DWORD dwMaxKb); +U14API(int) U14InitLib(void); + +#ifdef __cplusplus +} +#endif + +#endif /* End of ifndef __USE1401_H__ */ diff --git a/drivers/staging/ced1401/use14_ioc.h b/drivers/staging/ced1401/use14_ioc.h new file mode 100644 index 000000000000..15ca63888380 --- /dev/null +++ b/drivers/staging/ced1401/use14_ioc.h @@ -0,0 +1,301 @@ +/* use14_ioc.h +** definitions of use1401 module stuff that is shared between use1401 and the driver. +** Copyright (C) Cambridge Electronic Design Limited 2010 +** Author Greg P Smith +************************************************************************************/ +#ifndef __USE14_IOC_H__ +#define __USE14_IOC_H__ + +#define MAX_TRANSAREAS 8 /* The number of transfer areas supported by driver */ + +#define i386 +#include "winioctl.h" /* needed so we can access driver */ + +/* +** Defines for IOCTL functions to ask driver to perform. These must be matched +** in both use1401 and in the driver. The IOCTL code contains a command +** identifier, plus other information about the device, the type of access +** with which the file must have been opened, and the type of buffering. +** The IOCTL function codes from 0x80 to 0xFF are for developer use. +*/ +#define FILE_DEVICE_CED1401 0x8001 +#define FNNUMBASE 0x800 + +#define U14_OPEN1401 CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_CLOSE1401 CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+1, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_SENDSTRING CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+2, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_RESET1401 CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+3, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_GETCHAR CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+4, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_SENDCHAR CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+5, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_STAT1401 CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+6, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_LINECOUNT CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+7, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_GETSTRING CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+8, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_REGCALLBACK CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+9, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_GETMONITORBUF CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+10, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_SETTRANSFER CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+11, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_UNSETTRANSFER CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+12, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_SETTRANSEVENT CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+13, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_GETOUTBUFSPACE CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+14, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_GETBASEADDRESS CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+15, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_GETDRIVERREVISION CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+16, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_GETTRANSFER CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+17, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_KILLIO1401 CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+18, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_BLKTRANSSTATE CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+19, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_BYTECOUNT CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+20, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_ZEROBLOCKCOUNT CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+21, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_STOPCIRCULAR CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+22, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_STATEOF1401 CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+23, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_REGISTERS1401 CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+24, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_GRAB1401 CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+25, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_FREE1401 CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+26, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_STEP1401 CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+27, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_SET1401REGISTERS CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+28, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_STEPTILL1401 CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+29, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_SETORIN CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+30, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_STARTSELFTEST CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+31, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_CHECKSELFTEST CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+32, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_TYPEOF1401 CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+33, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_TRANSFERFLAGS CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+34, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_DBGPEEK CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+35, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_DBGPOKE CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+36, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_DBGRAMPDATA CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+37, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_DBGRAMPADDR CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+38, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_DBGGETDATA CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+39, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_DBGSTOPLOOP CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+40, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_FULLRESET CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+41, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_SETCIRCULAR CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+42, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_GETCIRCBLK CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+43, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +#define U14_FREECIRCBLK CTL_CODE( FILE_DEVICE_CED1401, \ + FNNUMBASE+44, \ + METHOD_BUFFERED, \ + FILE_ANY_ACCESS) + +//--------------- Structures that are shared with the driver ------------- +#pragma pack(1) + +typedef struct /* used for get/set standard 1401 registers */ +{ + short sPC; + char A; + char X; + char Y; + char stat; + char rubbish; +} T1401REGISTERS; + +typedef union /* to communicate with 1401 driver status & control funcs */ +{ + char chrs[22]; + short ints[11]; + long longs[5]; + T1401REGISTERS registers; +} TCSBLOCK; + +typedef TCSBLOCK* LPTCSBLOCK; + +typedef struct paramBlk +{ + short sState; + TCSBLOCK csBlock; +} PARAMBLK; + +typedef PARAMBLK* PPARAMBLK; + +typedef struct TransferDesc /* Structure and type for SetTransArea */ +{ + WORD wArea; /* number of transfer area to set up */ + void FAR * lpvBuff; /* address of transfer area */ + DWORD dwLength; /* length of area to set up */ + short eSize; /* size to move (for swapping on MAC) */ +} TRANSFERDESC; + +typedef TRANSFERDESC FAR * LPTRANSFERDESC; + +/* This is the structure used to set up a transfer area */ +typedef struct VXTransferDesc /* use1401.c and use1432x.x use only */ +{ + WORD wArea; /* number of transfer area to set up */ + WORD wAddrSel; /* 16 bit selector for area */ + DWORD dwAddrOfs; /* 32 bit offset for area start */ + DWORD dwLength; /* length of area to set up */ +} VXTRANSFERDESC; + +#pragma pack() + +#endif
\ No newline at end of file diff --git a/drivers/staging/ced1401/userspace/use1401.c b/drivers/staging/ced1401/userspace/use1401.c new file mode 100644 index 000000000000..d4c63168ea27 --- /dev/null +++ b/drivers/staging/ced1401/userspace/use1401.c @@ -0,0 +1,3035 @@ +/**************************************************************************** +** use1401.c +** Copyright (C) Cambridge Electronic Design Ltd, 1992-2010 +** +** This program is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License +** as published by the Free Software Foundation; either version 2 +** of the License, or (at your option) any later version. +** +** This program is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +** GNU General Public License for more details. +** +** You should have received a copy of the GNU General Public License +** along with this program; if not, write to the Free Software +** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +** +** Contact CED: Cambridge Electronic Design Limited, Science Park, Milton Road +** Cambridge, CB6 0FE. +** www.ced.co.uk +** greg@ced.co.uk +** +** Title: USE1401.C +** Version: 4.00 +** Author: Paul Cox, Tim Bergel, Greg Smith +** +** The code was vigorously pruned in DEC 2010 to remove the macintosh options +** and to get rid of the 16-bit support. It has also been aligned with the +** Linux version. See CVS for revisions. This will work for Win 9x onwards. +**************************************************************************** +** +** Notes on Windows interface to driver +** ************************************ +** +** Under Windows 9x and NT, Use1401 uses DeviceIoControl to get access to +** the 1401 driver. This has parameters for the device handle, the function +** code, an input pointer and byte count, an output pointer and byte count +** and a pointer to a DWORD to hold the output byte count. Note that input +** and output are from the point-of-view of the driver, so the output stuff +** is used to read values from the 1401, not send to the 1401. The use of +** these parameters varies with the function in use and the operating +** system; there are five separate DIOC calls SendString, GetString and +** SetTransferArea all have their own specialised calls, the rest use the +** Status1401 or Control1401 functions. +** +** There are two basic styles of DIOC call used, one for Win9x VxD drivers +** and one for NT Kernel-mode and WDM drivers (see below for tables showing +** the different parameters used. The array bUseNTDIOC[] selects between +** these two calling styles. +** +** Function codes +** In Win3.x, simple function codes from 0 to 40 were used, shifted left 8 +** bits with a sub-function code in the lower 8 bits. These were also used +** in the Windows 95 driver, though we had to add 1 to the code value to +** avoid problems (Open from CreateFile is zero), and the sub-function code +** is now unused. We found that this gave some problems with Windows 98 +** as the function code values are reserved by microsoft, so we switched to +** using the NT function codes instead. The NT codes are generated using the +** CTL_CODE macro, essentially this gives 0x80012000 | (func << 2), where +** func is the original 0 to 34 value. The driver will handle both types of +** code and Use1432 only uses the NT codes if it knows the driver is new +** enough. The array bUseNTCodes[] holds flags on the type of codes required. +** GPS/TDB Dec 2010: we removed the bUseNTCodes array as this is always true +** as we no longer support ancient versions. +** +** The CreateFile and CloseFile function calls are also handled +** by DIOC, using the special function codes 0 and -1 respectively. +** +** Input pointer and buffer size +** These are intended for data sent to the device driver. In nearly all cases +** they are unused in calls to the Win95 driver, the NT driver uses them +** for all information sent to the driver. The table below shows the pointer +** and byte count used for the various calls: +** +** Win 95 Win NT +** SendString NULL, 0 pStr, nStr +** GetString NULL, 0 NULL, 0 +** SetTransferArea pBuf, nBuf (unused?) pDesc, nDesc +** GetTransfer NULL, 0 NULL, 0 +** Status1401 NULL, 0 NULL, 0 +** Control1401 NULL, 0 pBlk, nBlk +** +** pStr and nStr are pointers to a char buffer and the buffer length for +** string I/O, note that these are temporary buffers owned by the DLL, not +** application memory, pBuf and nBuf are the transfer area buffer (I think +** these are unused), pDesc and nDesc are the TRANSFERDESC structure, pBlk +** and nBlk are the TCSBLOCK structure. +** +** +** Output pointer and buffer size +** These are intended for data read from the device driver. These are used +** for almost all information sent to the Win95 driver, the NT driver uses +** them for information read from the driver, chiefly the error code. The +** table below shows the pointer and byte count used for the various calls: +** +** Win 95 Win NT +** SendString pStr, nStr pPar, nPar +** GetString pStr, nStr+2 pStr, nStr+2 +** SetTransferArea pDesc, nDesc pPar, nPar +** GetTransfer pGet, nGet pGet, nGet +** Status1401 pBlk, nBlk pPar, nPar +** Control1401 pBlk, nBlk pPar, nPar +** +** pStr and nStr are pointers to a char buffer and the buffer length for +** string I/O, the +2 for GetString refers to two spare bytes at the start +** used to hold the string length and returning an error code for NT. Note +** again that these are (and must be) DLL-owned temporary buffers. pPar +** and nPar are a PARAM structure used in NT (it holds an error code and a +** TCSBLOCK structure). pDesc and nDesc are the VXTRANSFERDESC structure, +** pBlk and nBlk are the TCSBLOCK structure. pGet and nGet indicate the +** TGET_TX_BLOCK structure used for GetTransfer. +** +** +** The output byte count +** Both drivers return the output buffer size here, regardless of the actual +** bytes output. This is used to check that we did get through to the driver. +** +** Multiple 1401s +** ************** +** +** We have code that tries to support the use of multiple 1401s, but there +** are problems: The lDriverVersion and lDriverType variables are global, not +** per-1401 (a particular problem as the U14 functions that use them don't +** have a hand parameter). In addition, the mechansim for finding a free +** 1401 depends upon the 1401 device driver open operation failing if it's +** already in use, which doesn't always happen, particularly with the VxDs. +** The code in TryToOpen tries to fix this by relying on TYPEOF1401 to detect +** the 1401-in-use state - the VxDs contain special code to help this. This is +** working OK but multiple 1401 support works better with the Win2000 drivers. +** +** USB driver +** ********** +** +** The USB driver, which runs on both Win98 and NT2000, uses the NT-style +** calling convention, both for the DIOC codes and the DIOC parameters. The +** TryToOpen function has been altered to look for an NT driver first in +** the appropriate circumstances, and to set the driver DIOC flags up in +** the correct state. +** +** Adding a new 1401 type - now almost nothing to do +** ************************************************* +** +** The 1401 types are defined by a set of U14TYPExxxx codes in USE1401.H. +** You should add a new one of these to keep things tidy for applications. +** +** DRIVERET_MAX (below) specifies the maximum allowed type code from the +** 1401 driver; I have set this high to accomodate as yet undesigned 1401 +** types. Similarly, as long as the command file names follow the ARM, +** ARN, ARO sequence, these are calculated by the ExtForType function, so +** you don't need to do anything here either. +** +** Version number +** ************** +** The new U14InitLib() function returns 0 if the OS is incapable of use, +** otherwise is returns the version of the USE1401 library. This is done +** in three parts: Major(31-24).Minor(23-16).Revision.(15-0) (brackets are +** the bits used). The Major number starts at 2 for the first revision with +** the U14InitLib() function. Changes to the Major version means that we +** have broken backwards compatibility. Minor number changes mean that we +** have added new functionality that does not break backwards compatibility. +** we starts at 0. Revision changes mean we have fixed something. Each index +** returns to 0 when a higer one changes. +*/ +#define U14LIB_MAJOR 4 +#define U14LIB_MINOR 0 +#define U14LIB_REVISION 0 +#define U14LIB_VERSION ((U14LIB_MAJOR<<24) | (U14LIB_MINOR<<16) | U14LIB_REVISION) + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> + +#include "USE1401.H" + +#ifdef _IS_WINDOWS_ +#include <io.h> +#include <windows.h> +#pragma warning(disable: 4100) /* Disable "Unused formal parameter" warning */ +#include <assert.h> +#include "process.h" + + +#define sprintf wsprintf +#define PATHSEP '\\' +#define PATHSEPSTR "\\" +#define DEFCMDPATH "\\1401\\" // default command path if all else fails +#define MINDRIVERMAJREV 1 // minimum driver revision level we need +#define __packed // does nothing in Windows + +#include "use14_ioc.h" // links to device driver stuff +#endif + +#ifdef LINUX +#include <fcntl.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <errno.h> +#include <sys/time.h> +#include <sched.h> +#include <libgen.h> +#define PATHSEP '/' +#define PATHSEPSTR "/" +#define DEFCMDPATH "/var/1401/" // default command path if all else fails +#define MINDRIVERMAJREV 2 // minimum driver revision level we need + +#include "ced_ioctl.h" // links to device driver stuff +#endif + +#define MAX1401 8 // The number of 1401s that can be supported + +/* +** These are the 1401 type codes returned by the driver, they are a slightly +** odd sequence & start for reasons of compatability with the DOS driver. +** The maximum code value is the upper limit of 1401 device types. +*/ +#define DRIVRET_STD 4 // Codes for 1401 types matching driver values +#define DRIVRET_U1401 5 // This table does not need extending, as +#define DRIVRET_PLUS 6 // we can calculate values now. +#define DRIVRET_POWER 7 // but we need all of these values still +#define DRIVRET_MAX 26 // Maximum tolerated code - future designs + +/* +** These variables store data that will be used to generate the last +** error string. For now, a string will hold the 1401 command file name. +*/ +static char szLastName[20]; // additional text information + +/* +** Information stored per handle. NBNB, driverType and DriverVersion used to be +** only stored once for all handles... i.e. nonsensical. This change means that +** three U14...() calls now include handles that were previously void. We have +** set a constructor and a destructor call for the library (see the end) to +** initialise important structures, or call use1401_load(). +*/ +static short asDriverType[MAX1401] = {0}; +static int lLastDriverVersion = U14ERR_NO1401DRIV; +static int lLastDriverType = U14TYPEUNKNOWN; +static int alDriverVersion[MAX1401]; // version/type of each driver +static int alTimeOutPeriod[MAX1401]; // timeout time in milliseconds +static short asLastRetCode[MAX1401]; // last code from a fn call +static short asType1401[MAX1401] = {0}; // The type of the 1401 +static BOOL abGrabbed[MAX1401] = {0}; // Flag for grabbed, set true by grab1401 +static int iAttached = 0; // counts process attaches so can let go + +#ifdef _IS_WINDOWS_ +/**************************************************************************** +** Windows NT Specific Variables and internal types +****************************************************************************/ +static HANDLE aHand1401[MAX1401] = {0}; // handles for 1401s +static HANDLE aXferEvent[MAX1401] = {0}; // transfer events for the 1401s +static LPVOID apAreas[MAX1401][MAX_TRANSAREAS]; // Locked areas +static DWORD auAreas[MAX1401][MAX_TRANSAREAS]; // Size of locked areas +static BOOL bWindows9x = FALSE; // if we are Windows 95 or better +#ifdef _WIN64 +#define USE_NT_DIOC(ind) TRUE +#else +static BOOL abUseNTDIOC[MAX1401]; // Use NT-style DIOC parameters */ +#define USE_NT_DIOC(ind) abUseNTDIOC[ind] +#endif + +#endif + +#ifdef LINUX +static int aHand1401[MAX1401] = {0}; // handles for 1401s +#define INVALID_HANDLE_VALUE 0 // to avoid code differences +#endif + + +/* +** The CmdHead relates to backwards compatibility with ancient Microsoft (and Sperry!) +** versions of BASIC, where this header was needed so we could load a command into +** memory. +*/ +#pragma pack(1) // pack our structure +typedef struct CmdHead // defines header block on command +{ // for PC commands + char acBasic[5]; // BASIC information - needed to align things + WORD wBasicSz; // size as seen by BASIC + WORD wCmdSize; // size of the following info +} __packed CMDHEAD; +#pragma pack() // back to normal + +/* +** The rest of the header looks like this... +** int iRelPnt; relocation pointer... actual start +** char acName[8]; string holding the command name +** BYTE bMonRev; monitor revision level +** BYTE bCmdRev; command revision level +*/ + +typedef CMDHEAD *LPCMDHEAD; // pointer to a command header + +#define MAXSTRLEN 255 // maximum string length we use +#define TOHOST FALSE +#define TO1401 TRUE + +static short CheckHandle(short h) +{ + if ((h < 0) || (h >= MAX1401)) // must be legal range... + return U14ERR_BADHAND; + if (aHand1401[h] <= 0) // must be open + return U14ERR_BADHAND; + return U14ERR_NOERROR; +} + +#ifdef _IS_WINDOWS_ +/**************************************************************************** +** U14Status1401 Used for functions which do not pass any data in but +** get data back +****************************************************************************/ +static short U14Status1401(short sHand, LONG lCode, TCSBLOCK* pBlk) +{ + DWORD dwBytes = 0; + + if ((sHand < 0) || (sHand >= MAX1401)) /* Check parameters */ + return U14ERR_BADHAND; +#ifndef _WIN64 + if (!USE_NT_DIOC(sHand)) + { /* Windows 9x DIOC methods? */ + if (DeviceIoControl(aHand1401[sHand], lCode, NULL, 0, pBlk,sizeof(TCSBLOCK),&dwBytes,NULL)) + return (short)((dwBytes>=sizeof(TCSBLOCK)) ? U14ERR_NOERROR : U14ERR_DRIVCOMMS); + else + return (short)GetLastError(); + } + else +#endif + { /* Windows NT or USB driver */ + PARAMBLK rWork; + rWork.sState = U14ERR_DRIVCOMMS; + if (DeviceIoControl(aHand1401[sHand], lCode, NULL, 0, &rWork,sizeof(PARAMBLK),&dwBytes,NULL) && + (dwBytes >= sizeof(PARAMBLK))) + { + *pBlk = rWork.csBlock; + return rWork.sState; + } + } + + return U14ERR_DRIVCOMMS; +} + +/**************************************************************************** +** U14Control1401 Used for functions which pass data in and only expect +** an error code back +****************************************************************************/ +static short U14Control1401(short sHand, LONG lCode, TCSBLOCK* pBlk) +{ + DWORD dwBytes = 0; + + if ((sHand < 0) || (sHand >= MAX1401)) /* Check parameters */ + return U14ERR_BADHAND; + +#ifndef _WIN64 + if (!USE_NT_DIOC(sHand)) + { /* Windows 9x DIOC methods */ + if (DeviceIoControl(aHand1401[sHand], lCode, NULL, 0, pBlk, sizeof(TCSBLOCK), &dwBytes, NULL)) + return (short)(dwBytes >= sizeof(TCSBLOCK) ? U14ERR_NOERROR : U14ERR_DRIVCOMMS); + else + return (short)GetLastError(); + } + else +#endif + { /* Windows NT or later */ + PARAMBLK rWork; + rWork.sState = U14ERR_DRIVCOMMS; + if (DeviceIoControl(aHand1401[sHand], lCode, pBlk, sizeof(TCSBLOCK), &rWork, sizeof(PARAMBLK), &dwBytes, NULL) && + (dwBytes >= sizeof(PARAMBLK))) + return rWork.sState; + } + + return U14ERR_DRIVCOMMS; +} +#endif + +/**************************************************************************** +** SafeTickCount +** Gets time in approximately units of a millisecond. +*****************************************************************************/ +static long SafeTickCount() +{ +#ifdef _IS_WINDOWS_ + return GetTickCount(); +#endif +#ifdef LINUX + struct timeval tv; + gettimeofday(&tv, NULL); + return (tv.tv_sec*1000 + tv.tv_usec/1000); +#endif +} + +/**************************************************************************** +** A utility routine to get the command file extension for a given type +** of 1401. We assume the type code is vaguely legal. +****************************************************************************/ +static int ExtForType(short sType, char* szExt) +{ + szExt[0] = 0; /* Default return is a blank string */ + switch (sType) + { + case U14TYPE1401: strcpy(szExt, ".CMD"); break; // Standard 1401 + case U14TYPEPLUS: strcpy(szExt, ".GXC"); break; // 1401 plus + default: // All others are in a predictable sequence + strcpy(szExt, ".ARM"); + szExt[3] = (char)('M' + sType - U14TYPEU1401); + if (szExt[3] > 'Z') // Wrap round to ARA after ARZ + szExt[3] = (char)(szExt[3] - 26); + } + return 0; +} + +/**************************************************************************** +** U14WhenToTimeOut +** Returns the time to time out in time units suitable for the machine +** we are running on ie millsecs for pc/linux, or Mac/ +****************************************************************************/ +U14API(int) U14WhenToTimeOut(short hand) +{ + int iNow = SafeTickCount(); + if ((hand >= 0) && (hand < MAX1401)) + iNow += alTimeOutPeriod[hand]; + return iNow; +} + +/**************************************************************************** +** U14PassedTime +** Returns non zero if the timed passed in has been passed 0 if not +****************************************************************************/ +U14API(short) U14PassedTime(int lCheckTime) +{ + return (short)((SafeTickCount()-lCheckTime) > 0); +} + +/**************************************************************************** +** TranslateString +** Tidies up string that U14GetString returns. Converts all the commas in a +** string to spaces. Removes terminating CR character. May do more in future. +****************************************************************************/ +static void TranslateString(char* pStr) +{ + int i = 0; + while (pStr[i]) + { + if (pStr[i] == ',') + pStr[i] = ' '; /* convert comma to space */ + ++i; + } + + if ((i > 0) && (pStr[i-1] == '\n')) /* kill terminating LF */ + pStr[i-1] = (char)0; +} + +/**************************************************************************** +** U14StrToLongs +** Converts a string to an array of longs and returns the number of values +****************************************************************************/ +U14API(short) U14StrToLongs(const char* pszBuff, U14LONG *palNums, short sMaxLongs) +{ + WORD wChInd = 0; // index into source + short sLgInd = 0; // index into result longs + + while (pszBuff[wChInd] && // until we get to end of string... + (sLgInd < sMaxLongs)) // ...or filled the buffer + { + // Why not use a C Library converter? + switch (pszBuff[wChInd]) + { + case '-': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + BOOL bDone = FALSE; // true at end of number + int iSign = 1; // sign of number + long lValue = 0; + + while ((!bDone) && pszBuff[wChInd]) + { + switch (pszBuff[wChInd]) + { + case '-': + iSign = -1; // swap sign + break; + + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + lValue *= 10; // move to next digit base 10 + lValue += ((int)pszBuff[wChInd]-(int)'0'); + break; + + default: // end of number + bDone = TRUE; + break; + } + wChInd++; // move onto next character + } + palNums[sLgInd] = lValue * iSign; + sLgInd++; + } + break; + + default: + wChInd++; // look at next char + break; + } + } + return (sLgInd); +} + + +/**************************************************************************** +** U14LongsFrom1401 +** Gets the next waiting line from the 1401 and converts it longs +** Returns the number of numbers read or an error. +****************************************************************************/ +U14API(short) U14LongsFrom1401(short hand, U14LONG *palBuff, short sMaxLongs) +{ + char szWork[MAXSTRLEN]; + short sResult = U14GetString(hand, szWork, MAXSTRLEN);/* get reply from 1401 */ + if (sResult == U14ERR_NOERROR) /* if no error convert */ + sResult = U14StrToLongs(szWork, palBuff, sMaxLongs); + return sResult; +} + +/**************************************************************************** +** U14CheckErr +** Sends the ERR command to the 1401 and gets the result. Returns 0, a +** negative error code, or the first error value. +****************************************************************************/ +U14API(short) U14CheckErr(short hand) +{ + short sResult = U14SendString(hand, ";ERR;"); + if (sResult == U14ERR_NOERROR) + { + U14LONG er[3]; + sResult = U14LongsFrom1401(hand, er, 3); + if (sResult > 0) + { + sResult = (short)er[0]; /* Either zero or an error value */ +#ifdef _DEBUG + if (er[0] != 0) + { + char szMsg[50]; + sprintf(szMsg, "U14CheckErr returned %d,%d\n", er[0], er[1]); + OutputDebugString(szMsg); + } +#endif + } + else + { + if (sResult == 0) + sResult = U14ERR_TIMEOUT; /* No numbers equals timeout */ + } + } + + return sResult; +} + +/**************************************************************************** +** U14LastErrCode +** Returns the last code from the driver. This is for Windows where all calls +** go through the Control and Status routines, so we can save any error. +****************************************************************************/ +U14API(short) U14LastErrCode(short hand) +{ + if ((hand < 0) || (hand >= MAX1401)) + return U14ERR_BADHAND; + return asLastRetCode[hand]; +} + +/**************************************************************************** +** U14SetTimeout +** Set the timeout period for 1401 comms in milliseconds +****************************************************************************/ +U14API(void) U14SetTimeout(short hand, int lTimeOut) +{ + if ((hand < 0) || (hand >= MAX1401)) + return; + alTimeOutPeriod[hand] = lTimeOut; +} + +/**************************************************************************** +** U14GetTimeout +** Get the timeout period for 1401 comms in milliseconds +****************************************************************************/ +U14API(int) U14GetTimeout(short hand) +{ + if ((hand < 0) || (hand >= MAX1401)) + return U14ERR_BADHAND; + return alTimeOutPeriod[hand]; +} + +/**************************************************************************** +** U14OutBufSpace +** Return the space in the output buffer, or an error. +****************************************************************************/ +U14API(short) U14OutBufSpace(short hand) +{ +#ifdef _IS_WINDOWS_ + TCSBLOCK csBlock; + short sErr = U14Status1401(hand, U14_GETOUTBUFSPACE,&csBlock); + if (sErr == U14ERR_NOERROR) + sErr = csBlock.ints[0]; + return sErr; +#endif +#ifdef LINUX + short sErr = CheckHandle(hand); + return (sErr == U14ERR_NOERROR) ? CED_GetOutBufSpace(aHand1401[hand]) : sErr; +#endif +} + + +/**************************************************************************** +** U14BaseAddr1401 +** Returns the 1401 base address or an error code. Meaningless nowadays +****************************************************************************/ +U14API(int) U14BaseAddr1401(short hand) +{ +#ifdef _IS_WINDOWS_ + TCSBLOCK csBlock; + int iError = U14Status1401(hand, U14_GETBASEADDRESS,&csBlock); + if (iError == U14ERR_NOERROR) + iError = csBlock.longs[0]; + return iError; +#endif +#ifdef LINUX + short sErr = CheckHandle(hand); + return (sErr == U14ERR_NOERROR) ? CED_GetBaseAddress(aHand1401[hand]) : sErr; +#endif +} + +/**************************************************************************** +** U14StateOf1401 +** Return error state, either NOERROR or a negative code. +****************************************************************************/ +U14API(short) U14StateOf1401(short hand) +{ +#ifdef _IS_WINDOWS_ + TCSBLOCK csBlock; + short sErr = U14Status1401(hand, U14_STATEOF1401, &csBlock); + if (sErr == U14ERR_NOERROR) + { + sErr = csBlock.ints[0]; // returned 1401 state + if ((sErr >= DRIVRET_STD) && (sErr <= DRIVRET_MAX)) + sErr = U14ERR_NOERROR; + } +#endif +#ifdef LINUX + short sErr = CheckHandle(hand); + if (sErr == U14ERR_NOERROR) + { + sErr = (short)CED_StateOf1401(aHand1401[hand]); + if ((sErr >= DRIVRET_STD) && (sErr <= DRIVRET_MAX)) + sErr = U14ERR_NOERROR; + } +#endif + return sErr; +} + +/**************************************************************************** +** U14DriverVersion +** Returns the driver version. Hi word is major revision, low word is minor. +** If you pass in a silly handle (like -1), we return the version of the last +** driver we know of (to cope with PCI and no 1401 attached). +****************************************************************************/ +U14API(int) U14DriverVersion(short hand) +{ + return CheckHandle(hand) != U14ERR_NOERROR ? lLastDriverVersion : alDriverVersion[hand]; +} + +/**************************************************************************** +** U14DriverType +** Returns the driver type. The type, 0=ISA/NU-Bus, 1=PCI, 2=USB, 3=HSS +** If you pass in a silly handle (like -1), we return the type of the last +** driver we know of (to cope with PCI and no 1401 attached). +****************************************************************************/ +U14API(int) U14DriverType(short hand) +{ + return CheckHandle(hand) != U14ERR_NOERROR ? lLastDriverType : asDriverType[hand]; +} + +/**************************************************************************** +** U14DriverName +** Returns the driver type as 3 character (ISA, PCI, USB or HSS)) +****************************************************************************/ +U14API(short) U14DriverName(short hand, char* pBuf, WORD wMax) +{ + char* pName; + *pBuf = 0; // Start off with a blank string + switch (U14DriverType(hand)) // Results according to type + { + case 0: pName = "ISA"; break; + case 1: pName = "PCI"; break; + case 2: pName = "USB"; break; + case 3: pName = "HSS"; break; + default: pName = "???"; break; + } + strncpy(pBuf, pName, wMax); // Copy the correct name to return + + return U14ERR_NOERROR; +} + +/**************************************************************************** +** U14BlkTransState +** Returns 0 no transfer in progress, 1 transfer in progress or an error code +****************************************************************************/ +U14API(short) U14BlkTransState(short hand) +{ +#ifdef _IS_WINDOWS_ + TCSBLOCK csBlock; + short sErr = U14Status1401(hand, U14_BLKTRANSSTATE, &csBlock); + if (sErr == U14ERR_NOERROR) + sErr = csBlock.ints[0]; + return sErr; +#endif +#ifdef LINUX + short sErr = CheckHandle(hand); + return (sErr == U14ERR_NOERROR) ? CED_BlkTransState(aHand1401[hand]) : sErr; +#endif +} + +/**************************************************************************** +** U14Grab1401 +** Take control of the 1401 for diagnostics purposes. USB does nothing. +****************************************************************************/ +U14API(short) U14Grab1401(short hand) +{ + short sErr = CheckHandle(hand); + if (sErr == U14ERR_NOERROR) + { +#ifdef _IS_WINDOWS_ + if (abGrabbed[hand]) // 1401 should not have been grabbed + sErr = U14ERR_ALREADYSET; // Error code defined for this + else + { + TCSBLOCK csBlock; + sErr = U14Control1401(hand, U14_GRAB1401, &csBlock); + } +#endif +#ifdef LINUX + // 1401 should not have been grabbed + sErr = abGrabbed[hand] ? U14ERR_ALREADYSET : CED_Grab1401(aHand1401[hand]); +#endif + if (sErr == U14ERR_NOERROR) + abGrabbed[hand] = TRUE; + } + return sErr; +} + +/**************************************************************************** +** U14Free1401 +****************************************************************************/ +U14API(short) U14Free1401(short hand) +{ + short sErr = CheckHandle(hand); + if (sErr == U14ERR_NOERROR) + { +#ifdef _IS_WINDOWS_ + if (abGrabbed[hand]) // 1401 should have been grabbed + { + TCSBLOCK csBlock; + sErr = U14Control1401(hand, U14_FREE1401, &csBlock); + } + else + sErr = U14ERR_NOTSET; +#endif +#ifdef LINUX + // 1401 should not have been grabbed + sErr = abGrabbed[hand] ? CED_Free1401(aHand1401[hand]) : U14ERR_NOTSET; +#endif + if (sErr == U14ERR_NOERROR) + abGrabbed[hand] = FALSE; + } + return sErr; +} + +/**************************************************************************** +** U14Peek1401 +** DESCRIPTION Cause the 1401 to do one or more peek operations. +** If lRepeats is zero, the loop will continue until U14StopDebugLoop +** is called. After the peek is done, use U14GetDebugData to retrieve +** the results of the peek. +****************************************************************************/ +U14API(short) U14Peek1401(short hand, DWORD dwAddr, int nSize, int nRepeats) +{ + short sErr = CheckHandle(hand); + if (sErr == U14ERR_NOERROR) + { + if (abGrabbed[hand]) // 1401 should have been grabbed + { +#ifdef _IS_WINDOWS_ + TCSBLOCK csBlock; + csBlock.longs[0] = (long)dwAddr; + csBlock.longs[1] = nSize; + csBlock.longs[2] = nRepeats; + sErr = U14Control1401(hand, U14_DBGPEEK, &csBlock); +#endif +#ifdef LINUX + TDBGBLOCK dbb; + dbb.iAddr = (int)dwAddr; + dbb.iWidth = nSize; + dbb.iRepeats = nRepeats; + sErr = CED_DbgPeek(aHand1401[hand], &dbb); +#endif + } + else + sErr = U14ERR_NOTSET; + } + return sErr; +} + +/**************************************************************************** +** U14Poke1401 +** DESCRIPTION Cause the 1401 to do one or more poke operations. +** If lRepeats is zero, the loop will continue until U14StopDebugLoop +** is called. +****************************************************************************/ +U14API(short) U14Poke1401(short hand, DWORD dwAddr, DWORD dwValue, + int nSize, int nRepeats) +{ + short sErr = CheckHandle(hand); + if (sErr == U14ERR_NOERROR) + { + if (abGrabbed[hand]) // 1401 should have been grabbed + { +#ifdef _IS_WINDOWS_ + TCSBLOCK csBlock; + csBlock.longs[0] = (long)dwAddr; + csBlock.longs[1] = nSize; + csBlock.longs[2] = nRepeats; + csBlock.longs[3] = (long)dwValue; + sErr = U14Control1401(hand, U14_DBGPOKE, &csBlock); +#endif +#ifdef LINUX + TDBGBLOCK dbb; + dbb.iAddr = (int)dwAddr; + dbb.iWidth = nSize; + dbb.iRepeats= nRepeats; + dbb.iData = (int)dwValue; + sErr = CED_DbgPoke(aHand1401[hand], &dbb); +#endif + } + else + sErr = U14ERR_NOTSET; + } + return sErr; +} + +/**************************************************************************** +** U14Ramp1401 +** DESCRIPTION Cause the 1401 to loop, writing a ramp to a location. +** If lRepeats is zero, the loop will continue until U14StopDebugLoop. +****************************************************************************/ +U14API(short) U14Ramp1401(short hand, DWORD dwAddr, DWORD dwDef, DWORD dwEnable, + int nSize, int nRepeats) +{ + short sErr = CheckHandle(hand); + if (sErr == U14ERR_NOERROR) + { + if (abGrabbed[hand]) // 1401 should have been grabbed + { +#ifdef _IS_WINDOWS_ + TCSBLOCK csBlock; + csBlock.longs[0] = (long)dwAddr; + csBlock.longs[1] = (long)dwDef; + csBlock.longs[2] = (long)dwEnable; + csBlock.longs[3] = nSize; + csBlock.longs[4] = nRepeats; + sErr = U14Control1401(hand, U14_DBGRAMPDATA, &csBlock); +#endif +#ifdef LINUX + TDBGBLOCK dbb; + dbb.iAddr = (int)dwAddr; + dbb.iDefault = (int)dwDef; + dbb.iMask = (int)dwEnable; + dbb.iWidth = nSize; + dbb.iRepeats = nRepeats; + sErr = CED_DbgRampAddr(aHand1401[hand], &dbb); +#endif + } + else + sErr = U14ERR_NOTSET; + } + return sErr; +} + +/**************************************************************************** +** U14RampAddr +** DESCRIPTION Cause the 1401 to loop, reading from a ramping location. +** If lRepeats is zero, the loop will continue until U14StopDebugLoop +****************************************************************************/ +U14API(short) U14RampAddr(short hand, DWORD dwDef, DWORD dwEnable, + int nSize, int nRepeats) +{ + short sErr = CheckHandle(hand); + if (sErr == U14ERR_NOERROR) + { + if (abGrabbed[hand]) // 1401 should have been grabbed + { +#ifdef _IS_WINDOWS_ + TCSBLOCK csBlock; + csBlock.longs[0] = (long)dwDef; + csBlock.longs[1] = (long)dwEnable; + csBlock.longs[2] = nSize; + csBlock.longs[3] = nRepeats; + sErr = U14Control1401(hand, U14_DBGRAMPADDR, &csBlock); +#endif +#ifdef LINUX + TDBGBLOCK dbb; + dbb.iDefault = (int)dwDef; + dbb.iMask = (int)dwEnable; + dbb.iWidth = nSize; + dbb.iRepeats = nRepeats; + sErr = CED_DbgRampAddr(aHand1401[hand], &dbb); +#endif + } + else + sErr = U14ERR_NOTSET; + } + return sErr; +} + +/**************************************************************************** +** U14StopDebugLoop +** DESCRIPTION Stops a peek\poke\ramp that, with repeats set to zero, +** will otherwise continue forever. +****************************************************************************/ +U14API(short) U14StopDebugLoop(short hand) +{ + short sErr = CheckHandle(hand); + if (sErr == U14ERR_NOERROR) +#ifdef _IS_WINDOWS_ + { + if (abGrabbed[hand]) // 1401 should have been grabbed + { + TCSBLOCK csBlock; + sErr = U14Control1401(hand, U14_DBGSTOPLOOP, &csBlock); + } + else + sErr = U14ERR_NOTSET; + } +#endif +#ifdef LINUX + sErr = abGrabbed[hand] ? CED_DbgStopLoop(aHand1401[hand]) : U14ERR_NOTSET; +#endif + return sErr; +} + +/**************************************************************************** +** U14GetDebugData +** DESCRIPTION Returns the result from a previous peek operation. +****************************************************************************/ +U14API(short) U14GetDebugData(short hand, U14LONG* plValue) +{ + short sErr = CheckHandle(hand); + if (sErr == U14ERR_NOERROR) + { + if (abGrabbed[hand]) // 1401 should have been grabbed + { +#ifdef _IS_WINDOWS_ + TCSBLOCK csBlock; + sErr = U14Status1401(hand, U14_DBGGETDATA, &csBlock); + if (sErr == U14ERR_NOERROR) + *plValue = csBlock.longs[0]; // Return the data +#endif +#ifdef LINUX + TDBGBLOCK dbb; + sErr = CED_DbgGetData(aHand1401[hand], &dbb); + if (sErr == U14ERR_NOERROR) + *plValue = dbb.iData; /* Return the data */ +#endif + } + else + sErr = U14ERR_NOTSET; + } + return sErr; +} + +/**************************************************************************** +** U14StartSelfTest +****************************************************************************/ +U14API(short) U14StartSelfTest(short hand) +{ +#ifdef _IS_WINDOWS_ + TCSBLOCK csBlock; + return U14Control1401(hand, U14_STARTSELFTEST, &csBlock); +#endif +#ifdef LINUX + short sErr = CheckHandle(hand); + return (sErr == U14ERR_NOERROR) ? CED_StartSelfTest(aHand1401[hand]) : sErr; +#endif +} + +/**************************************************************************** +** U14CheckSelfTest +****************************************************************************/ +U14API(short) U14CheckSelfTest(short hand, U14LONG *pData) +{ +#ifdef _IS_WINDOWS_ + TCSBLOCK csBlock; + short sErr = U14Status1401(hand, U14_CHECKSELFTEST, &csBlock); + if (sErr == U14ERR_NOERROR) + { + pData[0] = csBlock.longs[0]; /* Return the results to user */ + pData[1] = csBlock.longs[1]; + pData[2] = csBlock.longs[2]; + } +#endif +#ifdef LINUX + short sErr = CheckHandle(hand); + if (sErr == U14ERR_NOERROR) /* Check parameters */ + { + TGET_SELFTEST gst; + sErr = CED_CheckSelfTest(aHand1401[hand], &gst); + if (sErr == U14ERR_NOERROR) + { + pData[0] = gst.code; /* Return the results to user */ + pData[1] = gst.x; + pData[2] = gst.y; + } + } +#endif + return sErr; +} + +/**************************************************************************** +** U14GetUserMemorySize +****************************************************************************/ +U14API(short) U14GetUserMemorySize(short hand, DWORD *pMemorySize) +{ + // The original 1401 used a different command for getting the size + short sErr = U14SendString(hand, (asType1401[hand] == U14TYPE1401) ? "MEMTOP;" : "MEMTOP,?;"); + *pMemorySize = 0; /* if we get error then leave size set at 0 */ + if (sErr == U14ERR_NOERROR) + { + U14LONG alLimits[4]; + sErr = U14LongsFrom1401(hand, alLimits, 4); + if (sErr > 0) /* +ve sErr is the number of values read */ + { + sErr = U14ERR_NOERROR; /* All OK, flag success */ + if (asType1401[hand] == U14TYPE1401) /* result for standard */ + *pMemorySize = alLimits[0] - alLimits[1]; /* memtop-membot */ + else + *pMemorySize = alLimits[0]; /* result for plus or u1401 */ + } + } + return sErr; +} + +/**************************************************************************** +** U14TypeOf1401 +** Returns the type of the 1401, maybe unknown +****************************************************************************/ +U14API(short) U14TypeOf1401(short hand) +{ + if ((hand < 0) || (hand >= MAX1401)) /* Check parameters */ + return U14ERR_BADHAND; + else + return asType1401[hand]; +} + +/**************************************************************************** +** U14NameOf1401 +** Returns the type of the 1401 as a string, blank if unknown +****************************************************************************/ +U14API(short) U14NameOf1401(short hand, char* pBuf, WORD wMax) +{ + short sErr = CheckHandle(hand); + if (sErr == U14ERR_NOERROR) + { + char* pName; + switch (asType1401[hand]) // Results according to type + { + case U14TYPE1401: pName = "Std 1401"; break; + case U14TYPEPLUS: pName = "1401plus"; break; + case U14TYPEU1401: pName = "micro1401"; break; + case U14TYPEPOWER: pName = "Power1401"; break; + case U14TYPEU14012:pName = "Micro1401 mk II"; break; + case U14TYPEPOWER2:pName = "Power1401 mk II"; break; + case U14TYPEU14013:pName = "Micro1401-3"; break; + case U14TYPEPOWER3:pName = "Power1401-3"; break; + default: pName = "Unknown"; + } + strncpy(pBuf, pName, wMax); + } + return sErr; +} + +/**************************************************************************** +** U14TransferFlags +** Returns the driver block transfer flags. +** Bits can be set - see U14TF_ constants in use1401.h +*****************************************************************************/ +U14API(short) U14TransferFlags(short hand) +{ +#ifdef _IS_WINDOWS_ + TCSBLOCK csBlock; + short sErr = U14Status1401(hand, U14_TRANSFERFLAGS, &csBlock); + return (sErr == U14ERR_NOERROR) ? (short)csBlock.ints[0] : sErr; +#endif +#ifdef LINUX + short sErr = CheckHandle(hand); + return (sErr == U14ERR_NOERROR) ? CED_TransferFlags(aHand1401[hand]) : sErr; +#endif +} + +/**************************************************************************** +** GetDriverVersion +** Actually reads driver version from the device driver. +** Hi word is major revision, low word is minor revision. +** Assumes that hand has been checked. Also codes driver type in bits 24 up. +*****************************************************************************/ +static int GetDriverVersion(short hand) +{ +#ifdef _IS_WINDOWS_ + TCSBLOCK csBlock; + int iErr = U14Status1401(hand, U14_GETDRIVERREVISION, &csBlock); + if (iErr == U14ERR_NOERROR) + iErr = csBlock.longs[0]; + return iErr; +#endif +#ifdef LINUX + return CED_GetDriverRevision(aHand1401[hand]); +#endif +} + +/**************************************************************************** +** U14MonitorRev +** Returns the 1401 monitor revision number. +** The number returned is the minor revision - the part after the +** decimal point - plus the major revision times 1000. +*****************************************************************************/ +U14API(int) U14MonitorRev(short hand) +{ + int iRev = 0; + int iErr = CheckHandle(hand); + if (iErr != U14ERR_NOERROR) // Check open and in use + return iErr; + + if (asType1401[hand] >= U14TYPEPOWER2) // The Power2 onwards can give us the monitor + { // revision directly for all versions + iErr = U14SendString(hand, "INFO,S,28;"); + if (iErr == U14ERR_NOERROR) + { + U14LONG lVals[2]; // Read a single number being the revision + iErr = U14LongsFrom1401(hand, lVals, 1); + if (iErr > 0) + { + iErr = U14ERR_NOERROR; + iRev = lVals[0]; // This is the minor part of the revision + iRev += asType1401[hand] * 10000; + } + } + } + else + { /* Do it the hard way for older hardware */ + iErr = U14SendString(hand, ";CLIST;"); /* ask for command levels */ + if (iErr == U14ERR_NOERROR) + { + while (iErr == U14ERR_NOERROR) + { + char wstr[50]; + iErr = U14GetString(hand, wstr, 45); + if (iErr == U14ERR_NOERROR) + { + char *pstr = strstr(wstr,"RESET"); /* Is this the RESET command? */ + if ((pstr == wstr) && (wstr[5] == ' ')) + { + char *pstr2; + size_t l; + pstr += 6; /* Move past RESET and followinmg char */ + l = strlen(pstr); /* The length of text remaining */ + while (((pstr[l-1] == ' ') || (pstr[l-1] == 13)) && (l > 0)) + { + pstr[l-1] = 0; /* Tidy up string at the end */ + l--; /* by removing spaces and CRs */ + } + pstr2 = strchr(pstr, '.'); /* Find the decimal point */ + if (pstr2 != NULL) /* If we found the DP */ + { + *pstr2 = 0; /* End pstr string at DP */ + pstr2++; /* Now past the decimal point */ + iRev = atoi(pstr2); /* Get the number after point */ + } + iRev += (atoi(pstr) * 1000); /* Add first bit * 1000 */ + } + if ((strlen(wstr) < 3) && (wstr[0] == ' ')) + break; /* Spot the last line of results */ + } + } + } + } + if (iErr == U14ERR_NOERROR) /* Return revision if no error */ + iErr = iRev; + + return iErr; +} + +/**************************************************************************** +** U14TryToOpen Tries to open the 1401 number passed +** Note : This will succeed with NT driver even if no I/F card or +** 1401 switched off, so we check state and close the driver +** if the state is unsatisfactory in U14Open1401. +****************************************************************************/ +#ifdef _IS_WINDOWS_ +#define U14NAMEOLD "\\\\.\\CED_140%d" +#define U14NAMENEW "\\\\.\\CED%d" +static short U14TryToOpen(int n1401, long* plRetVal, short* psHandle) +{ + short sErr = U14ERR_NOERROR; + HANDLE hDevice = INVALID_HANDLE_VALUE; + DWORD dwErr = 0; + int nFirst, nLast, nDev = 0; /* Used for the search for a 1401 */ + BOOL bOldName = FALSE; /* start by looking for a modern driver */ + + if (n1401 == 0) /* If we need to look for a 1401 */ + { + nFirst = 1; /* Set the search range */ + nLast = MAX1401; /* through all the possible 1401s */ + } + else + nFirst = nLast = n1401; /* Otherwise just one 1401 */ + + while (hDevice == INVALID_HANDLE_VALUE) /* Loop to try for a 1401 */ + { + for (nDev = nFirst; nDev <= nLast; nDev++) + { + char szDevName[40]; /* name of the device to open */ + sprintf(szDevName, bOldName ? U14NAMEOLD : U14NAMENEW, nDev); + hDevice = CreateFile(szDevName, GENERIC_WRITE | GENERIC_READ, + 0, 0, /* Unshared mode does nothing as this is a device */ + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + + if (hDevice != INVALID_HANDLE_VALUE)/* Check 1401 if opened */ + { + TCSBLOCK csBlock; + assert(aHand1401[nDev-1] == INVALID_HANDLE_VALUE); // assert if already open + aHand1401[nDev-1] = hDevice; /* Save handle for now */ + +#ifndef _WIN64 + // Use DIOC method if not windows 9x or if using new device name + abUseNTDIOC[nDev-1] = (BOOL)(!bWindows9x || !bOldName); +#endif + sErr = U14Status1401((short)(nDev-1), U14_TYPEOF1401, &csBlock); + if (sErr == U14ERR_NOERROR) + { + *plRetVal = csBlock.ints[0]; + if (csBlock.ints[0] == U14ERR_INUSE)/* Prevent multi opens */ + { + CloseHandle(hDevice); /* treat as open failure */ + hDevice = INVALID_HANDLE_VALUE; + aHand1401[nDev-1] = INVALID_HANDLE_VALUE; + sErr = U14ERR_INUSE; + } + else + break; /* Exit from for loop on success */ + } + else + { + CloseHandle(hDevice); /* Give up if func fails */ + hDevice = INVALID_HANDLE_VALUE; + aHand1401[nDev-1] = INVALID_HANDLE_VALUE; + } + } + else + { + DWORD dwe = GetLastError(); /* Get error code otherwise */ + if ((dwe != ERROR_FILE_NOT_FOUND) || (dwErr == 0)) + dwErr = dwe; /* Ignore repeats of 'not found' */ + } + } + + if ((hDevice == INVALID_HANDLE_VALUE) &&/* No device found, and... */ + (bWindows9x) && /* ...old names are allowed, and... */ + (bOldName == FALSE)) /* ...not tried old names yet */ + bOldName = TRUE; /* Set flag and go round again */ + else + break; /* otherwise that's all folks */ + } + + if (hDevice != INVALID_HANDLE_VALUE) /* If we got our device open */ + *psHandle = (short)(nDev-1); /* return 1401 number opened */ + else + { + if (dwErr == ERROR_FILE_NOT_FOUND) /* Sort out the error codes */ + sErr = U14ERR_NO1401DRIV; /* if file not found */ + else if (dwErr == ERROR_NOT_SUPPORTED) + sErr = U14ERR_DRIVTOOOLD; /* if DIOC not supported */ + else if (dwErr == ERROR_ACCESS_DENIED) + sErr = U14ERR_INUSE; + else + sErr = U14ERR_DRIVCOMMS; /* otherwise assume comms problem */ + } + return sErr; +} +#endif +#ifdef LINUX +static short U14TryToOpen(int n1401, long* plRetVal, short* psHandle) +{ + short sErr = U14ERR_NOERROR; + int fh = 0; // will be 1401 handle + int iErr = 0; + int nFirst, nLast, nDev = 0; // Used for the search for a 1401 + + if (n1401 == 0) // If we need to look for a 1401 + { + nFirst = 1; /* Set the search range */ + nLast = MAX1401; /* through all the possible 1401s */ + } + else + nFirst = nLast = n1401; /* Otherwise just one 1401 */ + + for (nDev = nFirst; nDev <= nLast; nDev++) + { + char szDevName[40]; // name of the device to open + sprintf(szDevName,"/dev/cedusb/%d", nDev-1); + fh = open(szDevName, O_RDWR); // can only be opened once at a time + if (fh > 0) // Check 1401 if opened + { + int iType1401 = CED_TypeOf1401(fh); // get 1401 type + aHand1401[nDev-1] = fh; // Save handle for now + if (iType1401 >= 0) + { + *plRetVal = iType1401; + break; // Exit from for loop on success + } + else + { + close(fh); // Give up if func fails + fh = 0; + aHand1401[nDev-1] = 0; + } + } + else + { + if (((errno != ENODEV) && (errno != ENOENT)) || (iErr == 0)) + iErr = errno; // Ignore repeats of 'not found' + } + } + + + if (fh) // If we got our device open + *psHandle = (short)(nDev-1); // return 1401 number opened + else + { + if ((iErr == ENODEV) || (iErr == ENOENT)) // Sort out the error codes + sErr = U14ERR_NO1401DRIV; // if file not found + else if (iErr == EBUSY) + sErr = U14ERR_INUSE; + else + sErr = U14ERR_DRIVCOMMS; // otherwise assume comms problem + } + + return sErr; +} +#endif +/**************************************************************************** +** U14Open1401 +** Tries to get the 1401 for use by this application +*****************************************************************************/ +U14API(short) U14Open1401(short n1401) +{ + long lRetVal = -1; + short sErr; + short hand = 0; + + if ((n1401 < 0) || (n1401 > MAX1401)) // must check the 1401 number + return U14ERR_BAD1401NUM; + + szLastName[0] = 0; /* initialise the error info string */ + + sErr = U14TryToOpen(n1401, &lRetVal, &hand); + if (sErr == U14ERR_NOERROR) + { + long lDriverVersion = GetDriverVersion(hand); /* get driver revision */ + long lDriverRev = -1; + if (lDriverVersion >= 0) /* can use it if all OK */ + { + lLastDriverType = (lDriverVersion >> 24) & 0x000000FF; + asDriverType[hand] = (short)lLastDriverType; /* Drv type */ + lLastDriverVersion = lDriverVersion & 0x00FFFFFF; + alDriverVersion[hand] = lLastDriverVersion; /* Actual version */ + lDriverRev = ((lDriverVersion>>16) & 0x00FF); /* use hi word */ + } + else + { + U14Close1401(hand); /* If there is a problem we should close */ + return (short)lDriverVersion; /* and return the error code */ + } + + if (lDriverRev < MINDRIVERMAJREV) /* late enough version? */ + { + U14Close1401(hand); /* If there is a problem we should close */ + return U14ERR_DRIVTOOOLD; /* too old */ + } + + asLastRetCode[hand] = U14ERR_NOERROR; /* Initialise this 1401s info */ + abGrabbed[hand] = FALSE; /* we are not in single step mode */ + U14SetTimeout(hand, 3000); /* set 3 seconds as default timeout */ + + switch (lRetVal) + { + case DRIVRET_STD: asType1401[hand] = U14TYPE1401; break; /* Some we do by hand */ + case DRIVRET_U1401:asType1401[hand] = U14TYPEU1401; break; + case DRIVRET_PLUS: asType1401[hand] = U14TYPEPLUS; break; + default: // For the power upwards, we can calculate the codes + if ((lRetVal >= DRIVRET_POWER) && (lRetVal <= DRIVRET_MAX)) + asType1401[hand] = (short)(lRetVal - (DRIVRET_POWER - U14TYPEPOWER)); + else + asType1401[hand] = U14TYPEUNKNOWN; + break; + } + U14KillIO1401(hand); /* resets the 1401 buffers */ + + if (asType1401[hand] != U14TYPEUNKNOWN) /* If all seems OK so far */ + { + sErr = U14CheckErr(hand); /* we can check 1401 comms now */ + if (sErr != 0) /* If this failed to go OK */ + U14Reset1401(hand); /* Reset the 1401 to try to sort it out */ + } + + sErr = U14StateOf1401(hand);/* Get the state of the 1401 for return */ + if (sErr == U14ERR_NOERROR) + sErr = hand; /* return the handle if no problem */ + else + U14Close1401(hand); /* If there is a problem we should close */ + } + + return sErr; +} + + +/**************************************************************************** +** U14Close1401 +** Closes the 1401 so someone else can use it. +****************************************************************************/ +U14API(short) U14Close1401(short hand) +{ + int j; + int iAreaMask = 0; // Mask for active areas + short sErr = CheckHandle(hand); + if (sErr != U14ERR_NOERROR) // Check open and in use + return sErr; + + for (j = 0; j<MAX_TRANSAREAS; ++j) + { + TGET_TX_BLOCK gtb; + int iReturn = U14GetTransfer(hand, >b); // get area information + if (iReturn == U14ERR_NOERROR) // ignore if any problem + if (gtb.used) + iAreaMask |= (1 << j); // set a bit for each used area + } + + if (iAreaMask) // if any areas are in use + { + U14Reset1401(hand); // in case an active transfer running + for (j = 0; j < MAX_TRANSAREAS; ++j) // Locate locked areas + if (iAreaMask & (1 << j)) // And kill off any transfers + U14UnSetTransfer(hand, (WORD)j); + } + +#ifdef _IS_WINDOWS_ + if (aXferEvent[hand]) // if this 1401 has an open event handle + { + CloseHandle(aXferEvent[hand]); // close down the handle + aXferEvent[hand] = NULL; // and mark it as gone + } + + if (CloseHandle(aHand1401[hand])) +#endif +#ifdef LINUX + if (close(aHand1401[hand]) == 0) // make sure that close works +#endif + { + aHand1401[hand] = INVALID_HANDLE_VALUE; + asType1401[hand] = U14TYPEUNKNOWN; + return U14ERR_NOERROR; + } + else + return U14ERR_BADHAND; /* BUGBUG GetLastError() ? */ +} + +/************************************************************************** +** +** Look for open 1401s and attempt to close them down. 32-bit windows only. +**************************************************************************/ +U14API(void) U14CloseAll(void) +{ + int i; + for (i = 0; i < MAX1401; i++) // Tidy up and make safe + if (aHand1401[i] != INVALID_HANDLE_VALUE) + U14Close1401((short)i); // Last ditch close 1401 +} + +/**************************************************************************** +** U14Reset1401 +** Resets the 1401 +****************************************************************************/ +U14API(short) U14Reset1401(short hand) +{ +#ifdef _IS_WINDOWS_ + TCSBLOCK csBlock; + return U14Control1401(hand, U14_RESET1401, &csBlock); +#endif +#ifdef LINUX + short sErr = CheckHandle(hand); + return (sErr == U14ERR_NOERROR) ? CED_Reset1401(aHand1401[hand]) : sErr; +#endif +} + +/**************************************************************************** +** U14ForceReset +** Sets the 1401 full reset flag, so that next call to Reset1401 will +** always cause a genuine reset. +*****************************************************************************/ +U14API(short) U14ForceReset(short hand) +{ +#ifdef _IS_WINDOWS_ + TCSBLOCK csBlock; + return U14Control1401(hand, U14_FULLRESET, &csBlock); +#endif +#ifdef LINUX + short sErr = CheckHandle(hand); + return (sErr == U14ERR_NOERROR) ? CED_FullReset(aHand1401[hand]) : sErr; +#endif +} + +/**************************************************************************** +** U14KillIO1401 +** Removes any pending IO from the buffers. +*****************************************************************************/ +U14API(short) U14KillIO1401(short hand) +{ +#ifdef _IS_WINDOWS_ + TCSBLOCK csBlock; + return U14Control1401(hand, U14_KILLIO1401, &csBlock); +#endif +#ifdef LINUX + short sErr = CheckHandle(hand); + return (sErr == U14ERR_NOERROR) ? CED_KillIO1401(aHand1401[hand]) : sErr; +#endif +} + + +/**************************************************************************** +** U14SendString +** Send characters to the 1401 +*****************************************************************************/ +U14API(short) U14SendString(short hand, const char* pString) +{ + int nChars; // length we are sending + long lTimeOutTicks; // when to time out + BOOL bSpaceToSend; // space to send yet + short sErr = CheckHandle(hand); + if (sErr != U14ERR_NOERROR) + return sErr; + + nChars = (int)strlen(pString); // get string length we want to send + if (nChars > MAXSTRLEN) + return U14ERR_STRLEN; // String too long + +#ifdef _IS_WINDOWS_ + // To get here we must wait for the buffer to have some space + lTimeOutTicks = U14WhenToTimeOut(hand); + do + { + bSpaceToSend = (BOOL)((long)U14OutBufSpace(hand) >= nChars); + } + while (!bSpaceToSend && !U14PassedTime(lTimeOutTicks)); + + if (!bSpaceToSend) /* Last-ditch attempt to avoid timeout */ + { /* This can happen with anti-virus or network activity! */ + int i; + for (i = 0; (i < 4) && (!bSpaceToSend); ++i) + { + Sleep(25); /* Give other threads a chance for a while */ + bSpaceToSend = (BOOL)((long)U14OutBufSpace(hand) >= nChars); + } + } + + if (asLastRetCode[hand] == U14ERR_NOERROR) /* no errors? */ + { + if (bSpaceToSend) + { + PARAMBLK rData; + DWORD dwBytes; + char tstr[MAXSTRLEN+5]; /* Buffer for chars */ + + if ((hand < 0) || (hand >= MAX1401)) + sErr = U14ERR_BADHAND; + else + { + strcpy(tstr, pString); /* Into local buf */ +#ifndef _WIN64 + if (!USE_NT_DIOC(hand)) /* Using WIN 95 driver access? */ + { + int iOK = DeviceIoControl(aHand1401[hand], (DWORD)U14_SENDSTRING, + NULL, 0, tstr, nChars, + &dwBytes, NULL); + if (iOK) + sErr = (dwBytes >= (DWORD)nChars) ? U14ERR_NOERROR : U14ERR_DRIVCOMMS; + else + sErr = (short)GetLastError(); + } + else +#endif + { + int iOK = DeviceIoControl(aHand1401[hand],(DWORD)U14_SENDSTRING, + tstr, nChars, + &rData,sizeof(PARAMBLK),&dwBytes,NULL); + if (iOK && (dwBytes >= sizeof(PARAMBLK))) + sErr = rData.sState; + else + sErr = U14ERR_DRIVCOMMS; + } + + if (sErr != U14ERR_NOERROR) // If we have had a comms error + U14ForceReset(hand); // make sure we get real reset + } + + return sErr; + + } + else + { + U14ForceReset(hand); // make sure we get real reset + return U14ERR_TIMEOUT; + } + } + else + return asLastRetCode[hand]; +#endif +#ifdef LINUX + // Just try to send it and see what happens! + sErr = CED_SendString(aHand1401[hand], pString, nChars); + if (sErr != U14ERR_NOOUT) // if any result except "no room in output"... + { + if (sErr != U14ERR_NOERROR) // if a problem... + U14ForceReset(hand); // ...make sure we get real reset next time + return sErr; // ... we are done as nothing we can do + } + + // To get here we must wait for the buffer to have some space + lTimeOutTicks = U14WhenToTimeOut(hand); + do + { + bSpaceToSend = (BOOL)((long)U14OutBufSpace(hand) >= nChars); + if (!bSpaceToSend) + sched_yield(); // let others have fun while we wait + } + while (!bSpaceToSend && !U14PassedTime(lTimeOutTicks)); + + if (asLastRetCode[hand] == U14ERR_NOERROR) /* no errors? */ + { + if (bSpaceToSend) + { + sErr = CED_SendString(aHand1401[hand], pString, nChars); + if (sErr != U14ERR_NOERROR) // If we have had a comms error + U14ForceReset(hand); // make sure we get real reset + return sErr; + } + else + { + U14ForceReset(hand); // make sure we get real reset + return U14ERR_TIMEOUT; + } + } + else + return asLastRetCode[hand]; +#endif +} + +/**************************************************************************** +** U14SendChar +** Send character to the 1401 +*****************************************************************************/ +U14API(short) U14SendChar(short hand, char cChar) +{ +#ifdef _IS_WINDOWS_ + char sz[2]=" "; // convert to a string and send + sz[0] = cChar; + sz[1] = 0; + return(U14SendString(hand, sz)); // String routines are better +#endif +#ifdef LINUX + short sErr = CheckHandle(hand); + return (sErr == U14ERR_NOERROR) ? CED_SendChar(aHand1401[hand], cChar) : sErr; +#endif +} + +/**************************************************************************** +** U14GetString +** Get a string from the 1401. Returns a null terminated string. +** The string is all the characters up to the next CR in the buffer +** or the end of the buffer if that comes first. This only returns text +** if there is a CR in the buffer. The terminating CR character is removed. +** wMaxLen Is the size of the buffer and must be at least 2 or an error. +** Returns U14ERR_NOERR if OK with the result in the string or a negative +** error code. Any error from the device causes us to set up for +** a full reset. +****************************************************************************/ +U14API(short) U14GetString(short hand, char* pBuffer, WORD wMaxLen) +{ + short sErr = CheckHandle(hand); + if (sErr != U14ERR_NOERROR) // If an error... + return sErr; // ...bail out! + +#ifdef _IS_WINDOWS_ + if (wMaxLen>1) // we need space for terminating 0 + { + BOOL bLineToGet; // true when a line to get + long lTimeOutTicks = U14WhenToTimeOut(hand); + do + bLineToGet = (BOOL)(U14LineCount(hand) != 0); + while (!bLineToGet && !U14PassedTime(lTimeOutTicks)); + + if (!bLineToGet) /* Last-ditch attempt to avoid timeout */ + { /* This can happen with anti-virus or network activity! */ + int i; + for (i = 0; (i < 4) && (!bLineToGet); ++i) + { + Sleep(25); /* Give other threads a chance for a while */ + bLineToGet = (BOOL)(U14LineCount(hand) != 0); + } + } + + if (bLineToGet) + { + if (asLastRetCode[hand] == U14ERR_NOERROR) /* all ok so far */ + { + DWORD dwBytes = 0; + *((WORD *)pBuffer) = wMaxLen; /* set up length */ +#ifndef _WIN64 + if (!USE_NT_DIOC(hand)) /* Win 95 DIOC here ? */ + { + char tstr[MAXSTRLEN+5]; /* Buffer for Win95 chars */ + int iOK; + + if (wMaxLen > MAXSTRLEN) /* Truncate length */ + wMaxLen = MAXSTRLEN; + + *((WORD *)tstr) = wMaxLen; /* set len */ + + iOK = DeviceIoControl(aHand1401[hand],(DWORD)U14_GETSTRING, + NULL, 0, tstr, wMaxLen+sizeof(short), + &dwBytes, NULL); + if (iOK) /* Device IO control OK ? */ + { + if (dwBytes >= 0) /* If driver OK */ + { + strcpy(pBuffer, tstr); + sErr = U14ERR_NOERROR; + } + else + sErr = U14ERR_DRIVCOMMS; + } + else + { + sErr = (short)GetLastError(); + if (sErr > 0) /* Errors are -ve */ + sErr = (short)-sErr; + } + } + else +#endif + { /* Here for NT, the DLL must own the buffer */ + HANDLE hMem = GlobalAlloc(GMEM_MOVEABLE,wMaxLen+sizeof(short)); + if (hMem) + { + char* pMem = (char*)GlobalLock(hMem); + if (pMem) + { + int iOK = DeviceIoControl(aHand1401[hand],(DWORD)U14_GETSTRING, + NULL, 0, pMem, wMaxLen+sizeof(short), + &dwBytes, NULL); + if (iOK) /* Device IO control OK ? */ + { + if (dwBytes >= wMaxLen) + { + strcpy(pBuffer, pMem+sizeof(short)); + sErr = *((SHORT*)pMem); + } + else + sErr = U14ERR_DRIVCOMMS; + } + else + sErr = U14ERR_DRIVCOMMS; + + GlobalUnlock(hMem); + } + else + sErr = U14ERR_OUTOFMEMORY; + + GlobalFree(hMem); + } + else + sErr = U14ERR_OUTOFMEMORY; + } + + if (sErr == U14ERR_NOERROR) // If all OK... + TranslateString(pBuffer); // ...convert any commas to spaces + else // If we have had a comms error... + U14ForceReset(hand); // ...make sure we get real reset + + } + else + sErr = asLastRetCode[hand]; + } + else + { + sErr = U14ERR_TIMEOUT; + U14ForceReset(hand); // make sure we get real reset + } + } + else + sErr = U14ERR_BUFF_SMALL; + return sErr; +#endif +#ifdef LINUX + if (wMaxLen>1) // we need space for terminating 0 + { + BOOL bLineToGet; // true when a line to get + long lTimeOutTicks = U14WhenToTimeOut(hand); + do + { + bLineToGet = (BOOL)(U14LineCount(hand) != 0); + if (!bLineToGet) + sched_yield(); + + } + while (!bLineToGet && !U14PassedTime(lTimeOutTicks)); + + if (bLineToGet) + { + sErr = CED_GetString(aHand1401[hand], pBuffer, wMaxLen-1); // space for terminator + if (sErr >=0) // if we were OK... + { + if (sErr >= wMaxLen) // this should NOT happen unless + sErr = U14ERR_DRIVCOMMS; // ...driver Comms are very bad + else + { + pBuffer[sErr] = 0; // OK, so terminate the string... + TranslateString(pBuffer); // ...and convert commas to spaces. + } + } + + if (sErr < U14ERR_NOERROR) // If we have had a comms error + U14ForceReset(hand); // make sure we get real reset + } + else + { + sErr = U14ERR_TIMEOUT; + U14ForceReset(hand); // make sure we get real reset + } + } + else + sErr = U14ERR_BUFF_SMALL; + + return sErr >= U14ERR_NOERROR ? U14ERR_NOERROR : sErr; +#endif +} + +/**************************************************************************** +** U14GetChar +** Get a character from the 1401. CR returned as CR. +*****************************************************************************/ +U14API(short) U14GetChar(short hand, char* pcChar) +{ +#ifdef _IS_WINDOWS_ + char sz[2]; // read a very short string + short sErr = U14GetString(hand, sz, 2); // read one char and nul terminate it + *pcChar = sz[0]; // copy to result, NB char translate done by GetString + if (sErr == U14ERR_NOERROR) + { // undo translate of CR to zero + if (*pcChar == '\0') // by converting back + *pcChar = '\n'; // What a nasty thing to have to do + } + return sErr; +#endif +#ifdef LINUX + short sErr = CheckHandle(hand); + if (sErr != U14ERR_NOERROR) // Check parameters + return sErr; + sErr = CED_GetChar(aHand1401[hand]); // get one char, if available + if (sErr >= 0) + { + *pcChar = (char)sErr; // return if it we have one + return U14ERR_NOERROR; // say all OK + } + else + return sErr; +#endif +} + +/**************************************************************************** +** U14Stat1401 +** Returns 0 for no lines or error or non zero for something waiting +****************************************************************************/ +U14API(short) U14Stat1401(short hand) +{ + return ((short)(U14LineCount(hand) > 0)); +} + +/**************************************************************************** +** U14CharCount +** Returns the number of characters in the input buffer +*****************************************************************************/ +U14API(short) U14CharCount(short hand) +{ +#ifdef _IS_WINDOWS_ + TCSBLOCK csBlock; + short sErr = U14Status1401(hand, U14_STAT1401, &csBlock); + if (sErr == U14ERR_NOERROR) + sErr = csBlock.ints[0]; + return sErr; +#endif +#ifdef LINUX + short sErr = CheckHandle(hand); + return (sErr == U14ERR_NOERROR) ? CED_Stat1401(aHand1401[hand]) : sErr; +#endif +} + +/**************************************************************************** +** U14LineCount +** Returns the number of CR characters in the input buffer +*****************************************************************************/ +U14API(short) U14LineCount(short hand) +{ +#ifdef _IS_WINDOWS_ + TCSBLOCK csBlock; + short sErr = U14Status1401(hand, U14_LINECOUNT, &csBlock); + if (sErr == U14ERR_NOERROR) + sErr = csBlock.ints[0]; + return sErr; +#endif +#ifdef LINUX + short sErr = CheckHandle(hand); + return (sErr == U14ERR_NOERROR) ? CED_LineCount(aHand1401[hand]) : sErr; +#endif +} + +/**************************************************************************** +** U14GetErrorString +** Converts error code supplied to a decent descriptive string. +** NOTE: This function may use some extra information stored +** internally in the DLL. This information is stored on a +** per-process basis, but it might be altered if you call +** other functions after getting an error and before using +** this function. +****************************************************************************/ +U14API(void) U14GetErrorString(short nErr, char* pStr, WORD wMax) +{ + char wstr[150]; + + switch (nErr) /* Basically, we do this with a switch block */ + { + case U14ERR_OFF: + sprintf(wstr, "The 1401 is apparently switched off (code %d)", nErr); + break; + + case U14ERR_NC: + sprintf(wstr, "The 1401 is not connected to the interface card (code %d)", nErr); + break; + + case U14ERR_ILL: + sprintf(wstr, "The 1401 is not working correctly (code %d)", nErr); + break; + + case U14ERR_NOIF: + sprintf(wstr, "The 1401 interface card was not detected (code %d)", nErr); + break; + + case U14ERR_TIME: + sprintf(wstr, "The 1401 fails to become ready for use (code %d)", nErr); + break; + + case U14ERR_BADSW: + sprintf(wstr, "The 1401 interface card jumpers are incorrect (code %d)", nErr); + break; + + case U14ERR_NOINT: + sprintf(wstr, "The 1401 interrupt is not available for use (code %d)", nErr); + break; + + case U14ERR_INUSE: + sprintf(wstr, "The 1401 is already in use by another program (code %d)", nErr); + break; + + case U14ERR_NODMA: + sprintf(wstr, "The 1401 DMA channel is not available for use (code %d)", nErr); + break; + + case U14ERR_BADHAND: + sprintf(wstr, "The application supplied an incorrect 1401 handle (code %d)", nErr); + break; + + case U14ERR_BAD1401NUM: + sprintf(wstr, "The application used an incorrect 1401 number (code %d)", nErr); + break; + + case U14ERR_NO_SUCH_FN: + sprintf(wstr, "The code passed to the 1401 driver is invalid (code %d)", nErr); + break; + + case U14ERR_NO_SUCH_SUBFN: + sprintf(wstr, "The sub-code passed to the 1401 driver is invalid (code %d)", nErr); + break; + + case U14ERR_NOOUT: + sprintf(wstr, "No room in buffer for characters for the 1401 (code %d)", nErr); + break; + + case U14ERR_NOIN: + sprintf(wstr, "No characters from the 1401 are available (code %d)", nErr); + break; + + case U14ERR_STRLEN: + sprintf(wstr, "A string sent to or read from the 1401 was too long (code %d)", nErr); + break; + + case U14ERR_LOCKFAIL: + sprintf(wstr, "Failed to lock host memory for data transfer (code %d)", nErr); + break; + + case U14ERR_UNLOCKFAIL: + sprintf(wstr, "Failed to unlock host memory after data transfer (code %d)", nErr); + break; + + case U14ERR_ALREADYSET: + sprintf(wstr, "The transfer area used is already set up (code %d)", nErr); + break; + + case U14ERR_NOTSET: + sprintf(wstr, "The transfer area used has not been set up (code %d)", nErr); + break; + + case U14ERR_BADAREA: + sprintf(wstr, "The transfer area number is incorrect (code %d)", nErr); + break; + + case U14ERR_NOFILE: + sprintf(wstr, "The command file %s could not be opened (code %d)", szLastName, nErr); + break; + + case U14ERR_READERR: + sprintf(wstr, "The command file %s could not be read (code %d)", szLastName, nErr); + break; + + case U14ERR_UNKNOWN: + sprintf(wstr, "The %s command resource could not be found (code %d)", szLastName, nErr); + break; + + case U14ERR_HOSTSPACE: + sprintf(wstr, "Unable to allocate memory for loading command %s (code %d)", szLastName, nErr); + break; + + case U14ERR_LOCKERR: + sprintf(wstr, "Unable to lock memory for loading command %s (code %d)", szLastName, nErr); + break; + + case U14ERR_CLOADERR: + sprintf(wstr, "Error in loading command %s, bad command format (code %d)", szLastName, nErr); + break; + + case U14ERR_TOXXXERR: + sprintf(wstr, "Error detected after data transfer to or from the 1401 (code %d)", nErr); + break; + + case U14ERR_NO386ENH: + sprintf(wstr, "Windows 3.1 is not running in 386 enhanced mode (code %d)", nErr); + break; + + case U14ERR_NO1401DRIV: + sprintf(wstr, "The 1401 device driver cannot be found (code %d)\nUSB: check plugged in and powered\nOther: not installed?", nErr); + break; + + case U14ERR_DRIVTOOOLD: + sprintf(wstr, "The 1401 device driver is too old for use (code %d)", nErr); + break; + + case U14ERR_TIMEOUT: + sprintf(wstr, "Character transmissions to the 1401 timed-out (code %d)", nErr); + break; + + case U14ERR_BUFF_SMALL: + sprintf(wstr, "Buffer for text from the 1401 was too small (code %d)", nErr); + break; + + case U14ERR_CBALREADY: + sprintf(wstr, "1401 monitor callback already set up (code %d)", nErr); + break; + + case U14ERR_BADDEREG: + sprintf(wstr, "1401 monitor callback deregister invalid (code %d)", nErr); + break; + + case U14ERR_DRIVCOMMS: + sprintf(wstr, "1401 device driver communications failed (code %d)", nErr); + break; + + case U14ERR_OUTOFMEMORY: + sprintf(wstr, "Failed to allocate or lock memory for text from the 1401 (code %d)", nErr); + break; + + default: + sprintf(wstr, "1401 error code %d returned; this code is unknown", nErr); + break; + + } + if ((WORD)strlen(wstr) >= wMax-1) /* Check for string being too long */ + wstr[wMax-1] = 0; /* and truncate it if so */ + strcpy(pStr, wstr); /* Return the error string */ +} + +/*************************************************************************** +** U14GetTransfer +** Get a TGET_TX_BLOCK describing a transfer area (held in the block) +***************************************************************************/ +U14API(short) U14GetTransfer(short hand, TGET_TX_BLOCK *pTransBlock) +{ + short sErr = CheckHandle(hand); +#ifdef _IS_WINDOWS_ + if (sErr == U14ERR_NOERROR) + { + DWORD dwBytes = 0; + BOOL bOK = DeviceIoControl(aHand1401[hand], (DWORD)U14_GETTRANSFER, NULL, 0, pTransBlock, + sizeof(TGET_TX_BLOCK), &dwBytes, NULL); + + if (bOK && (dwBytes >= sizeof(TGET_TX_BLOCK))) + sErr = U14ERR_NOERROR; + else + sErr = U14ERR_DRIVCOMMS; + } + return sErr; +#endif +#ifdef LINUX + return (sErr == U14ERR_NOERROR) ? CED_GetTransfer(aHand1401[hand], pTransBlock) : sErr; +#endif +} +///////////////////////////////////////////////////////////////////////////// +// U14WorkingSet +// For Win32 only, adjusts process working set so that minimum is at least +// dwMinKb and maximum is at least dwMaxKb. +// Return value is zero if all went OK, or a code from 1 to 3 indicating the +// cause of the failure: +// +// 1 unable to access process (insufficient rights?) +// 2 unable to read process working set +// 3 unable to set process working set - bad parameters? +U14API(short) U14WorkingSet(DWORD dwMinKb, DWORD dwMaxKb) +{ +#ifdef _IS_WINDOWS_ + short sRetVal = 0; // 0 means all is OK + HANDLE hProcess; + DWORD dwVer = GetVersion(); + if (dwVer & 0x80000000) // is this not NT? + return 0; // then give up right now + + // Now attempt to get information on working set size + hProcess = OpenProcess(STANDARD_RIGHTS_REQUIRED | + PROCESS_QUERY_INFORMATION | + PROCESS_SET_QUOTA, + FALSE, _getpid()); + if (hProcess) + { + SIZE_T dwMinSize,dwMaxSize; + if (GetProcessWorkingSetSize(hProcess, &dwMinSize, &dwMaxSize)) + { + DWORD dwMin = dwMinKb << 10; // convert from kb to bytes + DWORD dwMax = dwMaxKb << 10; + + // if we get here, we have managed to read the current size + if (dwMin > dwMinSize) // need to change sizes? + dwMinSize = dwMin; + + if (dwMax > dwMaxSize) + dwMaxSize = dwMax; + + if (!SetProcessWorkingSetSize(hProcess, dwMinSize, dwMaxSize)) + sRetVal = 3; // failed to change size + } + else + sRetVal = 2; // failed to read original size + + CloseHandle(hProcess); + } + else + sRetVal = 1; // failed to get handle + + return sRetVal; +#endif +#ifdef LINUX + if (dwMinKb | dwMaxKb) + { + // to stop compiler moaning + } + return U14ERR_NOERROR; +#endif +} + +/**************************************************************************** +** U14UnSetTransfer Cancels a transfer area +** wArea The index of a block previously used in by SetTransfer +*****************************************************************************/ +U14API(short) U14UnSetTransfer(short hand, WORD wArea) +{ + short sErr = CheckHandle(hand); +#ifdef _IS_WINDOWS_ + if (sErr == U14ERR_NOERROR) + { + TCSBLOCK csBlock; + csBlock.ints[0] = (short)wArea; /* Area number into control block */ + sErr = U14Control1401(hand, U14_UNSETTRANSFER, &csBlock); /* Free area */ + + VirtualUnlock(apAreas[hand][wArea], auAreas[hand][wArea]);/* Unlock */ + apAreas[hand][wArea] = NULL; /* Clear locations */ + auAreas[hand][wArea] = 0; + } + return sErr; +#endif +#ifdef LINUX + return (sErr == U14ERR_NOERROR) ? CED_UnsetTransfer(aHand1401[hand], wArea) : sErr; +#endif +} + +/**************************************************************************** +** U14SetTransArea Sets an area up to be used for transfers +** WORD wArea The area number to set up +** void *pvBuff The address of the buffer for the data. +** DWORD dwLength The length of the buffer for the data +** short eSz The element size (used for byte swapping on the Mac) +****************************************************************************/ +U14API(short) U14SetTransArea(short hand, WORD wArea, void *pvBuff, + DWORD dwLength, short eSz) +{ + TRANSFERDESC td; + short sErr = CheckHandle(hand); + if (sErr != U14ERR_NOERROR) + return sErr; + if (wArea >= MAX_TRANSAREAS) // Is this a valid area number + return U14ERR_BADAREA; + +#ifdef _IS_WINDOWS_ + assert(apAreas[hand][wArea] == NULL); + assert(auAreas[hand][wArea] == 0); + + apAreas[hand][wArea] = pvBuff; /* Save data for later */ + auAreas[hand][wArea] = dwLength; + + if (!VirtualLock(pvBuff, dwLength)) /* Lock using WIN32 calls */ + { + apAreas[hand][wArea] = NULL; /* Clear locations */ + auAreas[hand][wArea] = 0; + return U14ERR_LOCKERR; /* VirtualLock failed */ + } +#ifndef _WIN64 + if (!USE_NT_DIOC(hand)) /* Use Win 9x DIOC? */ + { + DWORD dwBytes; + VXTRANSFERDESC vxDesc; /* Structure to pass to VXD */ + vxDesc.wArea = wArea; /* Copy across simple params */ + vxDesc.dwLength = dwLength; + + // Check we are not asking an old driver for more than area 0 + if ((wArea != 0) && (U14DriverVersion(hand) < 0x00010002L)) + sErr = U14ERR_DRIVTOOOLD; + else + { + vxDesc.dwAddrOfs = (DWORD)pvBuff; /* 32 bit offset */ + vxDesc.wAddrSel = 0; + + if (DeviceIoControl(aHand1401[hand], (DWORD)U14_SETTRANSFER, + pvBuff,dwLength, /* Will translate pointer */ + &vxDesc,sizeof(VXTRANSFERDESC), + &dwBytes,NULL)) + { + if (dwBytes >= sizeof(VXTRANSFERDESC)) /* Driver OK ? */ + sErr = U14ERR_NOERROR; + else + sErr = U14ERR_DRIVCOMMS; /* Else never got there */ + } + else + sErr = (short)GetLastError(); + } + } + else +#endif + { + PARAMBLK rWork; + DWORD dwBytes; + td.wArea = wArea; /* Pure NT - put data into struct */ + td.lpvBuff = pvBuff; + td.dwLength = dwLength; + td.eSize = 0; // Dummy element size + + if (DeviceIoControl(aHand1401[hand],(DWORD)U14_SETTRANSFER, + &td,sizeof(TRANSFERDESC), + &rWork,sizeof(PARAMBLK),&dwBytes,NULL)) + { + if (dwBytes >= sizeof(PARAMBLK)) // maybe error from driver? + sErr = rWork.sState; // will report any error + else + sErr = U14ERR_DRIVCOMMS; // Else never got there + } + else + sErr = U14ERR_DRIVCOMMS; + } + + if (sErr != U14ERR_NOERROR) + { + if (sErr != U14ERR_LOCKERR) // unless lock failed... + VirtualUnlock(pvBuff, dwLength); // ...release the lock + apAreas[hand][wArea] = NULL; // Clear locations + auAreas[hand][wArea] = 0; + } + + return sErr; +#endif +#ifdef LINUX + // The strange cast is so that it works in 64 and 32-bit linux as long is 64-bits + // in the 64 bit version. + td.lpvBuff = (long long)((unsigned long)pvBuff); + td.wAreaNum = wArea; + td.dwLength = dwLength; + td.eSize = eSz; // Dummy element size + return CED_SetTransfer(aHand1401[hand], &td); +#endif +} + +/**************************************************************************** +** U14SetTransferEvent Sets an event for notification of application +** wArea The tranfer area index, from 0 to MAXAREAS-1 +** bEvent True to create an event, false to remove it +** bToHost Set 0 for notification on to1401 tranfers, 1 for +** notification of transfers to the host PC +** dwStart The offset of the sub-area of interest +** dwLength The size of the sub-area of interest +** +** The device driver will set the event supplied to the signalled state +** whenever a DMA transfer to/from the specified area is completed. The +** transfer has to be in the direction specified by bToHost, and overlap +** that part of the whole transfer area specified by dwStart and dwLength. +** It is important that this function is called with bEvent false to release +** the event once 1401 activity is finished. +** +** Returns 1 if an event handle exists, 0 if all OK and no event handle or +** a negative code for an error. +****************************************************************************/ +U14API(short) U14SetTransferEvent(short hand, WORD wArea, BOOL bEvent, + BOOL bToHost, DWORD dwStart, DWORD dwLength) +{ +#ifdef _IS_WINDOWS_ + TCSBLOCK csBlock; + short sErr = U14TransferFlags(hand); // see if we can handle events + if (sErr >= U14ERR_NOERROR) // check handle is OK + { + bEvent = bEvent && ((sErr & U14TF_NOTIFY) != 0); // remove request if we cannot do events + if (wArea >= MAX_TRANSAREAS) // Check a valid area... + return U14ERR_BADAREA; // ...and bail of not + + // We can hold an event for each area, so see if we need to change the + // state of the event. + if ((bEvent != 0) != (aXferEvent[hand] != 0)) // change of event state? + { + if (bEvent) // want one and none present + aXferEvent[hand] = CreateEvent(NULL, FALSE, FALSE, NULL); + else + { + CloseHandle(aXferEvent[hand]); // clear the existing event + aXferEvent[hand] = NULL; // and clear handle + } + } + + // We have to store the parameters differently for 64-bit operations + // because a handle is 64 bits long. The drivers know of this and + // handle the information appropriately. +#ifdef _WIN64 + csBlock.longs[0] = wArea; // Pass paramaters into the driver... + if (bToHost != 0) // The direction flag is held in the + csBlock.longs[0] |= 0x10000; // upper word of the transfer area value + *((HANDLE*)&csBlock.longs[1]) = aXferEvent[hand]; // The event handle is 64-bits + csBlock.longs[3] = dwStart; // Thankfully these two remain + csBlock.longs[4] = dwLength; // as unsigned 32-bit values +#else + csBlock.longs[0] = wArea; // pass paramaters into the driver... + csBlock.longs[1] = (long)aXferEvent[hand]; // ...especially the event handle + csBlock.longs[2] = bToHost; + csBlock.longs[3] = dwStart; + csBlock.longs[4] = dwLength; +#endif + sErr = U14Control1401(hand, U14_SETTRANSEVENT, &csBlock); + if (sErr == U14ERR_NOERROR) + sErr = (short)(aXferEvent[hand] != NULL); // report if we have a flag + } + + return sErr; +#endif +#ifdef LINUX + TRANSFEREVENT te; + short sErr = CheckHandle(hand); + if (sErr != U14ERR_NOERROR) + return sErr; + + if (wArea >= MAX_TRANSAREAS) // Is this a valid area number + return U14ERR_BADAREA; + + te.wAreaNum = wArea; // copy parameters to the control block + te.wFlags = bToHost ? 1 : 0; // bit 0 sets the direction + te.dwStart = dwStart; // start offset of the event area + te.dwLength = dwLength; // size of the event area + te.iSetEvent = bEvent; // in Windows, this creates/destroys the event + return CED_SetEvent(aHand1401[hand], &te); +#endif +} + +/**************************************************************************** +** U14TestTransferEvent +** Would a U14WaitTransferEvent() call return immediately? return 1 if so, +** 0 if not or a negative code if a problem. +****************************************************************************/ +U14API(int) U14TestTransferEvent(short hand, WORD wArea) +{ +#ifdef _IS_WINDOWS_ + int iErr = CheckHandle(hand); + if (iErr == U14ERR_NOERROR) + { + if (aXferEvent[hand]) // if a handle is set... + iErr = WaitForSingleObject(aXferEvent[hand], 0) == WAIT_OBJECT_0; + } + return iErr; +#endif +#ifdef LINUX + short sErr = CheckHandle(hand); + return (sErr == U14ERR_NOERROR) ? CED_TestEvent(aHand1401[hand], wArea) : sErr; +#endif +} + +/**************************************************************************** +** U14WaitTransferEvent +** Wait for a transfer event with a timeout. +** msTimeOut is 0 for an infinite wait, else it is the maximum time to wait +** in milliseconds in range 0-0x00ffffff. +** Returns If no event handle then return immediately. Else return 1 if +** timed out or 0=event, and a negative code if a problem. +****************************************************************************/ +U14API(int) U14WaitTransferEvent(short hand, WORD wArea, int msTimeOut) +{ +#ifdef _IS_WINDOWS_ + int iErr = CheckHandle(hand); + if (iErr == U14ERR_NOERROR) + { + if (aXferEvent[hand]) + { + if (msTimeOut == 0) + msTimeOut = INFINITE; + iErr = WaitForSingleObject(aXferEvent[hand], msTimeOut) != WAIT_OBJECT_0; + } + else + iErr = TRUE; // say we timed out if no event + } + return iErr; +#endif +#ifdef LINUX + short sErr = CheckHandle(hand); + return (sErr == U14ERR_NOERROR) ? CED_WaitEvent(aHand1401[hand], wArea, msTimeOut) : sErr; +#endif +} + +/**************************************************************************** +** U14SetCircular Sets an area up for circular DMA transfers +** WORD wArea The area number to set up +** BOOL bToHost Sets the direction of data transfer +** void *pvBuff The address of the buffer for the data +** DWORD dwLength The length of the buffer for the data +****************************************************************************/ +U14API(short) U14SetCircular(short hand, WORD wArea, BOOL bToHost, + void *pvBuff, DWORD dwLength) +{ + short sErr = CheckHandle(hand); + if (sErr != U14ERR_NOERROR) + return sErr; + + if (wArea >= MAX_TRANSAREAS) /* Is this a valid area number */ + return U14ERR_BADAREA; + + if (!bToHost) /* For now, support tohost transfers only */ + return U14ERR_BADAREA; /* best error code I can find */ +#ifdef _IS_WINDOWS_ + assert(apAreas[hand][wArea] == NULL); + assert(auAreas[hand][wArea] == 0); + + apAreas[hand][wArea] = pvBuff; /* Save data for later */ + auAreas[hand][wArea] = dwLength; + + if (!VirtualLock(pvBuff, dwLength)) /* Lock using WIN32 calls */ + sErr = U14ERR_LOCKERR; /* VirtualLock failed */ + else + { + PARAMBLK rWork; + DWORD dwBytes; + TRANSFERDESC txDesc; + txDesc.wArea = wArea; /* Pure NT - put data into struct */ + txDesc.lpvBuff = pvBuff; + txDesc.dwLength = dwLength; + txDesc.eSize = (short)bToHost; /* Use this for direction flag */ + + if (DeviceIoControl(aHand1401[hand],(DWORD)U14_SETCIRCULAR, + &txDesc, sizeof(TRANSFERDESC), + &rWork, sizeof(PARAMBLK),&dwBytes,NULL)) + { + if (dwBytes >= sizeof(PARAMBLK)) /* error from driver? */ + sErr = rWork.sState; /* No, just return driver data */ + else + sErr = U14ERR_DRIVCOMMS; /* Else never got there */ + } + else + sErr = U14ERR_DRIVCOMMS; + } + + if (sErr != U14ERR_NOERROR) + { + if (sErr != U14ERR_LOCKERR) + VirtualUnlock(pvBuff, dwLength); /* Release NT lock */ + apAreas[hand][wArea] = NULL; /* Clear locations */ + auAreas[hand][wArea] = 0; + } + + return sErr; +#endif +#ifdef LINUX + else + { + TRANSFERDESC td; + td.lpvBuff = (long long)((unsigned long)pvBuff); + td.wAreaNum = wArea; + td.dwLength = dwLength; + td.eSize = (short)bToHost; /* Use this for direction flag */ + return CED_SetCircular(aHand1401[hand], &td); + } +#endif +} + +/**************************************************************************** +** Function GetCircBlk returns the size (& start offset) of the next +** available block of circular data. +****************************************************************************/ +U14API(int) U14GetCircBlk(short hand, WORD wArea, DWORD *pdwOffs) +{ + int lErr = CheckHandle(hand); + if (lErr != U14ERR_NOERROR) + return lErr; + + if (wArea >= MAX_TRANSAREAS) // Is this a valid area number? + return U14ERR_BADAREA; + else + { +#ifdef _IS_WINDOWS_ + PARAMBLK rWork; + TCSBLOCK csBlock; + DWORD dwBytes; + csBlock.longs[0] = wArea; // Area number into control block + rWork.sState = U14ERR_DRIVCOMMS; + if (DeviceIoControl(aHand1401[hand], (DWORD)U14_GETCIRCBLK, &csBlock, sizeof(TCSBLOCK), &rWork, sizeof(PARAMBLK), &dwBytes, NULL) && + (dwBytes >= sizeof(PARAMBLK))) + lErr = rWork.sState; + else + lErr = U14ERR_DRIVCOMMS; + + if (lErr == U14ERR_NOERROR) // Did everything go OK? + { // Yes, we can pass the results back + lErr = rWork.csBlock.longs[1]; // Return the block information + *pdwOffs = rWork.csBlock.longs[0]; // Offset is first in array + } +#endif +#ifdef LINUX + TCIRCBLOCK cb; + cb.nArea = wArea; // Area number into control block + cb.dwOffset = 0; + cb.dwSize = 0; + lErr = CED_GetCircBlock(aHand1401[hand], &cb); + if (lErr == U14ERR_NOERROR) // Did everything go OK? + { // Yes, we can pass the results back + lErr = cb.dwSize; // return the size + *pdwOffs = cb.dwOffset; // and the offset + } +#endif + } + return lErr; +} + +/**************************************************************************** +** Function FreeCircBlk marks the specified area of memory as free for +** resuse for circular transfers and returns the size (& start +** offset) of the next available block of circular data. +****************************************************************************/ +U14API(int) U14FreeCircBlk(short hand, WORD wArea, DWORD dwOffs, DWORD dwSize, + DWORD *pdwOffs) +{ + int lErr = CheckHandle(hand); + if (lErr != U14ERR_NOERROR) + return lErr; + + if (wArea < MAX_TRANSAREAS) // Is this a valid area number + { +#ifdef _IS_WINDOWS_ + PARAMBLK rWork; + TCSBLOCK csBlock; + DWORD dwBytes; + csBlock.longs[0] = wArea; // Area number into control block + csBlock.longs[1] = dwOffs; + csBlock.longs[2] = dwSize; + rWork.sState = U14ERR_DRIVCOMMS; + if (DeviceIoControl(aHand1401[hand], (DWORD)U14_FREECIRCBLK, &csBlock, sizeof(TCSBLOCK), + &rWork, sizeof(PARAMBLK), &dwBytes, NULL) && + (dwBytes >= sizeof(PARAMBLK))) + lErr = rWork.sState; + else + lErr = U14ERR_DRIVCOMMS; + if (lErr == U14ERR_NOERROR) // Did everything work OK? + { // Yes, we can pass the results back + lErr = rWork.csBlock.longs[1]; // Return the block information + *pdwOffs = rWork.csBlock.longs[0]; // Offset is first in array + } +#endif +#ifdef LINUX + TCIRCBLOCK cb; + cb.nArea = wArea; // Area number into control block + cb.dwOffset = dwOffs; + cb.dwSize = dwSize; + + lErr = CED_FreeCircBlock(aHand1401[hand], &cb); + if (lErr == U14ERR_NOERROR) // Did everything work OK? + { // Yes, we can pass the results back + lErr = cb.dwSize; // Return the block information + *pdwOffs = cb.dwOffset; // Offset is first in array + } +#endif + } + else + lErr = U14ERR_BADAREA; + + return lErr; +} + +/**************************************************************************** +** Transfer +** Transfer moves data to 1401 or to host +** Assumes memory is allocated and locked, +** which it should be to get a pointer +*****************************************************************************/ +static short Transfer(short hand, BOOL bTo1401, char* pData, + DWORD dwSize, DWORD dw1401, short eSz) +{ + char strcopy[MAXSTRLEN+1]; // to hold copy of work string + short sResult = U14SetTransArea(hand, 0, (void *)pData, dwSize, eSz); + if (sResult == U14ERR_NOERROR) // no error + { + sprintf(strcopy, // data offset is always 0 + "TO%s,$%X,$%X,0;", bTo1401 ? "1401" : "HOST", dw1401, dwSize); + + U14SendString(hand, strcopy); // send transfer string + + sResult = U14CheckErr(hand); // Use ERR command to check for done + if (sResult > 0) + sResult = U14ERR_TOXXXERR; // If a 1401 error, use this code + + U14UnSetTransfer(hand, 0); + } + return sResult; +} + +/**************************************************************************** +** Function ToHost transfers data into the host from the 1401 +****************************************************************************/ +U14API(short) U14ToHost(short hand, char* pAddrHost, DWORD dwSize, + DWORD dw1401, short eSz) +{ + short sErr = CheckHandle(hand); + if ((sErr == U14ERR_NOERROR) && dwSize) // TOHOST is a constant + sErr = Transfer(hand, TOHOST, pAddrHost, dwSize, dw1401, eSz); + return sErr; +} + +/**************************************************************************** +** Function To1401 transfers data into the 1401 from the host +****************************************************************************/ +U14API(short) U14To1401(short hand, const char* pAddrHost,DWORD dwSize, + DWORD dw1401, short eSz) +{ + short sErr = CheckHandle(hand); + if ((sErr == U14ERR_NOERROR) && dwSize) // TO1401 is a constant + sErr = Transfer(hand, TO1401, (char*)pAddrHost, dwSize, dw1401, eSz); + return sErr; +} + +/**************************************************************************** +** Function LdCmd Loads a command from a full path or just a file +*****************************************************************************/ +#ifdef _IS_WINDOWS_ +#define file_exist(name) (_access(name, 0) != -1) +#define file_open(name) _lopen(name, OF_READ) +#define file_close(h) _lclose(h) +#define file_seek(h, pos) _llseek(h, pos, FILE_BEGIN) +#define file_read(h, buffer, size) (_lread(h, buffer, size) == size) +#endif +#ifdef LINUX +#define file_exist(name) (access(name, F_OK) != -1) +#define file_open(name) open(name, O_RDONLY) +#define file_close(h) close(h) +#define file_seek(h, pos) lseek(h, pos, SEEK_SET) +#define file_read(h, buffer, size) (read(h, buffer, size) == (ssize_t)size) +static DWORD GetModuleFileName(void* dummy, char* buffer, int max) +{ + // The following works for Linux systems with a /proc file system. + char szProcPath[32]; + sprintf(szProcPath, "/proc/%d/exe", getpid()); // attempt to read link + if (readlink(szProcPath, buffer, max) != -1) + { + dirname (buffer); + strcat (buffer, "/"); + return strlen(buffer); + } + return 0; +} +#endif + +U14API(short) U14LdCmd(short hand, const char* command) +{ + char strcopy[MAXSTRLEN+1]; // to hold copy of work string + BOOL bGotIt = FALSE; // have we found the command file? + int iFHandle; // file handle of command +#define FNSZ 260 + char filnam[FNSZ]; // space to build name in + char szCmd[25]; // just the command name with extension + + short sErr = CheckHandle(hand); + if (sErr != U14ERR_NOERROR) + return sErr; + + if (strchr(command, '.') != NULL) // see if we have full name + { + if (file_exist(command)) // If the file exists + { + strcpy(filnam, command); // use name as is + bGotIt = TRUE; // Flag no more searching + } + else // not found, get file name for search + { + char* pStr = strrchr(command, PATHSEP); // Point to last separator + if (pStr != NULL) // Check we got it + { + pStr++; // move past the backslash + strcpy(szCmd, pStr); // copy file name as is + } + else + strcpy(szCmd, command); // use as is + } + } + else // File extension not supplied, so build the command file name + { + char szExt[8]; + strcpy(szCmd, command); // Build command file name + ExtForType(asType1401[hand], szExt);// File extension string + strcat(szCmd, szExt); // add it to the end + } + + // Next place to look is in the 1401 folder in the same place as the + // application was run from. + if (!bGotIt) // Still not got it? + { + DWORD dwLen = GetModuleFileName(NULL, filnam, FNSZ); // Get app path + if (dwLen > 0) // and use it as path if found + { + char* pStr = strrchr(filnam, PATHSEP); // Point to last separator + if (pStr != NULL) + { + *(++pStr) = 0; // Terminate string there + if (strlen(filnam) < FNSZ-6) // make sure we have space + { + strcat(filnam, "1401" PATHSEPSTR); // add in 1401 subdir + strcat(filnam,szCmd); + bGotIt = (BOOL)file_exist(filnam); // See if file exists + } + } + } + } + + // Next place to look is in whatever path is set by the 1401DIR environment + // variable, if it exists. + if (!bGotIt) // Need to do more searches?/ + { + char* pStr = getenv("1401DIR"); // Try to find environment var + if (pStr != NULL) // and use it as path if found + { + strcpy(filnam, pStr); // Use path in environment + if (filnam[strlen(filnam)-1] != PATHSEP)// We need separator + strcat(filnam, PATHSEPSTR); + strcat(filnam, szCmd); + bGotIt = (BOOL)file_exist(filnam); // Got this one? + } + } + + // Last place to look is the default location. + if (!bGotIt) // Need to do more searches? + { + strcpy(filnam, DEFCMDPATH); // Use default path + strcat(filnam, szCmd); + bGotIt = file_exist(filnam); // Got this one? + } + + iFHandle = file_open(filnam); + if (iFHandle == -1) + sErr = U14ERR_NOFILE; + else + { // first read in the header block + CMDHEAD rCmdHead; // to hold the command header + if (file_read(iFHandle, &rCmdHead, sizeof(CMDHEAD))) + { + size_t nComSize = rCmdHead.wCmdSize; + char* pMem = malloc(nComSize); + if (pMem != NULL) + { + file_seek(iFHandle, sizeof(CMDHEAD)); + if (file_read(iFHandle, pMem, (UINT)nComSize)) + { + sErr = U14SetTransArea(hand, 0, (void *)pMem, (DWORD)nComSize, ESZBYTES); + if (sErr == U14ERR_NOERROR) + { + sprintf(strcopy, "CLOAD,0,$%X;", (int)nComSize); + sErr = U14SendString(hand, strcopy); + if (sErr == U14ERR_NOERROR) + { + sErr = U14CheckErr(hand); // Use ERR to check for done + if (sErr > 0) + sErr = U14ERR_CLOADERR; // If an error, this code + } + U14UnSetTransfer(hand, 0); // release transfer area + } + } + else + sErr = U14ERR_READERR; + free(pMem); + } + else + sErr = U14ERR_HOSTSPACE; // memory allocate failed + } + else + sErr = U14ERR_READERR; + + file_close(iFHandle); // close the file + } + + return sErr; +} + + +/**************************************************************************** +** Ld +** Loads a command into the 1401 +** Returns NOERROR code or a long with error in lo word and index of +** command that failed in high word +****************************************************************************/ +U14API(DWORD) U14Ld(short hand, const char* vl, const char* str) +{ + DWORD dwIndex = 0; // index to current command + long lErr = U14ERR_NOERROR; // what the error was that went wrong + char strcopy[MAXSTRLEN+1]; // stores unmodified str parameter + char szFExt[8]; // The command file extension + short sErr = CheckHandle(hand); + if (sErr != U14ERR_NOERROR) + return sErr; + + ExtForType(asType1401[hand], szFExt); // File extension string + strcpy(strcopy, str); // to avoid changing original + + // now break out one command at a time and see if loaded + if (*str) // if anything there + { + BOOL bDone = FALSE; // true when finished all commands + int iLoop1 = 0; // Point at start of string for command name + int iLoop2 = 0; // and at start of str parameter + do // repeat until end of str + { + char filnam[MAXSTRLEN+1]; // filename to use + char szFName[MAXSTRLEN+1]; // filename work string + + if (!strcopy[iLoop1]) // at the end of the string? + bDone = TRUE; // set the finish flag + + if (bDone || (strcopy[iLoop1] == ',')) // end of cmd? + { + U14LONG er[5]; // Used to read back error results + ++dwIndex; // Keep count of command number, first is 1 + szFName[iLoop2]=(char)0; // null terminate name of command + + strncpy(szLastName, szFName, sizeof(szLastName)); // Save for error info + szLastName[sizeof(szLastName)-1] = 0; + strncat(szLastName, szFExt, sizeof(szLastName)); // with extension included + szLastName[sizeof(szLastName)-1] = 0; + + U14SendString(hand, szFName); // ask if loaded + U14SendString(hand, ";ERR;"); // add err return + + lErr = U14LongsFrom1401(hand, er, 5); + if (lErr > 0) + { + lErr = U14ERR_NOERROR; + if (er[0] == 255) // if command not loaded at all + { + if (vl && *vl) // if we have a path name + { + strcpy(filnam, vl); + if (strchr("\\/:", filnam[strlen(filnam)-1]) == NULL) + strcat(filnam, PATHSEPSTR); // add separator if none found + strcat(filnam, szFName); // add the file name + strcat(filnam, szFExt); // and extension + } + else + strcpy(filnam, szFName); // simple name + + lErr = U14LdCmd(hand, filnam); // load cmd + if (lErr != U14ERR_NOERROR) // spot any errors + bDone = TRUE; // give up if an error + } + } + else + bDone = TRUE; // give up if an error + + iLoop2 = 0; // Reset pointer to command name string + ++iLoop1; // and move on through str parameter + } + else + szFName[iLoop2++] = strcopy[iLoop1++]; // no command end, so copy 1 char + } + while (!bDone); + } + + if (lErr == U14ERR_NOERROR) + { + szLastName[0] = 0; // No error, so clean out command name here + return lErr; + } + else + return ((dwIndex<<16) | ((DWORD)lErr & 0x0000FFFF)); +} + +// Initialise the library (if not initialised) and return the library version +U14API(int) U14InitLib(void) +{ + int iRetVal = U14LIB_VERSION; + if (iAttached == 0) // only do this the first time please + { + int i; +#ifdef _IS_WINDOWS_ + int j; + DWORD dwVersion = GetVersion(); + bWindows9x = FALSE; // Assume not Win9x + + if (dwVersion & 0x80000000) // if not windows NT + { + if ((LOBYTE(LOWORD(dwVersion)) < 4) && // if Win32s or... + (HIBYTE(LOWORD(dwVersion)) < 95)) // ...below Windows 95 + iRetVal = 0; // We do not support this + else + bWindows9x = TRUE; // Flag we have Win9x + } +#endif + + for (i = 0; i < MAX1401; i++) // initialise the device area + { + aHand1401[i] = INVALID_HANDLE_VALUE; // Clear handle values + asType1401[i] = U14TYPEUNKNOWN; // and 1401 type codes + alTimeOutPeriod[i] = 3000; // 3 second timeouts +#ifdef _IS_WINDOWS_ +#ifndef _WIN64 + abUseNTDIOC[i] = (BOOL)!bWindows9x; +#endif + aXferEvent[i] = NULL; // there are no Xfer events + for (j = 0; j < MAX_TRANSAREAS; j++) // Clear out locked area info + { + apAreas[i][j] = NULL; + auAreas[i][j] = 0; + } +#endif + } + } + return iRetVal; +} + +///-------------------------------------------------------------------------------- +/// Functions called when the library is loaded and unloaded to give us a chance to +/// setup the library. + + +#ifdef _IS_WINDOWS_ +#ifndef U14_NOT_DLL +/**************************************************************************** +** FUNCTION: DllMain(HANDLE, DWORD, LPVOID) +** LibMain is called by Windows when the DLL is initialized, Thread Attached, +** and other times. Refer to SDK documentation, as to the different ways this +** may be called. +****************************************************************************/ +INT APIENTRY DllMain(HANDLE hInst, DWORD ul_reason_being_called, LPVOID lpReserved) +{ + int iRetVal = 1; + + switch (ul_reason_being_called) + { + case DLL_PROCESS_ATTACH: + iRetVal = U14InitLib() > 0; // does nothing if iAttached != 0 + ++iAttached; // count times attached + break; + + case DLL_PROCESS_DETACH: + if (--iAttached == 0) // last man out? + U14CloseAll(); // release all open handles + break; + } + return iRetVal; + + UNREFERENCED_PARAMETER(lpReserved); +} +#endif +#endif +#ifdef LINUX +void __attribute__((constructor)) use1401_load(void) +{ + U14InitLib(); + ++iAttached; +} + +void __attribute__((destructor)) use1401_unload(void) +{ + if (--iAttached == 0) // last man out? + U14CloseAll(); // release all open handles +} +#endif diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig index 6cee7855b019..2093403af253 100644 --- a/drivers/staging/comedi/Kconfig +++ b/drivers/staging/comedi/Kconfig @@ -549,6 +549,23 @@ menuconfig COMEDI_PCI_DRIVERS if COMEDI_PCI_DRIVERS +config COMEDI_8255_PCI + tristate "Generic PCI based 8255 digital i/o board support" + select COMEDI_8255 + ---help--- + Enable support for PCI based 8255 digital i/o boards. This driver + provides a PCI wrapper around the generic 8255 driver. + + Supported boards: + ADlink - PCI-7224, PCI-7248, and PCI-7296 + Measurement Computing - PCI-DIO24, PCI-DIO24H, PCI-DIO48H and + PCI-DIO96H + National Instruments - PCI-DIO-96, PCI-DIO-96B, PXI-6508, PCI-6503, + PCI-6503B, PCI-6503X, and PXI-6503 + + To compile this driver as a module, choose M here: the module will + be called 8255_pci. + config COMEDI_ADDI_APCI_035 tristate "ADDI-DATA APCI_035 support" depends on VIRT_TO_BUS @@ -676,30 +693,16 @@ config COMEDI_ADL_PCI6208 To compile this driver as a module, choose M here: the module will be called adl_pci6208. -config COMEDI_ADL_PCI7230 - tristate "ADLink PCI-7230 digital io board support" - ---help--- - Enable support for ADlink PCI-7230 digital io board support - - To compile this driver as a module, choose M here: the module will be - called adl_pci7230. - -config COMEDI_ADL_PCI7296 - tristate "ADLink PCI-7296 96 ch. digital io board support" - select COMEDI_8255 +config COMEDI_ADL_PCI7X3X + tristate "ADLink PCI-723X/743X isolated digital i/o board support" ---help--- - Enable support for ADlink PCI-7296 96 ch. digital io board support + Enable support for ADlink PCI-723X/743X isolated digital i/o boards. + Supported boards include the 32-channel PCI-7230 (16 in/16 out), + PCI-7233 (32 in), and PCI-7234 (32 out) as well as the 64-channel + PCI-7432 (32 in/32 out), PCI-7433 (64 in), and PCI-7434 (64 out). To compile this driver as a module, choose M here: the module will be - called adl_pci7296. - -config COMEDI_ADL_PCI7432 - tristate "ADLink PCI-7432 64 ch. isolated digital io board support" - ---help--- - Enable support for ADlink PCI-7432 64 ch. isolated digital io board - - To compile this driver as a module, choose M here: the module will be - called adl_pci7432. + called adl_pci7x3x. config COMEDI_ADL_PCI8164 tristate "ADLink PCI-8164 4 Axes Motion Control board support" @@ -935,16 +938,6 @@ config COMEDI_CB_PCIDDA To compile this driver as a module, choose M here: the module will be called cb_pcidda. -config COMEDI_CB_PCIDIO - tristate "MeasurementComputing PCI-DIO series support" - select COMEDI_8255 - ---help--- - Enable support for ComputerBoards/MeasurementComputing PCI-DIO series - PCI-DIO24, PCI-DIO24H and PCI-DIO48H - - To compile this driver as a module, choose M here: the module will be - called cb_pcidio. - config COMEDI_CB_PCIMDAS tristate "MeasurementComputing PCIM-DAS1602/16 support" select COMEDI_8255 @@ -1039,15 +1032,12 @@ config COMEDI_NI_LABPC called ni_labpc. config COMEDI_NI_PCIDIO - tristate "NI PCI-DIO32HS, PCI-DIO96, PCI-6533, PCI-6503 support" + tristate "NI PCI-DIO32HS, PCI-6533, PCI-6534 support" select COMEDI_MITE select COMEDI_8255 ---help--- Enable support for National Instruments PCI-DIO-32HS, PXI-6533, - PCI-DIO-96, PCI-DIO-96B, PXI-6508, PCI-6503, PCI-6503B, PCI-6503X, - PXI-6503, PCI-6533 and PCI-6534 - The DIO-96 appears as four 8255 subdevices. See the 8255 - driver notes for details. + PCI-6533 and PCI-6534 To compile this driver as a module, choose M here: the module will be called ni_pcidio. @@ -1262,8 +1252,8 @@ config COMEDI_8255 that has an 8255 chip. For multifunction boards, the main driver will configure the 8255 subdevice automatically. - Note that most PCI 8255 boards do NOT work with this driver, and - need a separate driver as a wrapper. + Note that most PCI based 8255 boards use the 8255_pci driver as a + wrapper around this driver. To compile this driver as a module, choose M here: the module will be called 8255. diff --git a/drivers/staging/comedi/comedi.h b/drivers/staging/comedi/comedi.h index 8ea55aef10a7..133f013e0f6d 100644 --- a/drivers/staging/comedi/comedi.h +++ b/drivers/staging/comedi/comedi.h @@ -208,92 +208,92 @@ /* subdevice types */ - enum comedi_subdevice_type { - COMEDI_SUBD_UNUSED, /* unused by driver */ - COMEDI_SUBD_AI, /* analog input */ - COMEDI_SUBD_AO, /* analog output */ - COMEDI_SUBD_DI, /* digital input */ - COMEDI_SUBD_DO, /* digital output */ - COMEDI_SUBD_DIO, /* digital input/output */ - COMEDI_SUBD_COUNTER, /* counter */ - COMEDI_SUBD_TIMER, /* timer */ - COMEDI_SUBD_MEMORY, /* memory, EEPROM, DPRAM */ - COMEDI_SUBD_CALIB, /* calibration DACs */ - COMEDI_SUBD_PROC, /* processor, DSP */ - COMEDI_SUBD_SERIAL, /* serial IO */ - COMEDI_SUBD_PWM /* PWM */ - }; +enum comedi_subdevice_type { + COMEDI_SUBD_UNUSED, /* unused by driver */ + COMEDI_SUBD_AI, /* analog input */ + COMEDI_SUBD_AO, /* analog output */ + COMEDI_SUBD_DI, /* digital input */ + COMEDI_SUBD_DO, /* digital output */ + COMEDI_SUBD_DIO, /* digital input/output */ + COMEDI_SUBD_COUNTER, /* counter */ + COMEDI_SUBD_TIMER, /* timer */ + COMEDI_SUBD_MEMORY, /* memory, EEPROM, DPRAM */ + COMEDI_SUBD_CALIB, /* calibration DACs */ + COMEDI_SUBD_PROC, /* processor, DSP */ + COMEDI_SUBD_SERIAL, /* serial IO */ + COMEDI_SUBD_PWM /* PWM */ +}; /* configuration instructions */ - enum configuration_ids { - INSN_CONFIG_DIO_INPUT = 0, - INSN_CONFIG_DIO_OUTPUT = 1, - INSN_CONFIG_DIO_OPENDRAIN = 2, - INSN_CONFIG_ANALOG_TRIG = 16, +enum configuration_ids { + INSN_CONFIG_DIO_INPUT = 0, + INSN_CONFIG_DIO_OUTPUT = 1, + INSN_CONFIG_DIO_OPENDRAIN = 2, + INSN_CONFIG_ANALOG_TRIG = 16, /* INSN_CONFIG_WAVEFORM = 17, */ /* INSN_CONFIG_TRIG = 18, */ /* INSN_CONFIG_COUNTER = 19, */ - INSN_CONFIG_ALT_SOURCE = 20, - INSN_CONFIG_DIGITAL_TRIG = 21, - INSN_CONFIG_BLOCK_SIZE = 22, - INSN_CONFIG_TIMER_1 = 23, - INSN_CONFIG_FILTER = 24, - INSN_CONFIG_CHANGE_NOTIFY = 25, - - /*ALPHA*/ INSN_CONFIG_SERIAL_CLOCK = 26, - INSN_CONFIG_BIDIRECTIONAL_DATA = 27, - INSN_CONFIG_DIO_QUERY = 28, - INSN_CONFIG_PWM_OUTPUT = 29, - INSN_CONFIG_GET_PWM_OUTPUT = 30, - INSN_CONFIG_ARM = 31, - INSN_CONFIG_DISARM = 32, - INSN_CONFIG_GET_COUNTER_STATUS = 33, - INSN_CONFIG_RESET = 34, - /* Use CTR as single pulsegenerator */ - INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR = 1001, - /* Use CTR as pulsetraingenerator */ - INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR = 1002, - /* Use the counter as encoder */ - INSN_CONFIG_GPCT_QUADRATURE_ENCODER = 1003, - INSN_CONFIG_SET_GATE_SRC = 2001, /* Set gate source */ - INSN_CONFIG_GET_GATE_SRC = 2002, /* Get gate source */ - /* Set master clock source */ - INSN_CONFIG_SET_CLOCK_SRC = 2003, - INSN_CONFIG_GET_CLOCK_SRC = 2004, /* Get master clock source */ - INSN_CONFIG_SET_OTHER_SRC = 2005, /* Set other source */ - /* INSN_CONFIG_GET_OTHER_SRC = 2006,*//* Get other source */ - /* Get size in bytes of subdevice's on-board fifos used during - * streaming input/output */ - INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE = 2006, - INSN_CONFIG_SET_COUNTER_MODE = 4097, - /* INSN_CONFIG_8254_SET_MODE is deprecated */ - INSN_CONFIG_8254_SET_MODE = INSN_CONFIG_SET_COUNTER_MODE, - INSN_CONFIG_8254_READ_STATUS = 4098, - INSN_CONFIG_SET_ROUTING = 4099, - INSN_CONFIG_GET_ROUTING = 4109, -/* PWM */ - INSN_CONFIG_PWM_SET_PERIOD = 5000, /* sets frequency */ - INSN_CONFIG_PWM_GET_PERIOD = 5001, /* gets frequency */ - INSN_CONFIG_GET_PWM_STATUS = 5002, /* is it running? */ - /* sets H bridge: duty cycle and sign bit for a relay at the - * same time */ - INSN_CONFIG_PWM_SET_H_BRIDGE = 5003, - /* gets H bridge data: duty cycle and the sign bit */ - INSN_CONFIG_PWM_GET_H_BRIDGE = 5004 - }; - - enum comedi_io_direction { - COMEDI_INPUT = 0, - COMEDI_OUTPUT = 1, - COMEDI_OPENDRAIN = 2 - }; - - enum comedi_support_level { - COMEDI_UNKNOWN_SUPPORT = 0, - COMEDI_SUPPORTED, - COMEDI_UNSUPPORTED - }; + INSN_CONFIG_ALT_SOURCE = 20, + INSN_CONFIG_DIGITAL_TRIG = 21, + INSN_CONFIG_BLOCK_SIZE = 22, + INSN_CONFIG_TIMER_1 = 23, + INSN_CONFIG_FILTER = 24, + INSN_CONFIG_CHANGE_NOTIFY = 25, + + INSN_CONFIG_SERIAL_CLOCK = 26, /*ALPHA*/ + INSN_CONFIG_BIDIRECTIONAL_DATA = 27, + INSN_CONFIG_DIO_QUERY = 28, + INSN_CONFIG_PWM_OUTPUT = 29, + INSN_CONFIG_GET_PWM_OUTPUT = 30, + INSN_CONFIG_ARM = 31, + INSN_CONFIG_DISARM = 32, + INSN_CONFIG_GET_COUNTER_STATUS = 33, + INSN_CONFIG_RESET = 34, + /* Use CTR as single pulsegenerator */ + INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR = 1001, + /* Use CTR as pulsetraingenerator */ + INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR = 1002, + /* Use the counter as encoder */ + INSN_CONFIG_GPCT_QUADRATURE_ENCODER = 1003, + INSN_CONFIG_SET_GATE_SRC = 2001, /* Set gate source */ + INSN_CONFIG_GET_GATE_SRC = 2002, /* Get gate source */ + /* Set master clock source */ + INSN_CONFIG_SET_CLOCK_SRC = 2003, + INSN_CONFIG_GET_CLOCK_SRC = 2004, /* Get master clock source */ + INSN_CONFIG_SET_OTHER_SRC = 2005, /* Set other source */ + /* INSN_CONFIG_GET_OTHER_SRC = 2006,*//* Get other source */ + /* Get size in bytes of subdevice's on-board fifos used during + * streaming input/output */ + INSN_CONFIG_GET_HARDWARE_BUFFER_SIZE = 2006, + INSN_CONFIG_SET_COUNTER_MODE = 4097, + /* INSN_CONFIG_8254_SET_MODE is deprecated */ + INSN_CONFIG_8254_SET_MODE = INSN_CONFIG_SET_COUNTER_MODE, + INSN_CONFIG_8254_READ_STATUS = 4098, + INSN_CONFIG_SET_ROUTING = 4099, + INSN_CONFIG_GET_ROUTING = 4109, + /* PWM */ + INSN_CONFIG_PWM_SET_PERIOD = 5000, /* sets frequency */ + INSN_CONFIG_PWM_GET_PERIOD = 5001, /* gets frequency */ + INSN_CONFIG_GET_PWM_STATUS = 5002, /* is it running? */ + /* sets H bridge: duty cycle and sign bit for a relay at the + * same time */ + INSN_CONFIG_PWM_SET_H_BRIDGE = 5003, + /* gets H bridge data: duty cycle and the sign bit */ + INSN_CONFIG_PWM_GET_H_BRIDGE = 5004 +}; + +enum comedi_io_direction { + COMEDI_INPUT = 0, + COMEDI_OUTPUT = 1, + COMEDI_OPENDRAIN = 2 +}; + +enum comedi_support_level { + COMEDI_UNKNOWN_SUPPORT = 0, + COMEDI_SUPPORTED, + COMEDI_UNSUPPORTED +}; /* ioctls */ @@ -317,133 +317,133 @@ /* structures */ - struct comedi_trig { - unsigned int subdev; /* subdevice */ - unsigned int mode; /* mode */ - unsigned int flags; - unsigned int n_chan; /* number of channels */ - unsigned int *chanlist; /* channel/range list */ - short *data; /* data list, size depends on subd flags */ - unsigned int n; /* number of scans */ - unsigned int trigsrc; - unsigned int trigvar; - unsigned int trigvar1; - unsigned int data_len; - unsigned int unused[3]; - }; - - struct comedi_insn { - unsigned int insn; - unsigned int n; - unsigned int __user *data; - unsigned int subdev; - unsigned int chanspec; - unsigned int unused[3]; - }; - - struct comedi_insnlist { - unsigned int n_insns; - struct comedi_insn __user *insns; - }; - - struct comedi_cmd { - unsigned int subdev; - unsigned int flags; - - unsigned int start_src; - unsigned int start_arg; - - unsigned int scan_begin_src; - unsigned int scan_begin_arg; - - unsigned int convert_src; - unsigned int convert_arg; - - unsigned int scan_end_src; - unsigned int scan_end_arg; - - unsigned int stop_src; - unsigned int stop_arg; - - unsigned int __user *chanlist; /* channel/range list */ - unsigned int chanlist_len; - - short __user *data; /* data list, size depends on subd flags */ - unsigned int data_len; - }; - - struct comedi_chaninfo { - unsigned int subdev; - unsigned int __user *maxdata_list; - unsigned int __user *flaglist; - unsigned int __user *rangelist; - unsigned int unused[4]; - }; - - struct comedi_rangeinfo { - unsigned int range_type; - void __user *range_ptr; - }; - - struct comedi_krange { - int min; /* fixed point, multiply by 1e-6 */ - int max; /* fixed point, multiply by 1e-6 */ - unsigned int flags; - }; - - struct comedi_subdinfo { - unsigned int type; - unsigned int n_chan; - unsigned int subd_flags; - unsigned int timer_type; - unsigned int len_chanlist; - unsigned int maxdata; - unsigned int flags; /* channel flags */ - unsigned int range_type; /* lookup in kernel */ - unsigned int settling_time_0; - /* see support_level enum for values */ - unsigned insn_bits_support; - unsigned int unused[8]; - }; - - struct comedi_devinfo { - unsigned int version_code; - unsigned int n_subdevs; - char driver_name[COMEDI_NAMELEN]; - char board_name[COMEDI_NAMELEN]; - int read_subdevice; - int write_subdevice; - int unused[30]; - }; - - struct comedi_devconfig { - char board_name[COMEDI_NAMELEN]; - int options[COMEDI_NDEVCONFOPTS]; - }; - - struct comedi_bufconfig { - unsigned int subdevice; - unsigned int flags; - - unsigned int maximum_size; - unsigned int size; - - unsigned int unused[4]; - }; - - struct comedi_bufinfo { - unsigned int subdevice; - unsigned int bytes_read; - - unsigned int buf_write_ptr; - unsigned int buf_read_ptr; - unsigned int buf_write_count; - unsigned int buf_read_count; - - unsigned int bytes_written; - - unsigned int unused[4]; - }; +struct comedi_trig { + unsigned int subdev; /* subdevice */ + unsigned int mode; /* mode */ + unsigned int flags; + unsigned int n_chan; /* number of channels */ + unsigned int *chanlist; /* channel/range list */ + short *data; /* data list, size depends on subd flags */ + unsigned int n; /* number of scans */ + unsigned int trigsrc; + unsigned int trigvar; + unsigned int trigvar1; + unsigned int data_len; + unsigned int unused[3]; +}; + +struct comedi_insn { + unsigned int insn; + unsigned int n; + unsigned int __user *data; + unsigned int subdev; + unsigned int chanspec; + unsigned int unused[3]; +}; + +struct comedi_insnlist { + unsigned int n_insns; + struct comedi_insn __user *insns; +}; + +struct comedi_cmd { + unsigned int subdev; + unsigned int flags; + + unsigned int start_src; + unsigned int start_arg; + + unsigned int scan_begin_src; + unsigned int scan_begin_arg; + + unsigned int convert_src; + unsigned int convert_arg; + + unsigned int scan_end_src; + unsigned int scan_end_arg; + + unsigned int stop_src; + unsigned int stop_arg; + + unsigned int *chanlist; /* channel/range list */ + unsigned int chanlist_len; + + short __user *data; /* data list, size depends on subd flags */ + unsigned int data_len; +}; + +struct comedi_chaninfo { + unsigned int subdev; + unsigned int __user *maxdata_list; + unsigned int __user *flaglist; + unsigned int __user *rangelist; + unsigned int unused[4]; +}; + +struct comedi_rangeinfo { + unsigned int range_type; + void __user *range_ptr; +}; + +struct comedi_krange { + int min; /* fixed point, multiply by 1e-6 */ + int max; /* fixed point, multiply by 1e-6 */ + unsigned int flags; +}; + +struct comedi_subdinfo { + unsigned int type; + unsigned int n_chan; + unsigned int subd_flags; + unsigned int timer_type; + unsigned int len_chanlist; + unsigned int maxdata; + unsigned int flags; /* channel flags */ + unsigned int range_type; /* lookup in kernel */ + unsigned int settling_time_0; + /* see support_level enum for values */ + unsigned insn_bits_support; + unsigned int unused[8]; +}; + +struct comedi_devinfo { + unsigned int version_code; + unsigned int n_subdevs; + char driver_name[COMEDI_NAMELEN]; + char board_name[COMEDI_NAMELEN]; + int read_subdevice; + int write_subdevice; + int unused[30]; +}; + +struct comedi_devconfig { + char board_name[COMEDI_NAMELEN]; + int options[COMEDI_NDEVCONFOPTS]; +}; + +struct comedi_bufconfig { + unsigned int subdevice; + unsigned int flags; + + unsigned int maximum_size; + unsigned int size; + + unsigned int unused[4]; +}; + +struct comedi_bufinfo { + unsigned int subdevice; + unsigned int bytes_read; + + unsigned int buf_write_ptr; + unsigned int buf_read_ptr; + unsigned int buf_write_count; + unsigned int buf_read_count; + + unsigned int bytes_written; + + unsigned int unused[4]; +}; /* range stuff */ @@ -495,306 +495,306 @@ */ - enum i8254_mode { - I8254_MODE0 = (0 << 1), /* Interrupt on terminal count */ - I8254_MODE1 = (1 << 1), /* Hardware retriggerable one-shot */ - I8254_MODE2 = (2 << 1), /* Rate generator */ - I8254_MODE3 = (3 << 1), /* Square wave mode */ - I8254_MODE4 = (4 << 1), /* Software triggered strobe */ - I8254_MODE5 = (5 << 1), /* Hardware triggered strobe - * (retriggerable) */ - I8254_BCD = 1, /* use binary-coded decimal instead of binary +enum i8254_mode { + I8254_MODE0 = (0 << 1), /* Interrupt on terminal count */ + I8254_MODE1 = (1 << 1), /* Hardware retriggerable one-shot */ + I8254_MODE2 = (2 << 1), /* Rate generator */ + I8254_MODE3 = (3 << 1), /* Square wave mode */ + I8254_MODE4 = (4 << 1), /* Software triggered strobe */ + I8254_MODE5 = (5 << 1), /* Hardware triggered strobe + * (retriggerable) */ + I8254_BCD = 1, /* use binary-coded decimal instead of binary * (pretty useless) */ - I8254_BINARY = 0 - }; - - static inline unsigned NI_USUAL_PFI_SELECT(unsigned pfi_channel) - { - if (pfi_channel < 10) - return 0x1 + pfi_channel; - else - return 0xb + pfi_channel; - } - - static inline unsigned NI_USUAL_RTSI_SELECT(unsigned rtsi_channel) - { - if (rtsi_channel < 7) - return 0xb + rtsi_channel; - else - return 0x1b; - } + I8254_BINARY = 0 +}; + +static inline unsigned NI_USUAL_PFI_SELECT(unsigned pfi_channel) +{ + if (pfi_channel < 10) + return 0x1 + pfi_channel; + else + return 0xb + pfi_channel; +} + +static inline unsigned NI_USUAL_RTSI_SELECT(unsigned rtsi_channel) +{ + if (rtsi_channel < 7) + return 0xb + rtsi_channel; + else + return 0x1b; +} /* mode bits for NI general-purpose counters, set with * INSN_CONFIG_SET_COUNTER_MODE */ #define NI_GPCT_COUNTING_MODE_SHIFT 16 #define NI_GPCT_INDEX_PHASE_BITSHIFT 20 #define NI_GPCT_COUNTING_DIRECTION_SHIFT 24 - enum ni_gpct_mode_bits { - NI_GPCT_GATE_ON_BOTH_EDGES_BIT = 0x4, - NI_GPCT_EDGE_GATE_MODE_MASK = 0x18, - NI_GPCT_EDGE_GATE_STARTS_STOPS_BITS = 0x0, - NI_GPCT_EDGE_GATE_STOPS_STARTS_BITS = 0x8, - NI_GPCT_EDGE_GATE_STARTS_BITS = 0x10, - NI_GPCT_EDGE_GATE_NO_STARTS_NO_STOPS_BITS = 0x18, - NI_GPCT_STOP_MODE_MASK = 0x60, - NI_GPCT_STOP_ON_GATE_BITS = 0x00, - NI_GPCT_STOP_ON_GATE_OR_TC_BITS = 0x20, - NI_GPCT_STOP_ON_GATE_OR_SECOND_TC_BITS = 0x40, - NI_GPCT_LOAD_B_SELECT_BIT = 0x80, - NI_GPCT_OUTPUT_MODE_MASK = 0x300, - NI_GPCT_OUTPUT_TC_PULSE_BITS = 0x100, - NI_GPCT_OUTPUT_TC_TOGGLE_BITS = 0x200, - NI_GPCT_OUTPUT_TC_OR_GATE_TOGGLE_BITS = 0x300, - NI_GPCT_HARDWARE_DISARM_MASK = 0xc00, - NI_GPCT_NO_HARDWARE_DISARM_BITS = 0x000, - NI_GPCT_DISARM_AT_TC_BITS = 0x400, - NI_GPCT_DISARM_AT_GATE_BITS = 0x800, - NI_GPCT_DISARM_AT_TC_OR_GATE_BITS = 0xc00, - NI_GPCT_LOADING_ON_TC_BIT = 0x1000, - NI_GPCT_LOADING_ON_GATE_BIT = 0x4000, - NI_GPCT_COUNTING_MODE_MASK = 0x7 << NI_GPCT_COUNTING_MODE_SHIFT, - NI_GPCT_COUNTING_MODE_NORMAL_BITS = - 0x0 << NI_GPCT_COUNTING_MODE_SHIFT, - NI_GPCT_COUNTING_MODE_QUADRATURE_X1_BITS = - 0x1 << NI_GPCT_COUNTING_MODE_SHIFT, - NI_GPCT_COUNTING_MODE_QUADRATURE_X2_BITS = - 0x2 << NI_GPCT_COUNTING_MODE_SHIFT, - NI_GPCT_COUNTING_MODE_QUADRATURE_X4_BITS = - 0x3 << NI_GPCT_COUNTING_MODE_SHIFT, - NI_GPCT_COUNTING_MODE_TWO_PULSE_BITS = - 0x4 << NI_GPCT_COUNTING_MODE_SHIFT, - NI_GPCT_COUNTING_MODE_SYNC_SOURCE_BITS = - 0x6 << NI_GPCT_COUNTING_MODE_SHIFT, - NI_GPCT_INDEX_PHASE_MASK = 0x3 << NI_GPCT_INDEX_PHASE_BITSHIFT, - NI_GPCT_INDEX_PHASE_LOW_A_LOW_B_BITS = - 0x0 << NI_GPCT_INDEX_PHASE_BITSHIFT, - NI_GPCT_INDEX_PHASE_LOW_A_HIGH_B_BITS = - 0x1 << NI_GPCT_INDEX_PHASE_BITSHIFT, - NI_GPCT_INDEX_PHASE_HIGH_A_LOW_B_BITS = - 0x2 << NI_GPCT_INDEX_PHASE_BITSHIFT, - NI_GPCT_INDEX_PHASE_HIGH_A_HIGH_B_BITS = - 0x3 << NI_GPCT_INDEX_PHASE_BITSHIFT, - NI_GPCT_INDEX_ENABLE_BIT = 0x400000, - NI_GPCT_COUNTING_DIRECTION_MASK = - 0x3 << NI_GPCT_COUNTING_DIRECTION_SHIFT, - NI_GPCT_COUNTING_DIRECTION_DOWN_BITS = - 0x00 << NI_GPCT_COUNTING_DIRECTION_SHIFT, - NI_GPCT_COUNTING_DIRECTION_UP_BITS = - 0x1 << NI_GPCT_COUNTING_DIRECTION_SHIFT, - NI_GPCT_COUNTING_DIRECTION_HW_UP_DOWN_BITS = - 0x2 << NI_GPCT_COUNTING_DIRECTION_SHIFT, - NI_GPCT_COUNTING_DIRECTION_HW_GATE_BITS = - 0x3 << NI_GPCT_COUNTING_DIRECTION_SHIFT, - NI_GPCT_RELOAD_SOURCE_MASK = 0xc000000, - NI_GPCT_RELOAD_SOURCE_FIXED_BITS = 0x0, - NI_GPCT_RELOAD_SOURCE_SWITCHING_BITS = 0x4000000, - NI_GPCT_RELOAD_SOURCE_GATE_SELECT_BITS = 0x8000000, - NI_GPCT_OR_GATE_BIT = 0x10000000, - NI_GPCT_INVERT_OUTPUT_BIT = 0x20000000 - }; +enum ni_gpct_mode_bits { + NI_GPCT_GATE_ON_BOTH_EDGES_BIT = 0x4, + NI_GPCT_EDGE_GATE_MODE_MASK = 0x18, + NI_GPCT_EDGE_GATE_STARTS_STOPS_BITS = 0x0, + NI_GPCT_EDGE_GATE_STOPS_STARTS_BITS = 0x8, + NI_GPCT_EDGE_GATE_STARTS_BITS = 0x10, + NI_GPCT_EDGE_GATE_NO_STARTS_NO_STOPS_BITS = 0x18, + NI_GPCT_STOP_MODE_MASK = 0x60, + NI_GPCT_STOP_ON_GATE_BITS = 0x00, + NI_GPCT_STOP_ON_GATE_OR_TC_BITS = 0x20, + NI_GPCT_STOP_ON_GATE_OR_SECOND_TC_BITS = 0x40, + NI_GPCT_LOAD_B_SELECT_BIT = 0x80, + NI_GPCT_OUTPUT_MODE_MASK = 0x300, + NI_GPCT_OUTPUT_TC_PULSE_BITS = 0x100, + NI_GPCT_OUTPUT_TC_TOGGLE_BITS = 0x200, + NI_GPCT_OUTPUT_TC_OR_GATE_TOGGLE_BITS = 0x300, + NI_GPCT_HARDWARE_DISARM_MASK = 0xc00, + NI_GPCT_NO_HARDWARE_DISARM_BITS = 0x000, + NI_GPCT_DISARM_AT_TC_BITS = 0x400, + NI_GPCT_DISARM_AT_GATE_BITS = 0x800, + NI_GPCT_DISARM_AT_TC_OR_GATE_BITS = 0xc00, + NI_GPCT_LOADING_ON_TC_BIT = 0x1000, + NI_GPCT_LOADING_ON_GATE_BIT = 0x4000, + NI_GPCT_COUNTING_MODE_MASK = 0x7 << NI_GPCT_COUNTING_MODE_SHIFT, + NI_GPCT_COUNTING_MODE_NORMAL_BITS = + 0x0 << NI_GPCT_COUNTING_MODE_SHIFT, + NI_GPCT_COUNTING_MODE_QUADRATURE_X1_BITS = + 0x1 << NI_GPCT_COUNTING_MODE_SHIFT, + NI_GPCT_COUNTING_MODE_QUADRATURE_X2_BITS = + 0x2 << NI_GPCT_COUNTING_MODE_SHIFT, + NI_GPCT_COUNTING_MODE_QUADRATURE_X4_BITS = + 0x3 << NI_GPCT_COUNTING_MODE_SHIFT, + NI_GPCT_COUNTING_MODE_TWO_PULSE_BITS = + 0x4 << NI_GPCT_COUNTING_MODE_SHIFT, + NI_GPCT_COUNTING_MODE_SYNC_SOURCE_BITS = + 0x6 << NI_GPCT_COUNTING_MODE_SHIFT, + NI_GPCT_INDEX_PHASE_MASK = 0x3 << NI_GPCT_INDEX_PHASE_BITSHIFT, + NI_GPCT_INDEX_PHASE_LOW_A_LOW_B_BITS = + 0x0 << NI_GPCT_INDEX_PHASE_BITSHIFT, + NI_GPCT_INDEX_PHASE_LOW_A_HIGH_B_BITS = + 0x1 << NI_GPCT_INDEX_PHASE_BITSHIFT, + NI_GPCT_INDEX_PHASE_HIGH_A_LOW_B_BITS = + 0x2 << NI_GPCT_INDEX_PHASE_BITSHIFT, + NI_GPCT_INDEX_PHASE_HIGH_A_HIGH_B_BITS = + 0x3 << NI_GPCT_INDEX_PHASE_BITSHIFT, + NI_GPCT_INDEX_ENABLE_BIT = 0x400000, + NI_GPCT_COUNTING_DIRECTION_MASK = + 0x3 << NI_GPCT_COUNTING_DIRECTION_SHIFT, + NI_GPCT_COUNTING_DIRECTION_DOWN_BITS = + 0x00 << NI_GPCT_COUNTING_DIRECTION_SHIFT, + NI_GPCT_COUNTING_DIRECTION_UP_BITS = + 0x1 << NI_GPCT_COUNTING_DIRECTION_SHIFT, + NI_GPCT_COUNTING_DIRECTION_HW_UP_DOWN_BITS = + 0x2 << NI_GPCT_COUNTING_DIRECTION_SHIFT, + NI_GPCT_COUNTING_DIRECTION_HW_GATE_BITS = + 0x3 << NI_GPCT_COUNTING_DIRECTION_SHIFT, + NI_GPCT_RELOAD_SOURCE_MASK = 0xc000000, + NI_GPCT_RELOAD_SOURCE_FIXED_BITS = 0x0, + NI_GPCT_RELOAD_SOURCE_SWITCHING_BITS = 0x4000000, + NI_GPCT_RELOAD_SOURCE_GATE_SELECT_BITS = 0x8000000, + NI_GPCT_OR_GATE_BIT = 0x10000000, + NI_GPCT_INVERT_OUTPUT_BIT = 0x20000000 +}; /* Bits for setting a clock source with * INSN_CONFIG_SET_CLOCK_SRC when using NI general-purpose counters. */ - enum ni_gpct_clock_source_bits { - NI_GPCT_CLOCK_SRC_SELECT_MASK = 0x3f, - NI_GPCT_TIMEBASE_1_CLOCK_SRC_BITS = 0x0, - NI_GPCT_TIMEBASE_2_CLOCK_SRC_BITS = 0x1, - NI_GPCT_TIMEBASE_3_CLOCK_SRC_BITS = 0x2, - NI_GPCT_LOGIC_LOW_CLOCK_SRC_BITS = 0x3, - NI_GPCT_NEXT_GATE_CLOCK_SRC_BITS = 0x4, - NI_GPCT_NEXT_TC_CLOCK_SRC_BITS = 0x5, - /* NI 660x-specific */ - NI_GPCT_SOURCE_PIN_i_CLOCK_SRC_BITS = 0x6, - NI_GPCT_PXI10_CLOCK_SRC_BITS = 0x7, - NI_GPCT_PXI_STAR_TRIGGER_CLOCK_SRC_BITS = 0x8, - NI_GPCT_ANALOG_TRIGGER_OUT_CLOCK_SRC_BITS = 0x9, - NI_GPCT_PRESCALE_MODE_CLOCK_SRC_MASK = 0x30000000, - NI_GPCT_NO_PRESCALE_CLOCK_SRC_BITS = 0x0, - /* divide source by 2 */ - NI_GPCT_PRESCALE_X2_CLOCK_SRC_BITS = 0x10000000, - /* divide source by 8 */ - NI_GPCT_PRESCALE_X8_CLOCK_SRC_BITS = 0x20000000, - NI_GPCT_INVERT_CLOCK_SRC_BIT = 0x80000000 - }; - static inline unsigned NI_GPCT_SOURCE_PIN_CLOCK_SRC_BITS(unsigned n) - { - /* NI 660x-specific */ - return 0x10 + n; - } - static inline unsigned NI_GPCT_RTSI_CLOCK_SRC_BITS(unsigned n) - { - return 0x18 + n; - } - static inline unsigned NI_GPCT_PFI_CLOCK_SRC_BITS(unsigned n) - { - /* no pfi on NI 660x */ - return 0x20 + n; - } +enum ni_gpct_clock_source_bits { + NI_GPCT_CLOCK_SRC_SELECT_MASK = 0x3f, + NI_GPCT_TIMEBASE_1_CLOCK_SRC_BITS = 0x0, + NI_GPCT_TIMEBASE_2_CLOCK_SRC_BITS = 0x1, + NI_GPCT_TIMEBASE_3_CLOCK_SRC_BITS = 0x2, + NI_GPCT_LOGIC_LOW_CLOCK_SRC_BITS = 0x3, + NI_GPCT_NEXT_GATE_CLOCK_SRC_BITS = 0x4, + NI_GPCT_NEXT_TC_CLOCK_SRC_BITS = 0x5, + /* NI 660x-specific */ + NI_GPCT_SOURCE_PIN_i_CLOCK_SRC_BITS = 0x6, + NI_GPCT_PXI10_CLOCK_SRC_BITS = 0x7, + NI_GPCT_PXI_STAR_TRIGGER_CLOCK_SRC_BITS = 0x8, + NI_GPCT_ANALOG_TRIGGER_OUT_CLOCK_SRC_BITS = 0x9, + NI_GPCT_PRESCALE_MODE_CLOCK_SRC_MASK = 0x30000000, + NI_GPCT_NO_PRESCALE_CLOCK_SRC_BITS = 0x0, + /* divide source by 2 */ + NI_GPCT_PRESCALE_X2_CLOCK_SRC_BITS = 0x10000000, + /* divide source by 8 */ + NI_GPCT_PRESCALE_X8_CLOCK_SRC_BITS = 0x20000000, + NI_GPCT_INVERT_CLOCK_SRC_BIT = 0x80000000 +}; +static inline unsigned NI_GPCT_SOURCE_PIN_CLOCK_SRC_BITS(unsigned n) +{ + /* NI 660x-specific */ + return 0x10 + n; +} +static inline unsigned NI_GPCT_RTSI_CLOCK_SRC_BITS(unsigned n) +{ + return 0x18 + n; +} +static inline unsigned NI_GPCT_PFI_CLOCK_SRC_BITS(unsigned n) +{ + /* no pfi on NI 660x */ + return 0x20 + n; +} /* Possibilities for setting a gate source with INSN_CONFIG_SET_GATE_SRC when using NI general-purpose counters. May be bitwise-or'd with CR_EDGE or CR_INVERT. */ - enum ni_gpct_gate_select { - /* m-series gates */ - NI_GPCT_TIMESTAMP_MUX_GATE_SELECT = 0x0, - NI_GPCT_AI_START2_GATE_SELECT = 0x12, - NI_GPCT_PXI_STAR_TRIGGER_GATE_SELECT = 0x13, - NI_GPCT_NEXT_OUT_GATE_SELECT = 0x14, - NI_GPCT_AI_START1_GATE_SELECT = 0x1c, - NI_GPCT_NEXT_SOURCE_GATE_SELECT = 0x1d, - NI_GPCT_ANALOG_TRIGGER_OUT_GATE_SELECT = 0x1e, - NI_GPCT_LOGIC_LOW_GATE_SELECT = 0x1f, - /* more gates for 660x */ - NI_GPCT_SOURCE_PIN_i_GATE_SELECT = 0x100, - NI_GPCT_GATE_PIN_i_GATE_SELECT = 0x101, - /* more gates for 660x "second gate" */ - NI_GPCT_UP_DOWN_PIN_i_GATE_SELECT = 0x201, - NI_GPCT_SELECTED_GATE_GATE_SELECT = 0x21e, - /* m-series "second gate" sources are unknown, - * we should add them here with an offset of 0x300 when - * known. */ - NI_GPCT_DISABLED_GATE_SELECT = 0x8000, - }; - static inline unsigned NI_GPCT_GATE_PIN_GATE_SELECT(unsigned n) - { - return 0x102 + n; - } - static inline unsigned NI_GPCT_RTSI_GATE_SELECT(unsigned n) - { - return NI_USUAL_RTSI_SELECT(n); - } - static inline unsigned NI_GPCT_PFI_GATE_SELECT(unsigned n) - { - return NI_USUAL_PFI_SELECT(n); - } - static inline unsigned NI_GPCT_UP_DOWN_PIN_GATE_SELECT(unsigned n) - { - return 0x202 + n; - } +enum ni_gpct_gate_select { + /* m-series gates */ + NI_GPCT_TIMESTAMP_MUX_GATE_SELECT = 0x0, + NI_GPCT_AI_START2_GATE_SELECT = 0x12, + NI_GPCT_PXI_STAR_TRIGGER_GATE_SELECT = 0x13, + NI_GPCT_NEXT_OUT_GATE_SELECT = 0x14, + NI_GPCT_AI_START1_GATE_SELECT = 0x1c, + NI_GPCT_NEXT_SOURCE_GATE_SELECT = 0x1d, + NI_GPCT_ANALOG_TRIGGER_OUT_GATE_SELECT = 0x1e, + NI_GPCT_LOGIC_LOW_GATE_SELECT = 0x1f, + /* more gates for 660x */ + NI_GPCT_SOURCE_PIN_i_GATE_SELECT = 0x100, + NI_GPCT_GATE_PIN_i_GATE_SELECT = 0x101, + /* more gates for 660x "second gate" */ + NI_GPCT_UP_DOWN_PIN_i_GATE_SELECT = 0x201, + NI_GPCT_SELECTED_GATE_GATE_SELECT = 0x21e, + /* m-series "second gate" sources are unknown, + * we should add them here with an offset of 0x300 when + * known. */ + NI_GPCT_DISABLED_GATE_SELECT = 0x8000, +}; +static inline unsigned NI_GPCT_GATE_PIN_GATE_SELECT(unsigned n) +{ + return 0x102 + n; +} +static inline unsigned NI_GPCT_RTSI_GATE_SELECT(unsigned n) +{ + return NI_USUAL_RTSI_SELECT(n); +} +static inline unsigned NI_GPCT_PFI_GATE_SELECT(unsigned n) +{ + return NI_USUAL_PFI_SELECT(n); +} +static inline unsigned NI_GPCT_UP_DOWN_PIN_GATE_SELECT(unsigned n) +{ + return 0x202 + n; +} /* Possibilities for setting a source with INSN_CONFIG_SET_OTHER_SRC when using NI general-purpose counters. */ - enum ni_gpct_other_index { - NI_GPCT_SOURCE_ENCODER_A, - NI_GPCT_SOURCE_ENCODER_B, - NI_GPCT_SOURCE_ENCODER_Z - }; - enum ni_gpct_other_select { - /* m-series gates */ - /* Still unknown, probably only need NI_GPCT_PFI_OTHER_SELECT */ - NI_GPCT_DISABLED_OTHER_SELECT = 0x8000, - }; - static inline unsigned NI_GPCT_PFI_OTHER_SELECT(unsigned n) - { - return NI_USUAL_PFI_SELECT(n); - } +enum ni_gpct_other_index { + NI_GPCT_SOURCE_ENCODER_A, + NI_GPCT_SOURCE_ENCODER_B, + NI_GPCT_SOURCE_ENCODER_Z +}; +enum ni_gpct_other_select { + /* m-series gates */ + /* Still unknown, probably only need NI_GPCT_PFI_OTHER_SELECT */ + NI_GPCT_DISABLED_OTHER_SELECT = 0x8000, +}; +static inline unsigned NI_GPCT_PFI_OTHER_SELECT(unsigned n) +{ + return NI_USUAL_PFI_SELECT(n); +} /* start sources for ni general-purpose counters for use with INSN_CONFIG_ARM */ - enum ni_gpct_arm_source { - NI_GPCT_ARM_IMMEDIATE = 0x0, - NI_GPCT_ARM_PAIRED_IMMEDIATE = 0x1, /* Start both the counter - * and the adjacent paired - * counter simultaneously */ - /* NI doesn't document bits for selecting hardware arm triggers. - * If the NI_GPCT_ARM_UNKNOWN bit is set, we will pass the least - * significant bits (3 bits for 660x or 5 bits for m-series) - * through to the hardware. This will at least allow someone to - * figure out what the bits do later. */ - NI_GPCT_ARM_UNKNOWN = 0x1000, - }; +enum ni_gpct_arm_source { + NI_GPCT_ARM_IMMEDIATE = 0x0, + NI_GPCT_ARM_PAIRED_IMMEDIATE = 0x1, /* Start both the counter + * and the adjacent paired + * counter simultaneously */ + /* NI doesn't document bits for selecting hardware arm triggers. + * If the NI_GPCT_ARM_UNKNOWN bit is set, we will pass the least + * significant bits (3 bits for 660x or 5 bits for m-series) + * through to the hardware. This will at least allow someone to + * figure out what the bits do later. */ + NI_GPCT_ARM_UNKNOWN = 0x1000, +}; /* digital filtering options for ni 660x for use with INSN_CONFIG_FILTER. */ - enum ni_gpct_filter_select { - NI_GPCT_FILTER_OFF = 0x0, - NI_GPCT_FILTER_TIMEBASE_3_SYNC = 0x1, - NI_GPCT_FILTER_100x_TIMEBASE_1 = 0x2, - NI_GPCT_FILTER_20x_TIMEBASE_1 = 0x3, - NI_GPCT_FILTER_10x_TIMEBASE_1 = 0x4, - NI_GPCT_FILTER_2x_TIMEBASE_1 = 0x5, - NI_GPCT_FILTER_2x_TIMEBASE_3 = 0x6 - }; +enum ni_gpct_filter_select { + NI_GPCT_FILTER_OFF = 0x0, + NI_GPCT_FILTER_TIMEBASE_3_SYNC = 0x1, + NI_GPCT_FILTER_100x_TIMEBASE_1 = 0x2, + NI_GPCT_FILTER_20x_TIMEBASE_1 = 0x3, + NI_GPCT_FILTER_10x_TIMEBASE_1 = 0x4, + NI_GPCT_FILTER_2x_TIMEBASE_1 = 0x5, + NI_GPCT_FILTER_2x_TIMEBASE_3 = 0x6 +}; /* PFI digital filtering options for ni m-series for use with * INSN_CONFIG_FILTER. */ - enum ni_pfi_filter_select { - NI_PFI_FILTER_OFF = 0x0, - NI_PFI_FILTER_125ns = 0x1, - NI_PFI_FILTER_6425ns = 0x2, - NI_PFI_FILTER_2550us = 0x3 - }; +enum ni_pfi_filter_select { + NI_PFI_FILTER_OFF = 0x0, + NI_PFI_FILTER_125ns = 0x1, + NI_PFI_FILTER_6425ns = 0x2, + NI_PFI_FILTER_2550us = 0x3 +}; /* master clock sources for ni mio boards and INSN_CONFIG_SET_CLOCK_SRC */ - enum ni_mio_clock_source { - NI_MIO_INTERNAL_CLOCK = 0, - NI_MIO_RTSI_CLOCK = 1, /* doesn't work for m-series, use - NI_MIO_PLL_RTSI_CLOCK() */ - /* the NI_MIO_PLL_* sources are m-series only */ - NI_MIO_PLL_PXI_STAR_TRIGGER_CLOCK = 2, - NI_MIO_PLL_PXI10_CLOCK = 3, - NI_MIO_PLL_RTSI0_CLOCK = 4 - }; - static inline unsigned NI_MIO_PLL_RTSI_CLOCK(unsigned rtsi_channel) - { - return NI_MIO_PLL_RTSI0_CLOCK + rtsi_channel; - } +enum ni_mio_clock_source { + NI_MIO_INTERNAL_CLOCK = 0, + NI_MIO_RTSI_CLOCK = 1, /* doesn't work for m-series, use + NI_MIO_PLL_RTSI_CLOCK() */ + /* the NI_MIO_PLL_* sources are m-series only */ + NI_MIO_PLL_PXI_STAR_TRIGGER_CLOCK = 2, + NI_MIO_PLL_PXI10_CLOCK = 3, + NI_MIO_PLL_RTSI0_CLOCK = 4 +}; +static inline unsigned NI_MIO_PLL_RTSI_CLOCK(unsigned rtsi_channel) +{ + return NI_MIO_PLL_RTSI0_CLOCK + rtsi_channel; +} /* Signals which can be routed to an NI RTSI pin with INSN_CONFIG_SET_ROUTING. The numbers assigned are not arbitrary, they correspond to the bits required to program the board. */ - enum ni_rtsi_routing { - NI_RTSI_OUTPUT_ADR_START1 = 0, - NI_RTSI_OUTPUT_ADR_START2 = 1, - NI_RTSI_OUTPUT_SCLKG = 2, - NI_RTSI_OUTPUT_DACUPDN = 3, - NI_RTSI_OUTPUT_DA_START1 = 4, - NI_RTSI_OUTPUT_G_SRC0 = 5, - NI_RTSI_OUTPUT_G_GATE0 = 6, - NI_RTSI_OUTPUT_RGOUT0 = 7, - NI_RTSI_OUTPUT_RTSI_BRD_0 = 8, - NI_RTSI_OUTPUT_RTSI_OSC = 12 /* pre-m-series always have RTSI - * clock on line 7 */ - }; - static inline unsigned NI_RTSI_OUTPUT_RTSI_BRD(unsigned n) - { - return NI_RTSI_OUTPUT_RTSI_BRD_0 + n; - } +enum ni_rtsi_routing { + NI_RTSI_OUTPUT_ADR_START1 = 0, + NI_RTSI_OUTPUT_ADR_START2 = 1, + NI_RTSI_OUTPUT_SCLKG = 2, + NI_RTSI_OUTPUT_DACUPDN = 3, + NI_RTSI_OUTPUT_DA_START1 = 4, + NI_RTSI_OUTPUT_G_SRC0 = 5, + NI_RTSI_OUTPUT_G_GATE0 = 6, + NI_RTSI_OUTPUT_RGOUT0 = 7, + NI_RTSI_OUTPUT_RTSI_BRD_0 = 8, + NI_RTSI_OUTPUT_RTSI_OSC = 12 /* pre-m-series always have RTSI + * clock on line 7 */ +}; +static inline unsigned NI_RTSI_OUTPUT_RTSI_BRD(unsigned n) +{ + return NI_RTSI_OUTPUT_RTSI_BRD_0 + n; +} /* Signals which can be routed to an NI PFI pin on an m-series board with * INSN_CONFIG_SET_ROUTING. These numbers are also returned by * INSN_CONFIG_GET_ROUTING on pre-m-series boards, even though their routing * cannot be changed. The numbers assigned are not arbitrary, they correspond * to the bits required to program the board. */ - enum ni_pfi_routing { - NI_PFI_OUTPUT_PFI_DEFAULT = 0, - NI_PFI_OUTPUT_AI_START1 = 1, - NI_PFI_OUTPUT_AI_START2 = 2, - NI_PFI_OUTPUT_AI_CONVERT = 3, - NI_PFI_OUTPUT_G_SRC1 = 4, - NI_PFI_OUTPUT_G_GATE1 = 5, - NI_PFI_OUTPUT_AO_UPDATE_N = 6, - NI_PFI_OUTPUT_AO_START1 = 7, - NI_PFI_OUTPUT_AI_START_PULSE = 8, - NI_PFI_OUTPUT_G_SRC0 = 9, - NI_PFI_OUTPUT_G_GATE0 = 10, - NI_PFI_OUTPUT_EXT_STROBE = 11, - NI_PFI_OUTPUT_AI_EXT_MUX_CLK = 12, - NI_PFI_OUTPUT_GOUT0 = 13, - NI_PFI_OUTPUT_GOUT1 = 14, - NI_PFI_OUTPUT_FREQ_OUT = 15, - NI_PFI_OUTPUT_PFI_DO = 16, - NI_PFI_OUTPUT_I_ATRIG = 17, - NI_PFI_OUTPUT_RTSI0 = 18, - NI_PFI_OUTPUT_PXI_STAR_TRIGGER_IN = 26, - NI_PFI_OUTPUT_SCXI_TRIG1 = 27, - NI_PFI_OUTPUT_DIO_CHANGE_DETECT_RTSI = 28, - NI_PFI_OUTPUT_CDI_SAMPLE = 29, - NI_PFI_OUTPUT_CDO_UPDATE = 30 - }; - static inline unsigned NI_PFI_OUTPUT_RTSI(unsigned rtsi_channel) - { - return NI_PFI_OUTPUT_RTSI0 + rtsi_channel; - } +enum ni_pfi_routing { + NI_PFI_OUTPUT_PFI_DEFAULT = 0, + NI_PFI_OUTPUT_AI_START1 = 1, + NI_PFI_OUTPUT_AI_START2 = 2, + NI_PFI_OUTPUT_AI_CONVERT = 3, + NI_PFI_OUTPUT_G_SRC1 = 4, + NI_PFI_OUTPUT_G_GATE1 = 5, + NI_PFI_OUTPUT_AO_UPDATE_N = 6, + NI_PFI_OUTPUT_AO_START1 = 7, + NI_PFI_OUTPUT_AI_START_PULSE = 8, + NI_PFI_OUTPUT_G_SRC0 = 9, + NI_PFI_OUTPUT_G_GATE0 = 10, + NI_PFI_OUTPUT_EXT_STROBE = 11, + NI_PFI_OUTPUT_AI_EXT_MUX_CLK = 12, + NI_PFI_OUTPUT_GOUT0 = 13, + NI_PFI_OUTPUT_GOUT1 = 14, + NI_PFI_OUTPUT_FREQ_OUT = 15, + NI_PFI_OUTPUT_PFI_DO = 16, + NI_PFI_OUTPUT_I_ATRIG = 17, + NI_PFI_OUTPUT_RTSI0 = 18, + NI_PFI_OUTPUT_PXI_STAR_TRIGGER_IN = 26, + NI_PFI_OUTPUT_SCXI_TRIG1 = 27, + NI_PFI_OUTPUT_DIO_CHANGE_DETECT_RTSI = 28, + NI_PFI_OUTPUT_CDI_SAMPLE = 29, + NI_PFI_OUTPUT_CDO_UPDATE = 30 +}; +static inline unsigned NI_PFI_OUTPUT_RTSI(unsigned rtsi_channel) +{ + return NI_PFI_OUTPUT_RTSI0 + rtsi_channel; +} /* Signals which can be routed to output on a NI PFI pin on a 660x board with INSN_CONFIG_SET_ROUTING. The numbers assigned are @@ -802,113 +802,112 @@ INSN_CONFIG_ARM */ to program the board. Lines 0 to 7 can only be set to NI_660X_PFI_OUTPUT_DIO. Lines 32 to 39 can only be set to NI_660X_PFI_OUTPUT_COUNTER. */ - enum ni_660x_pfi_routing { - NI_660X_PFI_OUTPUT_COUNTER = 1, /* counter */ - NI_660X_PFI_OUTPUT_DIO = 2, /* static digital output */ - }; +enum ni_660x_pfi_routing { + NI_660X_PFI_OUTPUT_COUNTER = 1, /* counter */ + NI_660X_PFI_OUTPUT_DIO = 2, /* static digital output */ +}; /* NI External Trigger lines. These values are not arbitrary, but are related * to the bits required to program the board (offset by 1 for historical * reasons). */ - static inline unsigned NI_EXT_PFI(unsigned pfi_channel) - { - return NI_USUAL_PFI_SELECT(pfi_channel) - 1; - } - static inline unsigned NI_EXT_RTSI(unsigned rtsi_channel) - { - return NI_USUAL_RTSI_SELECT(rtsi_channel) - 1; - } +static inline unsigned NI_EXT_PFI(unsigned pfi_channel) +{ + return NI_USUAL_PFI_SELECT(pfi_channel) - 1; +} +static inline unsigned NI_EXT_RTSI(unsigned rtsi_channel) +{ + return NI_USUAL_RTSI_SELECT(rtsi_channel) - 1; +} /* status bits for INSN_CONFIG_GET_COUNTER_STATUS */ - enum comedi_counter_status_flags { - COMEDI_COUNTER_ARMED = 0x1, - COMEDI_COUNTER_COUNTING = 0x2, - COMEDI_COUNTER_TERMINAL_COUNT = 0x4, - }; +enum comedi_counter_status_flags { + COMEDI_COUNTER_ARMED = 0x1, + COMEDI_COUNTER_COUNTING = 0x2, + COMEDI_COUNTER_TERMINAL_COUNT = 0x4, +}; /* Clock sources for CDIO subdevice on NI m-series boards. Used as the * scan_begin_arg for a comedi_command. These sources may also be bitwise-or'd * with CR_INVERT to change polarity. */ - enum ni_m_series_cdio_scan_begin_src { - NI_CDIO_SCAN_BEGIN_SRC_GROUND = 0, - NI_CDIO_SCAN_BEGIN_SRC_AI_START = 18, - NI_CDIO_SCAN_BEGIN_SRC_AI_CONVERT = 19, - NI_CDIO_SCAN_BEGIN_SRC_PXI_STAR_TRIGGER = 20, - NI_CDIO_SCAN_BEGIN_SRC_G0_OUT = 28, - NI_CDIO_SCAN_BEGIN_SRC_G1_OUT = 29, - NI_CDIO_SCAN_BEGIN_SRC_ANALOG_TRIGGER = 30, - NI_CDIO_SCAN_BEGIN_SRC_AO_UPDATE = 31, - NI_CDIO_SCAN_BEGIN_SRC_FREQ_OUT = 32, - NI_CDIO_SCAN_BEGIN_SRC_DIO_CHANGE_DETECT_IRQ = 33 - }; - static inline unsigned NI_CDIO_SCAN_BEGIN_SRC_PFI(unsigned pfi_channel) - { - return NI_USUAL_PFI_SELECT(pfi_channel); - } - static inline unsigned - NI_CDIO_SCAN_BEGIN_SRC_RTSI(unsigned rtsi_channel) - { - return NI_USUAL_RTSI_SELECT(rtsi_channel); - } +enum ni_m_series_cdio_scan_begin_src { + NI_CDIO_SCAN_BEGIN_SRC_GROUND = 0, + NI_CDIO_SCAN_BEGIN_SRC_AI_START = 18, + NI_CDIO_SCAN_BEGIN_SRC_AI_CONVERT = 19, + NI_CDIO_SCAN_BEGIN_SRC_PXI_STAR_TRIGGER = 20, + NI_CDIO_SCAN_BEGIN_SRC_G0_OUT = 28, + NI_CDIO_SCAN_BEGIN_SRC_G1_OUT = 29, + NI_CDIO_SCAN_BEGIN_SRC_ANALOG_TRIGGER = 30, + NI_CDIO_SCAN_BEGIN_SRC_AO_UPDATE = 31, + NI_CDIO_SCAN_BEGIN_SRC_FREQ_OUT = 32, + NI_CDIO_SCAN_BEGIN_SRC_DIO_CHANGE_DETECT_IRQ = 33 +}; +static inline unsigned NI_CDIO_SCAN_BEGIN_SRC_PFI(unsigned pfi_channel) +{ + return NI_USUAL_PFI_SELECT(pfi_channel); +} +static inline unsigned NI_CDIO_SCAN_BEGIN_SRC_RTSI(unsigned rtsi_channel) +{ + return NI_USUAL_RTSI_SELECT(rtsi_channel); +} /* scan_begin_src for scan_begin_arg==TRIG_EXT with analog output command on NI * boards. These scan begin sources can also be bitwise-or'd with CR_INVERT to * change polarity. */ - static inline unsigned NI_AO_SCAN_BEGIN_SRC_PFI(unsigned pfi_channel) - { - return NI_USUAL_PFI_SELECT(pfi_channel); - } - static inline unsigned NI_AO_SCAN_BEGIN_SRC_RTSI(unsigned rtsi_channel) - { - return NI_USUAL_RTSI_SELECT(rtsi_channel); - } +static inline unsigned NI_AO_SCAN_BEGIN_SRC_PFI(unsigned pfi_channel) +{ + return NI_USUAL_PFI_SELECT(pfi_channel); +} +static inline unsigned NI_AO_SCAN_BEGIN_SRC_RTSI(unsigned rtsi_channel) +{ + return NI_USUAL_RTSI_SELECT(rtsi_channel); +} /* Bits for setting a clock source with * INSN_CONFIG_SET_CLOCK_SRC when using NI frequency output subdevice. */ - enum ni_freq_out_clock_source_bits { - NI_FREQ_OUT_TIMEBASE_1_DIV_2_CLOCK_SRC, /* 10 MHz */ - NI_FREQ_OUT_TIMEBASE_2_CLOCK_SRC /* 100 KHz */ - }; +enum ni_freq_out_clock_source_bits { + NI_FREQ_OUT_TIMEBASE_1_DIV_2_CLOCK_SRC, /* 10 MHz */ + NI_FREQ_OUT_TIMEBASE_2_CLOCK_SRC /* 100 KHz */ +}; /* Values for setting a clock source with INSN_CONFIG_SET_CLOCK_SRC for * 8254 counter subdevices on Amplicon DIO boards (amplc_dio200 driver). */ - enum amplc_dio_clock_source { - AMPLC_DIO_CLK_CLKN, /* per channel external clock - input/output pin (pin is only an - input when clock source set to this - value, otherwise it is an output) */ - AMPLC_DIO_CLK_10MHZ, /* 10 MHz internal clock */ - AMPLC_DIO_CLK_1MHZ, /* 1 MHz internal clock */ - AMPLC_DIO_CLK_100KHZ, /* 100 kHz internal clock */ - AMPLC_DIO_CLK_10KHZ, /* 10 kHz internal clock */ - AMPLC_DIO_CLK_1KHZ, /* 1 kHz internal clock */ - AMPLC_DIO_CLK_OUTNM1, /* output of preceding counter channel - (for channel 0, preceding counter - channel is channel 2 on preceding - counter subdevice, for first counter - subdevice, preceding counter - subdevice is the last counter - subdevice) */ - AMPLC_DIO_CLK_EXT /* per chip external input pin */ - }; +enum amplc_dio_clock_source { + AMPLC_DIO_CLK_CLKN, /* per channel external clock + input/output pin (pin is only an + input when clock source set to this + value, otherwise it is an output) */ + AMPLC_DIO_CLK_10MHZ, /* 10 MHz internal clock */ + AMPLC_DIO_CLK_1MHZ, /* 1 MHz internal clock */ + AMPLC_DIO_CLK_100KHZ, /* 100 kHz internal clock */ + AMPLC_DIO_CLK_10KHZ, /* 10 kHz internal clock */ + AMPLC_DIO_CLK_1KHZ, /* 1 kHz internal clock */ + AMPLC_DIO_CLK_OUTNM1, /* output of preceding counter channel + (for channel 0, preceding counter + channel is channel 2 on preceding + counter subdevice, for first counter + subdevice, preceding counter + subdevice is the last counter + subdevice) */ + AMPLC_DIO_CLK_EXT /* per chip external input pin */ +}; /* Values for setting a gate source with INSN_CONFIG_SET_GATE_SRC for * 8254 counter subdevices on Amplicon DIO boards (amplc_dio200 driver). */ - enum amplc_dio_gate_source { - AMPLC_DIO_GAT_VCC, /* internal high logic level */ - AMPLC_DIO_GAT_GND, /* internal low logic level */ - AMPLC_DIO_GAT_GATN, /* per channel external gate input */ - AMPLC_DIO_GAT_NOUTNM2, /* negated output of counter channel - minus 2 (for channels 0 or 1, - channel minus 2 is channel 1 or 2 on - the preceding counter subdevice, for - the first counter subdevice the - preceding counter subdevice is the - last counter subdevice) */ - AMPLC_DIO_GAT_RESERVED4, - AMPLC_DIO_GAT_RESERVED5, - AMPLC_DIO_GAT_RESERVED6, - AMPLC_DIO_GAT_RESERVED7 - }; +enum amplc_dio_gate_source { + AMPLC_DIO_GAT_VCC, /* internal high logic level */ + AMPLC_DIO_GAT_GND, /* internal low logic level */ + AMPLC_DIO_GAT_GATN, /* per channel external gate input */ + AMPLC_DIO_GAT_NOUTNM2, /* negated output of counter channel + minus 2 (for channels 0 or 1, + channel minus 2 is channel 1 or 2 on + the preceding counter subdevice, for + the first counter subdevice the + preceding counter subdevice is the + last counter subdevice) */ + AMPLC_DIO_GAT_RESERVED4, + AMPLC_DIO_GAT_RESERVED5, + AMPLC_DIO_GAT_RESERVED6, + AMPLC_DIO_GAT_RESERVED7 +}; #endif /* _COMEDI_H */ diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c index e82126407e95..c2a32cf95a82 100644 --- a/drivers/staging/comedi/comedi_fops.c +++ b/drivers/staging/comedi/comedi_fops.c @@ -370,7 +370,8 @@ static int do_devconfig_ioctl(struct comedi_device *dev, return -ENOMEM; if (copy_from_user(aux_data, - comedi_aux_data(it.options, 0), aux_len)) { + (unsigned char __user * + )comedi_aux_data(it.options, 0), aux_len)) { vfree(aux_data); return -EFAULT; } @@ -426,7 +427,7 @@ static int do_bufconfig_ioctl(struct comedi_device *dev, if (bc.subdevice >= dev->n_subdevices || bc.subdevice < 0) return -EINVAL; - s = dev->subdevices + bc.subdevice; + s = &dev->subdevices[bc.subdevice]; async = s->async; if (!async) { @@ -539,7 +540,7 @@ static int do_subdinfo_ioctl(struct comedi_device *dev, /* fill subdinfo structs */ for (i = 0; i < dev->n_subdevices; i++) { - s = dev->subdevices + i; + s = &dev->subdevices[i]; us = tmp + i; us->type = s->type; @@ -617,7 +618,7 @@ static int do_chaninfo_ioctl(struct comedi_device *dev, if (it.subdev >= dev->n_subdevices) return -EINVAL; - s = dev->subdevices + it.subdev; + s = &dev->subdevices[it.subdev]; if (it.maxdata_list) { if (s->maxdata || !s->maxdata_list) @@ -685,7 +686,7 @@ static int do_bufinfo_ioctl(struct comedi_device *dev, if (bi.subdevice >= dev->n_subdevices || bi.subdevice < 0) return -EINVAL; - s = dev->subdevices + bi.subdevice; + s = &dev->subdevices[bi.subdevice]; if (s->lock && s->lock != file) return -EACCES; @@ -882,14 +883,12 @@ static int check_insn_config_length(struct comedi_insn *insn, /* by default we allow the insn since we don't have checks for * all possible cases yet */ default: - printk(KERN_WARNING - "comedi: no check for data length of config insn id " - "%i is implemented.\n" - " Add a check to %s in %s.\n" - " Assuming n=%i is correct.\n", data[0], __func__, - __FILE__, insn->n); + pr_warn("comedi: No check for data length of config insn id %i is implemented.\n", + data[0]); + pr_warn("comedi: Add a check to %s in %s.\n", + __func__, __FILE__); + pr_warn("comedi: Assuming n=%i is correct.\n", insn->n); return 0; - break; } return -EINVAL; } @@ -940,7 +939,7 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, ret = -EINVAL; break; } - s = dev->subdevices + insn->subdev; + s = &dev->subdevices[insn->subdev]; if (!s->async) { DPRINTK("no async\n"); ret = -EINVAL; @@ -951,7 +950,7 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, ret = -EAGAIN; break; } - ret = s->async->inttrig(dev, s, insn->data[0]); + ret = s->async->inttrig(dev, s, data[0]); if (ret >= 0) ret = 1; break; @@ -969,7 +968,7 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn, ret = -EINVAL; goto out; } - s = dev->subdevices + insn->subdev; + s = &dev->subdevices[insn->subdev]; if (s->type == COMEDI_SUBD_UNUSED) { DPRINTK("%d not usable subdevice\n", insn->subdev); @@ -1133,37 +1132,37 @@ static void comedi_set_subdevice_runflags(struct comedi_subdevice *s, } static int do_cmd_ioctl(struct comedi_device *dev, - struct comedi_cmd __user *cmd, void *file) + struct comedi_cmd __user *arg, void *file) { - struct comedi_cmd user_cmd; + struct comedi_cmd cmd; struct comedi_subdevice *s; struct comedi_async *async; int ret = 0; - unsigned int __user *chanlist_saver = NULL; + unsigned int __user *user_chanlist; - if (copy_from_user(&user_cmd, cmd, sizeof(struct comedi_cmd))) { + if (copy_from_user(&cmd, arg, sizeof(struct comedi_cmd))) { DPRINTK("bad cmd address\n"); return -EFAULT; } /* save user's chanlist pointer so it can be restored later */ - chanlist_saver = user_cmd.chanlist; + user_chanlist = (unsigned int __user *)cmd.chanlist; - if (user_cmd.subdev >= dev->n_subdevices) { - DPRINTK("%d no such subdevice\n", user_cmd.subdev); + if (cmd.subdev >= dev->n_subdevices) { + DPRINTK("%d no such subdevice\n", cmd.subdev); return -ENODEV; } - s = dev->subdevices + user_cmd.subdev; + s = &dev->subdevices[cmd.subdev]; async = s->async; if (s->type == COMEDI_SUBD_UNUSED) { - DPRINTK("%d not valid subdevice\n", user_cmd.subdev); + DPRINTK("%d not valid subdevice\n", cmd.subdev); return -EIO; } if (!s->do_cmd || !s->do_cmdtest || !s->async) { DPRINTK("subdevice %i does not support commands\n", - user_cmd.subdev); + cmd.subdev); return -EIO; } @@ -1181,23 +1180,22 @@ static int do_cmd_ioctl(struct comedi_device *dev, s->busy = file; /* make sure channel/gain list isn't too long */ - if (user_cmd.chanlist_len > s->len_chanlist) { + if (cmd.chanlist_len > s->len_chanlist) { DPRINTK("channel/gain list too long %u > %d\n", - user_cmd.chanlist_len, s->len_chanlist); + cmd.chanlist_len, s->len_chanlist); ret = -EINVAL; goto cleanup; } /* make sure channel/gain list isn't too short */ - if (user_cmd.chanlist_len < 1) { + if (cmd.chanlist_len < 1) { DPRINTK("channel/gain list too short %u < 1\n", - user_cmd.chanlist_len); + cmd.chanlist_len); ret = -EINVAL; goto cleanup; } - kfree(async->cmd.chanlist); - async->cmd = user_cmd; + async->cmd = cmd; async->cmd.data = NULL; /* load channel/gain list */ async->cmd.chanlist = @@ -1208,7 +1206,7 @@ static int do_cmd_ioctl(struct comedi_device *dev, goto cleanup; } - if (copy_from_user(async->cmd.chanlist, user_cmd.chanlist, + if (copy_from_user(async->cmd.chanlist, user_chanlist, async->cmd.chanlist_len * sizeof(int))) { DPRINTK("fault reading chanlist\n"); ret = -EFAULT; @@ -1228,11 +1226,11 @@ static int do_cmd_ioctl(struct comedi_device *dev, if (async->cmd.flags & TRIG_BOGUS || ret) { DPRINTK("test returned %d\n", ret); - user_cmd = async->cmd; + cmd = async->cmd; /* restore chanlist pointer before copying back */ - user_cmd.chanlist = chanlist_saver; - user_cmd.data = NULL; - if (copy_to_user(cmd, &user_cmd, sizeof(struct comedi_cmd))) { + cmd.chanlist = (unsigned int __force *)user_chanlist; + cmd.data = NULL; + if (copy_to_user(arg, &cmd, sizeof(struct comedi_cmd))) { DPRINTK("fault writing cmd\n"); ret = -EFAULT; goto cleanup; @@ -1285,77 +1283,77 @@ cleanup: static int do_cmdtest_ioctl(struct comedi_device *dev, struct comedi_cmd __user *arg, void *file) { - struct comedi_cmd user_cmd; + struct comedi_cmd cmd; struct comedi_subdevice *s; int ret = 0; unsigned int *chanlist = NULL; - unsigned int __user *chanlist_saver = NULL; + unsigned int __user *user_chanlist; - if (copy_from_user(&user_cmd, arg, sizeof(struct comedi_cmd))) { + if (copy_from_user(&cmd, arg, sizeof(struct comedi_cmd))) { DPRINTK("bad cmd address\n"); return -EFAULT; } /* save user's chanlist pointer so it can be restored later */ - chanlist_saver = user_cmd.chanlist; + user_chanlist = (unsigned int __user *)cmd.chanlist; - if (user_cmd.subdev >= dev->n_subdevices) { - DPRINTK("%d no such subdevice\n", user_cmd.subdev); + if (cmd.subdev >= dev->n_subdevices) { + DPRINTK("%d no such subdevice\n", cmd.subdev); return -ENODEV; } - s = dev->subdevices + user_cmd.subdev; + s = &dev->subdevices[cmd.subdev]; if (s->type == COMEDI_SUBD_UNUSED) { - DPRINTK("%d not valid subdevice\n", user_cmd.subdev); + DPRINTK("%d not valid subdevice\n", cmd.subdev); return -EIO; } if (!s->do_cmd || !s->do_cmdtest) { DPRINTK("subdevice %i does not support commands\n", - user_cmd.subdev); + cmd.subdev); return -EIO; } /* make sure channel/gain list isn't too long */ - if (user_cmd.chanlist_len > s->len_chanlist) { + if (cmd.chanlist_len > s->len_chanlist) { DPRINTK("channel/gain list too long %d > %d\n", - user_cmd.chanlist_len, s->len_chanlist); + cmd.chanlist_len, s->len_chanlist); ret = -EINVAL; goto cleanup; } /* load channel/gain list */ - if (user_cmd.chanlist) { + if (cmd.chanlist) { chanlist = - kmalloc(user_cmd.chanlist_len * sizeof(int), GFP_KERNEL); + kmalloc(cmd.chanlist_len * sizeof(int), GFP_KERNEL); if (!chanlist) { DPRINTK("allocation failed\n"); ret = -ENOMEM; goto cleanup; } - if (copy_from_user(chanlist, user_cmd.chanlist, - user_cmd.chanlist_len * sizeof(int))) { + if (copy_from_user(chanlist, user_chanlist, + cmd.chanlist_len * sizeof(int))) { DPRINTK("fault reading chanlist\n"); ret = -EFAULT; goto cleanup; } /* make sure each element in channel/gain list is valid */ - ret = comedi_check_chanlist(s, user_cmd.chanlist_len, chanlist); + ret = comedi_check_chanlist(s, cmd.chanlist_len, chanlist); if (ret < 0) { DPRINTK("bad chanlist\n"); goto cleanup; } - user_cmd.chanlist = chanlist; + cmd.chanlist = chanlist; } - ret = s->do_cmdtest(dev, s, &user_cmd); + ret = s->do_cmdtest(dev, s, &cmd); /* restore chanlist pointer before copying back */ - user_cmd.chanlist = chanlist_saver; + cmd.chanlist = (unsigned int __force *)user_chanlist; - if (copy_to_user(arg, &user_cmd, sizeof(struct comedi_cmd))) { + if (copy_to_user(arg, &cmd, sizeof(struct comedi_cmd))) { DPRINTK("bad cmd address\n"); ret = -EFAULT; goto cleanup; @@ -1390,7 +1388,7 @@ static int do_lock_ioctl(struct comedi_device *dev, unsigned int arg, if (arg >= dev->n_subdevices) return -EINVAL; - s = dev->subdevices + arg; + s = &dev->subdevices[arg]; spin_lock_irqsave(&s->spin_lock, flags); if (s->busy || s->lock) @@ -1433,7 +1431,7 @@ static int do_unlock_ioctl(struct comedi_device *dev, unsigned int arg, if (arg >= dev->n_subdevices) return -EINVAL; - s = dev->subdevices + arg; + s = &dev->subdevices[arg]; if (s->busy) return -EBUSY; @@ -1474,7 +1472,7 @@ static int do_cancel_ioctl(struct comedi_device *dev, unsigned int arg, if (arg >= dev->n_subdevices) return -EINVAL; - s = dev->subdevices + arg; + s = &dev->subdevices[arg]; if (s->async == NULL) return -EINVAL; @@ -1511,7 +1509,7 @@ static int do_poll_ioctl(struct comedi_device *dev, unsigned int arg, if (arg >= dev->n_subdevices) return -EINVAL; - s = dev->subdevices + arg; + s = &dev->subdevices[arg]; if (s->lock && s->lock != file) return -EACCES; @@ -2025,7 +2023,8 @@ done: /* This function restores a subdevice to an idle state. */ -void do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s) +static void do_become_nonbusy(struct comedi_device *dev, + struct comedi_subdevice *s) { struct comedi_async *async = s->async; @@ -2033,9 +2032,11 @@ void do_become_nonbusy(struct comedi_device *dev, struct comedi_subdevice *s) if (async) { comedi_reset_async_buf(async); async->inttrig = NULL; + kfree(async->cmd.chanlist); + async->cmd.chanlist = NULL; } else { - printk(KERN_ERR - "BUG: (?) do_become_nonbusy called with async=0\n"); + dev_err(dev->class_dev, + "BUG: (?) do_become_nonbusy called with async=NULL\n"); } s->busy = NULL; @@ -2140,7 +2141,7 @@ static int comedi_close(struct inode *inode, struct file *file) if (dev->subdevices) { for (i = 0; i < dev->n_subdevices; i++) { - s = dev->subdevices + i; + s = &dev->subdevices[i]; if (s->busy == file) do_cancel(dev, s); @@ -2211,14 +2212,12 @@ static int __init comedi_init(void) int i; int retval; - printk(KERN_INFO "comedi: version " COMEDI_RELEASE - " - http://www.comedi.org\n"); + pr_info("comedi: version " COMEDI_RELEASE " - http://www.comedi.org\n"); if (comedi_num_legacy_minors < 0 || comedi_num_legacy_minors > COMEDI_NUM_BOARD_MINORS) { - printk(KERN_ERR "comedi: error: invalid value for module " - "parameter \"comedi_num_legacy_minors\". Valid values " - "are 0 through %i.\n", COMEDI_NUM_BOARD_MINORS); + pr_err("comedi: error: invalid value for module parameter \"comedi_num_legacy_minors\". Valid values are 0 through %i.\n", + COMEDI_NUM_BOARD_MINORS); return -EINVAL; } @@ -2247,7 +2246,7 @@ static int __init comedi_init(void) } comedi_class = class_create(THIS_MODULE, "comedi"); if (IS_ERR(comedi_class)) { - printk(KERN_ERR "comedi: failed to create class"); + pr_err("comedi: failed to create class\n"); cdev_del(&comedi_cdev); unregister_chrdev_region(MKDEV(COMEDI_MAJOR, 0), COMEDI_NUM_MINORS); @@ -2295,8 +2294,7 @@ module_exit(comedi_cleanup); void comedi_error(const struct comedi_device *dev, const char *s) { - printk(KERN_ERR "comedi%d: %s: %s\n", dev->minor, - dev->driver->driver_name, s); + dev_err(dev->class_dev, "%s: %s\n", dev->driver->driver_name, s); } EXPORT_SYMBOL(comedi_error); @@ -2364,7 +2362,7 @@ static int is_device_busy(struct comedi_device *dev) return 0; for (i = 0; i < dev->n_subdevices; i++) { - s = dev->subdevices + i; + s = &dev->subdevices[i]; if (s->busy) return 1; if (s->async && s->async->mmap_count) @@ -2420,9 +2418,7 @@ int comedi_alloc_board_minor(struct device *hardware_device) comedi_device_cleanup(info->device); kfree(info->device); kfree(info); - printk(KERN_ERR - "comedi: error: " - "ran out of minor numbers for board device files.\n"); + pr_err("comedi: error: ran out of minor numbers for board device files.\n"); return -EBUSY; } info->device->minor = i; @@ -2499,9 +2495,7 @@ int comedi_alloc_subdevice_minor(struct comedi_device *dev, spin_unlock(&comedi_file_info_table_lock); if (i == COMEDI_NUM_MINORS) { kfree(info); - printk(KERN_ERR - "comedi: error: " - "ran out of minor numbers for board device files.\n"); + pr_err("comedi: error: ran out of minor numbers for board device files.\n"); return -EBUSY; } s->minor = i; diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h index f713783ef624..cb67a5cb9c82 100644 --- a/drivers/staging/comedi/comedidev.h +++ b/drivers/staging/comedi/comedidev.h @@ -46,7 +46,7 @@ #define DPRINTK(format, args...) do { \ if (comedi_debug) \ - printk(KERN_DEBUG "comedi: " format , ## args); \ + pr_debug("comedi: " format, ## args); \ } while (0) #define COMEDI_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c)) diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c index 2359151af7e1..1db6bfdbf13b 100644 --- a/drivers/staging/comedi/drivers.c +++ b/drivers/staging/comedi/drivers.c @@ -71,7 +71,7 @@ int comedi_alloc_subdevices(struct comedi_device *dev, int num_subdevices) dev->n_subdevices = num_subdevices; for (i = 0; i < num_subdevices; ++i) { - s = dev->subdevices + i; + s = &dev->subdevices[i]; s->device = dev; s->async_dma_dir = DMA_NONE; spin_lock_init(&s->spin_lock); @@ -88,7 +88,7 @@ static void cleanup_device(struct comedi_device *dev) if (dev->subdevices) { for (i = 0; i < dev->n_subdevices; i++) { - s = dev->subdevices + i; + s = &dev->subdevices[i]; comedi_free_subdevice_minor(s); if (s->async) { comedi_buf_alloc(dev, s, 0); @@ -119,8 +119,8 @@ static void __comedi_device_detach(struct comedi_device *dev) if (dev->driver) dev->driver->detach(dev); else - printk(KERN_WARNING - "BUG: dev->driver=NULL in comedi_device_detach()\n"); + dev_warn(dev->class_dev, + "BUG: dev->driver=NULL in comedi_device_detach()\n"); cleanup_device(dev); } @@ -142,8 +142,7 @@ static int comedi_device_postconfig(struct comedi_device *dev) return ret; } if (!dev->board_name) { - printk(KERN_WARNING "BUG: dev->board_name=<%p>\n", - dev->board_name); + dev_warn(dev->class_dev, "BUG: dev->board_name=NULL\n"); dev->board_name = "BUG"; } smp_wmb(); @@ -160,10 +159,8 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it) return -EBUSY; for (driv = comedi_drivers; driv; driv = driv->next) { - if (!try_module_get(driv->module)) { - printk(KERN_INFO "comedi: failed to increment module count, skipping\n"); + if (!try_module_get(driv->module)) continue; - } if (driv->num_names) { dev->board_ptr = comedi_recognize(driv, it->board_name); if (dev->board_ptr) @@ -176,16 +173,21 @@ int comedi_device_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* recognize has failed if we get here */ /* report valid board names before returning error */ for (driv = comedi_drivers; driv; driv = driv->next) { - if (!try_module_get(driv->module)) { - printk(KERN_INFO - "comedi: failed to increment module count\n"); + if (!try_module_get(driv->module)) continue; - } comedi_report_boards(driv); module_put(driv->module); } return -EIO; } + if (driv->attach == NULL) { + /* driver does not support manual configuration */ + dev_warn(dev->class_dev, + "driver '%s' does not support attach using comedi_config\n", + driv->driver_name); + module_put(driv->module); + return -ENOSYS; + } /* initialize dev->driver here so * comedi_error() can be called from attach */ dev->driver = driv; @@ -225,8 +227,9 @@ int comedi_driver_unregister(struct comedi_driver *driver) mutex_lock(&dev->mutex); if (dev->attached && dev->driver == driver) { if (dev->use_count) - printk(KERN_WARNING "BUG! detaching device with use_count=%d\n", - dev->use_count); + dev_warn(dev->class_dev, + "BUG! detaching device with use_count=%d\n", + dev->use_count); comedi_device_detach(dev); } mutex_unlock(&dev->mutex); @@ -255,7 +258,7 @@ static int postconfig(struct comedi_device *dev) int ret; for (i = 0; i < dev->n_subdevices; i++) { - s = dev->subdevices + i; + s = &dev->subdevices[i]; if (s->type == COMEDI_SUBD_UNUSED) continue; @@ -273,8 +276,8 @@ static int postconfig(struct comedi_device *dev) async = kzalloc(sizeof(struct comedi_async), GFP_KERNEL); if (async == NULL) { - printk(KERN_INFO - "failed to allocate async struct\n"); + dev_warn(dev->class_dev, + "failed to allocate async struct\n"); return -ENOMEM; } init_waitqueue_head(&async->wait_head); @@ -290,7 +293,8 @@ static int postconfig(struct comedi_device *dev) async->prealloc_buf = NULL; async->prealloc_bufsz = 0; if (comedi_buf_alloc(dev, s, buf_size) < 0) { - printk(KERN_INFO "Buffer allocation failed\n"); + dev_warn(dev->class_dev, + "Buffer allocation failed\n"); return -ENOMEM; } if (s->buf_change) { @@ -370,17 +374,17 @@ static void comedi_report_boards(struct comedi_driver *driv) unsigned int i; const char *const *name_ptr; - printk(KERN_INFO "comedi: valid board names for %s driver are:\n", - driv->driver_name); + pr_info("comedi: valid board names for %s driver are:\n", + driv->driver_name); name_ptr = driv->board_name; for (i = 0; i < driv->num_names; i++) { - printk(KERN_INFO " %s\n", *name_ptr); + pr_info(" %s\n", *name_ptr); name_ptr = (const char **)((char *)name_ptr + driv->offset); } if (driv->num_names == 0) - printk(KERN_INFO " %s\n", driv->driver_name); + pr_info(" %s\n", driv->driver_name); } static int poll_invalid(struct comedi_device *dev, struct comedi_subdevice *s) @@ -411,7 +415,6 @@ static int insn_rw_emulate_bits(struct comedi_device *dev, new_insn.insn = INSN_BITS; new_insn.chanspec = base_bitfield_channel; new_insn.n = 2; - new_insn.data = new_data; new_insn.subdev = insn->subdev; if (insn->insn == INSN_WRITE) { @@ -584,9 +587,9 @@ static unsigned int comedi_buf_munge(struct comedi_async *async, block_size = num_bytes - count; if (block_size < 0) { - printk(KERN_WARNING - "%s: %s: bug! block_size is negative\n", - __FILE__, __func__); + dev_warn(s->device->class_dev, + "%s: %s: bug! block_size is negative\n", + __FILE__, __func__); break; } if ((int)(async->munge_ptr + block_size - @@ -667,7 +670,8 @@ unsigned comedi_buf_write_free(struct comedi_async *async, unsigned int nbytes) { if ((int)(async->buf_write_count + nbytes - async->buf_write_alloc_count) > 0) { - printk(KERN_INFO "comedi: attempted to write-free more bytes than have been write-allocated.\n"); + dev_info(async->subdevice->device->class_dev, + "attempted to write-free more bytes than have been write-allocated.\n"); nbytes = async->buf_write_alloc_count - async->buf_write_count; } async->buf_write_count += nbytes; @@ -703,8 +707,8 @@ unsigned comedi_buf_read_free(struct comedi_async *async, unsigned int nbytes) smp_mb(); if ((int)(async->buf_read_count + nbytes - async->buf_read_alloc_count) > 0) { - printk(KERN_INFO - "comedi: attempted to read-free more bytes than have been read-allocated.\n"); + dev_info(async->subdevice->device->class_dev, + "attempted to read-free more bytes than have been read-allocated.\n"); nbytes = async->buf_read_alloc_count - async->buf_read_count; } async->buf_read_count += nbytes; @@ -853,10 +857,9 @@ comedi_auto_config_helper(struct device *hardware_device, mutex_lock(&comedi_dev->mutex); if (comedi_dev->attached) ret = -EBUSY; - else if (!try_module_get(driver->module)) { - printk(KERN_INFO "comedi: failed to increment module count\n"); + else if (!try_module_get(driver->module)) ret = -EIO; - } else { + else { /* set comedi_dev->driver here for attach wrapper */ comedi_dev->driver = driver; ret = (*attach_wrapper)(comedi_dev, context); @@ -884,14 +887,19 @@ static int comedi_auto_config_wrapper(struct comedi_device *dev, void *context) * has already been copied to it->board_name */ dev->board_ptr = comedi_recognize(driv, it->board_name); if (dev->board_ptr == NULL) { - printk(KERN_WARNING - "comedi: auto config failed to find board entry" - " '%s' for driver '%s'\n", it->board_name, - driv->driver_name); + dev_warn(dev->class_dev, + "auto config failed to find board entry '%s' for driver '%s'\n", + it->board_name, driv->driver_name); comedi_report_boards(driv); return -EINVAL; } } + if (!driv->attach) { + dev_warn(dev->class_dev, + "BUG! driver '%s' using old-style auto config but has no attach handler\n", + driv->driver_name); + return -EINVAL; + } return driv->attach(dev, it); } diff --git a/drivers/staging/comedi/drivers/8253.h b/drivers/staging/comedi/drivers/8253.h index 3eb45d46e05b..429e0d60c0a3 100644 --- a/drivers/staging/comedi/drivers/8253.h +++ b/drivers/staging/comedi/drivers/8253.h @@ -262,8 +262,10 @@ static inline int i8254_load(unsigned long base_address, unsigned int regshift, return 0; } -static inline int i8254_mm_load(void *base_address, unsigned int regshift, - unsigned int counter_number, unsigned int count, +static inline int i8254_mm_load(void __iomem *base_address, + unsigned int regshift, + unsigned int counter_number, + unsigned int count, unsigned int mode) { unsigned int byte; @@ -311,7 +313,8 @@ static inline int i8254_read(unsigned long base_address, unsigned int regshift, return ret; } -static inline int i8254_mm_read(void *base_address, unsigned int regshift, +static inline int i8254_mm_read(void __iomem *base_address, + unsigned int regshift, unsigned int counter_number) { unsigned int byte; @@ -348,7 +351,7 @@ static inline void i8254_write(unsigned long base_address, outb(byte, base_address + (counter_number << regshift)); } -static inline void i8254_mm_write(void *base_address, +static inline void i8254_mm_write(void __iomem *base_address, unsigned int regshift, unsigned int counter_number, unsigned int count) @@ -390,7 +393,7 @@ static inline int i8254_set_mode(unsigned long base_address, return 0; } -static inline int i8254_mm_set_mode(void *base_address, +static inline int i8254_mm_set_mode(void __iomem *base_address, unsigned int regshift, unsigned int counter_number, unsigned int mode) @@ -419,7 +422,7 @@ static inline int i8254_status(unsigned long base_address, return inb(base_address + (counter_number << regshift)); } -static inline int i8254_mm_status(void *base_address, +static inline int i8254_mm_status(void __iomem *base_address, unsigned int regshift, unsigned int counter_number) { diff --git a/drivers/staging/comedi/drivers/8255.c b/drivers/staging/comedi/drivers/8255.c index 4c9977b8a5ae..a256622e2dd7 100644 --- a/drivers/staging/comedi/drivers/8255.c +++ b/drivers/staging/comedi/drivers/8255.c @@ -82,6 +82,8 @@ I/O port base address can be found in the output of 'lspci -v'. #include <linux/ioport.h> #include <linux/slab.h> + +#include "comedi_fc.h" #include "8255.h" #define _8255_SIZE 4 @@ -229,39 +231,20 @@ static int subdev_8255_cmdtest(struct comedi_device *dev, struct comedi_cmd *cmd) { int err = 0; - unsigned int tmp; - - /* step 1 */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_FOLLOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE); if (err) return 1; - /* step 2 */ + /* Step 2a : make sure trigger sources are unique */ + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -403,7 +386,7 @@ static int dev_8255_attach(struct comedi_device *dev, return ret; for (i = 0; i < dev->n_subdevices; i++) { - s = dev->subdevices + i; + s = &dev->subdevices[i]; iobase = it->options[i]; if (!request_region(iobase, _8255_SIZE, "8255")) { @@ -429,7 +412,7 @@ static void dev_8255_detach(struct comedi_device *dev) int i; for (i = 0; i < dev->n_subdevices; i++) { - s = dev->subdevices + i; + s = &dev->subdevices[i]; if (s->type != COMEDI_SUBD_UNUSED) { spriv = s->private; release_region(spriv->iobase, _8255_SIZE); diff --git a/drivers/staging/comedi/drivers/8255_pci.c b/drivers/staging/comedi/drivers/8255_pci.c new file mode 100644 index 000000000000..7dff3c01dc29 --- /dev/null +++ b/drivers/staging/comedi/drivers/8255_pci.c @@ -0,0 +1,353 @@ +/* + * COMEDI driver for generic PCI based 8255 digital i/o boards + * Copyright (C) 2012 H Hartley Sweeten <hsweeten@visionengravers.com> + * + * Based on the tested adl_pci7296 driver written by: + * Jon Grierson <jd@renko.co.uk> + * and the experimental cb_pcidio driver written by: + * Yoshiya Matsuzaka + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* +Driver: 8255_pci +Description: Generic PCI based 8255 Digital I/O boards +Devices: (ADLink) PCI-7224 [adl_pci-7224] - 24 channels + (ADLink) PCI-7248 [adl_pci-7248] - 48 channels + (ADLink) PCI-7296 [adl_pci-7296] - 96 channels + (Measurement Computing) PCI-DIO24 [cb_pci-dio24] - 24 channels + (Measurement Computing) PCI-DIO24H [cb_pci-dio24h] - 24 channels + (Measurement Computing) PCI-DIO48H [cb_pci-dio48h] - 48 channels + (Measurement Computing) PCI-DIO96H [cb_pci-dio96h] - 96 channels + (National Instruments) PCI-DIO-96 [ni_pci-dio-96] - 96 channels + (National Instruments) PCI-DIO-96B [ni_pci-dio-96b] - 96 channels + (National Instruments) PXI-6508 [ni_pxi-6508] - 96 channels + (National Instruments) PCI-6503 [ni_pci-6503] - 24 channels + (National Instruments) PCI-6503B [ni_pci-6503b] - 24 channels + (National Instruments) PCI-6503X [ni_pci-6503x] - 24 channels + (National Instruments) PXI-6503 [ni_pxi-6503] - 24 channels +Author: H Hartley Sweeten <hsweeten@visionengravers.com> +Updated: Wed, 12 Sep 2012 11:52:01 -0700 +Status: untested + +Some of these boards also have an 8254 programmable timer/counter +chip. This chip is not currently supported by this driver. + +Interrupt support for these boards is also not currently supported. + +Configuration Options: not applicable, uses PCI auto config +*/ + +#include "../comedidev.h" + +#include "8255.h" + +/* + * PCI Device ID's supported by this driver + */ +#define PCI_DEVICE_ID_ADLINK_PCI7224 0x7224 +#define PCI_DEVICE_ID_ADLINK_PCI7248 0x7248 +#define PCI_DEVICE_ID_ADLINK_PCI7296 0x7296 + +/* ComputerBoards is now known as Measurement Computing */ +#define PCI_VENDOR_ID_CB 0x1307 + +#define PCI_DEVICE_ID_CB_PCIDIO48H 0x000b +#define PCI_DEVICE_ID_CB_PCIDIO24H 0x0014 +#define PCI_DEVICE_ID_CB_PCIDIO96H 0x0017 +#define PCI_DEVICE_ID_CB_PCIDIO24 0x0028 + +#define PCI_DEVICE_ID_NI_PCIDIO96 0x0160 +#define PCI_DEVICE_ID_NI_PCI6503 0x0400 +#define PCI_DEVICE_ID_NI_PCI6503B 0x1250 +#define PCI_DEVICE_ID_NI_PXI6508 0x13c0 +#define PCI_DEVICE_ID_NI_PCIDIO96B 0x1630 +#define PCI_DEVICE_ID_NI_PCI6503X 0x17d0 +#define PCI_DEVICE_ID_NI_PXI_6503 0x1800 + +struct pci_8255_boardinfo { + const char *name; + unsigned short vendor; + unsigned short device; + int dio_badr; + int is_mmio; + int n_8255; +}; + +static const struct pci_8255_boardinfo pci_8255_boards[] = { + { + .name = "adl_pci-7224", + .vendor = PCI_VENDOR_ID_ADLINK, + .device = PCI_DEVICE_ID_ADLINK_PCI7224, + .dio_badr = 2, + .n_8255 = 1, + }, { + .name = "adl_pci-7248", + .vendor = PCI_VENDOR_ID_ADLINK, + .device = PCI_DEVICE_ID_ADLINK_PCI7248, + .dio_badr = 2, + .n_8255 = 2, + }, { + .name = "adl_pci-7296", + .vendor = PCI_VENDOR_ID_ADLINK, + .device = PCI_DEVICE_ID_ADLINK_PCI7296, + .dio_badr = 2, + .n_8255 = 4, + }, { + .name = "cb_pci-dio24", + .vendor = PCI_VENDOR_ID_CB, + .device = PCI_DEVICE_ID_CB_PCIDIO24, + .dio_badr = 2, + .n_8255 = 1, + }, { + .name = "cb_pci-dio24h", + .vendor = PCI_VENDOR_ID_CB, + .device = PCI_DEVICE_ID_CB_PCIDIO24H, + .dio_badr = 2, + .n_8255 = 1, + }, { + .name = "cb_pci-dio48h", + .vendor = PCI_VENDOR_ID_CB, + .device = PCI_DEVICE_ID_CB_PCIDIO48H, + .dio_badr = 1, + .n_8255 = 2, + }, { + .name = "cb_pci-dio96h", + .vendor = PCI_VENDOR_ID_CB, + .device = PCI_DEVICE_ID_CB_PCIDIO96H, + .dio_badr = 2, + .n_8255 = 4, + }, { + .name = "ni_pci-dio-96", + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PCIDIO96, + .dio_badr = 1, + .is_mmio = 1, + .n_8255 = 4, + }, { + .name = "ni_pci-dio-96b", + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PCIDIO96B, + .dio_badr = 1, + .is_mmio = 1, + .n_8255 = 4, + }, { + .name = "ni_pxi-6508", + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PXI6508, + .dio_badr = 1, + .is_mmio = 1, + .n_8255 = 4, + }, { + .name = "ni_pci-6503", + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PCI6503, + .dio_badr = 1, + .is_mmio = 1, + .n_8255 = 1, + }, { + .name = "ni_pci-6503b", + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PCI6503B, + .dio_badr = 1, + .is_mmio = 1, + .n_8255 = 1, + }, { + .name = "ni_pci-6503x", + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PCI6503X, + .dio_badr = 1, + .is_mmio = 1, + .n_8255 = 1, + }, { + .name = "ni_pxi-6503", + .vendor = PCI_VENDOR_ID_NI, + .device = PCI_DEVICE_ID_NI_PXI_6503, + .dio_badr = 1, + .is_mmio = 1, + .n_8255 = 1, + }, +}; + +struct pci_8255_private { + void __iomem *mmio_base; +}; + +static int pci_8255_mmio(int dir, int port, int data, unsigned long iobase) +{ + void __iomem *mmio_base = (void __iomem *)iobase; + + if (dir) { + writeb(data, mmio_base + port); + return 0; + } else { + return readb(mmio_base + port); + } +} + +static const void *pci_8255_find_boardinfo(struct comedi_device *dev, + struct pci_dev *pcidev) +{ + const struct pci_8255_boardinfo *board; + int i; + + for (i = 0; i < ARRAY_SIZE(pci_8255_boards); i++) { + board = &pci_8255_boards[i]; + if (pcidev->vendor == board->vendor && + pcidev->device == board->device) + return board; + } + return NULL; +} + +static int pci_8255_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) +{ + const struct pci_8255_boardinfo *board; + struct pci_8255_private *devpriv; + struct comedi_subdevice *s; + resource_size_t iobase; + unsigned long len; + int ret; + int i; + + comedi_set_hw_dev(dev, &pcidev->dev); + + board = pci_8255_find_boardinfo(dev, pcidev); + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; + + ret = alloc_private(dev, sizeof(*devpriv)); + if (ret < 0) + return ret; + devpriv = dev->private; + + ret = comedi_pci_enable(pcidev, dev->board_name); + if (ret) + return ret; + iobase = pci_resource_start(pcidev, board->dio_badr); + len = pci_resource_len(pcidev, board->dio_badr); + + if (board->is_mmio) { + devpriv->mmio_base = ioremap(iobase, len); + if (!devpriv->mmio_base) + return -ENOMEM; + } + dev->iobase = iobase; + + /* + * One, two, or four subdevices are setup by this driver depending + * on the number of channels provided by the board. Each subdevice + * has 24 channels supported by the 8255 module. + */ + ret = comedi_alloc_subdevices(dev, board->n_8255); + if (ret) + return ret; + + for (i = 0; i < board->n_8255; i++) { + s = &dev->subdevices[i]; + if (board->is_mmio) { + iobase = (unsigned long)(devpriv->mmio_base + (i * 4)); + ret = subdev_8255_init(dev, s, pci_8255_mmio, iobase); + } else { + iobase = dev->iobase + (i * 4); + ret = subdev_8255_init(dev, s, NULL, iobase); + } + if (ret) + return ret; + } + + dev_info(dev->class_dev, "%s attached (%d digital i/o channels)\n", + dev->board_name, board->n_8255 * 24); + + return 0; +} + +static void pci_8255_detach(struct comedi_device *dev) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct pci_8255_boardinfo *board = comedi_board(dev); + struct pci_8255_private *devpriv = dev->private; + struct comedi_subdevice *s; + int i; + + if (dev->subdevices) { + for (i = 0; i < board->n_8255; i++) { + s = &dev->subdevices[i]; + subdev_8255_cleanup(dev, s); + } + } + if (pcidev) { + if (devpriv->mmio_base) + iounmap(devpriv->mmio_base); + if (dev->iobase) + comedi_pci_disable(pcidev); + } +} + +static struct comedi_driver pci_8255_driver = { + .driver_name = "8255_pci", + .module = THIS_MODULE, + .attach_pci = pci_8255_attach_pci, + .detach = pci_8255_detach, +}; + +static int __devinit pci_8255_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + return comedi_pci_auto_config(dev, &pci_8255_driver); +} + +static void __devexit pci_8255_pci_remove(struct pci_dev *dev) +{ + comedi_pci_auto_unconfig(dev); +} + +static DEFINE_PCI_DEVICE_TABLE(pci_8255_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_ADLINK_PCI7224) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_ADLINK_PCI7248) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_ADLINK_PCI7296) }, + { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_CB_PCIDIO24) }, + { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_CB_PCIDIO24H) }, + { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_CB_PCIDIO48H) }, + { PCI_DEVICE(PCI_VENDOR_ID_CB, PCI_DEVICE_ID_CB_PCIDIO96H) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCIDIO96) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCIDIO96B) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI6508) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI6503) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI6503B) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PCI6503X) }, + { PCI_DEVICE(PCI_VENDOR_ID_NI, PCI_DEVICE_ID_NI_PXI_6503) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, pci_8255_pci_table); + +static struct pci_driver pci_8255_pci_driver = { + .name = "8255_pci", + .id_table = pci_8255_pci_table, + .probe = pci_8255_pci_probe, + .remove = __devexit_p(pci_8255_pci_remove), +}; +module_comedi_pci_driver(pci_8255_driver, pci_8255_pci_driver); + +MODULE_DESCRIPTION("COMEDI - Generic PCI based 8255 Digital I/O boards"); +MODULE_AUTHOR("Comedi http://www.comedi.org"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile index 57b19e44d867..a2787c0ca327 100644 --- a/drivers/staging/comedi/drivers/Makefile +++ b/drivers/staging/comedi/drivers/Makefile @@ -55,6 +55,7 @@ obj-$(CONFIG_COMEDI_MULTIQ3) += multiq3.o obj-$(CONFIG_COMEDI_POC) += poc.o # Comedi PCI drivers +obj-$(CONFIG_COMEDI_8255_PCI) += 8255_pci.o obj-$(CONFIG_COMEDI_ADDI_APCI_035) += addi_apci_035.o obj-$(CONFIG_COMEDI_ADDI_APCI_1032) += addi_apci_1032.o obj-$(CONFIG_COMEDI_ADDI_APCI_1500) += addi_apci_1500.o @@ -69,9 +70,7 @@ obj-$(CONFIG_COMEDI_ADDI_APCI_3120) += addi_apci_3120.o obj-$(CONFIG_COMEDI_ADDI_APCI_3501) += addi_apci_3501.o obj-$(CONFIG_COMEDI_ADDI_APCI_3XXX) += addi_apci_3xxx.o obj-$(CONFIG_COMEDI_ADL_PCI6208) += adl_pci6208.o -obj-$(CONFIG_COMEDI_ADL_PCI7230) += adl_pci7230.o -obj-$(CONFIG_COMEDI_ADL_PCI7296) += adl_pci7296.o -obj-$(CONFIG_COMEDI_ADL_PCI7432) += adl_pci7432.o +obj-$(CONFIG_COMEDI_ADL_PCI7X3X) += adl_pci7x3x.o obj-$(CONFIG_COMEDI_ADL_PCI8164) += adl_pci8164.o obj-$(CONFIG_COMEDI_ADL_PCI9111) += adl_pci9111.o obj-$(CONFIG_COMEDI_ADL_PCI9118) += adl_pci9118.o @@ -96,7 +95,6 @@ obj-$(CONFIG_COMEDI_KE_COUNTER) += ke_counter.o obj-$(CONFIG_COMEDI_CB_PCIDAS64) += cb_pcidas64.o obj-$(CONFIG_COMEDI_CB_PCIDAS) += cb_pcidas.o obj-$(CONFIG_COMEDI_CB_PCIDDA) += cb_pcidda.o -obj-$(CONFIG_COMEDI_CB_PCIDIO) += cb_pcidio.o obj-$(CONFIG_COMEDI_CB_PCIMDAS) += cb_pcimdas.o obj-$(CONFIG_COMEDI_CB_PCIMDDA) += cb_pcimdda.o obj-$(CONFIG_COMEDI_ME4000) += me4000.o diff --git a/drivers/staging/comedi/drivers/acl7225b.c b/drivers/staging/comedi/drivers/acl7225b.c index ddba5db1e2e1..28c7fd3a96b6 100644 --- a/drivers/staging/comedi/drivers/acl7225b.c +++ b/drivers/staging/comedi/drivers/acl7225b.c @@ -81,7 +81,7 @@ static int acl7225b_attach(struct comedi_device *dev, if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* Relays outputs */ s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE; @@ -91,7 +91,7 @@ static int acl7225b_attach(struct comedi_device *dev, s->range_table = &range_digital; s->private = (void *)ACL7225_RIO_LO; - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* Relays status */ s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; @@ -101,7 +101,7 @@ static int acl7225b_attach(struct comedi_device *dev, s->range_table = &range_digital; s->private = (void *)ACL7225_RIO_LO; - s = dev->subdevices + 2; + s = &dev->subdevices[2]; /* Isolated digital inputs */ s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; diff --git a/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c b/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c deleted file mode 100644 index b973095146f9..000000000000 --- a/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.c +++ /dev/null @@ -1,195 +0,0 @@ -/** -@verbatim - -Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - - ADDI-DATA GmbH - Dieselstrasse 3 - D-77833 Ottersweier - Tel: +19(0)7223/9493-0 - Fax: +49(0)7223/9493-92 - http://www.addi-data.com - info@addi-data.com - -This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - -This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - -You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -You should also find the complete GPL in the COPYING file accompanying this source code. - -@endverbatim -*/ -/* - +-----------------------------------------------------------------------+ - | (C) ADDI-DATA GmbH Dieselstraße 3 D-77833 Ottersweier | - +-----------------------------------------------------------------------+ - | Tel : +49 (0) 7223/9493-0 | email : info@addi-data.com | - | Fax : +49 (0) 7223/9493-92 | Internet : http://www.addi-data.com | - +-------------------------------+---------------------------------------+ - | Project : ADDI HEADER READ WRITER | Compiler : Visual C++ | - | Module name : S5920.cpp | Version : 6.0 | - +-------------------------------+---------------------------------------+ - | Author : E. LIBS Date : 02/05/2002 | - +-----------------------------------------------------------------------+ - | Description : DLL with the S5920 PCI Controller functions | - +-----------------------------------------------------------------------+ - | UPDATE'S | - +-----------------------------------------------------------------------+ - | Date | Author | Description of updates | - +----------+-----------+------------------------------------------------+ - | 28/08/02 | LIBS Eric | Add return codes each time a function of the | - | | | Addi Library is called | - +-----------------------------------------------------------------------+ - | 31/07/03 | KRAUTH J. | Changes for the MSX-Box | - +-----------------------------------------------------------------------+ -*/ - -#include "addi_amcc_S5920.h" - -/*+----------------------------------------------------------------------------+*/ -/*| Function Name : int i_AddiHeaderRW_ReadEeprom |*/ -/*| (int i_NbOfWordsToRead, |*/ -/*| unsigned int dw_PCIBoardEepromAddress, |*/ -/*| unsigned short w_EepromStartAddress, |*/ -/*| unsigned short * pw_DataRead) |*/ -/*+----------------------------------------------------------------------------+*/ -/*| Task : Read word from the 5920 eeprom. |*/ -/*+----------------------------------------------------------------------------+*/ -/*| Input Parameters : int i_NbOfWordsToRead : Nbr. of word to read |*/ -/*| unsigned int dw_PCIBoardEepromAddress : Address of the eeprom |*/ -/*| unsigned short w_EepromStartAddress : Eeprom start address |*/ -/*+----------------------------------------------------------------------------+*/ -/*| Output Parameters : unsigned short * pw_DataRead : Read data |*/ -/*+----------------------------------------------------------------------------+*/ -/*| Return Value : - |*/ -/*+----------------------------------------------------------------------------+*/ - -int i_AddiHeaderRW_ReadEeprom(int i_NbOfWordsToRead, - unsigned int dw_PCIBoardEepromAddress, - unsigned short w_EepromStartAddress, unsigned short *pw_DataRead) -{ - unsigned int dw_eeprom_busy = 0; - int i_Counter = 0; - int i_WordCounter; - int i; - unsigned char pb_ReadByte[1]; - unsigned char b_ReadLowByte = 0; - unsigned char b_ReadHighByte = 0; - unsigned char b_SelectedAddressLow = 0; - unsigned char b_SelectedAddressHigh = 0; - unsigned short w_ReadWord = 0; - - for (i_WordCounter = 0; i_WordCounter < i_NbOfWordsToRead; - i_WordCounter++) { - do { - dw_eeprom_busy = - inl(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR); - dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } while (dw_eeprom_busy == EEPROM_BUSY); - - for (i_Counter = 0; i_Counter < 2; i_Counter++) { - b_SelectedAddressLow = (w_EepromStartAddress + i_Counter) % 256; /* Read the low 8 bit part */ - b_SelectedAddressHigh = (w_EepromStartAddress + i_Counter) / 256; /* Read the high 8 bit part */ - - /* Select the load low address mode */ - outb(NVCMD_LOAD_LOW, - dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + - 3); - - /* Wait on busy */ - do { - dw_eeprom_busy = - inl(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR); - dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } while (dw_eeprom_busy == EEPROM_BUSY); - - /* Load the low address */ - outb(b_SelectedAddressLow, - dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + - 2); - - /* Wait on busy */ - do { - dw_eeprom_busy = - inl(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR); - dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } while (dw_eeprom_busy == EEPROM_BUSY); - - /* Select the load high address mode */ - outb(NVCMD_LOAD_HIGH, - dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + - 3); - - /* Wait on busy */ - do { - dw_eeprom_busy = - inl(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR); - dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } while (dw_eeprom_busy == EEPROM_BUSY); - - /* Load the high address */ - outb(b_SelectedAddressHigh, - dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + - 2); - - /* Wait on busy */ - do { - dw_eeprom_busy = - inl(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR); - dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } while (dw_eeprom_busy == EEPROM_BUSY); - - /* Select the READ mode */ - outb(NVCMD_BEGIN_READ, - dw_PCIBoardEepromAddress + AMCC_OP_REG_MCSR + - 3); - - /* Wait on busy */ - do { - dw_eeprom_busy = - inl(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR); - dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } while (dw_eeprom_busy == EEPROM_BUSY); - - /* Read data into the EEPROM */ - *pb_ReadByte = - inb(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR + 2); - - /* Wait on busy */ - do { - dw_eeprom_busy = - inl(dw_PCIBoardEepromAddress + - AMCC_OP_REG_MCSR); - dw_eeprom_busy = dw_eeprom_busy & EEPROM_BUSY; - } while (dw_eeprom_busy == EEPROM_BUSY); - - /* Select the upper address part */ - if (i_Counter == 0) - b_ReadLowByte = pb_ReadByte[0]; - else - b_ReadHighByte = pb_ReadByte[0]; - - /* Sleep */ - msleep(1); - - } - w_ReadWord = - (b_ReadLowByte | (((unsigned short)b_ReadHighByte) * - 256)); - - pw_DataRead[i_WordCounter] = w_ReadWord; - - w_EepromStartAddress += 2; /* to read the next word */ - - } /* for (...) i_NbOfWordsToRead */ - return 0; -} diff --git a/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.h b/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.h deleted file mode 100644 index 9afdb1357aa9..000000000000 --- a/drivers/staging/comedi/drivers/addi-data/addi_amcc_S5920.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module. - * - * ADDI-DATA GmbH - * Dieselstrasse 3 - * D-77833 Ottersweier - * Tel: +19(0)7223/9493-0 - * Fax: +49(0)7223/9493-92 - * http://www.addi-data.com - * info@addi-data.com - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the Free - * Software Foundation; either version 2 of the License, or (at your option) - * any later version. - */ - -#define AMCC_OP_REG_MCSR 0x3c -#define EEPROM_BUSY 0x80000000 -#define NVCMD_LOAD_LOW (0x4 << 5) /* nvRam load low command */ -#define NVCMD_LOAD_HIGH (0x5 << 5) /* nvRam load high command */ -#define NVCMD_BEGIN_READ (0x7 << 5) /* nvRam begin read command */ -#define NVCMD_BEGIN_WRITE (0x6 << 5) /* EEPROM begin write command */ - -int i_AddiHeaderRW_ReadEeprom(int i_NbOfWordsToRead, - unsigned int dw_PCIBoardEepromAddress, - unsigned short w_EepromStartAddress, unsigned short *pw_DataRead); diff --git a/drivers/staging/comedi/drivers/addi-data/addi_common.c b/drivers/staging/comedi/drivers/addi-data/addi_common.c index a3d4ed25fb0d..99a96bd96716 100644 --- a/drivers/staging/comedi/drivers/addi-data/addi_common.c +++ b/drivers/staging/comedi/drivers/addi-data/addi_common.c @@ -1669,7 +1669,7 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it) return ret; /* Allocate and Initialise AI Subdevice Structures */ - s = dev->subdevices + 0; + s = &dev->subdevices[0]; if ((devpriv->s_EeParameters.i_NbrAiChannel) || (this_board->i_NbrAiChannelDiff)) { dev->read_subdev = s; @@ -1705,7 +1705,7 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it) } /* Allocate and Initialise AO Subdevice Structures */ - s = dev->subdevices + 1; + s = &dev->subdevices[1]; if (devpriv->s_EeParameters.i_NbrAoChannel) { s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; @@ -1720,7 +1720,7 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it) s->type = COMEDI_SUBD_UNUSED; } /* Allocate and Initialise DI Subdevice Structures */ - s = dev->subdevices + 2; + s = &dev->subdevices[2]; if (devpriv->s_EeParameters.i_NbrDiChannel) { s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; @@ -1738,7 +1738,7 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it) s->type = COMEDI_SUBD_UNUSED; } /* Allocate and Initialise DO Subdevice Structures */ - s = dev->subdevices + 3; + s = &dev->subdevices[3]; if (devpriv->s_EeParameters.i_NbrDoChannel) { s->type = COMEDI_SUBD_DO; s->subdev_flags = @@ -1760,7 +1760,7 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it) } /* Allocate and Initialise Timer Subdevice Structures */ - s = dev->subdevices + 4; + s = &dev->subdevices[4]; if (devpriv->s_EeParameters.i_Timer) { s->type = COMEDI_SUBD_TIMER; s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; @@ -1778,7 +1778,7 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it) } /* Allocate and Initialise TTL */ - s = dev->subdevices + 5; + s = &dev->subdevices[5]; if (this_board->i_NbrTTLChannel) { s->type = COMEDI_SUBD_TTLIO; s->subdev_flags = @@ -1797,7 +1797,7 @@ static int i_ADDI_Attach(struct comedi_device *dev, struct comedi_devconfig *it) } /* EEPROM */ - s = dev->subdevices + 6; + s = &dev->subdevices[6]; if (this_board->i_PCIEeprom) { s->type = COMEDI_SUBD_MEMORY; s->subdev_flags = SDF_READABLE | SDF_INTERNAL; diff --git a/drivers/staging/comedi/drivers/addi-data/amcc_s5933_58.h b/drivers/staging/comedi/drivers/addi-data/amcc_s5933_58.h deleted file mode 100644 index c26c28c31b97..000000000000 --- a/drivers/staging/comedi/drivers/addi-data/amcc_s5933_58.h +++ /dev/null @@ -1,453 +0,0 @@ -/* - Modified by umesh on 16th may 2001 - Modified by sarath on 22nd may 2001 -*/ - -/* - comedi/drivers/amcc_s5933_v_58.h - - Stuff for AMCC S5933 PCI Controller - - Author: Michal Dobes <majkl@tesnet.cz> - - Inspirated from general-purpose AMCC S5933 PCI Matchmaker driver - made by Andrea Cisternino <acister@pcape1.pi.infn.it> - and as result of espionage from MITE code made by David A. Schleef. - Thanks to AMCC for their on-line documentation and bus master DMA - example. -*/ - -#ifndef _AMCC_S5933_H_ -#define _AMCC_S5933_H_ - -#include <linux/pci.h> -#include "../../comedidev.h" - -/***********Added by sarath for compatibility with APCI3120 - -*************************/ - -#define FIFO_ADVANCE_ON_BYTE_2 0x20000000 /* written on base0 */ - -#define AMWEN_ENABLE 0x02 /* added for step 6 dma written on base2 */ -#define A2P_FIFO_WRITE_ENABLE 0x01 - -#define AGCSTS_TC_ENABLE 0x10000000 /* Added for transfer count enable bit */ - -/* ADDON RELATED ADDITIONS */ -/* Constant */ -#define APCI3120_ENABLE_TRANSFER_ADD_ON_LOW 0x00 -#define APCI3120_ENABLE_TRANSFER_ADD_ON_HIGH 0x1200 -#define APCI3120_A2P_FIFO_MANAGEMENT 0x04000400L -#define APCI3120_AMWEN_ENABLE 0x02 -#define APCI3120_A2P_FIFO_WRITE_ENABLE 0x01 -#define APCI3120_FIFO_ADVANCE_ON_BYTE_2 0x20000000L -#define APCI3120_ENABLE_WRITE_TC_INT 0x00004000L -#define APCI3120_CLEAR_WRITE_TC_INT 0x00040000L -#define APCI3120_DISABLE_AMWEN_AND_A2P_FIFO_WRITE 0x0 -#define APCI3120_DISABLE_BUS_MASTER_ADD_ON 0x0 -#define APCI3120_DISABLE_BUS_MASTER_PCI 0x0 - - /* ADD_ON ::: this needed since apci supports 16 bit interface to add on */ -#define APCI3120_ADD_ON_AGCSTS_LOW 0x3C -#define APCI3120_ADD_ON_AGCSTS_HIGH APCI3120_ADD_ON_AGCSTS_LOW + 2 -#define APCI3120_ADD_ON_MWAR_LOW 0x24 -#define APCI3120_ADD_ON_MWAR_HIGH APCI3120_ADD_ON_MWAR_LOW + 2 -#define APCI3120_ADD_ON_MWTC_LOW 0x058 -#define APCI3120_ADD_ON_MWTC_HIGH APCI3120_ADD_ON_MWTC_LOW + 2 - -/* AMCC */ -#define APCI3120_AMCC_OP_MCSR 0x3C -#define APCI3120_AMCC_OP_REG_INTCSR 0x38 - -/*******from here all upward definitions are added by sarath */ - -/****************************************************************************/ -/* AMCC Operation Register Offsets - PCI */ -/****************************************************************************/ - -#define AMCC_OP_REG_OMB1 0x00 -#define AMCC_OP_REG_OMB2 0x04 -#define AMCC_OP_REG_OMB3 0x08 -#define AMCC_OP_REG_OMB4 0x0c -#define AMCC_OP_REG_IMB1 0x10 -#define AMCC_OP_REG_IMB2 0x14 -#define AMCC_OP_REG_IMB3 0x18 -#define AMCC_OP_REG_IMB4 0x1c -#define AMCC_OP_REG_FIFO 0x20 -#define AMCC_OP_REG_MWAR 0x24 -#define AMCC_OP_REG_MWTC 0x28 -#define AMCC_OP_REG_MRAR 0x2c -#define AMCC_OP_REG_MRTC 0x30 -#define AMCC_OP_REG_MBEF 0x34 -#define AMCC_OP_REG_INTCSR 0x38 -#define AMCC_OP_REG_INTCSR_SRC (AMCC_OP_REG_INTCSR + 2) /* int source */ -#define AMCC_OP_REG_INTCSR_FEC (AMCC_OP_REG_INTCSR + 3) /* FIFO ctrl */ -#define AMCC_OP_REG_MCSR 0x3c -#define AMCC_OP_REG_MCSR_NVDATA (AMCC_OP_REG_MCSR + 2) /* Data in byte 2 */ -#define AMCC_OP_REG_MCSR_NVCMD (AMCC_OP_REG_MCSR + 3) /* Command in byte 3 */ - -#define AMCC_FIFO_DEPTH_DWORD 8 -#define AMCC_FIFO_DEPTH_BYTES (8 * sizeof (u32)) - -/****************************************************************************/ -/* AMCC Operation Registers Size - PCI */ -/****************************************************************************/ - -#define AMCC_OP_REG_SIZE 64 /* in bytes */ - -/****************************************************************************/ -/* AMCC Operation Register Offsets - Add-on */ -/****************************************************************************/ - -#define AMCC_OP_REG_AIMB1 0x00 -#define AMCC_OP_REG_AIMB2 0x04 -#define AMCC_OP_REG_AIMB3 0x08 -#define AMCC_OP_REG_AIMB4 0x0c -#define AMCC_OP_REG_AOMB1 0x10 -#define AMCC_OP_REG_AOMB2 0x14 -#define AMCC_OP_REG_AOMB3 0x18 -#define AMCC_OP_REG_AOMB4 0x1c -#define AMCC_OP_REG_AFIFO 0x20 -#define AMCC_OP_REG_AMWAR 0x24 -#define AMCC_OP_REG_APTA 0x28 -#define AMCC_OP_REG_APTD 0x2c -#define AMCC_OP_REG_AMRAR 0x30 -#define AMCC_OP_REG_AMBEF 0x34 -#define AMCC_OP_REG_AINT 0x38 -#define AMCC_OP_REG_AGCSTS 0x3c -#define AMCC_OP_REG_AMWTC 0x58 -#define AMCC_OP_REG_AMRTC 0x5c - -/****************************************************************************/ -/* AMCC - Add-on General Control/Status Register */ -/****************************************************************************/ - -#define AGCSTS_CONTROL_MASK 0xfffff000 -#define AGCSTS_NV_ACC_MASK 0xe0000000 -#define AGCSTS_RESET_MASK 0x0e000000 -#define AGCSTS_NV_DA_MASK 0x00ff0000 -#define AGCSTS_BIST_MASK 0x0000f000 -#define AGCSTS_STATUS_MASK 0x000000ff -#define AGCSTS_TCZERO_MASK 0x000000c0 -#define AGCSTS_FIFO_ST_MASK 0x0000003f - -#define AGCSTS_RESET_MBFLAGS 0x08000000 -#define AGCSTS_RESET_P2A_FIFO 0x04000000 -#define AGCSTS_RESET_A2P_FIFO 0x02000000 -#define AGCSTS_RESET_FIFOS (AGCSTS_RESET_A2P_FIFO | AGCSTS_RESET_P2A_FIFO) - -#define AGCSTS_A2P_TCOUNT 0x00000080 -#define AGCSTS_P2A_TCOUNT 0x00000040 - -#define AGCSTS_FS_P2A_EMPTY 0x00000020 -#define AGCSTS_FS_P2A_HALF 0x00000010 -#define AGCSTS_FS_P2A_FULL 0x00000008 - -#define AGCSTS_FS_A2P_EMPTY 0x00000004 -#define AGCSTS_FS_A2P_HALF 0x00000002 -#define AGCSTS_FS_A2P_FULL 0x00000001 - -/****************************************************************************/ -/* AMCC - Add-on Interrupt Control/Status Register */ -/****************************************************************************/ - -#define AINT_INT_MASK 0x00ff0000 -#define AINT_SEL_MASK 0x0000ffff -#define AINT_IS_ENSEL_MASK 0x00001f1f - -#define AINT_INT_ASSERTED 0x00800000 -#define AINT_BM_ERROR 0x00200000 -#define AINT_BIST_INT 0x00100000 - -#define AINT_RT_COMPLETE 0x00080000 -#define AINT_WT_COMPLETE 0x00040000 - -#define AINT_OUT_MB_INT 0x00020000 -#define AINT_IN_MB_INT 0x00010000 - -#define AINT_READ_COMPL 0x00008000 -#define AINT_WRITE_COMPL 0x00004000 - -#define AINT_OMB_ENABLE 0x00001000 -#define AINT_OMB_SELECT 0x00000c00 -#define AINT_OMB_BYTE 0x00000300 - -#define AINT_IMB_ENABLE 0x00000010 -#define AINT_IMB_SELECT 0x0000000c -#define AINT_IMB_BYTE 0x00000003 - -/* Enable Bus Mastering */ -#define EN_A2P_TRANSFERS 0x00000400 -/* FIFO Flag Reset */ -#define RESET_A2P_FLAGS 0x04000000L -/* FIFO Relative Priority */ -#define A2P_HI_PRIORITY 0x00000100L -/* Identify Interrupt Sources */ -#define ANY_S593X_INT 0x00800000L -#define READ_TC_INT 0x00080000L -#define WRITE_TC_INT 0x00040000L -#define IN_MB_INT 0x00020000L -#define MASTER_ABORT_INT 0x00100000L -#define TARGET_ABORT_INT 0x00200000L -#define BUS_MASTER_INT 0x00200000L - -/****************************************************************************/ - -struct pcilst_struct { - struct pcilst_struct *next; - int used; - struct pci_dev *pcidev; - unsigned short vendor; - unsigned short device; - unsigned int master; - unsigned char pci_bus; - unsigned char pci_slot; - unsigned char pci_func; - unsigned int io_addr[5]; - unsigned int irq; -}; - -struct pcilst_struct *amcc_devices; /* ptr to root list of all amcc devices */ - -/****************************************************************************/ - -void v_pci_card_list_init(unsigned short pci_vendor, char display); -void v_pci_card_list_cleanup(unsigned short pci_vendor); -struct pcilst_struct *ptr_find_free_pci_card_by_device(unsigned short vendor_id, - unsigned short - device_id); -int i_find_free_pci_card_by_position(unsigned short vendor_id, - unsigned short device_id, - unsigned short pci_bus, - unsigned short pci_slot, - struct pcilst_struct **card); -struct pcilst_struct *ptr_select_and_alloc_pci_card(unsigned short vendor_id, - unsigned short device_id, - unsigned short pci_bus, - unsigned short pci_slot); - -int i_pci_card_alloc(struct pcilst_struct *amcc); -int i_pci_card_free(struct pcilst_struct *amcc); -void v_pci_card_list_display(void); -int i_pci_card_data(struct pcilst_struct *amcc, - unsigned char *pci_bus, unsigned char *pci_slot, - unsigned char *pci_func, unsigned short *io_addr, - unsigned short *irq, unsigned short *master); - -/****************************************************************************/ - -/* build list of amcc cards in this system */ -void v_pci_card_list_init(unsigned short pci_vendor, char display) -{ - struct pci_dev *pcidev; - struct pcilst_struct *amcc, *last; - int i; - - amcc_devices = NULL; - last = NULL; - - pci_for_each_dev(pcidev) { - if (pcidev->vendor == pci_vendor) { - amcc = kzalloc(sizeof(*amcc), GFP_KERNEL); - if (amcc == NULL) - continue; - - amcc->pcidev = pcidev; - if (last) { - last->next = amcc; - } else { - amcc_devices = amcc; - } - last = amcc; - - amcc->vendor = pcidev->vendor; - amcc->device = pcidev->device; -#if 0 - amcc->master = pcidev->master; /* how get this information under 2.4 kernels? */ -#endif - amcc->pci_bus = pcidev->bus->number; - amcc->pci_slot = PCI_SLOT(pcidev->devfn); - amcc->pci_func = PCI_FUNC(pcidev->devfn); - for (i = 0; i < 5; i++) - amcc->io_addr[i] = - pcidev->resource[i].start & ~3UL; - amcc->irq = pcidev->irq; - } - } - - if (display) - v_pci_card_list_display(); -} - -/****************************************************************************/ -/* free up list of amcc cards in this system */ -void v_pci_card_list_cleanup(unsigned short pci_vendor) -{ - struct pcilst_struct *amcc, *next; - - for (amcc = amcc_devices; amcc; amcc = next) { - next = amcc->next; - kfree(amcc); - } - - amcc_devices = NULL; -} - -/****************************************************************************/ -/* find first unused card with this device_id */ -struct pcilst_struct *ptr_find_free_pci_card_by_device(unsigned short vendor_id, - unsigned short device_id) -{ - struct pcilst_struct *amcc, *next; - - for (amcc = amcc_devices; amcc; amcc = next) { - next = amcc->next; - if ((!amcc->used) && (amcc->device == device_id) - && (amcc->vendor == vendor_id)) - return amcc; - - } - - return NULL; -} - -/****************************************************************************/ -/* find card on requested position */ -int i_find_free_pci_card_by_position(unsigned short vendor_id, - unsigned short device_id, - unsigned short pci_bus, - unsigned short pci_slot, - struct pcilst_struct **card) -{ - struct pcilst_struct *amcc, *next; - - *card = NULL; - for (amcc = amcc_devices; amcc; amcc = next) { - next = amcc->next; - if ((amcc->vendor == vendor_id) && (amcc->device == device_id) - && (amcc->pci_bus == pci_bus) - && (amcc->pci_slot == pci_slot)) { - if (!(amcc->used)) { - *card = amcc; - return 0; /* ok, card is found */ - } else { - printk - (" - \nCard on requested position is used b:s %d:%d!\n", - pci_bus, pci_slot); - return 2; /* card exist but is used */ - } - } - } - - return 1; /* no card found */ -} - -/****************************************************************************/ -/* mark card as used */ -int i_pci_card_alloc(struct pcilst_struct *amcc) -{ - if (!amcc) - return -1; - - if (amcc->used) - return 1; - amcc->used = 1; - return 0; -} - -/****************************************************************************/ -/* mark card as free */ -int i_pci_card_free(struct pcilst_struct *amcc) -{ - if (!amcc) - return -1; - - if (!amcc->used) - return 1; - amcc->used = 0; - return 0; -} - -/****************************************************************************/ -/* display list of found cards */ -void v_pci_card_list_display(void) -{ - struct pcilst_struct *amcc, *next; - - printk("List of pci cards\n"); - printk("bus:slot:func vendor device master io_amcc io_daq irq used\n"); - - for (amcc = amcc_devices; amcc; amcc = next) { - next = amcc->next; - printk - ("%2d %2d %2d 0x%4x 0x%4x %3s 0x%4x 0x%4x %2d %2d\n", - amcc->pci_bus, amcc->pci_slot, amcc->pci_func, - amcc->vendor, amcc->device, amcc->master ? "yes" : "no", - amcc->io_addr[0], amcc->io_addr[2], amcc->irq, amcc->used); - - } -} - -/****************************************************************************/ -/* return all card information for driver */ -int i_pci_card_data(struct pcilst_struct *amcc, - unsigned char *pci_bus, unsigned char *pci_slot, - unsigned char *pci_func, unsigned short *io_addr, - unsigned short *irq, unsigned short *master) -{ - int i; - - if (!amcc) - return -1; - *pci_bus = amcc->pci_bus; - *pci_slot = amcc->pci_slot; - *pci_func = amcc->pci_func; - for (i = 0; i < 5; i++) - io_addr[i] = amcc->io_addr[i]; - *irq = amcc->irq; - *master = amcc->master; - return 0; -} - -/****************************************************************************/ -/* select and alloc card */ -struct pcilst_struct *ptr_select_and_alloc_pci_card(unsigned short vendor_id, - unsigned short device_id, - unsigned short pci_bus, - unsigned short pci_slot) -{ - struct pcilst_struct *card; - - if ((pci_bus < 1) & (pci_slot < 1)) { /* use autodetection */ - card = ptr_find_free_pci_card_by_device(vendor_id, device_id); - if (card == NULL) { - printk(" - Unused card not found in system!\n"); - return NULL; - } - } else { - switch (i_find_free_pci_card_by_position(vendor_id, device_id, - pci_bus, pci_slot, - &card)) { - case 1: - printk - (" - Card not found on requested position b:s %d:%d!\n", - pci_bus, pci_slot); - return NULL; - case 2: - printk - (" - Card on requested position is used b:s %d:%d!\n", - pci_bus, pci_slot); - return NULL; - } - } - - if (i_pci_card_alloc(card) != 0) { - printk(" - Can't allocate card!\n"); - return NULL; - } - - return card; -} - -#endif diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c index 595238feaf42..f9a8937be8ed 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_APCI1710.c @@ -67,7 +67,7 @@ void i_ADDI_AttachPCI1710(struct comedi_device *dev) return; /* Allocate and Initialise Timer Subdevice Structures */ - s = dev->subdevices + 0; + s = &dev->subdevices[0]; s->type = COMEDI_SUBD_TIMER; s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; @@ -81,7 +81,7 @@ void i_ADDI_AttachPCI1710(struct comedi_device *dev) s->insn_bits = i_APCI1710_InsnBitsTimer; /* Allocate and Initialise DIO Subdevice Structures */ - s = dev->subdevices + 1; + s = &dev->subdevices[1]; s->type = COMEDI_SUBD_DIO; s->subdev_flags = @@ -96,7 +96,7 @@ void i_ADDI_AttachPCI1710(struct comedi_device *dev) s->insn_write = i_APCI1710_InsnWriteDigitalIOChlOnOff; /* Allocate and Initialise Chrono Subdevice Structures */ - s = dev->subdevices + 2; + s = &dev->subdevices[2]; s->type = COMEDI_SUBD_CHRONO; s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; @@ -110,7 +110,7 @@ void i_ADDI_AttachPCI1710(struct comedi_device *dev) s->insn_bits = i_APCI1710_InsnBitsChronoDigitalIO; /* Allocate and Initialise PWM Subdevice Structures */ - s = dev->subdevices + 3; + s = &dev->subdevices[3]; s->type = COMEDI_SUBD_PWM; s->subdev_flags = SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; @@ -125,7 +125,7 @@ void i_ADDI_AttachPCI1710(struct comedi_device *dev) s->insn_bits = i_APCI1710_InsnBitsReadPWMInterrupt; /* Allocate and Initialise TTLIO Subdevice Structures */ - s = dev->subdevices + 4; + s = &dev->subdevices[4]; s->type = COMEDI_SUBD_TTLIO; s->subdev_flags = SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; @@ -139,7 +139,7 @@ void i_ADDI_AttachPCI1710(struct comedi_device *dev) s->insn_read = i_APCI1710_InsnReadTTLIOAllPortValue; /* Allocate and Initialise TOR Subdevice Structures */ - s = dev->subdevices + 5; + s = &dev->subdevices[5]; s->type = COMEDI_SUBD_TOR; s->subdev_flags = SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; @@ -154,7 +154,7 @@ void i_ADDI_AttachPCI1710(struct comedi_device *dev) s->insn_bits = i_APCI1710_InsnBitsGetTorCounterProgressStatusAndValue; /* Allocate and Initialise SSI Subdevice Structures */ - s = dev->subdevices + 6; + s = &dev->subdevices[6]; s->type = COMEDI_SUBD_SSI; s->subdev_flags = SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; @@ -167,7 +167,7 @@ void i_ADDI_AttachPCI1710(struct comedi_device *dev) s->insn_bits = i_APCI1710_InsnBitsSSIDigitalIO; /* Allocate and Initialise PULSEENCODER Subdevice Structures */ - s = dev->subdevices + 7; + s = &dev->subdevices[7]; s->type = COMEDI_SUBD_PULSEENCODER; s->subdev_flags = SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; @@ -181,7 +181,7 @@ void i_ADDI_AttachPCI1710(struct comedi_device *dev) s->insn_read = i_APCI1710_InsnReadInterruptPulseEncoder; /* Allocate and Initialise INCREMENTALCOUNTER Subdevice Structures */ - s = dev->subdevices + 8; + s = &dev->subdevices[8]; s->type = COMEDI_SUBD_INCREMENTALCOUNTER; s->subdev_flags = SDF_WRITEABLE | SDF_READABLE | SDF_GROUND | SDF_COMMON; diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c index ffe390c6da83..f406dfb2a677 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3120.c @@ -479,57 +479,26 @@ int i_APCI3120_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_s struct comedi_cmd *cmd) { int err = 0; - int tmp; /* divisor1,divisor2; */ - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ - if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) - err++; - - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_FOLLOW) - err++; - - if (cmd->convert_src != TRIG_TIMER) - err++; + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); - if (cmd->scan_end_src != TRIG_COUNT) { - cmd->scan_end_src = TRIG_COUNT; - err++; - } - - if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT) - err++; + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -1451,7 +1420,7 @@ void v_APCI3120_Interrupt(int irq, void *d) unsigned short us_TmpValue; unsigned char b_DummyRead; - struct comedi_subdevice *s = dev->subdevices + 0; + struct comedi_subdevice *s = &dev->subdevices[0]; ui_Check = 1; int_daq = inw(dev->iobase + APCI3120_RD_STATUS) & 0xf000; /* get IRQ reasons */ @@ -1656,7 +1625,7 @@ void v_APCI3120_Interrupt(int irq, void *d) int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) { int n_chan, i; - struct comedi_subdevice *s = dev->subdevices + 0; + struct comedi_subdevice *s = &dev->subdevices[0]; int err = 1; n_chan = devpriv->ui_AiNbrofChannels; @@ -1698,7 +1667,7 @@ int i_APCI3120_InterruptHandleEos(struct comedi_device *dev) void v_APCI3120_InterruptDma(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; + struct comedi_subdevice *s = &dev->subdevices[0]; unsigned int next_dma_buf, samplesinbuf; unsigned long low_word, high_word, var; diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c index f9545b064eaf..38ab49917d7e 100644 --- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c +++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3200.c @@ -57,11 +57,8 @@ You should also find the complete GPL in the COPYING file accompanying this sour +----------------------------------------------------------------------------+ */ #include "hwdrv_apci3200.h" -/* Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ -#include "addi_amcc_S5920.h" -/* #define PRINT_INFO */ -/* End JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ +/* #define PRINT_INFO */ /* BEGIN JK 06.07.04: Management of sevrals boards */ /* @@ -90,7 +87,12 @@ You should also find the complete GPL in the COPYING file accompanying this sour struct str_BoardInfos s_BoardInfos[100]; /* 100 will be the max number of boards to be used */ /* END JK 06.07.04: Management of sevrals boards */ -/* Begin JK 21.10.2004: APCI-3200 / APCI-3300 Reading of EEPROM values */ +#define AMCC_OP_REG_MCSR 0x3c +#define EEPROM_BUSY 0x80000000 +#define NVCMD_LOAD_LOW (0x4 << 5) /* nvRam load low command */ +#define NVCMD_LOAD_HIGH (0x5 << 5) /* nvRam load high command */ +#define NVCMD_BEGIN_READ (0x7 << 5) /* nvRam begin read command */ +#define NVCMD_BEGIN_WRITE (0x6 << 5) /* EEPROM begin write command */ /*+----------------------------------------------------------------------------+*/ /*| Function Name : int i_AddiHeaderRW_ReadEeprom |*/ @@ -2558,7 +2560,6 @@ int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_s { int err = 0; - int tmp; /* divisor1,divisor2; */ unsigned int ui_ConvertTime = 0; unsigned int ui_ConvertTimeBase = 0; unsigned int ui_DelayTime = 0; @@ -2569,41 +2570,32 @@ int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_s int i_Cpt = 0; double d_ConversionTimeForAllChannels = 0.0; double d_SCANTimeNewUnit = 0.0; - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; - /* if(i_InterruptFlag==0) */ - if (s_BoardInfos[dev->minor].i_InterruptFlag == 0) { - err++; - /* printk("\nThe interrupt should be enabled\n"); */ - } + + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); + + if (s_BoardInfos[dev->minor].i_InterruptFlag == 0) + err |= -EINVAL; + if (err) { i_APCI3200_Reset(dev); return 1; } - if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) { - err++; - } + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(&cmd->start_src); + err |= cfc_check_trigger_is_unique(&cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(&cmd->stop_src); + + /* Step 2b : and mutually compatible */ + if (cmd->start_src == TRIG_EXT) { i_TriggerEdge = cmd->start_arg & 0xFFFF; i_Triggermode = cmd->start_arg >> 16; @@ -2617,21 +2609,6 @@ int i_APCI3200_CommandTestAnalogInput(struct comedi_device *dev, struct comedi_s } } - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_FOLLOW) - err++; - - if (cmd->convert_src != TRIG_TIMER) - err++; - - if (cmd->scan_end_src != TRIG_COUNT) { - cmd->scan_end_src = TRIG_COUNT; - err++; - } - - if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT) - err++; - if (err) { i_APCI3200_Reset(dev); return 2; @@ -3495,7 +3472,7 @@ void v_APCI3200_Interrupt(int irq, void *d) int i_APCI3200_InterruptHandleEos(struct comedi_device *dev) { unsigned int ui_StatusRegister = 0; - struct comedi_subdevice *s = dev->subdevices + 0; + struct comedi_subdevice *s = &dev->subdevices[0]; /* BEGIN JK 18.10.2004: APCI-3200 Driver update 0.7.57 -> 0.7.68 */ /* comedi_async *async = s->async; */ diff --git a/drivers/staging/comedi/drivers/addi_apci_all.c b/drivers/staging/comedi/drivers/addi_apci_all.c deleted file mode 100644 index aeb1b2688f3d..000000000000 --- a/drivers/staging/comedi/drivers/addi_apci_all.c +++ /dev/null @@ -1,18 +0,0 @@ -#define CONFIG_APCI_035 1 -#define CONFIG_APCI_1032 1 -#define CONFIG_APCI_1500 1 -#define CONFIG_APCI_1516 1 -#define CONFIG_APCI_1564 1 -#define CONFIG_APCI_16XX 1 -#define CONFIG_APCI_1710 1 -#define CONFIG_APCI_2016 1 -#define CONFIG_APCI_2032 1 -#define CONFIG_APCI_2200 1 -#define CONFIG_APCI_3001 1 -#define CONFIG_APCI_3120 1 -#define CONFIG_APCI_3200 1 -#define CONFIG_APCI_3300 1 -#define CONFIG_APCI_3501 1 -#define CONFIG_APCI_3XXX 1 - -#include "addi-data/addi_common.c" diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c index 3bec0f6e4a8c..3492ce1156e0 100644 --- a/drivers/staging/comedi/drivers/adl_pci6208.c +++ b/drivers/staging/comedi/drivers/adl_pci6208.c @@ -27,14 +27,14 @@ */ /* Driver: adl_pci6208 -Description: ADLink PCI-6208A -Devices: [ADLink] PCI-6208A (adl_pci6208) +Description: ADLink PCI-6208/6216 Series Multi-channel Analog Output Cards +Devices: (ADLink) PCI-6208 [adl_pci6208] + (ADLink) PCI-6216 [adl_pci6216] Author: nsyeow <nsyeow@pd.jaring.my> Updated: Fri, 30 Jan 2004 14:44:27 +0800 Status: untested -Configuration Options: - none +Configuration Options: not applicable, uses PCI auto config References: - ni_660x.c @@ -45,6 +45,12 @@ References: #include "../comedidev.h" /* + * ADLINK PCI Device ID's supported by this driver + */ +#define PCI_DEVICE_ID_PCI6208 0x6208 +#define PCI_DEVICE_ID_PCI6216 0x6216 + +/* * PCI-6208/6216-GL register map */ #define PCI6208_AO_CONTROL(x) (0x00 + (2 * (x))) @@ -56,7 +62,7 @@ References: #define PCI6208_DIO_DI_MASK (0xf0) #define PCI6208_DIO_DI_SHIFT (4) -#define PCI6208_MAX_AO_CHANNELS 8 +#define PCI6208_MAX_AO_CHANNELS 16 struct pci6208_board { const char *name; @@ -66,9 +72,13 @@ struct pci6208_board { static const struct pci6208_board pci6208_boards[] = { { - .name = "pci6208a", - .dev_id = 0x6208, + .name = "adl_pci6208", + .dev_id = PCI_DEVICE_ID_PCI6208, .ao_chans = 8, + }, { + .name = "adl_pci6216", + .dev_id = PCI_DEVICE_ID_PCI6216, + .ao_chans = 16, }, }; @@ -115,141 +125,122 @@ static int pci6208_ao_rinsn(struct comedi_device *dev, return insn->n; } -static int pci6208_dio_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) +static int pci6208_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned int val; + + val = inw(dev->iobase + PCI6208_DIO); + val = (val & PCI6208_DIO_DI_MASK) >> PCI6208_DIO_DI_SHIFT; + + data[1] = val; + + return insn->n; +} + +static int pci6208_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned int mask = data[0] & PCI6208_DIO_DO_MASK; + unsigned int mask = data[0]; unsigned int bits = data[1]; if (mask) { s->state &= ~mask; - s->state |= bits & mask; + s->state |= (bits & mask); outw(s->state, dev->iobase + PCI6208_DIO); } - s->state = inw(dev->iobase + PCI6208_DIO); data[1] = s->state; return insn->n; } -static int pci6208_dio_insn_config(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - int chan = CR_CHAN(insn->chanspec); - unsigned int mask = 1 << chan; - - switch (data[0]) { - case INSN_CONFIG_DIO_QUERY: - data[1] = (s->io_bits & mask) ? COMEDI_OUTPUT : COMEDI_INPUT; - break; - default: - return -EINVAL; - } - - return insn->n; -} - -static struct pci_dev *pci6208_find_device(struct comedi_device *dev, - struct comedi_devconfig *it) +static const void *pci6208_find_boardinfo(struct comedi_device *dev, + struct pci_dev *pcidev) { - const struct pci6208_board *thisboard; - struct pci_dev *pci_dev = NULL; - int bus = it->options[0]; - int slot = it->options[1]; + const struct pci6208_board *boardinfo; int i; - for_each_pci_dev(pci_dev) { - if (pci_dev->vendor != PCI_VENDOR_ID_ADLINK) - continue; - for (i = 0; i < ARRAY_SIZE(pci6208_boards); i++) { - thisboard = &pci6208_boards[i]; - if (thisboard->dev_id != pci_dev->device) - continue; - /* was a particular bus/slot requested? */ - if (bus || slot) { - /* are we on the wrong bus/slot? */ - if (pci_dev->bus->number != bus || - PCI_SLOT(pci_dev->devfn) != slot) - continue; - } - dev_dbg(dev->class_dev, - "Found %s on bus %d, slot, %d, irq=%d\n", - thisboard->name, - pci_dev->bus->number, - PCI_SLOT(pci_dev->devfn), - pci_dev->irq); - dev->board_ptr = thisboard; - return pci_dev; - } + for (i = 0; i < ARRAY_SIZE(pci6208_boards); i++) { + boardinfo = &pci6208_boards[i]; + if (boardinfo->dev_id == pcidev->device) + return boardinfo; } - dev_err(dev->class_dev, - "No supported board found! (req. bus %d, slot %d)\n", - bus, slot); return NULL; } -static int pci6208_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int pci6208_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) { - const struct pci6208_board *thisboard; + const struct pci6208_board *boardinfo; struct pci6208_private *devpriv; - struct pci_dev *pcidev; struct comedi_subdevice *s; + unsigned int val; int ret; + comedi_set_hw_dev(dev, &pcidev->dev); + + boardinfo = pci6208_find_boardinfo(dev, pcidev); + if (!boardinfo) + return -ENODEV; + dev->board_ptr = boardinfo; + dev->board_name = boardinfo->name; + ret = alloc_private(dev, sizeof(*devpriv)); if (ret < 0) return ret; devpriv = dev->private; - pcidev = pci6208_find_device(dev, it); - if (!pcidev) - return -EIO; - comedi_set_hw_dev(dev, &pcidev->dev); - thisboard = comedi_board(dev); - - dev->board_name = thisboard->name; - - ret = comedi_pci_enable(pcidev, dev->driver->driver_name); - if (ret) { - dev_err(dev->class_dev, - "Failed to enable PCI device and request regions\n"); + ret = comedi_pci_enable(pcidev, dev->board_name); + if (ret) return ret; - } dev->iobase = pci_resource_start(pcidev, 2); - ret = comedi_alloc_subdevices(dev, 2); + ret = comedi_alloc_subdevices(dev, 3); if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* analog output subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; - s->n_chan = thisboard->ao_chans; + s->n_chan = boardinfo->ao_chans; s->maxdata = 0xffff; s->range_table = &range_bipolar10; s->insn_write = pci6208_ao_winsn; s->insn_read = pci6208_ao_rinsn; - s = dev->subdevices + 1; - /* digital i/o subdevice */ - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 8; + s = &dev->subdevices[1]; + /* digital input subdevice */ + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 4; s->maxdata = 1; s->range_table = &range_digital; - s->insn_bits = pci6208_dio_insn_bits; - s->insn_config = pci6208_dio_insn_config; + s->insn_bits = pci6208_di_insn_bits; + s = &dev->subdevices[2]; + /* digital output subdevice */ + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 4; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pci6208_do_insn_bits; + + /* + * Get the read back signals from the digital outputs + * and save it as the initial state for the subdevice. + */ + val = inw(dev->iobase + PCI6208_DIO); + val = (val & PCI6208_DIO_DO_MASK) >> PCI6208_DIO_DO_SHIFT; + s->state = val; s->io_bits = 0x0f; - s->state = inw(dev->iobase + PCI6208_DIO); dev_info(dev->class_dev, "%s: %s, I/O base=0x%04lx\n", dev->driver->driver_name, dev->board_name, dev->iobase); @@ -264,14 +255,13 @@ static void pci6208_detach(struct comedi_device *dev) if (pcidev) { if (dev->iobase) comedi_pci_disable(pcidev); - pci_dev_put(pcidev); } } static struct comedi_driver adl_pci6208_driver = { .driver_name = "adl_pci6208", .module = THIS_MODULE, - .attach = pci6208_attach, + .attach_pci = pci6208_attach_pci, .detach = pci6208_detach, }; @@ -287,7 +277,8 @@ static void __devexit adl_pci6208_pci_remove(struct pci_dev *dev) } static DEFINE_PCI_DEVICE_TABLE(adl_pci6208_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, 0x6208) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI6208) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI6216) }, { 0 } }; MODULE_DEVICE_TABLE(pci, adl_pci6208_pci_table); diff --git a/drivers/staging/comedi/drivers/adl_pci7230.c b/drivers/staging/comedi/drivers/adl_pci7230.c deleted file mode 100644 index 7df4c960d5e4..000000000000 --- a/drivers/staging/comedi/drivers/adl_pci7230.c +++ /dev/null @@ -1,190 +0,0 @@ -/* - comedi/drivers/adl_pci7230.c - - Hardware comedi driver fot PCI7230 Adlink card - Copyright (C) 2010 David Fernandez <dfcastelao@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. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ -/* -Driver: adl_pci7230 -Description: Driver for the Adlink PCI-7230 32 ch. isolated digital io board -Devices: [ADLink] PCI-7230 (adl_pci7230) -Author: David Fernandez <dfcastelao@gmail.com> -Status: experimental -Updated: Mon, 14 Apr 2008 15:08:14 +0100 - -Configuration Options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - If bus/slot is not specified, the first supported - PCI device found will be used. -*/ - -#include "../comedidev.h" -#include <linux/kernel.h> - -#define PCI7230_DI 0x00 -#define PCI7230_DO 0x00 - -#define PCI_DEVICE_ID_PCI7230 0x7230 - -static int adl_pci7230_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - - outl((s->state << 16) & 0xffffffff, dev->iobase + PCI7230_DO); - } - - return insn->n; -} - -static int adl_pci7230_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - data[1] = inl(dev->iobase + PCI7230_DI) & 0xffffffff; - - return insn->n; -} - -static struct pci_dev *adl_pci7230_find_pci(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct pci_dev *pcidev = NULL; - int bus = it->options[0]; - int slot = it->options[1]; - - for_each_pci_dev(pcidev) { - if (pcidev->vendor != PCI_VENDOR_ID_ADLINK || - pcidev->device != PCI_DEVICE_ID_PCI7230) - continue; - if (bus || slot) { - /* requested particular bus/slot */ - if (pcidev->bus->number != bus || - PCI_SLOT(pcidev->devfn) != slot) - continue; - } - return pcidev; - } - printk(KERN_ERR "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n", - dev->minor, bus, slot); - return NULL; -} - -static int adl_pci7230_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct comedi_subdevice *s; - struct pci_dev *pcidev; - int ret; - - printk(KERN_INFO "comedi%d: adl_pci7230\n", dev->minor); - - dev->board_name = "pci7230"; - - ret = comedi_alloc_subdevices(dev, 2); - if (ret) - return ret; - - pcidev = adl_pci7230_find_pci(dev, it); - if (!pcidev) - return -EIO; - comedi_set_hw_dev(dev, &pcidev->dev); - - if (comedi_pci_enable(pcidev, "adl_pci7230") < 0) { - printk(KERN_ERR "comedi%d: Failed to enable PCI device and request regions\n", - dev->minor); - return -EIO; - } - dev->iobase = pci_resource_start(pcidev, 2); - printk(KERN_DEBUG "comedi: base addr %4lx\n", dev->iobase); - - s = dev->subdevices + 0; - /* Isolated do */ - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 16; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = adl_pci7230_do_insn_bits; - - s = dev->subdevices + 1; - /* Isolated di */ - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 16; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = adl_pci7230_di_insn_bits; - - printk(KERN_DEBUG "comedi: attached\n"); - - return 1; -} - -static void adl_pci7230_detach(struct comedi_device *dev) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - - if (pcidev) { - if (dev->iobase) - comedi_pci_disable(pcidev); - pci_dev_put(pcidev); - } -} - -static struct comedi_driver adl_pci7230_driver = { - .driver_name = "adl_pci7230", - .module = THIS_MODULE, - .attach = adl_pci7230_attach, - .detach = adl_pci7230_detach, -}; - -static int __devinit adl_pci7230_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, &adl_pci7230_driver); -} - -static void __devexit adl_pci7230_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static DEFINE_PCI_DEVICE_TABLE(adl_pci7230_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7230) }, - { 0 } -}; -MODULE_DEVICE_TABLE(pci, adl_pci7230_pci_table); - -static struct pci_driver adl_pci7230_pci_driver = { - .name = "adl_pci7230", - .id_table = adl_pci7230_pci_table, - .probe = adl_pci7230_pci_probe, - .remove = __devexit_p(adl_pci7230_pci_remove), -}; -module_comedi_pci_driver(adl_pci7230_driver, adl_pci7230_pci_driver); - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/adl_pci7296.c b/drivers/staging/comedi/drivers/adl_pci7296.c deleted file mode 100644 index 19b47af9c10e..000000000000 --- a/drivers/staging/comedi/drivers/adl_pci7296.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - comedi/drivers/adl_pci7296.c - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ -/* -Driver: adl_pci7296 -Description: Driver for the Adlink PCI-7296 96 ch. digital io board -Devices: [ADLink] PCI-7296 (adl_pci7296) -Author: Jon Grierson <jd@renko.co.uk> -Updated: Mon, 14 Apr 2008 15:05:56 +0100 -Status: testing - -Configuration Options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - If bus/slot is not specified, the first supported - PCI device found will be used. -*/ - -#include "../comedidev.h" -#include <linux/kernel.h> - -#include "8255.h" -/* #include "8253.h" */ - -#define PORT1A 0 -#define PORT2A 4 -#define PORT3A 8 -#define PORT4A 12 - -#define PCI_DEVICE_ID_PCI7296 0x7296 - -static struct pci_dev *adl_pci7296_find_pci(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct pci_dev *pcidev = NULL; - int bus = it->options[0]; - int slot = it->options[1]; - - for_each_pci_dev(pcidev) { - if (pcidev->vendor != PCI_VENDOR_ID_ADLINK || - pcidev->device != PCI_DEVICE_ID_PCI7296) - continue; - if (bus || slot) { - /* requested particular bus/slot */ - if (pcidev->bus->number != bus || - PCI_SLOT(pcidev->devfn) != slot) - continue; - } - return pcidev; - } - printk(KERN_ERR - "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n", - dev->minor, bus, slot); - return NULL; -} - -static int adl_pci7296_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct pci_dev *pcidev; - struct comedi_subdevice *s; - int ret; - - printk(KERN_INFO "comedi%d: attach adl_pci7432\n", dev->minor); - - dev->board_name = "pci7432"; - - ret = comedi_alloc_subdevices(dev, 4); - if (ret) - return ret; - - pcidev = adl_pci7296_find_pci(dev, it); - if (!pcidev) - return -EIO; - comedi_set_hw_dev(dev, &pcidev->dev); - - if (comedi_pci_enable(pcidev, "adl_pci7296") < 0) { - printk(KERN_ERR - "comedi%d: Failed to enable PCI device and request regions\n", - dev->minor); - return -EIO; - } - - dev->iobase = pci_resource_start(pcidev, 2); - printk(KERN_INFO "comedi: base addr %4lx\n", dev->iobase); - - /* four 8255 digital io subdevices */ - s = dev->subdevices + 0; - subdev_8255_init(dev, s, NULL, (unsigned long)(dev->iobase)); - - s = dev->subdevices + 1; - ret = subdev_8255_init(dev, s, NULL, - (unsigned long)(dev->iobase + PORT2A)); - if (ret < 0) - return ret; - - s = dev->subdevices + 2; - ret = subdev_8255_init(dev, s, NULL, - (unsigned long)(dev->iobase + PORT3A)); - if (ret < 0) - return ret; - - s = dev->subdevices + 3; - ret = subdev_8255_init(dev, s, NULL, - (unsigned long)(dev->iobase + PORT4A)); - if (ret < 0) - return ret; - - printk(KERN_DEBUG "comedi%d: adl_pci7432 attached\n", dev->minor); - - return 0; -} - -static void adl_pci7296_detach(struct comedi_device *dev) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - - if (pcidev) { - if (dev->iobase) - comedi_pci_disable(pcidev); - pci_dev_put(pcidev); - } - if (dev->subdevices) { - subdev_8255_cleanup(dev, dev->subdevices + 0); - subdev_8255_cleanup(dev, dev->subdevices + 1); - subdev_8255_cleanup(dev, dev->subdevices + 2); - subdev_8255_cleanup(dev, dev->subdevices + 3); - } -} - -static struct comedi_driver adl_pci7296_driver = { - .driver_name = "adl_pci7296", - .module = THIS_MODULE, - .attach = adl_pci7296_attach, - .detach = adl_pci7296_detach, -}; - -static int __devinit adl_pci7296_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, &adl_pci7296_driver); -} - -static void __devexit adl_pci7296_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static DEFINE_PCI_DEVICE_TABLE(adl_pci7296_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7296) }, - { 0 } -}; -MODULE_DEVICE_TABLE(pci, adl_pci7296_pci_table); - -static struct pci_driver adl_pci7296_pci_driver = { - .name = "adl_pci7296", - .id_table = adl_pci7296_pci_table, - .probe = adl_pci7296_pci_probe, - .remove = __devexit_p(adl_pci7296_pci_remove), -}; -module_comedi_pci_driver(adl_pci7296_driver, adl_pci7296_pci_driver); - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/adl_pci7432.c b/drivers/staging/comedi/drivers/adl_pci7432.c deleted file mode 100644 index 6b8d9408e3bc..000000000000 --- a/drivers/staging/comedi/drivers/adl_pci7432.c +++ /dev/null @@ -1,200 +0,0 @@ -/* - comedi/drivers/adl_pci7432.c - - Hardware comedi driver fot PCI7432 Adlink card - Copyright (C) 2004 Michel Lachine <mike@mikelachaine.ca> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ -/* -Driver: adl_pci7432 -Description: Driver for the Adlink PCI-7432 64 ch. isolated digital io board -Devices: [ADLink] PCI-7432 (adl_pci7432) -Author: Michel Lachaine <mike@mikelachaine.ca> -Status: experimental -Updated: Mon, 14 Apr 2008 15:08:14 +0100 - -Configuration Options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - If bus/slot is not specified, the first supported - PCI device found will be used. -*/ - -#include "../comedidev.h" -#include <linux/kernel.h> - -#define PCI7432_DI 0x00 -#define PCI7432_DO 0x00 - -#define PCI_DEVICE_ID_PCI7432 0x7432 - -static int adl_pci7432_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - printk(KERN_DEBUG "comedi: pci7432_do_insn_bits called\n"); - printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]); - - if (data[0]) { - s->state &= ~data[0]; - s->state |= (data[0] & data[1]); - - printk(KERN_DEBUG "comedi: out: %8x on iobase %4lx\n", s->state, - dev->iobase + PCI7432_DO); - outl(s->state & 0xffffffff, dev->iobase + PCI7432_DO); - } - return insn->n; -} - -static int adl_pci7432_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, - unsigned int *data) -{ - printk(KERN_DEBUG "comedi: pci7432_di_insn_bits called\n"); - printk(KERN_DEBUG "comedi: data0: %8x data1: %8x\n", data[0], data[1]); - - data[1] = inl(dev->iobase + PCI7432_DI) & 0xffffffff; - printk(KERN_DEBUG "comedi: data1 %8x\n", data[1]); - - return insn->n; -} - -static struct pci_dev *adl_pci7432_find_pci(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct pci_dev *pcidev = NULL; - int bus = it->options[0]; - int slot = it->options[1]; - - for_each_pci_dev(pcidev) { - if (pcidev->vendor != PCI_VENDOR_ID_ADLINK || - pcidev->device != PCI_DEVICE_ID_PCI7432) - continue; - if (bus || slot) { - /* requested particular bus/slot */ - if (pcidev->bus->number != bus || - PCI_SLOT(pcidev->devfn) != slot) - continue; - } - return pcidev; - } - printk(KERN_ERR - "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n", - dev->minor, bus, slot); - return NULL; -} - -static int adl_pci7432_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct pci_dev *pcidev; - struct comedi_subdevice *s; - int ret; - - printk(KERN_INFO "comedi%d: attach adl_pci7432\n", dev->minor); - - dev->board_name = "pci7432"; - - ret = comedi_alloc_subdevices(dev, 2); - if (ret) - return ret; - - pcidev = adl_pci7432_find_pci(dev, it); - if (!pcidev) - return -EIO; - comedi_set_hw_dev(dev, &pcidev->dev); - - if (comedi_pci_enable(pcidev, "adl_pci7432") < 0) { - printk(KERN_ERR "comedi%d: Failed to enable PCI device and request regions\n", - dev->minor); - return -EIO; - } - dev->iobase = pci_resource_start(pcidev, 2); - printk(KERN_INFO "comedi: base addr %4lx\n", dev->iobase); - - s = dev->subdevices + 0; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 32; - s->maxdata = 1; - s->len_chanlist = 32; - s->io_bits = 0x00000000; - s->range_table = &range_digital; - s->insn_bits = adl_pci7432_di_insn_bits; - - s = dev->subdevices + 1; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = 32; - s->maxdata = 1; - s->len_chanlist = 32; - s->io_bits = 0xffffffff; - s->range_table = &range_digital; - s->insn_bits = adl_pci7432_do_insn_bits; - - printk(KERN_DEBUG "comedi%d: adl_pci7432 attached\n", dev->minor); - return 0; -} - -static void adl_pci7432_detach(struct comedi_device *dev) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - - if (pcidev) { - if (dev->iobase) - comedi_pci_disable(pcidev); - pci_dev_put(pcidev); - } -} - -static struct comedi_driver adl_pci7432_driver = { - .driver_name = "adl_pci7432", - .module = THIS_MODULE, - .attach = adl_pci7432_attach, - .detach = adl_pci7432_detach, -}; - -static int __devinit adl_pci7432_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, &adl_pci7432_driver); -} - -static void __devexit adl_pci7432_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static DEFINE_PCI_DEVICE_TABLE(adl_pci7432_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7432) }, - { 0 } -}; -MODULE_DEVICE_TABLE(pci, adl_pci7432_pci_table); - -static struct pci_driver adl_pci7432_pci_driver = { - .name = "adl_pci7432", - .id_table = adl_pci7432_pci_table, - .probe = adl_pci7432_pci_probe, - .remove = __devexit_p(adl_pci7432_pci_remove), -}; -module_comedi_pci_driver(adl_pci7432_driver, adl_pci7432_pci_driver); - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/staging/comedi/drivers/adl_pci7x3x.c new file mode 100644 index 000000000000..599714e978b5 --- /dev/null +++ b/drivers/staging/comedi/drivers/adl_pci7x3x.c @@ -0,0 +1,332 @@ +/* + * COMEDI driver for the ADLINK PCI-723x/743x series boards. + * Copyright (C) 2012 H Hartley Sweeten <hsweeten@visionengravers.com> + * + * Based on the adl_pci7230 driver written by: + * David Fernandez <dfcastelao@gmail.com> + * and the adl_pci7432 driver written by: + * Michel Lachaine <mike@mikelachaine.ca> + * + * COMEDI - Linux Control and Measurement Device Interface + * Copyright (C) 2000 David A. Schleef <ds@schleef.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +/* +Driver: adl_pci7x3x +Description: 32/64-Channel Isolated Digital I/O Boards +Devices: (ADLink) PCI-7230 [adl_pci7230] - 16 input / 16 output + (ADLink) PCI-7233 [adl_pci7233] - 32 input + (ADLink) PCI-7234 [adl_pci7234] - 32 output + (ADLink) PCI-7432 [adl_pci7432] - 32 input / 32 output + (ADLink) PCI-7433 [adl_pci7433] - 64 input + (ADLink) PCI-7434 [adl_pci7434] - 64 output +Author: H Hartley Sweeten <hsweeten@visionengravers.com> +Updated: Thu, 02 Aug 2012 14:27:46 -0700 +Status: untested + +This driver only attaches using the PCI PnP auto config support +in the comedi core. The module parameter 'comedi_autoconfig' +must be 1 (default) to enable this feature. The COMEDI_DEVCONFIG +ioctl, used by the comedi_config utility, is not supported by +this driver. + +The PCI-7230, PCI-7432 and PCI-7433 boards also support external +interrupt signals on digital input channels 0 and 1. The PCI-7233 +has dual-interrupt sources for change-of-state (COS) on any 16 +digital input channels of LSB and for COS on any 16 digital input +lines of MSB. Interrupts are not currently supported by this +driver. + +Configuration Options: not applicable +*/ + +#include "../comedidev.h" + +/* + * PCI Device ID's supported by this driver + */ +#define PCI_DEVICE_ID_PCI7230 0x7230 +#define PCI_DEVICE_ID_PCI7233 0x7233 +#define PCI_DEVICE_ID_PCI7234 0x7234 +#define PCI_DEVICE_ID_PCI7432 0x7432 +#define PCI_DEVICE_ID_PCI7433 0x7433 +#define PCI_DEVICE_ID_PCI7434 0x7434 + +/* + * Register I/O map (32-bit access only) + */ +#define PCI7X3X_DIO_REG 0x00 +#define PCI743X_DIO_REG 0x04 + +struct adl_pci7x3x_boardinfo { + const char *name; + unsigned short device; + int nsubdevs; + int di_nchan; + int do_nchan; +}; + +static const struct adl_pci7x3x_boardinfo adl_pci7x3x_boards[] = { + { + .name = "adl_pci7230", + .device = PCI_DEVICE_ID_PCI7230, + .nsubdevs = 2, + .di_nchan = 16, + .do_nchan = 16, + }, { + .name = "adl_pci7233", + .device = PCI_DEVICE_ID_PCI7233, + .nsubdevs = 1, + .di_nchan = 32, + }, { + .name = "adl_pci7234", + .device = PCI_DEVICE_ID_PCI7234, + .nsubdevs = 1, + .do_nchan = 32, + }, { + .name = "adl_pci7432", + .device = PCI_DEVICE_ID_PCI7432, + .nsubdevs = 2, + .di_nchan = 32, + .do_nchan = 32, + }, { + .name = "adl_pci7433", + .device = PCI_DEVICE_ID_PCI7433, + .nsubdevs = 2, + .di_nchan = 64, + }, { + .name = "adl_pci7434", + .device = PCI_DEVICE_ID_PCI7434, + .nsubdevs = 2, + .do_nchan = 64, + } +}; + +static int adl_pci7x3x_do_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned long reg = (unsigned long)s->private; + unsigned int mask = data[0]; + unsigned int bits = data[1]; + + if (mask) { + s->state &= ~mask; + s->state |= (bits & mask); + + outl(s->state, dev->iobase + reg); + } + + /* + * NOTE: The output register is not readable. + * This returned state will not be correct until all the + * outputs have been updated. + */ + data[1] = s->state; + + return insn->n; +} + +static int adl_pci7x3x_di_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + unsigned long reg = (unsigned long)s->private; + + data[1] = inl(dev->iobase + reg); + + return insn->n; +} + +static const void *adl_pci7x3x_find_boardinfo(struct comedi_device *dev, + struct pci_dev *pcidev) +{ + const struct adl_pci7x3x_boardinfo *board; + int i; + + for (i = 0; i < ARRAY_SIZE(adl_pci7x3x_boards); i++) { + board = &adl_pci7x3x_boards[i]; + if (pcidev->device == board->device) + return board; + } + return NULL; +} + +static int adl_pci7x3x_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) +{ + const struct adl_pci7x3x_boardinfo *board; + struct comedi_subdevice *s; + int subdev; + int nchan; + int ret; + + comedi_set_hw_dev(dev, &pcidev->dev); + + board = adl_pci7x3x_find_boardinfo(dev, pcidev); + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; + + ret = comedi_pci_enable(pcidev, dev->board_name); + if (ret) + return ret; + dev->iobase = pci_resource_start(pcidev, 2); + + /* + * One or two subdevices are setup by this driver depending on + * the number of digital inputs and/or outputs provided by the + * board. Each subdevice has a maximum of 32 channels. + * + * PCI-7230 - 2 subdevices: 0 - 16 input, 1 - 16 output + * PCI-7233 - 1 subdevice: 0 - 32 input + * PCI-7234 - 1 subdevice: 0 - 32 output + * PCI-7432 - 2 subdevices: 0 - 32 input, 1 - 32 output + * PCI-7433 - 2 subdevices: 0 - 32 input, 1 - 32 input + * PCI-7434 - 2 subdevices: 0 - 32 output, 1 - 32 output + */ + ret = comedi_alloc_subdevices(dev, board->nsubdevs); + if (ret) + return ret; + + subdev = 0; + + if (board->di_nchan) { + nchan = min(board->di_nchan, 32); + + s = &dev->subdevices[subdev]; + /* Isolated digital inputs 0 to 15/31 */ + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = nchan; + s->maxdata = 1; + s->insn_bits = adl_pci7x3x_di_insn_bits; + s->range_table = &range_digital; + + s->private = (void *)PCI7X3X_DIO_REG; + + subdev++; + + nchan = board->di_nchan - nchan; + if (nchan) { + s = &dev->subdevices[subdev]; + /* Isolated digital inputs 32 to 63 */ + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = nchan; + s->maxdata = 1; + s->insn_bits = adl_pci7x3x_di_insn_bits; + s->range_table = &range_digital; + + s->private = (void *)PCI743X_DIO_REG; + + subdev++; + } + } + + if (board->do_nchan) { + nchan = min(board->do_nchan, 32); + + s = &dev->subdevices[subdev]; + /* Isolated digital outputs 0 to 15/31 */ + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = nchan; + s->maxdata = 1; + s->insn_bits = adl_pci7x3x_do_insn_bits; + s->range_table = &range_digital; + + s->private = (void *)PCI7X3X_DIO_REG; + + subdev++; + + nchan = board->do_nchan - nchan; + if (nchan) { + s = &dev->subdevices[subdev]; + /* Isolated digital outputs 32 to 63 */ + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = nchan; + s->maxdata = 1; + s->insn_bits = adl_pci7x3x_do_insn_bits; + s->range_table = &range_digital; + + s->private = (void *)PCI743X_DIO_REG; + + subdev++; + } + } + + dev_info(dev->class_dev, "%s attached (%d inputs/%d outputs)\n", + dev->board_name, board->di_nchan, board->do_nchan); + + return 0; +} + +static void adl_pci7x3x_detach(struct comedi_device *dev) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + + if (pcidev) { + if (dev->iobase) + comedi_pci_disable(pcidev); + } +} + +static struct comedi_driver adl_pci7x3x_driver = { + .driver_name = "adl_pci7x3x", + .module = THIS_MODULE, + .attach_pci = adl_pci7x3x_attach_pci, + .detach = adl_pci7x3x_detach, +}; + +static int __devinit adl_pci7x3x_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + return comedi_pci_auto_config(dev, &adl_pci7x3x_driver); +} + +static void __devexit adl_pci7x3x_pci_remove(struct pci_dev *dev) +{ + comedi_pci_auto_unconfig(dev); +} + +static DEFINE_PCI_DEVICE_TABLE(adl_pci7x3x_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7230) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7233) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7234) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7432) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7433) }, + { PCI_DEVICE(PCI_VENDOR_ID_ADLINK, PCI_DEVICE_ID_PCI7434) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, adl_pci7x3x_pci_table); + +static struct pci_driver adl_pci7x3x_pci_driver = { + .name = "adl_pci7x3x", + .id_table = adl_pci7x3x_pci_table, + .probe = adl_pci7x3x_pci_probe, + .remove = __devexit_p(adl_pci7x3x_pci_remove), +}; +module_comedi_pci_driver(adl_pci7x3x_driver, adl_pci7x3x_pci_driver); + +MODULE_DESCRIPTION("ADLINK PCI-723x/743x Isolated Digital I/O boards"); +MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/adl_pci8164.c b/drivers/staging/comedi/drivers/adl_pci8164.c index 247ef00a7c6c..05e06e7ba9f7 100644 --- a/drivers/staging/comedi/drivers/adl_pci8164.c +++ b/drivers/staging/comedi/drivers/adl_pci8164.c @@ -27,11 +27,7 @@ Author: Michel Lachaine <mike@mikelachaine.ca> Status: experimental Updated: Mon, 14 Apr 2008 15:10:32 +0100 -Configuration Options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - If bus/slot is not specified, the first supported - PCI device found will be used. +Configuration Options: not applicable, uses PCI auto config */ #include "../comedidev.h" @@ -216,61 +212,26 @@ static int adl_pci8164_insn_write_buf1(struct comedi_device *dev, return 2; } -static struct pci_dev *adl_pci8164_find_pci(struct comedi_device *dev, - struct comedi_devconfig *it) +static int adl_pci8164_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) { - struct pci_dev *pcidev = NULL; - int bus = it->options[0]; - int slot = it->options[1]; - - for_each_pci_dev(pcidev) { - if (pcidev->vendor != PCI_VENDOR_ID_ADLINK || - pcidev->device != PCI_DEVICE_ID_PCI8164) - continue; - if (bus || slot) { - /* requested particular bus/slot */ - if (pcidev->bus->number != bus || - PCI_SLOT(pcidev->devfn) != slot) - continue; - } - return pcidev; - } - printk(KERN_ERR - "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n", - dev->minor, bus, slot); - return NULL; -} - -static int adl_pci8164_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct pci_dev *pcidev; struct comedi_subdevice *s; int ret; - printk(KERN_INFO "comedi: attempt to attach...\n"); - printk(KERN_INFO "comedi%d: adl_pci8164\n", dev->minor); + comedi_set_hw_dev(dev, &pcidev->dev); - dev->board_name = "pci8164"; + dev->board_name = dev->driver->driver_name; - ret = comedi_alloc_subdevices(dev, 4); + ret = comedi_pci_enable(pcidev, dev->board_name); if (ret) return ret; - - pcidev = adl_pci8164_find_pci(dev, it); - if (!pcidev) - return -EIO; - comedi_set_hw_dev(dev, &pcidev->dev); - - if (comedi_pci_enable(pcidev, "adl_pci8164") < 0) { - printk(KERN_ERR "comedi%d: Failed to enable " - "PCI device and request regions\n", dev->minor); - return -EIO; - } dev->iobase = pci_resource_start(pcidev, 2); - printk(KERN_DEBUG "comedi: base addr %4lx\n", dev->iobase); - s = dev->subdevices + 0; + ret = comedi_alloc_subdevices(dev, 4); + if (ret) + return ret; + + s = &dev->subdevices[0]; s->type = COMEDI_SUBD_PROC; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = 4; @@ -280,7 +241,7 @@ static int adl_pci8164_attach(struct comedi_device *dev, s->insn_read = adl_pci8164_insn_read_msts; s->insn_write = adl_pci8164_insn_write_cmd; - s = dev->subdevices + 1; + s = &dev->subdevices[1]; s->type = COMEDI_SUBD_PROC; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = 4; @@ -290,7 +251,7 @@ static int adl_pci8164_attach(struct comedi_device *dev, s->insn_read = adl_pci8164_insn_read_ssts; s->insn_write = adl_pci8164_insn_write_otp; - s = dev->subdevices + 2; + s = &dev->subdevices[2]; s->type = COMEDI_SUBD_PROC; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = 4; @@ -300,7 +261,7 @@ static int adl_pci8164_attach(struct comedi_device *dev, s->insn_read = adl_pci8164_insn_read_buf0; s->insn_write = adl_pci8164_insn_write_buf0; - s = dev->subdevices + 3; + s = &dev->subdevices[3]; s->type = COMEDI_SUBD_PROC; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = 4; @@ -310,7 +271,8 @@ static int adl_pci8164_attach(struct comedi_device *dev, s->insn_read = adl_pci8164_insn_read_buf1; s->insn_write = adl_pci8164_insn_write_buf1; - printk(KERN_INFO "comedi: attached\n"); + dev_info(dev->class_dev, "%s attached\n", dev->board_name); + return 0; } @@ -321,14 +283,13 @@ static void adl_pci8164_detach(struct comedi_device *dev) if (pcidev) { if (dev->iobase) comedi_pci_disable(pcidev); - pci_dev_put(pcidev); } } static struct comedi_driver adl_pci8164_driver = { .driver_name = "adl_pci8164", .module = THIS_MODULE, - .attach = adl_pci8164_attach, + .attach_pci = adl_pci8164_attach_pci, .detach = adl_pci8164_detach, }; diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c index a31dae6e07df..a87192ac2846 100644 --- a/drivers/staging/comedi/drivers/adl_pci9111.c +++ b/drivers/staging/comedi/drivers/adl_pci9111.c @@ -47,14 +47,7 @@ Supports: The scanned channels must be consecutive and start from 0. They must all have the same range and aref. -Configuration options: - - [0] - PCI bus number (optional) - [1] - PCI slot number (optional) - -If bus/slot is not specified, the first available PCI -device will be used. - +Configuration options: not applicable, uses PCI auto config */ /* @@ -86,29 +79,9 @@ TODO: #define PCI9111_DRIVER_NAME "adl_pci9111" #define PCI9111_HR_DEVICE_ID 0x9111 -/* TODO: Add other pci9111 board id */ - -#define PCI9111_IO_RANGE 0x0100 - #define PCI9111_FIFO_HALF_SIZE 512 -#define PCI9111_AI_CHANNEL_NBR 16 - -#define PCI9111_AI_RESOLUTION 12 -#define PCI9111_AI_RESOLUTION_MASK 0x0FFF -#define PCI9111_AI_RESOLUTION_2_CMP_BIT 0x0800 - -#define PCI9111_HR_AI_RESOLUTION 16 -#define PCI9111_HR_AI_RESOLUTION_MASK 0xFFFF -#define PCI9111_HR_AI_RESOLUTION_2_CMP_BIT 0x8000 - #define PCI9111_AI_ACQUISITION_PERIOD_MIN_NS 10000 -#define PCI9111_AO_CHANNEL_NBR 1 -#define PCI9111_AO_RESOLUTION 12 -#define PCI9111_AO_RESOLUTION_MASK 0x0FFF -#define PCI9111_DI_CHANNEL_NBR 16 -#define PCI9111_DO_CHANNEL_NBR 16 -#define PCI9111_DO_MASK 0xFFFF #define PCI9111_RANGE_SETTING_DELAY 10 #define PCI9111_AI_INSTANT_READ_UDELAY_US 2 @@ -116,233 +89,49 @@ TODO: #define PCI9111_8254_CLOCK_PERIOD_NS 500 -#define PCI9111_8254_COUNTER_0 0x00 -#define PCI9111_8254_COUNTER_1 0x40 -#define PCI9111_8254_COUNTER_2 0x80 -#define PCI9111_8254_COUNTER_LATCH 0x00 -#define PCI9111_8254_READ_LOAD_LSB_ONLY 0x10 -#define PCI9111_8254_READ_LOAD_MSB_ONLY 0x20 -#define PCI9111_8254_READ_LOAD_LSB_MSB 0x30 -#define PCI9111_8254_MODE_0 0x00 -#define PCI9111_8254_MODE_1 0x02 -#define PCI9111_8254_MODE_2 0x04 -#define PCI9111_8254_MODE_3 0x06 -#define PCI9111_8254_MODE_4 0x08 -#define PCI9111_8254_MODE_5 0x0A -#define PCI9111_8254_BINARY_COUNTER 0x00 -#define PCI9111_8254_BCD_COUNTER 0x01 - -/* IO address map */ - -#define PCI9111_REGISTER_AD_FIFO_VALUE 0x00 /* AD Data stored - in FIFO */ -#define PCI9111_REGISTER_DA_OUTPUT 0x00 -#define PCI9111_REGISTER_DIGITAL_IO 0x02 -#define PCI9111_REGISTER_EXTENDED_IO_PORTS 0x04 -#define PCI9111_REGISTER_AD_CHANNEL_CONTROL 0x06 /* Channel - selection */ -#define PCI9111_REGISTER_AD_CHANNEL_READBACK 0x06 -#define PCI9111_REGISTER_INPUT_SIGNAL_RANGE 0x08 -#define PCI9111_REGISTER_RANGE_STATUS_READBACK 0x08 -#define PCI9111_REGISTER_TRIGGER_MODE_CONTROL 0x0A -#define PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK 0x0A -#define PCI9111_REGISTER_SOFTWARE_TRIGGER 0x0E -#define PCI9111_REGISTER_INTERRUPT_CONTROL 0x0C -#define PCI9111_REGISTER_8254_COUNTER_0 0x40 -#define PCI9111_REGISTER_8254_COUNTER_1 0x42 -#define PCI9111_REGISTER_8254_COUNTER_2 0X44 -#define PCI9111_REGISTER_8254_CONTROL 0x46 -#define PCI9111_REGISTER_INTERRUPT_CLEAR 0x48 - -#define PCI9111_TRIGGER_MASK 0x0F -#define PCI9111_PTRG_OFF (0 << 3) -#define PCI9111_PTRG_ON (1 << 3) -#define PCI9111_EITS_EXTERNAL (1 << 2) -#define PCI9111_EITS_INTERNAL (0 << 2) -#define PCI9111_TPST_SOFTWARE_TRIGGER (0 << 1) -#define PCI9111_TPST_TIMER_PACER (1 << 1) -#define PCI9111_ASCAN_ON (1 << 0) -#define PCI9111_ASCAN_OFF (0 << 0) - -#define PCI9111_ISC0_SET_IRQ_ON_ENDING_OF_AD_CONVERSION (0 << 0) -#define PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL (1 << 0) -#define PCI9111_ISC1_SET_IRQ_ON_TIMER_TICK (0 << 1) -#define PCI9111_ISC1_SET_IRQ_ON_EXT_TRG (1 << 1) -#define PCI9111_FFEN_SET_FIFO_ENABLE (0 << 2) -#define PCI9111_FFEN_SET_FIFO_DISABLE (1 << 2) - -#define PCI9111_CHANNEL_MASK 0x0F - -#define PCI9111_RANGE_MASK 0x07 -#define PCI9111_FIFO_EMPTY_MASK 0x10 -#define PCI9111_FIFO_HALF_FULL_MASK 0x20 -#define PCI9111_FIFO_FULL_MASK 0x40 -#define PCI9111_AD_BUSY_MASK 0x80 - -#define PCI9111_IO_BASE (dev->iobase) - /* - * Define inlined function + * IO address map and bit defines */ - -#define pci9111_trigger_and_autoscan_get() \ - (inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK)&0x0F) - -#define pci9111_trigger_and_autoscan_set(flags) \ - outb(flags, PCI9111_IO_BASE+PCI9111_REGISTER_TRIGGER_MODE_CONTROL) - -#define pci9111_interrupt_and_fifo_get() \ - ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_MODE_INTERRUPT_READBACK) \ - >> 4) & 0x03) - -#define pci9111_interrupt_and_fifo_set(flags) \ - outb(flags, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL) - -#define pci9111_interrupt_clear() \ - outb(0, PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CLEAR) - -#define pci9111_software_trigger() \ - outb(0, PCI9111_IO_BASE+PCI9111_REGISTER_SOFTWARE_TRIGGER) - -#define pci9111_fifo_reset() do { \ - outb(PCI9111_FFEN_SET_FIFO_ENABLE, \ - PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \ - outb(PCI9111_FFEN_SET_FIFO_DISABLE, \ - PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \ - outb(PCI9111_FFEN_SET_FIFO_ENABLE, \ - PCI9111_IO_BASE+PCI9111_REGISTER_INTERRUPT_CONTROL); \ - } while (0) - -#define pci9111_is_fifo_full() \ - ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \ - PCI9111_FIFO_FULL_MASK) == 0) - -#define pci9111_is_fifo_half_full() \ - ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \ - PCI9111_FIFO_HALF_FULL_MASK) == 0) - -#define pci9111_is_fifo_empty() \ - ((inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK)& \ - PCI9111_FIFO_EMPTY_MASK) == 0) - -#define pci9111_ai_channel_set(channel) \ - outb((channel)&PCI9111_CHANNEL_MASK, \ - PCI9111_IO_BASE+PCI9111_REGISTER_AD_CHANNEL_CONTROL) - -#define pci9111_ai_channel_get() \ - (inb(PCI9111_IO_BASE+PCI9111_REGISTER_AD_CHANNEL_READBACK) \ - &PCI9111_CHANNEL_MASK) - -#define pci9111_ai_range_set(range) \ - outb((range)&PCI9111_RANGE_MASK, \ - PCI9111_IO_BASE+PCI9111_REGISTER_INPUT_SIGNAL_RANGE) - -#define pci9111_ai_range_get() \ - (inb(PCI9111_IO_BASE+PCI9111_REGISTER_RANGE_STATUS_READBACK) \ - &PCI9111_RANGE_MASK) - -#define pci9111_ai_get_data() \ - (((inw(PCI9111_IO_BASE+PCI9111_REGISTER_AD_FIFO_VALUE)>>4) \ - &PCI9111_AI_RESOLUTION_MASK) \ - ^ PCI9111_AI_RESOLUTION_2_CMP_BIT) - -#define pci9111_hr_ai_get_data() \ - ((inw(PCI9111_IO_BASE+PCI9111_REGISTER_AD_FIFO_VALUE) \ - &PCI9111_HR_AI_RESOLUTION_MASK) \ - ^ PCI9111_HR_AI_RESOLUTION_2_CMP_BIT) - -#define pci9111_ao_set_data(data) \ - outw(data&PCI9111_AO_RESOLUTION_MASK, \ - PCI9111_IO_BASE+PCI9111_REGISTER_DA_OUTPUT) - -#define pci9111_di_get_bits() \ - inw(PCI9111_IO_BASE+PCI9111_REGISTER_DIGITAL_IO) - -#define pci9111_do_set_bits(bits) \ - outw(bits, PCI9111_IO_BASE+PCI9111_REGISTER_DIGITAL_IO) - -#define pci9111_8254_control_set(flags) \ - outb(flags, PCI9111_IO_BASE+PCI9111_REGISTER_8254_CONTROL) - -#define pci9111_8254_counter_0_set(data) \ - do { \ - outb(data & 0xFF, \ - PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_0); \ - outb((data >> 8) & 0xFF, \ - PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_0); \ - } while (0) - -#define pci9111_8254_counter_1_set(data) \ - do { \ - outb(data & 0xFF, \ - PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_1); \ - outb((data >> 8) & 0xFF, \ - PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_1); \ - } while (0) - -#define pci9111_8254_counter_2_set(data) \ - do { \ - outb(data & 0xFF, \ - PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_2); \ - outb((data >> 8) & 0xFF, \ - PCI9111_IO_BASE+PCI9111_REGISTER_8254_COUNTER_2); \ - } while (0) - -static const struct comedi_lrange pci9111_hr_ai_range = { +#define PCI9111_AI_FIFO_REG 0x00 +#define PCI9111_AO_REG 0x00 +#define PCI9111_DIO_REG 0x02 +#define PCI9111_EDIO_REG 0x04 +#define PCI9111_AI_CHANNEL_REG 0x06 +#define PCI9111_AI_RANGE_STAT_REG 0x08 +#define PCI9111_AI_STAT_AD_BUSY (1 << 7) +#define PCI9111_AI_STAT_FF_FF (1 << 6) +#define PCI9111_AI_STAT_FF_HF (1 << 5) +#define PCI9111_AI_STAT_FF_EF (1 << 4) +#define PCI9111_AI_RANGE_MASK (7 << 0) +#define PCI9111_AI_TRIG_CTRL_REG 0x0a +#define PCI9111_AI_TRIG_CTRL_TRGEVENT (1 << 5) +#define PCI9111_AI_TRIG_CTRL_POTRG (1 << 4) +#define PCI9111_AI_TRIG_CTRL_PTRG (1 << 3) +#define PCI9111_AI_TRIG_CTRL_ETIS (1 << 2) +#define PCI9111_AI_TRIG_CTRL_TPST (1 << 1) +#define PCI9111_AI_TRIG_CTRL_ASCAN (1 << 0) +#define PCI9111_INT_CTRL_REG 0x0c +#define PCI9111_INT_CTRL_ISC2 (1 << 3) +#define PCI9111_INT_CTRL_FFEN (1 << 2) +#define PCI9111_INT_CTRL_ISC1 (1 << 1) +#define PCI9111_INT_CTRL_ISC0 (1 << 0) +#define PCI9111_SOFT_TRIG_REG 0x0e +#define PCI9111_8254_BASE_REG 0x40 +#define PCI9111_INT_CLR_REG 0x48 + +static const struct comedi_lrange pci9111_ai_range = { 5, { - BIP_RANGE(10), - BIP_RANGE(5), - BIP_RANGE(2.5), - BIP_RANGE(1.25), - BIP_RANGE(0.625) - } -}; - -/* */ -/* Board specification structure */ -/* */ - -struct pci9111_board { - const char *name; /* driver name */ - int device_id; - int ai_channel_nbr; /* num of A/D chans */ - int ao_channel_nbr; /* num of D/A chans */ - int ai_resolution; /* resolution of A/D */ - int ai_resolution_mask; - int ao_resolution; /* resolution of D/A */ - int ao_resolution_mask; - const struct comedi_lrange *ai_range_list; /* rangelist for A/D */ - const struct comedi_lrange *ao_range_list; /* rangelist for D/A */ - unsigned int ai_acquisition_period_min_ns; -}; - -static const struct pci9111_board pci9111_boards[] = { - { - .name = "pci9111_hr", - .device_id = PCI9111_HR_DEVICE_ID, - .ai_channel_nbr = PCI9111_AI_CHANNEL_NBR, - .ao_channel_nbr = PCI9111_AO_CHANNEL_NBR, - .ai_resolution = PCI9111_HR_AI_RESOLUTION, - .ai_resolution_mask = PCI9111_HR_AI_RESOLUTION_MASK, - .ao_resolution = PCI9111_AO_RESOLUTION, - .ao_resolution_mask = PCI9111_AO_RESOLUTION_MASK, - .ai_range_list = &pci9111_hr_ai_range, - .ao_range_list = &range_bipolar10, - .ai_acquisition_period_min_ns = PCI9111_AI_ACQUISITION_PERIOD_MIN_NS} + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625) + } }; -#define pci9111_board_nbr \ - (sizeof(pci9111_boards)/sizeof(struct pci9111_board)) - -/* Private data structure */ - struct pci9111_private_data { - unsigned long io_range; /* PCI6503 io range */ - - unsigned long lcr_io_base; /* Local configuration register base - * address */ - unsigned long lcr_io_range; + unsigned long lcr_io_base; int stop_counter; int stop_is_none; @@ -352,23 +141,14 @@ struct pci9111_private_data { unsigned int chunk_counter; unsigned int chunk_num_samples; - int ao_readback; /* Last written analog output data */ + int ao_readback; - unsigned int timer_divisor_1; /* Divisor values for the 8254 timer - * pacer */ - unsigned int timer_divisor_2; - - int is_valid; /* Is device valid */ + unsigned int div1; + unsigned int div2; short ai_bounce_buffer[2 * PCI9111_FIFO_HALF_SIZE]; }; -#define dev_private ((struct pci9111_private_data *)dev->private) - -/* ------------------------------------------------------------------ */ -/* PLX9050 SECTION */ -/* ------------------------------------------------------------------ */ - #define PLX9050_REGISTER_INTERRUPT_CONTROL 0x4c #define PLX9050_LINTI1_ENABLE (1 << 0) @@ -404,33 +184,19 @@ static void plx9050_interrupt_control(unsigned long io_base, outb(flags, io_base + PLX9050_REGISTER_INTERRUPT_CONTROL); } -/* ------------------------------------------------------------------ */ -/* MISCELLANEOUS SECTION */ -/* ------------------------------------------------------------------ */ - -/* 8254 timer */ - static void pci9111_timer_set(struct comedi_device *dev) { - pci9111_8254_control_set(PCI9111_8254_COUNTER_0 | - PCI9111_8254_READ_LOAD_LSB_MSB | - PCI9111_8254_MODE_0 | - PCI9111_8254_BINARY_COUNTER); + struct pci9111_private_data *dev_private = dev->private; + unsigned long timer_base = dev->iobase + PCI9111_8254_BASE_REG; - pci9111_8254_control_set(PCI9111_8254_COUNTER_1 | - PCI9111_8254_READ_LOAD_LSB_MSB | - PCI9111_8254_MODE_2 | - PCI9111_8254_BINARY_COUNTER); - - pci9111_8254_control_set(PCI9111_8254_COUNTER_2 | - PCI9111_8254_READ_LOAD_LSB_MSB | - PCI9111_8254_MODE_2 | - PCI9111_8254_BINARY_COUNTER); + i8254_set_mode(timer_base, 1, 0, I8254_MODE0 | I8254_BINARY); + i8254_set_mode(timer_base, 1, 1, I8254_MODE2 | I8254_BINARY); + i8254_set_mode(timer_base, 1, 2, I8254_MODE2 | I8254_BINARY); udelay(1); - pci9111_8254_counter_2_set(dev_private->timer_divisor_2); - pci9111_8254_counter_1_set(dev_private->timer_divisor_1); + i8254_write(timer_base, 1, 2, dev_private->div2); + i8254_write(timer_base, 1, 1, dev_private->div1); } enum pci9111_trigger_sources { @@ -444,47 +210,55 @@ static void pci9111_trigger_source_set(struct comedi_device *dev, { int flags; - flags = pci9111_trigger_and_autoscan_get() & 0x09; + /* Read the current trigger mode control bits */ + flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG); + /* Mask off the EITS and TPST bits */ + flags &= 0x9; switch (source) { case software: - flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_SOFTWARE_TRIGGER; break; case timer_pacer: - flags |= PCI9111_EITS_INTERNAL | PCI9111_TPST_TIMER_PACER; + flags |= PCI9111_AI_TRIG_CTRL_TPST; break; case external: - flags |= PCI9111_EITS_EXTERNAL; + flags |= PCI9111_AI_TRIG_CTRL_ETIS; break; } - pci9111_trigger_and_autoscan_set(flags); + outb(flags, dev->iobase + PCI9111_AI_TRIG_CTRL_REG); } static void pci9111_pretrigger_set(struct comedi_device *dev, bool pretrigger) { int flags; - flags = pci9111_trigger_and_autoscan_get() & 0x07; + /* Read the current trigger mode control bits */ + flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG); + /* Mask off the PTRG bit */ + flags &= 0x7; if (pretrigger) - flags |= PCI9111_PTRG_ON; + flags |= PCI9111_AI_TRIG_CTRL_PTRG; - pci9111_trigger_and_autoscan_set(flags); + outb(flags, dev->iobase + PCI9111_AI_TRIG_CTRL_REG); } static void pci9111_autoscan_set(struct comedi_device *dev, bool autoscan) { int flags; - flags = pci9111_trigger_and_autoscan_get() & 0x0e; + /* Read the current trigger mode control bits */ + flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG); + /* Mask off the ASCAN bit */ + flags &= 0xe; if (autoscan) - flags |= PCI9111_ASCAN_ON; + flags |= PCI9111_AI_TRIG_CTRL_ASCAN; - pci9111_trigger_and_autoscan_set(flags); + outb(flags, dev->iobase + PCI9111_AI_TRIG_CTRL_REG); } enum pci9111_ISC0_sources { @@ -503,30 +277,39 @@ static void pci9111_interrupt_source_set(struct comedi_device *dev, { int flags; - flags = pci9111_interrupt_and_fifo_get() & 0x04; + /* Read the current interrupt control bits */ + flags = inb(dev->iobase + PCI9111_AI_TRIG_CTRL_REG); + /* Shift the bits so they are compatible with the write register */ + flags >>= 4; + /* Mask off the ISCx bits */ + flags &= 0xc0; + /* Now set the new ISCx bits */ if (irq_0_source == irq_on_fifo_half_full) - flags |= PCI9111_ISC0_SET_IRQ_ON_FIFO_HALF_FULL; + flags |= PCI9111_INT_CTRL_ISC0; if (irq_1_source == irq_on_external_trigger) - flags |= PCI9111_ISC1_SET_IRQ_ON_EXT_TRG; + flags |= PCI9111_INT_CTRL_ISC1; - pci9111_interrupt_and_fifo_set(flags); + outb(flags, dev->iobase + PCI9111_INT_CTRL_REG); } -/* ------------------------------------------------------------------ */ -/* HARDWARE TRIGGERED ANALOG INPUT SECTION */ -/* ------------------------------------------------------------------ */ - -/* Cancel analog input autoscan */ +static void pci9111_fifo_reset(struct comedi_device *dev) +{ + unsigned long int_ctrl_reg = dev->iobase + PCI9111_INT_CTRL_REG; -#undef AI_DO_CMD_DEBUG + /* To reset the FIFO, set FFEN sequence as 0 -> 1 -> 0 */ + outb(0, int_ctrl_reg); + outb(PCI9111_INT_CTRL_FFEN, int_ctrl_reg); + outb(0, int_ctrl_reg); +} static int pci9111_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - /* Disable interrupts */ + struct pci9111_private_data *dev_private = dev->private; + /* Disable interrupts */ plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true, true, false); @@ -534,97 +317,65 @@ static int pci9111_ai_cancel(struct comedi_device *dev, pci9111_autoscan_set(dev, false); - pci9111_fifo_reset(); - -#ifdef AI_DO_CMD_DEBUG - printk(PCI9111_DRIVER_NAME ": ai_cancel\n"); -#endif + pci9111_fifo_reset(dev); return 0; } -/* Test analog input command */ - -#define pci9111_check_trigger_src(src, flags) do { \ - tmp = src; \ - src &= flags; \ - if (!src || tmp != src) \ - error++; \ - } while (false); - -static int -pci9111_ai_do_cmd_test(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd) +static int pci9111_ai_do_cmd_test(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { + struct pci9111_private_data *dev_private = dev->private; int tmp; int error = 0; int range, reference; int i; - struct pci9111_board *board = (struct pci9111_board *)dev->board_ptr; - /* Step 1 : check if trigger are trivialy valid */ + /* Step 1 : check if triggers are trivially valid */ - pci9111_check_trigger_src(cmd->start_src, TRIG_NOW); - pci9111_check_trigger_src(cmd->scan_begin_src, - TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT); - pci9111_check_trigger_src(cmd->convert_src, TRIG_TIMER | TRIG_EXT); - pci9111_check_trigger_src(cmd->scan_end_src, TRIG_COUNT); - pci9111_check_trigger_src(cmd->stop_src, TRIG_COUNT | TRIG_NONE); + error |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + error |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT); + error |= cfc_check_trigger_src(&cmd->convert_src, + TRIG_TIMER | TRIG_EXT); + error |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + error |= cfc_check_trigger_src(&cmd->stop_src, + TRIG_COUNT | TRIG_NONE); if (error) return 1; - /* step 2 : make sure trigger sources are unique and mutually - * compatible */ + /* Step 2a : make sure trigger sources are unique */ - if (cmd->start_src != TRIG_NOW) - error++; + error |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + error |= cfc_check_trigger_is_unique(cmd->convert_src); + error |= cfc_check_trigger_is_unique(cmd->stop_src); - if ((cmd->scan_begin_src != TRIG_TIMER) && - (cmd->scan_begin_src != TRIG_FOLLOW) && - (cmd->scan_begin_src != TRIG_EXT)) - error++; + /* Step 2b : and mutually compatible */ - if ((cmd->convert_src != TRIG_TIMER) && (cmd->convert_src != TRIG_EXT)) - error++; if ((cmd->convert_src == TRIG_TIMER) && !((cmd->scan_begin_src == TRIG_TIMER) || (cmd->scan_begin_src == TRIG_FOLLOW))) - error++; + error |= -EINVAL; if ((cmd->convert_src == TRIG_EXT) && !((cmd->scan_begin_src == TRIG_EXT) || (cmd->scan_begin_src == TRIG_FOLLOW))) - error++; - - - if (cmd->scan_end_src != TRIG_COUNT) - error++; - if ((cmd->stop_src != TRIG_COUNT) && (cmd->stop_src != TRIG_NONE)) - error++; + error |= -EINVAL; if (error) return 2; /* Step 3 : make sure arguments are trivialy compatible */ - if (cmd->chanlist_len < 1) { - cmd->chanlist_len = 1; - error++; - } - - if (cmd->chanlist_len > board->ai_channel_nbr) { - cmd->chanlist_len = board->ai_channel_nbr; - error++; - } - if ((cmd->start_src == TRIG_NOW) && (cmd->start_arg != 0)) { cmd->start_arg = 0; error++; } if ((cmd->convert_src == TRIG_TIMER) && - (cmd->convert_arg < board->ai_acquisition_period_min_ns)) { - cmd->convert_arg = board->ai_acquisition_period_min_ns; + (cmd->convert_arg < PCI9111_AI_ACQUISITION_PERIOD_MIN_NS)) { + cmd->convert_arg = PCI9111_AI_ACQUISITION_PERIOD_MIN_NS; error++; } if ((cmd->convert_src == TRIG_EXT) && (cmd->convert_arg != 0)) { @@ -633,8 +384,8 @@ pci9111_ai_do_cmd_test(struct comedi_device *dev, } if ((cmd->scan_begin_src == TRIG_TIMER) && - (cmd->scan_begin_arg < board->ai_acquisition_period_min_ns)) { - cmd->scan_begin_arg = board->ai_acquisition_period_min_ns; + (cmd->scan_begin_arg < PCI9111_AI_ACQUISITION_PERIOD_MIN_NS)) { + cmd->scan_begin_arg = PCI9111_AI_ACQUISITION_PERIOD_MIN_NS; error++; } if ((cmd->scan_begin_src == TRIG_FOLLOW) @@ -670,9 +421,9 @@ pci9111_ai_do_cmd_test(struct comedi_device *dev, if (cmd->convert_src == TRIG_TIMER) { tmp = cmd->convert_arg; i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS, - &(dev_private->timer_divisor_1), - &(dev_private->timer_divisor_2), - &(cmd->convert_arg), + &dev_private->div1, + &dev_private->div2, + &cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK); if (tmp != cmd->convert_arg) error++; @@ -733,14 +484,6 @@ pci9111_ai_do_cmd_test(struct comedi_device *dev, error++; } } - } else { - if ((CR_CHAN(cmd->chanlist[0]) > - (board->ai_channel_nbr - 1)) - || (CR_CHAN(cmd->chanlist[0]) < 0)) { - comedi_error(dev, - "channel number is out of limits\n"); - error++; - } } } @@ -751,12 +494,11 @@ pci9111_ai_do_cmd_test(struct comedi_device *dev, } -/* Analog input command */ - static int pci9111_ai_do_cmd(struct comedi_device *dev, - struct comedi_subdevice *subdevice) + struct comedi_subdevice *s) { - struct comedi_cmd *async_cmd = &subdevice->async->cmd; + struct pci9111_private_data *dev_private = dev->private; + struct comedi_cmd *async_cmd = &s->async->cmd; if (!dev->irq) { comedi_error(dev, @@ -768,17 +510,20 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev, /* TODO: handle the case of an external multiplexer */ if (async_cmd->chanlist_len > 1) { - pci9111_ai_channel_set((async_cmd->chanlist_len) - 1); + outb(async_cmd->chanlist_len - 1, + dev->iobase + PCI9111_AI_CHANNEL_REG); pci9111_autoscan_set(dev, true); } else { - pci9111_ai_channel_set(CR_CHAN(async_cmd->chanlist[0])); + outb(CR_CHAN(async_cmd->chanlist[0]), + dev->iobase + PCI9111_AI_CHANNEL_REG); pci9111_autoscan_set(dev, false); } /* Set gain */ /* This is the same gain on every channel */ - pci9111_ai_range_set(CR_RANGE(async_cmd->chanlist[0])); + outb(CR_RANGE(async_cmd->chanlist[0]) & PCI9111_AI_RANGE_MASK, + dev->iobase + PCI9111_AI_RANGE_STAT_REG); /* Set counter */ @@ -804,21 +549,9 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev, dev_private->scan_delay = 0; switch (async_cmd->convert_src) { case TRIG_TIMER: - i8253_cascade_ns_to_timer_2div(PCI9111_8254_CLOCK_PERIOD_NS, - &(dev_private->timer_divisor_1), - &(dev_private->timer_divisor_2), - &(async_cmd->convert_arg), - async_cmd-> - flags & TRIG_ROUND_MASK); -#ifdef AI_DO_CMD_DEBUG - printk(PCI9111_DRIVER_NAME ": divisors = %d, %d\n", - dev_private->timer_divisor_1, - dev_private->timer_divisor_2); -#endif - pci9111_trigger_source_set(dev, software); pci9111_timer_set(dev); - pci9111_fifo_reset(); + pci9111_fifo_reset(dev); pci9111_interrupt_source_set(dev, irq_on_fifo_half_full, irq_on_timer_tick); pci9111_trigger_source_set(dev, timer_pacer); @@ -837,7 +570,7 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev, case TRIG_EXT: pci9111_trigger_source_set(dev, external); - pci9111_fifo_reset(); + pci9111_fifo_reset(dev); pci9111_interrupt_source_set(dev, irq_on_fifo_half_full, irq_on_timer_tick); plx9050_interrupt_control(dev_private->lcr_io_base, true, true, @@ -856,23 +589,6 @@ static int pci9111_ai_do_cmd(struct comedi_device *dev, dev_private->chunk_num_samples = dev_private->chanlist_len * (1 + dev_private->scan_delay); -#ifdef AI_DO_CMD_DEBUG - printk(PCI9111_DRIVER_NAME ": start interruptions!\n"); - printk(PCI9111_DRIVER_NAME ": trigger source = %2x\n", - pci9111_trigger_and_autoscan_get()); - printk(PCI9111_DRIVER_NAME ": irq source = %2x\n", - pci9111_interrupt_and_fifo_get()); - printk(PCI9111_DRIVER_NAME ": ai_do_cmd\n"); - printk(PCI9111_DRIVER_NAME ": stop counter = %d\n", - dev_private->stop_counter); - printk(PCI9111_DRIVER_NAME ": scan delay = %d\n", - dev_private->scan_delay); - printk(PCI9111_DRIVER_NAME ": chanlist_len = %d\n", - dev_private->chanlist_len); - printk(PCI9111_DRIVER_NAME ": chunk num samples = %d\n", - dev_private->chunk_num_samples); -#endif - return 0; } @@ -881,34 +597,24 @@ static void pci9111_ai_munge(struct comedi_device *dev, unsigned int num_bytes, unsigned int start_chan_index) { - unsigned int i, num_samples = num_bytes / sizeof(short); short *array = data; - int resolution = - ((struct pci9111_board *)dev->board_ptr)->ai_resolution; - - for (i = 0; i < num_samples; i++) { - if (resolution == PCI9111_HR_AI_RESOLUTION) - array[i] = - (array[i] & PCI9111_HR_AI_RESOLUTION_MASK) ^ - PCI9111_HR_AI_RESOLUTION_2_CMP_BIT; - else - array[i] = - ((array[i] >> 4) & PCI9111_AI_RESOLUTION_MASK) ^ - PCI9111_AI_RESOLUTION_2_CMP_BIT; - } + unsigned int maxdata = s->maxdata; + unsigned int invert = (maxdata + 1) >> 1; + unsigned int shift = (maxdata == 0xffff) ? 0 : 4; + unsigned int num_samples = num_bytes / sizeof(short); + unsigned int i; + + for (i = 0; i < num_samples; i++) + array[i] = ((array[i] >> shift) & maxdata) ^ invert; } -/* ------------------------------------------------------------------ */ -/* INTERRUPT SECTION */ -/* ------------------------------------------------------------------ */ - -#undef INTERRUPT_DEBUG - static irqreturn_t pci9111_interrupt(int irq, void *p_device) { struct comedi_device *dev = p_device; - struct comedi_subdevice *subdevice = dev->read_subdev; + struct pci9111_private_data *dev_private = dev->private; + struct comedi_subdevice *s = dev->read_subdev; struct comedi_async *async; + unsigned int status; unsigned long irq_flags; unsigned char intcsr; @@ -918,7 +624,7 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device) return IRQ_NONE; } - async = subdevice->async; + async = s->async; spin_lock_irqsave(&dev->spinlock, irq_flags); @@ -940,37 +646,37 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device) (PLX9050_LINTI1_ENABLE | PLX9050_LINTI1_STATUS)) { /* Interrupt comes from fifo_half-full signal */ - if (pci9111_is_fifo_full()) { + status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG); + + /* '0' means FIFO is full, data may have been lost */ + if (!(status & PCI9111_AI_STAT_FF_FF)) { spin_unlock_irqrestore(&dev->spinlock, irq_flags); comedi_error(dev, PCI9111_DRIVER_NAME " fifo overflow"); - pci9111_interrupt_clear(); - pci9111_ai_cancel(dev, subdevice); + outb(0, dev->iobase + PCI9111_INT_CLR_REG); + pci9111_ai_cancel(dev, s); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - comedi_event(dev, subdevice); + comedi_event(dev, s); return IRQ_HANDLED; } - if (pci9111_is_fifo_half_full()) { + /* '0' means FIFO is half-full */ + if (!(status & PCI9111_AI_STAT_FF_HF)) { unsigned int num_samples; unsigned int bytes_written = 0; -#ifdef INTERRUPT_DEBUG - printk(PCI9111_DRIVER_NAME ": fifo is half full\n"); -#endif - num_samples = PCI9111_FIFO_HALF_SIZE > dev_private->stop_counter && !dev_private-> stop_is_none ? dev_private->stop_counter : PCI9111_FIFO_HALF_SIZE; - insw(PCI9111_IO_BASE + PCI9111_REGISTER_AD_FIFO_VALUE, + insw(dev->iobase + PCI9111_AI_FIFO_REG, dev_private->ai_bounce_buffer, num_samples); if (dev_private->scan_delay < 1) { bytes_written = - cfc_write_array_to_buffer(subdevice, + cfc_write_array_to_buffer(s, dev_private-> ai_bounce_buffer, num_samples * @@ -994,7 +700,7 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device) bytes_written += cfc_write_array_to_buffer - (subdevice, + (s, dev_private->ai_bounce_buffer + position, to_read * sizeof(short)); @@ -1029,168 +735,135 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device) if ((dev_private->stop_counter == 0) && (!dev_private->stop_is_none)) { async->events |= COMEDI_CB_EOA; - pci9111_ai_cancel(dev, subdevice); + pci9111_ai_cancel(dev, s); } - /* Very important, otherwise another interrupt request will be inserted - * and will cause driver hangs on processing interrupt event. */ - - pci9111_interrupt_clear(); + outb(0, dev->iobase + PCI9111_INT_CLR_REG); spin_unlock_irqrestore(&dev->spinlock, irq_flags); - comedi_event(dev, subdevice); + comedi_event(dev, s); return IRQ_HANDLED; } -/* ------------------------------------------------------------------ */ -/* INSTANT ANALOG INPUT OUTPUT SECTION */ -/* ------------------------------------------------------------------ */ - -/* analog instant input */ - -#undef AI_INSN_DEBUG - static int pci9111_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *subdevice, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int resolution = - ((struct pci9111_board *)dev->board_ptr)->ai_resolution; - - int timeout, i; - -#ifdef AI_INSN_DEBUG - printk(PCI9111_DRIVER_NAME ": ai_insn set c/r/n = %2x/%2x/%2x\n", - CR_CHAN((&insn->chanspec)[0]), - CR_RANGE((&insn->chanspec)[0]), insn->n); -#endif + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int maxdata = s->maxdata; + unsigned int invert = (maxdata + 1) >> 1; + unsigned int shift = (maxdata == 0xffff) ? 0 : 4; + unsigned int status; + int timeout; + int i; - pci9111_ai_channel_set(CR_CHAN((&insn->chanspec)[0])); + outb(chan, dev->iobase + PCI9111_AI_CHANNEL_REG); - if ((pci9111_ai_range_get()) != CR_RANGE((&insn->chanspec)[0])) - pci9111_ai_range_set(CR_RANGE((&insn->chanspec)[0])); + status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG); + if ((status & PCI9111_AI_RANGE_MASK) != range) { + outb(range & PCI9111_AI_RANGE_MASK, + dev->iobase + PCI9111_AI_RANGE_STAT_REG); + } - pci9111_fifo_reset(); + pci9111_fifo_reset(dev); for (i = 0; i < insn->n; i++) { - pci9111_software_trigger(); + /* Generate a software trigger */ + outb(0, dev->iobase + PCI9111_SOFT_TRIG_REG); timeout = PCI9111_AI_INSTANT_READ_TIMEOUT; while (timeout--) { - if (!pci9111_is_fifo_empty()) + status = inb(dev->iobase + PCI9111_AI_RANGE_STAT_REG); + /* '1' means FIFO is not empty */ + if (status & PCI9111_AI_STAT_FF_EF) goto conversion_done; } comedi_error(dev, "A/D read timeout"); data[i] = 0; - pci9111_fifo_reset(); + pci9111_fifo_reset(dev); return -ETIME; conversion_done: - if (resolution == PCI9111_HR_AI_RESOLUTION) - data[i] = pci9111_hr_ai_get_data(); - else - data[i] = pci9111_ai_get_data(); + data[i] = inw(dev->iobase + PCI9111_AI_FIFO_REG); + data[i] = ((data[i] >> shift) & maxdata) ^ invert; } -#ifdef AI_INSN_DEBUG - printk(PCI9111_DRIVER_NAME ": ai_insn get c/r/t = %2x/%2x/%2x\n", - pci9111_ai_channel_get(), - pci9111_ai_range_get(), pci9111_trigger_and_autoscan_get()); -#endif - return i; } -/* Analog instant output */ - -static int -pci9111_ao_insn_write(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +static int pci9111_ao_insn_write(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { + struct pci9111_private_data *dev_private = dev->private; + unsigned int val = 0; int i; for (i = 0; i < insn->n; i++) { - pci9111_ao_set_data(data[i]); - dev_private->ao_readback = data[i]; + val = data[i]; + outw(val, dev->iobase + PCI9111_AO_REG); } + dev_private->ao_readback = val; - return i; + return insn->n; } -/* Analog output readback */ - static int pci9111_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { + struct pci9111_private_data *dev_private = dev->private; int i; for (i = 0; i < insn->n; i++) - data[i] = dev_private->ao_readback & PCI9111_AO_RESOLUTION_MASK; + data[i] = dev_private->ao_readback; - return i; + return insn->n; } -/* ------------------------------------------------------------------ */ -/* DIGITAL INPUT OUTPUT SECTION */ -/* ------------------------------------------------------------------ */ - -/* Digital inputs */ - static int pci9111_di_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *subdevice, - struct comedi_insn *insn, unsigned int *data) + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned int bits; - - bits = pci9111_di_get_bits(); - data[1] = bits; + data[1] = inw(dev->iobase + PCI9111_DIO_REG); return insn->n; } -/* Digital outputs */ - static int pci9111_do_insn_bits(struct comedi_device *dev, - struct comedi_subdevice *subdevice, - struct comedi_insn *insn, unsigned int *data) + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - unsigned int bits; - - /* Only set bits that have been masked */ - /* data[0] = mask */ - /* data[1] = bit state */ + unsigned int mask = data[0]; + unsigned int bits = data[1]; - data[0] &= PCI9111_DO_MASK; + if (mask) { + s->state &= ~mask; + s->state |= (bits & mask); - bits = subdevice->state; - bits &= ~data[0]; - bits |= data[0] & data[1]; - subdevice->state = bits; - - pci9111_do_set_bits(bits); + outw(s->state, dev->iobase + PCI9111_DIO_REG); + } - data[1] = bits; + data[1] = s->state; return insn->n; } -/* ------------------------------------------------------------------ */ -/* INITIALISATION SECTION */ -/* ------------------------------------------------------------------ */ - -/* Reset device */ - static int pci9111_reset(struct comedi_device *dev) { - /* Set trigger source to software */ + struct pci9111_private_data *dev_private = dev->private; + /* Set trigger source to software */ plx9050_interrupt_control(dev_private->lcr_io_base, true, true, true, true, false); @@ -1198,177 +871,90 @@ static int pci9111_reset(struct comedi_device *dev) pci9111_pretrigger_set(dev, false); pci9111_autoscan_set(dev, false); - /* Reset 8254 chip */ - - dev_private->timer_divisor_1 = 0; - dev_private->timer_divisor_2 = 0; - + /* Reset 8254 chip */ + dev_private->div1 = 0; + dev_private->div2 = 0; pci9111_timer_set(dev); return 0; } -static struct pci_dev *pci9111_find_pci(struct comedi_device *dev, - struct comedi_devconfig *it) +static int pci9111_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) { - struct pci_dev *pcidev = NULL; - int bus = it->options[0]; - int slot = it->options[1]; - int i; - - for_each_pci_dev(pcidev) { - if (pcidev->vendor != PCI_VENDOR_ID_ADLINK) - continue; - for (i = 0; i < pci9111_board_nbr; i++) { - if (pcidev->device != pci9111_boards[i].device_id) - continue; - if (bus || slot) { - /* requested particular bus/slot */ - if (pcidev->bus->number != bus || - PCI_SLOT(pcidev->devfn) != slot) - continue; - } - dev->board_ptr = pci9111_boards + i; - printk(KERN_ERR - "comedi%d: found %s (b:s:f=%d:%d:%d), irq=%d\n", - dev->minor, pci9111_boards[i].name, - pcidev->bus->number, PCI_SLOT(pcidev->devfn), - PCI_FUNC(pcidev->devfn), pcidev->irq); - return pcidev; - } - } - printk(KERN_ERR - "comedi%d: no supported board found! (req. bus/slot : %d/%d)\n", - dev->minor, bus, slot); - return NULL; -} + struct pci9111_private_data *dev_private; + struct comedi_subdevice *s; + int ret; -static int pci9111_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct pci_dev *pcidev; - struct comedi_subdevice *subdevice; - unsigned long io_base, io_range, lcr_io_base, lcr_io_range; - int error; - const struct pci9111_board *board; - - if (alloc_private(dev, sizeof(struct pci9111_private_data)) < 0) - return -ENOMEM; - /* Probe the device to determine what device in the series it is. */ - - printk(KERN_ERR "comedi%d: " PCI9111_DRIVER_NAME " driver\n", - dev->minor); - - pcidev = pci9111_find_pci(dev, it); - if (!pcidev) - return -EIO; comedi_set_hw_dev(dev, &pcidev->dev); - board = (struct pci9111_board *)dev->board_ptr; - - /* TODO: Warn about non-tested boards. */ - - /* Read local configuration register base address - * [PCI_BASE_ADDRESS #1]. */ - - lcr_io_base = pci_resource_start(pcidev, 1); - lcr_io_range = pci_resource_len(pcidev, 1); - - printk - ("comedi%d: local configuration registers at address 0x%4lx [0x%4lx]\n", - dev->minor, lcr_io_base, lcr_io_range); - - /* Enable PCI device and request regions */ - if (comedi_pci_enable(pcidev, PCI9111_DRIVER_NAME) < 0) { - printk - ("comedi%d: Failed to enable PCI device and request regions\n", - dev->minor); - return -EIO; - } - /* Read PCI6308 register base address [PCI_BASE_ADDRESS #2]. */ + dev->board_name = dev->driver->driver_name; - io_base = pci_resource_start(pcidev, 2); - io_range = pci_resource_len(pcidev, 2); + ret = alloc_private(dev, sizeof(*dev_private)); + if (ret) + return ret; + dev_private = dev->private; - printk(KERN_ERR "comedi%d: 6503 registers at address 0x%4lx [0x%4lx]\n", - dev->minor, io_base, io_range); - - dev->iobase = io_base; - dev->board_name = board->name; - dev_private->io_range = io_range; - dev_private->is_valid = 0; - dev_private->lcr_io_base = lcr_io_base; - dev_private->lcr_io_range = lcr_io_range; + ret = comedi_pci_enable(pcidev, dev->board_name); + if (ret) + return ret; + dev_private->lcr_io_base = pci_resource_start(pcidev, 1); + dev->iobase = pci_resource_start(pcidev, 2); pci9111_reset(dev); - /* Irq setup */ - - dev->irq = 0; if (pcidev->irq > 0) { + ret = request_irq(dev->irq, pci9111_interrupt, + IRQF_SHARED, dev->board_name, dev); + if (ret) + return ret; dev->irq = pcidev->irq; - - if (request_irq(dev->irq, pci9111_interrupt, - IRQF_SHARED, PCI9111_DRIVER_NAME, dev) != 0) { - printk(KERN_ERR - "comedi%d: unable to allocate irq %u\n", - dev->minor, dev->irq); - return -EINVAL; - } } - /* TODO: Add external multiplexer setup (according to option[2]). */ - - error = comedi_alloc_subdevices(dev, 4); - if (error) - return error; - - subdevice = dev->subdevices + 0; - dev->read_subdev = subdevice; - - subdevice->type = COMEDI_SUBD_AI; - subdevice->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_CMD_READ; - - /* TODO: Add external multiplexer data */ - /* if (devpriv->usemux) { subdevice->n_chan = devpriv->usemux; } */ - /* else { subdevice->n_chan = this_board->n_aichan; } */ - - subdevice->n_chan = board->ai_channel_nbr; - subdevice->maxdata = board->ai_resolution_mask; - subdevice->len_chanlist = board->ai_channel_nbr; - subdevice->range_table = board->ai_range_list; - subdevice->cancel = pci9111_ai_cancel; - subdevice->insn_read = pci9111_ai_insn_read; - subdevice->do_cmdtest = pci9111_ai_do_cmd_test; - subdevice->do_cmd = pci9111_ai_do_cmd; - subdevice->munge = pci9111_ai_munge; - - subdevice = dev->subdevices + 1; - subdevice->type = COMEDI_SUBD_AO; - subdevice->subdev_flags = SDF_WRITABLE | SDF_COMMON; - subdevice->n_chan = board->ao_channel_nbr; - subdevice->maxdata = board->ao_resolution_mask; - subdevice->len_chanlist = board->ao_channel_nbr; - subdevice->range_table = board->ao_range_list; - subdevice->insn_write = pci9111_ao_insn_write; - subdevice->insn_read = pci9111_ao_insn_read; - - subdevice = dev->subdevices + 2; - subdevice->type = COMEDI_SUBD_DI; - subdevice->subdev_flags = SDF_READABLE; - subdevice->n_chan = PCI9111_DI_CHANNEL_NBR; - subdevice->maxdata = 1; - subdevice->range_table = &range_digital; - subdevice->insn_bits = pci9111_di_insn_bits; - - subdevice = dev->subdevices + 3; - subdevice->type = COMEDI_SUBD_DO; - subdevice->subdev_flags = SDF_READABLE | SDF_WRITABLE; - subdevice->n_chan = PCI9111_DO_CHANNEL_NBR; - subdevice->maxdata = 1; - subdevice->range_table = &range_digital; - subdevice->insn_bits = pci9111_do_insn_bits; - - dev_private->is_valid = 1; + ret = comedi_alloc_subdevices(dev, 4); + if (ret) + return ret; + + s = &dev->subdevices[0]; + dev->read_subdev = s; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_CMD_READ; + s->n_chan = 16; + s->maxdata = 0xffff; + s->len_chanlist = 16; + s->range_table = &pci9111_ai_range; + s->cancel = pci9111_ai_cancel; + s->insn_read = pci9111_ai_insn_read; + s->do_cmdtest = pci9111_ai_do_cmd_test; + s->do_cmd = pci9111_ai_do_cmd; + s->munge = pci9111_ai_munge; + + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_COMMON; + s->n_chan = 1; + s->maxdata = 0x0fff; + s->len_chanlist = 1; + s->range_table = &range_bipolar10; + s->insn_write = pci9111_ao_insn_write; + s->insn_read = pci9111_ao_insn_read; + + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pci9111_di_insn_bits; + + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = pci9111_do_insn_bits; + + dev_info(dev->class_dev, "%s attached\n", dev->board_name); return 0; } @@ -1377,23 +963,20 @@ static void pci9111_detach(struct comedi_device *dev) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); - if (dev->private != NULL) { - if (dev_private->is_valid) - pci9111_reset(dev); - } + if (dev->iobase) + pci9111_reset(dev); if (dev->irq != 0) free_irq(dev->irq, dev); if (pcidev) { if (dev->iobase) comedi_pci_disable(pcidev); - pci_dev_put(pcidev); } } static struct comedi_driver adl_pci9111_driver = { .driver_name = "adl_pci9111", .module = THIS_MODULE, - .attach = pci9111_attach, + .attach_pci = pci9111_attach_pci, .detach = pci9111_detach, }; diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c index a1f74c2590e8..06ff65c85c9f 100644 --- a/drivers/staging/comedi/drivers/adl_pci9118.c +++ b/drivers/staging/comedi/drivers/adl_pci9118.c @@ -81,18 +81,6 @@ Configuration options: * correct channel number on every 12 bit sample */ -#undef PCI9118_EXTDEBUG /* - * if defined then driver prints - * a lot of messages - */ - -#undef DPRINTK -#ifdef PCI9118_EXTDEBUG -#define DPRINTK(fmt, args...) printk(fmt, ## args) -#else -#define DPRINTK(fmt, args...) -#endif - #define IORANGE_9118 64 /* I hope */ #define PCI9118_CHANLEN 255 /* * len of chanlist, some source say 256, @@ -356,43 +344,170 @@ struct pci9118_private { unsigned int ai_inttrig_start; /* TRIG_INT for start */ }; -#define devpriv ((struct pci9118_private *)dev->private) -#define this_board ((struct boardtype *)dev->board_ptr) - -/* -============================================================================== -*/ - static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, int n_chan, - unsigned int *chanlist, int frontadd, - int backadd); + unsigned int *chanlist, int frontadd, int backadd) +{ + const struct boardtype *this_board = comedi_board(dev); + struct pci9118_private *devpriv = dev->private; + unsigned int i, differencial = 0, bipolar = 0; + + /* correct channel and range number check itself comedi/range.c */ + if (n_chan < 1) { + comedi_error(dev, "range/channel list is empty!"); + return 0; + } + if ((frontadd + n_chan + backadd) > s->len_chanlist) { + printk + ("comedi%d: range/channel list is too long for " + "actual configuration (%d>%d)!", + dev->minor, n_chan, s->len_chanlist - frontadd - backadd); + return 0; + } + + if (CR_AREF(chanlist[0]) == AREF_DIFF) + differencial = 1; /* all input must be diff */ + if (CR_RANGE(chanlist[0]) < PCI9118_BIPOLAR_RANGES) + bipolar = 1; /* all input must be bipolar */ + if (n_chan > 1) + for (i = 1; i < n_chan; i++) { /* check S.E/diff */ + if ((CR_AREF(chanlist[i]) == AREF_DIFF) != + (differencial)) { + comedi_error(dev, + "Differencial and single ended " + "inputs can't be mixtured!"); + return 0; + } + if ((CR_RANGE(chanlist[i]) < PCI9118_BIPOLAR_RANGES) != + (bipolar)) { + comedi_error(dev, + "Bipolar and unipolar ranges " + "can't be mixtured!"); + return 0; + } + if (!devpriv->usemux && differencial && + (CR_CHAN(chanlist[i]) >= this_board->n_aichand)) { + comedi_error(dev, + "If AREF_DIFF is used then is " + "available only first 8 channels!"); + return 0; + } + } + + return 1; +} + static int setup_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, int n_chan, unsigned int *chanlist, int rot, int frontadd, - int backadd, int usedma, char eoshandle); -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2); -static int pci9118_reset(struct comedi_device *dev); -static int pci9118_exttrg_add(struct comedi_device *dev, unsigned char source); -static int pci9118_exttrg_del(struct comedi_device *dev, unsigned char source); -static int pci9118_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); -static void pci9118_calc_divisors(char mode, struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *tim1, unsigned int *tim2, - unsigned int flags, int chans, - unsigned int *div1, unsigned int *div2, - char usessh, unsigned int chnsshfront); + int backadd, int usedma, char useeos) +{ + struct pci9118_private *devpriv = dev->private; + unsigned int i, differencial = 0, bipolar = 0; + unsigned int scanquad, gain, ssh = 0x00; + + if (usedma == 1) { + rot = 8; + usedma = 0; + } + + if (CR_AREF(chanlist[0]) == AREF_DIFF) + differencial = 1; /* all input must be diff */ + if (CR_RANGE(chanlist[0]) < PCI9118_BIPOLAR_RANGES) + bipolar = 1; /* all input must be bipolar */ + + /* All is ok, so we can setup channel/range list */ + + if (!bipolar) { + devpriv->AdControlReg |= AdControl_UniP; + /* set unibipolar */ + } else { + devpriv->AdControlReg &= ((~AdControl_UniP) & 0xff); + /* enable bipolar */ + } + + if (differencial) { + devpriv->AdControlReg |= AdControl_Diff; + /* enable diff inputs */ + } else { + devpriv->AdControlReg &= ((~AdControl_Diff) & 0xff); + /* set single ended inputs */ + } + + outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); + /* setup mode */ + + outl(2, dev->iobase + PCI9118_SCANMOD); + /* gods know why this sequence! */ + outl(0, dev->iobase + PCI9118_SCANMOD); + outl(1, dev->iobase + PCI9118_SCANMOD); + +#ifdef PCI9118_PARANOIDCHECK + devpriv->chanlistlen = n_chan; + for (i = 0; i < (PCI9118_CHANLEN + 1); i++) + devpriv->chanlist[i] = 0x55aa; +#endif + + if (frontadd) { /* insert channels for S&H */ + ssh = devpriv->softsshsample; + for (i = 0; i < frontadd; i++) { + /* store range list to card */ + scanquad = CR_CHAN(chanlist[0]); + /* get channel number; */ + gain = CR_RANGE(chanlist[0]); + /* get gain number */ + scanquad |= ((gain & 0x03) << 8); + outl(scanquad | ssh, dev->iobase + PCI9118_GAIN); + ssh = devpriv->softsshhold; + } + } + + for (i = 0; i < n_chan; i++) { /* store range list to card */ + scanquad = CR_CHAN(chanlist[i]); /* get channel number */ +#ifdef PCI9118_PARANOIDCHECK + devpriv->chanlist[i ^ usedma] = (scanquad & 0xf) << rot; +#endif + gain = CR_RANGE(chanlist[i]); /* get gain number */ + scanquad |= ((gain & 0x03) << 8); + outl(scanquad | ssh, dev->iobase + PCI9118_GAIN); + } + + if (backadd) { /* insert channels for fit onto 32bit DMA */ + for (i = 0; i < backadd; i++) { /* store range list to card */ + scanquad = CR_CHAN(chanlist[0]); + /* get channel number */ + gain = CR_RANGE(chanlist[0]); /* get gain number */ + scanquad |= ((gain & 0x03) << 8); + outl(scanquad | ssh, dev->iobase + PCI9118_GAIN); + } + } +#ifdef PCI9118_PARANOIDCHECK + devpriv->chanlist[n_chan ^ usedma] = devpriv->chanlist[0 ^ usedma]; + /* for 32bit operations */ + if (useeos) { + for (i = 1; i < n_chan; i++) { /* store range list to card */ + devpriv->chanlist[(n_chan + i) ^ usedma] = + (CR_CHAN(chanlist[i]) & 0xf) << rot; + } + devpriv->chanlist[(2 * n_chan) ^ usedma] = + devpriv->chanlist[0 ^ usedma]; + /* for 32bit operations */ + useeos = 2; + } else { + useeos = 1; + } +#endif + outl(0, dev->iobase + PCI9118_SCANMOD); /* close scan queue */ + /* udelay(100); important delay, or first sample will be crippled */ + + return 1; /* we can serve this with scan logic */ +} -/* -============================================================================== -*/ static int pci9118_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - + struct pci9118_private *devpriv = dev->private; int n, timeout; devpriv->AdControlReg = AdControl_Int & 0xff; @@ -442,13 +557,11 @@ conv_finish: } -/* -============================================================================== -*/ static int pci9118_insn_write_ao(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct pci9118_private *devpriv = dev->private; int n, chanreg, ch; ch = CR_CHAN(insn->chanspec); @@ -466,13 +579,11 @@ static int pci9118_insn_write_ao(struct comedi_device *dev, return n; } -/* -============================================================================== -*/ static int pci9118_insn_read_ao(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct pci9118_private *devpriv = dev->private; int n, chan; chan = CR_CHAN(insn->chanspec); @@ -482,9 +593,6 @@ static int pci9118_insn_read_ao(struct comedi_device *dev, return n; } -/* -============================================================================== -*/ static int pci9118_insn_bits_di(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -494,9 +602,6 @@ static int pci9118_insn_bits_di(struct comedi_device *dev, return insn->n; } -/* -============================================================================== -*/ static int pci9118_insn_bits_do(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -511,11 +616,10 @@ static int pci9118_insn_bits_do(struct comedi_device *dev, return insn->n; } -/* -============================================================================== -*/ static void interrupt_pci9118_ai_mode4_switch(struct comedi_device *dev) { + struct pci9118_private *devpriv = dev->private; + devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg | AdFunction_AM; outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); @@ -533,6 +637,7 @@ static unsigned int defragment_dma_buffer(struct comedi_device *dev, short *dma_buffer, unsigned int num_samples) { + struct pci9118_private *devpriv = dev->private; unsigned int i = 0, j = 0; unsigned int start_pos = devpriv->ai_add_front, stop_pos = devpriv->ai_add_front + devpriv->ai_n_chan; @@ -551,14 +656,12 @@ static unsigned int defragment_dma_buffer(struct comedi_device *dev, return j; } -/* -============================================================================== -*/ static int move_block_from_dma(struct comedi_device *dev, struct comedi_subdevice *s, short *dma_buffer, unsigned int num_samples) { + struct pci9118_private *devpriv = dev->private; unsigned int num_bytes; num_samples = defragment_dma_buffer(dev, s, dma_buffer, num_samples); @@ -574,13 +677,153 @@ static int move_block_from_dma(struct comedi_device *dev, return 0; } -/* -============================================================================== -*/ +static int pci9118_exttrg_add(struct comedi_device *dev, unsigned char source) +{ + struct pci9118_private *devpriv = dev->private; + + if (source > 3) + return -1; /* incorrect source */ + devpriv->exttrg_users |= (1 << source); + devpriv->IntControlReg |= Int_DTrg; + outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); + outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00, + devpriv->iobase_a + AMCC_OP_REG_INTCSR); + /* allow INT in AMCC */ + return 0; +} + +static int pci9118_exttrg_del(struct comedi_device *dev, unsigned char source) +{ + struct pci9118_private *devpriv = dev->private; + + if (source > 3) + return -1; /* incorrect source */ + devpriv->exttrg_users &= ~(1 << source); + if (!devpriv->exttrg_users) { /* shutdown ext trg intterrupts */ + devpriv->IntControlReg &= ~Int_DTrg; + if (!devpriv->IntControlReg) /* all IRQ disabled */ + outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) & + (~0x00001f00), + devpriv->iobase_a + AMCC_OP_REG_INTCSR); + /* disable int in AMCC */ + outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); + } + return 0; +} + +static void pci9118_calc_divisors(char mode, struct comedi_device *dev, + struct comedi_subdevice *s, + unsigned int *tim1, unsigned int *tim2, + unsigned int flags, int chans, + unsigned int *div1, unsigned int *div2, + char usessh, unsigned int chnsshfront) +{ + const struct boardtype *this_board = comedi_board(dev); + struct pci9118_private *devpriv = dev->private; + + switch (mode) { + case 1: + case 4: + if (*tim2 < this_board->ai_ns_min) + *tim2 = this_board->ai_ns_min; + i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, div1, div2, + tim2, flags & TRIG_ROUND_NEAREST); + break; + case 2: + if (*tim2 < this_board->ai_ns_min) + *tim2 = this_board->ai_ns_min; + *div1 = *tim2 / devpriv->i8254_osc_base; + /* convert timer (burst) */ + if (*div1 < this_board->ai_pacer_min) + *div1 = this_board->ai_pacer_min; + *div2 = *tim1 / devpriv->i8254_osc_base; /* scan timer */ + *div2 = *div2 / *div1; /* major timer is c1*c2 */ + if (*div2 < chans) + *div2 = chans; + + *tim2 = *div1 * devpriv->i8254_osc_base; + /* real convert timer */ + + if (usessh & (chnsshfront == 0)) /* use BSSH signal */ + if (*div2 < (chans + 2)) + *div2 = chans + 2; + + *tim1 = *div1 * *div2 * devpriv->i8254_osc_base; + break; + } +} + +static void start_pacer(struct comedi_device *dev, int mode, + unsigned int divisor1, unsigned int divisor2) +{ + outl(0x74, dev->iobase + PCI9118_CNTCTRL); + outl(0xb4, dev->iobase + PCI9118_CNTCTRL); +/* outl(0x30, dev->iobase + PCI9118_CNTCTRL); */ + udelay(1); + + if ((mode == 1) || (mode == 2) || (mode == 4)) { + outl(divisor2 & 0xff, dev->iobase + PCI9118_CNT2); + outl((divisor2 >> 8) & 0xff, dev->iobase + PCI9118_CNT2); + outl(divisor1 & 0xff, dev->iobase + PCI9118_CNT1); + outl((divisor1 >> 8) & 0xff, dev->iobase + PCI9118_CNT1); + } +} + +static int pci9118_ai_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + struct pci9118_private *devpriv = dev->private; + + if (devpriv->usedma) + outl(inl(devpriv->iobase_a + AMCC_OP_REG_MCSR) & + (~EN_A2P_TRANSFERS), + devpriv->iobase_a + AMCC_OP_REG_MCSR); /* stop DMA */ + pci9118_exttrg_del(dev, EXTTRG_AI); + start_pacer(dev, 0, 0, 0); /* stop 8254 counters */ + devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg; + outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); + /* + * positive triggers, no S&H, no burst, + * burst stop, no post trigger, + * no about trigger, trigger stop + */ + devpriv->AdControlReg = 0x00; + outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); + /* + * bipolar, S.E., use 8254, stop 8354, + * internal trigger, soft trigger, + * disable INT and DMA + */ + outl(0, dev->iobase + PCI9118_BURST); + outl(1, dev->iobase + PCI9118_SCANMOD); + outl(2, dev->iobase + PCI9118_SCANMOD); /* reset scan queue */ + outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */ + + devpriv->ai_do = 0; + devpriv->usedma = 0; + + devpriv->ai_act_scan = 0; + devpriv->ai_act_dmapos = 0; + s->async->cur_chan = 0; + s->async->inttrig = NULL; + devpriv->ai_buf_ptr = 0; + devpriv->ai_neverending = 0; + devpriv->dma_actbuf = 0; + + if (!devpriv->IntControlReg) + outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00, + devpriv->iobase_a + AMCC_OP_REG_INTCSR); + /* allow INT in AMCC */ + + return 0; +} + static char pci9118_decode_error_status(struct comedi_device *dev, struct comedi_subdevice *s, unsigned char m) { + struct pci9118_private *devpriv = dev->private; + if (m & 0x100) { comedi_error(dev, "A/D FIFO Full status (Fatal Error!)"); devpriv->ai_maskerr &= ~0x100L; @@ -613,6 +856,7 @@ static void pci9118_ai_munge(struct comedi_device *dev, unsigned int num_bytes, unsigned int start_chan_index) { + struct pci9118_private *devpriv = dev->private; unsigned int i, num_samples = num_bytes / sizeof(short); short *array = data; @@ -627,15 +871,13 @@ static void pci9118_ai_munge(struct comedi_device *dev, } } -/* -============================================================================== -*/ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev, struct comedi_subdevice *s, unsigned short int_adstat, unsigned int int_amcc, unsigned short int_daq) { + struct pci9118_private *devpriv = dev->private; register short sampl; s->async->events = 0; @@ -680,15 +922,13 @@ static void interrupt_pci9118_ai_onesample(struct comedi_device *dev, comedi_event(dev, s); } -/* -============================================================================== -*/ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, struct comedi_subdevice *s, unsigned short int_adstat, unsigned int int_amcc, unsigned short int_daq) { + struct pci9118_private *devpriv = dev->private; unsigned int next_dma_buf, samplesinbuf, sampls, m; if (int_amcc & MASTER_ABORT_INT) { @@ -713,7 +953,6 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, samplesinbuf = devpriv->dmabuf_use_size[devpriv->dma_actbuf] >> 1; /* number of received real samples */ -/* DPRINTK("dma_actbuf=%d\n",devpriv->dma_actbuf); */ if (devpriv->dma_doublebuf) { /* * switch DMA buffers if is used @@ -735,17 +974,12 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, * how many samples is to * end of buffer */ -/* - * DPRINTK("samps=%d m=%d %d %d\n", - * samplesinbuf,m,s->async->buf_int_count,s->async->buf_int_ptr); - */ sampls = m; move_block_from_dma(dev, s, devpriv->dmabuf_virt[devpriv->dma_actbuf], samplesinbuf); m = m - sampls; /* m= how many samples was transferred */ } -/* DPRINTK("YYY\n"); */ if (!devpriv->ai_neverending) if (devpriv->ai_act_scan >= devpriv->ai_scans) { @@ -768,12 +1002,10 @@ static void interrupt_pci9118_ai_dma(struct comedi_device *dev, comedi_event(dev, s); } -/* -============================================================================== -*/ static irqreturn_t interrupt_pci9118(int irq, void *d) { struct comedi_device *dev = d; + struct pci9118_private *devpriv = dev->private; unsigned int int_daq = 0, int_amcc, int_adstat; if (!dev->attached) @@ -784,14 +1016,6 @@ static irqreturn_t interrupt_pci9118(int irq, void *d) int_amcc = inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR); /* get INT register from AMCC chip */ -/* - * DPRINTK("INT daq=0x%01x amcc=0x%08x MWAR=0x%08x - * MWTC=0x%08x ADSTAT=0x%02x ai_do=%d\n", - * int_daq, int_amcc, inl(devpriv->iobase_a+AMCC_OP_REG_MWAR), - * inl(devpriv->iobase_a+AMCC_OP_REG_MWTC), - * inw(dev->iobase+PCI9118_ADSTAT)&0x1ff,devpriv->ai_do); - */ - if ((!int_daq) && (!(int_amcc & ANY_S593X_INT))) return IRQ_NONE; /* interrupt from other source */ @@ -837,19 +1061,18 @@ static irqreturn_t interrupt_pci9118(int irq, void *d) } } - (devpriv->int_ai_func) (dev, dev->subdevices + 0, int_adstat, + (devpriv->int_ai_func) (dev, &dev->subdevices[0], int_adstat, int_amcc, int_daq); } return IRQ_HANDLED; } -/* -============================================================================== -*/ static int pci9118_ai_inttrig(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int trignum) { + struct pci9118_private *devpriv = dev->private; + if (trignum != devpriv->ai_inttrig_start) return -EINVAL; @@ -868,119 +1091,64 @@ static int pci9118_ai_inttrig(struct comedi_device *dev, return 1; } -/* -============================================================================== -*/ static int pci9118_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { + const struct boardtype *this_board = comedi_board(dev); + struct pci9118_private *devpriv = dev->private; int err = 0; + unsigned int flags; int tmp; unsigned int divisor1 = 0, divisor2 = 0; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT | TRIG_INT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, + TRIG_NOW | TRIG_EXT | TRIG_INT); - tmp = cmd->scan_begin_src; + flags = TRIG_FOLLOW; if (devpriv->master) - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT | TRIG_FOLLOW; - else - cmd->scan_begin_src &= TRIG_FOLLOW; + flags |= TRIG_TIMER | TRIG_EXT; + err |= cfc_check_trigger_src(&cmd->scan_begin_src, flags); - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; + flags = TRIG_TIMER | TRIG_EXT; if (devpriv->master) - cmd->convert_src &= TRIG_TIMER | TRIG_EXT | TRIG_NOW; - else - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + flags |= TRIG_NOW; + err |= cfc_check_trigger_src(&cmd->convert_src, flags); - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE | TRIG_EXT; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, + TRIG_COUNT | TRIG_NONE | TRIG_EXT); if (err) return 1; - /* - * step 2: - * make sure trigger sources are - * unique and mutually compatible - */ + /* Step 2a : make sure trigger sources are unique */ - if (cmd->start_src != TRIG_NOW && - cmd->start_src != TRIG_INT && cmd->start_src != TRIG_EXT) { - cmd->start_src = TRIG_NOW; - err++; - } - - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT && - cmd->scan_begin_src != TRIG_INT && - cmd->scan_begin_src != TRIG_FOLLOW) { - cmd->scan_begin_src = TRIG_FOLLOW; - err++; - } - - if (cmd->convert_src != TRIG_TIMER && - cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW) { - cmd->convert_src = TRIG_TIMER; - err++; - } - - if (cmd->scan_end_src != TRIG_COUNT) { - cmd->scan_end_src = TRIG_COUNT; - err++; - } + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); - if (cmd->stop_src != TRIG_NONE && - cmd->stop_src != TRIG_COUNT && - cmd->stop_src != TRIG_INT && cmd->stop_src != TRIG_EXT) { - cmd->stop_src = TRIG_COUNT; - err++; - } + /* Step 2b : and mutually compatible */ - if (cmd->start_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT) { - cmd->start_src = TRIG_NOW; - err++; - } + if (cmd->start_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT) + err |= -EINVAL; - if (cmd->start_src == TRIG_INT && cmd->scan_begin_src == TRIG_INT) { - cmd->start_src = TRIG_NOW; - err++; - } + if (cmd->start_src == TRIG_INT && cmd->scan_begin_src == TRIG_INT) + err |= -EINVAL; if ((cmd->scan_begin_src & (TRIG_TIMER | TRIG_EXT)) && - (!(cmd->convert_src & (TRIG_TIMER | TRIG_NOW)))) { - cmd->convert_src = TRIG_TIMER; - err++; - } + (!(cmd->convert_src & (TRIG_TIMER | TRIG_NOW)))) + err |= -EINVAL; if ((cmd->scan_begin_src == TRIG_FOLLOW) && - (!(cmd->convert_src & (TRIG_TIMER | TRIG_EXT)))) { - cmd->convert_src = TRIG_TIMER; - err++; - } + (!(cmd->convert_src & (TRIG_TIMER | TRIG_EXT)))) + err |= -EINVAL; - if (cmd->stop_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT) { - cmd->stop_src = TRIG_COUNT; - err++; - } + if (cmd->stop_src == TRIG_EXT && cmd->scan_begin_src == TRIG_EXT) + err |= -EINVAL; if (err) return 2; @@ -1074,11 +1242,9 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev, if (cmd->scan_begin_src == TRIG_TIMER) { tmp = cmd->scan_begin_arg; -/* printk("S1 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); */ i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1, &divisor2, &cmd->scan_begin_arg, cmd->flags & TRIG_ROUND_MASK); -/* printk("S2 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); */ if (cmd->scan_begin_arg < this_board->ai_ns_min) cmd->scan_begin_arg = this_board->ai_ns_min; if (tmp != cmd->scan_begin_arg) @@ -1090,7 +1256,6 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev, i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1, &divisor2, &cmd->convert_arg, cmd->flags & TRIG_ROUND_MASK); -/* printk("s1 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); */ if (cmd->convert_arg < this_board->ai_ns_min) cmd->convert_arg = this_board->ai_ns_min; if (tmp != cmd->convert_arg) @@ -1104,7 +1269,6 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev, cmd->scan_begin_arg = this_board->ai_ns_min * (cmd->scan_end_arg + 2); -/* printk("s2 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); */ err++; } } else { @@ -1113,7 +1277,6 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev, cmd->scan_begin_arg = cmd->convert_arg * cmd->chanlist_len; -/* printk("s3 timer1=%u timer2=%u\n",cmd->scan_begin_arg,cmd->convert_arg); */ err++; } } @@ -1131,18 +1294,13 @@ static int pci9118_ai_cmdtest(struct comedi_device *dev, return 0; } -/* -============================================================================== -*/ static int Compute_and_setup_dma(struct comedi_device *dev) { + struct pci9118_private *devpriv = dev->private; unsigned int dmalen0, dmalen1, i; - DPRINTK("adl_pci9118 EDBG: BGN: Compute_and_setup_dma()\n"); dmalen0 = devpriv->dmabuf_size[0]; dmalen1 = devpriv->dmabuf_size[1]; - DPRINTK("1 dmalen0=%d dmalen1=%d ai_data_len=%d\n", dmalen0, dmalen1, - devpriv->ai_data_len); /* isn't output buff smaller that our DMA buff? */ if (dmalen0 > (devpriv->ai_data_len)) { dmalen0 = devpriv->ai_data_len & ~3L; /* @@ -1154,7 +1312,6 @@ static int Compute_and_setup_dma(struct comedi_device *dev) * align to 32bit down */ } - DPRINTK("2 dmalen0=%d dmalen1=%d\n", dmalen0, dmalen1); /* we want wake up every scan? */ if (devpriv->ai_flags & TRIG_WAKE_EOS) { @@ -1169,11 +1326,6 @@ static int Compute_and_setup_dma(struct comedi_device *dev) } else { /* short first DMA buffer to one scan */ dmalen0 = devpriv->ai_n_realscanlen << 1; - DPRINTK - ("21 dmalen0=%d ai_n_realscanlen=%d " - "useeoshandle=%d\n", - dmalen0, devpriv->ai_n_realscanlen, - devpriv->useeoshandle); if (devpriv->useeoshandle) dmalen0 += 2; if (dmalen0 < 4) { @@ -1197,11 +1349,6 @@ static int Compute_and_setup_dma(struct comedi_device *dev) } else { /* short second DMA buffer to one scan */ dmalen1 = devpriv->ai_n_realscanlen << 1; - DPRINTK - ("22 dmalen1=%d ai_n_realscanlen=%d " - "useeoshandle=%d\n", - dmalen1, devpriv->ai_n_realscanlen, - devpriv->useeoshandle); if (devpriv->useeoshandle) dmalen1 -= 2; if (dmalen1 < 4) { @@ -1214,7 +1361,6 @@ static int Compute_and_setup_dma(struct comedi_device *dev) } } - DPRINTK("3 dmalen0=%d dmalen1=%d\n", dmalen0, dmalen1); /* transfer without TRIG_WAKE_EOS */ if (!(devpriv->ai_flags & TRIG_WAKE_EOS)) { /* if it's possible then align DMA buffers to length of scan */ @@ -1241,15 +1387,9 @@ static int Compute_and_setup_dma(struct comedi_device *dev) if (dmalen0 > ((devpriv->ai_n_realscanlen << 1) * devpriv->ai_scans)) { - DPRINTK - ("3.0 ai_n_realscanlen=%d ai_scans=%d\n", - devpriv->ai_n_realscanlen, - devpriv->ai_scans); dmalen0 = (devpriv->ai_n_realscanlen << 1) * devpriv->ai_scans; - DPRINTK("3.1 dmalen0=%d dmalen1=%d\n", dmalen0, - dmalen1); dmalen0 &= ~3L; } else { /* * fits whole measure into @@ -1261,21 +1401,16 @@ static int Compute_and_setup_dma(struct comedi_device *dev) dmalen1 = (devpriv->ai_n_realscanlen << 1) * devpriv->ai_scans - dmalen0; - DPRINTK("3.2 dmalen0=%d dmalen1=%d\n", dmalen0, - dmalen1); dmalen1 &= ~3L; } } } - DPRINTK("4 dmalen0=%d dmalen1=%d\n", dmalen0, dmalen1); - /* these DMA buffer size will be used */ devpriv->dma_actbuf = 0; devpriv->dmabuf_use_size[0] = dmalen0; devpriv->dmabuf_use_size[1] = dmalen1; - DPRINTK("5 dmalen0=%d dmalen1=%d\n", dmalen0, dmalen1); #if 0 if (devpriv->ai_n_scanlen < this_board->half_fifo_size) { devpriv->dmabuf_panic_size[0] = @@ -1308,18 +1443,14 @@ static int Compute_and_setup_dma(struct comedi_device *dev) devpriv->iobase_a + AMCC_OP_REG_INTCSR); /* allow bus mastering */ - DPRINTK("adl_pci9118 EDBG: END: Compute_and_setup_dma()\n"); return 0; } -/* -============================================================================== -*/ static int pci9118_ai_docmd_sampl(struct comedi_device *dev, struct comedi_subdevice *s) { - DPRINTK("adl_pci9118 EDBG: BGN: pci9118_ai_docmd_sampl(%d,) [%d]\n", - dev->minor, devpriv->ai_do); + struct pci9118_private *devpriv = dev->private; + switch (devpriv->ai_do) { case 1: devpriv->AdControlReg |= AdControl_TmrTr; @@ -1366,18 +1497,14 @@ static int pci9118_ai_docmd_sampl(struct comedi_device *dev, outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); } - DPRINTK("adl_pci9118 EDBG: END: pci9118_ai_docmd_sampl()\n"); return 0; } -/* -============================================================================== -*/ static int pci9118_ai_docmd_dma(struct comedi_device *dev, struct comedi_subdevice *s) { - DPRINTK("adl_pci9118 EDBG: BGN: pci9118_ai_docmd_dma(%d,) [%d,%d]\n", - dev->minor, devpriv->ai_do, devpriv->usedma); + struct pci9118_private *devpriv = dev->private; + Compute_and_setup_dma(dev); switch (devpriv->ai_do) { @@ -1440,20 +1567,17 @@ static int pci9118_ai_docmd_dma(struct comedi_device *dev, outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); } - DPRINTK("adl_pci9118 EDBG: BGN: pci9118_ai_docmd_dma()\n"); return 0; } -/* -============================================================================== -*/ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + const struct boardtype *this_board = comedi_board(dev); + struct pci9118_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; unsigned int addchans = 0; int ret = 0; - DPRINTK("adl_pci9118 EDBG: BGN: pci9118_ai_cmd(%d,)\n", dev->minor); devpriv->ai12_startstop = 0; devpriv->ai_flags = cmd->flags; devpriv->ai_n_chan = cmd->chanlist_len; @@ -1502,10 +1626,6 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->usessh = 0; /* no */ - DPRINTK("1 neverending=%d scans=%u usessh=%d ai_startstop=0x%2x\n", - devpriv->ai_neverending, devpriv->ai_scans, devpriv->usessh, - devpriv->ai12_startstop); - /* * use additional sample at end of every scan * to satisty DMA 32 bit transfer? @@ -1586,12 +1706,6 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->ai_add_back) * (devpriv->ai_n_scanlen / devpriv->ai_n_chan); - DPRINTK("2 usedma=%d realscan=%d af=%u n_chan=%d ab=%d n_scanlen=%d\n", - devpriv->usedma, - devpriv->ai_n_realscanlen, devpriv->ai_add_front, - devpriv->ai_n_chan, devpriv->ai_add_back, - devpriv->ai_n_scanlen); - /* check and setup channel list */ if (!check_channel_list(dev, s, devpriv->ai_n_chan, devpriv->ai_chanlist, devpriv->ai_add_front, @@ -1688,371 +1802,13 @@ static int pci9118_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) else ret = pci9118_ai_docmd_sampl(dev, s); - DPRINTK("adl_pci9118 EDBG: END: pci9118_ai_cmd()\n"); return ret; } -/* -============================================================================== -*/ -static int check_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, int n_chan, - unsigned int *chanlist, int frontadd, int backadd) -{ - unsigned int i, differencial = 0, bipolar = 0; - - /* correct channel and range number check itself comedi/range.c */ - if (n_chan < 1) { - comedi_error(dev, "range/channel list is empty!"); - return 0; - } - if ((frontadd + n_chan + backadd) > s->len_chanlist) { - printk - ("comedi%d: range/channel list is too long for " - "actual configuration (%d>%d)!", - dev->minor, n_chan, s->len_chanlist - frontadd - backadd); - return 0; - } - - if (CR_AREF(chanlist[0]) == AREF_DIFF) - differencial = 1; /* all input must be diff */ - if (CR_RANGE(chanlist[0]) < PCI9118_BIPOLAR_RANGES) - bipolar = 1; /* all input must be bipolar */ - if (n_chan > 1) - for (i = 1; i < n_chan; i++) { /* check S.E/diff */ - if ((CR_AREF(chanlist[i]) == AREF_DIFF) != - (differencial)) { - comedi_error(dev, - "Differencial and single ended " - "inputs can't be mixtured!"); - return 0; - } - if ((CR_RANGE(chanlist[i]) < PCI9118_BIPOLAR_RANGES) != - (bipolar)) { - comedi_error(dev, - "Bipolar and unipolar ranges " - "can't be mixtured!"); - return 0; - } - if (!devpriv->usemux && differencial && - (CR_CHAN(chanlist[i]) >= this_board->n_aichand)) { - comedi_error(dev, - "If AREF_DIFF is used then is " - "available only first 8 channels!"); - return 0; - } - } - - return 1; -} - -/* -============================================================================== -*/ -static int setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, int n_chan, - unsigned int *chanlist, int rot, int frontadd, - int backadd, int usedma, char useeos) -{ - unsigned int i, differencial = 0, bipolar = 0; - unsigned int scanquad, gain, ssh = 0x00; - - DPRINTK - ("adl_pci9118 EDBG: BGN: setup_channel_list" - "(%d,.,%d,.,%d,%d,%d,%d)\n", - dev->minor, n_chan, rot, frontadd, backadd, usedma); - - if (usedma == 1) { - rot = 8; - usedma = 0; - } - - if (CR_AREF(chanlist[0]) == AREF_DIFF) - differencial = 1; /* all input must be diff */ - if (CR_RANGE(chanlist[0]) < PCI9118_BIPOLAR_RANGES) - bipolar = 1; /* all input must be bipolar */ - - /* All is ok, so we can setup channel/range list */ - - if (!bipolar) { - devpriv->AdControlReg |= AdControl_UniP; - /* set unibipolar */ - } else { - devpriv->AdControlReg &= ((~AdControl_UniP) & 0xff); - /* enable bipolar */ - } - - if (differencial) { - devpriv->AdControlReg |= AdControl_Diff; - /* enable diff inputs */ - } else { - devpriv->AdControlReg &= ((~AdControl_Diff) & 0xff); - /* set single ended inputs */ - } - - outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); - /* setup mode */ - - outl(2, dev->iobase + PCI9118_SCANMOD); - /* gods know why this sequence! */ - outl(0, dev->iobase + PCI9118_SCANMOD); - outl(1, dev->iobase + PCI9118_SCANMOD); - -#ifdef PCI9118_PARANOIDCHECK - devpriv->chanlistlen = n_chan; - for (i = 0; i < (PCI9118_CHANLEN + 1); i++) - devpriv->chanlist[i] = 0x55aa; -#endif - - if (frontadd) { /* insert channels for S&H */ - ssh = devpriv->softsshsample; - DPRINTK("FA: %04x: ", ssh); - for (i = 0; i < frontadd; i++) { - /* store range list to card */ - scanquad = CR_CHAN(chanlist[0]); - /* get channel number; */ - gain = CR_RANGE(chanlist[0]); - /* get gain number */ - scanquad |= ((gain & 0x03) << 8); - outl(scanquad | ssh, dev->iobase + PCI9118_GAIN); - DPRINTK("%02x ", scanquad | ssh); - ssh = devpriv->softsshhold; - } - DPRINTK("\n "); - } - - DPRINTK("SL: ", ssh); - for (i = 0; i < n_chan; i++) { /* store range list to card */ - scanquad = CR_CHAN(chanlist[i]); /* get channel number */ -#ifdef PCI9118_PARANOIDCHECK - devpriv->chanlist[i ^ usedma] = (scanquad & 0xf) << rot; -#endif - gain = CR_RANGE(chanlist[i]); /* get gain number */ - scanquad |= ((gain & 0x03) << 8); - outl(scanquad | ssh, dev->iobase + PCI9118_GAIN); - DPRINTK("%02x ", scanquad | ssh); - } - DPRINTK("\n "); - - if (backadd) { /* insert channels for fit onto 32bit DMA */ - DPRINTK("BA: %04x: ", ssh); - for (i = 0; i < backadd; i++) { /* store range list to card */ - scanquad = CR_CHAN(chanlist[0]); - /* get channel number */ - gain = CR_RANGE(chanlist[0]); /* get gain number */ - scanquad |= ((gain & 0x03) << 8); - outl(scanquad | ssh, dev->iobase + PCI9118_GAIN); - DPRINTK("%02x ", scanquad | ssh); - } - DPRINTK("\n "); - } -#ifdef PCI9118_PARANOIDCHECK - devpriv->chanlist[n_chan ^ usedma] = devpriv->chanlist[0 ^ usedma]; - /* for 32bit operations */ - if (useeos) { - for (i = 1; i < n_chan; i++) { /* store range list to card */ - devpriv->chanlist[(n_chan + i) ^ usedma] = - (CR_CHAN(chanlist[i]) & 0xf) << rot; - } - devpriv->chanlist[(2 * n_chan) ^ usedma] = - devpriv->chanlist[0 ^ usedma]; - /* for 32bit operations */ - useeos = 2; - } else { - useeos = 1; - } -#ifdef PCI9118_EXTDEBUG - DPRINTK("CHL: "); - for (i = 0; i <= (useeos * n_chan); i++) - DPRINTK("%04x ", devpriv->chanlist[i]); - - DPRINTK("\n "); -#endif -#endif - outl(0, dev->iobase + PCI9118_SCANMOD); /* close scan queue */ - /* udelay(100); important delay, or first sample will be crippled */ - - DPRINTK("adl_pci9118 EDBG: END: setup_channel_list()\n"); - return 1; /* we can serve this with scan logic */ -} - -/* -============================================================================== - calculate 8254 divisors if they are used for dual timing -*/ -static void pci9118_calc_divisors(char mode, struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *tim1, unsigned int *tim2, - unsigned int flags, int chans, - unsigned int *div1, unsigned int *div2, - char usessh, unsigned int chnsshfront) -{ - DPRINTK - ("adl_pci9118 EDBG: BGN: pci9118_calc_divisors" - "(%d,%d,.,%u,%u,%u,%d,.,.,,%u,%u)\n", - mode, dev->minor, *tim1, *tim2, flags, chans, usessh, chnsshfront); - switch (mode) { - case 1: - case 4: - if (*tim2 < this_board->ai_ns_min) - *tim2 = this_board->ai_ns_min; - i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, div1, div2, - tim2, flags & TRIG_ROUND_NEAREST); - DPRINTK("OSC base=%u div1=%u div2=%u timer1=%u\n", - devpriv->i8254_osc_base, *div1, *div2, *tim1); - break; - case 2: - if (*tim2 < this_board->ai_ns_min) - *tim2 = this_board->ai_ns_min; - DPRINTK("1 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, - *tim1, *tim2); - *div1 = *tim2 / devpriv->i8254_osc_base; - /* convert timer (burst) */ - DPRINTK("2 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, - *tim1, *tim2); - if (*div1 < this_board->ai_pacer_min) - *div1 = this_board->ai_pacer_min; - DPRINTK("3 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, - *tim1, *tim2); - *div2 = *tim1 / devpriv->i8254_osc_base; /* scan timer */ - DPRINTK("4 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, - *tim1, *tim2); - *div2 = *div2 / *div1; /* major timer is c1*c2 */ - DPRINTK("5 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, - *tim1, *tim2); - if (*div2 < chans) - *div2 = chans; - DPRINTK("6 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, - *tim1, *tim2); - - *tim2 = *div1 * devpriv->i8254_osc_base; - /* real convert timer */ - - if (usessh & (chnsshfront == 0)) /* use BSSH signal */ - if (*div2 < (chans + 2)) - *div2 = chans + 2; - - DPRINTK("7 div1=%u div2=%u timer1=%u timer2=%u\n", *div1, *div2, - *tim1, *tim2); - *tim1 = *div1 * *div2 * devpriv->i8254_osc_base; - DPRINTK("OSC base=%u div1=%u div2=%u timer1=%u timer2=%u\n", - devpriv->i8254_osc_base, *div1, *div2, *tim1, *tim2); - break; - } - DPRINTK("adl_pci9118 EDBG: END: pci9118_calc_divisors(%u,%u)\n", - *div1, *div2); -} - -/* -============================================================================== -*/ -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2) -{ - outl(0x74, dev->iobase + PCI9118_CNTCTRL); - outl(0xb4, dev->iobase + PCI9118_CNTCTRL); -/* outl(0x30, dev->iobase + PCI9118_CNTCTRL); */ - udelay(1); - - if ((mode == 1) || (mode == 2) || (mode == 4)) { - outl(divisor2 & 0xff, dev->iobase + PCI9118_CNT2); - outl((divisor2 >> 8) & 0xff, dev->iobase + PCI9118_CNT2); - outl(divisor1 & 0xff, dev->iobase + PCI9118_CNT1); - outl((divisor1 >> 8) & 0xff, dev->iobase + PCI9118_CNT1); - } -} - -/* -============================================================================== -*/ -static int pci9118_exttrg_add(struct comedi_device *dev, unsigned char source) -{ - if (source > 3) - return -1; /* incorrect source */ - devpriv->exttrg_users |= (1 << source); - devpriv->IntControlReg |= Int_DTrg; - outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); - outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00, - devpriv->iobase_a + AMCC_OP_REG_INTCSR); - /* allow INT in AMCC */ - return 0; -} - -/* -============================================================================== -*/ -static int pci9118_exttrg_del(struct comedi_device *dev, unsigned char source) -{ - if (source > 3) - return -1; /* incorrect source */ - devpriv->exttrg_users &= ~(1 << source); - if (!devpriv->exttrg_users) { /* shutdown ext trg intterrupts */ - devpriv->IntControlReg &= ~Int_DTrg; - if (!devpriv->IntControlReg) /* all IRQ disabled */ - outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) & - (~0x00001f00), - devpriv->iobase_a + AMCC_OP_REG_INTCSR); - /* disable int in AMCC */ - outl(devpriv->IntControlReg, dev->iobase + PCI9118_INTCTRL); - } - return 0; -} - -/* -============================================================================== -*/ -static int pci9118_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - if (devpriv->usedma) - outl(inl(devpriv->iobase_a + AMCC_OP_REG_MCSR) & - (~EN_A2P_TRANSFERS), - devpriv->iobase_a + AMCC_OP_REG_MCSR); /* stop DMA */ - pci9118_exttrg_del(dev, EXTTRG_AI); - start_pacer(dev, 0, 0, 0); /* stop 8254 counters */ - devpriv->AdFunctionReg = AdFunction_PDTrg | AdFunction_PETrg; - outl(devpriv->AdFunctionReg, dev->iobase + PCI9118_ADFUNC); - /* - * positive triggers, no S&H, no burst, - * burst stop, no post trigger, - * no about trigger, trigger stop - */ - devpriv->AdControlReg = 0x00; - outl(devpriv->AdControlReg, dev->iobase + PCI9118_ADCNTRL); - /* - * bipolar, S.E., use 8254, stop 8354, - * internal trigger, soft trigger, - * disable INT and DMA - */ - outl(0, dev->iobase + PCI9118_BURST); - outl(1, dev->iobase + PCI9118_SCANMOD); - outl(2, dev->iobase + PCI9118_SCANMOD); /* reset scan queue */ - outl(0, dev->iobase + PCI9118_DELFIFO); /* flush FIFO */ - - devpriv->ai_do = 0; - devpriv->usedma = 0; - - devpriv->ai_act_scan = 0; - devpriv->ai_act_dmapos = 0; - s->async->cur_chan = 0; - s->async->inttrig = NULL; - devpriv->ai_buf_ptr = 0; - devpriv->ai_neverending = 0; - devpriv->dma_actbuf = 0; - - if (!devpriv->IntControlReg) - outl(inl(devpriv->iobase_a + AMCC_OP_REG_INTCSR) | 0x1f00, - devpriv->iobase_a + AMCC_OP_REG_INTCSR); - /* allow INT in AMCC */ - - return 0; -} - -/* -============================================================================== -*/ static int pci9118_reset(struct comedi_device *dev) { + struct pci9118_private *devpriv = dev->private; + devpriv->IntControlReg = 0; devpriv->exttrg_users = 0; inl(dev->iobase + PCI9118_INTCTRL); @@ -2112,6 +1868,7 @@ static int pci9118_reset(struct comedi_device *dev) static struct pci_dev *pci9118_find_pci(struct comedi_device *dev, struct comedi_devconfig *it) { + const struct boardtype *this_board = comedi_board(dev); struct pci_dev *pcidev = NULL; int bus = it->options[0]; int slot = it->options[1]; @@ -2150,6 +1907,8 @@ static struct pci_dev *pci9118_find_pci(struct comedi_device *dev, static int pci9118_attach(struct comedi_device *dev, struct comedi_devconfig *it) { + const struct boardtype *this_board = comedi_board(dev); + struct pci9118_private *devpriv; struct pci_dev *pcidev; struct comedi_subdevice *s; int ret, pages, i; @@ -2164,11 +1923,12 @@ static int pci9118_attach(struct comedi_device *dev, else master = 1; - ret = alloc_private(dev, sizeof(struct pci9118_private)); + ret = alloc_private(dev, sizeof(*devpriv)); if (ret < 0) { printk(" - Allocation failed!\n"); return -ENOMEM; } + devpriv = dev->private; pcidev = pci9118_find_pci(dev, it); if (!pcidev) @@ -2273,7 +2033,7 @@ static int pci9118_attach(struct comedi_device *dev, if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; dev->read_subdev = s; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF; @@ -2294,7 +2054,7 @@ static int pci9118_attach(struct comedi_device *dev, s->munge = pci9118_ai_munge; } - s = dev->subdevices + 1; + s = &dev->subdevices[1]; s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; s->n_chan = this_board->n_aochan; @@ -2304,7 +2064,7 @@ static int pci9118_attach(struct comedi_device *dev, s->insn_write = pci9118_insn_write_ao; s->insn_read = pci9118_insn_read_ao; - s = dev->subdevices + 2; + s = &dev->subdevices[2]; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; s->n_chan = 4; @@ -2314,7 +2074,7 @@ static int pci9118_attach(struct comedi_device *dev, s->io_bits = 0; /* all bits input */ s->insn_bits = pci9118_insn_bits_di; - s = dev->subdevices + 3; + s = &dev->subdevices[3]; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; s->n_chan = 4; @@ -2345,8 +2105,9 @@ static int pci9118_attach(struct comedi_device *dev, static void pci9118_detach(struct comedi_device *dev) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct pci9118_private *devpriv = dev->private; - if (dev->private) { + if (devpriv) { if (devpriv->valid) pci9118_reset(dev); if (dev->irq) diff --git a/drivers/staging/comedi/drivers/adq12b.c b/drivers/staging/comedi/drivers/adq12b.c index 6df51c8a602a..3a2aa5628be3 100644 --- a/drivers/staging/comedi/drivers/adq12b.c +++ b/drivers/staging/comedi/drivers/adq12b.c @@ -133,8 +133,6 @@ struct adq12b_private { unsigned int digital_state; }; -#define devpriv ((struct adq12b_private *)dev->private) - /* * "instructions" read/write data in "one-shot" or "software-triggered" * mode. @@ -144,6 +142,7 @@ static int adq12b_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct adq12b_private *devpriv = dev->private; int n, i; int range, channel; unsigned char hi, lo, status; @@ -200,6 +199,7 @@ static int adq12b_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct adq12b_private *devpriv = dev->private; int channel; for (channel = 0; channel < 8; channel++) @@ -221,6 +221,7 @@ static int adq12b_do_insn_bits(struct comedi_device *dev, static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct adq12b_board *board = comedi_board(dev); + struct adq12b_private *devpriv; struct comedi_subdevice *s; unsigned long iobase; int unipolar, differential; @@ -252,19 +253,18 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it) dev->board_name = board->name; -/* - * Allocate the private structure area. alloc_private() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_private(dev, sizeof(struct adq12b_private)) < 0) - return -ENOMEM; + ret = alloc_private(dev, sizeof(*devpriv)); + if (ret) + return ret; + devpriv = dev->private; -/* fill in devpriv structure */ devpriv->unipolar = unipolar; devpriv->differential = differential; devpriv->digital_state = 0; -/* initialize channel and range to -1 so we make sure we always write - at least once to the CTREG in the instruction */ + /* + * initialize channel and range to -1 so we make sure we + * always write at least once to the CTREG in the instruction + */ devpriv->last_channel = -1; devpriv->last_range = -1; @@ -272,7 +272,7 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* analog input subdevice */ s->type = COMEDI_SUBD_AI; if (differential) { @@ -294,7 +294,7 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it) the board can handle */ s->insn_read = adq12b_ai_rinsn; - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* digital input subdevice */ s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; @@ -303,7 +303,7 @@ static int adq12b_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->range_table = &range_digital; s->insn_bits = adq12b_di_insn_bits; - s = dev->subdevices + 2; + s = &dev->subdevices[2]; /* digital output subdevice */ s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE; @@ -321,7 +321,6 @@ static void adq12b_detach(struct comedi_device *dev) { if (dev->iobase) release_region(dev->iobase, ADQ12B_SIZE); - kfree(devpriv); } static const struct adq12b_board adq12b_boards[] = { diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c index 6b4d0d68e637..def37bcc2a66 100644 --- a/drivers/staging/comedi/drivers/adv_pci1710.c +++ b/drivers/staging/comedi/drivers/adv_pci1710.c @@ -45,6 +45,7 @@ Configuration options: #include "../comedidev.h" +#include "comedi_fc.h" #include "8253.h" #include "amcc_s5933.h" @@ -52,17 +53,6 @@ Configuration options: * correct channel number on every 12 bit * sample */ -#undef PCI171X_EXTDEBUG - -#define DRV_NAME "adv_pci1710" - -#undef DPRINTK -#ifdef PCI171X_EXTDEBUG -#define DPRINTK(fmt, args...) printk(fmt, ## args) -#else -#define DPRINTK(fmt, args...) -#endif - #define PCI_VENDOR_ID_ADVANTECH 0x13fe /* hardware types of the cards */ @@ -211,44 +201,101 @@ struct boardtype { }; static const struct boardtype boardtypes[] = { - {"pci1710", 0x1710, - IORANGE_171x, 1, TYPE_PCI171X, - 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff, - &range_pci1710_3, range_codes_pci1710_3, - &range_pci171x_da, - 10000, 2048}, - {"pci1710hg", 0x1710, - IORANGE_171x, 1, TYPE_PCI171X, - 16, 8, 2, 16, 16, 1, 0x0fff, 0x0fff, - &range_pci1710hg, range_codes_pci1710hg, - &range_pci171x_da, - 10000, 2048}, - {"pci1711", 0x1711, - IORANGE_171x, 1, TYPE_PCI171X, - 16, 0, 2, 16, 16, 1, 0x0fff, 0x0fff, - &range_pci17x1, range_codes_pci17x1, &range_pci171x_da, - 10000, 512}, - {"pci1713", 0x1713, - IORANGE_171x, 1, TYPE_PCI1713, - 32, 16, 0, 0, 0, 0, 0x0fff, 0x0000, - &range_pci1710_3, range_codes_pci1710_3, NULL, - 10000, 2048}, - {"pci1720", 0x1720, - IORANGE_1720, 0, TYPE_PCI1720, - 0, 0, 4, 0, 0, 0, 0x0000, 0x0fff, - NULL, NULL, &range_pci1720, - 0, 0}, - {"pci1731", 0x1731, - IORANGE_171x, 1, TYPE_PCI171X, - 16, 0, 0, 16, 16, 0, 0x0fff, 0x0000, - &range_pci17x1, range_codes_pci17x1, NULL, - 10000, 512}, - /* dummy entry corresponding to driver name */ - {.name = DRV_NAME}, + { + .name = "pci1710", + .device_id = 0x1710, + .iorange = IORANGE_171x, + .have_irq = 1, + .cardtype = TYPE_PCI171X, + .n_aichan = 16, + .n_aichand = 8, + .n_aochan = 2, + .n_dichan = 16, + .n_dochan = 16, + .n_counter = 1, + .ai_maxdata = 0x0fff, + .ao_maxdata = 0x0fff, + .rangelist_ai = &range_pci1710_3, + .rangecode_ai = range_codes_pci1710_3, + .rangelist_ao = &range_pci171x_da, + .ai_ns_min = 10000, + .fifo_half_size = 2048, + }, { + .name = "pci1710hg", + .device_id = 0x1710, + .iorange = IORANGE_171x, + .have_irq = 1, + .cardtype = TYPE_PCI171X, + .n_aichan = 16, + .n_aichand = 8, + .n_aochan = 2, + .n_dichan = 16, + .n_dochan = 16, + .n_counter = 1, + .ai_maxdata = 0x0fff, + .ao_maxdata = 0x0fff, + .rangelist_ai = &range_pci1710hg, + .rangecode_ai = range_codes_pci1710hg, + .rangelist_ao = &range_pci171x_da, + .ai_ns_min = 10000, + .fifo_half_size = 2048, + }, { + .name = "pci1711", + .device_id = 0x1711, + .iorange = IORANGE_171x, + .have_irq = 1, + .cardtype = TYPE_PCI171X, + .n_aichan = 16, + .n_aochan = 2, + .n_dichan = 16, + .n_dochan = 16, + .n_counter = 1, + .ai_maxdata = 0x0fff, + .ao_maxdata = 0x0fff, + .rangelist_ai = &range_pci17x1, + .rangecode_ai = range_codes_pci17x1, + .rangelist_ao = &range_pci171x_da, + .ai_ns_min = 10000, + .fifo_half_size = 512, + }, { + .name = "pci1713", + .device_id = 0x1713, + .iorange = IORANGE_171x, + .have_irq = 1, + .cardtype = TYPE_PCI1713, + .n_aichan = 32, + .n_aichand = 16, + .ai_maxdata = 0x0fff, + .rangelist_ai = &range_pci1710_3, + .rangecode_ai = range_codes_pci1710_3, + .ai_ns_min = 10000, + .fifo_half_size = 2048, + }, { + .name = "pci1720", + .device_id = 0x1720, + .iorange = IORANGE_1720, + .cardtype = TYPE_PCI1720, + .n_aochan = 4, + .ao_maxdata = 0x0fff, + .rangelist_ao = &range_pci1720, + }, { + .name = "pci1731", + .device_id = 0x1731, + .iorange = IORANGE_171x, + .have_irq = 1, + .cardtype = TYPE_PCI171X, + .n_aichan = 16, + .n_dichan = 16, + .n_dochan = 16, + .ai_maxdata = 0x0fff, + .rangelist_ai = &range_pci17x1, + .rangecode_ai = range_codes_pci17x1, + .ai_ns_min = 10000, + .fifo_half_size = 512, + }, }; struct pci1710_private { - char valid; /* card is usable */ char neverending_ai; /* we do unlimited AI */ unsigned int CntrlReg; /* Control register */ unsigned int i8254_osc_base; /* frequence of onboard oscilator */ @@ -278,33 +325,108 @@ struct pci1710_private { * internal state */ }; -#define devpriv ((struct pci1710_private *)dev->private) -#define this_board ((const struct boardtype *)dev->board_ptr) +/* used for gain list programming */ +static const unsigned int muxonechan[] = { + 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707, + 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f, + 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717, + 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f +}; /* ============================================================================== + Check if channel list from user is builded correctly + If it's ok, then program scan/gain logic. + This works for all cards. */ - static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan); + unsigned int *chanlist, unsigned int n_chan) +{ + unsigned int chansegment[32]; + unsigned int i, nowmustbechan, seglen, segpos; + + /* correct channel and range number check itself comedi/range.c */ + if (n_chan < 1) { + comedi_error(dev, "range/channel list is empty!"); + return 0; + } + + if (n_chan == 1) + return 1; /* seglen=1 */ + + chansegment[0] = chanlist[0]; /* first channel is every time ok */ + for (i = 1, seglen = 1; i < n_chan; i++, seglen++) { + if (chanlist[0] == chanlist[i]) + break; /* we detected a loop, stop */ + if ((CR_CHAN(chanlist[i]) & 1) && + (CR_AREF(chanlist[i]) == AREF_DIFF)) { + comedi_error(dev, "Odd channel cannot be differential input!\n"); + return 0; + } + nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan; + if (CR_AREF(chansegment[i - 1]) == AREF_DIFF) + nowmustbechan = (nowmustbechan + 1) % s->n_chan; + if (nowmustbechan != CR_CHAN(chanlist[i])) { + printk("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n", + i, CR_CHAN(chanlist[i]), nowmustbechan, + CR_CHAN(chanlist[0])); + return 0; + } + chansegment[i] = chanlist[i]; /* next correct channel in list */ + } + + for (i = 0, segpos = 0; i < n_chan; i++) { + if (chanlist[i] != chansegment[i % seglen]) { + printk("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", + i, CR_CHAN(chansegment[i]), + CR_RANGE(chansegment[i]), + CR_AREF(chansegment[i]), + CR_CHAN(chanlist[i % seglen]), + CR_RANGE(chanlist[i % seglen]), + CR_AREF(chansegment[i % seglen])); + return 0; + } + } + return seglen; +} + static void setup_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, unsigned int n_chan, - unsigned int seglen); -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2); -static int pci1710_reset(struct comedi_device *dev); -static int pci171x_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s); + unsigned int seglen) +{ + const struct boardtype *this_board = comedi_board(dev); + struct pci1710_private *devpriv = dev->private; + unsigned int i, range, chanprog; -/* used for gain list programming */ -static const unsigned int muxonechan[] = { - 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707, - 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f, - 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717, - 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f -}; + devpriv->act_chanlist_len = seglen; + devpriv->act_chanlist_pos = 0; + + for (i = 0; i < seglen; i++) { /* store range list to card */ + chanprog = muxonechan[CR_CHAN(chanlist[i])]; + outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */ + range = this_board->rangecode_ai[CR_RANGE(chanlist[i])]; + if (CR_AREF(chanlist[i]) == AREF_DIFF) + range |= 0x0020; + outw(range, dev->iobase + PCI171x_RANGE); /* select gain */ +#ifdef PCI171x_PARANOIDCHECK + devpriv->act_chanlist[i] = + (CR_CHAN(chanlist[i]) << 12) & 0xf000; +#endif + } +#ifdef PCI171x_PARANOIDCHECK + for ( ; i < n_chan; i++) { /* store remainder of channel list */ + devpriv->act_chanlist[i] = + (CR_CHAN(chanlist[i]) << 12) & 0xf000; + } +#endif + + devpriv->ai_et_MuxVal = + CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8); + /* select channel interval to scan */ + outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); +} /* ============================================================================== @@ -313,12 +435,13 @@ static int pci171x_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct pci1710_private *devpriv = dev->private; int n, timeout; #ifdef PCI171x_PARANOIDCHECK + const struct boardtype *this_board = comedi_board(dev); unsigned int idata; #endif - DPRINTK("adv_pci1710 EDBG: BGN: pci171x_insn_read_ai(...)\n"); devpriv->CntrlReg &= Control_CNT0; devpriv->CntrlReg |= Control_SW; /* set software trigger */ outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); @@ -327,32 +450,18 @@ static int pci171x_insn_read_ai(struct comedi_device *dev, setup_channel_list(dev, s, &insn->chanspec, 1, 1); - DPRINTK("adv_pci1710 A ST=%4x IO=%x\n", - inw(dev->iobase + PCI171x_STATUS), - dev->iobase + PCI171x_STATUS); for (n = 0; n < insn->n; n++) { outw(0, dev->iobase + PCI171x_SOFTTRG); /* start conversion */ - DPRINTK("adv_pci1710 B n=%d ST=%4x\n", n, - inw(dev->iobase + PCI171x_STATUS)); /* udelay(1); */ - DPRINTK("adv_pci1710 C n=%d ST=%4x\n", n, - inw(dev->iobase + PCI171x_STATUS)); timeout = 100; while (timeout--) { if (!(inw(dev->iobase + PCI171x_STATUS) & Status_FE)) goto conv_finish; - if (!(timeout % 10)) - DPRINTK("adv_pci1710 D n=%d tm=%d ST=%4x\n", n, - timeout, - inw(dev->iobase + PCI171x_STATUS)); } comedi_error(dev, "A/D insn timeout"); outb(0, dev->iobase + PCI171x_CLRFIFO); outb(0, dev->iobase + PCI171x_CLRINT); data[n] = 0; - DPRINTK - ("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n", - n); return -ETIME; conv_finish: @@ -373,7 +482,6 @@ conv_finish: outb(0, dev->iobase + PCI171x_CLRFIFO); outb(0, dev->iobase + PCI171x_CLRINT); - DPRINTK("adv_pci1710 EDBG: END: pci171x_insn_read_ai(...) n=%d\n", n); return n; } @@ -384,6 +492,7 @@ static int pci171x_insn_write_ao(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct pci1710_private *devpriv = dev->private; int n, chan, range, ofs; chan = CR_CHAN(insn->chanspec); @@ -416,6 +525,7 @@ static int pci171x_insn_read_ao(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct pci1710_private *devpriv = dev->private; int n, chan; chan = CR_CHAN(insn->chanspec); @@ -457,6 +567,23 @@ static int pci171x_insn_bits_do(struct comedi_device *dev, /* ============================================================================== */ +static void start_pacer(struct comedi_device *dev, int mode, + unsigned int divisor1, unsigned int divisor2) +{ + outw(0xb4, dev->iobase + PCI171x_CNTCTRL); + outw(0x74, dev->iobase + PCI171x_CNTCTRL); + + if (mode == 1) { + outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2); + outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2); + outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1); + outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1); + } +} + +/* +============================================================================== +*/ static int pci171x_insn_counter_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -486,6 +613,7 @@ static int pci171x_insn_counter_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { + struct pci1710_private *devpriv = dev->private; uint msb, lsb, ccntrl, status; lsb = data[0] & 0x00FF; @@ -517,6 +645,7 @@ static int pci171x_insn_counter_config(struct comedi_device *dev, { #ifdef unused /* This doesn't work like a normal Comedi counter config */ + struct pci1710_private *devpriv = dev->private; uint ccntrl = 0; devpriv->cnt0_write_wait = data[0] & 0x20; @@ -552,6 +681,7 @@ static int pci1720_insn_write_ao(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct pci1710_private *devpriv = dev->private; int n, rangereg, chan; chan = CR_CHAN(insn->chanspec); @@ -575,16 +705,47 @@ static int pci1720_insn_write_ao(struct comedi_device *dev, /* ============================================================================== */ +static int pci171x_ai_cancel(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + const struct boardtype *this_board = comedi_board(dev); + struct pci1710_private *devpriv = dev->private; + + switch (this_board->cardtype) { + default: + devpriv->CntrlReg &= Control_CNT0; + devpriv->CntrlReg |= Control_SW; + + outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */ + start_pacer(dev, -1, 0, 0); + outb(0, dev->iobase + PCI171x_CLRFIFO); + outb(0, dev->iobase + PCI171x_CLRINT); + break; + } + + devpriv->ai_do = 0; + devpriv->ai_act_scan = 0; + s->async->cur_chan = 0; + devpriv->ai_buf_ptr = 0; + devpriv->neverending_ai = 0; + + return 0; +} + +/* +============================================================================== +*/ static void interrupt_pci1710_every_sample(void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; + struct pci1710_private *devpriv = dev->private; + struct comedi_subdevice *s = &dev->subdevices[0]; int m; #ifdef PCI171x_PARANOIDCHECK + const struct boardtype *this_board = comedi_board(dev); short sampl; #endif - DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_every_sample(...)\n"); m = inw(dev->iobase + PCI171x_STATUS); if (m & Status_FE) { printk("comedi%d: A/D FIFO empty (%4x)\n", dev->minor, m); @@ -605,11 +766,9 @@ static void interrupt_pci1710_every_sample(void *d) outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ - DPRINTK("FOR "); for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) { #ifdef PCI171x_PARANOIDCHECK sampl = inw(dev->iobase + PCI171x_AD_DATA); - DPRINTK("%04x:", sampl); if (this_board->cardtype != TYPE_PCI1713) if ((sampl & 0xf000) != devpriv->act_chanlist[s->async->cur_chan]) { @@ -626,8 +785,6 @@ static void interrupt_pci1710_every_sample(void *d) comedi_event(dev, s); return; } - DPRINTK("%8d %2d %8d~", s->async->buf_int_ptr, - s->async->cur_chan, s->async->buf_int_count); comedi_buf_put(s->async, sampl & 0x0fff); #else comedi_buf_put(s->async, @@ -641,11 +798,6 @@ static void interrupt_pci1710_every_sample(void *d) if (s->async->cur_chan == 0) { /* one scan done */ devpriv->ai_act_scan++; - DPRINTK - ("adv_pci1710 EDBG: EOS1 bic %d bip %d buc %d bup %d\n", - s->async->buf_int_count, s->async->buf_int_ptr, - s->async->buf_user_count, s->async->buf_user_ptr); - DPRINTK("adv_pci1710 EDBG: EOS2\n"); if ((!devpriv->neverending_ai) && (devpriv->ai_act_scan >= devpriv->ai_scans)) { /* all data sampled */ @@ -658,7 +810,6 @@ static void interrupt_pci1710_every_sample(void *d) } outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ - DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_every_sample(...)\n"); comedi_event(dev, s); } @@ -669,12 +820,13 @@ static void interrupt_pci1710_every_sample(void *d) static int move_block_from_fifo(struct comedi_device *dev, struct comedi_subdevice *s, int n, int turn) { + struct pci1710_private *devpriv = dev->private; int i, j; #ifdef PCI171x_PARANOIDCHECK + const struct boardtype *this_board = comedi_board(dev); int sampl; #endif - DPRINTK("adv_pci1710 EDBG: BGN: move_block_from_fifo(...,%d,%d)\n", n, - turn); + j = s->async->cur_chan; for (i = 0; i < n; i++) { #ifdef PCI171x_PARANOIDCHECK @@ -705,7 +857,6 @@ static int move_block_from_fifo(struct comedi_device *dev, } } s->async->cur_chan = j; - DPRINTK("adv_pci1710 EDBG: END: move_block_from_fifo(...)\n"); return 0; } @@ -715,10 +866,11 @@ static int move_block_from_fifo(struct comedi_device *dev, static void interrupt_pci1710_half_fifo(void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; + const struct boardtype *this_board = comedi_board(dev); + struct pci1710_private *devpriv = dev->private; + struct comedi_subdevice *s = &dev->subdevices[0]; int m, samplesinbuf; - DPRINTK("adv_pci1710 EDBG: BGN: interrupt_pci1710_half_fifo(...)\n"); m = inw(dev->iobase + PCI171x_STATUS); if (!(m & Status_FH)) { printk("comedi%d: A/D FIFO not half full! (%4x)\n", @@ -760,7 +912,6 @@ static void interrupt_pci1710_half_fifo(void *d) return; } outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */ - DPRINTK("adv_pci1710 EDBG: END: interrupt_pci1710_half_fifo(...)\n"); comedi_event(dev, s); } @@ -771,18 +922,14 @@ static void interrupt_pci1710_half_fifo(void *d) static irqreturn_t interrupt_service_pci1710(int irq, void *d) { struct comedi_device *dev = d; + struct pci1710_private *devpriv = dev->private; - DPRINTK("adv_pci1710 EDBG: BGN: interrupt_service_pci1710(%d,...)\n", - irq); if (!dev->attached) /* is device attached? */ return IRQ_NONE; /* no, exit */ /* is this interrupt from our board? */ if (!(inw(dev->iobase + PCI171x_STATUS) & Status_IRQ)) return IRQ_NONE; /* no, exit */ - DPRINTK("adv_pci1710 EDBG: interrupt_service_pci1710() ST: %4x\n", - inw(dev->iobase + PCI171x_STATUS)); - if (devpriv->ai_et) { /* Switch from initial TRIG_EXT to TRIG_xxx. */ devpriv->ai_et = 0; devpriv->CntrlReg &= Control_CNT0; @@ -802,7 +949,6 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d) } else { interrupt_pci1710_half_fifo(d); } - DPRINTK("adv_pci1710 EDBG: END: interrupt_service_pci1710(...)\n"); return IRQ_HANDLED; } @@ -812,11 +958,11 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d) static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev, struct comedi_subdevice *s) { + const struct boardtype *this_board = comedi_board(dev); + struct pci1710_private *devpriv = dev->private; unsigned int divisor1 = 0, divisor2 = 0; unsigned int seglen; - DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_docmd_and_mode(%d,...)\n", - mode); start_pacer(dev, -1, 0, 0); /* stop pacer */ seglen = check_channel_list(dev, s, devpriv->ai_chanlist, @@ -869,10 +1015,6 @@ static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev, i8253_cascade_ns_to_timer(devpriv->i8254_osc_base, &divisor1, &divisor2, &devpriv->ai_timer1, devpriv->ai_flags & TRIG_ROUND_MASK); - DPRINTK - ("adv_pci1710 EDBG: OSC base=%u div1=%u div2=%u timer=%u\n", - devpriv->i8254_osc_base, divisor1, divisor2, - devpriv->ai_timer1); outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); if (mode != 2) { /* start pacer */ @@ -888,27 +1030,9 @@ static int pci171x_ai_docmd_and_mode(int mode, struct comedi_device *dev, break; } - DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_docmd_and_mode(...)\n"); return 0; } -#ifdef PCI171X_EXTDEBUG -/* -============================================================================== -*/ -static void pci171x_cmdtest_out(int e, struct comedi_cmd *cmd) -{ - printk("adv_pci1710 e=%d startsrc=%x scansrc=%x convsrc=%x\n", e, - cmd->start_src, cmd->scan_begin_src, cmd->convert_src); - printk("adv_pci1710 e=%d startarg=%d scanarg=%d convarg=%d\n", e, - cmd->start_arg, cmd->scan_begin_arg, cmd->convert_arg); - printk("adv_pci1710 e=%d stopsrc=%x scanend=%x\n", e, cmd->stop_src, - cmd->scan_end_src); - printk("adv_pci1710 e=%d stoparg=%d scanendarg=%d chanlistlen=%d\n", - e, cmd->stop_arg, cmd->scan_end_arg, cmd->chanlist_len); -} -#endif - /* ============================================================================== */ @@ -916,83 +1040,33 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { + const struct boardtype *this_board = comedi_board(dev); + struct pci1710_private *devpriv = dev->private; int err = 0; int tmp; unsigned int divisor1 = 0, divisor2 = 0; - DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...)\n"); -#ifdef PCI171X_EXTDEBUG - pci171x_cmdtest_out(-1, cmd); -#endif - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_FOLLOW; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; - - if (err) { -#ifdef PCI171X_EXTDEBUG - pci171x_cmdtest_out(1, cmd); -#endif - DPRINTK( - "adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=1\n", - err); + if (err) return 1; - } - - /* step2: make sure trigger srcs are unique and mutually compatible */ - - if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) { - cmd->start_src = TRIG_NOW; - err++; - } - if (cmd->scan_begin_src != TRIG_FOLLOW) { - cmd->scan_begin_src = TRIG_FOLLOW; - err++; - } + /* step 2a: make sure trigger sources are unique */ - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); - if (cmd->scan_end_src != TRIG_COUNT) { - cmd->scan_end_src = TRIG_COUNT; - err++; - } - - if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT) - err++; + /* step 2b: and mutually compatible */ - if (err) { -#ifdef PCI171X_EXTDEBUG - pci171x_cmdtest_out(2, cmd); -#endif - DPRINTK( - "adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=2\n", - err); + if (err) return 2; - } /* step 3: make sure arguments are trivially compatible */ @@ -1034,15 +1108,8 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev, } } - if (err) { -#ifdef PCI171X_EXTDEBUG - pci171x_cmdtest_out(3, cmd); -#endif - DPRINTK( - "adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=3\n", - err); + if (err) return 3; - } /* step 4: fix up any arguments */ @@ -1057,12 +1124,8 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev, err++; } - if (err) { - DPRINTK - ("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) err=%d ret=4\n", - err); + if (err) return 4; - } /* step 5: complain about special chanlist considerations */ @@ -1072,7 +1135,6 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev, return 5; /* incorrect channels list */ } - DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmdtest(...) ret=0\n"); return 0; } @@ -1081,9 +1143,9 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev, */ static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct pci1710_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; - DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cmd(...)\n"); devpriv->ai_n_chan = cmd->chanlist_len; devpriv->ai_chanlist = cmd->chanlist; devpriv->ai_flags = cmd->flags; @@ -1115,162 +1177,12 @@ static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* ============================================================================== - Check if channel list from user is builded correctly - If it's ok, then program scan/gain logic. - This works for all cards. -*/ -static int check_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan) -{ - unsigned int chansegment[32]; - unsigned int i, nowmustbechan, seglen, segpos; - - DPRINTK("adv_pci1710 EDBG: check_channel_list(...,%d)\n", n_chan); - /* correct channel and range number check itself comedi/range.c */ - if (n_chan < 1) { - comedi_error(dev, "range/channel list is empty!"); - return 0; - } - - if (n_chan == 1) - return 1; /* seglen=1 */ - - chansegment[0] = chanlist[0]; /* first channel is every time ok */ - for (i = 1, seglen = 1; i < n_chan; i++, seglen++) { - if (chanlist[0] == chanlist[i]) - break; /* we detected a loop, stop */ - if ((CR_CHAN(chanlist[i]) & 1) && - (CR_AREF(chanlist[i]) == AREF_DIFF)) { - comedi_error(dev, "Odd channel cannot be differential input!\n"); - return 0; - } - nowmustbechan = (CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan; - if (CR_AREF(chansegment[i - 1]) == AREF_DIFF) - nowmustbechan = (nowmustbechan + 1) % s->n_chan; - if (nowmustbechan != CR_CHAN(chanlist[i])) { - printk("channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n", - i, CR_CHAN(chanlist[i]), nowmustbechan, - CR_CHAN(chanlist[0])); - return 0; - } - chansegment[i] = chanlist[i]; /* next correct channel in list */ - } - - for (i = 0, segpos = 0; i < n_chan; i++) { - if (chanlist[i] != chansegment[i % seglen]) { - printk("bad channel, reference or range number! chanlist[%i]=%d,%d,%d and not %d,%d,%d!\n", - i, CR_CHAN(chansegment[i]), - CR_RANGE(chansegment[i]), - CR_AREF(chansegment[i]), - CR_CHAN(chanlist[i % seglen]), - CR_RANGE(chanlist[i % seglen]), - CR_AREF(chansegment[i % seglen])); - return 0; - } - } - return seglen; -} - -static void setup_channel_list(struct comedi_device *dev, - struct comedi_subdevice *s, - unsigned int *chanlist, unsigned int n_chan, - unsigned int seglen) -{ - unsigned int i, range, chanprog; - - DPRINTK("adv_pci1710 EDBG: setup_channel_list(...,%d,%d)\n", n_chan, - seglen); - devpriv->act_chanlist_len = seglen; - devpriv->act_chanlist_pos = 0; - - DPRINTK("SegLen: %d\n", seglen); - for (i = 0; i < seglen; i++) { /* store range list to card */ - chanprog = muxonechan[CR_CHAN(chanlist[i])]; - outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */ - range = this_board->rangecode_ai[CR_RANGE(chanlist[i])]; - if (CR_AREF(chanlist[i]) == AREF_DIFF) - range |= 0x0020; - outw(range, dev->iobase + PCI171x_RANGE); /* select gain */ -#ifdef PCI171x_PARANOIDCHECK - devpriv->act_chanlist[i] = - (CR_CHAN(chanlist[i]) << 12) & 0xf000; -#endif - DPRINTK("GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range, - devpriv->act_chanlist[i]); - } -#ifdef PCI171x_PARANOIDCHECK - for ( ; i < n_chan; i++) { /* store remainder of channel list */ - devpriv->act_chanlist[i] = - (CR_CHAN(chanlist[i]) << 12) & 0xf000; - } -#endif - - devpriv->ai_et_MuxVal = - CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8); - /* select channel interval to scan */ - outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX); - DPRINTK("MUX: %4x L%4x.H%4x\n", - CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8), - CR_CHAN(chanlist[0]), CR_CHAN(chanlist[seglen - 1])); -} - -/* -============================================================================== -*/ -static void start_pacer(struct comedi_device *dev, int mode, - unsigned int divisor1, unsigned int divisor2) -{ - DPRINTK("adv_pci1710 EDBG: BGN: start_pacer(%d,%u,%u)\n", mode, - divisor1, divisor2); - outw(0xb4, dev->iobase + PCI171x_CNTCTRL); - outw(0x74, dev->iobase + PCI171x_CNTCTRL); - - if (mode == 1) { - outw(divisor2 & 0xff, dev->iobase + PCI171x_CNT2); - outw((divisor2 >> 8) & 0xff, dev->iobase + PCI171x_CNT2); - outw(divisor1 & 0xff, dev->iobase + PCI171x_CNT1); - outw((divisor1 >> 8) & 0xff, dev->iobase + PCI171x_CNT1); - } - DPRINTK("adv_pci1710 EDBG: END: start_pacer(...)\n"); -} - -/* -============================================================================== -*/ -static int pci171x_ai_cancel(struct comedi_device *dev, - struct comedi_subdevice *s) -{ - DPRINTK("adv_pci1710 EDBG: BGN: pci171x_ai_cancel(...)\n"); - - switch (this_board->cardtype) { - default: - devpriv->CntrlReg &= Control_CNT0; - devpriv->CntrlReg |= Control_SW; - - outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */ - start_pacer(dev, -1, 0, 0); - outb(0, dev->iobase + PCI171x_CLRFIFO); - outb(0, dev->iobase + PCI171x_CLRINT); - break; - } - - devpriv->ai_do = 0; - devpriv->ai_act_scan = 0; - s->async->cur_chan = 0; - devpriv->ai_buf_ptr = 0; - devpriv->neverending_ai = 0; - - DPRINTK("adv_pci1710 EDBG: END: pci171x_ai_cancel(...)\n"); - return 0; -} - -/* -============================================================================== */ static int pci171x_reset(struct comedi_device *dev) { - DPRINTK("adv_pci1710 EDBG: BGN: pci171x_reset(...)\n"); + const struct boardtype *this_board = comedi_board(dev); + struct pci1710_private *devpriv = dev->private; + outw(0x30, dev->iobase + PCI171x_CNTCTRL); devpriv->CntrlReg = Control_SW | Control_CNT0; /* Software trigger, CNT0=external */ outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL); /* reset any operations */ @@ -1291,7 +1203,6 @@ static int pci171x_reset(struct comedi_device *dev) outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */ outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */ - DPRINTK("adv_pci1710 EDBG: END: pci171x_reset(...)\n"); return 0; } @@ -1300,7 +1211,8 @@ static int pci171x_reset(struct comedi_device *dev) */ static int pci1720_reset(struct comedi_device *dev) { - DPRINTK("adv_pci1710 EDBG: BGN: pci1720_reset(...)\n"); + struct pci1710_private *devpriv = dev->private; + outb(Syncont_SC0, dev->iobase + PCI1720_SYNCONT); /* set synchronous output mode */ devpriv->da_ranges = 0xAA; outb(devpriv->da_ranges, dev->iobase + PCI1720_RANGE); /* set all ranges to +/-5V */ @@ -1313,7 +1225,6 @@ static int pci1720_reset(struct comedi_device *dev) devpriv->ao_data[1] = 0x0800; devpriv->ao_data[2] = 0x0800; devpriv->ao_data[3] = 0x0800; - DPRINTK("adv_pci1710 EDBG: END: pci1720_reset(...)\n"); return 0; } @@ -1322,82 +1233,55 @@ static int pci1720_reset(struct comedi_device *dev) */ static int pci1710_reset(struct comedi_device *dev) { - DPRINTK("adv_pci1710 EDBG: BGN: pci1710_reset(...)\n"); + const struct boardtype *this_board = comedi_board(dev); + switch (this_board->cardtype) { case TYPE_PCI1720: return pci1720_reset(dev); default: return pci171x_reset(dev); } - DPRINTK("adv_pci1710 EDBG: END: pci1710_reset(...)\n"); } -static struct pci_dev *pci1710_find_pci_dev(struct comedi_device *dev, - struct comedi_devconfig *it) +static const void *pci1710_find_boardinfo(struct comedi_device *dev, + struct pci_dev *pcidev) { - struct pci_dev *pcidev = NULL; - int bus = it->options[0]; - int slot = it->options[1]; - int board_index = this_board - boardtypes; + const struct boardtype *this_board; int i; - for_each_pci_dev(pcidev) { - if (bus || slot) { - if (bus != pcidev->bus->number || - slot != PCI_SLOT(pcidev->devfn)) - continue; - } - if (pcidev->vendor != PCI_VENDOR_ID_ADVANTECH) - continue; - if (strcmp(this_board->name, DRV_NAME) == 0) { - for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) { - if (pcidev->device == boardtypes[i].device_id) { - board_index = i; - break; - } - } - if (i == ARRAY_SIZE(boardtypes)) - continue; - } else { - if (pcidev->device != boardtypes[board_index].device_id) - continue; - } - dev->board_ptr = &boardtypes[board_index]; - return pcidev; + for (i = 0; i < ARRAY_SIZE(boardtypes); i++) { + this_board = &boardtypes[i]; + if (pcidev->device == this_board->device_id) + return this_board; } - dev_err(dev->class_dev, - "No supported board found! (req. bus %d, slot %d)\n", - bus, slot); return NULL; } -static int pci1710_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int pci1710_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) { - struct pci_dev *pcidev; + const struct boardtype *this_board; + struct pci1710_private *devpriv; struct comedi_subdevice *s; int ret, subdev, n_subdevices; - unsigned int irq; - dev_info(dev->class_dev, DRV_NAME ": attach\n"); + comedi_set_hw_dev(dev, &pcidev->dev); - ret = alloc_private(dev, sizeof(struct pci1710_private)); - if (ret < 0) - return -ENOMEM; + this_board = pci1710_find_boardinfo(dev, pcidev); + if (!this_board) + return -ENODEV; + dev->board_ptr = this_board; + dev->board_name = this_board->name; - pcidev = pci1710_find_pci_dev(dev, it); - if (!pcidev) - return -EIO; - comedi_set_hw_dev(dev, &pcidev->dev); + ret = alloc_private(dev, sizeof(*devpriv)); + if (ret < 0) + return ret; + devpriv = dev->private; - ret = comedi_pci_enable(pcidev, DRV_NAME); + ret = comedi_pci_enable(pcidev, dev->board_name); if (ret) return ret; - dev->iobase = pci_resource_start(pcidev, 2); - irq = pcidev->irq; - - dev->board_name = this_board->name; n_subdevices = 0; if (this_board->n_aichan) @@ -1417,30 +1301,17 @@ static int pci1710_attach(struct comedi_device *dev, pci1710_reset(dev); - if (this_board->have_irq) { - if (irq) { - if (request_irq(irq, interrupt_service_pci1710, - IRQF_SHARED, "Advantech PCI-1710", - dev)) { - dev_dbg(dev->class_dev, - "unable to allocate IRQ %d, DISABLING IT", - irq); - irq = 0; /* Can't use IRQ */ - } else { - dev_dbg(dev->class_dev, "irq=%u", irq); - } - } else { - dev_dbg(dev->class_dev, "IRQ disabled"); - } - } else { - irq = 0; + if (this_board->have_irq && pcidev->irq) { + ret = request_irq(pcidev->irq, interrupt_service_pci1710, + IRQF_SHARED, dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; } - dev->irq = irq; subdev = 0; if (this_board->n_aichan) { - s = dev->subdevices + subdev; + s = &dev->subdevices[subdev]; dev->read_subdev = s; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND; @@ -1452,7 +1323,7 @@ static int pci1710_attach(struct comedi_device *dev, s->range_table = this_board->rangelist_ai; s->cancel = pci171x_ai_cancel; s->insn_read = pci171x_insn_read_ai; - if (irq) { + if (dev->irq) { s->subdev_flags |= SDF_CMD_READ; s->do_cmdtest = pci171x_ai_cmdtest; s->do_cmd = pci171x_ai_cmd; @@ -1462,7 +1333,7 @@ static int pci1710_attach(struct comedi_device *dev, } if (this_board->n_aochan) { - s = dev->subdevices + subdev; + s = &dev->subdevices[subdev]; s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; s->n_chan = this_board->n_aochan; @@ -1482,7 +1353,7 @@ static int pci1710_attach(struct comedi_device *dev, } if (this_board->n_dichan) { - s = dev->subdevices + subdev; + s = &dev->subdevices[subdev]; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; s->n_chan = this_board->n_dichan; @@ -1495,7 +1366,7 @@ static int pci1710_attach(struct comedi_device *dev, } if (this_board->n_dochan) { - s = dev->subdevices + subdev; + s = &dev->subdevices[subdev]; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; s->n_chan = this_board->n_dochan; @@ -1510,7 +1381,7 @@ static int pci1710_attach(struct comedi_device *dev, } if (this_board->n_counter) { - s = dev->subdevices + subdev; + s = &dev->subdevices[subdev]; s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = this_board->n_counter; @@ -1523,7 +1394,8 @@ static int pci1710_attach(struct comedi_device *dev, subdev++; } - devpriv->valid = 1; + dev_info(dev->class_dev, "%s attached, irq %sabled\n", + dev->board_name, dev->irq ? "en" : "dis"); return 0; } @@ -1532,27 +1404,21 @@ static void pci1710_detach(struct comedi_device *dev) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); - if (dev->private) { - if (devpriv->valid) - pci1710_reset(dev); - if (dev->irq) - free_irq(dev->irq, dev); - } + if (dev->iobase) + pci1710_reset(dev); + if (dev->irq) + free_irq(dev->irq, dev); if (pcidev) { if (dev->iobase) comedi_pci_disable(pcidev); - pci_dev_put(pcidev); } } static struct comedi_driver adv_pci1710_driver = { .driver_name = "adv_pci1710", .module = THIS_MODULE, - .attach = pci1710_attach, + .attach_pci = pci1710_attach_pci, .detach = pci1710_detach, - .num_names = ARRAY_SIZE(boardtypes), - .board_name = &boardtypes[0].name, - .offset = sizeof(struct boardtype), }; static int __devinit adv_pci1710_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c index dfde0f6328dd..df4efc0606de 100644 --- a/drivers/staging/comedi/drivers/adv_pci1723.c +++ b/drivers/staging/comedi/drivers/adv_pci1723.c @@ -52,11 +52,6 @@ TODO: #define PCI_VENDOR_ID_ADVANTECH 0x13fe /* Advantech PCI vendor ID */ -/* hardware types of the cards */ -#define TYPE_PCI1723 0 - -#define IORANGE_1723 0x2A - /* all the registers for the pci1723 board */ #define PCI1723_DA(N) ((N)<<1) /* W: D/A register N (0 to 7) */ @@ -112,63 +107,18 @@ TODO: #define PCI1723_SELECT_CALIBRATION 0x28 /* Select the calibration Ref_V */ -/* static unsigned short pci_list_builded=0; =1 list of card is know */ - -static const struct comedi_lrange range_pci1723 = { 1, { - BIP_RANGE(10) - } -}; - -/* - * Board descriptions for pci1723 boards. - */ -struct pci1723_board { - const char *name; - int vendor_id; /* PCI vendor a device ID of card */ - int device_id; - int iorange; - char cardtype; - int n_aochan; /* num of D/A chans */ - int n_diochan; /* num of DIO chans */ - int ao_maxdata; /* resolution of D/A */ - const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */ -}; - -static const struct pci1723_board boardtypes[] = { - { - .name = "pci1723", - .vendor_id = PCI_VENDOR_ID_ADVANTECH, - .device_id = 0x1723, - .iorange = IORANGE_1723, - .cardtype = TYPE_PCI1723, - .n_aochan = 8, - .n_diochan = 16, - .ao_maxdata = 0xffff, - .rangelist_ao = &range_pci1723, - }, -}; - -/* This structure is for data unique to this hardware driver. */ struct pci1723_private { - int valid; /* card is usable; */ - unsigned char da_range[8]; /* D/A output range for each channel */ - short ao_data[8]; /* data output buffer */ }; -/* The following macro to make it easy to access the private structure. */ -#define devpriv ((struct pci1723_private *)dev->private) - -#define this_board boardtypes - /* * The pci1723 card reset; */ static int pci1723_reset(struct comedi_device *dev) { + struct pci1723_private *devpriv = dev->private; int i; - DPRINTK("adv_pci1723 EDBG: BGN: pci1723_reset(...)\n"); outw(0x01, dev->iobase + PCI1723_SYN_SET); /* set synchronous output mode */ @@ -190,7 +140,6 @@ static int pci1723_reset(struct comedi_device *dev) /* set asynchronous output mode */ outw(0, dev->iobase + PCI1723_SYN_SET); - DPRINTK("adv_pci1723 EDBG: END: pci1723_reset(...)\n"); return 0; } @@ -198,10 +147,10 @@ static int pci1723_insn_read_ao(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct pci1723_private *devpriv = dev->private; int n, chan; chan = CR_CHAN(insn->chanspec); - DPRINTK(" adv_PCI1723 DEBUG: pci1723_insn_read_ao() -----\n"); for (n = 0; n < insn->n; n++) data[n] = devpriv->ao_data[chan]; @@ -215,11 +164,10 @@ static int pci1723_ao_write_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct pci1723_private *devpriv = dev->private; int n, chan; chan = CR_CHAN(insn->chanspec); - DPRINTK("PCI1723: the pci1723_ao_write_winsn() ------\n"); - for (n = 0; n < insn->n; n++) { devpriv->ao_data[chan] = data[n]; @@ -286,124 +234,73 @@ static int pci1723_dio_insn_bits(struct comedi_device *dev, return insn->n; } -static struct pci_dev *pci1723_find_pci_dev(struct comedi_device *dev, - struct comedi_devconfig *it) +static int pci1723_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) { - struct pci_dev *pcidev = NULL; - int bus = it->options[0]; - int slot = it->options[1]; - - for_each_pci_dev(pcidev) { - if (bus || slot) { - if (bus != pcidev->bus->number || - slot != PCI_SLOT(pcidev->devfn)) - continue; - } - if (pcidev->vendor != PCI_VENDOR_ID_ADVANTECH) - continue; - return pcidev; - } - dev_err(dev->class_dev, - "No supported board found! (req. bus %d, slot %d)\n", - bus, slot); - return NULL; -} - -static int pci1723_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct pci_dev *pcidev; + struct pci1723_private *devpriv; struct comedi_subdevice *s; - int ret, subdev, n_subdevices; + int ret; - printk(KERN_ERR "comedi%d: adv_pci1723: board=%s", - dev->minor, this_board->name); - - ret = alloc_private(dev, sizeof(struct pci1723_private)); - if (ret < 0) { - printk(" - Allocation failed!\n"); - return -ENOMEM; - } - - pcidev = pci1723_find_pci_dev(dev, it); - if (!pcidev) - return -EIO; comedi_set_hw_dev(dev, &pcidev->dev); + dev->board_name = dev->driver->driver_name; - ret = comedi_pci_enable(pcidev, "adv_pci1723"); - if (ret) + ret = alloc_private(dev, sizeof(*devpriv)); + if (ret < 0) return ret; + devpriv = dev->private; + ret = comedi_pci_enable(pcidev, dev->board_name); + if (ret) + return ret; dev->iobase = pci_resource_start(pcidev, 2); - dev->board_name = this_board->name; - - n_subdevices = 0; - - if (this_board->n_aochan) - n_subdevices++; - if (this_board->n_diochan) - n_subdevices++; - - ret = comedi_alloc_subdevices(dev, n_subdevices); + ret = comedi_alloc_subdevices(dev, 2); if (ret) return ret; - pci1723_reset(dev); - subdev = 0; - if (this_board->n_aochan) { - s = dev->subdevices + subdev; - dev->write_subdev = s; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = this_board->n_aochan; - s->maxdata = this_board->ao_maxdata; - s->len_chanlist = this_board->n_aochan; - s->range_table = this_board->rangelist_ao; - - s->insn_write = pci1723_ao_write_winsn; - s->insn_read = pci1723_insn_read_ao; - - /* read DIO config */ - switch (inw(dev->iobase + PCI1723_DIGITAL_IO_PORT_MODE) - & 0x03) { - case 0x00: /* low byte output, high byte output */ - s->io_bits = 0xFFFF; - break; - case 0x01: /* low byte input, high byte output */ - s->io_bits = 0xFF00; - break; - case 0x02: /* low byte output, high byte input */ - s->io_bits = 0x00FF; - break; - case 0x03: /* low byte input, high byte input */ - s->io_bits = 0x0000; - break; - } - /* read DIO port state */ - s->state = inw(dev->iobase + PCI1723_READ_DIGITAL_INPUT_DATA); - - subdev++; - } - - if (this_board->n_diochan) { - s = dev->subdevices + subdev; - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = - SDF_READABLE | SDF_WRITABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = this_board->n_diochan; - s->maxdata = 1; - s->len_chanlist = this_board->n_diochan; - s->range_table = &range_digital; - s->insn_config = pci1723_dio_insn_config; - s->insn_bits = pci1723_dio_insn_bits; - subdev++; + s = &dev->subdevices[0]; + dev->write_subdev = s; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = 8; + s->maxdata = 0xffff; + s->len_chanlist = 8; + s->range_table = &range_bipolar10; + s->insn_write = pci1723_ao_write_winsn; + s->insn_read = pci1723_insn_read_ao; + + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->len_chanlist = 16; + s->range_table = &range_digital; + s->insn_config = pci1723_dio_insn_config; + s->insn_bits = pci1723_dio_insn_bits; + + /* read DIO config */ + switch (inw(dev->iobase + PCI1723_DIGITAL_IO_PORT_MODE) & 0x03) { + case 0x00: /* low byte output, high byte output */ + s->io_bits = 0xFFFF; + break; + case 0x01: /* low byte input, high byte output */ + s->io_bits = 0xFF00; + break; + case 0x02: /* low byte output, high byte input */ + s->io_bits = 0x00FF; + break; + case 0x03: /* low byte input, high byte input */ + s->io_bits = 0x0000; + break; } - - devpriv->valid = 1; + /* read DIO port state */ + s->state = inw(dev->iobase + PCI1723_READ_DIGITAL_INPUT_DATA); pci1723_reset(dev); + dev_info(dev->class_dev, "%s attached\n", dev->board_name); + return 0; } @@ -411,21 +308,18 @@ static void pci1723_detach(struct comedi_device *dev) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); - if (dev->private) { - if (devpriv->valid) - pci1723_reset(dev); - } if (pcidev) { - if (dev->iobase) + if (dev->iobase) { + pci1723_reset(dev); comedi_pci_disable(pcidev); - pci_dev_put(pcidev); + } } } static struct comedi_driver adv_pci1723_driver = { .driver_name = "adv_pci1723", .module = THIS_MODULE, - .attach = pci1723_attach, + .attach_pci = pci1723_attach_pci, .detach = pci1723_detach, }; diff --git a/drivers/staging/comedi/drivers/adv_pci_dio.c b/drivers/staging/comedi/drivers/adv_pci_dio.c index 2d4cb7f638b2..a3c22419cd5f 100644 --- a/drivers/staging/comedi/drivers/adv_pci_dio.c +++ b/drivers/staging/comedi/drivers/adv_pci_dio.c @@ -36,15 +36,6 @@ Configuration options: #include "8255.h" #include "8253.h" -#undef PCI_DIO_EXTDEBUG /* if defined, enable extensive debug logging */ - -#undef DPRINTK -#ifdef PCI_DIO_EXTDEBUG -#define DPRINTK(fmt, args...) printk(fmt, ## args) -#else -#define DPRINTK(fmt, args...) -#endif - #define PCI_VENDOR_ID_ADVANTECH 0x13fe /* hardware types of the cards */ @@ -250,6 +241,7 @@ struct dio_boardtype { int device_id; int main_pci_region; /* main I/O PCI region */ enum hw_cards_id cardtype; + int nsubdevs; struct diosubd_data sdi[MAX_DI_SUBDEVS]; /* DI chans */ struct diosubd_data sdo[MAX_DO_SUBDEVS]; /* DO chans */ struct diosubd_data sdio[MAX_DIO_SUBDEVG]; /* DIO 8255 chans */ @@ -259,126 +251,164 @@ struct dio_boardtype { }; static const struct dio_boardtype boardtypes[] = { - {"pci1730", PCI_VENDOR_ID_ADVANTECH, 0x1730, PCIDIO_MAINREG, - TYPE_PCI1730, - { {16, PCI1730_DI, 2, 0}, {16, PCI1730_IDI, 2, 0} }, - { {16, PCI1730_DO, 2, 0}, {16, PCI1730_IDO, 2, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - {4, PCI173x_BOARDID, 1, SDF_INTERNAL}, - { {0, 0, 0, 0} }, - IO_8b}, - {"pci1733", PCI_VENDOR_ID_ADVANTECH, 0x1733, PCIDIO_MAINREG, - TYPE_PCI1733, - { {0, 0, 0, 0}, {32, PCI1733_IDI, 4, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - {4, PCI173x_BOARDID, 1, SDF_INTERNAL}, - { {0, 0, 0, 0} }, - IO_8b}, - {"pci1734", PCI_VENDOR_ID_ADVANTECH, 0x1734, PCIDIO_MAINREG, - TYPE_PCI1734, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {0, 0, 0, 0}, {32, PCI1734_IDO, 4, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - {4, PCI173x_BOARDID, 1, SDF_INTERNAL}, - { {0, 0, 0, 0} }, - IO_8b}, - {"pci1735", PCI_VENDOR_ID_ADVANTECH, 0x1735, PCIDIO_MAINREG, - TYPE_PCI1735, - { {32, PCI1735_DI, 4, 0}, {0, 0, 0, 0} }, - { {32, PCI1735_DO, 4, 0}, {0, 0, 0, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { 4, PCI1735_BOARDID, 1, SDF_INTERNAL}, - { {3, PCI1735_C8254, 1, 0} }, - IO_8b}, - {"pci1736", PCI_VENDOR_ID_ADVANTECH, 0x1736, PCI1736_MAINREG, - TYPE_PCI1736, - { {0, 0, 0, 0}, {16, PCI1736_IDI, 2, 0} }, - { {0, 0, 0, 0}, {16, PCI1736_IDO, 2, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - {4, PCI1736_BOARDID, 1, SDF_INTERNAL}, - { {0, 0, 0, 0} }, - IO_8b}, - {"pci1739", PCI_VENDOR_ID_ADVANTECH, 0x1739, PCIDIO_MAINREG, - TYPE_PCI1739, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {48, PCI1739_DIO, 2, 0}, {0, 0, 0, 0} }, - {0, 0, 0, 0}, - { {0, 0, 0, 0} }, - IO_8b}, - {"pci1750", PCI_VENDOR_ID_ADVANTECH, 0x1750, PCIDIO_MAINREG, - TYPE_PCI1750, - { {0, 0, 0, 0}, {16, PCI1750_IDI, 2, 0} }, - { {0, 0, 0, 0}, {16, PCI1750_IDO, 2, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - {0, 0, 0, 0}, - { {0, 0, 0, 0} }, - IO_8b}, - {"pci1751", PCI_VENDOR_ID_ADVANTECH, 0x1751, PCIDIO_MAINREG, - TYPE_PCI1751, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {48, PCI1751_DIO, 2, 0}, {0, 0, 0, 0} }, - {0, 0, 0, 0}, - { {3, PCI1751_CNT, 1, 0} }, - IO_8b}, - {"pci1752", PCI_VENDOR_ID_ADVANTECH, 0x1752, PCIDIO_MAINREG, - TYPE_PCI1752, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {32, PCI1752_IDO, 2, 0}, {32, PCI1752_IDO2, 2, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - {4, PCI175x_BOARDID, 1, SDF_INTERNAL}, - { {0, 0, 0, 0} }, - IO_16b}, - {"pci1753", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG, - TYPE_PCI1753, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {96, PCI1753_DIO, 4, 0}, {0, 0, 0, 0} }, - {0, 0, 0, 0}, - { {0, 0, 0, 0} }, - IO_8b}, - {"pci1753e", PCI_VENDOR_ID_ADVANTECH, 0x1753, PCIDIO_MAINREG, - TYPE_PCI1753E, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {96, PCI1753_DIO, 4, 0}, {96, PCI1753E_DIO, 4, 0} }, - {0, 0, 0, 0}, - { {0, 0, 0, 0} }, - IO_8b}, - {"pci1754", PCI_VENDOR_ID_ADVANTECH, 0x1754, PCIDIO_MAINREG, - TYPE_PCI1754, - { {32, PCI1754_IDI, 2, 0}, {32, PCI1754_IDI2, 2, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - {4, PCI175x_BOARDID, 1, SDF_INTERNAL}, - { {0, 0, 0, 0} }, - IO_16b}, - {"pci1756", PCI_VENDOR_ID_ADVANTECH, 0x1756, PCIDIO_MAINREG, - TYPE_PCI1756, - { {0, 0, 0, 0}, {32, PCI1756_IDI, 2, 0} }, - { {0, 0, 0, 0}, {32, PCI1756_IDO, 2, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - {4, PCI175x_BOARDID, 1, SDF_INTERNAL}, - { {0, 0, 0, 0} }, - IO_16b}, - {"pci1760", PCI_VENDOR_ID_ADVANTECH, 0x1760, 0, - TYPE_PCI1760, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, /* This card have own setup work */ - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - {0, 0, 0, 0}, - { {0, 0, 0, 0} }, - IO_8b}, - {"pci1762", PCI_VENDOR_ID_ADVANTECH, 0x1762, PCIDIO_MAINREG, - TYPE_PCI1762, - { {0, 0, 0, 0}, {16, PCI1762_IDI, 1, 0} }, - { {0, 0, 0, 0}, {16, PCI1762_RO, 1, 0} }, - { {0, 0, 0, 0}, {0, 0, 0, 0} }, - {4, PCI1762_BOARDID, 1, SDF_INTERNAL}, - { {0, 0, 0, 0} }, - IO_16b} + { + .name = "pci1730", + .vendor_id = PCI_VENDOR_ID_ADVANTECH, + .device_id = 0x1730, + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1730, + .nsubdevs = 5, + .sdi[0] = { 16, PCI1730_DI, 2, 0, }, + .sdi[1] = { 16, PCI1730_IDI, 2, 0, }, + .sdo[0] = { 16, PCI1730_DO, 2, 0, }, + .sdo[1] = { 16, PCI1730_IDO, 2, 0, }, + .boardid = { 4, PCI173x_BOARDID, 1, SDF_INTERNAL, }, + .io_access = IO_8b, + }, { + .name = "pci1733", + .vendor_id = PCI_VENDOR_ID_ADVANTECH, + .device_id = 0x1733, + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1733, + .nsubdevs = 2, + .sdi[1] = { 32, PCI1733_IDI, 4, 0, }, + .boardid = { 4, PCI173x_BOARDID, 1, SDF_INTERNAL, }, + .io_access = IO_8b, + }, { + .name = "pci1734", + .vendor_id = PCI_VENDOR_ID_ADVANTECH, + .device_id = 0x1734, + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1734, + .nsubdevs = 2, + .sdo[1] = { 32, PCI1734_IDO, 4, 0, }, + .boardid = { 4, PCI173x_BOARDID, 1, SDF_INTERNAL, }, + .io_access = IO_8b, + }, { + .name = "pci1735", + .vendor_id = PCI_VENDOR_ID_ADVANTECH, + .device_id = 0x1735, + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1735, + .nsubdevs = 4, + .sdi[0] = { 32, PCI1735_DI, 4, 0, }, + .sdo[0] = { 32, PCI1735_DO, 4, 0, }, + .boardid = { 4, PCI1735_BOARDID, 1, SDF_INTERNAL, }, + .s8254[0] = { 3, PCI1735_C8254, 1, 0, }, + .io_access = IO_8b, + }, { + .name = "pci1736", + .vendor_id = PCI_VENDOR_ID_ADVANTECH, + .device_id = 0x1736, + .main_pci_region = PCI1736_MAINREG, + .cardtype = TYPE_PCI1736, + .nsubdevs = 3, + .sdi[1] = { 16, PCI1736_IDI, 2, 0, }, + .sdo[1] = { 16, PCI1736_IDO, 2, 0, }, + .boardid = { 4, PCI1736_BOARDID, 1, SDF_INTERNAL, }, + .io_access = IO_8b, + }, { + .name = "pci1739", + .vendor_id = PCI_VENDOR_ID_ADVANTECH, + .device_id = 0x1739, + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1739, + .nsubdevs = 2, + .sdio[0] = { 48, PCI1739_DIO, 2, 0, }, + .io_access = IO_8b, + }, { + .name = "pci1750", + .vendor_id = PCI_VENDOR_ID_ADVANTECH, + .device_id = 0x1750, + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1750, + .nsubdevs = 2, + .sdi[1] = { 16, PCI1750_IDI, 2, 0, }, + .sdo[1] = { 16, PCI1750_IDO, 2, 0, }, + .io_access = IO_8b, + }, { + .name = "pci1751", + .vendor_id = PCI_VENDOR_ID_ADVANTECH, + .device_id = 0x1751, + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1751, + .nsubdevs = 3, + .sdio[0] = { 48, PCI1751_DIO, 2, 0, }, + .s8254[0] = { 3, PCI1751_CNT, 1, 0, }, + .io_access = IO_8b, + }, { + .name = "pci1752", + .vendor_id = PCI_VENDOR_ID_ADVANTECH, + .device_id = 0x1752, + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1752, + .nsubdevs = 3, + .sdo[0] = { 32, PCI1752_IDO, 2, 0, }, + .sdo[1] = { 32, PCI1752_IDO2, 2, 0, }, + .boardid = { 4, PCI175x_BOARDID, 1, SDF_INTERNAL, }, + .io_access = IO_16b, + }, { + .name = "pci1753", + .vendor_id = PCI_VENDOR_ID_ADVANTECH, + .device_id = 0x1753, + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1753, + .nsubdevs = 4, + .sdio[0] = { 96, PCI1753_DIO, 4, 0, }, + .io_access = IO_8b, + }, { + .name = "pci1753e", + .vendor_id = PCI_VENDOR_ID_ADVANTECH, + .device_id = 0x1753, + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1753E, + .nsubdevs = 8, + .sdio[0] = { 96, PCI1753_DIO, 4, 0, }, + .sdio[1] = { 96, PCI1753E_DIO, 4, 0, }, + .io_access = IO_8b, + }, { + .name = "pci1754", + .vendor_id = PCI_VENDOR_ID_ADVANTECH, + .device_id = 0x1754, + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1754, + .nsubdevs = 3, + .sdi[0] = { 32, PCI1754_IDI, 2, 0, }, + .sdi[1] = { 32, PCI1754_IDI2, 2, 0, }, + .boardid = { 4, PCI175x_BOARDID, 1, SDF_INTERNAL, }, + .io_access = IO_16b, + }, { + .name = "pci1756", + .vendor_id = PCI_VENDOR_ID_ADVANTECH, + .device_id = 0x1756, + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1756, + .nsubdevs = 3, + .sdi[1] = { 32, PCI1756_IDI, 2, 0, }, + .sdo[1] = { 32, PCI1756_IDO, 2, 0, }, + .boardid = { 4, PCI175x_BOARDID, 1, SDF_INTERNAL, }, + .io_access = IO_16b, + }, { + /* This card has its own 'attach' */ + .name = "pci1760", + .vendor_id = PCI_VENDOR_ID_ADVANTECH, + .device_id = 0x1760, + .main_pci_region = 0, + .cardtype = TYPE_PCI1760, + .nsubdevs = 4, + .io_access = IO_8b, + }, { + .name = "pci1762", + .vendor_id = PCI_VENDOR_ID_ADVANTECH, + .device_id = 0x1762, + .main_pci_region = PCIDIO_MAINREG, + .cardtype = TYPE_PCI1762, + .nsubdevs = 3, + .sdi[1] = { 16, PCI1762_IDI, 1, 0, }, + .sdo[1] = { 16, PCI1762_RO, 1, 0, }, + .boardid = { 4, PCI1762_BOARDID, 1, SDF_INTERNAL, }, + .io_access = IO_16b, + }, }; struct pci_dio_private { @@ -401,9 +431,6 @@ struct pci_dio_private { unsigned short IDIFiltrHigh[8]; /* IDI's filter value high signal */ }; -#define devpriv ((struct pci_dio_private *)dev->private) -#define this_board ((const struct dio_boardtype *)dev->board_ptr) - /* ============================================================================== */ @@ -694,6 +721,7 @@ static int pci1760_insn_cnt_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct pci_dio_private *devpriv = dev->private; int ret; unsigned char chan = CR_CHAN(insn->chanspec) & 0x07; unsigned char bitmask = 1 << chan; @@ -736,6 +764,7 @@ static int pci1760_insn_cnt_write(struct comedi_device *dev, */ static int pci1760_reset(struct comedi_device *dev) { + struct pci_dio_private *devpriv = dev->private; int i; unsigned char omb[4] = { 0x00, 0x00, 0x00, 0x00 }; unsigned char imb[4]; @@ -816,7 +845,7 @@ static int pci1760_reset(struct comedi_device *dev) */ static int pci_dio_reset(struct comedi_device *dev) { - DPRINTK("adv_pci_dio EDBG: BGN: pci171x_reset(...)\n"); + const struct dio_boardtype *this_board = comedi_board(dev); switch (this_board->cardtype) { case TYPE_PCI1730: @@ -917,21 +946,17 @@ static int pci_dio_reset(struct comedi_device *dev) break; } - DPRINTK("adv_pci_dio EDBG: END: pci171x_reset(...)\n"); - return 0; } /* ============================================================================== */ -static int pci1760_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int pci1760_attach(struct comedi_device *dev) { struct comedi_subdevice *s; - int subdev = 0; - s = dev->subdevices + subdev; + s = &dev->subdevices[0]; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON; s->n_chan = 8; @@ -939,9 +964,8 @@ static int pci1760_attach(struct comedi_device *dev, s->len_chanlist = 8; s->range_table = &range_digital; s->insn_bits = pci1760_insn_bits_di; - subdev++; - s = dev->subdevices + subdev; + s = &dev->subdevices[1]; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; s->n_chan = 8; @@ -950,18 +974,16 @@ static int pci1760_attach(struct comedi_device *dev, s->range_table = &range_digital; s->state = 0; s->insn_bits = pci1760_insn_bits_do; - subdev++; - s = dev->subdevices + subdev; + s = &dev->subdevices[2]; s->type = COMEDI_SUBD_TIMER; s->subdev_flags = SDF_WRITABLE | SDF_LSAMPL; s->n_chan = 2; s->maxdata = 0xffffffff; s->len_chanlist = 2; /* s->insn_config=pci1760_insn_pwm_cfg; */ - subdev++; - s = dev->subdevices + subdev; + s = &dev->subdevices[3]; s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = 8; @@ -970,7 +992,6 @@ static int pci1760_attach(struct comedi_device *dev, s->insn_read = pci1760_insn_cnt_read; s->insn_write = pci1760_insn_cnt_write; /* s->insn_config=pci1760_insn_cnt_cfg; */ - subdev++; return 0; } @@ -978,9 +999,12 @@ static int pci1760_attach(struct comedi_device *dev, /* ============================================================================== */ -static int pci_dio_add_di(struct comedi_device *dev, struct comedi_subdevice *s, - const struct diosubd_data *d, int subdev) +static int pci_dio_add_di(struct comedi_device *dev, + struct comedi_subdevice *s, + const struct diosubd_data *d) { + const struct dio_boardtype *this_board = comedi_board(dev); + s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_COMMON | d->specflags; if (d->chans > 16) @@ -1005,9 +1029,12 @@ static int pci_dio_add_di(struct comedi_device *dev, struct comedi_subdevice *s, /* ============================================================================== */ -static int pci_dio_add_do(struct comedi_device *dev, struct comedi_subdevice *s, - const struct diosubd_data *d, int subdev) +static int pci_dio_add_do(struct comedi_device *dev, + struct comedi_subdevice *s, + const struct diosubd_data *d) { + const struct dio_boardtype *this_board = comedi_board(dev); + s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; if (d->chans > 16) @@ -1035,7 +1062,7 @@ static int pci_dio_add_do(struct comedi_device *dev, struct comedi_subdevice *s, */ static int pci_dio_add_8254(struct comedi_device *dev, struct comedi_subdevice *s, - const struct diosubd_data *d, int subdev) + const struct diosubd_data *d) { s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = SDF_WRITABLE | SDF_READABLE; @@ -1050,101 +1077,69 @@ static int pci_dio_add_8254(struct comedi_device *dev, return 0; } -static struct pci_dev *pci_dio_find_pci_dev(struct comedi_device *dev, - struct comedi_devconfig *it) +static const void *pci_dio_find_boardinfo(struct comedi_device *dev, + struct pci_dev *pcidev) { - struct pci_dev *pcidev = NULL; - int bus = it->options[0]; - int slot = it->options[1]; + const struct dio_boardtype *this_board; int i; - for_each_pci_dev(pcidev) { - if (bus || slot) { - if (bus != pcidev->bus->number || - slot != PCI_SLOT(pcidev->devfn)) - continue; - } - for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) { - if (boardtypes[i].vendor_id != pcidev->vendor) - continue; - if (boardtypes[i].device_id != pcidev->device) - continue; - dev->board_ptr = boardtypes + i; - return pcidev; - } + for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) { + this_board = &boardtypes[i]; + if (this_board->vendor_id == pcidev->vendor && + this_board->device_id == pcidev->device) + return this_board; } - dev_err(dev->class_dev, - "No supported board found! (req. bus %d, slot %d)\n", - bus, slot); return NULL; } -static int pci_dio_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int pci_dio_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) { - struct pci_dev *pcidev; + const struct dio_boardtype *this_board; + struct pci_dio_private *devpriv; struct comedi_subdevice *s; - int ret, subdev, n_subdevices, i, j; + int ret, subdev, i, j; - ret = alloc_private(dev, sizeof(struct pci_dio_private)); - if (ret < 0) - return -ENOMEM; - - pcidev = pci_dio_find_pci_dev(dev, it); - if (!pcidev) - return -EIO; comedi_set_hw_dev(dev, &pcidev->dev); - if (comedi_pci_enable(pcidev, dev->driver->driver_name)) { - dev_err(dev->class_dev, - "Error: Can't enable PCI device and request regions!\n"); - return -EIO; - } - - dev->iobase = pci_resource_start(pcidev, this_board->main_pci_region); + this_board = pci_dio_find_boardinfo(dev, pcidev); + if (!this_board) + return -ENODEV; + dev->board_ptr = this_board; dev->board_name = this_board->name; - if (this_board->cardtype == TYPE_PCI1760) { - n_subdevices = 4; /* 8 IDI, 8 IDO, 2 PWM, 8 CNT */ - } else { - n_subdevices = 0; - for (i = 0; i < MAX_DI_SUBDEVS; i++) - if (this_board->sdi[i].chans) - n_subdevices++; - for (i = 0; i < MAX_DO_SUBDEVS; i++) - if (this_board->sdo[i].chans) - n_subdevices++; - for (i = 0; i < MAX_DIO_SUBDEVG; i++) - n_subdevices += this_board->sdio[i].regs; - if (this_board->boardid.chans) - n_subdevices++; - for (i = 0; i < MAX_8254_SUBDEVS; i++) - if (this_board->s8254[i].chans) - n_subdevices++; - } + ret = alloc_private(dev, sizeof(*devpriv)); + if (ret < 0) + return ret; + devpriv = dev->private; - ret = comedi_alloc_subdevices(dev, n_subdevices); + ret = comedi_pci_enable(pcidev, dev->board_name); + if (ret) + return ret; + dev->iobase = pci_resource_start(pcidev, this_board->main_pci_region); + + ret = comedi_alloc_subdevices(dev, this_board->nsubdevs); if (ret) return ret; subdev = 0; for (i = 0; i < MAX_DI_SUBDEVS; i++) if (this_board->sdi[i].chans) { - s = dev->subdevices + subdev; - pci_dio_add_di(dev, s, &this_board->sdi[i], subdev); + s = &dev->subdevices[subdev]; + pci_dio_add_di(dev, s, &this_board->sdi[i]); subdev++; } for (i = 0; i < MAX_DO_SUBDEVS; i++) if (this_board->sdo[i].chans) { - s = dev->subdevices + subdev; - pci_dio_add_do(dev, s, &this_board->sdo[i], subdev); + s = &dev->subdevices[subdev]; + pci_dio_add_do(dev, s, &this_board->sdo[i]); subdev++; } for (i = 0; i < MAX_DIO_SUBDEVG; i++) for (j = 0; j < this_board->sdio[i].regs; j++) { - s = dev->subdevices + subdev; + s = &dev->subdevices[subdev]; subdev_8255_init(dev, s, NULL, dev->iobase + this_board->sdio[i].addr + @@ -1153,21 +1148,21 @@ static int pci_dio_attach(struct comedi_device *dev, } if (this_board->boardid.chans) { - s = dev->subdevices + subdev; + s = &dev->subdevices[subdev]; s->type = COMEDI_SUBD_DI; - pci_dio_add_di(dev, s, &this_board->boardid, subdev); + pci_dio_add_di(dev, s, &this_board->boardid); subdev++; } for (i = 0; i < MAX_8254_SUBDEVS; i++) if (this_board->s8254[i].chans) { - s = dev->subdevices + subdev; - pci_dio_add_8254(dev, s, &this_board->s8254[i], subdev); + s = &dev->subdevices[subdev]; + pci_dio_add_8254(dev, s, &this_board->s8254[i]); subdev++; } if (this_board->cardtype == TYPE_PCI1760) - pci1760_attach(dev, it); + pci1760_attach(dev); devpriv->valid = 1; @@ -1178,52 +1173,34 @@ static int pci_dio_attach(struct comedi_device *dev, static void pci_dio_detach(struct comedi_device *dev) { + struct pci_dio_private *devpriv = dev->private; struct pci_dev *pcidev = comedi_to_pci_dev(dev); - int i, j; struct comedi_subdevice *s; - int subdev; + int i; - if (dev->private) { + if (devpriv) { if (devpriv->valid) pci_dio_reset(dev); - subdev = 0; - for (i = 0; i < MAX_DI_SUBDEVS; i++) { - if (this_board->sdi[i].chans) - subdev++; - } - for (i = 0; i < MAX_DO_SUBDEVS; i++) { - if (this_board->sdo[i].chans) - subdev++; - } - for (i = 0; i < MAX_DIO_SUBDEVG; i++) { - for (j = 0; j < this_board->sdio[i].regs; j++) { - s = dev->subdevices + subdev; - subdev_8255_cleanup(dev, s); - subdev++; - } - } - if (this_board->boardid.chans) - subdev++; - for (i = 0; i < MAX_8254_SUBDEVS; i++) - if (this_board->s8254[i].chans) - subdev++; + } + if (dev->subdevices) { for (i = 0; i < dev->n_subdevices; i++) { - s = dev->subdevices + i; + s = &dev->subdevices[i]; + if (s->type == COMEDI_SUBD_DIO) + subdev_8255_cleanup(dev, s); s->private = NULL; } } if (pcidev) { if (dev->iobase) comedi_pci_disable(pcidev); - pci_dev_put(pcidev); } } static struct comedi_driver adv_pci_dio_driver = { .driver_name = "adv_pci_dio", .module = THIS_MODULE, - .attach = pci_dio_attach, - .detach = pci_dio_detach + .attach_pci = pci_dio_attach_pci, + .detach = pci_dio_detach, }; static int __devinit adv_pci_dio_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/aio_aio12_8.c b/drivers/staging/comedi/drivers/aio_aio12_8.c index f7d453f8fe33..8acf60d0f20d 100644 --- a/drivers/staging/comedi/drivers/aio_aio12_8.c +++ b/drivers/staging/comedi/drivers/aio_aio12_8.c @@ -25,8 +25,9 @@ Driver: aio_aio12_8 Description: Access I/O Products PC-104 AIO12-8 Analog I/O Board Author: Pablo Mejia <pablo.mejia@cctechnol.com> -Devices: - [Access I/O] PC-104 AIO12-8 +Devices: [Access I/O] PC-104 AIO12-8 (aio_aio12_8) + [Access I/O] PC-104 AI12-8 (aio_ai12_8) + [Access I/O] PC-104 AO12-8 (aio_ao12_8) Status: experimental Configuration Options: @@ -42,91 +43,118 @@ Notes: #include <linux/ioport.h> #include "8255.h" -#define AIO12_8_STATUS 0x00 -#define AIO12_8_INTERRUPT 0x01 -#define AIO12_8_ADC 0x02 -#define AIO12_8_DAC_0 0x04 -#define AIO12_8_DAC_1 0x06 -#define AIO12_8_DAC_2 0x08 -#define AIO12_8_DAC_3 0x0A -#define AIO12_8_COUNTER_0 0x0C -#define AIO12_8_COUNTER_1 0x0D -#define AIO12_8_COUNTER_2 0x0E -#define AIO12_8_COUNTER_CONTROL 0x0F -#define AIO12_8_DIO_0 0x10 -#define AIO12_8_DIO_1 0x11 -#define AIO12_8_DIO_2 0x12 -#define AIO12_8_DIO_STATUS 0x13 -#define AIO12_8_DIO_CONTROL 0x14 -#define AIO12_8_ADC_TRIGGER_CONTROL 0x15 -#define AIO12_8_TRIGGER 0x16 -#define AIO12_8_POWER 0x17 - -#define STATUS_ADC_EOC 0x80 - -#define ADC_MODE_NORMAL 0x00 -#define ADC_MODE_INTERNAL_CLOCK 0x40 -#define ADC_MODE_STANDBY 0x80 -#define ADC_MODE_POWERDOWN 0xC0 - -#define DAC_ENABLE 0x18 +/* + * Register map + */ +#define AIO12_8_STATUS_REG 0x00 +#define AIO12_8_STATUS_ADC_EOC (1 << 7) +#define AIO12_8_STATUS_PORT_C_COS (1 << 6) +#define AIO12_8_STATUS_IRQ_ENA (1 << 2) +#define AIO12_8_INTERRUPT_REG 0x01 +#define AIO12_8_INTERRUPT_ADC (1 << 7) +#define AIO12_8_INTERRUPT_COS (1 << 6) +#define AIO12_8_INTERRUPT_COUNTER1 (1 << 5) +#define AIO12_8_INTERRUPT_PORT_C3 (1 << 4) +#define AIO12_8_INTERRUPT_PORT_C0 (1 << 3) +#define AIO12_8_INTERRUPT_ENA (1 << 2) +#define AIO12_8_ADC_REG 0x02 +#define AIO12_8_ADC_MODE_NORMAL (0 << 6) +#define AIO12_8_ADC_MODE_INT_CLK (1 << 6) +#define AIO12_8_ADC_MODE_STANDBY (2 << 6) +#define AIO12_8_ADC_MODE_POWERDOWN (3 << 6) +#define AIO12_8_ADC_ACQ_3USEC (0 << 5) +#define AIO12_8_ADC_ACQ_PROGRAM (1 << 5) +#define AIO12_8_ADC_RANGE(x) ((x) << 3) +#define AIO12_8_ADC_CHAN(x) ((x) << 0) +#define AIO12_8_DAC_REG(x) (0x04 + (x) * 2) +#define AIO12_8_8254_BASE_REG 0x0c +#define AIO12_8_8255_BASE_REG 0x10 +#define AIO12_8_DIO_CONTROL_REG 0x14 +#define AIO12_8_DIO_CONTROL_TST (1 << 0) +#define AIO12_8_ADC_TRIGGER_REG 0x15 +#define AIO12_8_ADC_TRIGGER_RANGE(x) ((x) << 3) +#define AIO12_8_ADC_TRIGGER_CHAN(x) ((x) << 0) +#define AIO12_8_TRIGGER_REG 0x16 +#define AIO12_8_TRIGGER_ADTRIG (1 << 1) +#define AIO12_8_TRIGGER_DACTRIG (1 << 0) +#define AIO12_8_COS_REG 0x17 +#define AIO12_8_DAC_ENABLE_REG 0x18 +#define AIO12_8_DAC_ENABLE_REF_ENA (1 << 0) struct aio12_8_boardtype { const char *name; + int ai_nchan; + int ao_nchan; }; static const struct aio12_8_boardtype board_types[] = { { - .name = "aio_aio12_8"}, + .name = "aio_aio12_8", + .ai_nchan = 8, + .ao_nchan = 4, + }, { + .name = "aio_ai12_8", + .ai_nchan = 8, + }, { + .name = "aio_ao12_8", + .ao_nchan = 4, + }, }; struct aio12_8_private { unsigned int ao_readback[4]; }; -#define devpriv ((struct aio12_8_private *) dev->private) - static int aio_aio12_8_ai_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned int range = CR_RANGE(insn->chanspec); + unsigned int val; + unsigned char control; int n; - unsigned char control = - ADC_MODE_NORMAL | - (CR_RANGE(insn->chanspec) << 3) | CR_CHAN(insn->chanspec); - /* read status to clear EOC latch */ - inb(dev->iobase + AIO12_8_STATUS); + /* + * Setup the control byte for internal 2MHz clock, 3uS conversion, + * at the desired range of the requested channel. + */ + control = AIO12_8_ADC_MODE_NORMAL | AIO12_8_ADC_ACQ_3USEC | + AIO12_8_ADC_RANGE(range) | AIO12_8_ADC_CHAN(chan); + + /* Read status to clear EOC latch */ + inb(dev->iobase + AIO12_8_STATUS_REG); for (n = 0; n < insn->n; n++) { int timeout = 5; /* Setup and start conversion */ - outb(control, dev->iobase + AIO12_8_ADC); + outb(control, dev->iobase + AIO12_8_ADC_REG); /* Wait for conversion to complete */ - while (timeout && - !(inb(dev->iobase + AIO12_8_STATUS) & STATUS_ADC_EOC)) { + do { + val = inb(dev->iobase + AIO12_8_STATUS_REG); timeout--; - printk(KERN_ERR "timeout %d\n", timeout); - udelay(1); - } - if (timeout == 0) { - comedi_error(dev, "ADC timeout"); - return -EIO; - } - - data[n] = inw(dev->iobase + AIO12_8_ADC) & 0x0FFF; + if (timeout == 0) { + dev_err(dev->class_dev, "ADC timeout\n"); + return -ETIMEDOUT; + } + } while (!(val & AIO12_8_STATUS_ADC_EOC)); + + data[n] = inw(dev->iobase + AIO12_8_ADC_REG) & s->maxdata; } - return n; + + return insn->n; } static int aio_aio12_8_ao_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct aio12_8_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + int val = devpriv->ao_readback[chan]; int i; - int val = devpriv->ao_readback[CR_CHAN(insn->chanspec)]; for (i = 0; i < insn->n; i++) data[i] = val; @@ -137,18 +165,22 @@ static int aio_aio12_8_ao_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct aio12_8_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned long port = dev->iobase + AIO12_8_DAC_REG(chan); + unsigned int val = 0; int i; - int chan = CR_CHAN(insn->chanspec); - unsigned long port = dev->iobase + AIO12_8_DAC_0 + (2 * chan); /* enable DACs */ - outb(0x01, dev->iobase + DAC_ENABLE); + outb(AIO12_8_DAC_ENABLE_REF_ENA, dev->iobase + AIO12_8_DAC_ENABLE_REG); for (i = 0; i < insn->n; i++) { - outb(data[i] & 0xFF, port); /* LSB */ - outb((data[i] >> 8) & 0x0F, port + 1); /* MSB */ - devpriv->ao_readback[chan] = data[i]; + val = data[i]; + outw(val, port); } + + devpriv->ao_readback[chan] = val; + return insn->n; } @@ -166,53 +198,77 @@ static int aio_aio12_8_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct aio12_8_boardtype *board = comedi_board(dev); - int iobase; + struct aio12_8_private *devpriv; struct comedi_subdevice *s; + int iobase; int ret; + dev->board_name = board->name; + iobase = it->options[0]; - if (!request_region(iobase, 24, "aio_aio12_8")) { + if (!request_region(iobase, 32, dev->board_name)) { printk(KERN_ERR "I/O port conflict"); return -EIO; } - - dev->board_name = board->name; - dev->iobase = iobase; - if (alloc_private(dev, sizeof(struct aio12_8_private)) < 0) - return -ENOMEM; + ret = alloc_private(dev, sizeof(*devpriv)); + if (ret) + return ret; + devpriv = dev->private; - ret = comedi_alloc_subdevices(dev, 3); + ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; s = &dev->subdevices[0]; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; - s->n_chan = 8; - s->maxdata = (1 << 12) - 1; - s->range_table = &range_aio_aio12_8; - s->insn_read = aio_aio12_8_ai_read; + if (board->ai_nchan) { + /* Analog input subdevice */ + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; + s->n_chan = board->ai_nchan; + s->maxdata = 0x0fff; + s->range_table = &range_aio_aio12_8; + s->insn_read = aio_aio12_8_ai_read; + } else { + s->type = COMEDI_SUBD_UNUSED; + } s = &dev->subdevices[1]; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_DIFF; - s->n_chan = 4; - s->maxdata = (1 << 12) - 1; - s->range_table = &range_aio_aio12_8; - s->insn_read = aio_aio12_8_ao_read; - s->insn_write = aio_aio12_8_ao_write; + if (board->ao_nchan) { + /* Analog output subdevice */ + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_DIFF; + s->n_chan = 4; + s->maxdata = 0x0fff; + s->range_table = &range_aio_aio12_8; + s->insn_read = aio_aio12_8_ao_read; + s->insn_write = aio_aio12_8_ao_write; + } else { + s->type = COMEDI_SUBD_UNUSED; + } s = &dev->subdevices[2]; - subdev_8255_init(dev, s, NULL, dev->iobase + AIO12_8_DIO_0); + /* 8255 Digital i/o subdevice */ + iobase = dev->iobase + AIO12_8_8255_BASE_REG; + ret = subdev_8255_init(dev, s, NULL, iobase); + if (ret) + return ret; + + s = &dev->subdevices[3]; + /* 8254 counter/timer subdevice */ + s->type = COMEDI_SUBD_UNUSED; + + dev_info(dev->class_dev, "%s: %s attached\n", + dev->driver->driver_name, dev->board_name); return 0; } static void aio_aio12_8_detach(struct comedi_device *dev) { - subdev_8255_cleanup(dev, &dev->subdevices[2]); + if (dev->subdevices) + subdev_8255_cleanup(dev, &dev->subdevices[2]); if (dev->iobase) release_region(dev->iobase, 24); } diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c index ba1e3bbf2df8..b2cb8b02b2a1 100644 --- a/drivers/staging/comedi/drivers/aio_iiro_16.c +++ b/drivers/staging/comedi/drivers/aio_iiro_16.c @@ -112,7 +112,7 @@ static int aio_iiro_16_attach(struct comedi_device *dev, if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_WRITABLE; s->n_chan = 16; @@ -120,7 +120,7 @@ static int aio_iiro_16_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = aio_iiro_16_dio_insn_bits_write; - s = dev->subdevices + 1; + s = &dev->subdevices[1]; s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE; s->n_chan = 16; diff --git a/drivers/staging/comedi/drivers/amplc_dio200.c b/drivers/staging/comedi/drivers/amplc_dio200.c index cc8931fde839..08f305210a69 100644 --- a/drivers/staging/comedi/drivers/amplc_dio200.c +++ b/drivers/staging/comedi/drivers/amplc_dio200.c @@ -210,11 +210,15 @@ order they appear in the channel list. #include "../comedidev.h" +#include "comedi_fc.h" #include "8255.h" #include "8253.h" #define DIO200_DRIVER_NAME "amplc_dio200" +#define DO_ISA IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA) +#define DO_PCI IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI) + /* PCI IDs */ #define PCI_VENDOR_ID_AMPLICON 0x14dc #define PCI_DEVICE_ID_AMPLICON_PCI272 0x000a @@ -272,12 +276,12 @@ enum dio200_model { }; enum dio200_layout { -#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA) +#if DO_ISA pc212_layout, pc214_layout, #endif pc215_layout, -#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA) +#if DO_ISA pc218_layout, #endif pc272_layout @@ -292,7 +296,7 @@ struct dio200_board { }; static const struct dio200_board dio200_boards[] = { -#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA) +#if DO_ISA { .name = "pc212e", .bustype = isa_bustype, @@ -324,7 +328,7 @@ static const struct dio200_board dio200_boards[] = { .layout = pc272_layout, }, #endif -#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI) +#if DO_PCI { .name = "pci215", .devid = PCI_DEVICE_ID_AMPLICON_PCI215, @@ -367,7 +371,7 @@ struct dio200_layout_struct { }; static const struct dio200_layout_struct dio200_layouts[] = { -#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA) +#if DO_ISA [pc212_layout] = { .n_subdevs = 6, .sdtype = {sd_8255, sd_8254, sd_8254, sd_8254, @@ -396,7 +400,7 @@ static const struct dio200_layout_struct dio200_layouts[] = { .has_int_sce = 1, .has_clk_gat_sce = 1, }, -#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA) +#if DO_ISA [pc218_layout] = { .n_subdevs = 7, .sdtype = {sd_8254, sd_8254, sd_8255, sd_8254, @@ -449,6 +453,16 @@ struct dio200_subdev_intr { int continuous; }; +static inline bool is_pci_board(const struct dio200_board *board) +{ + return DO_PCI && board->bustype == pci_bustype; +} + +static inline bool is_isa_board(const struct dio200_board *board) +{ + return DO_ISA && board->bustype == isa_bustype; +} + /* * This function looks for a board matching the supplied PCI device. */ @@ -458,7 +472,7 @@ dio200_find_pci_board(struct pci_dev *pci_dev) unsigned int i; for (i = 0; i < ARRAY_SIZE(dio200_boards); i++) - if (dio200_boards[i].bustype == pci_bustype && + if (is_pci_board(&dio200_boards[i]) && pci_dev->device == dio200_boards[i].devid) return &dio200_boards[i]; return NULL; @@ -758,52 +772,24 @@ dio200_subdev_intr_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; - unsigned int tmp; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= (TRIG_NOW | TRIG_INT); - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= (TRIG_COUNT | TRIG_NONE); - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually - compatible */ + /* Step 2a : make sure trigger sources are unique */ - /* these tests are true if more than one _src bit is set */ - if ((cmd->start_src & (cmd->start_src - 1)) != 0) - err++; - if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0) - err++; - if ((cmd->convert_src & (cmd->convert_src - 1)) != 0) - err++; - if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0) - err++; - if ((cmd->stop_src & (cmd->stop_src - 1)) != 0) - err++; + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -965,15 +951,15 @@ static irqreturn_t dio200_interrupt(int irq, void *d) { struct comedi_device *dev = d; struct dio200_private *devpriv = dev->private; + struct comedi_subdevice *s; int handled; if (!dev->attached) return IRQ_NONE; if (devpriv->intr_sd >= 0) { - handled = dio200_handle_read_intr(dev, - dev->subdevices + - devpriv->intr_sd); + s = &dev->subdevices[devpriv->intr_sd]; + handled = dio200_handle_read_intr(dev, s); } else { handled = 0; } @@ -1228,12 +1214,10 @@ static void dio200_report_attach(struct comedi_device *dev, unsigned int irq) char tmpbuf[60]; int tmplen; - if (IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA) && - thisboard->bustype == isa_bustype) + if (is_isa_board(thisboard)) tmplen = scnprintf(tmpbuf, sizeof(tmpbuf), "(base %#lx) ", dev->iobase); - else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI) && - thisboard->bustype == pci_bustype) + else if (is_pci_board(thisboard)) tmplen = scnprintf(tmpbuf, sizeof(tmpbuf), "(pci %s) ", pci_name(pcidev)); else @@ -1361,8 +1345,7 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it) } /* Process options and reserve resources according to bus type. */ - if (IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_ISA) && - thisboard->bustype == isa_bustype) { + if (is_isa_board(thisboard)) { unsigned long iobase; unsigned int irq; @@ -1372,8 +1355,7 @@ static int dio200_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret < 0) return ret; return dio200_common_attach(dev, iobase, irq, 0); - } else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI) && - thisboard->bustype == pci_bustype) { + } else if (is_pci_board(thisboard)) { struct pci_dev *pci_dev; pci_dev = dio200_find_pci_dev(dev, it); @@ -1397,7 +1379,7 @@ static int __devinit dio200_attach_pci(struct comedi_device *dev, { int ret; - if (!IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI)) + if (!DO_PCI) return -EINVAL; dev_info(dev->class_dev, DIO200_DRIVER_NAME ": attach pci %s\n", @@ -1425,7 +1407,6 @@ static int __devinit dio200_attach_pci(struct comedi_device *dev, static void dio200_detach(struct comedi_device *dev) { const struct dio200_board *thisboard = comedi_board(dev); - struct pci_dev *pcidev = comedi_to_pci_dev(dev); const struct dio200_layout_struct *layout; unsigned n; @@ -1450,13 +1431,16 @@ static void dio200_detach(struct comedi_device *dev) } } } - if (pcidev) { - if (dev->iobase) - comedi_pci_disable(pcidev); - pci_dev_put(pcidev); - } else { + if (is_isa_board(thisboard)) { if (dev->iobase) release_region(dev->iobase, DIO200_IO_SIZE); + } else if (is_pci_board(thisboard)) { + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + if (pcidev) { + if (dev->iobase) + comedi_pci_disable(pcidev); + pci_dev_put(pcidev); + } } } @@ -1477,7 +1461,7 @@ static struct comedi_driver amplc_dio200_driver = { .num_names = ARRAY_SIZE(dio200_boards), }; -#if IS_ENABLED(CONFIG_COMEDI_AMPLC_DIO200_PCI) +#if DO_PCI static DEFINE_PCI_DEVICE_TABLE(dio200_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI215) }, { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI272) }, diff --git a/drivers/staging/comedi/drivers/amplc_pc236.c b/drivers/staging/comedi/drivers/amplc_pc236.c index f50287903038..eacb5e4735d7 100644 --- a/drivers/staging/comedi/drivers/amplc_pc236.c +++ b/drivers/staging/comedi/drivers/amplc_pc236.c @@ -56,11 +56,15 @@ unused. #include "../comedidev.h" +#include "comedi_fc.h" #include "8255.h" #include "plx9052.h" #define PC236_DRIVER_NAME "amplc_pc236" +#define DO_ISA IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_ISA) +#define DO_PCI IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) + /* PCI236 PCI configuration register information */ #define PCI_VENDOR_ID_AMPLICON 0x14dc #define PCI_DEVICE_ID_AMPLICON_PCI236 0x0009 @@ -103,14 +107,14 @@ struct pc236_board { enum pc236_model model; }; static const struct pc236_board pc236_boards[] = { -#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_ISA) +#if DO_ISA { .name = "pc36at", .bustype = isa_bustype, .model = pc36at_model, }, #endif -#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) +#if DO_PCI { .name = "pci236", .devid = PCI_DEVICE_ID_AMPLICON_PCI236, @@ -135,6 +139,18 @@ struct pc236_private { int enable_irq; }; +/* test if ISA supported and this is an ISA board */ +static inline bool is_isa_board(const struct pc236_board *board) +{ + return DO_ISA && board->bustype == isa_bustype; +} + +/* test if PCI supported and this is a PCI board */ +static inline bool is_pci_board(const struct pc236_board *board) +{ + return DO_PCI && board->bustype == pci_bustype; +} + /* * This function looks for a board matching the supplied PCI device. */ @@ -143,7 +159,7 @@ static const struct pc236_board *pc236_find_pci_board(struct pci_dev *pci_dev) unsigned int i; for (i = 0; i < ARRAY_SIZE(pc236_boards); i++) - if (pc236_boards[i].bustype == pci_bustype && + if (is_pci_board(&pc236_boards[i]) && pci_dev->device == pc236_boards[i].devid) return &pc236_boards[i]; return NULL; @@ -214,12 +230,13 @@ static int pc236_request_region(struct comedi_device *dev, unsigned long from, */ static void pc236_intr_disable(struct comedi_device *dev) { + const struct pc236_board *thisboard = comedi_board(dev); struct pc236_private *devpriv = dev->private; unsigned long flags; spin_lock_irqsave(&dev->spinlock, flags); devpriv->enable_irq = 0; - if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) && devpriv->lcr_iobase) + if (is_pci_board(thisboard)) outl(PCI236_INTR_DISABLE, devpriv->lcr_iobase + PLX9052_INTCSR); spin_unlock_irqrestore(&dev->spinlock, flags); } @@ -231,12 +248,13 @@ static void pc236_intr_disable(struct comedi_device *dev) */ static void pc236_intr_enable(struct comedi_device *dev) { + const struct pc236_board *thisboard = comedi_board(dev); struct pc236_private *devpriv = dev->private; unsigned long flags; spin_lock_irqsave(&dev->spinlock, flags); devpriv->enable_irq = 1; - if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) && devpriv->lcr_iobase) + if (is_pci_board(thisboard)) outl(PCI236_INTR_ENABLE, devpriv->lcr_iobase + PLX9052_INTCSR); spin_unlock_irqrestore(&dev->spinlock, flags); } @@ -250,6 +268,7 @@ static void pc236_intr_enable(struct comedi_device *dev) */ static int pc236_intr_check(struct comedi_device *dev) { + const struct pc236_board *thisboard = comedi_board(dev); struct pc236_private *devpriv = dev->private; int retval = 0; unsigned long flags; @@ -257,8 +276,7 @@ static int pc236_intr_check(struct comedi_device *dev) spin_lock_irqsave(&dev->spinlock, flags); if (devpriv->enable_irq) { retval = 1; - if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) && - devpriv->lcr_iobase) { + if (is_pci_board(thisboard)) { if ((inl(devpriv->lcr_iobase + PLX9052_INTCSR) & PLX9052_INTCSR_LI1STAT_MASK) == PLX9052_INTCSR_LI1STAT_INACTIVE) { @@ -296,39 +314,20 @@ static int pc236_intr_cmdtest(struct comedi_device *dev, struct comedi_cmd *cmd) { int err = 0; - int tmp; - /* step 1 */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_FOLLOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE); if (err) return 1; - /* step 2: ignored */ + /* Step 2a : make sure trigger sources are unique */ + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -395,7 +394,7 @@ static int pc236_intr_cancel(struct comedi_device *dev, static irqreturn_t pc236_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 1; + struct comedi_subdevice *s = &dev->subdevices[1]; int handled; handled = pc236_intr_check(dev); @@ -414,15 +413,13 @@ static void pc236_report_attach(struct comedi_device *dev, unsigned int irq) char tmpbuf[60]; int tmplen; - if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_ISA) && - thisboard->bustype == isa_bustype) + if (is_isa_board(thisboard)) tmplen = scnprintf(tmpbuf, sizeof(tmpbuf), "(base %#lx) ", dev->iobase); - else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) && - thisboard->bustype == pci_bustype) { + else if (is_pci_board(thisboard)) tmplen = scnprintf(tmpbuf, sizeof(tmpbuf), "(pci %s) ", pci_name(pcidev)); - } else + else tmplen = 0; if (irq) tmplen += scnprintf(&tmpbuf[tmplen], sizeof(tmpbuf) - tmplen, @@ -449,14 +446,14 @@ static int pc236_common_attach(struct comedi_device *dev, unsigned long iobase, if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* digital i/o subdevice (8255) */ ret = subdev_8255_init(dev, s, NULL, iobase); if (ret < 0) { dev_err(dev->class_dev, "error! out of memory!\n"); return ret; } - s = dev->subdevices + 1; + s = &dev->subdevices[1]; dev->read_subdev = s; s->type = COMEDI_SUBD_UNUSED; pc236_intr_disable(dev); @@ -517,16 +514,14 @@ static int pc236_attach(struct comedi_device *dev, struct comedi_devconfig *it) return ret; } /* Process options according to bus type. */ - if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_ISA) && - thisboard->bustype == isa_bustype) { + if (is_isa_board(thisboard)) { unsigned long iobase = it->options[0]; unsigned int irq = it->options[1]; ret = pc236_request_region(dev, iobase, PC236_IO_SIZE); if (ret < 0) return ret; return pc236_common_attach(dev, iobase, irq, 0); - } else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) && - thisboard->bustype == pci_bustype) { + } else if (is_pci_board(thisboard)) { struct pci_dev *pci_dev; pci_dev = pc236_find_pci_dev(dev, it); @@ -550,7 +545,7 @@ static int __devinit pc236_attach_pci(struct comedi_device *dev, { int ret; - if (!IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI)) + if (!DO_PCI) return -EINVAL; dev_info(dev->class_dev, PC236_DRIVER_NAME ": attach pci %s\n", @@ -577,22 +572,25 @@ static int __devinit pc236_attach_pci(struct comedi_device *dev, static void pc236_detach(struct comedi_device *dev) { + const struct pc236_board *thisboard = comedi_board(dev); struct pc236_private *devpriv = dev->private; - struct pci_dev *pcidev = comedi_to_pci_dev(dev); if (devpriv) pc236_intr_disable(dev); if (dev->irq) free_irq(dev->irq, dev); if (dev->subdevices) - subdev_8255_cleanup(dev, dev->subdevices + 0); - if (pcidev) { - if (dev->iobase) - comedi_pci_disable(pcidev); - pci_dev_put(pcidev); - } else { + subdev_8255_cleanup(dev, &dev->subdevices[0]); + if (is_isa_board(thisboard)) { if (dev->iobase) release_region(dev->iobase, PC236_IO_SIZE); + } else if (is_pci_board(thisboard)) { + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + if (pcidev) { + if (dev->iobase) + comedi_pci_disable(pcidev); + pci_dev_put(pcidev); + } } } @@ -613,7 +611,7 @@ static struct comedi_driver amplc_pc236_driver = { .num_names = ARRAY_SIZE(pc236_boards), }; -#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC236_PCI) +#if DO_PCI static DEFINE_PCI_DEVICE_TABLE(pc236_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI236) }, {0} diff --git a/drivers/staging/comedi/drivers/amplc_pc263.c b/drivers/staging/comedi/drivers/amplc_pc263.c index 8191c4e28e0a..60830ccfb903 100644 --- a/drivers/staging/comedi/drivers/amplc_pc263.c +++ b/drivers/staging/comedi/drivers/amplc_pc263.c @@ -48,6 +48,9 @@ The state of the outputs can be read. #define PC263_DRIVER_NAME "amplc_pc263" +#define DO_ISA IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_ISA) +#define DO_PCI IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI) + /* PCI263 PCI configuration register information */ #define PCI_VENDOR_ID_AMPLICON 0x14dc #define PCI_DEVICE_ID_AMPLICON_PCI263 0x000c @@ -70,14 +73,14 @@ struct pc263_board { enum pc263_model model; }; static const struct pc263_board pc263_boards[] = { -#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_ISA) +#if DO_ISA { .name = "pc263", .bustype = isa_bustype, .model = pc263_model, }, #endif -#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI) +#if DO_PCI { .name = "pci263", .devid = PCI_DEVICE_ID_AMPLICON_PCI263, @@ -93,6 +96,18 @@ static const struct pc263_board pc263_boards[] = { #endif }; +/* test if ISA supported and this is an ISA board */ +static inline bool is_isa_board(const struct pc263_board *board) +{ + return DO_ISA && board->bustype == isa_bustype; +} + +/* test if PCI supported and this is a PCI board */ +static inline bool is_pci_board(const struct pc263_board *board) +{ + return DO_PCI && board->bustype == pci_bustype; +} + /* * This function looks for a board matching the supplied PCI device. */ @@ -101,7 +116,7 @@ static const struct pc263_board *pc263_find_pci_board(struct pci_dev *pci_dev) unsigned int i; for (i = 0; i < ARRAY_SIZE(pc263_boards); i++) - if (pc263_boards[i].bustype == pci_bustype && + if (is_pci_board(&pc263_boards[i]) && pci_dev->device == pc263_boards[i].devid) return &pc263_boards[i]; return NULL; @@ -187,11 +202,9 @@ static void pc263_report_attach(struct comedi_device *dev) struct pci_dev *pcidev = comedi_to_pci_dev(dev); char tmpbuf[40]; - if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_ISA) && - thisboard->bustype == isa_bustype) + if (is_isa_board(thisboard)) snprintf(tmpbuf, sizeof(tmpbuf), "(base %#lx) ", dev->iobase); - else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI) && - thisboard->bustype == pci_bustype) + else if (is_pci_board(thisboard)) snprintf(tmpbuf, sizeof(tmpbuf), "(pci %s) ", pci_name(pcidev)); else @@ -212,7 +225,7 @@ static int pc263_common_attach(struct comedi_device *dev, unsigned long iobase) if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* digital output subdevice */ s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; @@ -259,15 +272,13 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it) dev_info(dev->class_dev, PC263_DRIVER_NAME ": attach\n"); /* Process options and reserve resources according to bus type. */ - if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_ISA) && - thisboard->bustype == isa_bustype) { + if (is_isa_board(thisboard)) { unsigned long iobase = it->options[0]; ret = pc263_request_region(dev, iobase, PC263_IO_SIZE); if (ret < 0) return ret; return pc263_common_attach(dev, iobase); - } else if (IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI) && - thisboard->bustype == pci_bustype) { + } else if (is_pci_board(thisboard)) { struct pci_dev *pci_dev; pci_dev = pc263_find_pci_dev(dev, it); @@ -288,7 +299,7 @@ static int pc263_attach(struct comedi_device *dev, struct comedi_devconfig *it) static int __devinit pc263_attach_pci(struct comedi_device *dev, struct pci_dev *pci_dev) { - if (!IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI)) + if (!DO_PCI) return -EINVAL; dev_info(dev->class_dev, PC263_DRIVER_NAME ": attach pci %s\n", @@ -310,15 +321,18 @@ static int __devinit pc263_attach_pci(struct comedi_device *dev, static void pc263_detach(struct comedi_device *dev) { - struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct pc263_board *thisboard = comedi_board(dev); - if (pcidev) { - if (dev->iobase) - comedi_pci_disable(pcidev); - pci_dev_put(pcidev); - } else { + if (is_isa_board(thisboard)) { if (dev->iobase) release_region(dev->iobase, PC263_IO_SIZE); + } else if (is_pci_board(thisboard)) { + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + if (pcidev) { + if (dev->iobase) + comedi_pci_disable(pcidev); + pci_dev_put(pcidev); + } } } @@ -339,7 +353,7 @@ static struct comedi_driver amplc_pc263_driver = { .num_names = ARRAY_SIZE(pc263_boards), }; -#if IS_ENABLED(CONFIG_COMEDI_AMPLC_PC263_PCI) +#if DO_PCI static DEFINE_PCI_DEVICE_TABLE(pc263_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_AMPLICON, PCI_DEVICE_ID_AMPLICON_PCI263) }, {0} diff --git a/drivers/staging/comedi/drivers/amplc_pci224.c b/drivers/staging/comedi/drivers/amplc_pci224.c index 8bf109e7bb05..1f65ec4d261e 100644 --- a/drivers/staging/comedi/drivers/amplc_pci224.c +++ b/drivers/staging/comedi/drivers/amplc_pci224.c @@ -720,53 +720,31 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, int err = 0; unsigned int tmp; - /* Step 1: make sure trigger sources are trivially valid. */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_INT | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_EXT | TRIG_TIMER; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_EXT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_EXT | TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, + TRIG_COUNT | TRIG_EXT | TRIG_NONE); if (err) return 1; - /* Step 2: make sure trigger sources are unique and mutually - * compatible. */ + /* Step 2a : make sure trigger sources are unique */ - /* these tests are true if more than one _src bit is set */ - if ((cmd->start_src & (cmd->start_src - 1)) != 0) - err++; - if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0) - err++; - if ((cmd->convert_src & (cmd->convert_src - 1)) != 0) - err++; - if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0) - err++; - if ((cmd->stop_src & (cmd->stop_src - 1)) != 0) - err++; + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); - /* There's only one external trigger signal (which makes these - * tests easier). Only one thing can use it. */ + /* Step 2b : and mutually compatible */ + + /* + * There's only one external trigger signal (which makes these + * tests easier). Only one thing can use it. + */ tmp = 0; if (cmd->start_src & TRIG_EXT) tmp++; @@ -775,7 +753,7 @@ pci224_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, if (cmd->stop_src & TRIG_EXT) tmp++; if (tmp > 1) - err++; + err |= -EINVAL; if (err) return 2; @@ -1375,7 +1353,7 @@ static int pci224_attach_common(struct comedi_device *dev, if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* Analog output subdevice. */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_CMD_WRITE; @@ -1523,7 +1501,7 @@ static void pci224_detach(struct comedi_device *dev) if (dev->subdevices) { struct comedi_subdevice *s; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* AO subdevice */ kfree(s->range_table_list); } diff --git a/drivers/staging/comedi/drivers/amplc_pci230.c b/drivers/staging/comedi/drivers/amplc_pci230.c index 66e74bd12267..bd8fb876ce2e 100644 --- a/drivers/staging/comedi/drivers/amplc_pci230.c +++ b/drivers/staging/comedi/drivers/amplc_pci230.c @@ -193,6 +193,7 @@ for (or detection of) various hardware problems added by Ian Abbott. #include <linux/delay.h> #include <linux/interrupt.h> +#include "comedi_fc.h" #include "8253.h" #include "8255.h" @@ -958,23 +959,11 @@ static int pci230_ao_cmdtest(struct comedi_device *dev, int err = 0; unsigned int tmp; - /* cmdtest tests a particular command to see if it is valid. - * Using the cmdtest ioctl, a user can create a valid cmd - * and then have it executes by the cmd ioctl. - * - * cmdtest returns 1,2,3,4 or 0, depending on which tests - * the command passes. */ + /* Step 1 : check if triggers are trivially valid */ - /* Step 1: make sure trigger sources are trivially valid. - * "invalid source" returned by comedilib to user mode process - * if this fails. */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_INT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT); - tmp = cmd->scan_begin_src; + tmp = TRIG_TIMER | TRIG_INT; if ((thisboard->min_hwver > 0) && (devpriv->hwver >= 2)) { /* * For PCI230+ hardware version 2 onwards, allow external @@ -990,46 +979,23 @@ static int pci230_ao_cmdtest(struct comedi_device *dev, * scan_begin_src==TRIG_EXT support to be a bonus rather than a * guarantee! */ - cmd->scan_begin_src &= TRIG_TIMER | TRIG_INT | TRIG_EXT; - } else { - cmd->scan_begin_src &= TRIG_TIMER | TRIG_INT; + tmp |= TRIG_EXT; } - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + err |= cfc_check_trigger_src(&cmd->scan_begin_src, tmp); - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* Step 2: make sure trigger sources are unique and mutually compatible - * "source conflict" returned by comedilib to user mode process - * if this fails. */ + /* Step 2a : make sure trigger sources are unique */ - /* these tests are true if more than one _src bit is set */ - if ((cmd->start_src & (cmd->start_src - 1)) != 0) - err++; - if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0) - err++; - if ((cmd->convert_src & (cmd->convert_src - 1)) != 0) - err++; - if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0) - err++; - if ((cmd->stop_src & (cmd->stop_src - 1)) != 0) - err++; + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -1610,75 +1576,45 @@ static int pci230_ai_cmdtest(struct comedi_device *dev, int err = 0; unsigned int tmp; - /* cmdtest tests a particular command to see if it is valid. - * Using the cmdtest ioctl, a user can create a valid cmd - * and then have it executes by the cmd ioctl. - * - * cmdtest returns 1,2,3,4,5 or 0, depending on which tests - * the command passes. */ + /* Step 1 : check if triggers are trivially valid */ - /* Step 1: make sure trigger sources are trivially valid. - * "invalid source" returned by comedilib to user mode process - * if this fails. */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_INT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); - tmp = cmd->scan_begin_src; - /* Unfortunately, we cannot trigger a scan off an external source - * on the PCI260 board, since it uses the PPIC0 (DIO) input, which - * isn't present on the PCI260. For PCI260+ we can use the - * EXTTRIG/EXTCONVCLK input on pin 17 instead. */ + tmp = TRIG_FOLLOW | TRIG_TIMER | TRIG_INT; if ((thisboard->have_dio) || (thisboard->min_hwver > 0)) { - cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_INT - | TRIG_EXT; - } else { - cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_INT; + /* + * Unfortunately, we cannot trigger a scan off an external + * source on the PCI260 board, since it uses the PPIC0 (DIO) + * input, which isn't present on the PCI260. For PCI260+ + * we can use the EXTTRIG/EXTCONVCLK input on pin 17 instead. + */ + tmp |= TRIG_EXT; } - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_INT | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->scan_begin_src, tmp); + err |= cfc_check_trigger_src(&cmd->convert_src, + TRIG_TIMER | TRIG_INT | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* Step 2: make sure trigger sources are unique and mutually compatible - * "source conflict" returned by comedilib to user mode process - * if this fails. */ + /* Step 2a : make sure trigger sources are unique */ - /* these tests are true if more than one _src bit is set */ - if ((cmd->start_src & (cmd->start_src - 1)) != 0) - err++; - if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0) - err++; - if ((cmd->convert_src & (cmd->convert_src - 1)) != 0) - err++; - if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0) - err++; - if ((cmd->stop_src & (cmd->stop_src - 1)) != 0) - err++; + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ - /* If scan_begin_src is not TRIG_FOLLOW, then a monostable will be - * set up to generate a fixed number of timed conversion pulses. */ + /* + * If scan_begin_src is not TRIG_FOLLOW, then a monostable will be + * set up to generate a fixed number of timed conversion pulses. + */ if ((cmd->scan_begin_src != TRIG_FOLLOW) && (cmd->convert_src != TRIG_TIMER)) - err++; + err |= -EINVAL; if (err) return 2; @@ -2838,7 +2774,7 @@ static int pci230_attach_common(struct comedi_device *dev, if (rc) return rc; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* analog input subdevice */ s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND; @@ -2855,7 +2791,7 @@ static int pci230_attach_common(struct comedi_device *dev, s->do_cmdtest = &pci230_ai_cmdtest; s->cancel = pci230_ai_cancel; } - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* analog output subdevice */ if (thisboard->ao_chans > 0) { s->type = COMEDI_SUBD_AO; @@ -2878,7 +2814,7 @@ static int pci230_attach_common(struct comedi_device *dev, } else { s->type = COMEDI_SUBD_UNUSED; } - s = dev->subdevices + 2; + s = &dev->subdevices[2]; /* digital i/o subdevice */ if (thisboard->have_dio) { rc = subdev_8255_init(dev, s, NULL, @@ -2941,7 +2877,7 @@ static void pci230_detach(struct comedi_device *dev) struct pci_dev *pcidev = comedi_to_pci_dev(dev); if (dev->subdevices && thisboard->have_dio) - subdev_8255_cleanup(dev, dev->subdevices + 2); + subdev_8255_cleanup(dev, &dev->subdevices[2]); if (dev->irq) free_irq(dev->irq, dev); if (pcidev) { diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c index 41ed8576f301..070037c22db7 100644 --- a/drivers/staging/comedi/drivers/c6xdigio.c +++ b/drivers/staging/comedi/drivers/c6xdigio.c @@ -447,7 +447,7 @@ static int c6xdigio_attach(struct comedi_device *dev, else if (irq == 0) printk(KERN_DEBUG "comedi%d: no irq\n", dev->minor); - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* pwm output subdevice */ s->type = COMEDI_SUBD_AO; /* Not sure what to put here */ s->subdev_flags = SDF_WRITEABLE; @@ -458,7 +458,7 @@ static int c6xdigio_attach(struct comedi_device *dev, s->maxdata = 500; s->range_table = &range_bipolar10; /* A suitable lie */ - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* encoder (counter) subdevice */ s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = SDF_READABLE | SDF_LSAMPL; @@ -468,7 +468,7 @@ static int c6xdigio_attach(struct comedi_device *dev, s->maxdata = 0xffffff; s->range_table = &range_unknown; - /* s = dev->subdevices + 2; */ + /* s = &dev->subdevices[2]; */ /* pwm output subdevice */ /* s->type = COMEDI_SUBD_COUNTER; // Not sure what to put here */ /* s->subdev_flags = SDF_WRITEABLE; */ diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c index 58d45299bf85..6d81d8b40ccc 100644 --- a/drivers/staging/comedi/drivers/cb_das16_cs.c +++ b/drivers/staging/comedi/drivers/cb_das16_cs.c @@ -46,6 +46,7 @@ Status: experimental #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> +#include "comedi_fc.h" #include "8253.h" #define DAS16CS_SIZE 18 @@ -169,47 +170,26 @@ static int das16cs_ai_cmdtest(struct comedi_device *dev, int err = 0; int tmp; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, + TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and - * mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ - /* note that mutual compatibility is not an issue here */ - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -478,7 +458,7 @@ static int das16cs_attach(struct comedi_device *dev, if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; dev->read_subdev = s; /* analog input subdevice */ s->type = COMEDI_SUBD_AI; @@ -491,7 +471,7 @@ static int das16cs_attach(struct comedi_device *dev, s->do_cmd = das16cs_ai_cmd; s->do_cmdtest = das16cs_ai_cmdtest; - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* analog output subdevice */ if (thisboard->n_ao_chans) { s->type = COMEDI_SUBD_AO; @@ -505,7 +485,7 @@ static int das16cs_attach(struct comedi_device *dev, s->type = COMEDI_SUBD_UNUSED; } - s = dev->subdevices + 2; + s = &dev->subdevices[2]; /* digital i/o subdevice */ s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c index 2b6a637c3499..de21a261ff45 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas.c +++ b/drivers/staging/comedi/drivers/cb_pcidas.c @@ -45,11 +45,7 @@ Status: The boards may be autocalibrated using the comedi_calibrate utility. -Configuration options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - If bus/slot is not specified, the first supported - PCI device found will be used. +Configuration options: not applicable, uses PCI auto config For commands, the scanned channels must be consecutive (i.e. 4-5-6-7, 2-3-4,...), and must all have the same @@ -807,58 +803,35 @@ static int cb_pcidas_ai_cmdtest(struct comedi_device *dev, int tmp; int i, gain, start_chan; - /* step 1: trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_NOW | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, + TRIG_TIMER | TRIG_NOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: trigger sources are unique and mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ - if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) - err++; - if (cmd->scan_begin_src != TRIG_FOLLOW && - cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->convert_src != TRIG_TIMER && - cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ - /* make sure trigger sources are compatible with each other */ if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW) - err++; + err |= -EINVAL; if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_NOW) - err++; + err |= -EINVAL; if (cmd->start_src == TRIG_EXT && (cmd->convert_src == TRIG_EXT || cmd->scan_begin_src == TRIG_EXT)) - err++; + err |= -EINVAL; if (err) return 2; @@ -1083,43 +1056,24 @@ static int cb_pcidas_ao_cmdtest(struct comedi_device *dev, int err = 0; int tmp; - /* step 1: trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_INT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: trigger sources are unique and mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -1501,69 +1455,45 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d) return IRQ_HANDLED; } -static struct pci_dev *cb_pcidas_find_pci_device(struct comedi_device *dev, - struct comedi_devconfig *it) +static const void *cb_pcidas_find_boardinfo(struct comedi_device *dev, + struct pci_dev *pcidev) { const struct cb_pcidas_board *thisboard; - struct pci_dev *pcidev = NULL; - int bus = it->options[0]; - int slot = it->options[1]; int i; - for_each_pci_dev(pcidev) { - /* is it not a computer boards card? */ - if (pcidev->vendor != PCI_VENDOR_ID_CB) - continue; - /* loop through cards supported by this driver */ - for (i = 0; i < ARRAY_SIZE(cb_pcidas_boards); i++) { - thisboard = &cb_pcidas_boards[i]; - if (thisboard->device_id != pcidev->device) - continue; - /* was a particular bus/slot requested? */ - if (bus || slot) { - /* are we on the wrong bus/slot? */ - if (pcidev->bus->number != bus || - PCI_SLOT(pcidev->devfn) != slot) { - continue; - } - } - dev_dbg(dev->class_dev, - "Found %s on bus %i, slot %i\n", - thisboard->name, - pcidev->bus->number, PCI_SLOT(pcidev->devfn)); - dev->board_ptr = thisboard; - return pcidev; - } + for (i = 0; i < ARRAY_SIZE(cb_pcidas_boards); i++) { + thisboard = &cb_pcidas_boards[i]; + if (thisboard->device_id == pcidev->device) + return thisboard; } - dev_err(dev->class_dev, "No supported card found\n"); return NULL; } -static int cb_pcidas_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int cb_pcidas_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) { const struct cb_pcidas_board *thisboard; struct cb_pcidas_private *devpriv; - struct pci_dev *pcidev; struct comedi_subdevice *s; int i; int ret; - if (alloc_private(dev, sizeof(struct cb_pcidas_private)) < 0) - return -ENOMEM; - devpriv = dev->private; - - pcidev = cb_pcidas_find_pci_device(dev, it); - if (!pcidev) - return -EIO; comedi_set_hw_dev(dev, &pcidev->dev); - thisboard = comedi_board(dev); - if (comedi_pci_enable(pcidev, dev->driver->driver_name)) { - dev_err(dev->class_dev, - "Failed to enable PCI device and request regions\n"); - return -EIO; - } + thisboard = cb_pcidas_find_boardinfo(dev, pcidev); + if (!thisboard) + return -ENODEV; + dev->board_ptr = thisboard; + dev->board_name = thisboard->name; + + ret = alloc_private(dev, sizeof(*devpriv)); + if (ret) + return ret; + devpriv = dev->private; + + ret = comedi_pci_enable(pcidev, dev->board_name); + if (ret) + return ret; devpriv->s5933_config = pci_resource_start(pcidev, 0); devpriv->control_status = pci_resource_start(pcidev, 1); @@ -1584,13 +1514,11 @@ static int cb_pcidas_attach(struct comedi_device *dev, } dev->irq = pcidev->irq; - dev->board_name = thisboard->name; - ret = comedi_alloc_subdevices(dev, 7); if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* analog input subdevice */ dev->read_subdev = s; s->type = COMEDI_SUBD_AI; @@ -1607,7 +1535,7 @@ static int cb_pcidas_attach(struct comedi_device *dev, s->cancel = cb_pcidas_cancel; /* analog output subdevice */ - s = dev->subdevices + 1; + s = &dev->subdevices[1]; if (thisboard->ao_nchan) { s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_GROUND; @@ -1634,14 +1562,14 @@ static int cb_pcidas_attach(struct comedi_device *dev, } /* 8255 */ - s = dev->subdevices + 2; + s = &dev->subdevices[2]; ret = subdev_8255_init(dev, s, NULL, devpriv->pacer_counter_dio + DIO_8255); if (ret) return ret; /* serial EEPROM, */ - s = dev->subdevices + 3; + s = &dev->subdevices[3]; s->type = COMEDI_SUBD_MEMORY; s->subdev_flags = SDF_READABLE | SDF_INTERNAL; s->n_chan = 256; @@ -1649,7 +1577,7 @@ static int cb_pcidas_attach(struct comedi_device *dev, s->insn_read = eeprom_read_insn; /* 8800 caldac */ - s = dev->subdevices + 4; + s = &dev->subdevices[4]; s->type = COMEDI_SUBD_CALIB; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; s->n_chan = NUM_CHANNELS_8800; @@ -1660,7 +1588,7 @@ static int cb_pcidas_attach(struct comedi_device *dev, caldac_8800_write(dev, i, s->maxdata / 2); /* trim potentiometer */ - s = dev->subdevices + 5; + s = &dev->subdevices[5]; s->type = COMEDI_SUBD_CALIB; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; if (thisboard->trimpot == AD7376) { @@ -1676,7 +1604,7 @@ static int cb_pcidas_attach(struct comedi_device *dev, cb_pcidas_trimpot_write(dev, i, s->maxdata / 2); /* dac08 caldac */ - s = dev->subdevices + 6; + s = &dev->subdevices[6]; if (thisboard->has_dac08) { s->type = COMEDI_SUBD_CALIB; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; @@ -1698,7 +1626,10 @@ static int cb_pcidas_attach(struct comedi_device *dev, outl(devpriv->s5933_intcsr_bits | INTCSR_INBOX_INTR_STATUS, devpriv->s5933_config + AMCC_OP_REG_INTCSR); - return 1; + dev_info(dev->class_dev, "%s: %s attached\n", + dev->driver->driver_name, dev->board_name); + + return 0; } static void cb_pcidas_detach(struct comedi_device *dev) @@ -1715,18 +1646,17 @@ static void cb_pcidas_detach(struct comedi_device *dev) if (dev->irq) free_irq(dev->irq, dev); if (dev->subdevices) - subdev_8255_cleanup(dev, dev->subdevices + 2); + subdev_8255_cleanup(dev, &dev->subdevices[2]); if (pcidev) { if (devpriv->s5933_config) comedi_pci_disable(pcidev); - pci_dev_put(pcidev); } } static struct comedi_driver cb_pcidas_driver = { .driver_name = "cb_pcidas", .module = THIS_MODULE, - .attach = cb_pcidas_attach, + .attach_pci = cb_pcidas_attach_pci, .detach = cb_pcidas_detach, }; diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c index 65cbaabf6456..0472a9088abe 100644 --- a/drivers/staging/comedi/drivers/cb_pcidas64.c +++ b/drivers/staging/comedi/drivers/cb_pcidas64.c @@ -1348,7 +1348,7 @@ static int setup_subdevices(struct comedi_device *dev) if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* analog input subdevice */ dev->read_subdev = s; s->type = COMEDI_SUBD_AI; @@ -1379,7 +1379,7 @@ static int setup_subdevices(struct comedi_device *dev) } /* analog output subdevice */ - s = dev->subdevices + 1; + s = &dev->subdevices[1]; if (board(dev)->ao_nchan) { s->type = COMEDI_SUBD_AO; s->subdev_flags = @@ -1401,7 +1401,7 @@ static int setup_subdevices(struct comedi_device *dev) } /* digital input */ - s = dev->subdevices + 2; + s = &dev->subdevices[2]; if (board(dev)->layout == LAYOUT_64XX) { s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; @@ -1414,7 +1414,7 @@ static int setup_subdevices(struct comedi_device *dev) /* digital output */ if (board(dev)->layout == LAYOUT_64XX) { - s = dev->subdevices + 3; + s = &dev->subdevices[3]; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE | SDF_READABLE; s->n_chan = 4; @@ -1425,7 +1425,7 @@ static int setup_subdevices(struct comedi_device *dev) s->type = COMEDI_SUBD_UNUSED; /* 8255 */ - s = dev->subdevices + 4; + s = &dev->subdevices[4]; if (board(dev)->has_8255) { if (board(dev)->layout == LAYOUT_4020) { dio_8255_iobase = @@ -1442,7 +1442,7 @@ static int setup_subdevices(struct comedi_device *dev) s->type = COMEDI_SUBD_UNUSED; /* 8 channel dio for 60xx */ - s = dev->subdevices + 5; + s = &dev->subdevices[5]; if (board(dev)->layout == LAYOUT_60XX) { s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_WRITABLE | SDF_READABLE; @@ -1455,7 +1455,7 @@ static int setup_subdevices(struct comedi_device *dev) s->type = COMEDI_SUBD_UNUSED; /* caldac */ - s = dev->subdevices + 6; + s = &dev->subdevices[6]; s->type = COMEDI_SUBD_CALIB; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; s->n_chan = 8; @@ -1469,7 +1469,7 @@ static int setup_subdevices(struct comedi_device *dev) caldac_write(dev, i, s->maxdata / 2); /* 2 channel ad8402 potentiometer */ - s = dev->subdevices + 7; + s = &dev->subdevices[7]; if (board(dev)->layout == LAYOUT_64XX) { s->type = COMEDI_SUBD_CALIB; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; @@ -1483,7 +1483,7 @@ static int setup_subdevices(struct comedi_device *dev) s->type = COMEDI_SUBD_UNUSED; /* serial EEPROM, if present */ - s = dev->subdevices + 8; + s = &dev->subdevices[8]; if (readl(priv(dev)->plx9080_iobase + PLX_CONTROL_REG) & CTL_EECHK) { s->type = COMEDI_SUBD_MEMORY; s->subdev_flags = SDF_READABLE | SDF_INTERNAL; @@ -1494,7 +1494,7 @@ static int setup_subdevices(struct comedi_device *dev) s->type = COMEDI_SUBD_UNUSED; /* user counter subd XXX */ - s = dev->subdevices + 9; + s = &dev->subdevices[9]; s->type = COMEDI_SUBD_UNUSED; return 0; @@ -1847,7 +1847,7 @@ static void detach(struct comedi_device *dev) } } if (dev->subdevices) - subdev_8255_cleanup(dev, dev->subdevices + 4); + subdev_8255_cleanup(dev, &dev->subdevices[4]); if (pcidev) { if (dev->iobase) comedi_pci_disable(pcidev); @@ -2108,74 +2108,50 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; - int tmp; unsigned int tmp_arg, tmp_arg2; int i; int aref; unsigned int triggers; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); - tmp = cmd->scan_begin_src; triggers = TRIG_TIMER; if (board(dev)->layout == LAYOUT_4020) triggers |= TRIG_OTHER; else triggers |= TRIG_FOLLOW; - cmd->scan_begin_src &= triggers; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + err |= cfc_check_trigger_src(&cmd->scan_begin_src, triggers); - tmp = cmd->convert_src; triggers = TRIG_TIMER; if (board(dev)->layout == LAYOUT_4020) triggers |= TRIG_NOW; else triggers |= TRIG_EXT; - cmd->convert_src &= triggers; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + err |= cfc_check_trigger_src(&cmd->convert_src, triggers); - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_EXT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, + TRIG_COUNT | TRIG_EXT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ - /* uniqueness check */ - if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) - err++; - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_OTHER && - cmd->scan_begin_src != TRIG_FOLLOW) - err++; - if (cmd->convert_src != TRIG_TIMER && - cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW) - err++; - if (cmd->stop_src != TRIG_COUNT && - cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_EXT) - err++; + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ - /* compatibility check */ if (cmd->convert_src == TRIG_EXT && cmd->scan_begin_src == TRIG_TIMER) - err++; + err |= -EINVAL; if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_EXT) - err++; + err |= -EINVAL; if (err) return 2; @@ -3466,55 +3442,33 @@ static int ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; - int tmp; unsigned int tmp_arg; int i; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_INT | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ - /* uniqueness check */ - if (cmd->start_src != TRIG_INT && cmd->start_src != TRIG_EXT) - err++; - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT) - err++; + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + + /* Step 2b : and mutually compatible */ - /* compatibility check */ if (cmd->convert_src == TRIG_EXT && cmd->scan_begin_src == TRIG_TIMER) - err++; + err |= -EINVAL; if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_EXT) - err++; + err |= -EINVAL; if (err) return 2; diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c index 12660a384e59..aef946df27e2 100644 --- a/drivers/staging/comedi/drivers/cb_pcidda.c +++ b/drivers/staging/comedi/drivers/cb_pcidda.c @@ -48,6 +48,7 @@ Please report success/failure with other different cards to #include "../comedidev.h" +#include "comedi_fc.h" #include "8255.h" /* PCI vendor number of ComputerBoards */ @@ -56,14 +57,6 @@ Please report success/failure with other different cards to /* maximum number of ao channels for supported boards */ #define MAX_AO_CHANNELS 8 -/* PCI-DDA base addresses */ -#define DIGITALIO_BADRINDEX 2 - /* DIGITAL I/O is pci_dev->resource[2] */ -#define DIGITALIO_SIZE 8 - /* DIGITAL I/O uses 8 I/O port addresses */ -#define DAC_BADRINDEX 3 - /* DAC is pci_dev->resource[3] */ - /* Digital I/O registers */ #define PORT1A 0 /* PORT 1A DATA */ @@ -203,11 +196,6 @@ static const struct cb_pcidda_board cb_pcidda_boards[] = { }; /* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct cb_pcidda_board *)dev->board_ptr) - -/* * this structure is for data unique to this hardware driver. If * several hardware drivers keep similar information in this structure, * feel free to suggest moving the variable to the struct comedi_device @@ -230,164 +218,6 @@ struct cb_pcidda_private { }; /* - * most drivers define the following macro to make it easy to - * access the private structure. - */ -#define devpriv ((struct cb_pcidda_private *)dev->private) - -/* static int cb_pcidda_ai_rinsn(struct comedi_device *dev,struct comedi_subdevice *s,struct comedi_insn *insn,unsigned int *data); */ -static int cb_pcidda_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -/* static int cb_pcidda_ai_cmd(struct comedi_device *dev, struct *comedi_subdevice *s);*/ -/* static int cb_pcidda_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd); */ -/* static int cb_pcidda_ns_to_timer(unsigned int *ns,int *round); */ - -static unsigned int cb_pcidda_serial_in(struct comedi_device *dev); -static void cb_pcidda_serial_out(struct comedi_device *dev, unsigned int value, - unsigned int num_bits); -static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev, - unsigned int address); -static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel, - unsigned int range); - -static struct pci_dev *cb_pcidda_find_pci_dev(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct pci_dev *pcidev = NULL; - int bus = it->options[0]; - int slot = it->options[1]; - int i; - - for_each_pci_dev(pcidev) { - if (bus || slot) { - if (bus != pcidev->bus->number || - slot != PCI_SLOT(pcidev->devfn)) - continue; - } - if (pcidev->vendor != PCI_VENDOR_ID_CB) - continue; - - for (i = 0; i < ARRAY_SIZE(cb_pcidda_boards); i++) { - if (cb_pcidda_boards[i].device_id != pcidev->device) - continue; - dev->board_ptr = cb_pcidda_boards + i; - return pcidev; - } - } - dev_err(dev->class_dev, - "No supported board found! (req. bus %d, slot %d)\n", - bus, slot); - return NULL; -} - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. - */ -static int cb_pcidda_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct pci_dev *pcidev; - struct comedi_subdevice *s; - int index; - int ret; - -/* - * Allocate the private structure area. - */ - if (alloc_private(dev, sizeof(struct cb_pcidda_private)) < 0) - return -ENOMEM; - - pcidev = cb_pcidda_find_pci_dev(dev, it); - if (!pcidev) - return -EIO; - comedi_set_hw_dev(dev, &pcidev->dev); - - /* - * Enable PCI device and request regions. - */ - if (comedi_pci_enable(pcidev, thisboard->name)) { - dev_err(dev->class_dev, - "cb_pcidda: failed to enable PCI device and request regions\n"); - return -EIO; - } - -/* - * Allocate the I/O ports. - */ - devpriv->digitalio = pci_resource_start(pcidev, DIGITALIO_BADRINDEX); - devpriv->dac = pci_resource_start(pcidev, DAC_BADRINDEX); - dev->iobase = devpriv->dac; - -/* - * Warn about the status of the driver. - */ - if (thisboard->status == 2) - printk - ("WARNING: DRIVER FOR THIS BOARD NOT CHECKED WITH MANUAL. " - "WORKS ASSUMING FULL COMPATIBILITY WITH PCI-DDA08/12. " - "PLEASE REPORT USAGE TO <ivanmr@altavista.com>.\n"); - -/* - * Initialize dev->board_name. - */ - dev->board_name = thisboard->name; - - ret = comedi_alloc_subdevices(dev, 3); - if (ret) - return ret; - - s = dev->subdevices + 0; - /* analog output subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = thisboard->ao_chans; - s->maxdata = (1 << thisboard->ao_bits) - 1; - s->range_table = thisboard->ranges; - s->insn_write = cb_pcidda_ao_winsn; - - /* s->subdev_flags |= SDF_CMD_READ; */ - /* s->do_cmd = cb_pcidda_ai_cmd; */ - /* s->do_cmdtest = cb_pcidda_ai_cmdtest; */ - - /* two 8255 digital io subdevices */ - s = dev->subdevices + 1; - subdev_8255_init(dev, s, NULL, devpriv->digitalio); - s = dev->subdevices + 2; - subdev_8255_init(dev, s, NULL, devpriv->digitalio + PORT2A); - - dev_dbg(dev->class_dev, "eeprom:\n"); - for (index = 0; index < EEPROM_SIZE; index++) { - devpriv->eeprom_data[index] = cb_pcidda_read_eeprom(dev, index); - dev_dbg(dev->class_dev, "%i:0x%x\n", index, - devpriv->eeprom_data[index]); - } - - /* set calibrations dacs */ - for (index = 0; index < thisboard->ao_chans; index++) - cb_pcidda_calibrate(dev, index, devpriv->ao_range[index]); - - return 1; -} - -static void cb_pcidda_detach(struct comedi_device *dev) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - - if (pcidev) { - if (dev->iobase) - comedi_pci_disable(pcidev); - pci_dev_put(pcidev); - } - if (dev->subdevices) { - subdev_8255_cleanup(dev, dev->subdevices + 1); - subdev_8255_cleanup(dev, dev->subdevices + 2); - } -} - -/* * I will program this later... ;-) */ #if 0 @@ -418,56 +248,26 @@ static int cb_pcidda_ai_cmdtest(struct comedi_device *dev, int err = 0; int tmp; - /* cmdtest tests a particular command to see if it is valid. - * Using the cmdtest ioctl, a user can create a valid cmd - * and then have it executes by the cmd ioctl. - * - * cmdtest returns 1,2,3,4 or 0, depending on which tests - * the command passes. */ - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, + TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* - * step 2: make sure trigger sources are unique and mutually - * compatible - */ + /* Step 2a : make sure trigger sources are unique */ - /* note that mutual compatibility is not an issue here */ - if (cmd->scan_begin_src != TRIG_TIMER - && cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_TIMER && cmd->stop_src != TRIG_EXT) - err++; + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -581,59 +381,10 @@ static int cb_pcidda_ns_to_timer(unsigned int *ns, int round) } #endif -static int cb_pcidda_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - unsigned int command; - unsigned int channel, range; - - channel = CR_CHAN(insn->chanspec); - range = CR_RANGE(insn->chanspec); - - /* adjust calibration dacs if range has changed */ - if (range != devpriv->ao_range[channel]) - cb_pcidda_calibrate(dev, channel, range); - - /* output channel configuration */ - command = NOSU | ENABLEDAC; - - /* output channel range */ - switch (range) { - case 0: - command |= BIP | RANGE10V; - break; - case 1: - command |= BIP | RANGE5V; - break; - case 2: - command |= BIP | RANGE2V5; - break; - case 3: - command |= UNIP | RANGE10V; - break; - case 4: - command |= UNIP | RANGE5V; - break; - case 5: - command |= UNIP | RANGE2V5; - break; - } - - /* output channel specification */ - command |= channel << 2; - outw(command, devpriv->dac + DACONTROL); - - /* write data */ - outw(data[0], devpriv->dac + DADATA + channel * 2); - - /* return the number of samples read/written */ - return 1; -} - /* lowlevel read from eeprom */ static unsigned int cb_pcidda_serial_in(struct comedi_device *dev) { + struct cb_pcidda_private *devpriv = dev->private; unsigned int value = 0; int i; const int value_width = 16; /* number of bits wide values are */ @@ -651,6 +402,7 @@ static unsigned int cb_pcidda_serial_in(struct comedi_device *dev) static void cb_pcidda_serial_out(struct comedi_device *dev, unsigned int value, unsigned int num_bits) { + struct cb_pcidda_private *devpriv = dev->private; int i; for (i = 1; i <= num_bits; i++) { @@ -667,6 +419,7 @@ static void cb_pcidda_serial_out(struct comedi_device *dev, unsigned int value, static unsigned int cb_pcidda_read_eeprom(struct comedi_device *dev, unsigned int address) { + struct cb_pcidda_private *devpriv = dev->private; unsigned int i; unsigned int cal2_bits; unsigned int value; @@ -703,6 +456,7 @@ static void cb_pcidda_write_caldac(struct comedi_device *dev, unsigned int caldac, unsigned int channel, unsigned int value) { + struct cb_pcidda_private *devpriv = dev->private; unsigned int cal2_bits; unsigned int i; /* caldacs use 3 bit channel specification */ @@ -797,6 +551,7 @@ static unsigned int eeprom_fine_byte(unsigned int word) static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel, unsigned int range) { + struct cb_pcidda_private *devpriv = dev->private; unsigned int coarse_offset, fine_offset, coarse_gain, fine_gain; /* remember range so we can tell when we need to readjust calibration */ @@ -827,10 +582,164 @@ static void cb_pcidda_calibrate(struct comedi_device *dev, unsigned int channel, fine_gain_channel(channel), fine_gain); } +static int cb_pcidda_ao_winsn(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct cb_pcidda_private *devpriv = dev->private; + unsigned int command; + unsigned int channel, range; + + channel = CR_CHAN(insn->chanspec); + range = CR_RANGE(insn->chanspec); + + /* adjust calibration dacs if range has changed */ + if (range != devpriv->ao_range[channel]) + cb_pcidda_calibrate(dev, channel, range); + + /* output channel configuration */ + command = NOSU | ENABLEDAC; + + /* output channel range */ + switch (range) { + case 0: + command |= BIP | RANGE10V; + break; + case 1: + command |= BIP | RANGE5V; + break; + case 2: + command |= BIP | RANGE2V5; + break; + case 3: + command |= UNIP | RANGE10V; + break; + case 4: + command |= UNIP | RANGE5V; + break; + case 5: + command |= UNIP | RANGE2V5; + break; + } + + /* output channel specification */ + command |= channel << 2; + outw(command, devpriv->dac + DACONTROL); + + /* write data */ + outw(data[0], devpriv->dac + DADATA + channel * 2); + + /* return the number of samples read/written */ + return 1; +} + +static const void *cb_pcidda_find_boardinfo(struct comedi_device *dev, + struct pci_dev *pcidev) +{ + const struct cb_pcidda_board *thisboard; + int i; + + for (i = 0; i < ARRAY_SIZE(cb_pcidda_boards); i++) { + thisboard = &cb_pcidda_boards[i]; + if (thisboard->device_id != pcidev->device) + return thisboard; + } + return NULL; +} + +static int cb_pcidda_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) +{ + const struct cb_pcidda_board *thisboard; + struct cb_pcidda_private *devpriv; + struct comedi_subdevice *s; + int index; + int ret; + + comedi_set_hw_dev(dev, &pcidev->dev); + + thisboard = cb_pcidda_find_boardinfo(dev, pcidev); + if (!pcidev) + return -ENODEV; + dev->board_ptr = thisboard; + dev->board_name = thisboard->name; + + ret = alloc_private(dev, sizeof(*devpriv)); + if (ret) + return ret; + devpriv = dev->private; + + ret = comedi_pci_enable(pcidev, dev->board_name); + if (ret) + return ret; + + devpriv->digitalio = pci_resource_start(pcidev, 2); + devpriv->dac = pci_resource_start(pcidev, 3); + dev->iobase = devpriv->dac; + + if (thisboard->status == 2) + printk + ("WARNING: DRIVER FOR THIS BOARD NOT CHECKED WITH MANUAL. " + "WORKS ASSUMING FULL COMPATIBILITY WITH PCI-DDA08/12. " + "PLEASE REPORT USAGE TO <ivanmr@altavista.com>.\n"); + + ret = comedi_alloc_subdevices(dev, 3); + if (ret) + return ret; + + s = &dev->subdevices[0]; + /* analog output subdevice */ + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = thisboard->ao_chans; + s->maxdata = (1 << thisboard->ao_bits) - 1; + s->range_table = thisboard->ranges; + s->insn_write = cb_pcidda_ao_winsn; + + /* s->subdev_flags |= SDF_CMD_READ; */ + /* s->do_cmd = cb_pcidda_ai_cmd; */ + /* s->do_cmdtest = cb_pcidda_ai_cmdtest; */ + + /* two 8255 digital io subdevices */ + s = &dev->subdevices[1]; + subdev_8255_init(dev, s, NULL, devpriv->digitalio); + s = &dev->subdevices[2]; + subdev_8255_init(dev, s, NULL, devpriv->digitalio + PORT2A); + + dev_dbg(dev->class_dev, "eeprom:\n"); + for (index = 0; index < EEPROM_SIZE; index++) { + devpriv->eeprom_data[index] = cb_pcidda_read_eeprom(dev, index); + dev_dbg(dev->class_dev, "%i:0x%x\n", index, + devpriv->eeprom_data[index]); + } + + /* set calibrations dacs */ + for (index = 0; index < thisboard->ao_chans; index++) + cb_pcidda_calibrate(dev, index, devpriv->ao_range[index]); + + dev_info(dev->class_dev, "%s attached\n", dev->board_name); + + return 0; +} + +static void cb_pcidda_detach(struct comedi_device *dev) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + + if (dev->subdevices) { + subdev_8255_cleanup(dev, &dev->subdevices[1]); + subdev_8255_cleanup(dev, &dev->subdevices[2]); + } + if (pcidev) { + if (dev->iobase) + comedi_pci_disable(pcidev); + } +} + static struct comedi_driver cb_pcidda_driver = { .driver_name = "cb_pcidda", .module = THIS_MODULE, - .attach = cb_pcidda_attach, + .attach_pci = cb_pcidda_attach_pci, .detach = cb_pcidda_detach, }; diff --git a/drivers/staging/comedi/drivers/cb_pcidio.c b/drivers/staging/comedi/drivers/cb_pcidio.c deleted file mode 100644 index e370d0d81bbd..000000000000 --- a/drivers/staging/comedi/drivers/cb_pcidio.c +++ /dev/null @@ -1,211 +0,0 @@ -/* - comedi/drivers/cb_pcidio.c - A Comedi driver for PCI-DIO24H & PCI-DIO48H of ComputerBoards (currently MeasurementComputing) - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 2000 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ -/* -Driver: cb_pcidio -Description: ComputerBoards' DIO boards with PCI interface -Devices: [Measurement Computing] PCI-DIO24 (cb_pcidio), PCI-DIO24H, PCI-DIO48H -Author: Yoshiya Matsuzaka -Updated: Mon, 29 Oct 2007 15:40:47 +0000 -Status: experimental - -This driver has been modified from skel.c of comedi-0.7.70. - -Configuration Options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - If bus/slot is not specified, the first available PCI device will - be used. - -Passing a zero for an option is the same as leaving it unspecified. -*/ - -/*------------------------------ HEADER FILES ---------------------------------*/ -#include "../comedidev.h" -#include "8255.h" - -/*-------------------------- MACROS and DATATYPES -----------------------------*/ -#define PCI_VENDOR_ID_CB 0x1307 - -/* - * Board descriptions for two imaginary boards. Describing the - * boards in this way is optional, and completely driver-dependent. - * Some drivers use arrays such as this, other do not. - */ -struct pcidio_board { - const char *name; /* name of the board */ - int dev_id; - int n_8255; /* number of 8255 chips on board */ - - /* indices of base address regions */ - int pcicontroler_badrindex; - int dioregs_badrindex; -}; - -static const struct pcidio_board pcidio_boards[] = { - { - .name = "pci-dio24", - .dev_id = 0x0028, - .n_8255 = 1, - .pcicontroler_badrindex = 1, - .dioregs_badrindex = 2, - }, - { - .name = "pci-dio24h", - .dev_id = 0x0014, - .n_8255 = 1, - .pcicontroler_badrindex = 1, - .dioregs_badrindex = 2, - }, - { - .name = "pci-dio48h", - .dev_id = 0x000b, - .n_8255 = 2, - .pcicontroler_badrindex = 0, - .dioregs_badrindex = 1, - }, -}; - -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct pcidio_board *)dev->board_ptr) - -static struct pci_dev *pcidio_find_pci_dev(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct pci_dev *pcidev = NULL; - int bus = it->options[0]; - int slot = it->options[1]; - int i; - - for_each_pci_dev(pcidev) { - if (bus || slot) { - if (bus != pcidev->bus->number || - slot != PCI_SLOT(pcidev->devfn)) - continue; - } - if (pcidev->vendor != PCI_VENDOR_ID_CB) - continue; - for (i = 0; i < ARRAY_SIZE(pcidio_boards); i++) { - if (pcidio_boards[i].dev_id != pcidev->device) - continue; - - dev->board_ptr = pcidio_boards + i; - return pcidev; - } - } - dev_err(dev->class_dev, - "No supported board found! (req. bus %d, slot %d)\n", - bus, slot); - return NULL; -} - -static int pcidio_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct pci_dev *pcidev; - int i; - int ret; - - pcidev = pcidio_find_pci_dev(dev, it); - if (!pcidev) - return -EIO; - comedi_set_hw_dev(dev, &pcidev->dev); - -/* - * Initialize dev->board_name. Note that we can use the "thisboard" - * macro now, since we just initialized it in the last line. - */ - dev->board_name = thisboard->name; - - if (comedi_pci_enable(pcidev, thisboard->name)) - return -EIO; - - dev->iobase = pci_resource_start(pcidev, thisboard->dioregs_badrindex); - - ret = comedi_alloc_subdevices(dev, thisboard->n_8255); - if (ret) - return ret; - - for (i = 0; i < thisboard->n_8255; i++) { - subdev_8255_init(dev, dev->subdevices + i, - NULL, dev->iobase + i * 4); - dev_dbg(dev->class_dev, "subdev %d: base = 0x%lx\n", i, - dev->iobase + i * 4); - } - - return 1; -} - -static void pcidio_detach(struct comedi_device *dev) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - - if (pcidev) { - if (dev->iobase) - comedi_pci_disable(pcidev); - pci_dev_put(pcidev); - } - if (dev->subdevices) { - int i; - for (i = 0; i < thisboard->n_8255; i++) - subdev_8255_cleanup(dev, dev->subdevices + i); - } -} - -static struct comedi_driver cb_pcidio_driver = { - .driver_name = "cb_pcidio", - .module = THIS_MODULE, - .attach = pcidio_attach, - .detach = pcidio_detach, -}; - -static int __devinit cb_pcidio_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) -{ - return comedi_pci_auto_config(dev, &cb_pcidio_driver); -} - -static void __devexit cb_pcidio_pci_remove(struct pci_dev *dev) -{ - comedi_pci_auto_unconfig(dev); -} - -static DEFINE_PCI_DEVICE_TABLE(cb_pcidio_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0028) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x0014) }, - { PCI_DEVICE(PCI_VENDOR_ID_CB, 0x000b) }, - { 0 } -}; -MODULE_DEVICE_TABLE(pci, cb_pcidio_pci_table); - -static struct pci_driver cb_pcidio_pci_driver = { - .name = "cb_pcidio", - .id_table = cb_pcidio_pci_table, - .probe = cb_pcidio_pci_probe, - .remove = __devexit_p(cb_pcidio_pci_remove), -}; -module_comedi_pci_driver(cb_pcidio_driver, cb_pcidio_pci_driver); - -MODULE_AUTHOR("Comedi http://www.comedi.org"); -MODULE_DESCRIPTION("Comedi low-level driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/cb_pcimdas.c b/drivers/staging/comedi/drivers/cb_pcimdas.c index c632a89f3ae9..9515b6926662 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdas.c +++ b/drivers/staging/comedi/drivers/cb_pcimdas.c @@ -119,11 +119,6 @@ static const struct cb_pcimdas_board cb_pcimdas_boards[] = { }; /* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct cb_pcimdas_board *)dev->board_ptr) - -/* * this structure is for data unique to this hardware driver. If * several hardware drivers keep similar information in this structure, * feel free to suggest moving the variable to the struct comedi_device @@ -138,160 +133,6 @@ struct cb_pcimdas_private { }; /* - * most drivers define the following macro to make it easy to - * access the private structure. - */ -#define devpriv ((struct cb_pcimdas_private *)dev->private) - -static int cb_pcimdas_ai_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int cb_pcimdas_ao_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int cb_pcimdas_ao_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); - -static struct pci_dev *cb_pcimdas_find_pci_dev(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct pci_dev *pcidev = NULL; - int bus = it->options[0]; - int slot = it->options[1]; - int i; - - for_each_pci_dev(pcidev) { - if (bus || slot) { - if (bus != pcidev->bus->number || - slot != PCI_SLOT(pcidev->devfn)) - continue; - } - if (pcidev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS) - continue; - - for (i = 0; i < ARRAY_SIZE(cb_pcimdas_boards); i++) { - if (cb_pcimdas_boards[i].device_id != pcidev->device) - continue; - - dev->board_ptr = cb_pcimdas_boards + i; - return pcidev; - } - } - dev_err(dev->class_dev, - "No supported board found! (req. bus %d, slot %d)\n", - bus, slot); - return NULL; -} - -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ -static int cb_pcimdas_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct pci_dev *pcidev; - struct comedi_subdevice *s; - unsigned long iobase_8255; - int ret; - -/* - * Allocate the private structure area. - */ - if (alloc_private(dev, sizeof(struct cb_pcimdas_private)) < 0) - return -ENOMEM; - - pcidev = cb_pcimdas_find_pci_dev(dev, it); - if (!pcidev) - return -EIO; - comedi_set_hw_dev(dev, &pcidev->dev); - - /* Warn about non-tested features */ - switch (thisboard->device_id) { - case 0x56: - break; - default: - dev_dbg(dev->class_dev, "THIS CARD IS UNSUPPORTED.\n"); - dev_dbg(dev->class_dev, - "PLEASE REPORT USAGE TO <mocelet@sucs.org>\n"); - } - - if (comedi_pci_enable(pcidev, "cb_pcimdas")) { - dev_err(dev->class_dev, - "Failed to enable PCI device and request regions\n"); - return -EIO; - } - - dev->iobase = pci_resource_start(pcidev, 2); - devpriv->BADR3 = pci_resource_start(pcidev, 3); - iobase_8255 = pci_resource_start(pcidev, 4); - -/* Dont support IRQ yet */ -/* get irq */ -/* if(request_irq(pcidev->irq, cb_pcimdas_interrupt, IRQF_SHARED, "cb_pcimdas", dev )) */ -/* { */ -/* printk(" unable to allocate irq %u\n", pcidev->irq); */ -/* return -EINVAL; */ -/* } */ -/* dev->irq = pcidev->irq; */ - - /* Initialize dev->board_name */ - dev->board_name = thisboard->name; - - ret = comedi_alloc_subdevices(dev, 3); - if (ret) - return ret; - - s = dev->subdevices + 0; - /* dev->read_subdev=s; */ - /* analog input subdevice */ - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = thisboard->ai_se_chans; - s->maxdata = (1 << thisboard->ai_bits) - 1; - s->range_table = &range_unknown; - s->len_chanlist = 1; /* This is the maximum chanlist length that */ - /* the board can handle */ - s->insn_read = cb_pcimdas_ai_rinsn; - - s = dev->subdevices + 1; - /* analog output subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = thisboard->ao_nchan; - s->maxdata = 1 << thisboard->ao_bits; - /* ranges are hardware settable, but not software readable. */ - s->range_table = &range_unknown; - s->insn_write = &cb_pcimdas_ao_winsn; - s->insn_read = &cb_pcimdas_ao_rinsn; - - s = dev->subdevices + 2; - /* digital i/o subdevice */ - if (thisboard->has_dio) - subdev_8255_init(dev, s, NULL, iobase_8255); - else - s->type = COMEDI_SUBD_UNUSED; - - return 1; -} - -static void cb_pcimdas_detach(struct comedi_device *dev) -{ - struct pci_dev *pcidev = comedi_to_pci_dev(dev); - - if (dev->irq) - free_irq(dev->irq, dev); - if (pcidev) { - if (dev->iobase) - comedi_pci_disable(pcidev); - pci_dev_put(pcidev); - } -} - -/* * "instructions" read/write data in "one-shot" or "software-triggered" * mode. */ @@ -299,6 +140,8 @@ static int cb_pcimdas_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + const struct cb_pcimdas_board *thisboard = comedi_board(dev); + struct cb_pcimdas_private *devpriv = dev->private; int n, i; unsigned int d; unsigned int busy; @@ -368,6 +211,7 @@ static int cb_pcimdas_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct cb_pcimdas_private *devpriv = dev->private; int i; int chan = CR_CHAN(insn->chanspec); @@ -397,6 +241,7 @@ static int cb_pcimdas_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct cb_pcimdas_private *devpriv = dev->private; int i; int chan = CR_CHAN(insn->chanspec); @@ -406,10 +251,124 @@ static int cb_pcimdas_ao_rinsn(struct comedi_device *dev, return i; } +static const void *cb_pcimdas_find_boardinfo(struct comedi_device *dev, + struct pci_dev *pcidev) +{ + const struct cb_pcimdas_board *thisboard; + int i; + + for (i = 0; i < ARRAY_SIZE(cb_pcimdas_boards); i++) { + thisboard = &cb_pcimdas_boards[i]; + if (thisboard->device_id == pcidev->device) + return thisboard; + } + return NULL; +} + +static int cb_pcimdas_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) +{ + const struct cb_pcimdas_board *thisboard; + struct cb_pcimdas_private *devpriv; + struct comedi_subdevice *s; + unsigned long iobase_8255; + int ret; + + comedi_set_hw_dev(dev, &pcidev->dev); + + thisboard = cb_pcimdas_find_boardinfo(dev, pcidev); + if (!thisboard) + return -ENODEV; + dev->board_ptr = thisboard; + dev->board_name = thisboard->name; + + ret = alloc_private(dev, sizeof(*devpriv)); + if (ret) + return ret; + devpriv = dev->private; + + /* Warn about non-tested features */ + switch (thisboard->device_id) { + case 0x56: + break; + default: + dev_dbg(dev->class_dev, "THIS CARD IS UNSUPPORTED.\n"); + dev_dbg(dev->class_dev, + "PLEASE REPORT USAGE TO <mocelet@sucs.org>\n"); + } + + ret = comedi_pci_enable(pcidev, dev->board_name); + if (ret) + return ret; + + dev->iobase = pci_resource_start(pcidev, 2); + devpriv->BADR3 = pci_resource_start(pcidev, 3); + iobase_8255 = pci_resource_start(pcidev, 4); + +/* Dont support IRQ yet */ +/* get irq */ +/* if(request_irq(pcidev->irq, cb_pcimdas_interrupt, IRQF_SHARED, "cb_pcimdas", dev )) */ +/* { */ +/* printk(" unable to allocate irq %u\n", pcidev->irq); */ +/* return -EINVAL; */ +/* } */ +/* dev->irq = pcidev->irq; */ + + ret = comedi_alloc_subdevices(dev, 3); + if (ret) + return ret; + + s = &dev->subdevices[0]; + /* dev->read_subdev=s; */ + /* analog input subdevice */ + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = thisboard->ai_se_chans; + s->maxdata = (1 << thisboard->ai_bits) - 1; + s->range_table = &range_unknown; + s->len_chanlist = 1; /* This is the maximum chanlist length that */ + /* the board can handle */ + s->insn_read = cb_pcimdas_ai_rinsn; + + s = &dev->subdevices[1]; + /* analog output subdevice */ + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = thisboard->ao_nchan; + s->maxdata = 1 << thisboard->ao_bits; + /* ranges are hardware settable, but not software readable. */ + s->range_table = &range_unknown; + s->insn_write = &cb_pcimdas_ao_winsn; + s->insn_read = &cb_pcimdas_ao_rinsn; + + s = &dev->subdevices[2]; + /* digital i/o subdevice */ + if (thisboard->has_dio) + subdev_8255_init(dev, s, NULL, iobase_8255); + else + s->type = COMEDI_SUBD_UNUSED; + + dev_info(dev->class_dev, "%s attached\n", dev->board_name); + + return 0; +} + +static void cb_pcimdas_detach(struct comedi_device *dev) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + + if (dev->irq) + free_irq(dev->irq, dev); + if (pcidev) { + if (dev->iobase) + comedi_pci_disable(pcidev); + } +} + static struct comedi_driver cb_pcimdas_driver = { .driver_name = "cb_pcimdas", .module = THIS_MODULE, - .attach = cb_pcimdas_attach, + .attach_pci = cb_pcimdas_attach_pci, .detach = cb_pcimdas_detach, }; diff --git a/drivers/staging/comedi/drivers/cb_pcimdda.c b/drivers/staging/comedi/drivers/cb_pcimdda.c index a80146133c04..ba9f0599be28 100644 --- a/drivers/staging/comedi/drivers/cb_pcimdda.c +++ b/drivers/staging/comedi/drivers/cb_pcimdda.c @@ -57,12 +57,7 @@ output modes on the board: then issue one comedi_data_read() on any channel on the AO subdevice to initiate the simultaneous XFER. -Configuration Options: - [0] PCI bus (optional) - [1] PCI slot (optional) - [2] analog output range jumper setting - 0 == +/- 5 V - 1 == +/- 10 V +Configuration Options: not applicable, uses PCI auto config */ /* @@ -93,337 +88,133 @@ Configuration Options: #define PCI_ID_PCIM_DDA06_16 0x0053 /* - * This is straight from skel.c -- I did this in case this source file - * will someday support more than 1 board... + * Register map, 8-bit access only */ -struct board_struct { - const char *name; - unsigned short device_id; - int ao_chans; - int ao_bits; - int dio_chans; - int dio_method; - /* how many bytes into the BADR are the DIO ports */ - int dio_offset; - int regs_badrindex; /* IO Region for the control, analog output, - and DIO registers */ - int reg_sz; /* number of bytes of registers in io region */ -}; +#define PCIMDDA_DA_CHAN(x) (0x00 + (x) * 2) +#define PCIMDDA_8255_BASE_REG 0x0c -enum DIO_METHODS { - DIO_NONE = 0, - DIO_8255, - DIO_INTERNAL /* unimplemented */ -}; +#define MAX_AO_READBACK_CHANNELS 6 -static const struct board_struct boards[] = { - { - .name = "cb_pcimdda06-16", - .device_id = PCI_ID_PCIM_DDA06_16, - .ao_chans = 6, - .ao_bits = 16, - .dio_chans = 24, - .dio_method = DIO_8255, - .dio_offset = 12, - .regs_badrindex = 3, - .reg_sz = 16, - } +struct cb_pcimdda_private { + unsigned int ao_readback[MAX_AO_READBACK_CHANNELS]; }; -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct board_struct *)dev->board_ptr) - -#define REG_SZ (thisboard->reg_sz) -#define REGS_BADRINDEX (thisboard->regs_badrindex) - -/* - * this structure is for data unique to this hardware driver. If - * several hardware drivers keep similar information in this structure, - * feel free to suggest moving the variable to the struct comedi_device - * struct. - */ -struct board_private_struct { - unsigned long registers; /* set by probe */ - unsigned long dio_registers; - char attached_to_8255; /* boolean */ - /* would be useful for a PCI device */ - struct pci_dev *pci_dev; - -#define MAX_AO_READBACK_CHANNELS 6 - /* Used for AO readback */ - unsigned int ao_readback[MAX_AO_READBACK_CHANNELS]; +static int cb_pcimdda_ao_winsn(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) +{ + struct cb_pcimdda_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned long offset = dev->iobase + PCIMDDA_DA_CHAN(chan); + unsigned int val = 0; + int i; -}; + for (i = 0; i < insn->n; i++) { + val = data[i]; -/* - * most drivers define the following macro to make it easy to - * access the private structure. - */ -#define devpriv ((struct board_private_struct *)dev->private) + /* + * Write the LSB then MSB. + * + * If the simultaneous xfer mode is selected by the + * jumper on the card, a read instruction is needed + * in order to initiate the simultaneous transfer. + * Otherwise, the DAC will be updated when the MSB + * is written. + */ + outb(val & 0x00ff, offset); + outb((val >> 8) & 0x00ff, offset + 1); + } -static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); -static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data); + /* Cache the last value for readback */ + devpriv->ao_readback[chan] = val; -/*--------------------------------------------------------------------------- - HELPER FUNCTION DECLARATIONS ------------------------------------------------------------------------------*/ + return insn->n; +} -/* returns a maxdata value for a given n_bits */ -static inline unsigned int figure_out_maxdata(int bits) +static int cb_pcimdda_ao_rinsn(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, + unsigned int *data) { - return ((unsigned int)1 << bits) - 1; -} + struct cb_pcimdda_private *devpriv = dev->private; + int chan = CR_CHAN(insn->chanspec); + unsigned long offset = dev->iobase + PCIMDDA_DA_CHAN(chan); + int i; -/* - * Probes for a supported device. - * - * Prerequisite: private be allocated already inside dev - * - * If the device is found, it returns 0 and has the following side effects: - * - * o assigns a struct pci_dev * to dev->private->pci_dev - * o assigns a struct board * to dev->board_ptr - * o sets dev->private->registers - * o sets dev->private->dio_registers - * - * Otherwise, returns a -errno on error - */ -static int probe(struct comedi_device *dev, const struct comedi_devconfig *it); + for (i = 0; i < insn->n; i++) { + /* Initiate the simultaneous transfer */ + inw(offset); + + data[i] = devpriv->ao_readback[chan]; + } -/*--------------------------------------------------------------------------- - FUNCTION DEFINITIONS ------------------------------------------------------------------------------*/ + return insn->n; +} -/* - * Attach is called by the Comedi core to configure the driver - * for a particular board. If you specified a board_name array - * in the driver structure, dev->board_ptr contains that - * address. - */ -static int attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int cb_pcimdda_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) { + struct cb_pcimdda_private *devpriv; struct comedi_subdevice *s; - int err; + int ret; -/* - * Allocate the private structure area. alloc_private() is a - * convenient macro defined in comedidev.h. - * if this function fails (returns negative) then the private area is - * kfree'd by comedi - */ - if (alloc_private(dev, sizeof(struct board_private_struct)) < 0) - return -ENOMEM; + comedi_set_hw_dev(dev, &pcidev->dev); + dev->board_name = dev->driver->driver_name; -/* - * If you can probe the device to determine what device in a series - * it is, this is the place to do it. Otherwise, dev->board_ptr - * should already be initialized. - */ - err = probe(dev, it); - if (err) - return err; + ret = alloc_private(dev, sizeof(*devpriv)); + if (ret) + return ret; + devpriv = dev->private; -/* Output some info */ - printk("comedi%d: %s: ", dev->minor, thisboard->name); + ret = comedi_pci_enable(pcidev, dev->board_name); + if (ret) + return ret; + dev->iobase = pci_resource_start(pcidev, 3); -/* - * Initialize dev->board_name. Note that we can use the "thisboard" - * macro now, since we just initialized it in the last line. - */ - dev->board_name = thisboard->name; - - err = comedi_alloc_subdevices(dev, 2); - if (err) - return err; - - s = dev->subdevices + 0; + ret = comedi_alloc_subdevices(dev, 2); + if (ret) + return ret; + s = &dev->subdevices[0]; /* analog output subdevice */ - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE; - s->n_chan = thisboard->ao_chans; - s->maxdata = figure_out_maxdata(thisboard->ao_bits); - /* this is hard-coded here */ - if (it->options[2]) - s->range_table = &range_bipolar10; - else - s->range_table = &range_bipolar5; - s->insn_write = &ao_winsn; - s->insn_read = &ao_rinsn; - - s = dev->subdevices + 1; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + s->n_chan = 6; + s->maxdata = 0xffff; + s->range_table = &range_bipolar5; + s->insn_write = cb_pcimdda_ao_winsn; + s->insn_read = cb_pcimdda_ao_rinsn; + + s = &dev->subdevices[1]; /* digital i/o subdevice */ - if (thisboard->dio_chans) { - switch (thisboard->dio_method) { - case DIO_8255: - /* - * this is a straight 8255, so register us with - * the 8255 driver - */ - subdev_8255_init(dev, s, NULL, devpriv->dio_registers); - devpriv->attached_to_8255 = 1; - break; - case DIO_INTERNAL: - default: - printk("DIO_INTERNAL not implemented yet!\n"); - return -ENXIO; - break; - } - } else { - s->type = COMEDI_SUBD_UNUSED; - } + ret = subdev_8255_init(dev, s, NULL, + dev->iobase + PCIMDDA_8255_BASE_REG); + if (ret) + return ret; - printk("attached\n"); + dev_info(dev->class_dev, "%s attached\n", dev->board_name); return 1; } -static void detach(struct comedi_device *dev) -{ - if (devpriv) { - if (dev->subdevices && devpriv->attached_to_8255) { - subdev_8255_cleanup(dev, dev->subdevices + 2); - devpriv->attached_to_8255 = 0; - } - if (devpriv->pci_dev) { - if (devpriv->registers) - comedi_pci_disable(devpriv->pci_dev); - pci_dev_put(devpriv->pci_dev); - } - } -} - -static int ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void cb_pcimdda_detach(struct comedi_device *dev) { - int i; - int chan = CR_CHAN(insn->chanspec); - unsigned long offset = devpriv->registers + chan * 2; + struct pci_dev *pcidev = comedi_to_pci_dev(dev); - /* Writing a list of values to an AO channel is probably not - * very useful, but that's how the interface is defined. */ - for (i = 0; i < insn->n; i++) { - /* first, load the low byte */ - outb((char)(data[i] & 0x00ff), offset); - /* next, write the high byte -- only after this is written is - the channel voltage updated in the DAC, unless - we're in simultaneous xfer mode (jumper on card) - then a rinsn is necessary to actually update the DAC -- - see ao_rinsn() below... */ - outb((char)(data[i] >> 8 & 0x00ff), offset + 1); - - /* for testing only.. the actual rinsn SHOULD do an inw! - (see the stuff about simultaneous XFER mode on this board) */ - devpriv->ao_readback[chan] = data[i]; + if (dev->subdevices) + subdev_8255_cleanup(dev, &dev->subdevices[1]); + if (pcidev) { + if (dev->iobase) + comedi_pci_disable(pcidev); } - - /* return the number of samples read/written */ - return i; -} - -/* AO subdevices should have a read insn as well as a write insn. - - Usually this means copying a value stored in devpriv->ao_readback. - However, since this board has this jumper setting called "Simultaneous - Xfer mode" (off by default), we will support it. Simultaneaous xfer - mode is accomplished by loading ALL the values you want for AO in all the - channels, then READing off one of the AO registers to initiate the - instantaneous simultaneous update of all DAC outputs, which makes - all AO channels update simultaneously. This is useful for some control - applications, I would imagine. -*/ -static int ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) -{ - int i; - int chan = CR_CHAN(insn->chanspec); - - for (i = 0; i < insn->n; i++) { - inw(devpriv->registers + chan * 2); - /* - * should I set data[i] to the result of the actual read - * on the register or the cached unsigned int in - * devpriv->ao_readback[]? - */ - data[i] = devpriv->ao_readback[chan]; - } - - return i; -} - -/*--------------------------------------------------------------------------- - HELPER FUNCTION DEFINITIONS ------------------------------------------------------------------------------*/ - -/* - * Probes for a supported device. - * - * Prerequisite: private be allocated already inside dev - * - * If the device is found, it returns 0 and has the following side effects: - * - * o assigns a struct pci_dev * to dev->private->pci_dev - * o assigns a struct board * to dev->board_ptr - * o sets dev->private->registers - * o sets dev->private->dio_registers - * - * Otherwise, returns a -errno on error - */ -static int probe(struct comedi_device *dev, const struct comedi_devconfig *it) -{ - struct pci_dev *pcidev = NULL; - int index; - unsigned long registers; - - for_each_pci_dev(pcidev) { - /* is it not a computer boards card? */ - if (pcidev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS) - continue; - /* loop through cards supported by this driver */ - for (index = 0; index < ARRAY_SIZE(boards); index++) { - if (boards[index].device_id != pcidev->device) - continue; - /* was a particular bus/slot requested? */ - if (it->options[0] || it->options[1]) { - /* are we on the wrong bus/slot? */ - if (pcidev->bus->number != it->options[0] || - PCI_SLOT(pcidev->devfn) != it->options[1]) { - continue; - } - } - /* found ! */ - - devpriv->pci_dev = pcidev; - dev->board_ptr = boards + index; - if (comedi_pci_enable(pcidev, thisboard->name)) { - printk - ("cb_pcimdda: Failed to enable PCI device and request regions\n"); - return -EIO; - } - registers = - pci_resource_start(devpriv->pci_dev, - REGS_BADRINDEX); - devpriv->registers = registers; - devpriv->dio_registers - = devpriv->registers + thisboard->dio_offset; - return 0; - } - } - - printk("cb_pcimdda: No supported ComputerBoards/MeasurementComputing " - "card found at the requested position\n"); - return -ENODEV; } static struct comedi_driver cb_pcimdda_driver = { .driver_name = "cb_pcimdda", .module = THIS_MODULE, - .attach = attach, - .detach = detach, + .attach_pci = cb_pcimdda_attach_pci, + .detach = cb_pcimdda_detach, }; static int __devinit cb_pcimdda_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c index 5ed324c4f620..5c768bc76eb1 100644 --- a/drivers/staging/comedi/drivers/comedi_bond.c +++ b/drivers/staging/comedi/drivers/comedi_bond.c @@ -59,40 +59,6 @@ Configuration Options: /* The maxiumum number of channels per subdevice. */ #define MAX_CHANS 256 -#define MODULE_NAME "comedi_bond" -#ifndef STR -# define STR1(x) #x -# define STR(x) STR1(x) -#endif - -static int debug; -module_param(debug, int, 0644); -MODULE_PARM_DESC(debug, "If true, print extra cryptic debugging output useful" - "only to developers."); - -#define LOG_MSG(x...) printk(KERN_INFO MODULE_NAME": "x) -#define DEBUG(x...) \ - do { \ - if (debug) \ - printk(KERN_DEBUG MODULE_NAME": DEBUG: "x); \ - } while (0) -#define WARNING(x...) printk(KERN_WARNING MODULE_NAME ": WARNING: "x) -#define ERROR(x...) printk(KERN_ERR MODULE_NAME ": INTERNAL ERROR: "x) - -/* - * Board descriptions for two imaginary boards. Describing the - * boards in this way is optional, and completely driver-dependent. - * Some drivers use arrays such as this, other do not. - */ -struct BondingBoard { - const char *name; -}; - -/* - * Useful for shorthand access to the particular board structure - */ -#define thisboard ((const struct BondingBoard *)dev->board_ptr) - struct BondedDevice { struct comedi_device *dev; unsigned minor; @@ -107,7 +73,7 @@ struct BondedDevice { /* this structure is for data unique to this hardware driver. If several hardware drivers keep similar information in this structure, feel free to suggest moving the variable to the struct comedi_device struct. */ -struct Private { +struct comedi_bond_private { # define MAX_BOARD_NAME 256 char name[MAX_BOARD_NAME]; struct BondedDevice **devs; @@ -116,12 +82,6 @@ struct Private { unsigned nchans; }; -/* - * most drivers define the following macro to make it easy to - * access the private structure. - */ -#define devpriv ((struct Private *)dev->private) - /* DIO devices are slightly special. Although it is possible to * implement the insn_read/insn_write interface, it is much more * useful to applications if you implement the insn_bits interface. @@ -131,6 +91,7 @@ static int bonding_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct comedi_bond_private *devpriv = dev->private; #define LSAMPL_BITS (sizeof(unsigned int)*8) unsigned nchans = LSAMPL_BITS, num_done = 0, i; @@ -177,6 +138,7 @@ static int bonding_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct comedi_bond_private *devpriv = dev->private; int chan = CR_CHAN(insn->chanspec), ret, io_bits = s->io_bits; unsigned int io; struct BondedDevice *bdev; @@ -230,6 +192,7 @@ static void *Realloc(const void *oldmem, size_t newlen, size_t oldlen) static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it) { + struct comedi_bond_private *devpriv = dev->private; int i; struct comedi_device *devs_opened[COMEDI_NUM_BOARD_MINORS]; @@ -245,15 +208,18 @@ static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it) struct BondedDevice *bdev = NULL; if (minor < 0 || minor >= COMEDI_NUM_BOARD_MINORS) { - ERROR("Minor %d is invalid!\n", minor); + dev_err(dev->class_dev, + "Minor %d is invalid!\n", minor); return 0; } if (minor == dev->minor) { - ERROR("Cannot bond this driver to itself!\n"); + dev_err(dev->class_dev, + "Cannot bond this driver to itself!\n"); return 0; } if (devs_opened[minor]) { - ERROR("Minor %d specified more than once!\n", minor); + dev_err(dev->class_dev, + "Minor %d specified more than once!\n", minor); return 0; } @@ -263,7 +229,8 @@ static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it) d = devs_opened[minor] = comedi_open(file); if (!d) { - ERROR("Minor %u could not be opened\n", minor); + dev_err(dev->class_dev, + "Minor %u could not be opened\n", minor); return 0; } @@ -272,14 +239,14 @@ static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it) sdev + 1)) > -1) { nchans = comedi_get_n_channels(d, sdev); if (nchans <= 0) { - ERROR("comedi_get_n_channels() returned %d " - "on minor %u subdev %d!\n", - nchans, minor, sdev); + dev_err(dev->class_dev, + "comedi_get_n_channels() returned %d on minor %u subdev %d!\n", + nchans, minor, sdev); return 0; } bdev = kmalloc(sizeof(*bdev), GFP_KERNEL); if (!bdev) { - ERROR("Out of memory.\n"); + dev_err(dev->class_dev, "Out of memory\n"); return 0; } bdev->dev = d; @@ -302,8 +269,8 @@ static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it) Realloc(devpriv->devs, ++devpriv->ndevs * sizeof(bdev), tmp); if (!devpriv->devs) { - ERROR("Could not allocate memory. " - "Out of memory?"); + dev_err(dev->class_dev, + "Could not allocate memory. Out of memory?\n"); return 0; } @@ -323,7 +290,7 @@ static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it) } if (!devpriv->nchans) { - ERROR("No channels found!\n"); + dev_err(dev->class_dev, "No channels found!\n"); return 0; } @@ -333,35 +300,28 @@ static int doDevConfig(struct comedi_device *dev, struct comedi_devconfig *it) static int bonding_attach(struct comedi_device *dev, struct comedi_devconfig *it) { + struct comedi_bond_private *devpriv; struct comedi_subdevice *s; int ret; - LOG_MSG("comedi%d\n", dev->minor); - - /* - * Allocate the private structure area. alloc_private() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_private(dev, sizeof(struct Private)) < 0) - return -ENOMEM; + ret = alloc_private(dev, sizeof(*devpriv)); + if (ret) + return ret; + devpriv = dev->private; /* - * Setup our bonding from config params.. sets up our Private struct.. + * Setup our bonding from config params.. sets up our private struct.. */ if (!doDevConfig(dev, it)) return -EINVAL; - /* - * Initialize dev->board_name. Note that we can use the "thisboard" - * macro now, since we just initialized it in the last line. - */ dev->board_name = devpriv->name; ret = comedi_alloc_subdevices(dev, 1); if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = devpriv->nchans; @@ -370,9 +330,9 @@ static int bonding_attach(struct comedi_device *dev, s->insn_bits = bonding_dio_insn_bits; s->insn_config = bonding_dio_insn_config; - LOG_MSG("attached with %u DIO channels coming from %u different " - "subdevices all bonded together. " - "John Lennon would be proud!\n", + dev_info(dev->class_dev, + "%s: %s attached, %u channels from %u devices\n", + dev->driver->driver_name, dev->board_name, devpriv->nchans, devpriv->ndevs); return 1; @@ -380,6 +340,7 @@ static int bonding_attach(struct comedi_device *dev, static void bonding_detach(struct comedi_device *dev) { + struct comedi_bond_private *devpriv = dev->private; unsigned long devs_closed = 0; if (devpriv) { @@ -402,25 +363,16 @@ static void bonding_detach(struct comedi_device *dev) } } -static const struct BondingBoard bondingBoards[] = { - { - .name = "comedi_bond", - }, -}; - static struct comedi_driver bonding_driver = { .driver_name = "comedi_bond", .module = THIS_MODULE, .attach = bonding_attach, .detach = bonding_detach, - .board_name = &bondingBoards[0].name, - .offset = sizeof(struct BondingBoard), - .num_names = ARRAY_SIZE(bondingBoards), }; module_comedi_driver(bonding_driver); MODULE_AUTHOR("Calin A. Culianu"); -MODULE_DESCRIPTION(MODULE_NAME "A driver for COMEDI to bond multiple COMEDI " +MODULE_DESCRIPTION("comedi_bond: A driver for COMEDI to bond multiple COMEDI " "devices together as one. In the words of John Lennon: " "'And the world will live as one...'"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/comedi_fc.h b/drivers/staging/comedi/drivers/comedi_fc.h index 4b2cfd327995..94481c637a0a 100644 --- a/drivers/staging/comedi/drivers/comedi_fc.h +++ b/drivers/staging/comedi/drivers/comedi_fc.h @@ -73,4 +73,36 @@ static inline unsigned int cfc_bytes_per_scan(struct comedi_subdevice *subd) return num_samples * bytes_per_sample(subd); } +/** + * cfc_check_trigger_src() - trivially validate a comedi_cmd trigger source + * @src: pointer to the trigger source to validate + * @flags: bitmask of valid TRIG_* for the trigger + * + * This is used in "step 1" of the do_cmdtest functions of comedi drivers + * to vaildate the comedi_cmd triggers. The mask of the @src against the + * @flags allows the userspace comedilib to pass all the comedi_cmd + * triggers as TRIG_ANY and get back a bitmask of the valid trigger sources. + */ +static inline int cfc_check_trigger_src(unsigned int *src, unsigned int flags) +{ + unsigned int orig_src = *src; + + *src = orig_src & flags; + if (*src == TRIG_INVALID || *src != orig_src) + return -EINVAL; + return 0; +} + +/** + * cfc_check_trigger_is_unique() - make sure a trigger source is unique + * @src: the trigger source to check + */ +static inline int cfc_check_trigger_is_unique(unsigned int src) +{ + /* this test is true if more than one _src bit is set */ + if ((src & (src - 1)) != 0) + return -EINVAL; + return 0; +} + #endif /* _COMEDI_FC_H */ diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/staging/comedi/drivers/comedi_parport.c index 9a63cac2434a..22ef94242590 100644 --- a/drivers/staging/comedi/drivers/comedi_parport.c +++ b/drivers/staging/comedi/drivers/comedi_parport.c @@ -85,6 +85,8 @@ pin, which can be used to wake up tasks. #include <linux/interrupt.h> #include <linux/ioport.h> +#include "comedi_fc.h" + #define PARPORT_SIZE 3 #define PARPORT_A 0 @@ -96,11 +98,12 @@ struct parport_private { unsigned int c_data; int enable_irq; }; -#define devpriv ((struct parport_private *)(dev->private)) static int parport_insn_a(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct parport_private *devpriv = dev->private; + if (data[0]) { devpriv->a_data &= ~data[0]; devpriv->a_data |= (data[0] & data[1]); @@ -117,6 +120,8 @@ static int parport_insn_config_a(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct parport_private *devpriv = dev->private; + if (data[0]) { s->io_bits = 0xff; devpriv->c_data &= ~(1 << 5); @@ -145,6 +150,8 @@ static int parport_insn_b(struct comedi_device *dev, struct comedi_subdevice *s, static int parport_insn_c(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct parport_private *devpriv = dev->private; + data[0] &= 0x0f; if (data[0]) { devpriv->c_data &= ~data[0]; @@ -171,39 +178,20 @@ static int parport_intr_cmdtest(struct comedi_device *dev, struct comedi_cmd *cmd) { int err = 0; - int tmp; - - /* step 1 */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_FOLLOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE); if (err) return 1; - /* step 2: ignored */ + /* Step 2a : make sure trigger sources are unique */ + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -245,6 +233,8 @@ static int parport_intr_cmdtest(struct comedi_device *dev, static int parport_intr_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct parport_private *devpriv = dev->private; + devpriv->c_data |= 0x10; outb(devpriv->c_data, dev->iobase + PARPORT_C); @@ -256,7 +246,7 @@ static int parport_intr_cmd(struct comedi_device *dev, static int parport_intr_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { - printk(KERN_DEBUG "parport_intr_cancel()\n"); + struct parport_private *devpriv = dev->private; devpriv->c_data &= ~0x10; outb(devpriv->c_data, dev->iobase + PARPORT_C); @@ -269,12 +259,11 @@ static int parport_intr_cancel(struct comedi_device *dev, static irqreturn_t parport_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 3; + struct parport_private *devpriv = dev->private; + struct comedi_subdevice *s = &dev->subdevices[3]; - if (!devpriv->enable_irq) { - printk(KERN_ERR "comedi_parport: bogus irq, ignored\n"); + if (!devpriv->enable_irq) return IRQ_NONE; - } comedi_buf_put(s->async, 0); s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; @@ -286,41 +275,42 @@ static irqreturn_t parport_interrupt(int irq, void *d) static int parport_attach(struct comedi_device *dev, struct comedi_devconfig *it) { + struct parport_private *devpriv; int ret; unsigned int irq; unsigned long iobase; struct comedi_subdevice *s; + dev->board_name = dev->driver->driver_name; + iobase = it->options[0]; - printk(KERN_INFO "comedi%d: parport: 0x%04lx ", dev->minor, iobase); - if (!request_region(iobase, PARPORT_SIZE, "parport (comedi)")) { - printk(KERN_ERR "I/O port conflict\n"); + if (!request_region(iobase, PARPORT_SIZE, dev->board_name)) { + dev_err(dev->class_dev, "I/O port conflict\n"); return -EIO; } dev->iobase = iobase; irq = it->options[1]; if (irq) { - printk(KERN_INFO " irq=%u", irq); - ret = request_irq(irq, parport_interrupt, 0, "comedi_parport", + ret = request_irq(irq, parport_interrupt, 0, dev->board_name, dev); if (ret < 0) { - printk(KERN_ERR " irq not available\n"); + dev_err(dev->class_dev, "irq not available\n"); return -EINVAL; } dev->irq = irq; } - dev->board_name = "parport"; ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; - ret = alloc_private(dev, sizeof(struct parport_private)); + ret = alloc_private(dev, sizeof(*devpriv)); if (ret < 0) return ret; + devpriv = dev->private; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = 8; @@ -329,7 +319,7 @@ static int parport_attach(struct comedi_device *dev, s->insn_bits = parport_insn_a; s->insn_config = parport_insn_config_a; - s = dev->subdevices + 1; + s = &dev->subdevices[1]; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; s->n_chan = 5; @@ -337,7 +327,7 @@ static int parport_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = parport_insn_b; - s = dev->subdevices + 2; + s = &dev->subdevices[2]; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE; s->n_chan = 4; @@ -345,7 +335,7 @@ static int parport_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = parport_insn_c; - s = dev->subdevices + 3; + s = &dev->subdevices[3]; if (irq) { dev->read_subdev = s; s->type = COMEDI_SUBD_DI; @@ -366,8 +356,10 @@ static int parport_attach(struct comedi_device *dev, devpriv->c_data = 0; outb(devpriv->c_data, dev->iobase + PARPORT_C); - printk(KERN_INFO "\n"); - return 1; + dev_info(dev->class_dev, "%s: iobase=0x%04lx, irq %sabled", + dev->board_name, dev->iobase, dev->irq ? "en" : "dis"); + + return 0; } static void parport_detach(struct comedi_device *dev) diff --git a/drivers/staging/comedi/drivers/comedi_test.c b/drivers/staging/comedi/drivers/comedi_test.c index 523a809708b7..7817def1556c 100644 --- a/drivers/staging/comedi/drivers/comedi_test.c +++ b/drivers/staging/comedi/drivers/comedi_test.c @@ -57,14 +57,6 @@ zero volts). #include "comedi_fc.h" #include <linux/timer.h> -/* Board descriptions */ -struct waveform_board { - const char *name; - int ai_chans; - int ai_bits; - int have_dio; -}; - #define N_CHANS 8 /* Data unique to this driver */ @@ -81,7 +73,6 @@ struct waveform_private { unsigned timer_running:1; unsigned int ao_loopbacks[N_CHANS]; }; -#define devpriv ((struct waveform_private *)dev->private) /* 1000 nanosec in a microsec */ static const int nano_per_micro = 1000; @@ -98,6 +89,7 @@ static const struct comedi_lrange waveform_ai_ranges = { static short fake_sawtooth(struct comedi_device *dev, unsigned int range_index, unsigned long current_time) { + struct waveform_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; unsigned int offset = s->maxdata / 2; u64 value; @@ -122,6 +114,7 @@ static short fake_squarewave(struct comedi_device *dev, unsigned int range_index, unsigned long current_time) { + struct waveform_private *devpriv = dev->private; struct comedi_subdevice *s = dev->read_subdev; unsigned int offset = s->maxdata / 2; u64 value; @@ -175,6 +168,7 @@ static short fake_waveform(struct comedi_device *dev, unsigned int channel, static void waveform_ai_interrupt(unsigned long arg) { struct comedi_device *dev = (struct comedi_device *)arg; + struct waveform_private *devpriv = dev->private; struct comedi_async *async = dev->read_subdev->async; struct comedi_cmd *cmd = &async->cmd; unsigned int i, j; @@ -237,44 +231,23 @@ static int waveform_ai_cmdtest(struct comedi_device *dev, int err = 0; int tmp; - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW | TRIG_TIMER; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW | TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* - * step 2: make sure trigger sources are unique and mutually compatible - */ + /* Step 2a : make sure trigger sources are unique */ - if (cmd->convert_src != TRIG_NOW && cmd->convert_src != TRIG_TIMER) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -362,6 +335,7 @@ static int waveform_ai_cmdtest(struct comedi_device *dev, static int waveform_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { + struct waveform_private *devpriv = dev->private; struct comedi_cmd *cmd = &s->async->cmd; if (cmd->flags & TRIG_RT) { @@ -395,6 +369,8 @@ static int waveform_ai_cmd(struct comedi_device *dev, static int waveform_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s) { + struct waveform_private *devpriv = dev->private; + devpriv->timer_running = 0; del_timer(&devpriv->timer); return 0; @@ -404,6 +380,7 @@ static int waveform_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct waveform_private *devpriv = dev->private; int i, chan = CR_CHAN(insn->chanspec); for (i = 0; i < insn->n; i++) @@ -416,6 +393,7 @@ static int waveform_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct waveform_private *devpriv = dev->private; int i, chan = CR_CHAN(insn->chanspec); for (i = 0; i < insn->n; i++) @@ -427,17 +405,19 @@ static int waveform_ao_insn_write(struct comedi_device *dev, static int waveform_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct waveform_board *board = comedi_board(dev); + struct waveform_private *devpriv; struct comedi_subdevice *s; int amplitude = it->options[0]; int period = it->options[1]; int i; int ret; - dev->board_name = board->name; + dev->board_name = dev->driver->driver_name; - if (alloc_private(dev, sizeof(struct waveform_private)) < 0) - return -ENOMEM; + ret = alloc_private(dev, sizeof(*devpriv)); + if (ret < 0) + return ret; + devpriv = dev->private; /* set default amplitude and period */ if (amplitude <= 0) @@ -452,13 +432,13 @@ static int waveform_attach(struct comedi_device *dev, if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; dev->read_subdev = s; /* analog input subdevice */ s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; - s->n_chan = board->ai_chans; - s->maxdata = (1 << board->ai_bits) - 1; + s->n_chan = N_CHANS; + s->maxdata = 0xffff; s->range_table = &waveform_ai_ranges; s->len_chanlist = s->n_chan * 2; s->insn_read = waveform_ai_insn_read; @@ -466,13 +446,13 @@ static int waveform_attach(struct comedi_device *dev, s->do_cmdtest = waveform_ai_cmdtest; s->cancel = waveform_ai_cancel; - s = dev->subdevices + 1; + s = &dev->subdevices[1]; dev->write_subdev = s; /* analog output subdevice (loopback) */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITEABLE | SDF_GROUND; - s->n_chan = board->ai_chans; - s->maxdata = (1 << board->ai_bits) - 1; + s->n_chan = N_CHANS; + s->maxdata = 0xffff; s->range_table = &waveform_ai_ranges; s->len_chanlist = s->n_chan * 2; s->insn_write = waveform_ao_insn_write; @@ -488,35 +468,27 @@ static int waveform_attach(struct comedi_device *dev, devpriv->timer.function = waveform_ai_interrupt; devpriv->timer.data = (unsigned long)dev; - printk(KERN_INFO "comedi%d: comedi_test: " - "%i microvolt, %li microsecond waveform attached\n", dev->minor, - devpriv->uvolt_amplitude, devpriv->usec_period); - return 1; + dev_info(dev->class_dev, + "%s: %i microvolt, %li microsecond waveform attached\n", + dev->board_name, + devpriv->uvolt_amplitude, devpriv->usec_period); + + return 0; } static void waveform_detach(struct comedi_device *dev) { - if (dev->private) + struct waveform_private *devpriv = dev->private; + + if (devpriv) waveform_ai_cancel(dev, dev->read_subdev); } -static const struct waveform_board waveform_boards[] = { - { - .name = "comedi_test", - .ai_chans = N_CHANS, - .ai_bits = 16, - .have_dio = 0, - }, -}; - static struct comedi_driver waveform_driver = { .driver_name = "comedi_test", .module = THIS_MODULE, .attach = waveform_attach, .detach = waveform_detach, - .board_name = &waveform_boards[0].name, - .offset = sizeof(struct waveform_board), - .num_names = ARRAY_SIZE(waveform_boards), }; module_comedi_driver(waveform_driver); diff --git a/drivers/staging/comedi/drivers/contec_pci_dio.c b/drivers/staging/comedi/drivers/contec_pci_dio.c index 944cfeeb2b2d..178a6a4bb7d5 100644 --- a/drivers/staging/comedi/drivers/contec_pci_dio.c +++ b/drivers/staging/comedi/drivers/contec_pci_dio.c @@ -27,51 +27,35 @@ Author: Stefano Rivoir <s.rivoir@gts.it> Updated: Wed, 27 Jun 2007 13:00:06 +0100 Status: works -Configuration Options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - If bus/slot is not specified, the first supported - PCI device found will be used. +Configuration Options: not applicable, uses comedi PCI auto config */ #include "../comedidev.h" -enum contec_model { - PIO1616L = 0, -}; - -struct contec_board { - const char *name; - int model; - int in_ports; - int out_ports; - int in_offs; - int out_offs; - int out_boffs; -}; -static const struct contec_board contec_boards[] = { - {"PIO1616L", PIO1616L, 16, 16, 0, 2, 10}, -}; - #define PCI_DEVICE_ID_PIO1616L 0x8172 -#define thisboard ((const struct contec_board *)dev->board_ptr) +/* + * Register map + */ +#define PIO1616L_DI_REG 0x00 +#define PIO1616L_DO_REG 0x02 static int contec_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + unsigned int mask = data[0]; + unsigned int bits = data[1]; - dev_dbg(dev->class_dev, "contec_do_insn_bits called\n"); - dev_dbg(dev->class_dev, "data: %d %d\n", data[0], data[1]); + if (mask) { + s->state &= ~mask; + s->state |= (bits & mask); - if (data[0]) { - s->state &= ~data[0]; - s->state |= data[0] & data[1]; - dev_dbg(dev->class_dev, "out: %d on %lx\n", s->state, - dev->iobase + thisboard->out_offs); - outw(s->state, dev->iobase + thisboard->out_offs); + outw(s->state, dev->iobase + PIO1616L_DO_REG); } + + data[1] = s->state; + return insn->n; } @@ -79,87 +63,49 @@ static int contec_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - - dev_dbg(dev->class_dev, "contec_di_insn_bits called\n"); - dev_dbg(dev->class_dev, "data: %d %d\n", data[0], data[1]); - - data[1] = inw(dev->iobase + thisboard->in_offs); + data[1] = inw(dev->iobase + PIO1616L_DI_REG); return insn->n; } -static struct pci_dev *contec_find_pci_dev(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct pci_dev *pcidev = NULL; - int bus = it->options[0]; - int slot = it->options[1]; - - for_each_pci_dev(pcidev) { - if (bus || slot) { - if (bus != pcidev->bus->number || - slot != PCI_SLOT(pcidev->devfn)) - continue; - } - if (pcidev->vendor != PCI_VENDOR_ID_CONTEC || - pcidev->device != PCI_DEVICE_ID_PIO1616L) - continue; - - dev->board_ptr = contec_boards + 0; - return pcidev; - } - dev_err(dev->class_dev, - "No supported board found! (req. bus %d, slot %d)\n", - bus, slot); - return NULL; -} - -static int contec_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int contec_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) { - struct pci_dev *pcidev; struct comedi_subdevice *s; int ret; - printk("comedi%d: contec: ", dev->minor); + comedi_set_hw_dev(dev, &pcidev->dev); - dev->board_name = thisboard->name; + dev->board_name = dev->driver->driver_name; - ret = comedi_alloc_subdevices(dev, 2); + ret = comedi_pci_enable(pcidev, dev->board_name); if (ret) return ret; - - pcidev = contec_find_pci_dev(dev, it); - if (!pcidev) - return -EIO; - comedi_set_hw_dev(dev, &pcidev->dev); - - if (comedi_pci_enable(pcidev, "contec_pci_dio")) { - printk("error enabling PCI device and request regions!\n"); - return -EIO; - } dev->iobase = pci_resource_start(pcidev, 0); - printk(" base addr %lx ", dev->iobase); - s = dev->subdevices + 0; - - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = 16; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = contec_di_insn_bits; - - s = dev->subdevices + 1; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE; - s->n_chan = 16; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = contec_do_insn_bits; - - printk("attached\n"); + ret = comedi_alloc_subdevices(dev, 2); + if (ret) + return ret; - return 1; + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = contec_di_insn_bits; + + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE; + s->n_chan = 16; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = contec_do_insn_bits; + + dev_info(dev->class_dev, "%s attached\n", dev->board_name); + + return 0; } static void contec_detach(struct comedi_device *dev) @@ -169,14 +115,13 @@ static void contec_detach(struct comedi_device *dev) if (pcidev) { if (dev->iobase) comedi_pci_disable(pcidev); - pci_dev_put(pcidev); } } static struct comedi_driver contec_pci_dio_driver = { .driver_name = "contec_pci_dio", .module = THIS_MODULE, - .attach = contec_attach, + .attach_pci = contec_attach_pci, .detach = contec_detach, }; @@ -192,8 +137,7 @@ static void __devexit contec_pci_dio_pci_remove(struct pci_dev *dev) } static DEFINE_PCI_DEVICE_TABLE(contec_pci_dio_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_CONTEC, PCI_DEVICE_ID_PIO1616L), - .driver_data = PIO1616L }, + { PCI_DEVICE(PCI_VENDOR_ID_CONTEC, PCI_DEVICE_ID_PIO1616L) }, { 0 } }; MODULE_DEVICE_TABLE(pci, contec_pci_dio_pci_table); diff --git a/drivers/staging/comedi/drivers/daqboard2000.c b/drivers/staging/comedi/drivers/daqboard2000.c index cad559a1a730..d13c8c5822bf 100644 --- a/drivers/staging/comedi/drivers/daqboard2000.c +++ b/drivers/staging/comedi/drivers/daqboard2000.c @@ -31,16 +31,10 @@ Devices: [IOTech] DAQBoard/2000 (daqboard2000) Much of the functionality of this driver was determined from reading the source code for the Windows driver. -The FPGA on the board requires initialization code, which can -be loaded by comedi_config using the -i -option. The initialization code is available from http://www.comedi.org -in the comedi_nonfree_firmware tarball. - -Configuration options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - If bus/slot is not specified, the first supported - PCI device found will be used. +The FPGA on the board requires fimware, which is available from +http://www.comedi.org in the comedi_nonfree_firmware tarball. + +Configuration options: not applicable, uses PCI auto config */ /* This card was obviously never intended to leave the Windows world, @@ -117,17 +111,17 @@ Configuration options: #include <linux/delay.h> #include <linux/interrupt.h> +#include <linux/firmware.h> #include "8255.h" +#define DAQBOARD2000_FIRMWARE "daqboard2000_firmware.bin" + #define PCI_VENDOR_ID_IOTECH 0x1616 #define DAQBOARD2000_SUBSYSTEM_IDS2 0x0002 /* Daqboard/2000 - 2 Dacs */ #define DAQBOARD2000_SUBSYSTEM_IDS4 0x0004 /* Daqboard/2000 - 4 Dacs */ -#define DAQBOARD2000_DAQ_SIZE 0x1002 -#define DAQBOARD2000_PLX_SIZE 0x100 - /* Initialization bits for the Serial EEPROM Control Register */ #define DAQBOARD2000_SECRProgPinHi 0x8001767e #define DAQBOARD2000_SECRProgPinLo 0x8000767e @@ -143,85 +137,56 @@ Configuration options: #define DAQBOARD2000_CPLD_INIT 0x0002 #define DAQBOARD2000_CPLD_DONE 0x0004 -/* Available ranges */ -static const struct comedi_lrange range_daqboard2000_ai = { 13, { - RANGE(-10, 10), - RANGE(-5, 5), - RANGE(-2.5, - 2.5), - RANGE(-1.25, - 1.25), - RANGE(-0.625, - 0.625), - RANGE(-0.3125, - 0.3125), - RANGE(-0.156, - 0.156), - RANGE(0, 10), - RANGE(0, 5), - RANGE(0, 2.5), - RANGE(0, 1.25), - RANGE(0, - 0.625), - RANGE(0, - 0.3125) - } -}; - -static const struct comedi_lrange range_daqboard2000_ao = { 1, { - RANGE(-10, 10) - } +static const struct comedi_lrange range_daqboard2000_ai = { + 13, { + BIP_RANGE(10), + BIP_RANGE(5), + BIP_RANGE(2.5), + BIP_RANGE(1.25), + BIP_RANGE(0.625), + BIP_RANGE(0.3125), + BIP_RANGE(0.156), + UNI_RANGE(10), + UNI_RANGE(5), + UNI_RANGE(2.5), + UNI_RANGE(1.25), + UNI_RANGE(0.625), + UNI_RANGE(0.3125) + } }; -struct daqboard2000_hw { - volatile u16 acqControl; /* 0x00 */ - volatile u16 acqScanListFIFO; /* 0x02 */ - volatile u32 acqPacerClockDivLow; /* 0x04 */ - - volatile u16 acqScanCounter; /* 0x08 */ - volatile u16 acqPacerClockDivHigh; /* 0x0a */ - volatile u16 acqTriggerCount; /* 0x0c */ - volatile u16 fill2; /* 0x0e */ - volatile u16 acqResultsFIFO; /* 0x10 */ - volatile u16 fill3; /* 0x12 */ - volatile u16 acqResultsShadow; /* 0x14 */ - volatile u16 fill4; /* 0x16 */ - volatile u16 acqAdcResult; /* 0x18 */ - volatile u16 fill5; /* 0x1a */ - volatile u16 dacScanCounter; /* 0x1c */ - volatile u16 fill6; /* 0x1e */ - - volatile u16 dacControl; /* 0x20 */ - volatile u16 fill7; /* 0x22 */ - volatile s16 dacFIFO; /* 0x24 */ - volatile u16 fill8[2]; /* 0x26 */ - volatile u16 dacPacerClockDiv; /* 0x2a */ - volatile u16 refDacs; /* 0x2c */ - volatile u16 fill9; /* 0x2e */ - - volatile u16 dioControl; /* 0x30 */ - volatile s16 dioP3hsioData; /* 0x32 */ - volatile u16 dioP3Control; /* 0x34 */ - volatile u16 calEepromControl; /* 0x36 */ - volatile s16 dacSetting[4]; /* 0x38 */ - volatile s16 dioP2ExpansionIO8Bit[32]; /* 0x40 */ - - volatile u16 ctrTmrControl; /* 0x80 */ - volatile u16 fill10[3]; /* 0x82 */ - volatile s16 ctrInput[4]; /* 0x88 */ - volatile u16 fill11[8]; /* 0x90 */ - volatile u16 timerDivisor[2]; /* 0xa0 */ - volatile u16 fill12[6]; /* 0xa4 */ - - volatile u16 dmaControl; /* 0xb0 */ - volatile u16 trigControl; /* 0xb2 */ - volatile u16 fill13[2]; /* 0xb4 */ - volatile u16 calEeprom; /* 0xb8 */ - volatile u16 acqDigitalMark; /* 0xba */ - volatile u16 trigDacs; /* 0xbc */ - volatile u16 fill14; /* 0xbe */ - volatile s16 dioP2ExpansionIO16Bit[32]; /* 0xc0 */ -}; +/* + * Register Memory Map + */ +#define acqControl 0x00 /* u16 */ +#define acqScanListFIFO 0x02 /* u16 */ +#define acqPacerClockDivLow 0x04 /* u32 */ +#define acqScanCounter 0x08 /* u16 */ +#define acqPacerClockDivHigh 0x0a /* u16 */ +#define acqTriggerCount 0x0c /* u16 */ +#define acqResultsFIFO 0x10 /* u16 */ +#define acqResultsShadow 0x14 /* u16 */ +#define acqAdcResult 0x18 /* u16 */ +#define dacScanCounter 0x1c /* u16 */ +#define dacControl 0x20 /* u16 */ +#define dacFIFO 0x24 /* s16 */ +#define dacPacerClockDiv 0x2a /* u16 */ +#define refDacs 0x2c /* u16 */ +#define dioControl 0x30 /* u16 */ +#define dioP3hsioData 0x32 /* s16 */ +#define dioP3Control 0x34 /* u16 */ +#define calEepromControl 0x36 /* u16 */ +#define dacSetting(x) (0x38 + (x)*2) /* s16 */ +#define dioP2ExpansionIO8Bit 0x40 /* s16 */ +#define ctrTmrControl 0x80 /* u16 */ +#define ctrInput(x) (0x88 + (x)*2) /* s16 */ +#define timerDivisor(x) (0xa0 + (x)*2) /* u16 */ +#define dmaControl 0xb0 /* u16 */ +#define trigControl 0xb2 /* u16 */ +#define calEeprom 0xb8 /* u16 */ +#define acqDigitalMark 0xba /* u16 */ +#define trigDacs 0xbc /* u16 */ +#define dioP2ExpansionIO16Bit(x) (0xc0 + (x)*2) /* s16 */ /* Scan Sequencer programming */ #define DAQBOARD2000_SeqStartScanList 0x0011 @@ -311,27 +276,23 @@ static const struct daq200_boardtype boardtypes[] = { {"ids4", DAQBOARD2000_SUBSYSTEM_IDS4}, }; -#define this_board ((const struct daq200_boardtype *)dev->board_ptr) - struct daqboard2000_private { enum { card_daqboard_2000 } card; - void *daq; + void __iomem *daq; void __iomem *plx; unsigned int ao_readback[2]; }; -#define devpriv ((struct daqboard2000_private *)dev->private) - static void writeAcqScanListEntry(struct comedi_device *dev, u16 entry) { - struct daqboard2000_hw *fpga = devpriv->daq; + struct daqboard2000_private *devpriv = dev->private; -/* udelay(4); */ - fpga->acqScanListFIFO = entry & 0x00ff; -/* udelay(4); */ - fpga->acqScanListFIFO = (entry >> 8) & 0x00ff; + /* udelay(4); */ + writew(entry & 0x00ff, devpriv->daq + acqScanListFIFO); + /* udelay(4); */ + writew((entry >> 8) & 0x00ff, devpriv->daq + acqScanListFIFO); } static void setup_sampling(struct comedi_device *dev, int chan, int gain) @@ -372,7 +333,6 @@ static void setup_sampling(struct comedi_device *dev, int chan, int gain) /* These should be read from EEPROM */ word2 |= 0x0800; word3 |= 0xc000; -/* printk("%d %4.4x %4.4x %4.4x %4.4x\n", chan, word0, word1, word2, word3);*/ writeAcqScanListEntry(dev, word0); writeAcqScanListEntry(dev, word1); writeAcqScanListEntry(dev, word2); @@ -384,21 +344,22 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - int i; - struct daqboard2000_hw *fpga = devpriv->daq; + struct daqboard2000_private *devpriv = dev->private; + unsigned int val; int gain, chan, timeout; + int i; - fpga->acqControl = - DAQBOARD2000_AcqResetScanListFifo | - DAQBOARD2000_AcqResetResultsFifo | DAQBOARD2000_AcqResetConfigPipe; + writew(DAQBOARD2000_AcqResetScanListFifo | + DAQBOARD2000_AcqResetResultsFifo | + DAQBOARD2000_AcqResetConfigPipe, devpriv->daq + acqControl); /* * If pacer clock is not set to some high value (> 10 us), we * risk multiple samples to be put into the result FIFO. */ /* 1 second, should be long enough */ - fpga->acqPacerClockDivLow = 1000000; - fpga->acqPacerClockDivHigh = 0; + writel(1000000, devpriv->daq + acqPacerClockDivLow); + writew(0, devpriv->daq + acqPacerClockDivHigh); gain = CR_RANGE(insn->chanspec); chan = CR_CHAN(insn->chanspec); @@ -410,28 +371,30 @@ static int daqboard2000_ai_insn_read(struct comedi_device *dev, for (i = 0; i < insn->n; i++) { setup_sampling(dev, chan, gain); /* Enable reading from the scanlist FIFO */ - fpga->acqControl = DAQBOARD2000_SeqStartScanList; + writew(DAQBOARD2000_SeqStartScanList, + devpriv->daq + acqControl); for (timeout = 0; timeout < 20; timeout++) { - if (fpga->acqControl & DAQBOARD2000_AcqConfigPipeFull) + val = readw(devpriv->daq + acqControl); + if (val & DAQBOARD2000_AcqConfigPipeFull) break; /* udelay(2); */ } - fpga->acqControl = DAQBOARD2000_AdcPacerEnable; + writew(DAQBOARD2000_AdcPacerEnable, devpriv->daq + acqControl); for (timeout = 0; timeout < 20; timeout++) { - if (fpga->acqControl & DAQBOARD2000_AcqLogicScanning) + val = readw(devpriv->daq + acqControl); + if (val & DAQBOARD2000_AcqLogicScanning) break; /* udelay(2); */ } for (timeout = 0; timeout < 20; timeout++) { - if (fpga->acqControl & - DAQBOARD2000_AcqResultsFIFOHasValidData) { + val = readw(devpriv->daq + acqControl); + if (val & DAQBOARD2000_AcqResultsFIFOHasValidData) break; - } /* udelay(2); */ } - data[i] = fpga->acqResultsFIFO; - fpga->acqControl = DAQBOARD2000_AdcPacerDisable; - fpga->acqControl = DAQBOARD2000_SeqStopScanList; + data[i] = readw(devpriv->daq + acqResultsFIFO); + writew(DAQBOARD2000_AdcPacerDisable, devpriv->daq + acqControl); + writew(DAQBOARD2000_SeqStopScanList, devpriv->daq + acqControl); } return i; @@ -442,8 +405,9 @@ static int daqboard2000_ao_insn_read(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - int i; + struct daqboard2000_private *devpriv = dev->private; int chan = CR_CHAN(insn->chanspec); + int i; for (i = 0; i < insn->n; i++) data[i] = devpriv->ao_readback[chan]; @@ -456,28 +420,39 @@ static int daqboard2000_ao_insn_write(struct comedi_device *dev, struct comedi_insn *insn, unsigned int *data) { - int i; + struct daqboard2000_private *devpriv = dev->private; int chan = CR_CHAN(insn->chanspec); - struct daqboard2000_hw *fpga = devpriv->daq; + unsigned int val; int timeout; + int i; for (i = 0; i < insn->n; i++) { +#if 0 /* - * OK, since it works OK without enabling the DAC's, let's keep - * it as simple as possible... + * OK, since it works OK without enabling the DAC's, + * let's keep it as simple as possible... */ - /* fpga->dacControl = (chan + 2) * 0x0010 | 0x0001; udelay(1000); */ - fpga->dacSetting[chan] = data[i]; + writew((chan + 2) * 0x0010 | 0x0001, + devpriv->daq + dacControl); + udelay(1000); +#endif + writew(data[i], devpriv->daq + dacSetting(chan)); for (timeout = 0; timeout < 20; timeout++) { - if ((fpga->dacControl & ((chan + 1) * 0x0010)) == 0) + val = readw(devpriv->daq + dacControl); + if ((val & ((chan + 1) * 0x0010)) == 0) break; /* udelay(2); */ } devpriv->ao_readback[chan] = data[i]; +#if 0 /* - * Since we never enabled the DAC's, we don't need to disable it... - * fpga->dacControl = (chan + 2) * 0x0010 | 0x0000; udelay(1000); + * Since we never enabled the DAC's, we don't need + * to disable it... */ + writew((chan + 2) * 0x0010 | 0x0000, + devpriv->daq + dacControl); + udelay(1000); +#endif } return i; @@ -485,7 +460,8 @@ static int daqboard2000_ao_insn_write(struct comedi_device *dev, static void daqboard2000_resetLocalBus(struct comedi_device *dev) { - dev_dbg(dev->class_dev, "daqboard2000_resetLocalBus\n"); + struct daqboard2000_private *devpriv = dev->private; + writel(DAQBOARD2000_SECRLocalBusHi, devpriv->plx + 0x6c); udelay(10000); writel(DAQBOARD2000_SECRLocalBusLo, devpriv->plx + 0x6c); @@ -494,7 +470,8 @@ static void daqboard2000_resetLocalBus(struct comedi_device *dev) static void daqboard2000_reloadPLX(struct comedi_device *dev) { - dev_dbg(dev->class_dev, "daqboard2000_reloadPLX\n"); + struct daqboard2000_private *devpriv = dev->private; + writel(DAQBOARD2000_SECRReloadLo, devpriv->plx + 0x6c); udelay(10000); writel(DAQBOARD2000_SECRReloadHi, devpriv->plx + 0x6c); @@ -505,7 +482,8 @@ static void daqboard2000_reloadPLX(struct comedi_device *dev) static void daqboard2000_pulseProgPin(struct comedi_device *dev) { - dev_dbg(dev->class_dev, "daqboard2000_pulseProgPin 1\n"); + struct daqboard2000_private *devpriv = dev->private; + writel(DAQBOARD2000_SECRProgPinHi, devpriv->plx + 0x6c); udelay(10000); writel(DAQBOARD2000_SECRProgPinLo, devpriv->plx + 0x6c); @@ -514,6 +492,7 @@ static void daqboard2000_pulseProgPin(struct comedi_device *dev) static int daqboard2000_pollCPLD(struct comedi_device *dev, int mask) { + struct daqboard2000_private *devpriv = dev->private; int result = 0; int i; int cpld; @@ -533,6 +512,7 @@ static int daqboard2000_pollCPLD(struct comedi_device *dev, int mask) static int daqboard2000_writeCPLD(struct comedi_device *dev, int data) { + struct daqboard2000_private *devpriv = dev->private; int result = 0; udelay(10); @@ -545,41 +525,29 @@ static int daqboard2000_writeCPLD(struct comedi_device *dev, int data) } static int initialize_daqboard2000(struct comedi_device *dev, - unsigned char *cpld_array, int len) + const u8 *cpld_array, size_t len) { + struct daqboard2000_private *devpriv = dev->private; int result = -EIO; /* Read the serial EEPROM control register */ int secr; int retry; - int i; + size_t i; /* Check to make sure the serial eeprom is present on the board */ secr = readl(devpriv->plx + 0x6c); - if (!(secr & DAQBOARD2000_EEPROM_PRESENT)) { -#ifdef DEBUG_EEPROM - dev_dbg(dev->class_dev, "no serial eeprom\n"); -#endif + if (!(secr & DAQBOARD2000_EEPROM_PRESENT)) return -EIO; - } for (retry = 0; retry < 3; retry++) { -#ifdef DEBUG_EEPROM - dev_dbg(dev->class_dev, "Programming EEPROM try %x\n", retry); -#endif - daqboard2000_resetLocalBus(dev); daqboard2000_reloadPLX(dev); daqboard2000_pulseProgPin(dev); if (daqboard2000_pollCPLD(dev, DAQBOARD2000_CPLD_INIT)) { for (i = 0; i < len; i++) { - if (cpld_array[i] == 0xff - && cpld_array[i + 1] == 0x20) { -#ifdef DEBUG_EEPROM - dev_dbg(dev->class_dev, - "Preamble found at %d\n", i); -#endif + if (cpld_array[i] == 0xff && + cpld_array[i + 1] == 0x20) break; - } } for (; i < len; i += 2) { int data = @@ -588,9 +556,6 @@ static int initialize_daqboard2000(struct comedi_device *dev, break; } if (i >= len) { -#ifdef DEBUG_EEPROM - dev_dbg(dev->class_dev, "Programmed\n"); -#endif daqboard2000_resetLocalBus(dev); daqboard2000_reloadPLX(dev); result = 0; @@ -601,28 +566,45 @@ static int initialize_daqboard2000(struct comedi_device *dev, return result; } +static int daqboard2000_upload_firmware(struct comedi_device *dev) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, DAQBOARD2000_FIRMWARE, &pcidev->dev); + if (ret) + return ret; + + ret = initialize_daqboard2000(dev, fw->data, fw->size); + release_firmware(fw); + + return ret; +} + static void daqboard2000_adcStopDmaTransfer(struct comedi_device *dev) { -/* printk("Implement: daqboard2000_adcStopDmaTransfer\n");*/ } static void daqboard2000_adcDisarm(struct comedi_device *dev) { - struct daqboard2000_hw *fpga = devpriv->daq; + struct daqboard2000_private *devpriv = dev->private; /* Disable hardware triggers */ udelay(2); - fpga->trigControl = DAQBOARD2000_TrigAnalog | DAQBOARD2000_TrigDisable; + writew(DAQBOARD2000_TrigAnalog | DAQBOARD2000_TrigDisable, + devpriv->daq + trigControl); udelay(2); - fpga->trigControl = DAQBOARD2000_TrigTTL | DAQBOARD2000_TrigDisable; + writew(DAQBOARD2000_TrigTTL | DAQBOARD2000_TrigDisable, + devpriv->daq + trigControl); /* Stop the scan list FIFO from loading the configuration pipe */ udelay(2); - fpga->acqControl = DAQBOARD2000_SeqStopScanList; + writew(DAQBOARD2000_SeqStopScanList, devpriv->daq + acqControl); /* Stop the pacer clock */ udelay(2); - fpga->acqControl = DAQBOARD2000_AdcPacerDisable; + writew(DAQBOARD2000_AdcPacerDisable, devpriv->daq + acqControl); /* Stop the input dma (abort channel 1) */ daqboard2000_adcStopDmaTransfer(dev); @@ -630,41 +612,39 @@ static void daqboard2000_adcDisarm(struct comedi_device *dev) static void daqboard2000_activateReferenceDacs(struct comedi_device *dev) { - struct daqboard2000_hw *fpga = devpriv->daq; + struct daqboard2000_private *devpriv = dev->private; + unsigned int val; int timeout; /* Set the + reference dac value in the FPGA */ - fpga->refDacs = 0x80 | DAQBOARD2000_PosRefDacSelect; + writew(0x80 | DAQBOARD2000_PosRefDacSelect, devpriv->daq + refDacs); for (timeout = 0; timeout < 20; timeout++) { - if ((fpga->dacControl & DAQBOARD2000_RefBusy) == 0) + val = readw(devpriv->daq + dacControl); + if ((val & DAQBOARD2000_RefBusy) == 0) break; udelay(2); } -/* printk("DAQBOARD2000_PosRefDacSelect %d\n", timeout);*/ /* Set the - reference dac value in the FPGA */ - fpga->refDacs = 0x80 | DAQBOARD2000_NegRefDacSelect; + writew(0x80 | DAQBOARD2000_NegRefDacSelect, devpriv->daq + refDacs); for (timeout = 0; timeout < 20; timeout++) { - if ((fpga->dacControl & DAQBOARD2000_RefBusy) == 0) + val = readw(devpriv->daq + dacControl); + if ((val & DAQBOARD2000_RefBusy) == 0) break; udelay(2); } -/* printk("DAQBOARD2000_NegRefDacSelect %d\n", timeout);*/ } static void daqboard2000_initializeCtrs(struct comedi_device *dev) { -/* printk("Implement: daqboard2000_initializeCtrs\n");*/ } static void daqboard2000_initializeTmrs(struct comedi_device *dev) { -/* printk("Implement: daqboard2000_initializeTmrs\n");*/ } static void daqboard2000_dacDisarm(struct comedi_device *dev) { -/* printk("Implement: daqboard2000_dacDisarm\n");*/ } static void daqboard2000_initializeAdc(struct comedi_device *dev) @@ -680,92 +660,66 @@ static void daqboard2000_initializeDac(struct comedi_device *dev) daqboard2000_dacDisarm(dev); } -/* -The test command, REMOVE!!: - -rmmod daqboard2000 ; rmmod comedi; make install ; modprobe daqboard2000; /usr/sbin/comedi_config /dev/comedi0 daqboard/2000 ; tail -40 /var/log/messages -*/ - static int daqboard2000_8255_cb(int dir, int port, int data, unsigned long ioaddr) { - int result = 0; + void __iomem *mmio_base = (void __iomem *)ioaddr; + if (dir) { - writew(data, ((void *)ioaddr) + port * 2); - result = 0; + writew(data, mmio_base + port * 2); + return 0; } else { - result = readw(((void *)ioaddr) + port * 2); + return readw(mmio_base + port * 2); } -/* - printk("daqboard2000_8255_cb %x %d %d %2.2x -> %2.2x\n", - arg, dir, port, data, result); -*/ - return result; } -static struct pci_dev *daqboard2000_find_pci_dev(struct comedi_device *dev, - struct comedi_devconfig *it) +static const void *daqboard2000_find_boardinfo(struct comedi_device *dev, + struct pci_dev *pcidev) { - struct pci_dev *pcidev = NULL; - int bus = it->options[0]; - int slot = it->options[1]; + const struct daq200_boardtype *board; int i; - for_each_pci_dev(pcidev) { - if (bus || slot) { - if (bus != pcidev->bus->number || - slot != PCI_SLOT(pcidev->devfn)) - continue; - } - if (pcidev->vendor != PCI_VENDOR_ID_IOTECH || - pcidev->device != 0x0409 || - pcidev->subsystem_device != PCI_VENDOR_ID_IOTECH) - continue; - - for (i = 0; i < ARRAY_SIZE(boardtypes); i++) { - if (boardtypes[i].id != pcidev->subsystem_device) - continue; - dev->board_ptr = boardtypes + i; - return pcidev; - } + if (pcidev->subsystem_device != PCI_VENDOR_ID_IOTECH) + return NULL; + + for (i = 0; i < ARRAY_SIZE(boardtypes); i++) { + board = &boardtypes[i]; + if (pcidev->subsystem_device == board->id) + return board; } - dev_err(dev->class_dev, - "No supported board found! (req. bus %d, slot %d)\n", - bus, slot); return NULL; } -static int daqboard2000_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int daqboard2000_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) { - struct pci_dev *pcidev; + const struct daq200_boardtype *board; + struct daqboard2000_private *devpriv; struct comedi_subdevice *s; - resource_size_t pci_base; - void *aux_data; - unsigned int aux_len; int result; - result = alloc_private(dev, sizeof(struct daqboard2000_private)); + comedi_set_hw_dev(dev, &pcidev->dev); + + board = daqboard2000_find_boardinfo(dev, pcidev); + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; + + result = alloc_private(dev, sizeof(*devpriv)); if (result < 0) return -ENOMEM; + devpriv = dev->private; - pcidev = daqboard2000_find_pci_dev(dev, it); - if (!pcidev) - return -EIO; - comedi_set_hw_dev(dev, &pcidev->dev); - - result = comedi_pci_enable(pcidev, "daqboard2000"); - if (result < 0) { - dev_err(dev->class_dev, - "failed to enable PCI device and request regions\n"); - return -EIO; - } + result = comedi_pci_enable(pcidev, dev->driver->driver_name); + if (result < 0) + return result; dev->iobase = 1; /* the "detach" needs this */ - pci_base = pci_resource_start(pcidev, 0); - devpriv->plx = ioremap(pci_base, DAQBOARD2000_PLX_SIZE); - pci_base = pci_resource_start(pcidev, 2); - devpriv->daq = ioremap(pci_base, DAQBOARD2000_DAQ_SIZE); + devpriv->plx = ioremap(pci_resource_start(pcidev, 0), + pci_resource_len(pcidev, 0)); + devpriv->daq = ioremap(pci_resource_start(pcidev, 2), + pci_resource_len(pcidev, 2)); if (!devpriv->plx || !devpriv->daq) return -ENOMEM; @@ -775,36 +729,14 @@ static int daqboard2000_attach(struct comedi_device *dev, readl(devpriv->plx + 0x6c); - /* - u8 interrupt; - Windows code does restore interrupts, but since we don't use them... - pci_read_config_byte(pcidev, PCI_INTERRUPT_LINE, &interrupt); - printk("Interrupt before is: %x\n", interrupt); - */ - - aux_data = comedi_aux_data(it->options, 0); - aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]; - - if (aux_data && aux_len) { - result = initialize_daqboard2000(dev, aux_data, aux_len); - } else { - dev_dbg(dev->class_dev, - "no FPGA initialization code, aborting\n"); - result = -EIO; - } + result = daqboard2000_upload_firmware(dev); if (result < 0) - goto out; + return result; + daqboard2000_initializeAdc(dev); daqboard2000_initializeDac(dev); - /* - Windows code does restore interrupts, but since we don't use them... - pci_read_config_byte(pcidev, PCI_INTERRUPT_LINE, &interrupt); - printk("Interrupt after is: %x\n", interrupt); - */ - - dev->board_name = this_board->name; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* ai subdevice */ s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND; @@ -813,7 +745,7 @@ static int daqboard2000_attach(struct comedi_device *dev, s->insn_read = daqboard2000_ai_insn_read; s->range_table = &range_daqboard2000_ai; - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* ao subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; @@ -821,22 +753,27 @@ static int daqboard2000_attach(struct comedi_device *dev, s->maxdata = 0xffff; s->insn_read = daqboard2000_ao_insn_read; s->insn_write = daqboard2000_ao_insn_write; - s->range_table = &range_daqboard2000_ao; + s->range_table = &range_bipolar10; - s = dev->subdevices + 2; + s = &dev->subdevices[2]; result = subdev_8255_init(dev, s, daqboard2000_8255_cb, - (unsigned long)(devpriv->daq + 0x40)); + (unsigned long)(devpriv->daq + dioP2ExpansionIO8Bit)); + if (result) + return result; -out: - return result; + dev_info(dev->class_dev, "%s: %s attached\n", + dev->driver->driver_name, dev->board_name); + + return 0; } static void daqboard2000_detach(struct comedi_device *dev) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct daqboard2000_private *devpriv = dev->private; if (dev->subdevices) - subdev_8255_cleanup(dev, dev->subdevices + 2); + subdev_8255_cleanup(dev, &dev->subdevices[2]); if (dev->irq) free_irq(dev->irq, dev); if (devpriv) { @@ -855,7 +792,7 @@ static void daqboard2000_detach(struct comedi_device *dev) static struct comedi_driver daqboard2000_driver = { .driver_name = "daqboard2000", .module = THIS_MODULE, - .attach = daqboard2000_attach, + .attach_pci = daqboard2000_attach_pci, .detach = daqboard2000_detach, }; @@ -887,3 +824,4 @@ module_comedi_pci_driver(daqboard2000_driver, daqboard2000_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(DAQBOARD2000_FIRMWARE); diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c index 67a914a10b55..5fd21fa6c1c7 100644 --- a/drivers/staging/comedi/drivers/das08.c +++ b/drivers/staging/comedi/drivers/das08.c @@ -32,8 +32,9 @@ * [ComputerBoards] DAS08 (isa-das08), DAS08-PGM (das08-pgm), * DAS08-PGH (das08-pgh), DAS08-PGL (das08-pgl), DAS08-AOH (das08-aoh), * DAS08-AOL (das08-aol), DAS08-AOM (das08-aom), DAS08/JR-AO (das08/jr-ao), - * DAS08/JR-16-AO (das08jr-16-ao), PCI-DAS08 (pci-das08 or das08), + * DAS08/JR-16-AO (das08jr-16-ao), PCI-DAS08 (pci-das08), * PC104-DAS08 (pc104-das08), DAS08/JR/16 (das08jr/16) + * Updated: Fri, 31 Aug 2012 19:19:06 +0100 * Status: works * * This is a rewrite of the das08 and das08jr drivers. @@ -41,9 +42,8 @@ * Options (for ISA cards): * [0] - base io address * - * Options (for pci-das08): - * [0] - bus (optional) - * [1] = slot (optional) + * Manual configuration of PCI cards is not supported; they are + * configured automatically. * * The das08 driver doesn't support asynchronous commands, since * the cheap das08 hardware doesn't really support them. The @@ -61,9 +61,9 @@ #define DRV_NAME "das08" -#define DO_COMEDI_DRIVER_REGISTER \ - (IS_ENABLED(CONFIG_COMEDI_DAS08_ISA) || \ - IS_ENABLED(CONFIG_COMEDI_DAS08_PCI)) +#define DO_ISA IS_ENABLED(CONFIG_COMEDI_DAS08_ISA) +#define DO_PCI IS_ENABLED(CONFIG_COMEDI_DAS08_PCI) +#define DO_COMEDI_DRIVER_REGISTER (DO_ISA || DO_PCI) #define PCI_VENDOR_ID_COMPUTERBOARDS 0x1307 #define PCI_DEVICE_ID_PCIDAS08 0x29 @@ -236,6 +236,16 @@ static const int *const das08_gainlists[] = { das08_pgm_gainlist, }; +static inline bool is_isa_board(const struct das08_board_struct *board) +{ + return DO_ISA && board->bustype == isa; +} + +static inline bool is_pci_board(const struct das08_board_struct *board) +{ + return DO_PCI && board->bustype == pci; +} + #define TIMEOUT 100000 static int das08_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, @@ -342,9 +352,9 @@ static int das08_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, return insn->n; } -static int __maybe_unused -das08jr_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int das08jr_di_rbits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { data[0] = 0; data[1] = inb(dev->iobase + DAS08JR_DIO); @@ -352,9 +362,9 @@ das08jr_di_rbits(struct comedi_device *dev, struct comedi_subdevice *s, return insn->n; } -static int __maybe_unused -das08jr_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static int das08jr_do_wbits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { struct das08_private_struct *devpriv = dev->private; @@ -369,88 +379,92 @@ das08jr_do_wbits(struct comedi_device *dev, struct comedi_subdevice *s, return insn->n; } -static int __maybe_unused -das08jr_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void das08_ao_set_data(struct comedi_device *dev, + unsigned int chan, unsigned int data) { - int n; - int lsb, msb; - int chan; - - lsb = data[0] & 0xff; - msb = (data[0] >> 8) & 0xff; - - chan = CR_CHAN(insn->chanspec); + const struct das08_board_struct *thisboard = comedi_board(dev); + struct das08_private_struct *devpriv = dev->private; + unsigned char lsb; + unsigned char msb; - for (n = 0; n < insn->n; n++) { -#if 0 - outb(lsb, dev->iobase + devpriv->ao_offset_lsb[chan]); - outb(msb, dev->iobase + devpriv->ao_offset_msb[chan]); -#else + lsb = data & 0xff; + msb = (data >> 8) & 0xff; + if (thisboard->is_jr) { outb(lsb, dev->iobase + DAS08JR_AO_LSB(chan)); outb(msb, dev->iobase + DAS08JR_AO_MSB(chan)); -#endif - /* load DACs */ inb(dev->iobase + DAS08JR_DIO); + } else { + outb(lsb, dev->iobase + DAS08AO_AO_LSB(chan)); + outb(msb, dev->iobase + DAS08AO_AO_MSB(chan)); + /* load DACs */ + inb(dev->iobase + DAS08AO_AO_UPDATE); } - - return n; + devpriv->ao_readback[chan] = data; } -/* - * - * The -aox boards have the DACs at a different offset and use - * a different method to force an update. - * - */ -static int __maybe_unused -das08ao_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) +static void das08_ao_initialize(struct comedi_device *dev, + struct comedi_subdevice *s) { int n; - int lsb, msb; - int chan; + unsigned int data; + + data = s->maxdata / 2; /* should be about 0 volts */ + for (n = 0; n < s->n_chan; n++) + das08_ao_set_data(dev, n, data); +} - lsb = data[0] & 0xff; - msb = (data[0] >> 8) & 0xf; +static int das08_ao_winsn(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + unsigned int n; + unsigned int chan; chan = CR_CHAN(insn->chanspec); - for (n = 0; n < insn->n; n++) { -#if 0 - outb(lsb, dev->iobase + devpriv->ao_offset_lsb[chan]); - outb(msb, dev->iobase + devpriv->ao_offset_msb[chan]); -#else - outb(lsb, dev->iobase + DAS08AO_AO_LSB(chan)); - outb(msb, dev->iobase + DAS08AO_AO_MSB(chan)); -#endif + for (n = 0; n < insn->n; n++) + das08_ao_set_data(dev, chan, *data); - /* load DACs */ - inb(dev->iobase + DAS08AO_AO_UPDATE); - } + return n; +} + +static int das08_ao_rinsn(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) +{ + struct das08_private_struct *devpriv = dev->private; + unsigned int n; + unsigned int chan; + + chan = CR_CHAN(insn->chanspec); + + for (n = 0; n < insn->n; n++) + data[n] = devpriv->ao_readback[chan]; return n; } static void i8254_initialize(struct comedi_device *dev) { - struct das08_private_struct *devpriv = dev->private; + const struct das08_board_struct *thisboard = comedi_board(dev); + unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset; unsigned int mode = I8254_MODE0 | I8254_BINARY; int i; for (i = 0; i < 3; ++i) - i8254_set_mode(devpriv->i8254_iobase, 0, i, mode); + i8254_set_mode(i8254_iobase, 0, i, mode); } static int das08_counter_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - struct das08_private_struct *devpriv = dev->private; + const struct das08_board_struct *thisboard = comedi_board(dev); + unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset; int chan = insn->chanspec; - data[0] = i8254_read(devpriv->i8254_iobase, 0, chan); + data[0] = i8254_read(i8254_iobase, 0, chan); return 1; } @@ -458,10 +472,11 @@ static int das08_counter_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - struct das08_private_struct *devpriv = dev->private; + const struct das08_board_struct *thisboard = comedi_board(dev); + unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset; int chan = insn->chanspec; - i8254_write(devpriv->i8254_iobase, 0, chan, data[0]); + i8254_write(i8254_iobase, 0, chan, data[0]); return 1; } @@ -469,18 +484,16 @@ static int das08_counter_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - struct das08_private_struct *devpriv = dev->private; + const struct das08_board_struct *thisboard = comedi_board(dev); + unsigned long i8254_iobase = dev->iobase + thisboard->i8254_offset; int chan = insn->chanspec; - if (insn->n != 2) - return -EINVAL; - switch (data[0]) { case INSN_CONFIG_SET_COUNTER_MODE: - i8254_set_mode(devpriv->i8254_iobase, 0, chan, data[1]); + i8254_set_mode(i8254_iobase, 0, chan, data[1]); break; case INSN_CONFIG_8254_READ_STATUS: - data[1] = i8254_status(devpriv->i8254_iobase, 0, chan); + data[1] = i8254_status(i8254_iobase, 0, chan); break; default: return -EINVAL; @@ -491,18 +504,14 @@ static int das08_counter_config(struct comedi_device *dev, #if DO_COMEDI_DRIVER_REGISTER static const struct das08_board_struct das08_boards[] = { -#if IS_ENABLED(CONFIG_COMEDI_DAS08_ISA) +#if DO_ISA { .name = "isa-das08", /* cio-das08.pdf */ .bustype = isa, - .ai = das08_ai_rinsn, .ai_nbits = 12, .ai_pg = das08_pg_none, .ai_encoding = das08_encode12, - .ao = NULL, - .ao_nbits = 12, - .di = das08_di_rbits, - .do_ = das08_do_wbits, + .di_nchan = 3, .do_nchan = 4, .i8255_offset = 8, .i8254_offset = 4, @@ -511,13 +520,10 @@ static const struct das08_board_struct das08_boards[] = { { .name = "das08-pgm", /* cio-das08pgx.pdf */ .bustype = isa, - .ai = das08_ai_rinsn, .ai_nbits = 12, .ai_pg = das08_pgm, .ai_encoding = das08_encode12, - .ao = NULL, - .di = das08_di_rbits, - .do_ = das08_do_wbits, + .di_nchan = 3, .do_nchan = 4, .i8255_offset = 0, .i8254_offset = 0x04, @@ -526,44 +532,33 @@ static const struct das08_board_struct das08_boards[] = { { .name = "das08-pgh", /* cio-das08pgx.pdf */ .bustype = isa, - .ai = das08_ai_rinsn, .ai_nbits = 12, .ai_pg = das08_pgh, .ai_encoding = das08_encode12, - .ao = NULL, - .di = das08_di_rbits, - .do_ = das08_do_wbits, + .di_nchan = 3, .do_nchan = 4, - .i8255_offset = 0, .i8254_offset = 0x04, .iosize = 16, /* unchecked */ }, { .name = "das08-pgl", /* cio-das08pgx.pdf */ .bustype = isa, - .ai = das08_ai_rinsn, .ai_nbits = 12, .ai_pg = das08_pgl, .ai_encoding = das08_encode12, - .ao = NULL, - .di = das08_di_rbits, - .do_ = das08_do_wbits, + .di_nchan = 3, .do_nchan = 4, - .i8255_offset = 0, .i8254_offset = 0x04, .iosize = 16, /* unchecked */ }, { .name = "das08-aoh", /* cio-das08_aox.pdf */ .bustype = isa, - .ai = das08_ai_rinsn, .ai_nbits = 12, .ai_pg = das08_pgh, .ai_encoding = das08_encode12, - .ao = das08ao_ao_winsn, /* 8 */ .ao_nbits = 12, - .di = das08_di_rbits, - .do_ = das08_do_wbits, + .di_nchan = 3, .do_nchan = 4, .i8255_offset = 0x0c, .i8254_offset = 0x04, @@ -572,14 +567,11 @@ static const struct das08_board_struct das08_boards[] = { { .name = "das08-aol", /* cio-das08_aox.pdf */ .bustype = isa, - .ai = das08_ai_rinsn, .ai_nbits = 12, .ai_pg = das08_pgl, .ai_encoding = das08_encode12, - .ao = das08ao_ao_winsn, /* 8 */ .ao_nbits = 12, - .di = das08_di_rbits, - .do_ = das08_do_wbits, + .di_nchan = 3, .do_nchan = 4, .i8255_offset = 0x0c, .i8254_offset = 0x04, @@ -588,14 +580,11 @@ static const struct das08_board_struct das08_boards[] = { { .name = "das08-aom", /* cio-das08_aox.pdf */ .bustype = isa, - .ai = das08_ai_rinsn, .ai_nbits = 12, .ai_pg = das08_pgm, .ai_encoding = das08_encode12, - .ao = das08ao_ao_winsn, /* 8 */ .ao_nbits = 12, - .di = das08_di_rbits, - .do_ = das08_do_wbits, + .di_nchan = 3, .do_nchan = 4, .i8255_offset = 0x0c, .i8254_offset = 0x04, @@ -604,152 +593,68 @@ static const struct das08_board_struct das08_boards[] = { { .name = "das08/jr-ao", /* cio-das08-jr-ao.pdf */ .bustype = isa, - .ai = das08_ai_rinsn, + .is_jr = true, .ai_nbits = 12, .ai_pg = das08_pg_none, .ai_encoding = das08_encode12, - .ao = das08jr_ao_winsn, .ao_nbits = 12, - .di = das08jr_di_rbits, - .do_ = das08jr_do_wbits, + .di_nchan = 8, .do_nchan = 8, - .i8255_offset = 0, - .i8254_offset = 0, .iosize = 16, /* unchecked */ }, { .name = "das08jr-16-ao", /* cio-das08jr-16-ao.pdf */ .bustype = isa, - .ai = das08_ai_rinsn, + .is_jr = true, .ai_nbits = 16, .ai_pg = das08_pg_none, .ai_encoding = das08_encode16, - .ao = das08jr_ao_winsn, .ao_nbits = 16, - .di = das08jr_di_rbits, - .do_ = das08jr_do_wbits, + .di_nchan = 8, .do_nchan = 8, - .i8255_offset = 0, .i8254_offset = 0x04, .iosize = 16, /* unchecked */ }, { .name = "pc104-das08", - .bustype = pc104, - .ai = das08_ai_rinsn, + .bustype = isa, .ai_nbits = 12, .ai_pg = das08_pg_none, .ai_encoding = das08_encode12, - .ao = NULL, - .ao_nbits = 0, - .di = das08_di_rbits, - .do_ = das08_do_wbits, + .di_nchan = 3, .do_nchan = 4, - .i8255_offset = 0, .i8254_offset = 4, .iosize = 16, /* unchecked */ }, -#if 0 - { - .name = "das08/f", - }, - { - .name = "das08jr", - }, -#endif { .name = "das08jr/16", .bustype = isa, - .ai = das08_ai_rinsn, + .is_jr = true, .ai_nbits = 16, .ai_pg = das08_pg_none, .ai_encoding = das08_encode16, - .ao = NULL, - .ao_nbits = 0, - .di = das08jr_di_rbits, - .do_ = das08jr_do_wbits, + .di_nchan = 8, .do_nchan = 8, - .i8255_offset = 0, - .i8254_offset = 0, .iosize = 16, /* unchecked */ }, -#if 0 - { - .name = "das48-pga", /* cio-das48-pga.pdf */ - }, - { - .name = "das08-pga-g2", /* a KM board */ - }, -#endif -#endif /* IS_ENABLED(CONFIG_COMEDI_DAS08_ISA) */ -#if IS_ENABLED(CONFIG_COMEDI_DAS08_PCI) +#endif /* DO_ISA */ +#if DO_PCI { .name = "pci-das08", /* pci-das08 */ .id = PCI_DEVICE_ID_PCIDAS08, .bustype = pci, - .ai = das08_ai_rinsn, .ai_nbits = 12, .ai_pg = das08_bipolar5, .ai_encoding = das08_encode12, - .ao = NULL, - .ao_nbits = 0, - .di = das08_di_rbits, - .do_ = das08_do_wbits, + .di_nchan = 3, .do_nchan = 4, - .i8255_offset = 0, .i8254_offset = 4, .iosize = 8, }, - { /* wildcard entry matches any supported PCI device */ - .name = DRV_NAME, - .id = PCI_ANY_ID, - .bustype = pci, - }, -#endif /* IS_ENABLED(CONFIG_COMEDI_DAS08_PCI) */ +#endif /* DO_PCI */ }; #endif /* DO_COMEDI_DRIVER_REGISTER */ -#if IS_ENABLED(CONFIG_COMEDI_DAS08_CS) -struct das08_board_struct das08_cs_boards[NUM_DAS08_CS_BOARDS] = { - { - .name = "pcm-das08", - .id = 0x0, /* XXX */ - .bustype = pcmcia, - .ai = das08_ai_rinsn, - .ai_nbits = 12, - .ai_pg = das08_bipolar5, - .ai_encoding = das08_pcm_encode12, - .ao = NULL, - .ao_nbits = 0, - .di = das08_di_rbits, - .do_ = das08_do_wbits, - .do_nchan = 3, - .i8255_offset = 0, - .i8254_offset = 0, - .iosize = 16, - }, - /* duplicate so driver name can be used also */ - { - .name = "das08_cs", - .id = 0x0, /* XXX */ - .bustype = pcmcia, - .ai = das08_ai_rinsn, - .ai_nbits = 12, - .ai_pg = das08_bipolar5, - .ai_encoding = das08_pcm_encode12, - .ao = NULL, - .ao_nbits = 0, - .di = das08_di_rbits, - .do_ = das08_do_wbits, - .do_nchan = 3, - .i8255_offset = 0, - .i8254_offset = 0, - .iosize = 16, - }, -}; -EXPORT_SYMBOL_GPL(das08_cs_boards); -#endif - int das08_common_attach(struct comedi_device *dev, unsigned long iobase) { const struct das08_board_struct *thisboard = comedi_board(dev); @@ -765,9 +670,9 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* ai */ - if (thisboard->ai) { + if (thisboard->ai_nbits) { s->type = COMEDI_SUBD_AI; /* XXX some boards actually have differential * inputs instead of single ended. @@ -778,53 +683,56 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) s->n_chan = 8; s->maxdata = (1 << thisboard->ai_nbits) - 1; s->range_table = das08_ai_lranges[thisboard->ai_pg]; - s->insn_read = thisboard->ai; + s->insn_read = das08_ai_rinsn; devpriv->pg_gainlist = das08_gainlists[thisboard->ai_pg]; } else { s->type = COMEDI_SUBD_UNUSED; } - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* ao */ - if (thisboard->ao) { + if (thisboard->ao_nbits) { s->type = COMEDI_SUBD_AO; -/* XXX lacks read-back insn */ s->subdev_flags = SDF_WRITABLE; s->n_chan = 2; s->maxdata = (1 << thisboard->ao_nbits) - 1; s->range_table = &range_bipolar5; - s->insn_write = thisboard->ao; + s->insn_write = das08_ao_winsn; + s->insn_read = das08_ao_rinsn; + das08_ao_initialize(dev, s); } else { s->type = COMEDI_SUBD_UNUSED; } - s = dev->subdevices + 2; + s = &dev->subdevices[2]; /* di */ - if (thisboard->di) { + if (thisboard->di_nchan) { s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; - s->n_chan = (thisboard->di == das08_di_rbits) ? 3 : 8; + s->n_chan = thisboard->di_nchan; s->maxdata = 1; s->range_table = &range_digital; - s->insn_bits = thisboard->di; + s->insn_bits = + thisboard->is_jr ? das08jr_di_rbits : das08_di_rbits; } else { s->type = COMEDI_SUBD_UNUSED; } - s = dev->subdevices + 3; + s = &dev->subdevices[3]; /* do */ - if (thisboard->do_) { + if (thisboard->do_nchan) { s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE | SDF_READABLE; s->n_chan = thisboard->do_nchan; s->maxdata = 1; s->range_table = &range_digital; - s->insn_bits = thisboard->do_; + s->insn_bits = + thisboard->is_jr ? das08jr_do_wbits : das08_do_wbits; } else { s->type = COMEDI_SUBD_UNUSED; } - s = dev->subdevices + 4; + s = &dev->subdevices[4]; /* 8255 */ if (thisboard->i8255_offset != 0) { subdev_8255_init(dev, s, NULL, (unsigned long)(dev->iobase + @@ -834,7 +742,7 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) s->type = COMEDI_SUBD_UNUSED; } - s = dev->subdevices + 5; + s = &dev->subdevices[5]; /* 8254 */ if (thisboard->i8254_offset != 0) { s->type = COMEDI_SUBD_COUNTER; @@ -844,8 +752,6 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) s->insn_read = das08_counter_read; s->insn_write = das08_counter_write; s->insn_config = das08_counter_config; - - devpriv->i8254_iobase = iobase + thisboard->i8254_offset; i8254_initialize(dev); } else { s->type = COMEDI_SUBD_UNUSED; @@ -855,50 +761,13 @@ int das08_common_attach(struct comedi_device *dev, unsigned long iobase) } EXPORT_SYMBOL_GPL(das08_common_attach); -static int das08_pci_attach_common(struct comedi_device *dev, - struct pci_dev *pdev) -{ - unsigned long iobase; - unsigned long pci_iobase; - struct das08_private_struct *devpriv = dev->private; - - if (!IS_ENABLED(CONFIG_COMEDI_DAS08_PCI)) - return -EINVAL; - - devpriv->pdev = pdev; - /* enable PCI device and reserve I/O spaces */ - if (comedi_pci_enable(pdev, dev->driver->driver_name)) { - dev_err(dev->class_dev, - "Error enabling PCI device and requesting regions\n"); - return -EIO; - } - /* read base addresses */ - pci_iobase = pci_resource_start(pdev, 1); - iobase = pci_resource_start(pdev, 2); - dev_info(dev->class_dev, "pcibase 0x%lx iobase 0x%lx\n", - pci_iobase, iobase); - devpriv->pci_iobase = pci_iobase; -#if 0 - /* We could enable pci-das08's interrupt here to make it possible - * to do timed input in this driver, but there is little point since - * conversions would have to be started by the interrupt handler - * so you might as well use comedi_rt_timer to emulate commands - */ - /* set source of interrupt trigger to counter2 output */ - outb(CNTRL_INTR | CNTRL_DIR, pci_iobase + CNTRL); - /* Enable local interrupt 1 and pci interrupt */ - outw(INTR1_ENABLE | PCI_INTR_ENABLE, pci_iobase + INTCSR); -#endif - return das08_common_attach(dev, iobase); -} - static const struct das08_board_struct * das08_find_pci_board(struct pci_dev *pdev) { #if DO_COMEDI_DRIVER_REGISTER unsigned int i; for (i = 0; i < ARRAY_SIZE(das08_boards); i++) - if (das08_boards[i].bustype == pci && + if (is_pci_board(&das08_boards[i]) && pdev->device == das08_boards[i].id) return &das08_boards[i]; #endif @@ -909,9 +778,10 @@ das08_find_pci_board(struct pci_dev *pdev) static int __devinit __maybe_unused das08_attach_pci(struct comedi_device *dev, struct pci_dev *pdev) { + unsigned long iobase; int ret; - if (!IS_ENABLED(CONFIG_COMEDI_DAS08_PCI)) + if (!DO_PCI) return -EINVAL; ret = alloc_private(dev, sizeof(struct das08_private_struct)); if (ret < 0) @@ -922,65 +792,16 @@ das08_attach_pci(struct comedi_device *dev, struct pci_dev *pdev) dev_err(dev->class_dev, "BUG! cannot determine board type!\n"); return -EINVAL; } - /* - * Need to 'get' the PCI device to match the 'put' in das08_detach(). - * TODO: Remove the pci_dev_get() and matching pci_dev_put() once - * support for manual attachment of PCI devices via das08_attach() - * has been removed. - */ - pci_dev_get(pdev); - return das08_pci_attach_common(dev, pdev); -} - -static struct pci_dev *das08_find_pci(struct comedi_device *dev, - int bus, int slot) -{ - const struct das08_board_struct *thisboard = comedi_board(dev); - struct pci_dev *pdev; - unsigned int matchid; - - if (bus || slot) - dev_dbg(dev->class_dev, "Looking for %s at PCI %02X:%02X\n", - thisboard->name, bus, slot); - else - dev_dbg(dev->class_dev, "Looking for %s on PCI buses\n", - thisboard->name); - - matchid = thisboard->id; - pdev = NULL; - for_each_pci_dev(pdev) { - if ((bus || slot) && - (bus != pdev->bus->number || slot != PCI_SLOT(pdev->devfn))) - continue; - if (pdev->vendor != PCI_VENDOR_ID_COMPUTERBOARDS) - continue; - if (matchid == PCI_ANY_ID) { - /* wildcard board matches any supported PCI board */ - const struct das08_board_struct *foundboard; - foundboard = das08_find_pci_board(pdev); - if (foundboard == NULL) - continue; - /* replace wildcard board_ptr */ - dev->board_ptr = thisboard = foundboard; - } else { - /* match specific PCI board */ - if (pdev->device != matchid) - continue; - } - /* found a match */ - dev_info(dev->class_dev, "Found %s at PCI %s\n", - thisboard->name, pci_name(pdev)); - return pdev; - } - /* no match found */ - if (bus || slot) + comedi_set_hw_dev(dev, &pdev->dev); + /* enable PCI device and reserve I/O spaces */ + if (comedi_pci_enable(pdev, dev->driver->driver_name)) { dev_err(dev->class_dev, - "No %s cards found at PCI %02X:%02X\n", - thisboard->name, bus, slot); - else - dev_err(dev->class_dev, "No %s cards found on PCI buses\n", - thisboard->name); - return NULL; + "Error enabling PCI device and requesting regions\n"); + return -EIO; + } + /* read base addresses */ + iobase = pci_resource_start(pdev, 2); + return das08_common_attach(dev, iobase); } static int __maybe_unused @@ -997,14 +818,12 @@ das08_attach(struct comedi_device *dev, struct comedi_devconfig *it) devpriv = dev->private; dev_info(dev->class_dev, "attach\n"); - if (IS_ENABLED(CONFIG_COMEDI_DAS08_PCI) && thisboard->bustype == pci) { - struct pci_dev *pdev; - pdev = das08_find_pci(dev, it->options[0], it->options[1]); - if (pdev == NULL) - return -EIO; - return das08_pci_attach_common(dev, pdev); - } else if (IS_ENABLED(CONFIG_COMEDI_DAS08_ISA) && - (thisboard->bustype == isa || thisboard->bustype == pc104)) { + if (is_pci_board(thisboard)) { + dev_err(dev->class_dev, + "Manual configuration of PCI board '%s' is not supported\n", + thisboard->name); + return -EIO; + } else if (is_isa_board(thisboard)) { iobase = it->options[0]; dev_info(dev->class_dev, "iobase 0x%lx\n", iobase); if (!request_region(iobase, thisboard->iosize, DRV_NAME)) { @@ -1019,26 +838,23 @@ das08_attach(struct comedi_device *dev, struct comedi_devconfig *it) void das08_common_detach(struct comedi_device *dev) { if (dev->subdevices) - subdev_8255_cleanup(dev, dev->subdevices + 4); + subdev_8255_cleanup(dev, &dev->subdevices[4]); } EXPORT_SYMBOL_GPL(das08_common_detach); static void __maybe_unused das08_detach(struct comedi_device *dev) { const struct das08_board_struct *thisboard = comedi_board(dev); - struct das08_private_struct *devpriv = dev->private; das08_common_detach(dev); - if (IS_ENABLED(CONFIG_COMEDI_DAS08_ISA) && - (thisboard->bustype == isa || thisboard->bustype == pc104)) { + if (is_isa_board(thisboard)) { if (dev->iobase) release_region(dev->iobase, thisboard->iosize); - } else if (IS_ENABLED(CONFIG_COMEDI_DAS08_PCI) && - thisboard->bustype == pci) { - if (devpriv && devpriv->pdev) { - if (devpriv->pci_iobase) - comedi_pci_disable(devpriv->pdev); - pci_dev_put(devpriv->pdev); + } else if (is_pci_board(thisboard)) { + struct pci_dev *pdev = comedi_to_pci_dev(dev); + if (pdev) { + if (dev->iobase) + comedi_pci_disable(pdev); } } } @@ -1056,7 +872,7 @@ static struct comedi_driver das08_driver = { }; #endif -#if IS_ENABLED(CONFIG_COMEDI_DAS08_PCI) +#if DO_PCI static DEFINE_PCI_DEVICE_TABLE(das08_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_COMPUTERBOARDS, PCI_DEVICE_ID_PCIDAS08) }, {0} @@ -1081,10 +897,10 @@ static struct pci_driver das08_pci_driver = { .probe = &das08_pci_probe, .remove = __devexit_p(&das08_pci_remove) }; -#endif /* CONFIG_COMEDI_DAS08_PCI */ +#endif /* DO_PCI */ #if DO_COMEDI_DRIVER_REGISTER -#if IS_ENABLED(CONFIG_COMEDI_DAS08_PCI) +#if DO_PCI module_comedi_pci_driver(das08_driver, das08_pci_driver); #else module_comedi_driver(das08_driver); diff --git a/drivers/staging/comedi/drivers/das08.h b/drivers/staging/comedi/drivers/das08.h index 27b6d4ec9032..0314baebae39 100644 --- a/drivers/staging/comedi/drivers/das08.h +++ b/drivers/staging/comedi/drivers/das08.h @@ -24,7 +24,7 @@ #ifndef _DAS08_H #define _DAS08_H -enum das08_bustype { isa, pci, pcmcia, pc104 }; +enum das08_bustype { isa, pci, pcmcia }; /* different ways ai data is encoded in first two registers */ enum das08_ai_encoding { das08_encode12, das08_encode16, das08_pcm_encode12 }; enum das08_lrange { das08_pg_none, das08_bipolar5, das08_pgh, das08_pgl, @@ -35,14 +35,12 @@ struct das08_board_struct { const char *name; unsigned int id; /* id for pci/pcmcia boards */ enum das08_bustype bustype; - void *ai; + bool is_jr; /* true for 'JR' boards */ unsigned int ai_nbits; enum das08_lrange ai_pg; enum das08_ai_encoding ai_encoding; - void *ao; unsigned int ao_nbits; - void *di; - void *do_; + unsigned int di_nchan; unsigned int do_nchan; unsigned int i8255_offset; unsigned int i8254_offset; @@ -53,14 +51,9 @@ struct das08_private_struct { unsigned int do_mux_bits; /* bits for do/mux register on boards without separate do register */ unsigned int do_bits; /* bits for do register on boards with register dedicated to digital out only */ const unsigned int *pg_gainlist; - struct pci_dev *pdev; /* struct for pci-das08 */ - unsigned int pci_iobase; /* additional base address for pci-das08 */ - unsigned int i8254_iobase; + unsigned int ao_readback[2]; /* assume 2 AO channels */ }; -#define NUM_DAS08_CS_BOARDS 2 -extern struct das08_board_struct das08_cs_boards[NUM_DAS08_CS_BOARDS]; - int das08_common_attach(struct comedi_device *dev, unsigned long iobase); void das08_common_detach(struct comedi_device *dev); diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c index f5700de7b6c0..e4c91e675379 100644 --- a/drivers/staging/comedi/drivers/das08_cs.c +++ b/drivers/staging/comedi/drivers/das08_cs.c @@ -58,6 +58,32 @@ Command support does not exist, but could be added for this board. #include <pcmcia/cistpl.h> #include <pcmcia/ds.h> +static const struct das08_board_struct das08_cs_boards[] = { + { + .name = "pcm-das08", + .id = 0x0, /* XXX */ + .bustype = pcmcia, + .ai_nbits = 12, + .ai_pg = das08_bipolar5, + .ai_encoding = das08_pcm_encode12, + .di_nchan = 3, + .do_nchan = 3, + .iosize = 16, + }, + /* duplicate so driver name can be used also */ + { + .name = "das08_cs", + .id = 0x0, /* XXX */ + .bustype = pcmcia, + .ai_nbits = 12, + .ai_pg = das08_bipolar5, + .ai_encoding = das08_pcm_encode12, + .di_nchan = 3, + .do_nchan = 3, + .iosize = 16, + }, +}; + static struct pcmcia_device *cur_dev; static int das08_cs_attach(struct comedi_device *dev, diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c index 895cc7783c9c..fcb8a32adb2f 100644 --- a/drivers/staging/comedi/drivers/das16.c +++ b/drivers/staging/comedi/drivers/das16.c @@ -402,62 +402,42 @@ static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, int gain, start_chan, i; int mask; - /* make sure triggers are valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); - tmp = cmd->scan_begin_src; mask = TRIG_FOLLOW; /* if board supports burst mode */ if (board->size > 0x400) mask |= TRIG_TIMER | TRIG_EXT; - cmd->scan_begin_src &= mask; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + err |= cfc_check_trigger_src(&cmd->scan_begin_src, mask); tmp = cmd->convert_src; mask = TRIG_TIMER | TRIG_EXT; /* if board supports burst mode */ if (board->size > 0x400) mask |= TRIG_NOW; - cmd->convert_src &= mask; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + err |= cfc_check_trigger_src(&cmd->convert_src, mask); - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /** - * step 2: make sure trigger sources are unique and - * mutually compatible - */ - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT && - cmd->scan_begin_src != TRIG_FOLLOW) - err++; - if (cmd->convert_src != TRIG_TIMER && - cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW) - err++; - if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT) - err++; + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ /* make sure scan_begin_src and convert_src dont conflict */ if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW) - err++; + err |= -EINVAL; if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_NOW) - err++; + err |= -EINVAL; if (err) return 2; @@ -558,7 +538,7 @@ static int das16_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, /* utility function that suggests a dma transfer size in bytes */ static unsigned int das16_suggest_transfer_size(struct comedi_device *dev, - struct comedi_cmd cmd) + const struct comedi_cmd *cmd) { unsigned int size; unsigned int freq; @@ -571,16 +551,16 @@ static unsigned int das16_suggest_transfer_size(struct comedi_device *dev, /* otherwise, we are relying on dma terminal count interrupt, * so pick a reasonable size */ - if (cmd.convert_src == TRIG_TIMER) - freq = 1000000000 / cmd.convert_arg; - else if (cmd.scan_begin_src == TRIG_TIMER) - freq = (1000000000 / cmd.scan_begin_arg) * cmd.chanlist_len; + if (cmd->convert_src == TRIG_TIMER) + freq = 1000000000 / cmd->convert_arg; + else if (cmd->scan_begin_src == TRIG_TIMER) + freq = (1000000000 / cmd->scan_begin_arg) * cmd->chanlist_len; /* return some default value */ else freq = 0xffffffff; - if (cmd.flags & TRIG_WAKE_EOS) { - size = sample_size * cmd.chanlist_len; + if (cmd->flags & TRIG_WAKE_EOS) { + size = sample_size * cmd->chanlist_len; } else { /* make buffer fill in no more than 1/3 second */ size = (freq / 3) * sample_size; @@ -592,7 +572,7 @@ static unsigned int das16_suggest_transfer_size(struct comedi_device *dev, else if (size < sample_size) size = sample_size; - if (cmd.stop_src == TRIG_COUNT && size > devpriv->adc_byte_count) + if (cmd->stop_src == TRIG_COUNT && size > devpriv->adc_byte_count) size = devpriv->adc_byte_count; return size; @@ -685,7 +665,7 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s) set_dma_addr(devpriv->dma_chan, devpriv->dma_buffer_addr[devpriv->current_buffer]); /* set appropriate size of transfer */ - devpriv->dma_transfer_size = das16_suggest_transfer_size(dev, *cmd); + devpriv->dma_transfer_size = das16_suggest_transfer_size(dev, cmd); set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size); enable_dma(devpriv->dma_chan); release_dma_lock(flags); @@ -1268,7 +1248,7 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; dev->read_subdev = s; /* ai */ if (board->ai) { @@ -1300,7 +1280,7 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->type = COMEDI_SUBD_UNUSED; } - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* ao */ if (board->ao) { s->type = COMEDI_SUBD_AO; @@ -1318,7 +1298,7 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->type = COMEDI_SUBD_UNUSED; } - s = dev->subdevices + 2; + s = &dev->subdevices[2]; /* di */ if (board->di) { s->type = COMEDI_SUBD_DI; @@ -1331,7 +1311,7 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->type = COMEDI_SUBD_UNUSED; } - s = dev->subdevices + 3; + s = &dev->subdevices[3]; /* do */ if (board->do_) { s->type = COMEDI_SUBD_DO; @@ -1346,7 +1326,7 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->type = COMEDI_SUBD_UNUSED; } - s = dev->subdevices + 4; + s = &dev->subdevices[4]; /* 8255 */ if (board->i8255_offset != 0) { subdev_8255_init(dev, s, NULL, (dev->iobase + @@ -1376,7 +1356,7 @@ static void das16_detach(struct comedi_device *dev) das16_reset(dev); if (dev->subdevices) - subdev_8255_cleanup(dev, dev->subdevices + 4); + subdev_8255_cleanup(dev, &dev->subdevices[4]); if (devpriv) { int i; for (i = 0; i < 2; i++) { diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c index 200926347861..3f87d7598e5b 100644 --- a/drivers/staging/comedi/drivers/das16m1.c +++ b/drivers/staging/comedi/drivers/das16m1.c @@ -170,42 +170,24 @@ static int das16m1_cmd_test(struct comedi_device *dev, const struct das16m1_board *board = comedi_board(dev); unsigned int err = 0, tmp, i; - /* make sure triggers are valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_FOLLOW; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually compatible */ - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; - if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) - err++; - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -650,7 +632,7 @@ static int das16m1_attach(struct comedi_device *dev, if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; dev->read_subdev = s; /* ai */ s->type = COMEDI_SUBD_AI; @@ -666,7 +648,7 @@ static int das16m1_attach(struct comedi_device *dev, s->cancel = das16m1_cancel; s->poll = das16m1_poll; - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* di */ s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; @@ -675,7 +657,7 @@ static int das16m1_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = das16m1_di_rbits; - s = dev->subdevices + 2; + s = &dev->subdevices[2]; /* do */ s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE | SDF_READABLE; @@ -684,7 +666,7 @@ static int das16m1_attach(struct comedi_device *dev, s->range_table = &range_digital; s->insn_bits = das16m1_do_wbits; - s = dev->subdevices + 3; + s = &dev->subdevices[3]; /* 8255 */ subdev_8255_init(dev, s, NULL, dev->iobase + DAS16M1_82C55); @@ -707,7 +689,7 @@ static int das16m1_attach(struct comedi_device *dev, static void das16m1_detach(struct comedi_device *dev) { if (dev->subdevices) - subdev_8255_cleanup(dev, dev->subdevices + 3); + subdev_8255_cleanup(dev, &dev->subdevices[3]); if (dev->irq) free_irq(dev->irq, dev); if (dev->iobase) { diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c index 25e7e56a376f..2555f3297d7b 100644 --- a/drivers/staging/comedi/drivers/das1800.c +++ b/drivers/staging/comedi/drivers/das1800.c @@ -656,7 +656,7 @@ static int das1800_cancel(struct comedi_device *dev, struct comedi_subdevice *s) /* the guts of the interrupt handler, that is shared with das1800_ai_poll */ static void das1800_ai_handler(struct comedi_device *dev) { - struct comedi_subdevice *s = dev->subdevices + 0; /* analog input subdevice */ + struct comedi_subdevice *s = &dev->subdevices[0]; struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; unsigned int status = inb(dev->iobase + DAS1800_STATUS); @@ -784,59 +784,35 @@ static int das1800_ai_do_cmdtest(struct comedi_device *dev, struct comedi_cmd *cmd) { int err = 0; - int tmp; unsigned int tmp_arg; int i; int unipolar; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_EXT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, + TRIG_COUNT | TRIG_EXT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ - /* uniqueness check */ - if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) - err++; - if (cmd->scan_begin_src != TRIG_FOLLOW && - cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_COUNT && - cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_EXT) - err++; - /* compatibility check */ if (cmd->scan_begin_src != TRIG_FOLLOW && cmd->convert_src != TRIG_TIMER) - err++; + err |= -EINVAL; if (err) return 2; @@ -958,14 +934,14 @@ static int das1800_ai_do_cmdtest(struct comedi_device *dev, } /* returns appropriate bits for control register a, depending on command */ -static int control_a_bits(struct comedi_cmd cmd) +static int control_a_bits(const struct comedi_cmd *cmd) { int control_a; control_a = FFEN; /* enable fifo */ - if (cmd.stop_src == TRIG_EXT) + if (cmd->stop_src == TRIG_EXT) control_a |= ATEN; - switch (cmd.start_src) { + switch (cmd->start_src) { case TRIG_EXT: control_a |= TGEN | CGSL; break; @@ -980,7 +956,7 @@ static int control_a_bits(struct comedi_cmd cmd) } /* returns appropriate bits for control register c, depending on command */ -static int control_c_bits(struct comedi_cmd cmd) +static int control_c_bits(const struct comedi_cmd *cmd) { int control_c; int aref; @@ -988,18 +964,18 @@ static int control_c_bits(struct comedi_cmd cmd) /* set clock source to internal or external, select analog reference, * select unipolar / bipolar */ - aref = CR_AREF(cmd.chanlist[0]); + aref = CR_AREF(cmd->chanlist[0]); control_c = UQEN; /* enable upper qram addresses */ if (aref != AREF_DIFF) control_c |= SD; if (aref == AREF_COMMON) control_c |= CMEN; /* if a unipolar range was selected */ - if (CR_RANGE(cmd.chanlist[0]) & UNIPOLAR) + if (CR_RANGE(cmd->chanlist[0]) & UNIPOLAR) control_c |= UB; - switch (cmd.scan_begin_src) { + switch (cmd->scan_begin_src) { case TRIG_FOLLOW: /* not in burst mode */ - switch (cmd.convert_src) { + switch (cmd->convert_src) { case TRIG_TIMER: /* trig on cascaded counters */ control_c |= IPCLK; @@ -1047,29 +1023,33 @@ static int das1800_set_frequency(struct comedi_device *dev) } /* sets up counters */ -static int setup_counters(struct comedi_device *dev, struct comedi_cmd cmd) +static int setup_counters(struct comedi_device *dev, + const struct comedi_cmd *cmd) { + unsigned int period; + /* setup cascaded counters for conversion/scan frequency */ - switch (cmd.scan_begin_src) { + switch (cmd->scan_begin_src) { case TRIG_FOLLOW: /* not in burst mode */ - if (cmd.convert_src == TRIG_TIMER) { + if (cmd->convert_src == TRIG_TIMER) { /* set conversion frequency */ + period = cmd->convert_arg; i8253_cascade_ns_to_timer_2div(TIMER_BASE, - &(devpriv->divisor1), - &(devpriv->divisor2), - &(cmd.convert_arg), - cmd. - flags & TRIG_ROUND_MASK); + &devpriv->divisor1, + &devpriv->divisor2, + &period, + cmd->flags & + TRIG_ROUND_MASK); if (das1800_set_frequency(dev) < 0) return -1; } break; case TRIG_TIMER: /* in burst mode */ /* set scan frequency */ - i8253_cascade_ns_to_timer_2div(TIMER_BASE, &(devpriv->divisor1), - &(devpriv->divisor2), - &(cmd.scan_begin_arg), - cmd.flags & TRIG_ROUND_MASK); + period = cmd->scan_begin_arg; + i8253_cascade_ns_to_timer_2div(TIMER_BASE, &devpriv->divisor1, + &devpriv->divisor2, &period, + cmd->flags & TRIG_ROUND_MASK); if (das1800_set_frequency(dev) < 0) return -1; break; @@ -1078,7 +1058,7 @@ static int setup_counters(struct comedi_device *dev, struct comedi_cmd cmd) } /* setup counter 0 for 'about triggering' */ - if (cmd.stop_src == TRIG_EXT) { + if (cmd->stop_src == TRIG_EXT) { /* load counter 0 in mode 0 */ i8254_load(dev->iobase + DAS1800_COUNTER, 0, 0, 1, 0); } @@ -1087,7 +1067,7 @@ static int setup_counters(struct comedi_device *dev, struct comedi_cmd cmd) } /* utility function that suggests a dma transfer size based on the conversion period 'ns' */ -static unsigned int suggest_transfer_size(struct comedi_cmd *cmd) +static unsigned int suggest_transfer_size(const struct comedi_cmd *cmd) { unsigned int size = DMA_BUF_SIZE; static const int sample_size = 2; /* size in bytes of one sample from board */ @@ -1125,7 +1105,7 @@ static unsigned int suggest_transfer_size(struct comedi_cmd *cmd) } /* sets up dma */ -static void setup_dma(struct comedi_device *dev, struct comedi_cmd cmd) +static void setup_dma(struct comedi_device *dev, const struct comedi_cmd *cmd) { unsigned long lock_flags; const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL; @@ -1134,7 +1114,7 @@ static void setup_dma(struct comedi_device *dev, struct comedi_cmd cmd) return; /* determine a reasonable dma transfer size */ - devpriv->dma_transfer_size = suggest_transfer_size(&cmd); + devpriv->dma_transfer_size = suggest_transfer_size(cmd); lock_flags = claim_dma_lock(); disable_dma(devpriv->dma0); /* clear flip-flop to make sure 2-byte registers for @@ -1163,14 +1143,15 @@ static void setup_dma(struct comedi_device *dev, struct comedi_cmd cmd) } /* programs channel/gain list into card */ -static void program_chanlist(struct comedi_device *dev, struct comedi_cmd cmd) +static void program_chanlist(struct comedi_device *dev, + const struct comedi_cmd *cmd) { int i, n, chan_range; unsigned long irq_flags; const int range_mask = 0x3; /* masks unipolar/bipolar bit off range */ const int range_bitshift = 8; - n = cmd.chanlist_len; + n = cmd->chanlist_len; /* spinlock protects indirect addressing */ spin_lock_irqsave(&dev->spinlock, irq_flags); outb(QRAM, dev->iobase + DAS1800_SELECT); /* select QRAM for baseAddress + 0x0 */ @@ -1178,9 +1159,9 @@ static void program_chanlist(struct comedi_device *dev, struct comedi_cmd cmd) /* make channel / gain list */ for (i = 0; i < n; i++) { chan_range = - CR_CHAN(cmd. - chanlist[i]) | ((CR_RANGE(cmd.chanlist[i]) & - range_mask) << range_bitshift); + CR_CHAN(cmd->chanlist[i]) | + ((CR_RANGE(cmd->chanlist[i]) & range_mask) << + range_bitshift); outw(chan_range, dev->iobase + DAS1800_QRAM); } outb(n - 1, dev->iobase + DAS1800_QRAM_ADDRESS); /*finish write to QRAM */ @@ -1196,7 +1177,7 @@ static int das1800_ai_do_cmd(struct comedi_device *dev, int ret; int control_a, control_c; struct comedi_async *async = s->async; - struct comedi_cmd cmd = async->cmd; + const struct comedi_cmd *cmd = &async->cmd; if (!dev->irq) { comedi_error(dev, @@ -1206,12 +1187,12 @@ static int das1800_ai_do_cmd(struct comedi_device *dev, /* disable dma on TRIG_WAKE_EOS, or TRIG_RT * (because dma in handler is unsafe at hard real-time priority) */ - if (cmd.flags & (TRIG_WAKE_EOS | TRIG_RT)) + if (cmd->flags & (TRIG_WAKE_EOS | TRIG_RT)) devpriv->irq_dma_bits &= ~DMA_ENABLED; else devpriv->irq_dma_bits |= devpriv->dma_bits; /* interrupt on end of conversion for TRIG_WAKE_EOS */ - if (cmd.flags & TRIG_WAKE_EOS) { + if (cmd->flags & TRIG_WAKE_EOS) { /* interrupt fifo not empty */ devpriv->irq_dma_bits &= ~FIMD; } else { @@ -1219,8 +1200,8 @@ static int das1800_ai_do_cmd(struct comedi_device *dev, devpriv->irq_dma_bits |= FIMD; } /* determine how many conversions we need */ - if (cmd.stop_src == TRIG_COUNT) - devpriv->count = cmd.stop_arg * cmd.chanlist_len; + if (cmd->stop_src == TRIG_COUNT) + devpriv->count = cmd->stop_arg * cmd->chanlist_len; das1800_cancel(dev, s); @@ -1240,9 +1221,9 @@ static int das1800_ai_do_cmd(struct comedi_device *dev, /* set conversion rate and length for burst mode */ if (control_c & BMDE) { /* program conversion period with number of microseconds minus 1 */ - outb(cmd.convert_arg / 1000 - 1, + outb(cmd->convert_arg / 1000 - 1, dev->iobase + DAS1800_BURST_RATE); - outb(cmd.chanlist_len - 1, dev->iobase + DAS1800_BURST_LENGTH); + outb(cmd->chanlist_len - 1, dev->iobase + DAS1800_BURST_LENGTH); } outb(devpriv->irq_dma_bits, dev->iobase + DAS1800_CONTROL_B); /* enable irq/dma */ outb(control_a, dev->iobase + DAS1800_CONTROL_A); /* enable fifo and triggering */ @@ -1653,7 +1634,7 @@ static int das1800_attach(struct comedi_device *dev, return retval; /* analog input subdevice */ - s = dev->subdevices + 0; + s = &dev->subdevices[0]; dev->read_subdev = s; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_GROUND | SDF_CMD_READ; @@ -1670,7 +1651,7 @@ static int das1800_attach(struct comedi_device *dev, s->cancel = das1800_cancel; /* analog out */ - s = dev->subdevices + 1; + s = &dev->subdevices[1]; if (thisboard->ao_ability == 1) { s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; @@ -1683,7 +1664,7 @@ static int das1800_attach(struct comedi_device *dev, } /* di */ - s = dev->subdevices + 2; + s = &dev->subdevices[2]; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; s->n_chan = 4; @@ -1692,7 +1673,7 @@ static int das1800_attach(struct comedi_device *dev, s->insn_bits = das1800_di_rbits; /* do */ - s = dev->subdevices + 3; + s = &dev->subdevices[3]; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE | SDF_READABLE; s->n_chan = thisboard->do_n_chan; diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c index e3afcfa9efc8..e134c46dedff 100644 --- a/drivers/staging/comedi/drivers/das6402.c +++ b/drivers/staging/comedi/drivers/das6402.c @@ -152,7 +152,7 @@ static void das6402_setcounter(struct comedi_device *dev) static irqreturn_t intr_handler(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices; + struct comedi_subdevice *s = &dev->subdevices[0]; if (!dev->attached || devpriv->das6402_ignoreirq) { dev_warn(dev->class_dev, "BUG: spurious interrupt\n"); @@ -312,7 +312,7 @@ static int das6402_attach(struct comedi_device *dev, return ret; /* ai subdevice */ - s = dev->subdevices + 0; + s = &dev->subdevices[0]; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND; s->n_chan = 8; diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c index a0959a5e8747..215deac0a396 100644 --- a/drivers/staging/comedi/drivers/das800.c +++ b/drivers/staging/comedi/drivers/das800.c @@ -435,7 +435,7 @@ static irqreturn_t das800_interrupt(int irq, void *d) if (fifo_overflow) { spin_unlock_irqrestore(&dev->spinlock, irq_flags); comedi_error(dev, "DAS800 FIFO overflow"); - das800_cancel(dev, dev->subdevices + 0); + das800_cancel(dev, s); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; comedi_event(dev, s); async->events = 0; @@ -517,7 +517,7 @@ static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it) return ret; /* analog input subdevice */ - s = dev->subdevices + 0; + s = &dev->subdevices[0]; dev->read_subdev = s; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; @@ -531,7 +531,7 @@ static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->cancel = das800_cancel; /* di */ - s = dev->subdevices + 1; + s = &dev->subdevices[1]; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; s->n_chan = 3; @@ -540,7 +540,7 @@ static int das800_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_bits = das800_di_rbits; /* do */ - s = dev->subdevices + 2; + s = &dev->subdevices[2]; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE | SDF_READABLE; s->n_chan = 4; @@ -609,44 +609,24 @@ static int das800_ai_do_cmdtest(struct comedi_device *dev, int gain, startChan; int i; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_FOLLOW; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ - if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) - err++; - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c index 7107f590b1fe..4d5c33c4750f 100644 --- a/drivers/staging/comedi/drivers/dmm32at.c +++ b/drivers/staging/comedi/drivers/dmm32at.c @@ -41,6 +41,8 @@ Configuration Options: #include "../comedidev.h" #include <linux/ioport.h> +#include "comedi_fc.h" + /* Board register addresses */ #define DMM32AT_MEMSIZE 0x10 @@ -258,47 +260,26 @@ static int dmm32at_ai_cmdtest(struct comedi_device *dev, int tmp; int start_chan, gain, i; - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER /*| TRIG_EXT */ ; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER /*| TRIG_EXT */ ; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER /*| TRIG_EXT */); + err |= cfc_check_trigger_src(&cmd->convert_src, + TRIG_TIMER /*| TRIG_EXT */); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually - * compatible */ + /* Step 2a : make sure trigger sources are unique */ - /* note that mutual compatibility is not an issue here */ - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -825,7 +806,7 @@ static int dmm32at_attach(struct comedi_device *dev, if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; dev->read_subdev = s; /* analog input subdevice */ s->type = COMEDI_SUBD_AI; @@ -841,7 +822,7 @@ static int dmm32at_attach(struct comedi_device *dev, s->do_cmdtest = dmm32at_ai_cmdtest; s->cancel = dmm32at_ai_cancel; - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* analog output subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; @@ -851,7 +832,7 @@ static int dmm32at_attach(struct comedi_device *dev, s->insn_write = dmm32at_ao_winsn; s->insn_read = dmm32at_ao_rinsn; - s = dev->subdevices + 2; + s = &dev->subdevices[2]; /* digital i/o subdevice */ /* get access to the DIO regs */ diff --git a/drivers/staging/comedi/drivers/dt2801.c b/drivers/staging/comedi/drivers/dt2801.c index d332269375ab..c59a652a1194 100644 --- a/drivers/staging/comedi/drivers/dt2801.c +++ b/drivers/staging/comedi/drivers/dt2801.c @@ -532,7 +532,7 @@ static int dt2801_dio_insn_bits(struct comedi_device *dev, { int which = 0; - if (s == dev->subdevices + 4) + if (s == &dev->subdevices[3]) which = 1; if (data[0]) { @@ -555,7 +555,7 @@ static int dt2801_dio_insn_config(struct comedi_device *dev, { int which = 0; - if (s == dev->subdevices + 4) + if (s == &dev->subdevices[3]) which = 1; /* configure */ @@ -636,7 +636,7 @@ havetype: dev->board_name = boardtype.name; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* ai subdevice */ s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND; @@ -652,7 +652,7 @@ havetype: s->range_table = ai_range_lkup(boardtype.adrangetype, it->options[3]); s->insn_read = dt2801_ai_insn_read; - s++; + s = &dev->subdevices[1]; /* ao subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; @@ -664,7 +664,7 @@ havetype: s->insn_read = dt2801_ao_insn_read; s->insn_write = dt2801_ao_insn_write; - s++; + s = &dev->subdevices[2]; /* 1st digital subdevice */ s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; @@ -674,7 +674,7 @@ havetype: s->insn_bits = dt2801_dio_insn_bits; s->insn_config = dt2801_dio_insn_config; - s++; + s = &dev->subdevices[3]; /* 2nd digital subdevice */ s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; diff --git a/drivers/staging/comedi/drivers/dt2811.c b/drivers/staging/comedi/drivers/dt2811.c index 290b933c5f96..d3a8c1aec9d6 100644 --- a/drivers/staging/comedi/drivers/dt2811.c +++ b/drivers/staging/comedi/drivers/dt2811.c @@ -510,7 +510,7 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) break; } - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* initialize the ADC subdevice */ s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND; @@ -530,7 +530,7 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) break; } - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* ao subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; @@ -542,7 +542,7 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) devpriv->range_type_list[0] = dac_range_types[devpriv->dac_range[0]]; devpriv->range_type_list[1] = dac_range_types[devpriv->dac_range[1]]; - s = dev->subdevices + 2; + s = &dev->subdevices[2]; /* di subdevice */ s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; @@ -551,7 +551,7 @@ static int dt2811_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = 1; s->range_table = &range_digital; - s = dev->subdevices + 3; + s = &dev->subdevices[3]; /* do subdevice */ s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE; diff --git a/drivers/staging/comedi/drivers/dt2814.c b/drivers/staging/comedi/drivers/dt2814.c index 2e39ebe36fb5..064a8f215e4d 100644 --- a/drivers/staging/comedi/drivers/dt2814.c +++ b/drivers/staging/comedi/drivers/dt2814.c @@ -45,6 +45,8 @@ addition, the clock does not seem to be very accurate. #include <linux/ioport.h> #include <linux/delay.h> +#include "comedi_fc.h" + #define DT2814_SIZE 2 #define DT2814_CSR 0 @@ -129,42 +131,22 @@ static int dt2814_ai_cmdtest(struct comedi_device *dev, int err = 0; int tmp; - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are - * unique and mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ - /* note that mutual compatibility is not an issue here */ - if (cmd->stop_src != TRIG_TIMER && cmd->stop_src != TRIG_EXT) - err++; + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -247,7 +229,7 @@ static irqreturn_t dt2814_interrupt(int irq, void *d) return IRQ_HANDLED; } - s = dev->subdevices + 0; + s = &dev->subdevices[0]; hi = inb(dev->iobase + DT2814_DATA); lo = inb(dev->iobase + DT2814_DATA); @@ -346,7 +328,7 @@ static int dt2814_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret < 0) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; dev->read_subdev = s; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_CMD_READ; diff --git a/drivers/staging/comedi/drivers/dt2815.c b/drivers/staging/comedi/drivers/dt2815.c index 45b20bee4369..b9692ef64c41 100644 --- a/drivers/staging/comedi/drivers/dt2815.c +++ b/drivers/staging/comedi/drivers/dt2815.c @@ -185,7 +185,7 @@ static int dt2815_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (alloc_private(dev, sizeof(struct dt2815_private)) < 0) return -ENOMEM; - s = dev->subdevices; + s = &dev->subdevices[0]; /* ao subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; diff --git a/drivers/staging/comedi/drivers/dt2817.c b/drivers/staging/comedi/drivers/dt2817.c index beba0447b3ee..502e42e0753e 100644 --- a/drivers/staging/comedi/drivers/dt2817.c +++ b/drivers/staging/comedi/drivers/dt2817.c @@ -141,7 +141,7 @@ static int dt2817_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; s->n_chan = 32; s->type = COMEDI_SUBD_DIO; diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c index 1f0b40e4bddd..78d340716d1e 100644 --- a/drivers/staging/comedi/drivers/dt282x.c +++ b/drivers/staging/comedi/drivers/dt282x.c @@ -312,7 +312,7 @@ static void dt282x_ao_dma_interrupt(struct comedi_device *dev) void *ptr; int size; int i; - struct comedi_subdevice *s = dev->subdevices + 1; + struct comedi_subdevice *s = &dev->subdevices[1]; outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR); @@ -345,7 +345,7 @@ static void dt282x_ai_dma_interrupt(struct comedi_device *dev) int size; int i; int ret; - struct comedi_subdevice *s = dev->subdevices; + struct comedi_subdevice *s = &dev->subdevices[0]; outw(devpriv->supcsr | DT2821_CLRDMADNE, dev->iobase + DT2821_SUPCSR); @@ -457,8 +457,8 @@ static irqreturn_t dt282x_interrupt(int irq, void *d) return IRQ_HANDLED; } - s = dev->subdevices + 0; - s_ao = dev->subdevices + 1; + s = &dev->subdevices[0]; + s_ao = &dev->subdevices[1]; adcsr = inw(dev->iobase + DT2821_ADCSR); dacsr = inw(dev->iobase + DT2821_DACSR); supcsr = inw(dev->iobase + DT2821_SUPCSR); @@ -582,47 +582,24 @@ static int dt282x_ai_cmdtest(struct comedi_device *dev, int err = 0; int tmp; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_FOLLOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* - * step 2: make sure trigger sources are unique - * and mutually compatible - */ + /* Step 2a : make sure trigger sources are unique */ - /* note that mutual compatibility is not an issue here */ - if (cmd->scan_begin_src != TRIG_FOLLOW && - cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -862,44 +839,22 @@ static int dt282x_ao_cmdtest(struct comedi_device *dev, int err = 0; int tmp; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_INT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* - * step 2: make sure trigger sources are unique - * and mutually compatible - */ + /* Step 2a : make sure trigger sources are unique */ - /* note that mutual compatibility is not an issue here */ - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -1275,7 +1230,7 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; dev->read_subdev = s; /* ai subdevice */ @@ -1294,7 +1249,7 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it) opt_ai_range_lkup(boardtype.ispgl, it->options[opt_ai_range]); devpriv->ad_2scomp = it->options[opt_ai_twos]; - s++; + s = &dev->subdevices[1]; s->n_chan = boardtype.dachan; if (s->n_chan) { @@ -1320,7 +1275,7 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->type = COMEDI_SUBD_UNUSED; } - s++; + s = &dev->subdevices[2]; /* dio subsystem */ s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c index 3476cda0fff0..43d05ef97157 100644 --- a/drivers/staging/comedi/drivers/dt3000.c +++ b/drivers/staging/comedi/drivers/dt3000.c @@ -63,6 +63,8 @@ AO commands are not supported. #include "../comedidev.h" #include <linux/delay.h> +#include "comedi_fc.h" + #define PCI_VENDOR_ID_DT 0x1116 static const struct comedi_lrange range_dt3000_ai = { 4, { @@ -330,7 +332,7 @@ static irqreturn_t dt3k_interrupt(int irq, void *d) if (!dev->attached) return IRQ_NONE; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; status = readw(devpriv->io_addr + DPR_Intr_Flag); #ifdef DEBUG debug_intr_flags(status); @@ -408,37 +410,19 @@ static int dt3k_ai_cmdtest(struct comedi_device *dev, int err = 0; int tmp; - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -842,7 +826,7 @@ static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - s = dev->subdevices; + s = &dev->subdevices[0]; dev->read_subdev = s; /* ai subdevice */ @@ -857,7 +841,7 @@ static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->do_cmdtest = dt3k_ai_cmdtest; s->cancel = dt3k_ai_cancel; - s++; + s = &dev->subdevices[1]; /* ao subsystem */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; @@ -868,7 +852,7 @@ static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->len_chanlist = 1; s->range_table = &range_bipolar10; - s++; + s = &dev->subdevices[2]; /* dio subsystem */ s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; @@ -879,7 +863,7 @@ static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->len_chanlist = 8; s->range_table = &range_digital; - s++; + s = &dev->subdevices[3]; /* mem subsystem */ s->type = COMEDI_SUBD_MEMORY; s->subdev_flags = SDF_READABLE; @@ -890,7 +874,7 @@ static int dt3000_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->range_table = &range_unknown; #if 0 - s++; + s = &dev->subdevices[4]; /* proc subsystem */ s->type = COMEDI_SUBD_PROC; #endif diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c index 40821c7303ea..bc6f409b7e19 100644 --- a/drivers/staging/comedi/drivers/dt9812.c +++ b/drivers/staging/comedi/drivers/dt9812.c @@ -1041,7 +1041,7 @@ static int dt9812_attach(struct comedi_device *dev, struct comedi_devconfig *it) return ret; /* digital input subdevice */ - s = dev->subdevices + 0; + s = &dev->subdevices[0]; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; s->n_chan = 0; @@ -1050,7 +1050,7 @@ static int dt9812_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_read = &dt9812_di_rinsn; /* digital output subdevice */ - s = dev->subdevices + 1; + s = &dev->subdevices[1]; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITEABLE; s->n_chan = 0; @@ -1059,7 +1059,7 @@ static int dt9812_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_write = &dt9812_do_winsn; /* analog input subdevice */ - s = dev->subdevices + 2; + s = &dev->subdevices[2]; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND; s->n_chan = 0; @@ -1068,7 +1068,7 @@ static int dt9812_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_read = &dt9812_ai_rinsn; /* analog output subdevice */ - s = dev->subdevices + 3; + s = &dev->subdevices[3]; s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITEABLE; s->n_chan = 0; diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c index 064be9aae3aa..6f612be1b0a5 100644 --- a/drivers/staging/comedi/drivers/dyna_pci10xx.c +++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c @@ -41,7 +41,6 @@ #include <linux/mutex.h> #define PCI_VENDOR_ID_DYNALOG 0x10b5 -#define DRV_NAME "dyna_pci10xx" #define READ_TIMEOUT 50 @@ -54,59 +53,11 @@ static const struct comedi_lrange range_pci1050_ai = { 3, { static const char range_codes_pci1050_ai[] = { 0x00, 0x10, 0x30 }; -static const struct comedi_lrange range_pci1050_ao = { 1, { - UNI_RANGE(10) - } -}; - -static const char range_codes_pci1050_ao[] = { 0x00 }; - -struct boardtype { - const char *name; - int device_id; - int ai_chans; - int ai_bits; - int ao_chans; - int ao_bits; - int di_chans; - int di_bits; - int do_chans; - int do_bits; - const struct comedi_lrange *range_ai; - const char *range_codes_ai; - const struct comedi_lrange *range_ao; - const char *range_codes_ao; -}; - -static const struct boardtype boardtypes[] = { - { - .name = "dyna_pci1050", - .device_id = 0x1050, - .ai_chans = 16, - .ai_bits = 12, - .ao_chans = 16, - .ao_bits = 12, - .di_chans = 16, - .di_bits = 16, - .do_chans = 16, - .do_bits = 16, - .range_ai = &range_pci1050_ai, - .range_codes_ai = range_codes_pci1050_ai, - .range_ao = &range_pci1050_ao, - .range_codes_ao = range_codes_pci1050_ao, - }, - /* dummy entry corresponding to driver name */ - {.name = DRV_NAME}, -}; - struct dyna_pci10xx_private { struct mutex mutex; unsigned long BADR3; }; -#define thisboard ((const struct boardtype *)dev->board_ptr) -#define devpriv ((struct dyna_pci10xx_private *)dev->private) - /******************************************************************************/ /************************** READ WRITE FUNCTIONS ******************************/ /******************************************************************************/ @@ -116,13 +67,14 @@ static int dyna_pci10xx_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct dyna_pci10xx_private *devpriv = dev->private; int n, counter; u16 d = 0; unsigned int chan, range; /* get the channel number and range */ chan = CR_CHAN(insn->chanspec); - range = thisboard->range_codes_ai[CR_RANGE((insn->chanspec))]; + range = range_codes_pci1050_ai[CR_RANGE((insn->chanspec))]; mutex_lock(&devpriv->mutex); /* convert n samples */ @@ -159,11 +111,12 @@ static int dyna_pci10xx_insn_write_ao(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct dyna_pci10xx_private *devpriv = dev->private; int n; unsigned int chan, range; chan = CR_CHAN(insn->chanspec); - range = thisboard->range_codes_ai[CR_RANGE((insn->chanspec))]; + range = range_codes_pci1050_ai[CR_RANGE((insn->chanspec))]; mutex_lock(&devpriv->mutex); for (n = 0; n < insn->n; n++) { @@ -181,6 +134,7 @@ static int dyna_pci10xx_di_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct dyna_pci10xx_private *devpriv = dev->private; u16 d = 0; mutex_lock(&devpriv->mutex); @@ -200,6 +154,8 @@ static int dyna_pci10xx_do_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct dyna_pci10xx_private *devpriv = dev->private; + /* The insn data is a mask in data[0] and the new data * in data[1], each channel cooresponding to a bit. * s->state contains the previous write data @@ -223,143 +179,98 @@ static int dyna_pci10xx_do_insn_bits(struct comedi_device *dev, return insn->n; } -static struct pci_dev *dyna_pci10xx_find_pci_dev(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - struct pci_dev *pcidev = NULL; - int bus = it->options[0]; - int slot = it->options[1]; - int i; - - for_each_pci_dev(pcidev) { - if (bus || slot) { - if (bus != pcidev->bus->number || - slot != PCI_SLOT(pcidev->devfn)) - continue; - } - if (pcidev->vendor != PCI_VENDOR_ID_DYNALOG) - continue; - - for (i = 0; i < ARRAY_SIZE(boardtypes); ++i) { - if (pcidev->device != boardtypes[i].device_id) - continue; - - dev->board_ptr = &boardtypes[i]; - return pcidev; - } - } - dev_err(dev->class_dev, - "No supported board found! (req. bus %d, slot %d)\n", - bus, slot); - return NULL; -} - -static int dyna_pci10xx_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int dyna_pci10xx_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) { - struct pci_dev *pcidev; + struct dyna_pci10xx_private *devpriv; struct comedi_subdevice *s; int ret; - if (alloc_private(dev, sizeof(struct dyna_pci10xx_private)) < 0) { - printk(KERN_ERR "comedi: dyna_pci10xx: " - "failed to allocate memory!\n"); - return -ENOMEM; - } - - pcidev = dyna_pci10xx_find_pci_dev(dev, it); - if (!pcidev) - return -EIO; comedi_set_hw_dev(dev, &pcidev->dev); - dev->board_name = thisboard->name; - dev->irq = 0; - - if (comedi_pci_enable(pcidev, DRV_NAME)) { - printk(KERN_ERR "comedi: dyna_pci10xx: " - "failed to enable PCI device and request regions!"); - return -EIO; - } - - mutex_init(&devpriv->mutex); + dev->board_name = dev->driver->driver_name; - printk(KERN_INFO "comedi: dyna_pci10xx: device found!\n"); + ret = alloc_private(dev, sizeof(*devpriv)); + if (ret) + return ret; + devpriv = dev->private; + ret = comedi_pci_enable(pcidev, dev->board_name); + if (ret) + return ret; dev->iobase = pci_resource_start(pcidev, 2); devpriv->BADR3 = pci_resource_start(pcidev, 3); + mutex_init(&devpriv->mutex); + ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; /* analog input */ - s = dev->subdevices + 0; + s = &dev->subdevices[0]; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; - s->n_chan = thisboard->ai_chans; + s->n_chan = 16; s->maxdata = 0x0FFF; - s->range_table = thisboard->range_ai; + s->range_table = &range_pci1050_ai; s->len_chanlist = 16; s->insn_read = dyna_pci10xx_insn_read_ai; /* analog output */ - s = dev->subdevices + 1; + s = &dev->subdevices[1]; s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; - s->n_chan = thisboard->ao_chans; + s->n_chan = 16; s->maxdata = 0x0FFF; - s->range_table = thisboard->range_ao; + s->range_table = &range_unipolar10; s->len_chanlist = 16; s->insn_write = dyna_pci10xx_insn_write_ao; /* digital input */ - s = dev->subdevices + 2; + s = &dev->subdevices[2]; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE | SDF_GROUND; - s->n_chan = thisboard->di_chans; + s->n_chan = 16; s->maxdata = 1; s->range_table = &range_digital; - s->len_chanlist = thisboard->di_chans; + s->len_chanlist = 16; s->insn_bits = dyna_pci10xx_di_insn_bits; /* digital output */ - s = dev->subdevices + 3; + s = &dev->subdevices[3]; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND; - s->n_chan = thisboard->do_chans; + s->n_chan = 16; s->maxdata = 1; s->range_table = &range_digital; - s->len_chanlist = thisboard->do_chans; + s->len_chanlist = 16; s->state = 0; s->insn_bits = dyna_pci10xx_do_insn_bits; - printk(KERN_INFO "comedi: dyna_pci10xx: %s - device setup completed!\n", - thisboard->name); + dev_info(dev->class_dev, "%s attached\n", dev->board_name); - return 1; + return 0; } static void dyna_pci10xx_detach(struct comedi_device *dev) { struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct dyna_pci10xx_private *devpriv = dev->private; if (devpriv) mutex_destroy(&devpriv->mutex); if (pcidev) { if (dev->iobase) comedi_pci_disable(pcidev); - pci_dev_put(pcidev); } } static struct comedi_driver dyna_pci10xx_driver = { .driver_name = "dyna_pci10xx", .module = THIS_MODULE, - .attach = dyna_pci10xx_attach, + .attach_pci = dyna_pci10xx_attach_pci, .detach = dyna_pci10xx_detach, - .board_name = &boardtypes[0].name, - .offset = sizeof(struct boardtype), - .num_names = ARRAY_SIZE(boardtypes), }; static int __devinit dyna_pci10xx_pci_probe(struct pci_dev *dev, diff --git a/drivers/staging/comedi/drivers/fl512.c b/drivers/staging/comedi/drivers/fl512.c index d1da80976f84..ae8e8f460295 100644 --- a/drivers/staging/comedi/drivers/fl512.c +++ b/drivers/staging/comedi/drivers/fl512.c @@ -140,7 +140,7 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it) * this if the definitions of the supdevices, 2 have been defined */ /* Analog indput */ - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* define subdevice as Analog In */ s->type = COMEDI_SUBD_AI; /* you can read it from userspace */ @@ -156,7 +156,7 @@ static int fl512_attach(struct comedi_device *dev, struct comedi_devconfig *it) printk(KERN_INFO "comedi: fl512: subdevice 0 initialized\n"); /* Analog output */ - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* define subdevice as Analog OUT */ s->type = COMEDI_SUBD_AO; /* you can write it from userspace */ diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c index 79f580841dee..abff6603952a 100644 --- a/drivers/staging/comedi/drivers/gsc_hpdi.c +++ b/drivers/staging/comedi/drivers/gsc_hpdi.c @@ -436,7 +436,7 @@ static int setup_subdevices(struct comedi_device *dev) if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* analog input subdevice */ dev->read_subdev = s; /* dev->write_subdev = s; */ @@ -723,45 +723,24 @@ static int di_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; - int tmp; int i; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually - * compatible */ + /* Step 2a : make sure trigger sources are unique */ - /* uniqueness check */ - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; diff --git a/drivers/staging/comedi/drivers/icp_multi.c b/drivers/staging/comedi/drivers/icp_multi.c index b10ebdbc1f7e..d696d4d51e28 100644 --- a/drivers/staging/comedi/drivers/icp_multi.c +++ b/drivers/staging/comedi/drivers/icp_multi.c @@ -44,10 +44,7 @@ There are 4 x 12-bit Analogue Outputs. Ranges : 5V, 10V, +/-5V, +/-10V 4 x 16-bit counters -Options: - [0] - PCI bus number - if bus number and slot number are 0, - then driver search for first unused card - [1] - PCI slot number +Configuration options: not applicable, uses PCI auto config */ #include <linux/interrupt.h> @@ -56,16 +53,7 @@ Options: #include <linux/delay.h> #include <linux/pci.h> -#include "icp_multi.h" - -#define DEVICE_ID 0x8000 /* Device ID */ - -#define ICP_MULTI_EXTDEBUG - -/* Hardware types of the cards */ -#define TYPE_ICP_MULTI 0 - -#define IORANGE_ICP_MULTI 32 +#define PCI_DEVICE_ID_ICP_MULTI 0x8000 #define ICP_MULTI_ADC_CSR 0 /* R/W: ADC command/status register */ #define ICP_MULTI_AI 2 /* R: Analogue input data */ @@ -124,32 +112,10 @@ static const char range_codes_analog[] = { 0x00, 0x20, 0x10, 0x30 }; Data & Structure declarations ============================================================================== */ -static unsigned short pci_list_builded; /*>0 list of card is known */ - -struct boardtype { - const char *name; /* driver name */ - int device_id; - int iorange; /* I/O range len */ - char have_irq; /* 1=card support IRQ */ - char cardtype; /* 0=ICP Multi */ - int n_aichan; /* num of A/D chans */ - int n_aichand; /* num of A/D chans in diff mode */ - int n_aochan; /* num of D/A chans */ - int n_dichan; /* num of DI chans */ - int n_dochan; /* num of DO chans */ - int n_ctrs; /* num of counters */ - int ai_maxdata; /* resolution of A/D */ - int ao_maxdata; /* resolution of D/A */ - const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */ - const char *rangecode; /* range codes for programming */ - const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */ -}; struct icp_multi_private { - struct pcilst_struct *card; /* pointer to card */ char valid; /* card is usable */ void __iomem *io_addr; /* Pointer to mapped io address */ - resource_size_t phys_iobase; /* Physical io address */ unsigned int AdcCmdStatus; /* ADC Command/Status register */ unsigned int DacCmdStatus; /* DAC Command/Status register */ unsigned int IntEnable; /* Interrupt Enable register */ @@ -164,40 +130,14 @@ struct icp_multi_private { unsigned int do_data; /* Remember digital output data */ }; -#define devpriv ((struct icp_multi_private *)dev->private) -#define this_board ((const struct boardtype *)dev->board_ptr) - -/* -============================================================================== - -Name: setup_channel_list - -Description: - This function sets the appropriate channel selection, - differential input mode and range bits in the ADC Command/ - Status register. - -Parameters: - struct comedi_device *dev Pointer to current service structure - struct comedi_subdevice *s Pointer to current subdevice structure - unsigned int *chanlist Pointer to packed channel list - unsigned int n_chan Number of channels to scan - -Returns:Void - -============================================================================== -*/ static void setup_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, unsigned int n_chan) { + struct icp_multi_private *devpriv = dev->private; unsigned int i, range, chanprog; unsigned int diff; -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp multi EDBG: setup_channel_list(...,%d)\n", n_chan); -#endif devpriv->act_chanlist_len = n_chan; devpriv->act_chanlist_pos = 0; @@ -228,50 +168,23 @@ static void setup_channel_list(struct comedi_device *dev, devpriv->AdcCmdStatus |= (chanprog << 8); /* Get range for current channel */ - range = this_board->rangecode[CR_RANGE(chanlist[i])]; + range = range_codes_analog[CR_RANGE(chanlist[i])]; /* Set range. bits 4-5 */ devpriv->AdcCmdStatus |= range; /* Output channel, range, mode to ICP Multi */ writew(devpriv->AdcCmdStatus, devpriv->io_addr + ICP_MULTI_ADC_CSR); - -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "GS: %2d. [%4x]=%4x %4x\n", i, chanprog, range, - devpriv->act_chanlist[i]); -#endif } - } -/* -============================================================================== - -Name: icp_multi_insn_read_ai - -Description: - This function reads a single analogue input. - -Parameters: - struct comedi_device *dev Pointer to current device structure - struct comedi_subdevice *s Pointer to current subdevice structure - struct comedi_insn *insn Pointer to current comedi instruction - unsigned int *data Pointer to analogue input data - -Returns:int Nmuber of instructions executed - -============================================================================== -*/ static int icp_multi_insn_read_ai(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct icp_multi_private *devpriv = dev->private; int n, timeout; -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG "icp multi EDBG: BGN: icp_multi_insn_read_ai(...)\n"); -#endif /* Disable A/D conversion ready interrupt */ devpriv->IntEnable &= ~ADC_READY; writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN); @@ -283,12 +196,6 @@ static int icp_multi_insn_read_ai(struct comedi_device *dev, /* Set up appropriate channel, mode and range data, for specified ch */ setup_channel_list(dev, s, &insn->chanspec, 1); -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG "icp_multi A ST=%4x IO=%p\n", - readw(devpriv->io_addr + ICP_MULTI_ADC_CSR), - devpriv->io_addr + ICP_MULTI_ADC_CSR); -#endif - for (n = 0; n < insn->n; n++) { /* Set start ADC bit */ devpriv->AdcCmdStatus |= ADC_ST; @@ -296,18 +203,8 @@ static int icp_multi_insn_read_ai(struct comedi_device *dev, devpriv->io_addr + ICP_MULTI_ADC_CSR); devpriv->AdcCmdStatus &= ~ADC_ST; -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG "icp multi B n=%d ST=%4x\n", n, - readw(devpriv->io_addr + ICP_MULTI_ADC_CSR)); -#endif - udelay(1); -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG "icp multi C n=%d ST=%4x\n", n, - readw(devpriv->io_addr + ICP_MULTI_ADC_CSR)); -#endif - /* Wait for conversion to complete, or get fed up waiting */ timeout = 100; while (timeout--) { @@ -315,15 +212,6 @@ static int icp_multi_insn_read_ai(struct comedi_device *dev, ICP_MULTI_ADC_CSR) & ADC_BSY)) goto conv_finish; -#ifdef ICP_MULTI_EXTDEBUG - if (!(timeout % 10)) - printk(KERN_DEBUG - "icp multi D n=%d tm=%d ST=%4x\n", n, - timeout, - readw(devpriv->io_addr + - ICP_MULTI_ADC_CSR)); -#endif - udelay(1); } @@ -342,11 +230,6 @@ static int icp_multi_insn_read_ai(struct comedi_device *dev, /* Clear data received */ data[n] = 0; -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp multi EDBG: END: icp_multi_insn_read_ai(...) n=%d\n", - n); -#endif return -ETIME; conv_finish: @@ -362,41 +245,16 @@ conv_finish: devpriv->IntStatus |= ADC_READY; writew(devpriv->IntStatus, devpriv->io_addr + ICP_MULTI_INT_STAT); -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp multi EDBG: END: icp_multi_insn_read_ai(...) n=%d\n", n); -#endif return n; } -/* -============================================================================== - -Name: icp_multi_insn_write_ao - -Description: - This function writes a single analogue output. - -Parameters: - struct comedi_device *dev Pointer to current device structure - struct comedi_subdevice *s Pointer to current subdevice structure - struct comedi_insn *insn Pointer to current comedi instruction - unsigned int *data Pointer to analogue output data - -Returns:int Nmuber of instructions executed - -============================================================================== -*/ static int icp_multi_insn_write_ao(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct icp_multi_private *devpriv = dev->private; int n, chan, range, timeout; -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp multi EDBG: BGN: icp_multi_insn_write_ao(...)\n"); -#endif /* Disable D/A conversion ready interrupt */ devpriv->IntEnable &= ~DAC_READY; writew(devpriv->IntEnable, devpriv->io_addr + ICP_MULTI_INT_EN); @@ -415,7 +273,7 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev, /* Bit 5 = 1 : 10V */ /* Bits 8-9 : Channel number */ devpriv->DacCmdStatus &= 0xfccf; - devpriv->DacCmdStatus |= this_board->rangecode[range]; + devpriv->DacCmdStatus |= range_codes_analog[range]; devpriv->DacCmdStatus |= (chan << 8); writew(devpriv->DacCmdStatus, devpriv->io_addr + ICP_MULTI_DAC_CSR); @@ -429,15 +287,6 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev, ICP_MULTI_DAC_CSR) & DAC_BSY)) goto dac_ready; -#ifdef ICP_MULTI_EXTDEBUG - if (!(timeout % 10)) - printk(KERN_DEBUG - "icp multi A n=%d tm=%d ST=%4x\n", n, - timeout, - readw(devpriv->io_addr + - ICP_MULTI_DAC_CSR)); -#endif - udelay(1); } @@ -456,11 +305,6 @@ static int icp_multi_insn_write_ao(struct comedi_device *dev, /* Clear data received */ devpriv->ao_data[chan] = 0; -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp multi EDBG: END: icp_multi_insn_write_ao(...) n=%d\n", - n); -#endif return -ETIME; dac_ready: @@ -477,35 +321,14 @@ dac_ready: devpriv->ao_data[chan] = data[n]; } -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp multi EDBG: END: icp_multi_insn_write_ao(...) n=%d\n", n); -#endif return n; } -/* -============================================================================== - -Name: icp_multi_insn_read_ao - -Description: - This function reads a single analogue output. - -Parameters: - struct comedi_device *dev Pointer to current device structure - struct comedi_subdevice *s Pointer to current subdevice structure - struct comedi_insn *insn Pointer to current comedi instruction - unsigned int *data Pointer to analogue output data - -Returns:int Nmuber of instructions executed - -============================================================================== -*/ static int icp_multi_insn_read_ao(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct icp_multi_private *devpriv = dev->private; int n, chan; /* Get channel number */ @@ -518,58 +341,22 @@ static int icp_multi_insn_read_ao(struct comedi_device *dev, return n; } -/* -============================================================================== - -Name: icp_multi_insn_bits_di - -Description: - This function reads the digital inputs. - -Parameters: - struct comedi_device *dev Pointer to current device structure - struct comedi_subdevice *s Pointer to current subdevice structure - struct comedi_insn *insn Pointer to current comedi instruction - unsigned int *data Pointer to analogue output data - -Returns:int Nmuber of instructions executed - -============================================================================== -*/ static int icp_multi_insn_bits_di(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct icp_multi_private *devpriv = dev->private; + data[1] = readw(devpriv->io_addr + ICP_MULTI_DI); return insn->n; } -/* -============================================================================== - -Name: icp_multi_insn_bits_do - -Description: - This function writes the appropriate digital outputs. - -Parameters: - struct comedi_device *dev Pointer to current device structure - struct comedi_subdevice *s Pointer to current subdevice structure - struct comedi_insn *insn Pointer to current comedi instruction - unsigned int *data Pointer to analogue output data - -Returns:int Nmuber of instructions executed - -============================================================================== -*/ static int icp_multi_insn_bits_do(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG "icp multi EDBG: BGN: icp_multi_insn_bits_do(...)\n"); -#endif + struct icp_multi_private *devpriv = dev->private; if (data[0]) { s->state &= ~data[0]; @@ -582,30 +369,9 @@ static int icp_multi_insn_bits_do(struct comedi_device *dev, data[1] = readw(devpriv->io_addr + ICP_MULTI_DI); -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG "icp multi EDBG: END: icp_multi_insn_bits_do(...)\n"); -#endif return insn->n; } -/* -============================================================================== - -Name: icp_multi_insn_read_ctr - -Description: - This function reads the specified counter. - -Parameters: - struct comedi_device *dev Pointer to current device structure - struct comedi_subdevice *s Pointer to current subdevice structure - struct comedi_insn *insn Pointer to current comedi instruction - unsigned int *data Pointer to counter data - -Returns:int Nmuber of instructions executed - -============================================================================== -*/ static int icp_multi_insn_read_ctr(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -613,24 +379,6 @@ static int icp_multi_insn_read_ctr(struct comedi_device *dev, return 0; } -/* -============================================================================== - -Name: icp_multi_insn_write_ctr - -Description: - This function write to the specified counter. - -Parameters: - struct comedi_device *dev Pointer to current device structure - struct comedi_subdevice *s Pointer to current subdevice structure - struct comedi_insn *insn Pointer to current comedi instruction - unsigned int *data Pointer to counter data - -Returns:int Nmuber of instructions executed - -============================================================================== -*/ static int icp_multi_insn_write_ctr(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, @@ -639,44 +387,18 @@ static int icp_multi_insn_write_ctr(struct comedi_device *dev, return 0; } -/* -============================================================================== - -Name: interrupt_service_icp_multi - -Description: - This function is the interrupt service routine for all - interrupts generated by the icp multi board. - -Parameters: - int irq - void *d Pointer to current device - -============================================================================== -*/ static irqreturn_t interrupt_service_icp_multi(int irq, void *d) { struct comedi_device *dev = d; + struct icp_multi_private *devpriv = dev->private; int int_no; -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp multi EDBG: BGN: interrupt_service_icp_multi(%d,...)\n", - irq); -#endif - /* Is this interrupt from our board? */ int_no = readw(devpriv->io_addr + ICP_MULTI_INT_STAT) & Status_IRQ; if (!int_no) /* No, exit */ return IRQ_NONE; -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp multi EDBG: interrupt_service_icp_multi() ST: %4x\n", - readw(devpriv->io_addr + ICP_MULTI_INT_STAT)); -#endif - /* Determine which interrupt is active & handle it */ switch (int_no) { case ADC_READY: @@ -700,44 +422,16 @@ static irqreturn_t interrupt_service_icp_multi(int irq, void *d) } -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp multi EDBG: END: interrupt_service_icp_multi(...)\n"); -#endif return IRQ_HANDLED; } #if 0 -/* -============================================================================== - -Name: check_channel_list - -Description: - This function checks if the channel list, provided by user - is built correctly - -Parameters: - struct comedi_device *dev Pointer to current service structure - struct comedi_subdevice *s Pointer to current subdevice structure - unsigned int *chanlist Pointer to packed channel list - unsigned int n_chan Number of channels to scan - -Returns:int 0 = failure - 1 = success - -============================================================================== -*/ static int check_channel_list(struct comedi_device *dev, struct comedi_subdevice *s, unsigned int *chanlist, unsigned int n_chan) { unsigned int i; -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp multi EDBG: check_channel_list(...,%d)\n", n_chan); -#endif /* Check that we at least have one channel to check */ if (n_chan < 1) { comedi_error(dev, "range/channel list is empty!"); @@ -747,13 +441,13 @@ static int check_channel_list(struct comedi_device *dev, for (i = 0; i < n_chan; i++) { /* Check that channel number is < maximum */ if (CR_AREF(chanlist[i]) == AREF_DIFF) { - if (CR_CHAN(chanlist[i]) > this_board->n_aichand) { + if (CR_CHAN(chanlist[i]) > (s->nchan / 2)) { comedi_error(dev, "Incorrect differential ai ch-nr"); return 0; } } else { - if (CR_CHAN(chanlist[i]) > this_board->n_aichan) { + if (CR_CHAN(chanlist[i]) > s->n_chan) { comedi_error(dev, "Incorrect ai channel number"); return 0; @@ -764,295 +458,189 @@ static int check_channel_list(struct comedi_device *dev, } #endif -/* -============================================================================== - -Name: icp_multi_reset - -Description: - This function resets the icp multi device to a 'safe' state - -Parameters: - struct comedi_device *dev Pointer to current service structure - -Returns:int 0 = success - -============================================================================== -*/ static int icp_multi_reset(struct comedi_device *dev) { + struct icp_multi_private *devpriv = dev->private; unsigned int i; -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp_multi EDBG: BGN: icp_multi_reset(...)\n"); -#endif /* Clear INT enables and requests */ writew(0, devpriv->io_addr + ICP_MULTI_INT_EN); writew(0x00ff, devpriv->io_addr + ICP_MULTI_INT_STAT); - if (this_board->n_aochan) - /* Set DACs to 0..5V range and 0V output */ - for (i = 0; i < this_board->n_aochan; i++) { - devpriv->DacCmdStatus &= 0xfcce; + /* Set DACs to 0..5V range and 0V output */ + for (i = 0; i < 4; i++) { + devpriv->DacCmdStatus &= 0xfcce; + + /* Set channel number */ + devpriv->DacCmdStatus |= (i << 8); - /* Set channel number */ - devpriv->DacCmdStatus |= (i << 8); + /* Output 0V */ + writew(0, devpriv->io_addr + ICP_MULTI_AO); - /* Output 0V */ - writew(0, devpriv->io_addr + ICP_MULTI_AO); + /* Set start conversion bit */ + devpriv->DacCmdStatus |= DAC_ST; - /* Set start conversion bit */ - devpriv->DacCmdStatus |= DAC_ST; + /* Output to command / status register */ + writew(devpriv->DacCmdStatus, + devpriv->io_addr + ICP_MULTI_DAC_CSR); - /* Output to command / status register */ - writew(devpriv->DacCmdStatus, - devpriv->io_addr + ICP_MULTI_DAC_CSR); + /* Delay to allow DAC time to recover */ + udelay(1); + } - /* Delay to allow DAC time to recover */ - udelay(1); - } - /* Digital outputs to 0 */ + /* Digital outputs to 0 */ writew(0, devpriv->io_addr + ICP_MULTI_DO); -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "icp multi EDBG: END: icp_multi_reset(...)\n"); -#endif return 0; } -static int icp_multi_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int icp_multi_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) { + struct icp_multi_private *devpriv; struct comedi_subdevice *s; - int ret, subdev, n_subdevices; - unsigned int irq; - struct pcilst_struct *card = NULL; - resource_size_t io_addr[5], iobase; - unsigned char pci_bus, pci_slot, pci_func; + resource_size_t iobase; + int ret; - printk(KERN_WARNING - "icp_multi EDBG: BGN: icp_multi_attach(...)\n"); + comedi_set_hw_dev(dev, &pcidev->dev); + dev->board_name = dev->driver->driver_name; - /* Allocate private data storage space */ - ret = alloc_private(dev, sizeof(struct icp_multi_private)); + ret = alloc_private(dev, sizeof(*devpriv)); if (ret < 0) return ret; + devpriv = dev->private; - /* Initialise list of PCI cards in system, if not already done so */ - if (pci_list_builded++ == 0) { - pci_card_list_init(PCI_VENDOR_ID_ICP, -#ifdef ICP_MULTI_EXTDEBUG - 1 -#else - 0 -#endif - ); - } - - printk(KERN_WARNING - "Anne's comedi%d: icp_multi: board=%s", dev->minor, - this_board->name); - - card = select_and_alloc_pci_card(PCI_VENDOR_ID_ICP, - this_board->device_id, it->options[0], - it->options[1]); - - if (card == NULL) - return -EIO; - - devpriv->card = card; - - if ((pci_card_data(card, &pci_bus, &pci_slot, &pci_func, &io_addr[0], - &irq)) < 0) { - printk(KERN_WARNING " - Can't get configuration data!\n"); - return -EIO; - } - - iobase = io_addr[2]; - devpriv->phys_iobase = iobase; - - printk(KERN_WARNING - ", b:s:f=%d:%d:%d, io=0x%8llx \n", pci_bus, pci_slot, pci_func, - (unsigned long long)iobase); + ret = comedi_pci_enable(pcidev, dev->board_name); + if (ret) + return ret; + iobase = pci_resource_start(pcidev, 2); + dev->iobase = iobase; devpriv->io_addr = ioremap(iobase, ICP_MULTI_SIZE); - - if (devpriv->io_addr == NULL) { - printk(KERN_WARNING "ioremap failed.\n"); + if (!devpriv->io_addr) return -ENOMEM; - } -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG - "0x%08llx mapped to %p, ", (unsigned long long)iobase, - devpriv->io_addr); -#endif - dev->board_name = this_board->name; - - n_subdevices = 0; - if (this_board->n_aichan) - n_subdevices++; - if (this_board->n_aochan) - n_subdevices++; - if (this_board->n_dichan) - n_subdevices++; - if (this_board->n_dochan) - n_subdevices++; - if (this_board->n_ctrs) - n_subdevices++; - - ret = comedi_alloc_subdevices(dev, n_subdevices); + ret = comedi_alloc_subdevices(dev, 5); if (ret) return ret; icp_multi_reset(dev); - if (this_board->have_irq) { - if (irq) { - if (request_irq(irq, interrupt_service_icp_multi, - IRQF_SHARED, "Inova Icp Multi", dev)) { - printk(KERN_WARNING - "unable to allocate IRQ %u, DISABLING IT", - irq); - irq = 0; /* Can't use IRQ */ - } else - printk(KERN_WARNING ", irq=%u", irq); - } else - printk(KERN_WARNING ", IRQ disabled"); - } else - irq = 0; - - dev->irq = irq; - - printk(KERN_WARNING ".\n"); - - subdev = 0; - - if (this_board->n_aichan) { - s = dev->subdevices + subdev; - dev->read_subdev = s; - s->type = COMEDI_SUBD_AI; - s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND; - if (this_board->n_aichand) - s->subdev_flags |= SDF_DIFF; - s->n_chan = this_board->n_aichan; - s->maxdata = this_board->ai_maxdata; - s->len_chanlist = this_board->n_aichan; - s->range_table = this_board->rangelist_ai; - s->insn_read = icp_multi_insn_read_ai; - subdev++; + if (pcidev->irq) { + ret = request_irq(pcidev->irq, interrupt_service_icp_multi, + IRQF_SHARED, dev->board_name, dev); + if (ret == 0) + dev->irq = pcidev->irq; } - if (this_board->n_aochan) { - s = dev->subdevices + subdev; - s->type = COMEDI_SUBD_AO; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = this_board->n_aochan; - s->maxdata = this_board->ao_maxdata; - s->len_chanlist = this_board->n_aochan; - s->range_table = this_board->rangelist_ao; - s->insn_write = icp_multi_insn_write_ao; - s->insn_read = icp_multi_insn_read_ao; - subdev++; - } - - if (this_board->n_dichan) { - s = dev->subdevices + subdev; - s->type = COMEDI_SUBD_DI; - s->subdev_flags = SDF_READABLE; - s->n_chan = this_board->n_dichan; - s->maxdata = 1; - s->len_chanlist = this_board->n_dichan; - s->range_table = &range_digital; - s->io_bits = 0; - s->insn_bits = icp_multi_insn_bits_di; - subdev++; - } - - if (this_board->n_dochan) { - s = dev->subdevices + subdev; - s->type = COMEDI_SUBD_DO; - s->subdev_flags = SDF_WRITABLE | SDF_READABLE; - s->n_chan = this_board->n_dochan; - s->maxdata = 1; - s->len_chanlist = this_board->n_dochan; - s->range_table = &range_digital; - s->io_bits = (1 << this_board->n_dochan) - 1; - s->state = 0; - s->insn_bits = icp_multi_insn_bits_do; - subdev++; - } - - if (this_board->n_ctrs) { - s = dev->subdevices + subdev; - s->type = COMEDI_SUBD_COUNTER; - s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; - s->n_chan = this_board->n_ctrs; - s->maxdata = 0xffff; - s->len_chanlist = this_board->n_ctrs; - s->state = 0; - s->insn_read = icp_multi_insn_read_ctr; - s->insn_write = icp_multi_insn_write_ctr; - subdev++; - } + s = &dev->subdevices[0]; + dev->read_subdev = s; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF; + s->n_chan = 16; + s->maxdata = 0x0fff; + s->len_chanlist = 16; + s->range_table = &range_analog; + s->insn_read = icp_multi_insn_read_ai; + + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = 4; + s->maxdata = 0x0fff; + s->len_chanlist = 4; + s->range_table = &range_analog; + s->insn_write = icp_multi_insn_write_ao; + s->insn_read = icp_multi_insn_read_ao; + + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DI; + s->subdev_flags = SDF_READABLE; + s->n_chan = 16; + s->maxdata = 1; + s->len_chanlist = 16; + s->range_table = &range_digital; + s->io_bits = 0; + s->insn_bits = icp_multi_insn_bits_di; + + s = &dev->subdevices[3]; + s->type = COMEDI_SUBD_DO; + s->subdev_flags = SDF_WRITABLE | SDF_READABLE; + s->n_chan = 8; + s->maxdata = 1; + s->len_chanlist = 8; + s->range_table = &range_digital; + s->io_bits = 0xff; + s->state = 0; + s->insn_bits = icp_multi_insn_bits_do; + + s = &dev->subdevices[4]; + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON; + s->n_chan = 4; + s->maxdata = 0xffff; + s->len_chanlist = 4; + s->state = 0; + s->insn_read = icp_multi_insn_read_ctr; + s->insn_write = icp_multi_insn_write_ctr; devpriv->valid = 1; -#ifdef ICP_MULTI_EXTDEBUG - printk(KERN_DEBUG "icp multi EDBG: END: icp_multi_attach(...)\n"); -#endif + dev_info(dev->class_dev, "%s attached, irq %sabled\n", + dev->board_name, dev->irq ? "en" : "dis"); return 0; } static void icp_multi_detach(struct comedi_device *dev) { - if (dev->private) + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct icp_multi_private *devpriv = dev->private; + + if (devpriv) if (devpriv->valid) icp_multi_reset(dev); if (dev->irq) free_irq(dev->irq, dev); - if (dev->private && devpriv->io_addr) + if (devpriv && devpriv->io_addr) iounmap(devpriv->io_addr); - if (dev->private && devpriv->card) - pci_card_free(devpriv->card); - if (--pci_list_builded == 0) - pci_card_list_cleanup(PCI_VENDOR_ID_ICP); + if (pcidev) { + if (dev->iobase) + comedi_pci_disable(pcidev); + } } -static const struct boardtype boardtypes[] = { - { - .name = "icp_multi", - .device_id = DEVICE_ID, - .iorange = IORANGE_ICP_MULTI, - .have_irq = 1, - .cardtype = TYPE_ICP_MULTI, - .n_aichan = 16, - .n_aichand = 8, - .n_aochan = 4, - .n_dichan = 16, - .n_dochan = 8, - .n_ctrs = 4, - .ai_maxdata = 0x0fff, - .ao_maxdata = 0x0fff, - .rangelist_ai = &range_analog, - .rangecode = range_codes_analog, - .rangelist_ao = &range_analog, - }, -}; - static struct comedi_driver icp_multi_driver = { .driver_name = "icp_multi", .module = THIS_MODULE, - .attach = icp_multi_attach, + .attach_pci = icp_multi_attach_pci, .detach = icp_multi_detach, - .num_names = ARRAY_SIZE(boardtypes), - .board_name = &boardtypes[0].name, - .offset = sizeof(struct boardtype), }; -module_comedi_driver(icp_multi_driver); + +static int __devinit icp_multi_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) +{ + return comedi_pci_auto_config(dev, &icp_multi_driver); +} + +static void __devexit icp_multi_pci_remove(struct pci_dev *dev) +{ + comedi_pci_auto_unconfig(dev); +} + +static DEFINE_PCI_DEVICE_TABLE(icp_multi_pci_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_ICP, PCI_DEVICE_ID_ICP_MULTI) }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, icp_multi_pci_table); + +static struct pci_driver icp_multi_pci_driver = { + .name = "icp_multi", + .id_table = icp_multi_pci_table, + .probe = icp_multi_pci_probe, + .remove = __devexit_p(icp_multi_pci_remove), +}; +module_comedi_pci_driver(icp_multi_driver, icp_multi_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/icp_multi.h b/drivers/staging/comedi/drivers/icp_multi.h deleted file mode 100644 index dbf9908cfde6..000000000000 --- a/drivers/staging/comedi/drivers/icp_multi.h +++ /dev/null @@ -1,297 +0,0 @@ -/* - comedi/drivers/icp_multi.h - - Stuff for ICP Multi - - Author: Anne Smorthit <anne.smorthit@sfwte.ch> - -*/ - -#ifndef _ICP_MULTI_H_ -#define _ICP_MULTI_H_ - -#include "../comedidev.h" - -/****************************************************************************/ - -struct pcilst_struct { - struct pcilst_struct *next; - int used; - struct pci_dev *pcidev; - unsigned short vendor; - unsigned short device; - unsigned char pci_bus; - unsigned char pci_slot; - unsigned char pci_func; - resource_size_t io_addr[5]; - unsigned int irq; -}; - -struct pcilst_struct *inova_devices; -/* ptr to root list of all Inova devices */ - -/****************************************************************************/ - -static void pci_card_list_init(unsigned short pci_vendor, char display); -static void pci_card_list_cleanup(unsigned short pci_vendor); -static struct pcilst_struct *find_free_pci_card_by_device(unsigned short - vendor_id, - unsigned short - device_id); -static int find_free_pci_card_by_position(unsigned short vendor_id, - unsigned short device_id, - unsigned short pci_bus, - unsigned short pci_slot, - struct pcilst_struct **card); -static struct pcilst_struct *select_and_alloc_pci_card(unsigned short vendor_id, - unsigned short device_id, - unsigned short pci_bus, - unsigned short pci_slot); - -static int pci_card_alloc(struct pcilst_struct *amcc); -static int pci_card_free(struct pcilst_struct *amcc); -static void pci_card_list_display(void); -static int pci_card_data(struct pcilst_struct *amcc, - unsigned char *pci_bus, unsigned char *pci_slot, - unsigned char *pci_func, resource_size_t * io_addr, - unsigned int *irq); - -/****************************************************************************/ - -/* build list of Inova cards in this system */ -static void pci_card_list_init(unsigned short pci_vendor, char display) -{ - struct pci_dev *pcidev = NULL; - struct pcilst_struct *inova, *last; - int i; - - inova_devices = NULL; - last = NULL; - - for_each_pci_dev(pcidev) { - if (pcidev->vendor == pci_vendor) { - inova = kzalloc(sizeof(*inova), GFP_KERNEL); - if (!inova) { - printk - ("icp_multi: pci_card_list_init: allocation failed\n"); - pci_dev_put(pcidev); - break; - } - - inova->pcidev = pci_dev_get(pcidev); - if (last) { - last->next = inova; - } else { - inova_devices = inova; - } - last = inova; - - inova->vendor = pcidev->vendor; - inova->device = pcidev->device; - inova->pci_bus = pcidev->bus->number; - inova->pci_slot = PCI_SLOT(pcidev->devfn); - inova->pci_func = PCI_FUNC(pcidev->devfn); - /* Note: resources may be invalid if PCI device - * not enabled, but they are corrected in - * pci_card_alloc. */ - for (i = 0; i < 5; i++) - inova->io_addr[i] = - pci_resource_start(pcidev, i); - inova->irq = pcidev->irq; - } - } - - if (display) - pci_card_list_display(); -} - -/****************************************************************************/ -/* free up list of amcc cards in this system */ -static void pci_card_list_cleanup(unsigned short pci_vendor) -{ - struct pcilst_struct *inova, *next; - - for (inova = inova_devices; inova; inova = next) { - next = inova->next; - pci_dev_put(inova->pcidev); - kfree(inova); - } - - inova_devices = NULL; -} - -/****************************************************************************/ -/* find first unused card with this device_id */ -static struct pcilst_struct *find_free_pci_card_by_device(unsigned short - vendor_id, - unsigned short - device_id) -{ - struct pcilst_struct *inova, *next; - - for (inova = inova_devices; inova; inova = next) { - next = inova->next; - if ((!inova->used) && (inova->device == device_id) - && (inova->vendor == vendor_id)) - return inova; - - } - - return NULL; -} - -/****************************************************************************/ -/* find card on requested position */ -static int find_free_pci_card_by_position(unsigned short vendor_id, - unsigned short device_id, - unsigned short pci_bus, - unsigned short pci_slot, - struct pcilst_struct **card) -{ - struct pcilst_struct *inova, *next; - - *card = NULL; - for (inova = inova_devices; inova; inova = next) { - next = inova->next; - if ((inova->vendor == vendor_id) && (inova->device == device_id) - && (inova->pci_bus == pci_bus) - && (inova->pci_slot == pci_slot)) { - if (!(inova->used)) { - *card = inova; - return 0; /* ok, card is found */ - } else { - return 2; /* card exist but is used */ - } - } - } - - return 1; /* no card found */ -} - -/****************************************************************************/ -/* mark card as used */ -static int pci_card_alloc(struct pcilst_struct *inova) -{ - int i; - - if (!inova) { - printk(" - BUG!! inova is NULL!\n"); - return -1; - } - - if (inova->used) - return 1; - if (comedi_pci_enable(inova->pcidev, "icp_multi")) { - printk(" - Can't enable PCI device and request regions!\n"); - return -1; - } - /* Resources will be accurate now. */ - for (i = 0; i < 5; i++) - inova->io_addr[i] = pci_resource_start(inova->pcidev, i); - inova->irq = inova->pcidev->irq; - inova->used = 1; - return 0; -} - -/****************************************************************************/ -/* mark card as free */ -static int pci_card_free(struct pcilst_struct *inova) -{ - if (!inova) - return -1; - - if (!inova->used) - return 1; - inova->used = 0; - comedi_pci_disable(inova->pcidev); - return 0; -} - -/****************************************************************************/ -/* display list of found cards */ -static void pci_card_list_display(void) -{ - struct pcilst_struct *inova, *next; - - printk("Anne's List of pci cards\n"); - printk("bus:slot:func vendor device io_inova io_daq irq used\n"); - - for (inova = inova_devices; inova; inova = next) { - next = inova->next; - printk - ("%2d %2d %2d 0x%4x 0x%4x 0x%8llx 0x%8llx %2u %2d\n", - inova->pci_bus, inova->pci_slot, inova->pci_func, - inova->vendor, inova->device, - (unsigned long long)inova->io_addr[0], - (unsigned long long)inova->io_addr[2], inova->irq, - inova->used); - - } -} - -/****************************************************************************/ -/* return all card information for driver */ -static int pci_card_data(struct pcilst_struct *inova, - unsigned char *pci_bus, unsigned char *pci_slot, - unsigned char *pci_func, resource_size_t * io_addr, - unsigned int *irq) -{ - int i; - - if (!inova) - return -1; - *pci_bus = inova->pci_bus; - *pci_slot = inova->pci_slot; - *pci_func = inova->pci_func; - for (i = 0; i < 5; i++) - io_addr[i] = inova->io_addr[i]; - *irq = inova->irq; - return 0; -} - -/****************************************************************************/ -/* select and alloc card */ -static struct pcilst_struct *select_and_alloc_pci_card(unsigned short vendor_id, - unsigned short device_id, - unsigned short pci_bus, - unsigned short pci_slot) -{ - struct pcilst_struct *card; - int err; - - if ((pci_bus < 1) & (pci_slot < 1)) { /* use autodetection */ - - card = find_free_pci_card_by_device(vendor_id, device_id); - if (card == NULL) { - printk(" - Unused card not found in system!\n"); - return NULL; - } - } else { - switch (find_free_pci_card_by_position(vendor_id, device_id, - pci_bus, pci_slot, - &card)) { - case 1: - printk - (" - Card not found on requested position b:s %d:%d!\n", - pci_bus, pci_slot); - return NULL; - case 2: - printk - (" - Card on requested position is used b:s %d:%d!\n", - pci_bus, pci_slot); - return NULL; - } - } - - err = pci_card_alloc(card); - if (err != 0) { - if (err > 0) - printk(" - Can't allocate card!\n"); - /* else: error already printed. */ - return NULL; - } - - return card; -} - -#endif diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c index 0f9cfe662b9a..65ff1c9b973c 100644 --- a/drivers/staging/comedi/drivers/ii_pci20kc.c +++ b/drivers/staging/comedi/drivers/ii_pci20kc.c @@ -224,7 +224,7 @@ static int pci20xxx_attach(struct comedi_device *dev, dev->minor, devpriv->ioaddr); for (i = 0; i < PCI20000_MODULES; i++) { - s = dev->subdevices + i; + s = &dev->subdevices[i]; id = readb(devpriv->ioaddr + (i + 1) * PCI20000_OFFSET); s->private = devpriv->subdev_private + i; sdp = s->private; @@ -259,7 +259,7 @@ static int pci20xxx_attach(struct comedi_device *dev, } /* initialize struct pci20xxx_private */ - pci20xxx_dio_init(dev, dev->subdevices + PCI20000_MODULES); + pci20xxx_dio_init(dev, &dev->subdevices[PCI20000_MODULES]); return 1; } diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c index 93f94cd7bae2..4a108ea8a9aa 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.c +++ b/drivers/staging/comedi/drivers/jr3_pci.c @@ -362,10 +362,11 @@ static int jr3_pci_open(struct comedi_device *dev) return 0; } -int read_idm_word(const u8 * data, size_t size, int *pos, unsigned int *val) +static int read_idm_word(const u8 *data, size_t size, int *pos, + unsigned int *val) { int result = 0; - if (pos != 0 && val != 0) { + if (pos && val) { /* Skip over non hex */ for (; *pos < size && !isxdigit(data[*pos]); (*pos)++) { } @@ -875,7 +876,7 @@ static int jr3_pci_attach(struct comedi_device *dev, p->maxdata_list[56] = 0xffff; p->maxdata_list[57] = 0xffff; /* Channel specific range and maxdata */ - dev->subdevices[i].range_table = 0; + dev->subdevices[i].range_table = NULL; dev->subdevices[i].range_table_list = p->range_table_list; dev->subdevices[i].maxdata = 0; @@ -884,7 +885,7 @@ static int jr3_pci_attach(struct comedi_device *dev, } /* Reset DSP card */ - devpriv->iobase->channel[0].reset = 0; + writel(0, &devpriv->iobase->channel[0].reset); result = comedi_load_firmware(dev, "jr3pci.idm", jr3_download_firmware); dev_dbg(dev->class_dev, "Firmare load %d\n", result); diff --git a/drivers/staging/comedi/drivers/jr3_pci.h b/drivers/staging/comedi/drivers/jr3_pci.h index a1469611d84e..9c42653d8f18 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.h +++ b/drivers/staging/comedi/drivers/jr3_pci.h @@ -97,7 +97,7 @@ enum { mz = 0x0020, changeV2 = 0x0040, changeV1 = 0x0080 -} vect_bits_t; +}; /* WARNING_BITS */ /* The warning_bits structure shows the bit pattern for the warning @@ -116,7 +116,7 @@ enum { mx_near_sat = 0x0008, my_near_sat = 0x0010, mz_near_sat = 0x0020 -} warning_bits_t; +}; /* ERROR_BITS */ /* XX_SAT */ diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c index d4e9292483a0..e867b720f666 100644 --- a/drivers/staging/comedi/drivers/ke_counter.c +++ b/drivers/staging/comedi/drivers/ke_counter.c @@ -28,11 +28,7 @@ Author: Michael Hillmann Updated: Mon, 14 Apr 2008 15:42:42 +0100 Status: tested -Configuration Options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - If bus/slot is not specified, the first supported - PCI device found will be used. +Configuration Options: not applicable, uses PCI auto config This driver is a simple driver to read the counter values from Kolter Electronic PCI Counter Card. @@ -111,82 +107,53 @@ static int cnt_rinsn(struct comedi_device *dev, return 1; } -static struct pci_dev *cnt_find_pci_dev(struct comedi_device *dev, - struct comedi_devconfig *it) +static const void *cnt_find_boardinfo(struct comedi_device *dev, + struct pci_dev *pcidev) { const struct cnt_board_struct *board; - struct pci_dev *pcidev = NULL; - int bus = it->options[0]; - int slot = it->options[1]; int i; - /* Probe the device to determine what device in the series it is. */ - for_each_pci_dev(pcidev) { - if (bus || slot) { - if (pcidev->bus->number != bus || - PCI_SLOT(pcidev->devfn) != slot) - continue; - } - if (pcidev->vendor != PCI_VENDOR_ID_KOLTER) - continue; - - for (i = 0; i < ARRAY_SIZE(cnt_boards); i++) { - board = &cnt_boards[i]; - if (board->device_id != pcidev->device) - continue; - - dev->board_ptr = board; - return pcidev; - } + for (i = 0; i < ARRAY_SIZE(cnt_boards); i++) { + board = &cnt_boards[i]; + if (board->device_id == pcidev->device) + return board; } - dev_err(dev->class_dev, - "No supported board found! (req. bus %d, slot %d)\n", - bus, slot); return NULL; } -static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int cnt_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) { const struct cnt_board_struct *board; - struct pci_dev *pcidev; - struct comedi_subdevice *subdevice; - unsigned long io_base; - int error; - - pcidev = cnt_find_pci_dev(dev, it); - if (!pcidev) - return -EIO; + struct comedi_subdevice *s; + int ret; + comedi_set_hw_dev(dev, &pcidev->dev); - board = comedi_board(dev); + board = cnt_find_boardinfo(dev, pcidev); + if (!board) + return -ENODEV; + dev->board_ptr = board; dev->board_name = board->name; - /* enable PCI device and request regions */ - error = comedi_pci_enable(pcidev, CNT_DRIVER_NAME); - if (error < 0) { - printk(KERN_WARNING "comedi%d: " - "failed to enable PCI device and request regions!\n", - dev->minor); - return error; - } - - /* read register base address [PCI_BASE_ADDRESS #0] */ - io_base = pci_resource_start(pcidev, 0); - dev->iobase = io_base; + ret = comedi_pci_enable(pcidev, dev->board_name); + if (ret) + return ret; + dev->iobase = pci_resource_start(pcidev, 0); - error = comedi_alloc_subdevices(dev, 1); - if (error) - return error; + ret = comedi_alloc_subdevices(dev, 1); + if (ret) + return ret; - subdevice = dev->subdevices + 0; - dev->read_subdev = subdevice; + s = &dev->subdevices[0]; + dev->read_subdev = s; - subdevice->type = COMEDI_SUBD_COUNTER; - subdevice->subdev_flags = SDF_READABLE /* | SDF_COMMON */ ; - subdevice->n_chan = board->cnt_channel_nbr; - subdevice->maxdata = (1 << board->cnt_bits) - 1; - subdevice->insn_read = cnt_rinsn; - subdevice->insn_write = cnt_winsn; + s->type = COMEDI_SUBD_COUNTER; + s->subdev_flags = SDF_READABLE /* | SDF_COMMON */ ; + s->n_chan = board->cnt_channel_nbr; + s->maxdata = (1 << board->cnt_bits) - 1; + s->insn_read = cnt_rinsn; + s->insn_write = cnt_winsn; /* select 20MHz clock */ outb(3, dev->iobase + 248); @@ -196,8 +163,9 @@ static int cnt_attach(struct comedi_device *dev, struct comedi_devconfig *it) outb(0, dev->iobase + 0x20); outb(0, dev->iobase + 0x40); - printk(KERN_INFO "comedi%d: " CNT_DRIVER_NAME " attached.\n", - dev->minor); + dev_info(dev->class_dev, "%s: %s attached\n", + dev->driver->driver_name, dev->board_name); + return 0; } @@ -208,14 +176,13 @@ static void cnt_detach(struct comedi_device *dev) if (pcidev) { if (dev->iobase) comedi_pci_disable(pcidev); - pci_dev_put(pcidev); } } static struct comedi_driver ke_counter_driver = { .driver_name = "ke_counter", .module = THIS_MODULE, - .attach = cnt_attach, + .attach_pci = cnt_attach_pci, .detach = cnt_detach, }; diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c index 9a8258e6fa45..22db35d091f8 100644 --- a/drivers/staging/comedi/drivers/me4000.c +++ b/drivers/staging/comedi/drivers/me4000.c @@ -35,13 +35,7 @@ Supports: - Digital I/O - Counter -Configuration Options: - - [0] - PCI bus number (optional) - [1] - PCI slot number (optional) - - If bus/slot is not specified, the first available PCI - device will be used. +Configuration Options: not applicable, uses PCI auto config The firmware required by these boards is available in the comedi_nonfree_firmware tarball available from @@ -58,51 +52,306 @@ broken. #include <linux/list.h> #include <linux/spinlock.h> -#include "me4000.h" +#include "comedi_fc.h" +#include "8253.h" + #if 0 /* file removed due to GPL incompatibility */ #include "me4000_fw.h" #endif -static const struct me4000_board me4000_boards[] = { - {"ME-4650", 0x4650, {0, 0}, {16, 0, 0, 0}, {4}, {0} }, - - {"ME-4660", 0x4660, {0, 0}, {32, 0, 16, 0}, {4}, {3} }, - {"ME-4660i", 0x4661, {0, 0}, {32, 0, 16, 0}, {4}, {3} }, - {"ME-4660s", 0x4662, {0, 0}, {32, 8, 16, 0}, {4}, {3} }, - {"ME-4660is", 0x4663, {0, 0}, {32, 8, 16, 0}, {4}, {3} }, - - {"ME-4670", 0x4670, {4, 0}, {32, 0, 16, 1}, {4}, {3} }, - {"ME-4670i", 0x4671, {4, 0}, {32, 0, 16, 1}, {4}, {3} }, - {"ME-4670s", 0x4672, {4, 0}, {32, 8, 16, 1}, {4}, {3} }, - {"ME-4670is", 0x4673, {4, 0}, {32, 8, 16, 1}, {4}, {3} }, +#define PCI_VENDOR_ID_MEILHAUS 0x1402 + +#define PCI_DEVICE_ID_MEILHAUS_ME4650 0x4650 +#define PCI_DEVICE_ID_MEILHAUS_ME4660 0x4660 +#define PCI_DEVICE_ID_MEILHAUS_ME4660I 0x4661 +#define PCI_DEVICE_ID_MEILHAUS_ME4660S 0x4662 +#define PCI_DEVICE_ID_MEILHAUS_ME4660IS 0x4663 +#define PCI_DEVICE_ID_MEILHAUS_ME4670 0x4670 +#define PCI_DEVICE_ID_MEILHAUS_ME4670I 0x4671 +#define PCI_DEVICE_ID_MEILHAUS_ME4670S 0x4672 +#define PCI_DEVICE_ID_MEILHAUS_ME4670IS 0x4673 +#define PCI_DEVICE_ID_MEILHAUS_ME4680 0x4680 +#define PCI_DEVICE_ID_MEILHAUS_ME4680I 0x4681 +#define PCI_DEVICE_ID_MEILHAUS_ME4680S 0x4682 +#define PCI_DEVICE_ID_MEILHAUS_ME4680IS 0x4683 - {"ME-4680", 0x4680, {4, 4}, {32, 0, 16, 1}, {4}, {3} }, - {"ME-4680i", 0x4681, {4, 4}, {32, 0, 16, 1}, {4}, {3} }, - {"ME-4680s", 0x4682, {4, 4}, {32, 8, 16, 1}, {4}, {3} }, - {"ME-4680is", 0x4683, {4, 4}, {32, 8, 16, 1}, {4}, {3} }, +/* + * ME4000 Register map and bit defines + */ +#define ME4000_AO_CHAN(x) ((x) * 0x18) + +#define ME4000_AO_CTRL_REG(x) (0x00 + ME4000_AO_CHAN(x)) +#define ME4000_AO_CTRL_BIT_MODE_0 (1 << 0) +#define ME4000_AO_CTRL_BIT_MODE_1 (1 << 1) +#define ME4000_AO_CTRL_MASK_MODE (3 << 0) +#define ME4000_AO_CTRL_BIT_STOP (1 << 2) +#define ME4000_AO_CTRL_BIT_ENABLE_FIFO (1 << 3) +#define ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG (1 << 4) +#define ME4000_AO_CTRL_BIT_EX_TRIG_EDGE (1 << 5) +#define ME4000_AO_CTRL_BIT_IMMEDIATE_STOP (1 << 7) +#define ME4000_AO_CTRL_BIT_ENABLE_DO (1 << 8) +#define ME4000_AO_CTRL_BIT_ENABLE_IRQ (1 << 9) +#define ME4000_AO_CTRL_BIT_RESET_IRQ (1 << 10) +#define ME4000_AO_STATUS_REG(x) (0x04 + ME4000_AO_CHAN(x)) +#define ME4000_AO_STATUS_BIT_FSM (1 << 0) +#define ME4000_AO_STATUS_BIT_FF (1 << 1) +#define ME4000_AO_STATUS_BIT_HF (1 << 2) +#define ME4000_AO_STATUS_BIT_EF (1 << 3) +#define ME4000_AO_FIFO_REG(x) (0x08 + ME4000_AO_CHAN(x)) +#define ME4000_AO_SINGLE_REG(x) (0x0c + ME4000_AO_CHAN(x)) +#define ME4000_AO_TIMER_REG(x) (0x10 + ME4000_AO_CHAN(x)) +#define ME4000_AI_CTRL_REG 0x74 +#define ME4000_AI_STATUS_REG 0x74 +#define ME4000_AI_CTRL_BIT_MODE_0 (1 << 0) +#define ME4000_AI_CTRL_BIT_MODE_1 (1 << 1) +#define ME4000_AI_CTRL_BIT_MODE_2 (1 << 2) +#define ME4000_AI_CTRL_BIT_SAMPLE_HOLD (1 << 3) +#define ME4000_AI_CTRL_BIT_IMMEDIATE_STOP (1 << 4) +#define ME4000_AI_CTRL_BIT_STOP (1 << 5) +#define ME4000_AI_CTRL_BIT_CHANNEL_FIFO (1 << 6) +#define ME4000_AI_CTRL_BIT_DATA_FIFO (1 << 7) +#define ME4000_AI_CTRL_BIT_FULLSCALE (1 << 8) +#define ME4000_AI_CTRL_BIT_OFFSET (1 << 9) +#define ME4000_AI_CTRL_BIT_EX_TRIG_ANALOG (1 << 10) +#define ME4000_AI_CTRL_BIT_EX_TRIG (1 << 11) +#define ME4000_AI_CTRL_BIT_EX_TRIG_FALLING (1 << 12) +#define ME4000_AI_CTRL_BIT_EX_IRQ (1 << 13) +#define ME4000_AI_CTRL_BIT_EX_IRQ_RESET (1 << 14) +#define ME4000_AI_CTRL_BIT_LE_IRQ (1 << 15) +#define ME4000_AI_CTRL_BIT_LE_IRQ_RESET (1 << 16) +#define ME4000_AI_CTRL_BIT_HF_IRQ (1 << 17) +#define ME4000_AI_CTRL_BIT_HF_IRQ_RESET (1 << 18) +#define ME4000_AI_CTRL_BIT_SC_IRQ (1 << 19) +#define ME4000_AI_CTRL_BIT_SC_IRQ_RESET (1 << 20) +#define ME4000_AI_CTRL_BIT_SC_RELOAD (1 << 21) +#define ME4000_AI_STATUS_BIT_EF_CHANNEL (1 << 22) +#define ME4000_AI_STATUS_BIT_HF_CHANNEL (1 << 23) +#define ME4000_AI_STATUS_BIT_FF_CHANNEL (1 << 24) +#define ME4000_AI_STATUS_BIT_EF_DATA (1 << 25) +#define ME4000_AI_STATUS_BIT_HF_DATA (1 << 26) +#define ME4000_AI_STATUS_BIT_FF_DATA (1 << 27) +#define ME4000_AI_STATUS_BIT_LE (1 << 28) +#define ME4000_AI_STATUS_BIT_FSM (1 << 29) +#define ME4000_AI_CTRL_BIT_EX_TRIG_BOTH (1 << 31) +#define ME4000_AI_CHANNEL_LIST_REG 0x78 +#define ME4000_AI_LIST_INPUT_SINGLE_ENDED (0 << 5) +#define ME4000_AI_LIST_INPUT_DIFFERENTIAL (1 << 5) +#define ME4000_AI_LIST_RANGE_BIPOLAR_10 (0 << 6) +#define ME4000_AI_LIST_RANGE_BIPOLAR_2_5 (1 << 6) +#define ME4000_AI_LIST_RANGE_UNIPOLAR_10 (2 << 6) +#define ME4000_AI_LIST_RANGE_UNIPOLAR_2_5 (3 << 6) +#define ME4000_AI_LIST_LAST_ENTRY (1 << 8) +#define ME4000_AI_DATA_REG 0x7c +#define ME4000_AI_CHAN_TIMER_REG 0x80 +#define ME4000_AI_CHAN_PRE_TIMER_REG 0x84 +#define ME4000_AI_SCAN_TIMER_LOW_REG 0x88 +#define ME4000_AI_SCAN_TIMER_HIGH_REG 0x8c +#define ME4000_AI_SCAN_PRE_TIMER_LOW_REG 0x90 +#define ME4000_AI_SCAN_PRE_TIMER_HIGH_REG 0x94 +#define ME4000_AI_START_REG 0x98 +#define ME4000_IRQ_STATUS_REG 0x9c +#define ME4000_IRQ_STATUS_BIT_EX (1 << 0) +#define ME4000_IRQ_STATUS_BIT_LE (1 << 1) +#define ME4000_IRQ_STATUS_BIT_AI_HF (1 << 2) +#define ME4000_IRQ_STATUS_BIT_AO_0_HF (1 << 3) +#define ME4000_IRQ_STATUS_BIT_AO_1_HF (1 << 4) +#define ME4000_IRQ_STATUS_BIT_AO_2_HF (1 << 5) +#define ME4000_IRQ_STATUS_BIT_AO_3_HF (1 << 6) +#define ME4000_IRQ_STATUS_BIT_SC (1 << 7) +#define ME4000_DIO_PORT_0_REG 0xa0 +#define ME4000_DIO_PORT_1_REG 0xa4 +#define ME4000_DIO_PORT_2_REG 0xa8 +#define ME4000_DIO_PORT_3_REG 0xac +#define ME4000_DIO_DIR_REG 0xb0 +#define ME4000_AO_LOADSETREG_XX 0xb4 +#define ME4000_DIO_CTRL_REG 0xb8 +#define ME4000_DIO_CTRL_BIT_MODE_0 (1 << 0) +#define ME4000_DIO_CTRL_BIT_MODE_1 (1 << 1) +#define ME4000_DIO_CTRL_BIT_MODE_2 (1 << 2) +#define ME4000_DIO_CTRL_BIT_MODE_3 (1 << 3) +#define ME4000_DIO_CTRL_BIT_MODE_4 (1 << 4) +#define ME4000_DIO_CTRL_BIT_MODE_5 (1 << 5) +#define ME4000_DIO_CTRL_BIT_MODE_6 (1 << 6) +#define ME4000_DIO_CTRL_BIT_MODE_7 (1 << 7) +#define ME4000_DIO_CTRL_BIT_FUNCTION_0 (1 << 8) +#define ME4000_DIO_CTRL_BIT_FUNCTION_1 (1 << 9) +#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_0 (1 << 10) +#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_1 (1 << 11) +#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_2 (1 << 12) +#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_3 (1 << 13) +#define ME4000_AO_DEMUX_ADJUST_REG 0xbc +#define ME4000_AO_DEMUX_ADJUST_VALUE 0x4c +#define ME4000_AI_SAMPLE_COUNTER_REG 0xc0 - {0}, +/* + * PLX Register map and bit defines + */ +#define PLX_INTCSR 0x4c +#define PLX_INTCSR_LOCAL_INT1_EN (1 << 0) +#define PLX_INTCSR_LOCAL_INT1_POL (1 << 1) +#define PLX_INTCSR_LOCAL_INT1_STATE (1 << 2) +#define PLX_INTCSR_LOCAL_INT2_EN (1 << 3) +#define PLX_INTCSR_LOCAL_INT2_POL (1 << 4) +#define PLX_INTCSR_LOCAL_INT2_STATE (1 << 5) +#define PLX_INTCSR_PCI_INT_EN (1 << 6) +#define PLX_INTCSR_SOFT_INT (1 << 7) +#define PLX_ICR 0x50 +#define PLX_ICR_BIT_EEPROM_CLOCK_SET (1 << 24) +#define PLX_ICR_BIT_EEPROM_CHIP_SELECT (1 << 25) +#define PLX_ICR_BIT_EEPROM_WRITE (1 << 26) +#define PLX_ICR_BIT_EEPROM_READ (1 << 27) +#define PLX_ICR_BIT_EEPROM_VALID (1 << 28) +#define PLX_ICR_MASK_EEPROM (0x1f << 24) + +#define EEPROM_DELAY 1 + +#define ME4000_AI_FIFO_COUNT 2048 + +#define ME4000_AI_MIN_TICKS 66 +#define ME4000_AI_MIN_SAMPLE_TIME 2000 +#define ME4000_AI_BASE_FREQUENCY (unsigned int) 33E6 + +#define ME4000_AI_CHANNEL_LIST_COUNT 1024 + +struct me4000_info { + unsigned long plx_regbase; + unsigned long timer_regbase; + + unsigned int ao_readback[4]; }; -#define ME4000_BOARD_VERSIONS (ARRAY_SIZE(me4000_boards) - 1) - -/*----------------------------------------------------------------------------- - Meilhaus function prototypes - ---------------------------------------------------------------------------*/ -static int get_registers(struct comedi_device *dev, struct pci_dev *pci_dev_p); -static int init_board_info(struct comedi_device *dev, - struct pci_dev *pci_dev_p); -static int init_ao_context(struct comedi_device *dev); -static int init_ai_context(struct comedi_device *dev); -static int init_dio_context(struct comedi_device *dev); -static int init_cnt_context(struct comedi_device *dev); -static int xilinx_download(struct comedi_device *dev); -static int reset_board(struct comedi_device *dev); +struct me4000_board { + const char *name; + unsigned short device_id; + int ao_nchan; + int ao_fifo; + int ai_nchan; + int ai_diff_nchan; + int ai_sh_nchan; + int ex_trig_analog; + int dio_nchan; + int has_counter; +}; -static int ai_write_chanlist(struct comedi_device *dev, - struct comedi_subdevice *s, - struct comedi_cmd *cmd); +static const struct me4000_board me4000_boards[] = { + { + .name = "ME-4650", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4650, + .ai_nchan = 16, + .dio_nchan = 32, + }, { + .name = "ME-4660", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4660, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .dio_nchan = 32, + .has_counter = 1, + }, { + .name = "ME-4660i", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4660I, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .dio_nchan = 32, + .has_counter = 1, + }, { + .name = "ME-4660s", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4660S, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ai_sh_nchan = 8, + .dio_nchan = 32, + .has_counter = 1, + }, { + .name = "ME-4660is", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4660IS, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ai_sh_nchan = 8, + .dio_nchan = 32, + .has_counter = 1, + }, { + .name = "ME-4670", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4670, + .ao_nchan = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, { + .name = "ME-4670i", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4670I, + .ao_nchan = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, { + .name = "ME-4670s", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4670S, + .ao_nchan = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ai_sh_nchan = 8, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, { + .name = "ME-4670is", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4670IS, + .ao_nchan = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ai_sh_nchan = 8, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, { + .name = "ME-4680", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4680, + .ao_nchan = 4, + .ao_fifo = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, { + .name = "ME-4680i", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4680I, + .ao_nchan = 4, + .ao_fifo = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, { + .name = "ME-4680s", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4680S, + .ao_nchan = 4, + .ao_fifo = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ai_sh_nchan = 8, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, { + .name = "ME-4680is", + .device_id = PCI_DEVICE_ID_MEILHAUS_ME4680IS, + .ao_nchan = 4, + .ao_fifo = 4, + .ai_nchan = 32, + .ai_diff_nchan = 16, + .ai_sh_nchan = 8, + .ex_trig_analog = 1, + .dio_nchan = 32, + .has_counter = 1, + }, +}; static const struct comedi_lrange me4000_ai_range = { 4, @@ -114,380 +363,6 @@ static const struct comedi_lrange me4000_ai_range = { } }; -static const struct comedi_lrange me4000_ao_range = { - 1, - { - BIP_RANGE(10), - } -}; - -static int me4000_probe(struct comedi_device *dev, struct comedi_devconfig *it) -{ - struct pci_dev *pci_device = NULL; - int result, i; - struct me4000_board *board; - - /* Allocate private memory */ - if (alloc_private(dev, sizeof(struct me4000_info)) < 0) - return -ENOMEM; - - /* - * Probe the device to determine what device in the series it is. - */ - for_each_pci_dev(pci_device) { - if (pci_device->vendor == PCI_VENDOR_ID_MEILHAUS) { - for (i = 0; i < ME4000_BOARD_VERSIONS; i++) { - if (me4000_boards[i].device_id == - pci_device->device) { - /* - * Was a particular - * bus/slot requested? - */ - if ((it->options[0] != 0) - || (it->options[1] != 0)) { - /* - * Are we on the wrong - * bus/slot? - */ - if (pci_device->bus->number != - it->options[0] - || - PCI_SLOT(pci_device->devfn) - != it->options[1]) { - continue; - } - } - dev->board_ptr = me4000_boards + i; - board = - (struct me4000_board *) - dev->board_ptr; - info->pci_dev_p = pci_device; - goto found; - } - } - } - } - - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "No supported board found (req. bus/slot : %d/%d)\n", - dev->minor, it->options[0], it->options[1]); - return -ENODEV; - -found: - - printk(KERN_INFO - "comedi%d: me4000: me4000_probe(): " - "Found %s at PCI bus %d, slot %d\n", - dev->minor, me4000_boards[i].name, pci_device->bus->number, - PCI_SLOT(pci_device->devfn)); - - /* Set data in device structure */ - dev->board_name = board->name; - - /* Enable PCI device and request regions */ - result = comedi_pci_enable(pci_device, dev->board_name); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): Cannot enable PCI " - "device and request I/O regions\n", dev->minor); - return result; - } - - /* Get the PCI base registers */ - result = get_registers(dev, pci_device); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "Cannot get registers\n", dev->minor); - return result; - } - /* Initialize board info */ - result = init_board_info(dev, pci_device); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "Cannot init baord info\n", dev->minor); - return result; - } - - /* Init analog output context */ - result = init_ao_context(dev); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "Cannot init ao context\n", dev->minor); - return result; - } - - /* Init analog input context */ - result = init_ai_context(dev); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "Cannot init ai context\n", dev->minor); - return result; - } - - /* Init digital I/O context */ - result = init_dio_context(dev); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "Cannot init dio context\n", dev->minor); - return result; - } - - /* Init counter context */ - result = init_cnt_context(dev); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "Cannot init cnt context\n", dev->minor); - return result; - } - - /* Download the xilinx firmware */ - result = xilinx_download(dev); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): " - "Can't download firmware\n", dev->minor); - return result; - } - - /* Make a hardware reset */ - result = reset_board(dev); - if (result) { - printk(KERN_ERR - "comedi%d: me4000: me4000_probe(): Can't reset board\n", - dev->minor); - return result; - } - - return 0; -} - -static int get_registers(struct comedi_device *dev, struct pci_dev *pci_dev_p) -{ - /*--------------------------- plx regbase -------------------------------*/ - - info->plx_regbase = pci_resource_start(pci_dev_p, 1); - if (info->plx_regbase == 0) { - printk(KERN_ERR - "comedi%d: me4000: get_registers(): " - "PCI base address 1 is not available\n", dev->minor); - return -ENODEV; - } - info->plx_regbase_size = pci_resource_len(pci_dev_p, 1); - - /*--------------------------- me4000 regbase ----------------------------*/ - - info->me4000_regbase = pci_resource_start(pci_dev_p, 2); - if (info->me4000_regbase == 0) { - printk(KERN_ERR - "comedi%d: me4000: get_registers(): " - "PCI base address 2 is not available\n", dev->minor); - return -ENODEV; - } - info->me4000_regbase_size = pci_resource_len(pci_dev_p, 2); - - /*--------------------------- timer regbase ------------------------------*/ - - info->timer_regbase = pci_resource_start(pci_dev_p, 3); - if (info->timer_regbase == 0) { - printk(KERN_ERR - "comedi%d: me4000: get_registers(): " - "PCI base address 3 is not available\n", dev->minor); - return -ENODEV; - } - info->timer_regbase_size = pci_resource_len(pci_dev_p, 3); - - /*--------------------------- program regbase ----------------------------*/ - - info->program_regbase = pci_resource_start(pci_dev_p, 5); - if (info->program_regbase == 0) { - printk(KERN_ERR - "comedi%d: me4000: get_registers(): " - "PCI base address 5 is not available\n", dev->minor); - return -ENODEV; - } - info->program_regbase_size = pci_resource_len(pci_dev_p, 5); - - return 0; -} - -static int init_board_info(struct comedi_device *dev, struct pci_dev *pci_dev_p) -{ - int result; - - /* Init spin locks */ - /* spin_lock_init(&info->preload_lock); */ - /* spin_lock_init(&info->ai_ctrl_lock); */ - - /* Get the serial number */ - result = pci_read_config_dword(pci_dev_p, 0x2C, &info->serial_no); - if (result != PCIBIOS_SUCCESSFUL) - return result; - - /* Get the hardware revision */ - result = pci_read_config_byte(pci_dev_p, 0x08, &info->hw_revision); - if (result != PCIBIOS_SUCCESSFUL) - return result; - - /* Get the vendor id */ - info->vendor_id = pci_dev_p->vendor; - - /* Get the device id */ - info->device_id = pci_dev_p->device; - - /* Get the irq assigned to the board */ - info->irq = pci_dev_p->irq; - - return 0; -} - -static int init_ao_context(struct comedi_device *dev) -{ - int i; - - for (i = 0; i < thisboard->ao.count; i++) { - /* spin_lock_init(&info->ao_context[i].use_lock); */ - info->ao_context[i].irq = info->irq; - - switch (i) { - case 0: - info->ao_context[i].ctrl_reg = - info->me4000_regbase + ME4000_AO_00_CTRL_REG; - info->ao_context[i].status_reg = - info->me4000_regbase + ME4000_AO_00_STATUS_REG; - info->ao_context[i].fifo_reg = - info->me4000_regbase + ME4000_AO_00_FIFO_REG; - info->ao_context[i].single_reg = - info->me4000_regbase + ME4000_AO_00_SINGLE_REG; - info->ao_context[i].timer_reg = - info->me4000_regbase + ME4000_AO_00_TIMER_REG; - info->ao_context[i].irq_status_reg = - info->me4000_regbase + ME4000_IRQ_STATUS_REG; - info->ao_context[i].preload_reg = - info->me4000_regbase + ME4000_AO_LOADSETREG_XX; - break; - case 1: - info->ao_context[i].ctrl_reg = - info->me4000_regbase + ME4000_AO_01_CTRL_REG; - info->ao_context[i].status_reg = - info->me4000_regbase + ME4000_AO_01_STATUS_REG; - info->ao_context[i].fifo_reg = - info->me4000_regbase + ME4000_AO_01_FIFO_REG; - info->ao_context[i].single_reg = - info->me4000_regbase + ME4000_AO_01_SINGLE_REG; - info->ao_context[i].timer_reg = - info->me4000_regbase + ME4000_AO_01_TIMER_REG; - info->ao_context[i].irq_status_reg = - info->me4000_regbase + ME4000_IRQ_STATUS_REG; - info->ao_context[i].preload_reg = - info->me4000_regbase + ME4000_AO_LOADSETREG_XX; - break; - case 2: - info->ao_context[i].ctrl_reg = - info->me4000_regbase + ME4000_AO_02_CTRL_REG; - info->ao_context[i].status_reg = - info->me4000_regbase + ME4000_AO_02_STATUS_REG; - info->ao_context[i].fifo_reg = - info->me4000_regbase + ME4000_AO_02_FIFO_REG; - info->ao_context[i].single_reg = - info->me4000_regbase + ME4000_AO_02_SINGLE_REG; - info->ao_context[i].timer_reg = - info->me4000_regbase + ME4000_AO_02_TIMER_REG; - info->ao_context[i].irq_status_reg = - info->me4000_regbase + ME4000_IRQ_STATUS_REG; - info->ao_context[i].preload_reg = - info->me4000_regbase + ME4000_AO_LOADSETREG_XX; - break; - case 3: - info->ao_context[i].ctrl_reg = - info->me4000_regbase + ME4000_AO_03_CTRL_REG; - info->ao_context[i].status_reg = - info->me4000_regbase + ME4000_AO_03_STATUS_REG; - info->ao_context[i].fifo_reg = - info->me4000_regbase + ME4000_AO_03_FIFO_REG; - info->ao_context[i].single_reg = - info->me4000_regbase + ME4000_AO_03_SINGLE_REG; - info->ao_context[i].timer_reg = - info->me4000_regbase + ME4000_AO_03_TIMER_REG; - info->ao_context[i].irq_status_reg = - info->me4000_regbase + ME4000_IRQ_STATUS_REG; - info->ao_context[i].preload_reg = - info->me4000_regbase + ME4000_AO_LOADSETREG_XX; - break; - default: - break; - } - } - - return 0; -} - -static int init_ai_context(struct comedi_device *dev) -{ - info->ai_context.irq = info->irq; - - info->ai_context.ctrl_reg = info->me4000_regbase + ME4000_AI_CTRL_REG; - info->ai_context.status_reg = - info->me4000_regbase + ME4000_AI_STATUS_REG; - info->ai_context.channel_list_reg = - info->me4000_regbase + ME4000_AI_CHANNEL_LIST_REG; - info->ai_context.data_reg = info->me4000_regbase + ME4000_AI_DATA_REG; - info->ai_context.chan_timer_reg = - info->me4000_regbase + ME4000_AI_CHAN_TIMER_REG; - info->ai_context.chan_pre_timer_reg = - info->me4000_regbase + ME4000_AI_CHAN_PRE_TIMER_REG; - info->ai_context.scan_timer_low_reg = - info->me4000_regbase + ME4000_AI_SCAN_TIMER_LOW_REG; - info->ai_context.scan_timer_high_reg = - info->me4000_regbase + ME4000_AI_SCAN_TIMER_HIGH_REG; - info->ai_context.scan_pre_timer_low_reg = - info->me4000_regbase + ME4000_AI_SCAN_PRE_TIMER_LOW_REG; - info->ai_context.scan_pre_timer_high_reg = - info->me4000_regbase + ME4000_AI_SCAN_PRE_TIMER_HIGH_REG; - info->ai_context.start_reg = info->me4000_regbase + ME4000_AI_START_REG; - info->ai_context.irq_status_reg = - info->me4000_regbase + ME4000_IRQ_STATUS_REG; - info->ai_context.sample_counter_reg = - info->me4000_regbase + ME4000_AI_SAMPLE_COUNTER_REG; - - return 0; -} - -static int init_dio_context(struct comedi_device *dev) -{ - info->dio_context.dir_reg = info->me4000_regbase + ME4000_DIO_DIR_REG; - info->dio_context.ctrl_reg = info->me4000_regbase + ME4000_DIO_CTRL_REG; - info->dio_context.port_0_reg = - info->me4000_regbase + ME4000_DIO_PORT_0_REG; - info->dio_context.port_1_reg = - info->me4000_regbase + ME4000_DIO_PORT_1_REG; - info->dio_context.port_2_reg = - info->me4000_regbase + ME4000_DIO_PORT_2_REG; - info->dio_context.port_3_reg = - info->me4000_regbase + ME4000_DIO_PORT_3_REG; - - return 0; -} - -static int init_cnt_context(struct comedi_device *dev) -{ - info->cnt_context.ctrl_reg = info->timer_regbase + ME4000_CNT_CTRL_REG; - info->cnt_context.counter_0_reg = - info->timer_regbase + ME4000_CNT_COUNTER_0_REG; - info->cnt_context.counter_1_reg = - info->timer_regbase + ME4000_CNT_COUNTER_1_REG; - info->cnt_context.counter_2_reg = - info->timer_regbase + ME4000_CNT_COUNTER_2_REG; - - return 0; -} - #define FIRMWARE_NOT_AVAILABLE 1 #if FIRMWARE_NOT_AVAILABLE extern unsigned char *xilinx_firm; @@ -495,11 +370,17 @@ extern unsigned char *xilinx_firm; static int xilinx_download(struct comedi_device *dev) { + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + struct me4000_info *info = dev->private; + unsigned long xilinx_iobase = pci_resource_start(pcidev, 5); u32 value = 0; wait_queue_head_t queue; int idx = 0; int size = 0; + if (!xilinx_iobase) + return -ENODEV; + init_waitqueue_head(&queue); /* @@ -514,14 +395,12 @@ static int xilinx_download(struct comedi_device *dev) outl(value, info->plx_regbase + PLX_ICR); /* Init Xilinx with CS1 */ - inb(info->program_regbase + 0xC8); + inb(xilinx_iobase + 0xC8); /* Wait until /INIT pin is set */ udelay(20); if (!(inl(info->plx_regbase + PLX_INTCSR) & 0x20)) { - printk(KERN_ERR - "comedi%d: me4000: xilinx_download(): " - "Can't init Xilinx\n", dev->minor); + dev_err(dev->class_dev, "Can't init Xilinx\n"); return -EIO; } @@ -530,8 +409,8 @@ static int xilinx_download(struct comedi_device *dev) value &= ~0x100; outl(value, info->plx_regbase + PLX_ICR); if (FIRMWARE_NOT_AVAILABLE) { - comedi_error(dev, "xilinx firmware unavailable " - "due to licensing, aborting"); + dev_err(dev->class_dev, + "xilinx firmware unavailable due to licensing, aborting"); return -EIO; } else { /* Download Xilinx firmware */ @@ -540,15 +419,14 @@ static int xilinx_download(struct comedi_device *dev) udelay(10); for (idx = 0; idx < size; idx++) { - outb(xilinx_firm[16 + idx], info->program_regbase); + outb(xilinx_firm[16 + idx], xilinx_iobase); udelay(10); /* Check if BUSY flag is low */ if (inl(info->plx_regbase + PLX_ICR) & 0x20) { - printk(KERN_ERR - "comedi%d: me4000: xilinx_download(): " - "Xilinx is still busy (idx = %d)\n", - dev->minor, idx); + dev_err(dev->class_dev, + "Xilinx is still busy (idx = %d)\n", + idx); return -EIO; } } @@ -557,12 +435,8 @@ static int xilinx_download(struct comedi_device *dev) /* If done flag is high download was successful */ if (inl(info->plx_regbase + PLX_ICR) & 0x4) { } else { - printk(KERN_ERR - "comedi%d: me4000: xilinx_download(): " - "DONE flag is not set\n", dev->minor); - printk(KERN_ERR - "comedi%d: me4000: xilinx_download(): " - "Download not successful\n", dev->minor); + dev_err(dev->class_dev, "DONE flag is not set\n"); + dev_err(dev->class_dev, "Download not successful\n"); return -EIO; } @@ -574,52 +448,45 @@ static int xilinx_download(struct comedi_device *dev) return 0; } -static int reset_board(struct comedi_device *dev) +static void me4000_reset(struct comedi_device *dev) { - unsigned long icr; + struct me4000_info *info = dev->private; + unsigned long val; + int chan; /* Make a hardware reset */ - icr = inl(info->plx_regbase + PLX_ICR); - icr |= 0x40000000; - outl(icr, info->plx_regbase + PLX_ICR); - icr &= ~0x40000000; - outl(icr, info->plx_regbase + PLX_ICR); + val = inl(info->plx_regbase + PLX_ICR); + val |= 0x40000000; + outl(val, info->plx_regbase + PLX_ICR); + val &= ~0x40000000; + outl(val , info->plx_regbase + PLX_ICR); /* 0x8000 to the DACs means an output voltage of 0V */ - outl(0x8000, info->me4000_regbase + ME4000_AO_00_SINGLE_REG); - outl(0x8000, info->me4000_regbase + ME4000_AO_01_SINGLE_REG); - outl(0x8000, info->me4000_regbase + ME4000_AO_02_SINGLE_REG); - outl(0x8000, info->me4000_regbase + ME4000_AO_03_SINGLE_REG); + for (chan = 0; chan < 4; chan++) + outl(0x8000, dev->iobase + ME4000_AO_SINGLE_REG(chan)); /* Set both stop bits in the analog input control register */ outl(ME4000_AI_CTRL_BIT_IMMEDIATE_STOP | ME4000_AI_CTRL_BIT_STOP, - info->me4000_regbase + ME4000_AI_CTRL_REG); + dev->iobase + ME4000_AI_CTRL_REG); /* Set both stop bits in the analog output control register */ - outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, - info->me4000_regbase + ME4000_AO_00_CTRL_REG); - outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, - info->me4000_regbase + ME4000_AO_01_CTRL_REG); - outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, - info->me4000_regbase + ME4000_AO_02_CTRL_REG); - outl(ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP, - info->me4000_regbase + ME4000_AO_03_CTRL_REG); + val = ME4000_AO_CTRL_BIT_IMMEDIATE_STOP | ME4000_AO_CTRL_BIT_STOP; + for (chan = 0; chan < 4; chan++) + outl(val, dev->iobase + ME4000_AO_CTRL_REG(chan)); /* Enable interrupts on the PLX */ outl(0x43, info->plx_regbase + PLX_INTCSR); /* Set the adustment register for AO demux */ outl(ME4000_AO_DEMUX_ADJUST_VALUE, - info->me4000_regbase + ME4000_AO_DEMUX_ADJUST_REG); + dev->iobase + ME4000_AO_DEMUX_ADJUST_REG); /* * Set digital I/O direction for port 0 * to output on isolated versions */ - if (!(inl(info->me4000_regbase + ME4000_DIO_DIR_REG) & 0x1)) - outl(0x1, info->me4000_regbase + ME4000_DIO_CTRL_REG); - - return 0; + if (!(inl(dev->iobase + ME4000_DIO_DIR_REG) & 0x1)) + outl(0x1, dev->iobase + ME4000_DIO_CTRL_REG); } /*============================================================================= @@ -630,7 +497,7 @@ static int me4000_ai_insn_read(struct comedi_device *dev, struct comedi_subdevice *subdevice, struct comedi_insn *insn, unsigned int *data) { - + const struct me4000_board *thisboard = comedi_board(dev); int chan = CR_CHAN(insn->chanspec); int rang = CR_RANGE(insn->chanspec); int aref = CR_AREF(insn->chanspec); @@ -642,9 +509,8 @@ static int me4000_ai_insn_read(struct comedi_device *dev, if (insn->n == 0) { return 0; } else if (insn->n > 1) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_insn_read(): " - "Invalid instruction length %d\n", dev->minor, insn->n); + dev_err(dev->class_dev, "Invalid instruction length %d\n", + insn->n); return -EINVAL; } @@ -662,19 +528,16 @@ static int me4000_ai_insn_read(struct comedi_device *dev, entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10; break; default: - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_insn_read(): " - "Invalid range specified\n", dev->minor); + dev_err(dev->class_dev, "Invalid range specified\n"); return -EINVAL; } switch (aref) { case AREF_GROUND: case AREF_COMMON: - if (chan >= thisboard->ai.count) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_insn_read(): " - "Analog input is not available\n", dev->minor); + if (chan >= thisboard->ai_nchan) { + dev_err(dev->class_dev, + "Analog input is not available\n"); return -EINVAL; } entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED | chan; @@ -682,68 +545,61 @@ static int me4000_ai_insn_read(struct comedi_device *dev, case AREF_DIFF: if (rang == 0 || rang == 1) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_insn_read(): " - "Range must be bipolar when aref = diff\n", - dev->minor); + dev_err(dev->class_dev, + "Range must be bipolar when aref = diff\n"); return -EINVAL; } - if (chan >= thisboard->ai.diff_count) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_insn_read(): " - "Analog input is not available\n", dev->minor); + if (chan >= thisboard->ai_diff_nchan) { + dev_err(dev->class_dev, + "Analog input is not available\n"); return -EINVAL; } entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL | chan; break; default: - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_insn_read(): " - "Invalid aref specified\n", dev->minor); + dev_err(dev->class_dev, "Invalid aref specified\n"); return -EINVAL; } entry |= ME4000_AI_LIST_LAST_ENTRY; /* Clear channel list, data fifo and both stop bits */ - tmp = inl(info->ai_context.ctrl_reg); + tmp = inl(dev->iobase + ME4000_AI_CTRL_REG); tmp &= ~(ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_DATA_FIFO | ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP); - outl(tmp, info->ai_context.ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Set the acquisition mode to single */ tmp &= ~(ME4000_AI_CTRL_BIT_MODE_0 | ME4000_AI_CTRL_BIT_MODE_1 | ME4000_AI_CTRL_BIT_MODE_2); - outl(tmp, info->ai_context.ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Enable channel list and data fifo */ tmp |= ME4000_AI_CTRL_BIT_CHANNEL_FIFO | ME4000_AI_CTRL_BIT_DATA_FIFO; - outl(tmp, info->ai_context.ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Generate channel list entry */ - outl(entry, info->ai_context.channel_list_reg); + outl(entry, dev->iobase + ME4000_AI_CHANNEL_LIST_REG); /* Set the timer to maximum sample rate */ - outl(ME4000_AI_MIN_TICKS, info->ai_context.chan_timer_reg); - outl(ME4000_AI_MIN_TICKS, info->ai_context.chan_pre_timer_reg); + outl(ME4000_AI_MIN_TICKS, dev->iobase + ME4000_AI_CHAN_TIMER_REG); + outl(ME4000_AI_MIN_TICKS, dev->iobase + ME4000_AI_CHAN_PRE_TIMER_REG); /* Start conversion by dummy read */ - inl(info->ai_context.start_reg); + inl(dev->iobase + ME4000_AI_START_REG); /* Wait until ready */ udelay(10); - if (!(inl(info->ai_context.status_reg) & + if (!(inl(dev->iobase + ME4000_AI_STATUS_REG) & ME4000_AI_STATUS_BIT_EF_DATA)) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_insn_read(): " - "Value not available after wait\n", dev->minor); + dev_err(dev->class_dev, "Value not available after wait\n"); return -EIO; } /* Read value from data fifo */ - lval = inl(info->ai_context.data_reg) & 0xFFFF; + lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF; data[0] = lval ^ 0x8000; return 1; @@ -755,12 +611,12 @@ static int me4000_ai_cancel(struct comedi_device *dev, unsigned long tmp; /* Stop any running conversion */ - tmp = inl(info->ai_context.ctrl_reg); + tmp = inl(dev->iobase + ME4000_AI_CTRL_REG); tmp &= ~(ME4000_AI_CTRL_BIT_STOP | ME4000_AI_CTRL_BIT_IMMEDIATE_STOP); - outl(tmp, info->ai_context.ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Clear the control register */ - outl(0x0, info->ai_context.ctrl_reg); + outl(0x0, dev->iobase + ME4000_AI_CTRL_REG); return 0; } @@ -768,30 +624,25 @@ static int me4000_ai_cancel(struct comedi_device *dev, static int ai_check_chanlist(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { + const struct me4000_board *thisboard = comedi_board(dev); int aref; int i; /* Check whether a channel list is available */ if (!cmd->chanlist_len) { - printk(KERN_ERR - "comedi%d: me4000: ai_check_chanlist(): " - "No channel list available\n", dev->minor); + dev_err(dev->class_dev, "No channel list available\n"); return -EINVAL; } /* Check the channel list size */ if (cmd->chanlist_len > ME4000_AI_CHANNEL_LIST_COUNT) { - printk(KERN_ERR - "comedi%d: me4000: ai_check_chanlist(): " - "Channel list is to large\n", dev->minor); + dev_err(dev->class_dev, "Channel list is to large\n"); return -EINVAL; } /* Check the pointer */ if (!cmd->chanlist) { - printk(KERN_ERR - "comedi%d: me4000: ai_check_chanlist(): " - "NULL pointer to channel list\n", dev->minor); + dev_err(dev->class_dev, "NULL pointer to channel list\n"); return -EFAULT; } @@ -799,10 +650,8 @@ static int ai_check_chanlist(struct comedi_device *dev, aref = CR_AREF(cmd->chanlist[0]); for (i = 0; i < cmd->chanlist_len; i++) { if (CR_AREF(cmd->chanlist[i]) != aref) { - printk(KERN_ERR - "comedi%d: me4000: ai_check_chanlist(): " - "Mode is not equal for all entries\n", - dev->minor); + dev_err(dev->class_dev, + "Mode is not equal for all entries\n"); return -EINVAL; } } @@ -811,19 +660,17 @@ static int ai_check_chanlist(struct comedi_device *dev, if (aref == SDF_DIFF) { for (i = 0; i < cmd->chanlist_len; i++) { if (CR_CHAN(cmd->chanlist[i]) >= - thisboard->ai.diff_count) { - printk(KERN_ERR - "comedi%d: me4000: ai_check_chanlist():" - " Channel number to high\n", dev->minor); + thisboard->ai_diff_nchan) { + dev_err(dev->class_dev, + "Channel number to high\n"); return -EINVAL; } } } else { for (i = 0; i < cmd->chanlist_len; i++) { - if (CR_CHAN(cmd->chanlist[i]) >= thisboard->ai.count) { - printk(KERN_ERR - "comedi%d: me4000: ai_check_chanlist(): " - "Channel number to high\n", dev->minor); + if (CR_CHAN(cmd->chanlist[i]) >= thisboard->ai_nchan) { + dev_err(dev->class_dev, + "Channel number to high\n"); return -EINVAL; } } @@ -834,11 +681,8 @@ static int ai_check_chanlist(struct comedi_device *dev, for (i = 0; i < cmd->chanlist_len; i++) { if (CR_RANGE(cmd->chanlist[i]) != 1 && CR_RANGE(cmd->chanlist[i]) != 2) { - printk(KERN_ERR - "comedi%d: me4000: ai_check_chanlist(): " - "Bipolar is not selected in " - "differential mode\n", - dev->minor); + dev_err(dev->class_dev, + "Bipolar is not selected in differential mode\n"); return -EINVAL; } } @@ -906,16 +750,52 @@ static void ai_write_timer(struct comedi_device *dev, unsigned int init_ticks, unsigned int scan_ticks, unsigned int chan_ticks) { - outl(init_ticks - 1, info->ai_context.scan_pre_timer_low_reg); - outl(0x0, info->ai_context.scan_pre_timer_high_reg); + outl(init_ticks - 1, dev->iobase + ME4000_AI_SCAN_PRE_TIMER_LOW_REG); + outl(0x0, dev->iobase + ME4000_AI_SCAN_PRE_TIMER_HIGH_REG); if (scan_ticks) { - outl(scan_ticks - 1, info->ai_context.scan_timer_low_reg); - outl(0x0, info->ai_context.scan_timer_high_reg); + outl(scan_ticks - 1, dev->iobase + ME4000_AI_SCAN_TIMER_LOW_REG); + outl(0x0, dev->iobase + ME4000_AI_SCAN_TIMER_HIGH_REG); } - outl(chan_ticks - 1, info->ai_context.chan_pre_timer_reg); - outl(chan_ticks - 1, info->ai_context.chan_timer_reg); + outl(chan_ticks - 1, dev->iobase + ME4000_AI_CHAN_PRE_TIMER_REG); + outl(chan_ticks - 1, dev->iobase + ME4000_AI_CHAN_TIMER_REG); +} + +static int ai_write_chanlist(struct comedi_device *dev, + struct comedi_subdevice *s, struct comedi_cmd *cmd) +{ + unsigned int entry; + unsigned int chan; + unsigned int rang; + unsigned int aref; + int i; + + for (i = 0; i < cmd->chanlist_len; i++) { + chan = CR_CHAN(cmd->chanlist[i]); + rang = CR_RANGE(cmd->chanlist[i]); + aref = CR_AREF(cmd->chanlist[i]); + + entry = chan; + + if (rang == 0) + entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_2_5; + else if (rang == 1) + entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_10; + else if (rang == 2) + entry |= ME4000_AI_LIST_RANGE_BIPOLAR_2_5; + else + entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10; + + if (aref == SDF_DIFF) + entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL; + else + entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED; + + outl(entry, dev->iobase + ME4000_AI_CHANNEL_LIST_REG); + } + + return 0; } static int ai_prepare(struct comedi_device *dev, @@ -931,7 +811,7 @@ static int ai_prepare(struct comedi_device *dev, ai_write_timer(dev, init_ticks, scan_ticks, chan_ticks); /* Reset control register */ - outl(tmp, info->ai_context.ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Start sources */ if ((cmd->start_src == TRIG_EXT && @@ -965,19 +845,19 @@ static int ai_prepare(struct comedi_device *dev, /* Stop triggers */ if (cmd->stop_src == TRIG_COUNT) { outl(cmd->chanlist_len * cmd->stop_arg, - info->ai_context.sample_counter_reg); + dev->iobase + ME4000_AI_SAMPLE_COUNTER_REG); tmp |= ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ; } else if (cmd->stop_src == TRIG_NONE && cmd->scan_end_src == TRIG_COUNT) { outl(cmd->scan_end_arg, - info->ai_context.sample_counter_reg); + dev->iobase + ME4000_AI_SAMPLE_COUNTER_REG); tmp |= ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ; } else { tmp |= ME4000_AI_CTRL_BIT_HF_IRQ; } /* Write the setup to the control register */ - outl(tmp, info->ai_context.ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Write the channel list */ ai_write_chanlist(dev, s, cmd); @@ -985,42 +865,6 @@ static int ai_prepare(struct comedi_device *dev, return 0; } -static int ai_write_chanlist(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd) -{ - unsigned int entry; - unsigned int chan; - unsigned int rang; - unsigned int aref; - int i; - - for (i = 0; i < cmd->chanlist_len; i++) { - chan = CR_CHAN(cmd->chanlist[i]); - rang = CR_RANGE(cmd->chanlist[i]); - aref = CR_AREF(cmd->chanlist[i]); - - entry = chan; - - if (rang == 0) - entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_2_5; - else if (rang == 1) - entry |= ME4000_AI_LIST_RANGE_UNIPOLAR_10; - else if (rang == 2) - entry |= ME4000_AI_LIST_RANGE_BIPOLAR_2_5; - else - entry |= ME4000_AI_LIST_RANGE_BIPOLAR_10; - - if (aref == SDF_DIFF) - entry |= ME4000_AI_LIST_INPUT_DIFFERENTIAL; - else - entry |= ME4000_AI_LIST_INPUT_SINGLE_ENDED; - - outl(entry, info->ai_context.channel_list_reg); - } - - return 0; -} - static int me4000_ai_do_cmd(struct comedi_device *dev, struct comedi_subdevice *s) { @@ -1047,23 +891,11 @@ static int me4000_ai_do_cmd(struct comedi_device *dev, return err; /* Start acquistion by dummy read */ - inl(info->ai_context.start_reg); + inl(dev->iobase + ME4000_AI_START_REG); return 0; } -/* - * me4000_ai_do_cmd_test(): - * - * The demo cmd.c in ./comedilib/demo specifies 6 return values: - * - success - * - invalid source - * - source conflict - * - invalid argument - * - argument conflict - * - invalid chanlist - * So I tried to adopt this scheme. - */ static int me4000_ai_do_cmd_test(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) @@ -1080,91 +912,29 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, /* Round the timer arguments */ ai_round_cmd_args(dev, s, cmd, &init_ticks, &scan_ticks, &chan_ticks); - /* - * Stage 1. Check if the trigger sources are generally valid. - */ - switch (cmd->start_src) { - case TRIG_NOW: - case TRIG_EXT: - break; - case TRIG_ANY: - cmd->start_src &= TRIG_NOW | TRIG_EXT; - err++; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start source\n", dev->minor); - cmd->start_src = TRIG_NOW; - err++; - } - switch (cmd->scan_begin_src) { - case TRIG_FOLLOW: - case TRIG_TIMER: - case TRIG_EXT: - break; - case TRIG_ANY: - cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT; - err++; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid scan begin source\n", dev->minor); - cmd->scan_begin_src = TRIG_FOLLOW; - err++; - } - switch (cmd->convert_src) { - case TRIG_TIMER: - case TRIG_EXT: - break; - case TRIG_ANY: - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - err++; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid convert source\n", dev->minor); - cmd->convert_src = TRIG_TIMER; - err++; - } - switch (cmd->scan_end_src) { - case TRIG_NONE: - case TRIG_COUNT: - break; - case TRIG_ANY: - cmd->scan_end_src &= TRIG_NONE | TRIG_COUNT; - err++; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid scan end source\n", dev->minor); - cmd->scan_end_src = TRIG_NONE; - err++; - } - switch (cmd->stop_src) { - case TRIG_NONE: - case TRIG_COUNT: - break; - case TRIG_ANY: - cmd->stop_src &= TRIG_NONE | TRIG_COUNT; - err++; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid stop source\n", dev->minor); - cmd->stop_src = TRIG_NONE; - err++; - } + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_FOLLOW | TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_end_src, + TRIG_NONE | TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE | TRIG_COUNT); + if (err) return 1; - /* - * Stage 2. Check for trigger source conflicts. - */ + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->scan_end_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ + if (cmd->start_src == TRIG_NOW && cmd->scan_begin_src == TRIG_TIMER && cmd->convert_src == TRIG_TIMER) { @@ -1184,13 +954,7 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, cmd->scan_begin_src == TRIG_EXT && cmd->convert_src == TRIG_EXT) { } else { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start trigger combination\n", dev->minor); - cmd->start_src = TRIG_NOW; - cmd->scan_begin_src = TRIG_FOLLOW; - cmd->convert_src = TRIG_TIMER; - err++; + err |= -EINVAL; } if (cmd->stop_src == TRIG_NONE && cmd->scan_end_src == TRIG_NONE) { @@ -1201,13 +965,9 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, } else if (cmd->stop_src == TRIG_COUNT && cmd->scan_end_src == TRIG_COUNT) { } else { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid stop trigger combination\n", dev->minor); - cmd->stop_src = TRIG_NONE; - cmd->scan_end_src = TRIG_NONE; - err++; + err |= -EINVAL; } + if (err) return 2; @@ -1215,30 +975,22 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, * Stage 3. Check if arguments are generally valid. */ if (cmd->chanlist_len < 1) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "No channel list\n", dev->minor); + dev_err(dev->class_dev, "No channel list\n"); cmd->chanlist_len = 1; err++; } if (init_ticks < 66) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Start arg to low\n", dev->minor); + dev_err(dev->class_dev, "Start arg to low\n"); cmd->start_arg = 2000; err++; } if (scan_ticks && scan_ticks < 67) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Scan begin arg to low\n", dev->minor); + dev_err(dev->class_dev, "Scan begin arg to low\n"); cmd->scan_begin_arg = 2031; err++; } if (chan_ticks < 66) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Convert arg to low\n", dev->minor); + dev_err(dev->class_dev, "Convert arg to low\n"); cmd->convert_arg = 2000; err++; } @@ -1255,23 +1007,17 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, /* Check timer arguments */ if (init_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; } if (chan_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid convert arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid convert arg\n"); cmd->convert_arg = 2000; /* 66 ticks at least */ err++; } if (scan_ticks <= cmd->chanlist_len * chan_ticks) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid scan end arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid scan end arg\n"); /* At least one tick more */ cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31; @@ -1283,16 +1029,12 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, /* Check timer arguments */ if (init_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; } if (chan_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid convert arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid convert arg\n"); cmd->convert_arg = 2000; /* 66 ticks at least */ err++; } @@ -1302,23 +1044,17 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, /* Check timer arguments */ if (init_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; } if (chan_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid convert arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid convert arg\n"); cmd->convert_arg = 2000; /* 66 ticks at least */ err++; } if (scan_ticks <= cmd->chanlist_len * chan_ticks) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid scan end arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid scan end arg\n"); /* At least one tick more */ cmd->scan_end_arg = 2000 * cmd->chanlist_len + 31; @@ -1330,16 +1066,12 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, /* Check timer arguments */ if (init_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; } if (chan_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid convert arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid convert arg\n"); cmd->convert_arg = 2000; /* 66 ticks at least */ err++; } @@ -1349,16 +1081,12 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, /* Check timer arguments */ if (init_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; } if (chan_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid convert arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid convert arg\n"); cmd->convert_arg = 2000; /* 66 ticks at least */ err++; } @@ -1368,27 +1096,21 @@ static int me4000_ai_do_cmd_test(struct comedi_device *dev, /* Check timer arguments */ if (init_ticks < ME4000_AI_MIN_TICKS) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid start arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid start arg\n"); cmd->start_arg = 2000; /* 66 ticks at least */ err++; } } if (cmd->stop_src == TRIG_COUNT) { if (cmd->stop_arg == 0) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid stop arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid stop arg\n"); cmd->stop_arg = 1; err++; } } if (cmd->scan_end_src == TRIG_COUNT) { if (cmd->scan_end_arg == 0) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_do_cmd_test(): " - "Invalid scan end arg\n", dev->minor); + dev_err(dev->class_dev, "Invalid scan end arg\n"); cmd->scan_end_arg = 1; err++; } @@ -1410,8 +1132,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) { unsigned int tmp; struct comedi_device *dev = dev_id; - struct comedi_subdevice *s = dev->subdevices; - struct me4000_ai_context *ai_context = &info->ai_context; + struct comedi_subdevice *s = &dev->subdevices[0]; int i; int c = 0; long lval; @@ -1423,17 +1144,15 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) s->async->events = 0; /* Check if irq number is right */ - if (irq != ai_context->irq) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_isr(): " - "Incorrect interrupt num: %d\n", dev->minor, irq); + if (irq != dev->irq) { + dev_err(dev->class_dev, "Incorrect interrupt num: %d\n", irq); return IRQ_HANDLED; } - if (inl(ai_context->irq_status_reg) & + if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) & ME4000_IRQ_STATUS_BIT_AI_HF) { /* Read status register to find out what happened */ - tmp = inl(ai_context->ctrl_reg); + tmp = inl(dev->iobase + ME4000_AI_CTRL_REG); if (!(tmp & ME4000_AI_STATUS_BIT_FF_DATA) && !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) && @@ -1447,13 +1166,11 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ); - outl(tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_isr(): " - "FIFO overflow\n", dev->minor); + dev_err(dev->class_dev, "FIFO overflow\n"); } else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA) && !(tmp & ME4000_AI_STATUS_BIT_HF_DATA) && (tmp & ME4000_AI_STATUS_BIT_EF_DATA)) { @@ -1461,9 +1178,8 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) c = ME4000_AI_FIFO_COUNT / 2; } else { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_isr(): " - "Can't determine state of fifo\n", dev->minor); + dev_err(dev->class_dev, + "Can't determine state of fifo\n"); c = 0; /* @@ -1473,18 +1189,16 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ); - outl(tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_isr(): " - "Undefined FIFO state\n", dev->minor); + dev_err(dev->class_dev, "Undefined FIFO state\n"); } for (i = 0; i < c; i++) { /* Read value from data fifo */ - lval = inl(ai_context->data_reg) & 0xFFFF; + lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF; lval ^= 0x8000; if (!comedi_buf_put(s->async, lval)) { @@ -1495,13 +1209,11 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ); - outl(tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); s->async->events |= COMEDI_CB_OVERFLOW; - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_isr(): " - "Buffer overflow\n", dev->minor); + dev_err(dev->class_dev, "Buffer overflow\n"); break; } @@ -1509,33 +1221,33 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) /* Work is done, so reset the interrupt */ tmp |= ME4000_AI_CTRL_BIT_HF_IRQ_RESET; - outl(tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); tmp &= ~ME4000_AI_CTRL_BIT_HF_IRQ_RESET; - outl(tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); } - if (inl(ai_context->irq_status_reg) & ME4000_IRQ_STATUS_BIT_SC) { + if (inl(dev->iobase + ME4000_IRQ_STATUS_REG) & + ME4000_IRQ_STATUS_BIT_SC) { s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOA; /* * Acquisition is complete, so stop * conversion and disable all interrupts */ - tmp = inl(ai_context->ctrl_reg); + tmp = inl(dev->iobase + ME4000_AI_CTRL_REG); tmp |= ME4000_AI_CTRL_BIT_IMMEDIATE_STOP; tmp &= ~(ME4000_AI_CTRL_BIT_HF_IRQ | ME4000_AI_CTRL_BIT_SC_IRQ); - outl(tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); /* Poll data until fifo empty */ - while (inl(ai_context->ctrl_reg) & ME4000_AI_STATUS_BIT_EF_DATA) { + while (inl(dev->iobase + ME4000_AI_CTRL_REG) & + ME4000_AI_STATUS_BIT_EF_DATA) { /* Read value from data fifo */ - lval = inl(ai_context->data_reg) & 0xFFFF; + lval = inl(dev->iobase + ME4000_AI_DATA_REG) & 0xFFFF; lval ^= 0x8000; if (!comedi_buf_put(s->async, lval)) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ai_isr(): " - "Buffer overflow\n", dev->minor); + dev_err(dev->class_dev, "Buffer overflow\n"); s->async->events |= COMEDI_CB_OVERFLOW; break; } @@ -1543,9 +1255,9 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id) /* Work is done, so reset the interrupt */ tmp |= ME4000_AI_CTRL_BIT_SC_IRQ_RESET; - outl(tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); tmp &= ~ME4000_AI_CTRL_BIT_SC_IRQ_RESET; - outl(tmp, ai_context->ctrl_reg); + outl(tmp, dev->iobase + ME4000_AI_CTRL_REG); } if (s->async->events) @@ -1562,7 +1274,8 @@ static int me4000_ao_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - + const struct me4000_board *thisboard = comedi_board(dev); + struct me4000_info *info = dev->private; int chan = CR_CHAN(insn->chanspec); int rang = CR_RANGE(insn->chanspec); int aref = CR_AREF(insn->chanspec); @@ -1571,46 +1284,39 @@ static int me4000_ao_insn_write(struct comedi_device *dev, if (insn->n == 0) { return 0; } else if (insn->n > 1) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ao_insn_write(): " - "Invalid instruction length %d\n", dev->minor, insn->n); + dev_err(dev->class_dev, "Invalid instruction length %d\n", + insn->n); return -EINVAL; } - if (chan >= thisboard->ao.count) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ao_insn_write(): " - "Invalid channel %d\n", dev->minor, insn->n); + if (chan >= thisboard->ao_nchan) { + dev_err(dev->class_dev, "Invalid channel %d\n", insn->n); return -EINVAL; } if (rang != 0) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ao_insn_write(): " - "Invalid range %d\n", dev->minor, insn->n); + dev_err(dev->class_dev, "Invalid range %d\n", insn->n); return -EINVAL; } if (aref != AREF_GROUND && aref != AREF_COMMON) { - printk(KERN_ERR - "comedi%d: me4000: me4000_ao_insn_write(): " - "Invalid aref %d\n", dev->minor, insn->n); + dev_err(dev->class_dev, "Invalid aref %d\n", insn->n); return -EINVAL; } /* Stop any running conversion */ - tmp = inl(info->ao_context[chan].ctrl_reg); + tmp = inl(dev->iobase + ME4000_AO_CTRL_REG(chan)); tmp |= ME4000_AO_CTRL_BIT_IMMEDIATE_STOP; - outl(tmp, info->ao_context[chan].ctrl_reg); + outl(tmp, dev->iobase + ME4000_AO_CTRL_REG(chan)); /* Clear control register and set to single mode */ - outl(0x0, info->ao_context[chan].ctrl_reg); + outl(0x0, dev->iobase + ME4000_AO_CTRL_REG(chan)); /* Write data value */ - outl(data[0], info->ao_context[chan].single_reg); + outl(data[0], dev->iobase + ME4000_AO_SINGLE_REG(chan)); /* Store in the mirror */ - info->ao_context[chan].mirror = data[0]; + info->ao_readback[chan] = data[0]; return 1; } @@ -1619,18 +1325,17 @@ static int me4000_ao_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct me4000_info *info = dev->private; int chan = CR_CHAN(insn->chanspec); if (insn->n == 0) { return 0; } else if (insn->n > 1) { - printk - ("comedi%d: me4000: me4000_ao_insn_read(): " - "Invalid instruction length\n", dev->minor); + dev_err(dev->class_dev, "Invalid instruction length\n"); return -EINVAL; } - data[0] = info->ao_context[chan].mirror; + data[0] = info->ao_readback[chan]; return 1; } @@ -1659,21 +1364,21 @@ static int me4000_dio_insn_bits(struct comedi_device *dev, /* Write out the new digital output lines */ outl((s->state >> 0) & 0xFF, - info->dio_context.port_0_reg); + dev->iobase + ME4000_DIO_PORT_0_REG); outl((s->state >> 8) & 0xFF, - info->dio_context.port_1_reg); + dev->iobase + ME4000_DIO_PORT_1_REG); outl((s->state >> 16) & 0xFF, - info->dio_context.port_2_reg); + dev->iobase + ME4000_DIO_PORT_2_REG); outl((s->state >> 24) & 0xFF, - info->dio_context.port_3_reg); + dev->iobase + ME4000_DIO_PORT_3_REG); } /* On return, data[1] contains the value of the digital input and output lines. */ - data[1] = ((inl(info->dio_context.port_0_reg) & 0xFF) << 0) | - ((inl(info->dio_context.port_1_reg) & 0xFF) << 8) | - ((inl(info->dio_context.port_2_reg) & 0xFF) << 16) | - ((inl(info->dio_context.port_3_reg) & 0xFF) << 24); + data[1] = ((inl(dev->iobase + ME4000_DIO_PORT_0_REG) & 0xFF) << 0) | + ((inl(dev->iobase + ME4000_DIO_PORT_1_REG) & 0xFF) << 8) | + ((inl(dev->iobase + ME4000_DIO_PORT_2_REG) & 0xFF) << 16) | + ((inl(dev->iobase + ME4000_DIO_PORT_3_REG) & 0xFF) << 24); return insn->n; } @@ -1705,7 +1410,7 @@ static int me4000_dio_insn_config(struct comedi_device *dev, * On the ME-4000 it is only possible to switch port wise (8 bit) */ - tmp = inl(info->dio_context.ctrl_reg); + tmp = inl(dev->iobase + ME4000_DIO_CTRL_REG); if (data[0] == INSN_CONFIG_DIO_OUTPUT) { if (chan < 8) { @@ -1719,7 +1424,7 @@ static int me4000_dio_insn_config(struct comedi_device *dev, * If one the first port is a fixed output * port and the second is a fixed input port. */ - if (!inl(info->dio_context.dir_reg)) + if (!inl(dev->iobase + ME4000_DIO_DIR_REG)) return -ENODEV; s->io_bits |= 0xFF00; @@ -1746,7 +1451,7 @@ static int me4000_dio_insn_config(struct comedi_device *dev, * If one the first port is a fixed output * port and the second is a fixed input port. */ - if (!inl(info->dio_context.dir_reg)) + if (!inl(dev->iobase + ME4000_DIO_DIR_REG)) return -ENODEV; s->io_bits &= ~0xFF; @@ -1769,7 +1474,7 @@ static int me4000_dio_insn_config(struct comedi_device *dev, } } - outl(tmp, info->dio_context.ctrl_reg); + outl(tmp, dev->iobase + ME4000_DIO_CTRL_REG); return 1; } @@ -1778,177 +1483,56 @@ static int me4000_dio_insn_config(struct comedi_device *dev, Counter section ===========================================================================*/ -static int cnt_reset(struct comedi_device *dev, unsigned int channel) -{ - switch (channel) { - case 0: - outb(0x30, info->cnt_context.ctrl_reg); - outb(0x00, info->cnt_context.counter_0_reg); - outb(0x00, info->cnt_context.counter_0_reg); - break; - case 1: - outb(0x70, info->cnt_context.ctrl_reg); - outb(0x00, info->cnt_context.counter_1_reg); - outb(0x00, info->cnt_context.counter_1_reg); - break; - case 2: - outb(0xB0, info->cnt_context.ctrl_reg); - outb(0x00, info->cnt_context.counter_2_reg); - outb(0x00, info->cnt_context.counter_2_reg); - break; - default: - printk(KERN_ERR - "comedi%d: me4000: cnt_reset(): Invalid channel\n", - dev->minor); - return -EINVAL; - } - - return 0; -} - -static int cnt_config(struct comedi_device *dev, unsigned int channel, - unsigned int mode) -{ - int tmp = 0; - - switch (channel) { - case 0: - tmp |= ME4000_CNT_COUNTER_0; - break; - case 1: - tmp |= ME4000_CNT_COUNTER_1; - break; - case 2: - tmp |= ME4000_CNT_COUNTER_2; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: cnt_config(): Invalid channel\n", - dev->minor); - return -EINVAL; - } - - switch (mode) { - case 0: - tmp |= ME4000_CNT_MODE_0; - break; - case 1: - tmp |= ME4000_CNT_MODE_1; - break; - case 2: - tmp |= ME4000_CNT_MODE_2; - break; - case 3: - tmp |= ME4000_CNT_MODE_3; - break; - case 4: - tmp |= ME4000_CNT_MODE_4; - break; - case 5: - tmp |= ME4000_CNT_MODE_5; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: cnt_config(): Invalid counter mode\n", - dev->minor); - return -EINVAL; - } - - /* Write the control word */ - tmp |= 0x30; - outb(tmp, info->cnt_context.ctrl_reg); - - return 0; -} - static int me4000_cnt_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - + struct me4000_info *info = dev->private; int err; switch (data[0]) { case GPCT_RESET: - if (insn->n != 1) { - printk(KERN_ERR - "comedi%d: me4000: me4000_cnt_insn_config(): " - "Invalid instruction length%d\n", - dev->minor, insn->n); + if (insn->n != 1) return -EINVAL; - } - err = cnt_reset(dev, insn->chanspec); + err = i8254_load(info->timer_regbase, 0, insn->chanspec, 0, + I8254_MODE0 | I8254_BINARY); if (err) return err; break; case GPCT_SET_OPERATION: - if (insn->n != 2) { - printk(KERN_ERR - "comedi%d: me4000: me4000_cnt_insn_config(): " - "Invalid instruction length%d\n", - dev->minor, insn->n); + if (insn->n != 2) return -EINVAL; - } - err = cnt_config(dev, insn->chanspec, data[1]); + err = i8254_set_mode(info->timer_regbase, 0, insn->chanspec, + (data[1] << 1) | I8254_BINARY); if (err) return err; break; default: - printk(KERN_ERR - "comedi%d: me4000: me4000_cnt_insn_config(): " - "Invalid instruction\n", dev->minor); return -EINVAL; } - return 2; + return insn->n; } static int me4000_cnt_insn_read(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - - unsigned short tmp; + struct me4000_info *info = dev->private; if (insn->n == 0) return 0; if (insn->n > 1) { - printk(KERN_ERR - "comedi%d: me4000: me4000_cnt_insn_read(): " - "Invalid instruction length %d\n", - dev->minor, insn->n); + dev_err(dev->class_dev, "Invalid instruction length %d\n", + insn->n); return -EINVAL; } - switch (insn->chanspec) { - case 0: - tmp = inb(info->cnt_context.counter_0_reg); - data[0] = tmp; - tmp = inb(info->cnt_context.counter_0_reg); - data[0] |= tmp << 8; - break; - case 1: - tmp = inb(info->cnt_context.counter_1_reg); - data[0] = tmp; - tmp = inb(info->cnt_context.counter_1_reg); - data[0] |= tmp << 8; - break; - case 2: - tmp = inb(info->cnt_context.counter_2_reg); - data[0] = tmp; - tmp = inb(info->cnt_context.counter_2_reg); - data[0] |= tmp << 8; - break; - default: - printk(KERN_ERR - "comedi%d: me4000: me4000_cnt_insn_read(): " - "Invalid channel %d\n", - dev->minor, insn->chanspec); - return -EINVAL; - } + data[0] = i8254_read(info->timer_regbase, 0, insn->chanspec); return 1; } @@ -1957,58 +1541,72 @@ static int me4000_cnt_insn_write(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - - unsigned short tmp; + struct me4000_info *info = dev->private; if (insn->n == 0) { return 0; } else if (insn->n > 1) { - printk(KERN_ERR - "comedi%d: me4000: me4000_cnt_insn_write(): " - "Invalid instruction length %d\n", - dev->minor, insn->n); + dev_err(dev->class_dev, "Invalid instruction length %d\n", + insn->n); return -EINVAL; } - switch (insn->chanspec) { - case 0: - tmp = data[0] & 0xFF; - outb(tmp, info->cnt_context.counter_0_reg); - tmp = (data[0] >> 8) & 0xFF; - outb(tmp, info->cnt_context.counter_0_reg); - break; - case 1: - tmp = data[0] & 0xFF; - outb(tmp, info->cnt_context.counter_1_reg); - tmp = (data[0] >> 8) & 0xFF; - outb(tmp, info->cnt_context.counter_1_reg); - break; - case 2: - tmp = data[0] & 0xFF; - outb(tmp, info->cnt_context.counter_2_reg); - tmp = (data[0] >> 8) & 0xFF; - outb(tmp, info->cnt_context.counter_2_reg); - break; - default: - printk(KERN_ERR - "comedi%d: me4000: me4000_cnt_insn_write(): " - "Invalid channel %d\n", - dev->minor, insn->chanspec); - return -EINVAL; - } + i8254_write(info->timer_regbase, 0, insn->chanspec, data[0]); return 1; } -static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static const void *me4000_find_boardinfo(struct comedi_device *dev, + struct pci_dev *pcidev) { + const struct me4000_board *thisboard; + int i; + + for (i = 0; i < ARRAY_SIZE(me4000_boards); i++) { + thisboard = &me4000_boards[i]; + if (thisboard->device_id == pcidev->device) + return thisboard; + } + return NULL; +} + +static int me4000_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) +{ + const struct me4000_board *thisboard; + struct me4000_info *info; struct comedi_subdevice *s; int result; - result = me4000_probe(dev, it); + comedi_set_hw_dev(dev, &pcidev->dev); + + thisboard = me4000_find_boardinfo(dev, pcidev); + if (!thisboard) + return -ENODEV; + dev->board_ptr = thisboard; + dev->board_name = thisboard->name; + + result = alloc_private(dev, sizeof(*info)); + if (result) + return result; + info = dev->private; + + result = comedi_pci_enable(pcidev, dev->board_name); + if (result) + return result; + + info->plx_regbase = pci_resource_start(pcidev, 1); + dev->iobase = pci_resource_start(pcidev, 2); + info->timer_regbase = pci_resource_start(pcidev, 3); + if (!info->plx_regbase || !dev->iobase || !info->timer_regbase) + return -ENODEV; + + result = xilinx_download(dev); if (result) return result; + me4000_reset(dev); + result = comedi_alloc_subdevices(dev, 4); if (result) return result; @@ -2017,35 +1615,34 @@ static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it) Analog input subdevice ========================================================================*/ - s = dev->subdevices + 0; + s = &dev->subdevices[0]; - if (thisboard->ai.count) { + if (thisboard->ai_nchan) { s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND | SDF_DIFF; - s->n_chan = thisboard->ai.count; + s->n_chan = thisboard->ai_nchan; s->maxdata = 0xFFFF; /* 16 bit ADC */ s->len_chanlist = ME4000_AI_CHANNEL_LIST_COUNT; s->range_table = &me4000_ai_range; s->insn_read = me4000_ai_insn_read; - if (info->irq > 0) { - if (request_irq(info->irq, me4000_ai_isr, - IRQF_SHARED, "ME-4000", dev)) { - printk - ("comedi%d: me4000: me4000_attach(): " - "Unable to allocate irq\n", dev->minor); + if (pcidev->irq > 0) { + if (request_irq(pcidev->irq, me4000_ai_isr, + IRQF_SHARED, dev->board_name, dev)) { + dev_warn(dev->class_dev, + "request_irq failed\n"); } else { dev->read_subdev = s; s->subdev_flags |= SDF_CMD_READ; s->cancel = me4000_ai_cancel; s->do_cmdtest = me4000_ai_do_cmd_test; s->do_cmd = me4000_ai_do_cmd; + + dev->irq = pcidev->irq; } } else { - printk(KERN_WARNING - "comedi%d: me4000: me4000_attach(): " - "No interrupt available\n", dev->minor); + dev_warn(dev->class_dev, "No interrupt available\n"); } } else { s->type = COMEDI_SUBD_UNUSED; @@ -2055,14 +1652,14 @@ static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it) Analog output subdevice ========================================================================*/ - s = dev->subdevices + 1; + s = &dev->subdevices[1]; - if (thisboard->ao.count) { + if (thisboard->ao_nchan) { s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITEABLE | SDF_COMMON | SDF_GROUND; - s->n_chan = thisboard->ao.count; + s->n_chan = thisboard->ao_nchan; s->maxdata = 0xFFFF; /* 16 bit DAC */ - s->range_table = &me4000_ao_range; + s->range_table = &range_bipolar10; s->insn_write = me4000_ao_insn_write; s->insn_read = me4000_ao_insn_read; } else { @@ -2073,12 +1670,12 @@ static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it) Digital I/O subdevice ========================================================================*/ - s = dev->subdevices + 2; + s = &dev->subdevices[2]; - if (thisboard->dio.count) { + if (thisboard->dio_nchan) { s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = thisboard->dio.count * 8; + s->n_chan = thisboard->dio_nchan; s->maxdata = 1; s->range_table = &range_digital; s->insn_bits = me4000_dio_insn_bits; @@ -2091,21 +1688,22 @@ static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it) * Check for optoisolated ME-4000 version. If one the first * port is a fixed output port and the second is a fixed input port. */ - if (!inl(info->dio_context.dir_reg)) { + if (!inl(dev->iobase + ME4000_DIO_DIR_REG)) { s->io_bits |= 0xFF; - outl(ME4000_DIO_CTRL_BIT_MODE_0, info->dio_context.dir_reg); + outl(ME4000_DIO_CTRL_BIT_MODE_0, + dev->iobase + ME4000_DIO_DIR_REG); } /*========================================================================= Counter subdevice ========================================================================*/ - s = dev->subdevices + 3; + s = &dev->subdevices[3]; - if (thisboard->cnt.count) { + if (thisboard->has_counter) { s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = thisboard->cnt.count; + s->n_chan = 3; s->maxdata = 0xFFFF; /* 16 bit counters */ s->insn_read = me4000_cnt_insn_read; s->insn_write = me4000_cnt_insn_write; @@ -2119,12 +1717,14 @@ static int me4000_attach(struct comedi_device *dev, struct comedi_devconfig *it) static void me4000_detach(struct comedi_device *dev) { - if (info) { - if (info->pci_dev_p) { - reset_board(dev); - if (info->plx_regbase) - comedi_pci_disable(info->pci_dev_p); - pci_dev_put(info->pci_dev_p); + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + + if (dev->irq) + free_irq(dev->irq, dev); + if (pcidev) { + if (dev->iobase) { + me4000_reset(dev); + comedi_pci_disable(pcidev); } } } @@ -2132,7 +1732,7 @@ static void me4000_detach(struct comedi_device *dev) static struct comedi_driver me4000_driver = { .driver_name = "me4000", .module = THIS_MODULE, - .attach = me4000_attach, + .attach_pci = me4000_attach_pci, .detach = me4000_detach, }; @@ -2148,20 +1748,20 @@ static void __devexit me4000_pci_remove(struct pci_dev *dev) } static DEFINE_PCI_DEVICE_TABLE(me4000_pci_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4650) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4660) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4661) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4662) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4663) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4670) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4671) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4672) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4673) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4680) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4681) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4682) }, - { PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, 0x4683) }, - { 0 } + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4650)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660I)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660S)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4660IS)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670I)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670S)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4670IS)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680I)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680S)}, + {PCI_DEVICE(PCI_VENDOR_ID_MEILHAUS, PCI_DEVICE_ID_MEILHAUS_ME4680IS)}, + {0} }; MODULE_DEVICE_TABLE(pci, me4000_pci_table); diff --git a/drivers/staging/comedi/drivers/me4000.h b/drivers/staging/comedi/drivers/me4000.h deleted file mode 100644 index 5a4df4e4b236..000000000000 --- a/drivers/staging/comedi/drivers/me4000.h +++ /dev/null @@ -1,409 +0,0 @@ -/* - me4000.h - Register descriptions and defines for the ME-4000 board family - - COMEDI - Linux Control and Measurement Device Interface - Copyright (C) 1998-9 David A. Schleef <ds@schleef.org> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#ifndef _ME4000_H_ -#define _ME4000_H_ - -/*============================================================================= - PCI vendor and device IDs - ===========================================================================*/ - -#define PCI_VENDOR_ID_MEILHAUS 0x1402 - -#define PCI_DEVICE_ID_MEILHAUS_ME4650 0x4650 /* Low Cost version */ - -#define PCI_DEVICE_ID_MEILHAUS_ME4660 0x4660 /* Standard version */ -#define PCI_DEVICE_ID_MEILHAUS_ME4660I 0x4661 /* Isolated version */ -#define PCI_DEVICE_ID_MEILHAUS_ME4660S 0x4662 /* Standard version with Sample and Hold */ -#define PCI_DEVICE_ID_MEILHAUS_ME4660IS 0x4663 /* Isolated version with Sample and Hold */ - -#define PCI_DEVICE_ID_MEILHAUS_ME4670 0x4670 /* Standard version */ -#define PCI_DEVICE_ID_MEILHAUS_ME4670I 0x4671 /* Isolated version */ -#define PCI_DEVICE_ID_MEILHAUS_ME4670S 0x4672 /* Standard version with Sample and Hold */ -#define PCI_DEVICE_ID_MEILHAUS_ME4670IS 0x4673 /* Isolated version with Sample and Hold */ - -#define PCI_DEVICE_ID_MEILHAUS_ME4680 0x4680 /* Standard version */ -#define PCI_DEVICE_ID_MEILHAUS_ME4680I 0x4681 /* Isolated version */ -#define PCI_DEVICE_ID_MEILHAUS_ME4680S 0x4682 /* Standard version with Sample and Hold */ -#define PCI_DEVICE_ID_MEILHAUS_ME4680IS 0x4683 /* Isolated version with Sample and Hold */ - -/*============================================================================= - ME-4000 base register offsets - ===========================================================================*/ - -#define ME4000_AO_00_CTRL_REG 0x00 /* R/W */ -#define ME4000_AO_00_STATUS_REG 0x04 /* R/_ */ -#define ME4000_AO_00_FIFO_REG 0x08 /* _/W */ -#define ME4000_AO_00_SINGLE_REG 0x0C /* R/W */ -#define ME4000_AO_00_TIMER_REG 0x10 /* _/W */ - -#define ME4000_AO_01_CTRL_REG 0x18 /* R/W */ -#define ME4000_AO_01_STATUS_REG 0x1C /* R/_ */ -#define ME4000_AO_01_FIFO_REG 0x20 /* _/W */ -#define ME4000_AO_01_SINGLE_REG 0x24 /* R/W */ -#define ME4000_AO_01_TIMER_REG 0x28 /* _/W */ - -#define ME4000_AO_02_CTRL_REG 0x30 /* R/W */ -#define ME4000_AO_02_STATUS_REG 0x34 /* R/_ */ -#define ME4000_AO_02_FIFO_REG 0x38 /* _/W */ -#define ME4000_AO_02_SINGLE_REG 0x3C /* R/W */ -#define ME4000_AO_02_TIMER_REG 0x40 /* _/W */ - -#define ME4000_AO_03_CTRL_REG 0x48 /* R/W */ -#define ME4000_AO_03_STATUS_REG 0x4C /* R/_ */ -#define ME4000_AO_03_FIFO_REG 0x50 /* _/W */ -#define ME4000_AO_03_SINGLE_REG 0x54 /* R/W */ -#define ME4000_AO_03_TIMER_REG 0x58 /* _/W */ - -#define ME4000_AI_CTRL_REG 0x74 /* _/W */ -#define ME4000_AI_STATUS_REG 0x74 /* R/_ */ -#define ME4000_AI_CHANNEL_LIST_REG 0x78 /* _/W */ -#define ME4000_AI_DATA_REG 0x7C /* R/_ */ -#define ME4000_AI_CHAN_TIMER_REG 0x80 /* _/W */ -#define ME4000_AI_CHAN_PRE_TIMER_REG 0x84 /* _/W */ -#define ME4000_AI_SCAN_TIMER_LOW_REG 0x88 /* _/W */ -#define ME4000_AI_SCAN_TIMER_HIGH_REG 0x8C /* _/W */ -#define ME4000_AI_SCAN_PRE_TIMER_LOW_REG 0x90 /* _/W */ -#define ME4000_AI_SCAN_PRE_TIMER_HIGH_REG 0x94 /* _/W */ -#define ME4000_AI_START_REG 0x98 /* R/_ */ - -#define ME4000_IRQ_STATUS_REG 0x9C /* R/_ */ - -#define ME4000_DIO_PORT_0_REG 0xA0 /* R/W */ -#define ME4000_DIO_PORT_1_REG 0xA4 /* R/W */ -#define ME4000_DIO_PORT_2_REG 0xA8 /* R/W */ -#define ME4000_DIO_PORT_3_REG 0xAC /* R/W */ -#define ME4000_DIO_DIR_REG 0xB0 /* R/W */ - -#define ME4000_AO_LOADSETREG_XX 0xB4 /* R/W */ - -#define ME4000_DIO_CTRL_REG 0xB8 /* R/W */ - -#define ME4000_AO_DEMUX_ADJUST_REG 0xBC /* -/W */ - -#define ME4000_AI_SAMPLE_COUNTER_REG 0xC0 /* _/W */ - -/*============================================================================= - Value to adjust Demux - ===========================================================================*/ - -#define ME4000_AO_DEMUX_ADJUST_VALUE 0x4C - -/*============================================================================= - Counter base register offsets - ===========================================================================*/ - -#define ME4000_CNT_COUNTER_0_REG 0x00 -#define ME4000_CNT_COUNTER_1_REG 0x01 -#define ME4000_CNT_COUNTER_2_REG 0x02 -#define ME4000_CNT_CTRL_REG 0x03 - -/*============================================================================= - PLX base register offsets - ===========================================================================*/ - -#define PLX_INTCSR 0x4C /* Interrupt control and status register */ -#define PLX_ICR 0x50 /* Initialization control register */ - -/*============================================================================= - Bits for the PLX_ICSR register - ===========================================================================*/ - -#define PLX_INTCSR_LOCAL_INT1_EN 0x01 /* If set, local interrupt 1 is enabled (r/w) */ -#define PLX_INTCSR_LOCAL_INT1_POL 0x02 /* If set, local interrupt 1 polarity is active high (r/w) */ -#define PLX_INTCSR_LOCAL_INT1_STATE 0x04 /* If set, local interrupt 1 is active (r/_) */ -#define PLX_INTCSR_LOCAL_INT2_EN 0x08 /* If set, local interrupt 2 is enabled (r/w) */ -#define PLX_INTCSR_LOCAL_INT2_POL 0x10 /* If set, local interrupt 2 polarity is active high (r/w) */ -#define PLX_INTCSR_LOCAL_INT2_STATE 0x20 /* If set, local interrupt 2 is active (r/_) */ -#define PLX_INTCSR_PCI_INT_EN 0x40 /* If set, PCI interrupt is enabled (r/w) */ -#define PLX_INTCSR_SOFT_INT 0x80 /* If set, a software interrupt is generated (r/w) */ - -/*============================================================================= - Bits for the PLX_ICR register - ===========================================================================*/ - -#define PLX_ICR_BIT_EEPROM_CLOCK_SET 0x01000000 -#define PLX_ICR_BIT_EEPROM_CHIP_SELECT 0x02000000 -#define PLX_ICR_BIT_EEPROM_WRITE 0x04000000 -#define PLX_ICR_BIT_EEPROM_READ 0x08000000 -#define PLX_ICR_BIT_EEPROM_VALID 0x10000000 - -#define PLX_ICR_MASK_EEPROM 0x1F000000 - -#define EEPROM_DELAY 1 - -/*============================================================================= - Bits for the ME4000_AO_CTRL_REG register - ===========================================================================*/ - -#define ME4000_AO_CTRL_BIT_MODE_0 0x001 -#define ME4000_AO_CTRL_BIT_MODE_1 0x002 -#define ME4000_AO_CTRL_MASK_MODE 0x003 -#define ME4000_AO_CTRL_BIT_STOP 0x004 -#define ME4000_AO_CTRL_BIT_ENABLE_FIFO 0x008 -#define ME4000_AO_CTRL_BIT_ENABLE_EX_TRIG 0x010 -#define ME4000_AO_CTRL_BIT_EX_TRIG_EDGE 0x020 -#define ME4000_AO_CTRL_BIT_IMMEDIATE_STOP 0x080 -#define ME4000_AO_CTRL_BIT_ENABLE_DO 0x100 -#define ME4000_AO_CTRL_BIT_ENABLE_IRQ 0x200 -#define ME4000_AO_CTRL_BIT_RESET_IRQ 0x400 - -/*============================================================================= - Bits for the ME4000_AO_STATUS_REG register - ===========================================================================*/ - -#define ME4000_AO_STATUS_BIT_FSM 0x01 -#define ME4000_AO_STATUS_BIT_FF 0x02 -#define ME4000_AO_STATUS_BIT_HF 0x04 -#define ME4000_AO_STATUS_BIT_EF 0x08 - -/*============================================================================= - Bits for the ME4000_AI_CTRL_REG register - ===========================================================================*/ - -#define ME4000_AI_CTRL_BIT_MODE_0 0x00000001 -#define ME4000_AI_CTRL_BIT_MODE_1 0x00000002 -#define ME4000_AI_CTRL_BIT_MODE_2 0x00000004 -#define ME4000_AI_CTRL_BIT_SAMPLE_HOLD 0x00000008 -#define ME4000_AI_CTRL_BIT_IMMEDIATE_STOP 0x00000010 -#define ME4000_AI_CTRL_BIT_STOP 0x00000020 -#define ME4000_AI_CTRL_BIT_CHANNEL_FIFO 0x00000040 -#define ME4000_AI_CTRL_BIT_DATA_FIFO 0x00000080 -#define ME4000_AI_CTRL_BIT_FULLSCALE 0x00000100 -#define ME4000_AI_CTRL_BIT_OFFSET 0x00000200 -#define ME4000_AI_CTRL_BIT_EX_TRIG_ANALOG 0x00000400 -#define ME4000_AI_CTRL_BIT_EX_TRIG 0x00000800 -#define ME4000_AI_CTRL_BIT_EX_TRIG_FALLING 0x00001000 -#define ME4000_AI_CTRL_BIT_EX_IRQ 0x00002000 -#define ME4000_AI_CTRL_BIT_EX_IRQ_RESET 0x00004000 -#define ME4000_AI_CTRL_BIT_LE_IRQ 0x00008000 -#define ME4000_AI_CTRL_BIT_LE_IRQ_RESET 0x00010000 -#define ME4000_AI_CTRL_BIT_HF_IRQ 0x00020000 -#define ME4000_AI_CTRL_BIT_HF_IRQ_RESET 0x00040000 -#define ME4000_AI_CTRL_BIT_SC_IRQ 0x00080000 -#define ME4000_AI_CTRL_BIT_SC_IRQ_RESET 0x00100000 -#define ME4000_AI_CTRL_BIT_SC_RELOAD 0x00200000 -#define ME4000_AI_CTRL_BIT_EX_TRIG_BOTH 0x80000000 - -/*============================================================================= - Bits for the ME4000_AI_STATUS_REG register - ===========================================================================*/ - -#define ME4000_AI_STATUS_BIT_EF_CHANNEL 0x00400000 -#define ME4000_AI_STATUS_BIT_HF_CHANNEL 0x00800000 -#define ME4000_AI_STATUS_BIT_FF_CHANNEL 0x01000000 -#define ME4000_AI_STATUS_BIT_EF_DATA 0x02000000 -#define ME4000_AI_STATUS_BIT_HF_DATA 0x04000000 -#define ME4000_AI_STATUS_BIT_FF_DATA 0x08000000 -#define ME4000_AI_STATUS_BIT_LE 0x10000000 -#define ME4000_AI_STATUS_BIT_FSM 0x20000000 - -/*============================================================================= - Bits for the ME4000_IRQ_STATUS_REG register - ===========================================================================*/ - -#define ME4000_IRQ_STATUS_BIT_EX 0x01 -#define ME4000_IRQ_STATUS_BIT_LE 0x02 -#define ME4000_IRQ_STATUS_BIT_AI_HF 0x04 -#define ME4000_IRQ_STATUS_BIT_AO_0_HF 0x08 -#define ME4000_IRQ_STATUS_BIT_AO_1_HF 0x10 -#define ME4000_IRQ_STATUS_BIT_AO_2_HF 0x20 -#define ME4000_IRQ_STATUS_BIT_AO_3_HF 0x40 -#define ME4000_IRQ_STATUS_BIT_SC 0x80 - -/*============================================================================= - Bits for the ME4000_DIO_CTRL_REG register - ===========================================================================*/ - -#define ME4000_DIO_CTRL_BIT_MODE_0 0x0001 -#define ME4000_DIO_CTRL_BIT_MODE_1 0x0002 -#define ME4000_DIO_CTRL_BIT_MODE_2 0x0004 -#define ME4000_DIO_CTRL_BIT_MODE_3 0x0008 -#define ME4000_DIO_CTRL_BIT_MODE_4 0x0010 -#define ME4000_DIO_CTRL_BIT_MODE_5 0x0020 -#define ME4000_DIO_CTRL_BIT_MODE_6 0x0040 -#define ME4000_DIO_CTRL_BIT_MODE_7 0x0080 - -#define ME4000_DIO_CTRL_BIT_FUNCTION_0 0x0100 -#define ME4000_DIO_CTRL_BIT_FUNCTION_1 0x0200 - -#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_0 0x0400 -#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_1 0x0800 -#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_2 0x1000 -#define ME4000_DIO_CTRL_BIT_FIFO_HIGH_3 0x2000 - -/*============================================================================= - Information about the hardware capabilities - ===========================================================================*/ - -struct me4000_ao_info { - int count; - int fifo_count; -}; - -struct me4000_ai_info { - int count; - int sh_count; - int diff_count; - int ex_trig_analog; -}; - -struct me4000_dio_info { - int count; -}; - -struct me4000_cnt_info { - int count; -}; - -struct me4000_board { - const char *name; - unsigned short device_id; - struct me4000_ao_info ao; - struct me4000_ai_info ai; - struct me4000_dio_info dio; - struct me4000_cnt_info cnt; -}; - -#define thisboard ((const struct me4000_board *)dev->board_ptr) - -/*============================================================================= - Global board and subdevice information structures - ===========================================================================*/ - -struct me4000_ao_context { - int irq; - - unsigned long mirror; /* Store the last written value */ - - unsigned long ctrl_reg; - unsigned long status_reg; - unsigned long fifo_reg; - unsigned long single_reg; - unsigned long timer_reg; - unsigned long irq_status_reg; - unsigned long preload_reg; -}; - -struct me4000_ai_context { - int irq; - - unsigned long ctrl_reg; - unsigned long status_reg; - unsigned long channel_list_reg; - unsigned long data_reg; - unsigned long chan_timer_reg; - unsigned long chan_pre_timer_reg; - unsigned long scan_timer_low_reg; - unsigned long scan_timer_high_reg; - unsigned long scan_pre_timer_low_reg; - unsigned long scan_pre_timer_high_reg; - unsigned long start_reg; - unsigned long irq_status_reg; - unsigned long sample_counter_reg; -}; - -struct me4000_dio_context { - unsigned long dir_reg; - unsigned long ctrl_reg; - unsigned long port_0_reg; - unsigned long port_1_reg; - unsigned long port_2_reg; - unsigned long port_3_reg; -}; - -struct me4000_cnt_context { - unsigned long ctrl_reg; - unsigned long counter_0_reg; - unsigned long counter_1_reg; - unsigned long counter_2_reg; -}; - -struct me4000_info { - unsigned long plx_regbase; /* PLX configuration space base address */ - unsigned long me4000_regbase; /* Base address of the ME4000 */ - unsigned long timer_regbase; /* Base address of the timer circuit */ - unsigned long program_regbase; /* Base address to set the program pin for the xilinx */ - - unsigned long plx_regbase_size; /* PLX register set space */ - unsigned long me4000_regbase_size; /* ME4000 register set space */ - unsigned long timer_regbase_size; /* Timer circuit register set space */ - unsigned long program_regbase_size; /* Size of program base address of the ME4000 */ - - unsigned int serial_no; /* Serial number of the board */ - unsigned char hw_revision; /* Hardware revision of the board */ - unsigned short vendor_id; /* Meilhaus vendor id */ - unsigned short device_id; /* Device id */ - - struct pci_dev *pci_dev_p; /* General PCI information */ - - unsigned int irq; /* IRQ assigned from the PCI BIOS */ - - struct me4000_ai_context ai_context; /* Analog input specific context */ - struct me4000_ao_context ao_context[4]; /* Vector with analog output specific context */ - struct me4000_dio_context dio_context; /* Digital I/O specific context */ - struct me4000_cnt_context cnt_context; /* Counter specific context */ -}; - -#define info ((struct me4000_info *)dev->private) - -/*----------------------------------------------------------------------------- - Defines for analog input - ----------------------------------------------------------------------------*/ - -/* General stuff */ -#define ME4000_AI_FIFO_COUNT 2048 - -#define ME4000_AI_MIN_TICKS 66 -#define ME4000_AI_MIN_SAMPLE_TIME 2000 /* Minimum sample time [ns] */ -#define ME4000_AI_BASE_FREQUENCY (unsigned int) 33E6 - -/* Channel list defines and masks */ -#define ME4000_AI_CHANNEL_LIST_COUNT 1024 - -#define ME4000_AI_LIST_INPUT_SINGLE_ENDED 0x000 -#define ME4000_AI_LIST_INPUT_DIFFERENTIAL 0x020 - -#define ME4000_AI_LIST_RANGE_BIPOLAR_10 0x000 -#define ME4000_AI_LIST_RANGE_BIPOLAR_2_5 0x040 -#define ME4000_AI_LIST_RANGE_UNIPOLAR_10 0x080 -#define ME4000_AI_LIST_RANGE_UNIPOLAR_2_5 0x0C0 - -#define ME4000_AI_LIST_LAST_ENTRY 0x100 - -/*----------------------------------------------------------------------------- - Defines for counters - ----------------------------------------------------------------------------*/ - -#define ME4000_CNT_COUNTER_0 0x00 -#define ME4000_CNT_COUNTER_1 0x40 -#define ME4000_CNT_COUNTER_2 0x80 - -#define ME4000_CNT_MODE_0 0x00 /* Change state if zero crossing */ -#define ME4000_CNT_MODE_1 0x02 /* Retriggerable One-Shot */ -#define ME4000_CNT_MODE_2 0x04 /* Asymmetrical divider */ -#define ME4000_CNT_MODE_3 0x06 /* Symmetrical divider */ -#define ME4000_CNT_MODE_4 0x08 /* Counter start by software trigger */ -#define ME4000_CNT_MODE_5 0x0A /* Counter start by hardware trigger */ - -#endif diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c index 8c6f8b93b277..2ce0b14af589 100644 --- a/drivers/staging/comedi/drivers/me_daq.c +++ b/drivers/staging/comedi/drivers/me_daq.c @@ -41,22 +41,14 @@ Configuration options: If bus/slot is not specified, the first available PCI device will be used. - -The 2600 requires a firmware upload, which can be accomplished -using the -i or --init-data option of comedi_config. -The firmware can be -found in the comedi_nonfree_firmware tarball available -from http://www.comedi.org - */ #include <linux/interrupt.h> #include <linux/sched.h> +#include <linux/firmware.h> #include "../comedidev.h" -/*#include "me2600_fw.h" */ - -#define ME_DRIVER_NAME "me_daq" +#define ME2600_FIRMWARE "me2600_firmware.bin" #define PCI_VENDOR_ID_MEILHAUS 0x1402 #define ME2000_DEVICE_ID 0x2000 @@ -198,8 +190,7 @@ struct me_board { static const struct me_board me_boards[] = { { - /* -- ME-2600i -- */ - .name = ME_DRIVER_NAME, + .name = "me-2600i", .device_id = ME2600_DEVICE_ID, /* Analog Output */ .ao_channel_nbr = 4, @@ -214,8 +205,7 @@ static const struct me_board me_boards[] = { .dio_channel_nbr = 32, }, { - /* -- ME-2000i -- */ - .name = ME_DRIVER_NAME, + .name = "me-2000i", .device_id = ME2000_DEVICE_ID, /* Analog Output */ .ao_channel_nbr = 0, @@ -341,7 +331,7 @@ static int me_dio_insn_bits(struct comedi_device *dev, /* Analog instant input */ static int me_ai_insn_read(struct comedi_device *dev, - struct comedi_subdevice *subdevice, + struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { unsigned short value; @@ -435,7 +425,7 @@ static int me_ai_do_cmd_test(struct comedi_device *dev, /* Analog input command */ static int me_ai_do_cmd(struct comedi_device *dev, - struct comedi_subdevice *subdevice) + struct comedi_subdevice *s) { return 0; } @@ -524,8 +514,7 @@ static int me_ao_insn_read(struct comedi_device *dev, /* Xilinx firmware download for card: ME-2600i */ static int me2600_xilinx_download(struct comedi_device *dev, - unsigned char *me2600_firmware, - unsigned int length) + const u8 *data, size_t size) { unsigned int value; unsigned int file_length; @@ -552,19 +541,20 @@ static int me2600_xilinx_download(struct comedi_device *dev, * Byte 8-11: date * Byte 12-15: reserved */ - if (length < 16) + if (size < 16) return -EINVAL; - file_length = (((unsigned int)me2600_firmware[0] & 0xff) << 24) + - (((unsigned int)me2600_firmware[1] & 0xff) << 16) + - (((unsigned int)me2600_firmware[2] & 0xff) << 8) + - ((unsigned int)me2600_firmware[3] & 0xff); + + file_length = (((unsigned int)data[0] & 0xff) << 24) + + (((unsigned int)data[1] & 0xff) << 16) + + (((unsigned int)data[2] & 0xff) << 8) + + ((unsigned int)data[3] & 0xff); /* * Loop for writing firmware byte by byte to xilinx * Firmware data start at offfset 16 */ for (i = 0; i < file_length; i++) - writeb((me2600_firmware[16 + i] & 0xff), + writeb((data[16 + i] & 0xff), dev_private->me_regbase + 0x0); /* Write 5 dummy values to xilinx */ @@ -590,6 +580,22 @@ static int me2600_xilinx_download(struct comedi_device *dev, return 0; } +static int me2600_upload_firmware(struct comedi_device *dev) +{ + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + const struct firmware *fw; + int ret; + + ret = request_firmware(&fw, ME2600_FIRMWARE, &pcidev->dev); + if (ret) + return ret; + + ret = me2600_xilinx_download(dev, fw->data, fw->size); + release_firmware(fw); + + return ret; +} + /* Reset device */ static int me_reset(struct comedi_device *dev) { @@ -607,44 +613,24 @@ static int me_reset(struct comedi_device *dev) return 0; } -static struct pci_dev *me_find_pci_dev(struct comedi_device *dev, - struct comedi_devconfig *it) +static const void *me_find_boardinfo(struct comedi_device *dev, + struct pci_dev *pcidev) { const struct me_board *board; - struct pci_dev *pcidev = NULL; - int bus = it->options[0]; - int slot = it->options[1]; int i; - for_each_pci_dev(pcidev) { - if (bus || slot) { - if (pcidev->bus->number != bus || - PCI_SLOT(pcidev->devfn) != slot) - continue; - } - if (pcidev->vendor != PCI_VENDOR_ID_MEILHAUS) - continue; - - for (i = 0; i < ARRAY_SIZE(me_boards); i++) { - board = &me_boards[i]; - if (board->device_id != pcidev->device) - continue; - - dev->board_ptr = board; - return pcidev; - } + for (i = 0; i < ARRAY_SIZE(me_boards); i++) { + board = &me_boards[i]; + if (board->device_id == pcidev->device) + return board; } - dev_err(dev->class_dev, - "No supported board found! (req. bus %d, slot %d)\n", - bus, slot); return NULL; } -static int me_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int me_attach_pci(struct comedi_device *dev, struct pci_dev *pcidev) { - struct pci_dev *pci_device; - struct comedi_subdevice *subdevice; - struct me_board *board; + const struct me_board *board; + struct comedi_subdevice *s; resource_size_t plx_regbase_tmp; unsigned long plx_regbase_size_tmp; resource_size_t me_regbase_tmp; @@ -654,29 +640,28 @@ static int me_attach(struct comedi_device *dev, struct comedi_devconfig *it) resource_size_t regbase_tmp; int result, error; + comedi_set_hw_dev(dev, &pcidev->dev); + + board = me_find_boardinfo(dev, pcidev); + if (!board) + return -ENODEV; + dev->board_ptr = board; + dev->board_name = board->name; + /* Allocate private memory */ if (alloc_private(dev, sizeof(struct me_private_data)) < 0) return -ENOMEM; - pci_device = me_find_pci_dev(dev, it); - if (!pci_device) - return -EIO; - comedi_set_hw_dev(dev, &pci_device->dev); - board = (struct me_board *)dev->board_ptr; - /* Enable PCI device and request PCI regions */ - if (comedi_pci_enable(pci_device, ME_DRIVER_NAME) < 0) { + if (comedi_pci_enable(pcidev, dev->board_name) < 0) { printk(KERN_ERR "comedi%d: Failed to enable PCI device and " "request regions\n", dev->minor); return -EIO; } - /* Set data in device structure */ - dev->board_name = board->name; - /* Read PLX register base address [PCI_BASE_ADDRESS #0]. */ - plx_regbase_tmp = pci_resource_start(pci_device, 0); - plx_regbase_size_tmp = pci_resource_len(pci_device, 0); + plx_regbase_tmp = pci_resource_start(pcidev, 0); + plx_regbase_size_tmp = pci_resource_len(pcidev, 0); dev_private->plx_regbase = ioremap(plx_regbase_tmp, plx_regbase_size_tmp); dev_private->plx_regbase_size = plx_regbase_size_tmp; @@ -687,8 +672,8 @@ static int me_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* Read Swap base address [PCI_BASE_ADDRESS #5]. */ - swap_regbase_tmp = pci_resource_start(pci_device, 5); - swap_regbase_size_tmp = pci_resource_len(pci_device, 5); + swap_regbase_tmp = pci_resource_start(pcidev, 5); + swap_regbase_size_tmp = pci_resource_len(pcidev, 5); if (!swap_regbase_tmp) printk(KERN_ERR "comedi%d: Swap not present\n", dev->minor); @@ -702,20 +687,20 @@ static int me_attach(struct comedi_device *dev, struct comedi_devconfig *it) plx_regbase_tmp = swap_regbase_tmp; swap_regbase_tmp = regbase_tmp; - result = pci_write_config_dword(pci_device, + result = pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_0, plx_regbase_tmp); if (result != PCIBIOS_SUCCESSFUL) return -EIO; - result = pci_write_config_dword(pci_device, + result = pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_5, swap_regbase_tmp); if (result != PCIBIOS_SUCCESSFUL) return -EIO; } else { plx_regbase_tmp -= 0x80; - result = pci_write_config_dword(pci_device, + result = pci_write_config_dword(pcidev, PCI_BASE_ADDRESS_0, plx_regbase_tmp); if (result != PCIBIOS_SUCCESSFUL) @@ -726,8 +711,8 @@ static int me_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* Read Meilhaus register base address [PCI_BASE_ADDRESS #2]. */ - me_regbase_tmp = pci_resource_start(pci_device, 2); - me_regbase_size_tmp = pci_resource_len(pci_device, 2); + me_regbase_tmp = pci_resource_start(pcidev, 2); + me_regbase_size_tmp = pci_resource_len(pcidev, 2); dev_private->me_regbase_size = me_regbase_size_tmp; dev_private->me_regbase = ioremap(me_regbase_tmp, me_regbase_size_tmp); if (!dev_private->me_regbase) { @@ -735,64 +720,55 @@ static int me_attach(struct comedi_device *dev, struct comedi_devconfig *it) dev->minor); return -ENOMEM; } + /* Download firmware and reset card */ if (board->device_id == ME2600_DEVICE_ID) { - unsigned char *aux_data; - int aux_len; - - aux_data = comedi_aux_data(it->options, 0); - aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]; - - if (!aux_data || aux_len < 1) { - comedi_error(dev, "You must provide me2600 firmware " - "using the --init-data option of " - "comedi_config"); - return -EINVAL; - } - me2600_xilinx_download(dev, aux_data, aux_len); + result = me2600_upload_firmware(dev); + if (result < 0) + return result; } - me_reset(dev); error = comedi_alloc_subdevices(dev, 3); if (error) return error; - subdevice = dev->subdevices + 0; - subdevice->type = COMEDI_SUBD_AI; - subdevice->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_CMD_READ; - subdevice->n_chan = board->ai_channel_nbr; - subdevice->maxdata = board->ai_resolution_mask; - subdevice->len_chanlist = board->ai_channel_nbr; - subdevice->range_table = board->ai_range_list; - subdevice->cancel = me_ai_cancel; - subdevice->insn_read = me_ai_insn_read; - subdevice->do_cmdtest = me_ai_do_cmd_test; - subdevice->do_cmd = me_ai_do_cmd; - - subdevice = dev->subdevices + 1; - subdevice->type = COMEDI_SUBD_AO; - subdevice->subdev_flags = SDF_WRITEABLE | SDF_COMMON; - subdevice->n_chan = board->ao_channel_nbr; - subdevice->maxdata = board->ao_resolution_mask; - subdevice->len_chanlist = board->ao_channel_nbr; - subdevice->range_table = board->ao_range_list; - subdevice->insn_read = me_ao_insn_read; - subdevice->insn_write = me_ao_insn_write; - - subdevice = dev->subdevices + 2; - subdevice->type = COMEDI_SUBD_DIO; - subdevice->subdev_flags = SDF_READABLE | SDF_WRITEABLE; - subdevice->n_chan = board->dio_channel_nbr; - subdevice->maxdata = 1; - subdevice->len_chanlist = board->dio_channel_nbr; - subdevice->range_table = &range_digital; - subdevice->insn_bits = me_dio_insn_bits; - subdevice->insn_config = me_dio_insn_config; - subdevice->io_bits = 0; - - printk(KERN_INFO "comedi%d: " ME_DRIVER_NAME " attached.\n", - dev->minor); + s = &dev->subdevices[0]; + s->type = COMEDI_SUBD_AI; + s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_CMD_READ; + s->n_chan = board->ai_channel_nbr; + s->maxdata = board->ai_resolution_mask; + s->len_chanlist = board->ai_channel_nbr; + s->range_table = board->ai_range_list; + s->cancel = me_ai_cancel; + s->insn_read = me_ai_insn_read; + s->do_cmdtest = me_ai_do_cmd_test; + s->do_cmd = me_ai_do_cmd; + + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_AO; + s->subdev_flags = SDF_WRITEABLE | SDF_COMMON; + s->n_chan = board->ao_channel_nbr; + s->maxdata = board->ao_resolution_mask; + s->len_chanlist = board->ao_channel_nbr; + s->range_table = board->ao_range_list; + s->insn_read = me_ao_insn_read; + s->insn_write = me_ao_insn_write; + + s = &dev->subdevices[2]; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITEABLE; + s->n_chan = board->dio_channel_nbr; + s->maxdata = 1; + s->len_chanlist = board->dio_channel_nbr; + s->range_table = &range_digital; + s->insn_bits = me_dio_insn_bits; + s->insn_config = me_dio_insn_config; + s->io_bits = 0; + + dev_info(dev->class_dev, "%s: %s attached\n", + dev->driver->driver_name, dev->board_name); + return 0; } @@ -818,7 +794,7 @@ static void me_detach(struct comedi_device *dev) static struct comedi_driver me_daq_driver = { .driver_name = "me_daq", .module = THIS_MODULE, - .attach = me_attach, + .attach_pci = me_attach_pci, .detach = me_detach, }; @@ -851,3 +827,4 @@ module_comedi_pci_driver(me_daq_driver, me_daq_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(ME2600_FIRMWARE); diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c index a93166d6a8f8..e27850f628ce 100644 --- a/drivers/staging/comedi/drivers/mite.c +++ b/drivers/staging/comedi/drivers/mite.c @@ -49,6 +49,8 @@ /* #define USE_KMALLOC */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include "mite.h" #include "comedi_fc.h" @@ -59,52 +61,38 @@ #define PCI_DAQ_SIZE 4096 #define PCI_DAQ_SIZE_660X 8192 -struct mite_struct *mite_devices; -EXPORT_SYMBOL(mite_devices); - #define TOP_OF_PAGE(x) ((x)|(~(PAGE_MASK))) -void mite_init(void) +struct mite_struct *mite_alloc(struct pci_dev *pcidev) { - struct pci_dev *pcidev = NULL; struct mite_struct *mite; - - for_each_pci_dev(pcidev) { - if (pcidev->vendor == PCI_VENDOR_ID_NI) { - unsigned i; - - mite = kzalloc(sizeof(*mite), GFP_KERNEL); - if (!mite) { - printk(KERN_ERR "mite: allocation failed\n"); - pci_dev_put(pcidev); - return; - } - spin_lock_init(&mite->lock); - mite->pcidev = pci_dev_get(pcidev); - for (i = 0; i < MAX_MITE_DMA_CHANNELS; ++i) { - mite->channels[i].mite = mite; - mite->channels[i].channel = i; - mite->channels[i].done = 1; - } - mite->next = mite_devices; - mite_devices = mite; + unsigned int i; + + mite = kzalloc(sizeof(*mite), GFP_KERNEL); + if (mite) { + spin_lock_init(&mite->lock); + mite->pcidev = pcidev; + for (i = 0; i < MAX_MITE_DMA_CHANNELS; ++i) { + mite->channels[i].mite = mite; + mite->channels[i].channel = i; + mite->channels[i].done = 1; } } + return mite; } +EXPORT_SYMBOL(mite_alloc); static void dump_chip_signature(u32 csigr_bits) { - printk(KERN_INFO "mite: version = %i, type = %i, mite mode = %i," - "interface mode = %i\n", - mite_csigr_version(csigr_bits), mite_csigr_type(csigr_bits), - mite_csigr_mmode(csigr_bits), mite_csigr_imode(csigr_bits)); - printk(KERN_INFO "mite: num channels = %i, write post fifo depth = %i," - "wins = %i, iowins = %i\n", - mite_csigr_dmac(csigr_bits), mite_csigr_wpdep(csigr_bits), - mite_csigr_wins(csigr_bits), mite_csigr_iowins(csigr_bits)); + pr_info("version = %i, type = %i, mite mode = %i, interface mode = %i\n", + mite_csigr_version(csigr_bits), mite_csigr_type(csigr_bits), + mite_csigr_mmode(csigr_bits), mite_csigr_imode(csigr_bits)); + pr_info("num channels = %i, write post fifo depth = %i, wins = %i, iowins = %i\n", + mite_csigr_dmac(csigr_bits), mite_csigr_wpdep(csigr_bits), + mite_csigr_wins(csigr_bits), mite_csigr_iowins(csigr_bits)); } -unsigned mite_fifo_size(struct mite_struct *mite, unsigned channel) +static unsigned mite_fifo_size(struct mite_struct *mite, unsigned channel) { unsigned fcr_bits = readl(mite->mite_io_addr + MITE_FCR(channel)); unsigned empty_count = (fcr_bits >> 16) & 0xff; @@ -121,7 +109,8 @@ int mite_setup2(struct mite_struct *mite, unsigned use_iodwbsr_1) unsigned unknown_dma_burst_bits; if (comedi_pci_enable(mite->pcidev, "mite")) { - printk(KERN_ERR "error enabling mite and requesting io regions\n"); + dev_err(&mite->pcidev->dev, + "error enabling mite and requesting io regions\n"); return -EIO; } pci_set_master(mite->pcidev); @@ -130,11 +119,10 @@ int mite_setup2(struct mite_struct *mite, unsigned use_iodwbsr_1) mite->mite_phys_addr = addr; mite->mite_io_addr = ioremap(addr, PCI_MITE_SIZE); if (!mite->mite_io_addr) { - printk(KERN_ERR "Failed to remap mite io memory address\n"); + dev_err(&mite->pcidev->dev, + "Failed to remap mite io memory address\n"); return -ENOMEM; } - printk(KERN_INFO "MITE:0x%08llx mapped to %p ", - (unsigned long long)mite->mite_phys_addr, mite->mite_io_addr); addr = pci_resource_start(mite->pcidev, 1); mite->daq_phys_addr = addr; @@ -145,15 +133,15 @@ int mite_setup2(struct mite_struct *mite, unsigned use_iodwbsr_1) */ mite->daq_io_addr = ioremap(mite->daq_phys_addr, length); if (!mite->daq_io_addr) { - printk(KERN_ERR "Failed to remap daq io memory address\n"); + dev_err(&mite->pcidev->dev, + "Failed to remap daq io memory address\n"); return -ENOMEM; } - printk(KERN_INFO "DAQ:0x%08llx mapped to %p\n", - (unsigned long long)mite->daq_phys_addr, mite->daq_io_addr); if (use_iodwbsr_1) { writel(0, mite->mite_io_addr + MITE_IODWBSR); - printk(KERN_INFO "mite: using I/O Window Base Size register 1\n"); + dev_info(&mite->pcidev->dev, + "using I/O Window Base Size register 1\n"); writel(mite->daq_phys_addr | WENAB | MITE_IODWBSR_1_WSIZE_bits(length), mite->mite_io_addr + MITE_IODWBSR_1); @@ -178,9 +166,9 @@ int mite_setup2(struct mite_struct *mite, unsigned use_iodwbsr_1) csigr_bits = readl(mite->mite_io_addr + MITE_CSIGR); mite->num_channels = mite_csigr_dmac(csigr_bits); if (mite->num_channels > MAX_MITE_DMA_CHANNELS) { - printk(KERN_WARNING "mite: bug? chip claims to have %i dma " - "channels. Setting to %i.\n", - mite->num_channels, MAX_MITE_DMA_CHANNELS); + dev_warn(&mite->pcidev->dev, + "mite: bug? chip claims to have %i dma channels. Setting to %i.\n", + mite->num_channels, MAX_MITE_DMA_CHANNELS); mite->num_channels = MAX_MITE_DMA_CHANNELS; } dump_chip_signature(csigr_bits); @@ -193,9 +181,7 @@ int mite_setup2(struct mite_struct *mite, unsigned use_iodwbsr_1) mite->mite_io_addr + MITE_CHCR(i)); } mite->fifo_size = mite_fifo_size(mite, 0); - printk(KERN_INFO "mite: fifo size is %i.\n", mite->fifo_size); - mite->used = 1; - + dev_info(&mite->pcidev->dev, "fifo size is %i.\n", mite->fifo_size); return 0; } EXPORT_SYMBOL(mite_setup2); @@ -206,17 +192,6 @@ int mite_setup(struct mite_struct *mite) } EXPORT_SYMBOL(mite_setup); -void mite_cleanup(void) -{ - struct mite_struct *mite, *next; - - for (mite = mite_devices; mite; mite = next) { - pci_dev_put(mite->pcidev); - next = mite->next; - kfree(mite); - } -} - void mite_unsetup(struct mite_struct *mite) { /* unsigned long offset, start, length; */ @@ -236,26 +211,43 @@ void mite_unsetup(struct mite_struct *mite) comedi_pci_disable(mite->pcidev); mite->mite_phys_addr = 0; } - - mite->used = 0; } EXPORT_SYMBOL(mite_unsetup); -void mite_list_devices(void) +struct mite_dma_descriptor_ring *mite_alloc_ring(struct mite_struct *mite) +{ + struct mite_dma_descriptor_ring *ring = + kmalloc(sizeof(struct mite_dma_descriptor_ring), GFP_KERNEL); + + if (ring == NULL) + return ring; + ring->hw_dev = get_device(&mite->pcidev->dev); + if (ring->hw_dev == NULL) { + kfree(ring); + return NULL; + } + ring->n_links = 0; + ring->descriptors = NULL; + ring->descriptors_dma_addr = 0; + return ring; +}; +EXPORT_SYMBOL(mite_alloc_ring); + +void mite_free_ring(struct mite_dma_descriptor_ring *ring) { - struct mite_struct *mite, *next; - - printk(KERN_INFO "Available NI device IDs:"); - if (mite_devices) - for (mite = mite_devices; mite; mite = next) { - next = mite->next; - printk(KERN_INFO " 0x%04x", mite_device_id(mite)); - if (mite->used) - printk(KERN_INFO "(used)"); + if (ring) { + if (ring->descriptors) { + dma_free_coherent(ring->hw_dev, + ring->n_links * + sizeof(struct mite_dma_descriptor), + ring->descriptors, + ring->descriptors_dma_addr); } - printk(KERN_INFO "\n"); -} -EXPORT_SYMBOL(mite_list_devices); + put_device(ring->hw_dev); + kfree(ring); + } +}; +EXPORT_SYMBOL(mite_free_ring); struct mite_channel *mite_request_channel_in_range(struct mite_struct *mite, struct @@ -317,7 +309,7 @@ void mite_dma_arm(struct mite_channel *mite_chan) int chor; unsigned long flags; - MDPRINTK("mite_dma_arm ch%i\n", channel); + MDPRINTK("mite_dma_arm ch%i\n", mite_chan->channel); /* * memory barrier is intended to insure any twiddling with the buffer * is done before writing to the mite to arm dma transfer @@ -365,7 +357,8 @@ int mite_buf_change(struct mite_dma_descriptor_ring *ring, n_links * sizeof(struct mite_dma_descriptor), &ring->descriptors_dma_addr, GFP_KERNEL); if (!ring->descriptors) { - printk(KERN_ERR "mite: ring buffer allocation failed\n"); + dev_err(async->subdevice->device->class_dev, + "mite: ring buffer allocation failed\n"); return -ENOMEM; } ring->n_links = n_links; @@ -442,8 +435,7 @@ void mite_prep_dma(struct mite_channel *mite_chan, mcr |= CR_PSIZE32; break; default: - printk(KERN_WARNING "mite: bug! invalid mem bit width for dma " - "transfer\n"); + pr_warn("bug! invalid mem bit width for dma transfer\n"); break; } writel(mcr, mite->mite_io_addr + MITE_MCR(mite_chan->channel)); @@ -462,8 +454,7 @@ void mite_prep_dma(struct mite_channel *mite_chan, dcr |= CR_PSIZE32; break; default: - printk(KERN_WARNING "mite: bug! invalid dev bit width for dma " - "transfer\n"); + pr_warn("bug! invalid dev bit width for dma transfer\n"); break; } writel(dcr, mite->mite_io_addr + MITE_DCR(mite_chan->channel)); @@ -483,7 +474,7 @@ void mite_prep_dma(struct mite_channel *mite_chan, } EXPORT_SYMBOL(mite_prep_dma); -u32 mite_device_bytes_transferred(struct mite_channel *mite_chan) +static u32 mite_device_bytes_transferred(struct mite_channel *mite_chan) { struct mite_struct *mite = mite_chan->mite; return readl(mite->mite_io_addr + MITE_DAR(mite_chan->channel)); @@ -577,7 +568,8 @@ int mite_sync_input_dma(struct mite_channel *mite_chan, nbytes = mite_bytes_written_to_memory_lb(mite_chan); if ((int)(mite_bytes_written_to_memory_ub(mite_chan) - old_alloc_count) > 0) { - printk("mite: DMA overwrite of free area\n"); + dev_warn(async->subdevice->device->class_dev, + "mite: DMA overwrite of free area\n"); async->events |= COMEDI_CB_OVERFLOW; return -1; } @@ -621,7 +613,8 @@ int mite_sync_output_dma(struct mite_channel *mite_chan, (int)(nbytes_ub - stop_count) > 0) nbytes_ub = stop_count; if ((int)(nbytes_ub - old_alloc_count) > 0) { - printk(KERN_ERR "mite: DMA underrun\n"); + dev_warn(async->subdevice->device->class_dev, + "mite: DMA underrun\n"); async->events |= COMEDI_CB_OVERFLOW; return -1; } @@ -672,8 +665,6 @@ EXPORT_SYMBOL(mite_done); #ifdef DEBUG_MITE -static void mite_decode(char **bit_str, unsigned int bits); - /* names of bits in mite registers */ static const char *const mite_CHOR_strings[] = { @@ -743,86 +734,80 @@ static const char *const mite_CHSR_strings[] = { "28", "lpauses", "30", "int", }; -void mite_dump_regs(struct mite_channel *mite_chan) -{ - unsigned long mite_io_addr = - (unsigned long)mite_chan->mite->mite_io_addr; - unsigned long addr = 0; - unsigned long temp = 0; - - printk(KERN_DEBUG "mite_dump_regs ch%i\n", mite_chan->channel); - printk(KERN_DEBUG "mite address is =0x%08lx\n", mite_io_addr); - - addr = mite_io_addr + MITE_CHOR(channel); - printk(KERN_DEBUG "mite status[CHOR]at 0x%08lx =0x%08lx\n", addr, - temp = readl(addr)); - mite_decode(mite_CHOR_strings, temp); - addr = mite_io_addr + MITE_CHCR(channel); - printk(KERN_DEBUG "mite status[CHCR]at 0x%08lx =0x%08lx\n", addr, - temp = readl(addr)); - mite_decode(mite_CHCR_strings, temp); - addr = mite_io_addr + MITE_TCR(channel); - printk(KERN_DEBUG "mite status[TCR] at 0x%08lx =0x%08x\n", addr, - readl(addr)); - addr = mite_io_addr + MITE_MCR(channel); - printk(KERN_DEBUG "mite status[MCR] at 0x%08lx =0x%08lx\n", addr, - temp = readl(addr)); - mite_decode(mite_MCR_strings, temp); - - addr = mite_io_addr + MITE_MAR(channel); - printk(KERN_DEBUG "mite status[MAR] at 0x%08lx =0x%08x\n", addr, - readl(addr)); - addr = mite_io_addr + MITE_DCR(channel); - printk(KERN_DEBUG "mite status[DCR] at 0x%08lx =0x%08lx\n", addr, - temp = readl(addr)); - mite_decode(mite_DCR_strings, temp); - addr = mite_io_addr + MITE_DAR(channel); - printk(KERN_DEBUG "mite status[DAR] at 0x%08lx =0x%08x\n", addr, - readl(addr)); - addr = mite_io_addr + MITE_LKCR(channel); - printk(KERN_DEBUG "mite status[LKCR]at 0x%08lx =0x%08lx\n", addr, - temp = readl(addr)); - mite_decode(mite_LKCR_strings, temp); - addr = mite_io_addr + MITE_LKAR(channel); - printk(KERN_DEBUG "mite status[LKAR]at 0x%08lx =0x%08x\n", addr, - readl(addr)); - addr = mite_io_addr + MITE_CHSR(channel); - printk(KERN_DEBUG "mite status[CHSR]at 0x%08lx =0x%08lx\n", addr, - temp = readl(addr)); - mite_decode(mite_CHSR_strings, temp); - addr = mite_io_addr + MITE_FCR(channel); - printk(KERN_DEBUG "mite status[FCR] at 0x%08lx =0x%08x\n\n", addr, - readl(addr)); -} -EXPORT_SYMBOL(mite_dump_regs); - -static void mite_decode(char **bit_str, unsigned int bits) +static void mite_decode(const char *const *bit_str, unsigned int bits) { int i; for (i = 31; i >= 0; i--) { if (bits & (1 << i)) - printk(KERN_DEBUG " %s", bit_str[i]); + pr_debug(" %s\n", bit_str[i]); } - printk(KERN_DEBUG "\n"); } -EXPORT_SYMBOL(mite_decode); -#endif -#ifdef MODULE -int __init init_module(void) +void mite_dump_regs(struct mite_channel *mite_chan) { - mite_init(); - mite_list_devices(); + void __iomem *mite_io_addr = mite_chan->mite->mite_io_addr; + unsigned int offset; + unsigned int value; + int channel = mite_chan->channel; + + pr_debug("mite_dump_regs ch%i\n", channel); + pr_debug("mite address is =%p\n", mite_io_addr); + + offset = MITE_CHOR(channel); + value = readl(mite_io_addr + offset); + pr_debug("mite status[CHOR] at 0x%08x =0x%08x\n", offset, value); + mite_decode(mite_CHOR_strings, value); + offset = MITE_CHCR(channel); + value = readl(mite_io_addr + offset); + pr_debug("mite status[CHCR] at 0x%08x =0x%08x\n", offset, value); + mite_decode(mite_CHCR_strings, value); + offset = MITE_TCR(channel); + value = readl(mite_io_addr + offset); + pr_debug("mite status[TCR] at 0x%08x =0x%08x\n", offset, value); + offset = MITE_MCR(channel); + value = readl(mite_io_addr + offset); + pr_debug("mite status[MCR] at 0x%08x =0x%08x\n", offset, value); + mite_decode(mite_MCR_strings, value); + offset = MITE_MAR(channel); + value = readl(mite_io_addr + offset); + pr_debug("mite status[MAR] at 0x%08x =0x%08x\n", offset, value); + offset = MITE_DCR(channel); + value = readl(mite_io_addr + offset); + pr_debug("mite status[DCR] at 0x%08x =0x%08x\n", offset, value); + mite_decode(mite_DCR_strings, value); + offset = MITE_DAR(channel); + value = readl(mite_io_addr + offset); + pr_debug("mite status[DAR] at 0x%08x =0x%08x\n", offset, value); + offset = MITE_LKCR(channel); + value = readl(mite_io_addr + offset); + pr_debug("mite status[LKCR] at 0x%08x =0x%08x\n", offset, value); + mite_decode(mite_LKCR_strings, value); + offset = MITE_LKAR(channel); + value = readl(mite_io_addr + offset); + pr_debug("mite status[LKAR] at 0x%08x =0x%08x\n", offset, value); + offset = MITE_CHSR(channel); + value = readl(mite_io_addr + offset); + pr_debug("mite status[CHSR] at 0x%08x =0x%08x\n", offset, value); + mite_decode(mite_CHSR_strings, value); + offset = MITE_FCR(channel); + value = readl(mite_io_addr + offset); + pr_debug("mite status[FCR] at 0x%08x =0x%08x\n", offset, value); +} +EXPORT_SYMBOL(mite_dump_regs); +#endif +static int __init mite_module_init(void) +{ return 0; } -void __exit cleanup_module(void) +static void __exit mite_module_exit(void) { - mite_cleanup(); } -#endif + +module_init(mite_module_init); +module_exit(mite_module_exit); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/mite.h b/drivers/staging/comedi/drivers/mite.h index 83f1b27a4720..255b8ba9c917 100644 --- a/drivers/staging/comedi/drivers/mite.h +++ b/drivers/staging/comedi/drivers/mite.h @@ -25,15 +25,16 @@ #define _MITE_H_ #include <linux/pci.h> +#include <linux/log2.h> #include "../comedidev.h" /* #define DEBUG_MITE */ #define PCIMIO_COMPAT #ifdef DEBUG_MITE -#define MDPRINTK(format, args...) printk(format , ## args) +#define MDPRINTK(format, args...) pr_debug(format , ## args) #else -#define MDPRINTK(format, args...) +#define MDPRINTK(format, args...) do { } while (0) #endif #define MAX_MITE_DMA_CHANNELS 8 @@ -61,15 +62,11 @@ struct mite_channel { }; struct mite_struct { - struct mite_struct *next; - int used; - struct pci_dev *pcidev; resource_size_t mite_phys_addr; void __iomem *mite_io_addr; resource_size_t daq_phys_addr; void __iomem *daq_io_addr; - struct mite_channel channels[MAX_MITE_DMA_CHANNELS]; short channel_allocated[MAX_MITE_DMA_CHANNELS]; int num_channels; @@ -77,41 +74,12 @@ struct mite_struct { spinlock_t lock; }; -static inline struct mite_dma_descriptor_ring *mite_alloc_ring(struct - mite_struct - *mite) -{ - struct mite_dma_descriptor_ring *ring = - kmalloc(sizeof(struct mite_dma_descriptor_ring), GFP_KERNEL); - if (ring == NULL) - return ring; - ring->hw_dev = get_device(&mite->pcidev->dev); - if (ring->hw_dev == NULL) { - kfree(ring); - return NULL; - } - ring->n_links = 0; - ring->descriptors = NULL; - ring->descriptors_dma_addr = 0; - return ring; -}; - -static inline void mite_free_ring(struct mite_dma_descriptor_ring *ring) -{ - if (ring) { - if (ring->descriptors) { - dma_free_coherent(ring->hw_dev, - ring->n_links * - sizeof(struct mite_dma_descriptor), - ring->descriptors, - ring->descriptors_dma_addr); - } - put_device(ring->hw_dev); - kfree(ring); - } -}; +struct mite_struct *mite_alloc(struct pci_dev *pcidev); -extern struct mite_struct *mite_devices; +static inline void mite_free(struct mite_struct *mite) +{ + kfree(mite); +} static inline unsigned int mite_irq(struct mite_struct *mite) { @@ -123,12 +91,11 @@ static inline unsigned int mite_device_id(struct mite_struct *mite) return mite->pcidev->device; }; -void mite_init(void); -void mite_cleanup(void); int mite_setup(struct mite_struct *mite); int mite_setup2(struct mite_struct *mite, unsigned use_iodwbsr_1); void mite_unsetup(struct mite_struct *mite); -void mite_list_devices(void); +struct mite_dma_descriptor_ring *mite_alloc_ring(struct mite_struct *mite); +void mite_free_ring(struct mite_dma_descriptor_ring *ring); struct mite_channel *mite_request_channel_in_range(struct mite_struct *mite, struct mite_dma_descriptor_ring @@ -279,8 +246,9 @@ enum MITE_IODWBSR_bits { static inline unsigned MITE_IODWBSR_1_WSIZE_bits(unsigned size) { unsigned order = 0; - while (size >>= 1) - ++order; + + BUG_ON(size == 0); + order = ilog2(size); BUG_ON(order < 1); return (order - 1) & 0x1f; } @@ -427,12 +395,10 @@ static inline int CR_RL(unsigned int retry_limit) { int value = 0; - while (retry_limit) { - retry_limit >>= 1; - value++; - } + if (retry_limit) + value = 1 + ilog2(retry_limit); if (value > 0x7) - printk("comedi: bug! retry_limit too large\n"); + value = 0x7; return (value & 0x7) << 21; } diff --git a/drivers/staging/comedi/drivers/mpc624.c b/drivers/staging/comedi/drivers/mpc624.c index b928b6763cd5..f8b7faefc961 100644 --- a/drivers/staging/comedi/drivers/mpc624.c +++ b/drivers/staging/comedi/drivers/mpc624.c @@ -353,7 +353,7 @@ static int mpc624_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_DIFF; s->n_chan = 8; diff --git a/drivers/staging/comedi/drivers/mpc8260cpm.c b/drivers/staging/comedi/drivers/mpc8260cpm.c index a7fda8f01e8c..c0c33299b7f1 100644 --- a/drivers/staging/comedi/drivers/mpc8260cpm.c +++ b/drivers/staging/comedi/drivers/mpc8260cpm.c @@ -137,7 +137,7 @@ static int mpc8260cpm_attach(struct comedi_device *dev, return ret; for (i = 0; i < 4; i++) { - s = dev->subdevices + i; + s = &dev->subdevices[i]; s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = 32; diff --git a/drivers/staging/comedi/drivers/multiq3.c b/drivers/staging/comedi/drivers/multiq3.c index eccbe1fb4f2c..4625cb4d07c6 100644 --- a/drivers/staging/comedi/drivers/multiq3.c +++ b/drivers/staging/comedi/drivers/multiq3.c @@ -204,8 +204,10 @@ static int multiq3_encoder_insn_read(struct comedi_device *dev, static void encoder_reset(struct comedi_device *dev) { + struct comedi_subdevice *s = &dev->subdevices[4]; int chan; - for (chan = 0; chan < dev->subdevices[4].n_chan; chan++) { + + for (chan = 0; chan < s->n_chan; chan++) { int control = MULTIQ3_CONTROL_MUST | MULTIQ3_AD_MUX_EN | (chan << 3); outw(control, dev->iobase + MULTIQ3_CONTROL); @@ -258,7 +260,7 @@ static int multiq3_attach(struct comedi_device *dev, if (result < 0) return result; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* ai subdevice */ s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND; @@ -267,7 +269,7 @@ static int multiq3_attach(struct comedi_device *dev, s->maxdata = 0x1fff; s->range_table = &range_bipolar5; - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* ao subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; @@ -277,7 +279,7 @@ static int multiq3_attach(struct comedi_device *dev, s->maxdata = 0xfff; s->range_table = &range_bipolar5; - s = dev->subdevices + 2; + s = &dev->subdevices[2]; /* di subdevice */ s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; @@ -286,7 +288,7 @@ static int multiq3_attach(struct comedi_device *dev, s->maxdata = 1; s->range_table = &range_digital; - s = dev->subdevices + 3; + s = &dev->subdevices[3]; /* do subdevice */ s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE; @@ -296,7 +298,7 @@ static int multiq3_attach(struct comedi_device *dev, s->range_table = &range_digital; s->state = 0; - s = dev->subdevices + 4; + s = &dev->subdevices[4]; /* encoder (counter) subdevice */ s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = SDF_READABLE | SDF_LSAMPL; diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c index a80c52fb2731..51295f32ee89 100644 --- a/drivers/staging/comedi/drivers/ni_6527.c +++ b/drivers/staging/comedi/drivers/ni_6527.c @@ -44,8 +44,11 @@ Updated: Sat, 25 Jan 2003 13:24:40 -0800 #include <linux/interrupt.h> #include "../comedidev.h" +#include "comedi_fc.h" #include "mite.h" +#define DRIVER_NAME "ni_6527" + #define NI6527_DIO_SIZE 4096 #define NI6527_MITE_SIZE 4096 @@ -76,16 +79,6 @@ Updated: Sat, 25 Jan 2003 13:24:40 -0800 #define Rising_Edge_Detection_Enable(x) (0x018+(x)) #define Falling_Edge_Detection_Enable(x) (0x020+(x)) -static int ni6527_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static void ni6527_detach(struct comedi_device *dev); -static struct comedi_driver driver_ni6527 = { - .driver_name = "ni6527", - .module = THIS_MODULE, - .attach = ni6527_attach, - .detach = ni6527_detach, -}; - struct ni6527_board { int dev_id; @@ -103,7 +96,6 @@ static const struct ni6527_board ni6527_boards[] = { }, }; -#define n_ni6527_boards ARRAY_SIZE(ni6527_boards) #define this_board ((const struct ni6527_board *)dev->board_ptr) static DEFINE_PCI_DEVICE_TABLE(ni6527_pci_table) = { @@ -122,8 +114,6 @@ struct ni6527_private { #define devpriv ((struct ni6527_private *)dev->private) -static int ni6527_find_device(struct comedi_device *dev, int bus, int slot); - static int ni6527_di_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -212,7 +202,7 @@ static int ni6527_do_insn_bits(struct comedi_device *dev, static irqreturn_t ni6527_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 2; + struct comedi_subdevice *s = &dev->subdevices[2]; unsigned int status; status = readb(devpriv->mite->daq_io_addr + Change_Status); @@ -235,40 +225,20 @@ static int ni6527_intr_cmdtest(struct comedi_device *dev, struct comedi_cmd *cmd) { int err = 0; - int tmp; - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_OTHER; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_FOLLOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_OTHER); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT); if (err) return 1; - /* step 2: make sure trigger sources are unique and */ - /* are mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -364,36 +334,53 @@ static int ni6527_intr_insn_config(struct comedi_device *dev, return 2; } -static int ni6527_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static const struct ni6527_board * +ni6527_find_boardinfo(struct pci_dev *pcidev) +{ + unsigned int dev_id = pcidev->device; + unsigned int n; + + for (n = 0; n < ARRAY_SIZE(ni6527_boards); n++) { + const struct ni6527_board *board = &ni6527_boards[n]; + if (board->dev_id == dev_id) + return board; + } + return NULL; +} + +static int __devinit ni6527_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) { struct comedi_subdevice *s; int ret; - printk(KERN_INFO "comedi%d: ni6527\n", dev->minor); - ret = alloc_private(dev, sizeof(struct ni6527_private)); if (ret < 0) return ret; - ret = ni6527_find_device(dev, it->options[0], it->options[1]); - if (ret < 0) - return ret; + dev->board_ptr = ni6527_find_boardinfo(pcidev); + if (!dev->board_ptr) + return -ENODEV; + + devpriv->mite = mite_alloc(pcidev); + if (!devpriv->mite) + return -ENOMEM; ret = mite_setup(devpriv->mite); if (ret < 0) { - printk(KERN_ERR "comedi: error setting up mite\n"); + dev_err(dev->class_dev, "error setting up mite\n"); return ret; } dev->board_name = this_board->name; - printk(KERN_INFO "comedi board: %s, ID=0x%02x\n", dev->board_name, - readb(devpriv->mite->daq_io_addr + ID_Register)); + dev_info(dev->class_dev, "board: %s, ID=0x%02x\n", dev->board_name, + readb(devpriv->mite->daq_io_addr + ID_Register)); ret = comedi_alloc_subdevices(dev, 3); if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; s->n_chan = 24; @@ -402,7 +389,7 @@ static int ni6527_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_config = ni6527_di_insn_config; s->insn_bits = ni6527_di_insn_bits; - s = dev->subdevices + 1; + s = &dev->subdevices[1]; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = 24; @@ -410,7 +397,7 @@ static int ni6527_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = 1; s->insn_bits = ni6527_do_insn_bits; - s = dev->subdevices + 2; + s = &dev->subdevices[2]; dev->read_subdev = s; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE | SDF_CMD_READ; @@ -432,9 +419,9 @@ static int ni6527_attach(struct comedi_device *dev, struct comedi_devconfig *it) writeb(0x00, devpriv->mite->daq_io_addr + Master_Interrupt_Control); ret = request_irq(mite_irq(devpriv->mite), ni6527_interrupt, - IRQF_SHARED, "ni6527", dev); + IRQF_SHARED, DRIVER_NAME, dev); if (ret < 0) - printk(KERN_WARNING "comedi i6527 irq not available\n"); + dev_warn(dev->class_dev, "irq not available\n"); else dev->irq = mite_irq(devpriv->mite); @@ -448,73 +435,37 @@ static void ni6527_detach(struct comedi_device *dev) devpriv->mite->daq_io_addr + Master_Interrupt_Control); if (dev->irq) free_irq(dev->irq, dev); - if (devpriv && devpriv->mite) + if (devpriv && devpriv->mite) { mite_unsetup(devpriv->mite); -} - -static int ni6527_find_device(struct comedi_device *dev, int bus, int slot) -{ - struct mite_struct *mite; - int i; - - for (mite = mite_devices; mite; mite = mite->next) { - if (mite->used) - continue; - if (bus || slot) { - if (bus != mite->pcidev->bus->number || - slot != PCI_SLOT(mite->pcidev->devfn)) - continue; - } - for (i = 0; i < n_ni6527_boards; i++) { - if (mite_device_id(mite) == ni6527_boards[i].dev_id) { - dev->board_ptr = ni6527_boards + i; - devpriv->mite = mite; - return 0; - } - } + mite_free(devpriv->mite); } - printk(KERN_ERR "comedi 6527: no device found\n"); - mite_list_devices(); - return -EIO; } -static int __devinit driver_ni6527_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +static struct comedi_driver ni6527_driver = { + .driver_name = DRIVER_NAME, + .module = THIS_MODULE, + .attach_pci = ni6527_attach_pci, + .detach = ni6527_detach, +}; + +static int __devinit ni6527_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, &driver_ni6527); + return comedi_pci_auto_config(dev, &ni6527_driver); } -static void __devexit driver_ni6527_pci_remove(struct pci_dev *dev) +static void __devexit ni6527_pci_remove(struct pci_dev *dev) { comedi_pci_auto_unconfig(dev); } -static struct pci_driver driver_ni6527_pci_driver = { +static struct pci_driver ni6527_pci_driver = { + .name = DRIVER_NAME, .id_table = ni6527_pci_table, - .probe = &driver_ni6527_pci_probe, - .remove = __devexit_p(&driver_ni6527_pci_remove) + .probe = ni6527_pci_probe, + .remove = __devexit_p(ni6527_pci_remove) }; - -static int __init driver_ni6527_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_ni6527); - if (retval < 0) - return retval; - - driver_ni6527_pci_driver.name = (char *)driver_ni6527.driver_name; - return pci_register_driver(&driver_ni6527_pci_driver); -} - -static void __exit driver_ni6527_cleanup_module(void) -{ - pci_unregister_driver(&driver_ni6527_pci_driver); - comedi_driver_unregister(&driver_ni6527); -} - -module_init(driver_ni6527_init_module); -module_exit(driver_ni6527_cleanup_module); +module_comedi_pci_driver(ni6527_driver, ni6527_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c index bce39f1ea36d..2a73ff57a2fb 100644 --- a/drivers/staging/comedi/drivers/ni_65xx.c +++ b/drivers/staging/comedi/drivers/ni_65xx.c @@ -55,6 +55,7 @@ except maybe the 6514. #include <linux/slab.h> #include "../comedidev.h" +#include "comedi_fc.h" #include "mite.h" #define NI6514_DIO_SIZE 4096 @@ -109,18 +110,7 @@ static inline unsigned Filter_Enable(unsigned port) #define OverflowIntEnable 0x02 #define EdgeIntEnable 0x01 -static int ni_65xx_attach(struct comedi_device *dev, - struct comedi_devconfig *it); -static void ni_65xx_detach(struct comedi_device *dev); -static struct comedi_driver driver_ni_65xx = { - .driver_name = "ni_65xx", - .module = THIS_MODULE, - .attach = ni_65xx_attach, - .detach = ni_65xx_detach, -}; - struct ni_65xx_board { - int dev_id; const char *name; unsigned num_dio_ports; @@ -325,8 +315,6 @@ static struct ni_65xx_subdevice_private *ni_65xx_alloc_subdevice_private(void) return subdev_private; } -static int ni_65xx_find_device(struct comedi_device *dev, int bus, int slot); - static int ni_65xx_config_filter(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -453,11 +441,9 @@ static int ni_65xx_dio_insn_bits(struct comedi_device *dev, writeb(bits, private(dev)->mite->daq_io_addr + Port_Data(port)); -/* printk("wrote 0x%x to port %i\n", bits, port); */ } port_read_bits = readb(private(dev)->mite->daq_io_addr + Port_Data(port)); -/* printk("read 0x%x from port %i\n", port_read_bits, port); */ if (s->type == COMEDI_SUBD_DO && board(dev)->invert_outputs) { /* Outputs inverted, so invert value read back from * DO subdevice. (Does not apply to boards with DIO @@ -478,7 +464,7 @@ static int ni_65xx_dio_insn_bits(struct comedi_device *dev, static irqreturn_t ni_65xx_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 2; + struct comedi_subdevice *s = &dev->subdevices[2]; unsigned int status; status = readb(private(dev)->mite->daq_io_addr + Change_Status); @@ -501,40 +487,20 @@ static int ni_65xx_intr_cmdtest(struct comedi_device *dev, struct comedi_cmd *cmd) { int err = 0; - int tmp; - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_OTHER; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_FOLLOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_OTHER); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually - compatible */ + /* Step 2a : make sure trigger sources are unique */ + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -644,41 +610,55 @@ static int ni_65xx_intr_insn_config(struct comedi_device *dev, return 2; } -static int ni_65xx_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static const struct ni_65xx_board * +ni_65xx_find_boardinfo(struct pci_dev *pcidev) +{ + unsigned int dev_id = pcidev->device; + unsigned int n; + + for (n = 0; n < ARRAY_SIZE(ni_65xx_boards); n++) { + const struct ni_65xx_board *board = &ni_65xx_boards[n]; + if (board->dev_id == dev_id) + return board; + } + return NULL; +} + +static int __devinit ni_65xx_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) { struct comedi_subdevice *s; unsigned i; int ret; - printk(KERN_INFO "comedi%d: ni_65xx:", dev->minor); - ret = alloc_private(dev, sizeof(struct ni_65xx_private)); if (ret < 0) return ret; - ret = ni_65xx_find_device(dev, it->options[0], it->options[1]); - if (ret < 0) - return ret; + dev->board_ptr = ni_65xx_find_boardinfo(pcidev); + if (!dev->board_ptr) + return -ENODEV; + + private(dev)->mite = mite_alloc(pcidev); + if (!private(dev)->mite) + return -ENOMEM; ret = mite_setup(private(dev)->mite); if (ret < 0) { - printk(KERN_WARNING "error setting up mite\n"); + dev_warn(dev->class_dev, "error setting up mite\n"); return ret; } dev->board_name = board(dev)->name; dev->irq = mite_irq(private(dev)->mite); - printk(KERN_INFO " %s", dev->board_name); - - printk(KERN_INFO " ID=0x%02x", + dev_info(dev->class_dev, "board: %s, ID=0x%02x", dev->board_name, readb(private(dev)->mite->daq_io_addr + ID_Register)); ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; if (board(dev)->num_di_ports) { s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; @@ -696,7 +676,7 @@ static int ni_65xx_attach(struct comedi_device *dev, s->type = COMEDI_SUBD_UNUSED; } - s = dev->subdevices + 1; + s = &dev->subdevices[1]; if (board(dev)->num_do_ports) { s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; @@ -713,7 +693,7 @@ static int ni_65xx_attach(struct comedi_device *dev, s->type = COMEDI_SUBD_UNUSED; } - s = dev->subdevices + 2; + s = &dev->subdevices[2]; if (board(dev)->num_dio_ports) { s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; @@ -737,7 +717,7 @@ static int ni_65xx_attach(struct comedi_device *dev, s->type = COMEDI_SUBD_UNUSED; } - s = dev->subdevices + 3; + s = &dev->subdevices[3]; dev->read_subdev = s; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE | SDF_CMD_READ; @@ -772,11 +752,9 @@ static int ni_65xx_attach(struct comedi_device *dev, "ni_65xx", dev); if (ret < 0) { dev->irq = 0; - printk(KERN_WARNING " irq not available"); + dev_warn(dev->class_dev, "irq not available\n"); } - printk("\n"); - return 0; } @@ -791,79 +769,46 @@ static void ni_65xx_detach(struct comedi_device *dev) if (dev->irq) free_irq(dev->irq, dev); if (private(dev)) { + struct comedi_subdevice *s; unsigned i; + for (i = 0; i < dev->n_subdevices; ++i) { - kfree(dev->subdevices[i].private); - dev->subdevices[i].private = NULL; + s = &dev->subdevices[i]; + kfree(s->private); + s->private = NULL; } - if (private(dev)->mite) + if (private(dev)->mite) { mite_unsetup(private(dev)->mite); - } -} - -static int ni_65xx_find_device(struct comedi_device *dev, int bus, int slot) -{ - struct mite_struct *mite; - int i; - - for (mite = mite_devices; mite; mite = mite->next) { - if (mite->used) - continue; - if (bus || slot) { - if (bus != mite->pcidev->bus->number || - slot != PCI_SLOT(mite->pcidev->devfn)) - continue; - } - for (i = 0; i < n_ni_65xx_boards; i++) { - if (mite_device_id(mite) == ni_65xx_boards[i].dev_id) { - dev->board_ptr = ni_65xx_boards + i; - private(dev)->mite = mite; - return 0; - } + mite_free(private(dev)->mite); } } - printk(KERN_WARNING "no device found\n"); - mite_list_devices(); - return -EIO; } -static int __devinit driver_ni_65xx_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +static struct comedi_driver ni_65xx_driver = { + .driver_name = "ni_65xx", + .module = THIS_MODULE, + .attach_pci = ni_65xx_attach_pci, + .detach = ni_65xx_detach, +}; + +static int __devinit ni_65xx_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, &driver_ni_65xx); + return comedi_pci_auto_config(dev, &ni_65xx_driver); } -static void __devexit driver_ni_65xx_pci_remove(struct pci_dev *dev) +static void __devexit ni_65xx_pci_remove(struct pci_dev *dev) { comedi_pci_auto_unconfig(dev); } -static struct pci_driver driver_ni_65xx_pci_driver = { +static struct pci_driver ni_65xx_pci_driver = { + .name = "ni_65xx", .id_table = ni_65xx_pci_table, - .probe = &driver_ni_65xx_pci_probe, - .remove = __devexit_p(&driver_ni_65xx_pci_remove) + .probe = ni_65xx_pci_probe, + .remove = __devexit_p(ni_65xx_pci_remove) }; - -static int __init driver_ni_65xx_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_ni_65xx); - if (retval < 0) - return retval; - - driver_ni_65xx_pci_driver.name = (char *)driver_ni_65xx.driver_name; - return pci_register_driver(&driver_ni_65xx_pci_driver); -} - -static void __exit driver_ni_65xx_cleanup_module(void) -{ - pci_unregister_driver(&driver_ni_65xx_pci_driver); - comedi_driver_unregister(&driver_ni_65xx); -} - -module_init(driver_ni_65xx_init_module); -module_exit(driver_ni_65xx_cleanup_module); +module_comedi_pci_driver(ni_65xx_driver, ni_65xx_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/ni_660x.c b/drivers/staging/comedi/drivers/ni_660x.c index 5e863ff343dd..df2f3b0bab48 100644 --- a/drivers/staging/comedi/drivers/ni_660x.c +++ b/drivers/staging/comedi/drivers/ni_660x.c @@ -448,68 +448,46 @@ static inline struct ni_660x_private *private(struct comedi_device *dev) return dev->private; } -/* initialized in ni_660x_find_device() */ +/* initialized in ni_660x_attach_pci() */ static inline const struct ni_660x_board *board(struct comedi_device *dev) { return dev->board_ptr; } -#define n_ni_660x_boards ARRAY_SIZE(ni_660x_boards) - -static int ni_660x_attach(struct comedi_device *dev, - struct comedi_devconfig *it); +static int ni_660x_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev); static void ni_660x_detach(struct comedi_device *dev); static void init_tio_chip(struct comedi_device *dev, int chipset); static void ni_660x_select_pfi_output(struct comedi_device *dev, unsigned pfi_channel, unsigned output_select); -static struct comedi_driver driver_ni_660x = { +static struct comedi_driver ni_660x_driver = { .driver_name = "ni_660x", .module = THIS_MODULE, - .attach = ni_660x_attach, + .attach_pci = ni_660x_attach_pci, .detach = ni_660x_detach, }; -static int __devinit driver_ni_660x_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +static int __devinit ni_660x_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, &driver_ni_660x); + return comedi_pci_auto_config(dev, &ni_660x_driver); } -static void __devexit driver_ni_660x_pci_remove(struct pci_dev *dev) +static void __devexit ni_660x_pci_remove(struct pci_dev *dev) { comedi_pci_auto_unconfig(dev); } -static struct pci_driver driver_ni_660x_pci_driver = { +static struct pci_driver ni_660x_pci_driver = { + .name = "ni_660x", .id_table = ni_660x_pci_table, - .probe = &driver_ni_660x_pci_probe, - .remove = __devexit_p(&driver_ni_660x_pci_remove) + .probe = ni_660x_pci_probe, + .remove = __devexit_p(ni_660x_pci_remove) }; +module_comedi_pci_driver(ni_660x_driver, ni_660x_pci_driver); -static int __init driver_ni_660x_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_ni_660x); - if (retval < 0) - return retval; - - driver_ni_660x_pci_driver.name = (char *)driver_ni_660x.driver_name; - return pci_register_driver(&driver_ni_660x_pci_driver); -} - -static void __exit driver_ni_660x_cleanup_module(void) -{ - pci_unregister_driver(&driver_ni_660x_pci_driver); - comedi_driver_unregister(&driver_ni_660x); -} - -module_init(driver_ni_660x_init_module); -module_exit(driver_ni_660x_cleanup_module); - -static int ni_660x_find_device(struct comedi_device *dev, int bus, int slot); static int ni_660x_set_pfi_routing(struct comedi_device *dev, unsigned chan, unsigned source); @@ -748,8 +726,6 @@ static enum NI_660x_Register ni_gpct_to_660x_register(enum ni_gpct_register reg) ni_660x_register = G3InterruptEnable; break; default: - printk(KERN_WARNING "%s: unhandled register 0x%x in switch.\n", - __func__, reg); BUG(); return 0; break; @@ -773,8 +749,6 @@ static inline void ni_660x_write_register(struct comedi_device *dev, writel(bits, write_address); break; default: - printk(KERN_WARNING "%s: %s: bug! unhandled case (reg=0x%x) in switch.\n", - __FILE__, __func__, reg); BUG(); break; } @@ -796,8 +770,6 @@ static inline unsigned ni_660x_read_register(struct comedi_device *dev, return readl(read_address); break; default: - printk(KERN_WARNING "%s: %s: bug! unhandled case (reg=0x%x) in switch.\n", - __FILE__, __func__, reg); BUG(); break; } @@ -893,8 +865,8 @@ static int ni_660x_request_mite_channel(struct comedi_device *dev, return 0; } -void ni_660x_release_mite_channel(struct comedi_device *dev, - struct ni_gpct *counter) +static void ni_660x_release_mite_channel(struct comedi_device *dev, + struct ni_gpct *counter) { unsigned long flags; @@ -985,7 +957,7 @@ static irqreturn_t ni_660x_interrupt(int irq, void *d) spin_lock_irqsave(&private(dev)->interrupt_lock, flags); smp_mb(); for (i = 0; i < ni_660x_num_counters(dev); ++i) { - s = dev->subdevices + NI_660X_GPCT_SUBDEV(i); + s = &dev->subdevices[NI_660X_GPCT_SUBDEV(i)]; ni_660x_handle_gpct_interrupt(dev, s); } spin_unlock_irqrestore(&private(dev)->interrupt_lock, flags); @@ -1062,28 +1034,43 @@ static void ni_660x_free_mite_rings(struct comedi_device *dev) } } -static int ni_660x_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static const struct ni_660x_board * +ni_660x_find_boardinfo(struct pci_dev *pcidev) +{ + unsigned int dev_id = pcidev->device; + unsigned int n; + + for (n = 0; n < ARRAY_SIZE(ni_660x_boards); n++) { + const struct ni_660x_board *board = &ni_660x_boards[n]; + if (board->dev_id == dev_id) + return board; + } + return NULL; +} + +static int __devinit ni_660x_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) { struct comedi_subdevice *s; int ret; unsigned i; unsigned global_interrupt_config_bits; - printk(KERN_INFO "comedi%d: ni_660x: ", dev->minor); - ret = ni_660x_allocate_private(dev); if (ret < 0) return ret; - ret = ni_660x_find_device(dev, it->options[0], it->options[1]); - if (ret < 0) - return ret; + dev->board_ptr = ni_660x_find_boardinfo(pcidev); + if (!dev->board_ptr) + return -ENODEV; + private(dev)->mite = mite_alloc(pcidev); + if (!private(dev)->mite) + return -ENOMEM; dev->board_name = board(dev)->name; ret = mite_setup2(private(dev)->mite, 1); if (ret < 0) { - printk(KERN_WARNING "error setting up mite\n"); + dev_warn(dev->class_dev, "error setting up mite\n"); return ret; } comedi_set_hw_dev(dev, &private(dev)->mite->pcidev->dev); @@ -1091,17 +1078,15 @@ static int ni_660x_attach(struct comedi_device *dev, if (ret < 0) return ret; - printk(KERN_INFO " %s ", dev->board_name); - ret = comedi_alloc_subdevices(dev, 2 + NI_660X_MAX_NUM_COUNTERS); if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* Old GENERAL-PURPOSE COUNTER/TIME (GPCT) subdevice, no longer used */ s->type = COMEDI_SUBD_UNUSED; - s = dev->subdevices + NI_660X_DIO_SUBDEV; + s = &dev->subdevices[NI_660X_DIO_SUBDEV]; /* DIGITAL I/O SUBDEVICE */ s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; @@ -1124,7 +1109,7 @@ static int ni_660x_attach(struct comedi_device *dev, if (private(dev)->counter_dev == NULL) return -ENOMEM; for (i = 0; i < NI_660X_MAX_NUM_COUNTERS; ++i) { - s = dev->subdevices + NI_660X_GPCT_SUBDEV(i); + s = &dev->subdevices[NI_660X_GPCT_SUBDEV(i)]; if (i < ni_660x_num_counters(dev)) { s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = @@ -1174,7 +1159,7 @@ static int ni_660x_attach(struct comedi_device *dev, ret = request_irq(mite_irq(private(dev)->mite), ni_660x_interrupt, IRQF_SHARED, "ni_660x", dev); if (ret < 0) { - printk(KERN_WARNING " irq not available\n"); + dev_warn(dev->class_dev, " irq not available\n"); return ret; } dev->irq = mite_irq(private(dev)->mite); @@ -1183,7 +1168,7 @@ static int ni_660x_attach(struct comedi_device *dev, global_interrupt_config_bits |= Cascade_Int_Enable_Bit; ni_660x_write_register(dev, 0, global_interrupt_config_bits, GlobalInterruptConfigRegister); - printk(KERN_INFO "attached\n"); + dev_info(dev->class_dev, "ni_660x: %s attached\n", dev->board_name); return 0; } @@ -1197,6 +1182,7 @@ static void ni_660x_detach(struct comedi_device *dev) if (private(dev)->mite) { ni_660x_free_mite_rings(dev); mite_unsetup(private(dev)->mite); + mite_free(private(dev)->mite); } } } @@ -1240,33 +1226,6 @@ static int ni_660x_GPCT_winsn(struct comedi_device *dev, return ni_tio_winsn(subdev_to_counter(s), insn, data); } -static int ni_660x_find_device(struct comedi_device *dev, int bus, int slot) -{ - struct mite_struct *mite; - int i; - - for (mite = mite_devices; mite; mite = mite->next) { - if (mite->used) - continue; - if (bus || slot) { - if (bus != mite->pcidev->bus->number || - slot != PCI_SLOT(mite->pcidev->devfn)) - continue; - } - - for (i = 0; i < n_ni_660x_boards; i++) { - if (mite_device_id(mite) == ni_660x_boards[i].dev_id) { - dev->board_ptr = ni_660x_boards + i; - private(dev)->mite = mite; - return 0; - } - } - } - printk(KERN_WARNING "no device found\n"); - mite_list_devices(); - return -EIO; -} - static int ni_660x_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) diff --git a/drivers/staging/comedi/drivers/ni_670x.c b/drivers/staging/comedi/drivers/ni_670x.c index 9c57618f2c5b..eac6dc047bb0 100644 --- a/drivers/staging/comedi/drivers/ni_670x.c +++ b/drivers/staging/comedi/drivers/ni_670x.c @@ -187,37 +187,22 @@ static int ni_670x_dio_insn_config(struct comedi_device *dev, return insn->n; } -static int ni_670x_find_device(struct comedi_device *dev, int bus, int slot) +static const struct ni_670x_board * +ni_670x_find_boardinfo(struct pci_dev *pcidev) { - struct ni_670x_private *devpriv = dev->private; - struct mite_struct *mite; - int i; - - for (mite = mite_devices; mite; mite = mite->next) { - if (mite->used) - continue; - if (bus || slot) { - if (bus != mite->pcidev->bus->number - || slot != PCI_SLOT(mite->pcidev->devfn)) - continue; - } - - for (i = 0; i < ARRAY_SIZE(ni_670x_boards); i++) { - if (mite_device_id(mite) == ni_670x_boards[i].dev_id) { - dev->board_ptr = ni_670x_boards + i; - devpriv->mite = mite; + unsigned int dev_id = pcidev->device; + unsigned int n; - return 0; - } - } + for (n = 0; n < ARRAY_SIZE(ni_670x_boards); n++) { + const struct ni_670x_board *board = &ni_670x_boards[n]; + if (board->dev_id == dev_id) + return board; } - dev_warn(dev->class_dev, "no device found\n"); - mite_list_devices(); - return -EIO; + return NULL; } -static int ni_670x_attach(struct comedi_device *dev, - struct comedi_devconfig *it) +static int __devinit ni_670x_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) { const struct ni_670x_board *thisboard; struct ni_670x_private *devpriv; @@ -229,10 +214,12 @@ static int ni_670x_attach(struct comedi_device *dev, if (ret < 0) return ret; devpriv = dev->private; - - ret = ni_670x_find_device(dev, it->options[0], it->options[1]); - if (ret < 0) - return ret; + dev->board_ptr = ni_670x_find_boardinfo(pcidev); + if (!dev->board_ptr) + return -ENODEV; + devpriv->mite = mite_alloc(pcidev); + if (!devpriv->mite) + return -ENOMEM; thisboard = comedi_board(dev); ret = mite_setup(devpriv->mite); @@ -241,13 +228,12 @@ static int ni_670x_attach(struct comedi_device *dev, return ret; } dev->board_name = thisboard->name; - dev->irq = mite_irq(devpriv->mite); ret = comedi_alloc_subdevices(dev, 2); if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* analog output subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; @@ -271,7 +257,7 @@ static int ni_670x_attach(struct comedi_device *dev, s->insn_write = &ni_670x_ao_winsn; s->insn_read = &ni_670x_ao_rinsn; - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* digital i/o subdevice */ s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; @@ -298,20 +284,20 @@ static void ni_670x_detach(struct comedi_device *dev) struct comedi_subdevice *s; if (dev->n_subdevices) { - s = dev->subdevices + 0; + s = &dev->subdevices[0]; if (s) kfree(s->range_table_list); } - if (devpriv && devpriv->mite) + if (devpriv && devpriv->mite) { mite_unsetup(devpriv->mite); - if (dev->irq) - free_irq(dev->irq, dev); + mite_free(devpriv->mite); + } } static struct comedi_driver ni_670x_driver = { .driver_name = "ni_670x", .module = THIS_MODULE, - .attach = ni_670x_attach, + .attach_pci = ni_670x_attach_pci, .detach = ni_670x_detach, }; diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c index b53a4286f8cb..83950807b672 100644 --- a/drivers/staging/comedi/drivers/ni_at_a2150.c +++ b/drivers/staging/comedi/drivers/ni_at_a2150.c @@ -321,45 +321,23 @@ static int a2150_ai_cmdtest(struct comedi_device *dev, int startChan; int i; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* - * step 2: make sure trigger sources are unique and mutually - * compatible - */ + /* Step 2a : make sure trigger sources are unique */ - if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -832,7 +810,7 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it) return ret; /* analog input subdevice */ - s = dev->subdevices + 0; + s = &dev->subdevices[0]; dev->read_subdev = s; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_OTHER | SDF_CMD_READ; diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c index 62c8c44a8d28..93938cec93e7 100644 --- a/drivers/staging/comedi/drivers/ni_at_ao.c +++ b/drivers/staging/comedi/drivers/ni_at_ao.c @@ -358,7 +358,7 @@ static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* analog output subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; @@ -371,7 +371,7 @@ static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_write = &atao_ao_winsn; s->insn_read = &atao_ao_rinsn; - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* digital i/o subdevice */ s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; @@ -381,7 +381,7 @@ static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_bits = atao_dio_insn_bits; s->insn_config = atao_dio_insn_config; - s = dev->subdevices + 2; + s = &dev->subdevices[2]; /* caldac subdevice */ s->type = COMEDI_SUBD_CALIB; s->subdev_flags = SDF_WRITABLE | SDF_INTERNAL; @@ -390,7 +390,7 @@ static int atao_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_read = atao_calib_insn_read; s->insn_write = atao_calib_insn_write; - s = dev->subdevices + 3; + s = &dev->subdevices[3]; /* eeprom subdevice */ /* s->type=COMEDI_SUBD_EEPROM; */ s->type = COMEDI_SUBD_UNUSED; diff --git a/drivers/staging/comedi/drivers/ni_atmio.c b/drivers/staging/comedi/drivers/ni_atmio.c index 6448373878ed..cac25572f6bb 100644 --- a/drivers/staging/comedi/drivers/ni_atmio.c +++ b/drivers/staging/comedi/drivers/ni_atmio.c @@ -489,7 +489,7 @@ static int ni_atmio_attach(struct comedi_device *dev, /* generic E series stuff in ni_mio_common.c */ - ret = ni_E_init(dev, it); + ret = ni_E_init(dev); if (ret < 0) return ret; diff --git a/drivers/staging/comedi/drivers/ni_atmio16d.c b/drivers/staging/comedi/drivers/ni_atmio16d.c index 2c78d3dd242a..e91a620f9db3 100644 --- a/drivers/staging/comedi/drivers/ni_atmio16d.c +++ b/drivers/staging/comedi/drivers/ni_atmio16d.c @@ -40,6 +40,7 @@ Devices: [National Instruments] AT-MIO-16 (atmio16), AT-MIO-16D (atmio16d) #include <linux/ioport.h> +#include "comedi_fc.h" #include "8255.h" /* Configuration and Status Registers */ @@ -234,7 +235,7 @@ static void reset_atmio16d(struct comedi_device *dev) static irqreturn_t atmio16d_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; + struct comedi_subdevice *s = &dev->subdevices[0]; comedi_buf_put(s->async, inw(dev->iobase + AD_FIFO_REG)); @@ -246,45 +247,26 @@ static int atmio16d_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - int err = 0, tmp; + int err = 0; - /* make sure triggers are valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_TIMER; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_FOLLOW | TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique & mutually compatible */ - /* note that mutual compatibility is not an issue here */ - if (cmd->scan_begin_src != TRIG_FOLLOW && - cmd->scan_begin_src != TRIG_EXT && - cmd->scan_begin_src != TRIG_TIMER) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -724,7 +706,7 @@ static int atmio16d_attach(struct comedi_device *dev, devpriv->dac1_coding = it->options[12]; /* setup sub-devices */ - s = dev->subdevices + 0; + s = &dev->subdevices[0]; dev->read_subdev = s; /* ai subdevice */ s->type = COMEDI_SUBD_AI; @@ -749,7 +731,7 @@ static int atmio16d_attach(struct comedi_device *dev, } /* ao subdevice */ - s++; + s = &dev->subdevices[1]; s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; s->n_chan = 2; @@ -775,7 +757,7 @@ static int atmio16d_attach(struct comedi_device *dev, } /* Digital I/O */ - s++; + s = &dev->subdevices[2]; s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_WRITABLE | SDF_READABLE; s->n_chan = 8; @@ -785,7 +767,7 @@ static int atmio16d_attach(struct comedi_device *dev, s->range_table = &range_digital; /* 8255 subdevice */ - s++; + s = &dev->subdevices[3]; if (board->has_8255) subdev_8255_init(dev, s, NULL, dev->iobase); else @@ -793,7 +775,7 @@ static int atmio16d_attach(struct comedi_device *dev, /* don't yet know how to deal with counter/timers */ #if 0 - s++; + s = &dev->subdevices[4]; /* do */ s->type = COMEDI_SUBD_TIMER; s->n_chan = 0; @@ -807,9 +789,12 @@ static int atmio16d_attach(struct comedi_device *dev, static void atmio16d_detach(struct comedi_device *dev) { const struct atmio16_board_t *board = comedi_board(dev); + struct comedi_subdevice *s; - if (dev->subdevices && board->has_8255) - subdev_8255_cleanup(dev, dev->subdevices + 3); + if (dev->subdevices && board->has_8255) { + s = &dev->subdevices[3]; + subdev_8255_cleanup(dev, s); + } if (dev->irq) free_irq(dev->irq, dev); reset_atmio16d(dev); diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c index 83016b411851..2ba0ade45c64 100644 --- a/drivers/staging/comedi/drivers/ni_daq_700.c +++ b/drivers/staging/comedi/drivers/ni_daq_700.c @@ -1,6 +1,6 @@ /* * comedi/drivers/ni_daq_700.c - * Driver for DAQCard-700 DIO only + * Driver for DAQCard-700 DIO/AI * copied from 8255 * * COMEDI - Linux Control and Measurement Device Interface @@ -29,14 +29,25 @@ Author: Fred Brooks <nsaspook@nsaspook.com>, based on ni_daq_dio24 by Daniel Vecino Castel <dvecino@able.es> Devices: [National Instruments] PCMCIA DAQ-Card-700 (ni_daq_700) Status: works -Updated: Thu, 21 Feb 2008 12:07:20 +0000 +Updated: Wed, 19 Sep 2012 12:07:20 +0000 -The daqcard-700 appears in Comedi as a single digital I/O subdevice with -16 channels. The channel 0 corresponds to the daqcard-700's output +The daqcard-700 appears in Comedi as a digital I/O subdevice (0) with +16 channels and a analog input subdevice (1) with 16 single-ended channels. + +Digital: The channel 0 corresponds to the daqcard-700's output port, bit 0; channel 8 corresponds to the input port, bit 0. -Direction configuration: channels 0-7 output, 8-15 input (8225 device +Digital direction configuration: channels 0-7 output, 8-15 input (8225 device emu as port A output, port B input, port C N/A). + +Analog: The input range is 0 to 4095 for -10 to +10 volts +IRQ is assigned but not used. + +Version 0.1 Original DIO only driver +Version 0.2 DIO and basic AI analog input support on 16 se channels + +Manuals: Register level: http://www.ni.com/pdf/manuals/340698.pdf + User Manual: http://www.ni.com/pdf/manuals/320676d.pdf */ #include <linux/interrupt.h> @@ -51,16 +62,29 @@ emu as port A output, port B input, port C N/A). static struct pcmcia_device *pcmcia_cur_dev; -struct dio700_board { +struct daq700_board { const char *name; }; -#define DIO_W 0x04 -#define DIO_R 0x05 - -static int subdev_700_insn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, - unsigned int *data) +/* daqcard700 registers */ +#define DIO_W 0x04 /* WO 8bit */ +#define DIO_R 0x05 /* RO 8bit */ +#define CMD_R1 0x00 /* WO 8bit */ +#define CMD_R2 0x07 /* RW 8bit */ +#define CMD_R3 0x05 /* W0 8bit */ +#define STA_R1 0x00 /* RO 8bit */ +#define STA_R2 0x01 /* RO 8bit */ +#define ADFIFO_R 0x02 /* RO 16bit */ +#define ADCLEAR_R 0x01 /* WO 8bit */ +#define CDA_R0 0x08 /* RW 8bit */ +#define CDA_R1 0x09 /* RW 8bit */ +#define CDA_R2 0x0A /* RW 8bit */ +#define CMO_R 0x0B /* RO 8bit */ +#define TIC_R 0x06 /* WO 8bit */ + +static int daq700_dio_insn_bits(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { if (data[0]) { s->state &= ~data[0]; @@ -76,7 +100,7 @@ static int subdev_700_insn(struct comedi_device *dev, return insn->n; } -static int subdev_700_insn_config(struct comedi_device *dev, +static int daq700_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { @@ -97,9 +121,90 @@ static int subdev_700_insn_config(struct comedi_device *dev, return insn->n; } -static int dio700_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int daq700_ai_rinsn(struct comedi_device *dev, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - const struct dio700_board *thisboard = comedi_board(dev); + int n, i, chan; + int d; + unsigned int status; + enum { TIMEOUT = 100 }; + + chan = CR_CHAN(insn->chanspec); + /* write channel to multiplexer */ + /* set mask scan bit high to disable scanning */ + outb(chan | 0x80, dev->iobase + CMD_R1); + + /* convert n samples */ + for (n = 0; n < insn->n; n++) { + /* trigger conversion with out0 L to H */ + outb(0x00, dev->iobase + CMD_R2); /* enable ADC conversions */ + outb(0x30, dev->iobase + CMO_R); /* mode 0 out0 L, from H */ + /* mode 1 out0 H, L to H, start conversion */ + outb(0x32, dev->iobase + CMO_R); + /* wait for conversion to end */ + for (i = 0; i < TIMEOUT; i++) { + status = inb(dev->iobase + STA_R2); + if ((status & 0x03) != 0) { + dev_info(dev->class_dev, + "Overflow/run Error\n"); + return -EOVERFLOW; + } + status = inb(dev->iobase + STA_R1); + if ((status & 0x02) != 0) { + dev_info(dev->class_dev, "Data Error\n"); + return -ENODATA; + } + if ((status & 0x11) == 0x01) { + /* ADC conversion complete */ + break; + } + udelay(1); + } + if (i == TIMEOUT) { + dev_info(dev->class_dev, + "timeout during ADC conversion\n"); + return -ETIMEDOUT; + } + /* read data */ + d = inw(dev->iobase + ADFIFO_R); + /* mangle the data as necessary */ + /* Bipolar Offset Binary: 0 to 4095 for -10 to +10 */ + d &= 0x0fff; + d ^= 0x0800; + data[n] = d; + } + return n; +} + +/* + * Data acquisition is enabled. + * The counter 0 output is high. + * The I/O connector pin CLK1 drives counter 1 source. + * Multiple-channel scanning is disabled. + * All interrupts are disabled. + * The analog input range is set to +-10 V + * The analog input mode is single-ended. + * The analog input circuitry is initialized to channel 0. + * The A/D FIFO is cleared. + */ +static void daq700_ai_config(struct comedi_device *dev, + struct comedi_subdevice *s) +{ + unsigned long iobase = dev->iobase; + + outb(0x80, iobase + CMD_R1); /* disable scanning, ADC to chan 0 */ + outb(0x00, iobase + CMD_R2); /* clear all bits */ + outb(0x00, iobase + CMD_R3); /* set +-10 range */ + outb(0x32, iobase + CMO_R); /* config counter mode1, out0 to H */ + outb(0x00, iobase + TIC_R); /* clear counter interrupt */ + outb(0x00, iobase + ADCLEAR_R); /* clear the ADC FIFO */ + inw(iobase + ADFIFO_R); /* read 16bit junk from FIFO to clear */ +} + +static int daq700_attach(struct comedi_device *dev, struct comedi_devconfig *it) +{ + const struct daq700_board *thisboard = comedi_board(dev); struct comedi_subdevice *s; struct pcmcia_device *link; int ret; @@ -116,23 +221,33 @@ static int dio700_attach(struct comedi_device *dev, struct comedi_devconfig *it) dev->board_name = thisboard->name; - ret = comedi_alloc_subdevices(dev, 1); + ret = comedi_alloc_subdevices(dev, 2); if (ret) return ret; /* DAQCard-700 dio */ - s = dev->subdevices + 0; + s = &dev->subdevices[0]; s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = 16; s->range_table = &range_digital; s->maxdata = 1; - s->insn_bits = subdev_700_insn; - s->insn_config = subdev_700_insn_config; - + s->insn_bits = daq700_dio_insn_bits; + s->insn_config = daq700_dio_insn_config; s->state = 0; s->io_bits = 0x00ff; + /* DAQCard-700 ai */ + s = &dev->subdevices[1]; + s->type = COMEDI_SUBD_AI; + /* we support single-ended (ground) */ + s->subdev_flags = SDF_READABLE | SDF_GROUND; + s->n_chan = 16; + s->maxdata = (1 << 12) - 1; + s->range_table = &range_bipolar10; + s->insn_read = daq700_ai_rinsn; + daq700_ai_config(dev, s); + dev_info(dev->class_dev, "%s: %s, io 0x%lx\n", dev->driver->driver_name, dev->board_name, @@ -141,12 +256,12 @@ static int dio700_attach(struct comedi_device *dev, struct comedi_devconfig *it) return 0; } -static void dio700_detach(struct comedi_device *dev) +static void daq700_detach(struct comedi_device *dev) { /* nothing to cleanup */ } -static const struct dio700_board dio700_boards[] = { +static const struct daq700_board daq700_boards[] = { { .name = "daqcard-700", }, { @@ -154,17 +269,17 @@ static const struct dio700_board dio700_boards[] = { }, }; -static struct comedi_driver driver_dio700 = { +static struct comedi_driver daq700_driver = { .driver_name = "ni_daq_700", .module = THIS_MODULE, - .attach = dio700_attach, - .detach = dio700_detach, - .board_name = &dio700_boards[0].name, - .num_names = ARRAY_SIZE(dio700_boards), - .offset = sizeof(struct dio700_board), + .attach = daq700_attach, + .detach = daq700_detach, + .board_name = &daq700_boards[0].name, + .num_names = ARRAY_SIZE(daq700_boards), + .offset = sizeof(struct daq700_board), }; -static int dio700_pcmcia_config_loop(struct pcmcia_device *p_dev, +static int daq700_pcmcia_config_loop(struct pcmcia_device *p_dev, void *priv_data) { if (p_dev->config_index == 0) @@ -173,14 +288,14 @@ static int dio700_pcmcia_config_loop(struct pcmcia_device *p_dev, return pcmcia_request_io(p_dev); } -static int dio700_cs_attach(struct pcmcia_device *link) +static int daq700_cs_attach(struct pcmcia_device *link) { int ret; link->config_flags |= CONF_ENABLE_IRQ | CONF_AUTO_AUDIO | CONF_AUTO_SET_IO; - ret = pcmcia_loop_config(link, dio700_pcmcia_config_loop, NULL); + ret = pcmcia_loop_config(link, daq700_pcmcia_config_loop, NULL); if (ret) goto failed; @@ -199,52 +314,53 @@ failed: return ret; } -static void dio700_cs_detach(struct pcmcia_device *link) +static void daq700_cs_detach(struct pcmcia_device *link) { pcmcia_disable_device(link); pcmcia_cur_dev = NULL; } -static const struct pcmcia_device_id dio700_cs_ids[] = { +static const struct pcmcia_device_id daq700_cs_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x010b, 0x4743), PCMCIA_DEVICE_NULL }; -MODULE_DEVICE_TABLE(pcmcia, dio700_cs_ids); +MODULE_DEVICE_TABLE(pcmcia, daq700_cs_ids); -static struct pcmcia_driver dio700_cs_driver = { +static struct pcmcia_driver daq700_cs_driver = { .name = "ni_daq_700", .owner = THIS_MODULE, - .probe = dio700_cs_attach, - .remove = dio700_cs_detach, - .id_table = dio700_cs_ids, + .probe = daq700_cs_attach, + .remove = daq700_cs_detach, + .id_table = daq700_cs_ids, }; -static int __init dio700_cs_init(void) +static int __init daq700_cs_init(void) { int ret; - ret = comedi_driver_register(&driver_dio700); + ret = comedi_driver_register(&daq700_driver); if (ret < 0) return ret; - ret = pcmcia_register_driver(&dio700_cs_driver); + ret = pcmcia_register_driver(&daq700_cs_driver); if (ret < 0) { - comedi_driver_unregister(&driver_dio700); + comedi_driver_unregister(&daq700_driver); return ret; } return 0; } -module_init(dio700_cs_init); +module_init(daq700_cs_init); -static void __exit dio700_cs_exit(void) +static void __exit daq700_cs_exit(void) { - pcmcia_unregister_driver(&dio700_cs_driver); - comedi_driver_unregister(&driver_dio700); + pcmcia_unregister_driver(&daq700_cs_driver); + comedi_driver_unregister(&daq700_driver); } -module_exit(dio700_cs_exit); +module_exit(daq700_cs_exit); MODULE_AUTHOR("Fred Brooks <nsaspook@nsaspook.com>"); MODULE_DESCRIPTION( - "Comedi driver for National Instruments PCMCIA DAQCard-700 DIO"); + "Comedi driver for National Instruments PCMCIA DAQCard-700 DIO/AI"); +MODULE_VERSION("0.2.00"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c index e27cae0eb8a2..0ca222bbcbe6 100644 --- a/drivers/staging/comedi/drivers/ni_daq_dio24.c +++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c @@ -164,7 +164,7 @@ static int dio24_attach(struct comedi_device *dev, struct comedi_devconfig *it) return ret; /* 8255 dio */ - s = dev->subdevices + 0; + s = &dev->subdevices[0]; subdev_8255_init(dev, s, NULL, dev->iobase); return 0; @@ -172,8 +172,12 @@ static int dio24_attach(struct comedi_device *dev, struct comedi_devconfig *it) static void dio24_detach(struct comedi_device *dev) { - if (dev->subdevices) - subdev_8255_cleanup(dev, dev->subdevices + 0); + struct comedi_subdevice *s; + + if (dev->subdevices) { + s = &dev->subdevices[0]; + subdev_8255_cleanup(dev, s); + } if (thisboard->bustype != pcmcia_bustype && dev->iobase) release_region(dev->iobase, DIO24_SIZE); if (dev->irq) @@ -304,7 +308,7 @@ MODULE_DESCRIPTION("Comedi driver for National Instruments " "PCMCIA DAQ-Card DIO-24"); MODULE_LICENSE("GPL"); -struct pcmcia_driver dio24_cs_driver = { +static struct pcmcia_driver dio24_cs_driver = { .probe = dio24_cs_attach, .remove = dio24_cs_detach, .suspend = dio24_cs_suspend, diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c index ab8b787c78bb..28b91a6c3789 100644 --- a/drivers/staging/comedi/drivers/ni_labpc.c +++ b/drivers/staging/comedi/drivers/ni_labpc.c @@ -73,9 +73,6 @@ NI manuals: */ -#undef LABPC_DEBUG -/* #define LABPC_DEBUG enable debugging messages */ - #include <linux/interrupt.h> #include <linux/slab.h> #include <linux/io.h> @@ -209,7 +206,13 @@ NI manuals: #define INIT_A1_BITS 0x70 #define COUNTER_B_BASE_REG 0x18 -static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it); +enum scan_mode { + MODE_SINGLE_CHAN, + MODE_SINGLE_CHAN_INTERVAL, + MODE_MULT_CHAN_UP, + MODE_MULT_CHAN_DOWN, +}; + static int labpc_cancel(struct comedi_device *dev, struct comedi_subdevice *s); static irqreturn_t labpc_interrupt(int irq, void *d); static int labpc_drain_fifo(struct comedi_device *dev); @@ -240,12 +243,10 @@ static int labpc_eeprom_write_insn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data); -static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd); +static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd, + enum scan_mode scan_mode); #ifdef CONFIG_ISA_DMA_API -static unsigned int labpc_suggest_transfer_size(struct comedi_cmd cmd); -#endif -#ifdef CONFIG_COMEDI_PCI_DRIVERS -static int labpc_find_device(struct comedi_device *dev, int bus, int slot); +static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd); #endif static int labpc_dio_mem_callback(int dir, int port, int data, unsigned long arg); @@ -261,13 +262,6 @@ static int labpc_eeprom_write(struct comedi_device *dev, static void write_caldac(struct comedi_device *dev, unsigned int channel, unsigned int value); -enum scan_mode { - MODE_SINGLE_CHAN, - MODE_SINGLE_CHAN_INTERVAL, - MODE_MULT_CHAN_UP, - MODE_MULT_CHAN_DOWN, -}; - /* analog input ranges */ #define NUM_LABPC_PLUS_AI_RANGES 16 /* indicates unipolar ranges */ @@ -416,12 +410,12 @@ static inline void labpc_outb(unsigned int byte, unsigned long address) static inline unsigned int labpc_readb(unsigned long address) { - return readb((void *)address); + return readb((void __iomem *)address); } static inline void labpc_writeb(unsigned int byte, unsigned long address) { - writeb(byte, (void *)address); + writeb(byte, (void __iomem *)address); } static const struct labpc_board_struct labpc_boards[] = { @@ -495,33 +489,14 @@ static const int sample_size = 2; #define devpriv ((struct labpc_private *)dev->private) -static struct comedi_driver driver_labpc = { - .driver_name = DRV_NAME, - .module = THIS_MODULE, - .attach = labpc_attach, - .detach = labpc_common_detach, - .num_names = ARRAY_SIZE(labpc_boards), - .board_name = &labpc_boards[0].name, - .offset = sizeof(struct labpc_board_struct), -}; - -#ifdef CONFIG_COMEDI_PCI_DRIVERS -static DEFINE_PCI_DEVICE_TABLE(labpc_pci_table) = { - {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x161)}, - {0} -}; - -MODULE_DEVICE_TABLE(pci, labpc_pci_table); -#endif /* CONFIG_COMEDI_PCI_DRIVERS */ - static inline int labpc_counter_load(struct comedi_device *dev, unsigned long base_address, unsigned int counter_number, unsigned int count, unsigned int mode) { if (thisboard->memory_mapped_io) - return i8254_mm_load((void *)base_address, 0, counter_number, - count, mode); + return i8254_mm_load((void __iomem *)base_address, 0, + counter_number, count, mode); else return i8254_load(base_address, 0, counter_number, count, mode); } @@ -538,25 +513,16 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase, short lsb, msb; int ret; - printk(KERN_ERR "comedi%d: ni_labpc: %s, io 0x%lx", dev->minor, - thisboard->name, - iobase); - if (irq) - printk(", irq %u", irq); - if (dma_chan) - printk(", dma %u", dma_chan); - printk("\n"); - + dev_info(dev->class_dev, "ni_labpc: %s\n", thisboard->name); if (iobase == 0) { - printk(KERN_ERR "io base address is zero!\n"); + dev_err(dev->class_dev, "io base address is zero!\n"); return -EINVAL; } /* request io regions for isa boards */ if (thisboard->bustype == isa_bustype) { /* check if io addresses are available */ - if (!request_region(iobase, LABPC_SIZE, - driver_labpc.driver_name)) { - printk(KERN_ERR "I/O port conflict\n"); + if (!request_region(iobase, LABPC_SIZE, DRV_NAME)) { + dev_err(dev->class_dev, "I/O port conflict\n"); return -EIO; } } @@ -588,8 +554,9 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase, || thisboard->bustype == pcmcia_bustype) isr_flags |= IRQF_SHARED; if (request_irq(irq, labpc_interrupt, isr_flags, - driver_labpc.driver_name, dev)) { - printk(KERN_ERR "unable to allocate irq %u\n", irq); + DRV_NAME, dev)) { + dev_err(dev->class_dev, "unable to allocate irq %u\n", + irq); return -EINVAL; } } @@ -598,19 +565,21 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase, #ifdef CONFIG_ISA_DMA_API /* grab dma channel */ if (dma_chan > 3) { - printk(KERN_ERR " invalid dma channel %u\n", dma_chan); + dev_err(dev->class_dev, "invalid dma channel %u\n", dma_chan); return -EINVAL; } else if (dma_chan) { /* allocate dma buffer */ devpriv->dma_buffer = kmalloc(dma_buffer_size, GFP_KERNEL | GFP_DMA); if (devpriv->dma_buffer == NULL) { - printk(KERN_ERR " failed to allocate dma buffer\n"); + dev_err(dev->class_dev, + "failed to allocate dma buffer\n"); return -ENOMEM; } - if (request_dma(dma_chan, driver_labpc.driver_name)) { - printk(KERN_ERR " failed to allocate dma channel %u\n", - dma_chan); + if (request_dma(dma_chan, DRV_NAME)) { + dev_err(dev->class_dev, + "failed to allocate dma channel %u\n", + dma_chan); return -EINVAL; } devpriv->dma_chan = dma_chan; @@ -628,7 +597,7 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase, return ret; /* analog input subdevice */ - s = dev->subdevices + 0; + s = &dev->subdevices[0]; dev->read_subdev = s; s->type = COMEDI_SUBD_AI; s->subdev_flags = @@ -643,7 +612,7 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase, s->cancel = labpc_cancel; /* analog output */ - s = dev->subdevices + 1; + s = &dev->subdevices[1]; if (thisboard->has_ao) { /* * Could provide command support, except it only has a @@ -670,7 +639,7 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase, } /* 8255 dio */ - s = dev->subdevices + 2; + s = &dev->subdevices[2]; /* if board uses io memory we have to give a custom callback * function to the 8255 driver */ if (thisboard->memory_mapped_io) @@ -680,7 +649,7 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase, subdev_8255_init(dev, s, NULL, dev->iobase + DIO_BASE_REG); /* calibration subdevices for boards that have one */ - s = dev->subdevices + 3; + s = &dev->subdevices[3]; if (thisboard->register_layout == labpc_1200_layout) { s->type = COMEDI_SUBD_CALIB; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; @@ -695,7 +664,7 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase, s->type = COMEDI_SUBD_UNUSED; /* EEPROM */ - s = dev->subdevices + 4; + s = &dev->subdevices[4]; if (thisboard->register_layout == labpc_1200_layout) { s->type = COMEDI_SUBD_MEMORY; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; @@ -706,12 +675,6 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase, for (i = 0; i < EEPROM_SIZE; i++) devpriv->eeprom_data[i] = labpc_eeprom_read(dev, i); -#ifdef LABPC_DEBUG - printk(KERN_ERR " eeprom:"); - for (i = 0; i < EEPROM_SIZE; i++) - printk(" %i:0x%x ", i, devpriv->eeprom_data[i]); - printk("\n"); -#endif } else s->type = COMEDI_SUBD_UNUSED; @@ -719,14 +682,52 @@ int labpc_common_attach(struct comedi_device *dev, unsigned long iobase, } EXPORT_SYMBOL_GPL(labpc_common_attach); +static const struct labpc_board_struct * +labpc_pci_find_boardinfo(struct pci_dev *pcidev) +{ + unsigned int device_id = pcidev->device; + unsigned int n; + + for (n = 0; n < ARRAY_SIZE(labpc_boards); n++) { + const struct labpc_board_struct *board = &labpc_boards[n]; + if (board->bustype == pci_bustype && + board->device_id == device_id) + return board; + } + return NULL; +} + +static int __devinit labpc_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) +{ + unsigned long iobase; + unsigned int irq; + int ret; + + if (!IS_ENABLED(CONFIG_COMEDI_PCI_DRIVERS)) + return -ENODEV; + ret = alloc_private(dev, sizeof(struct labpc_private)); + if (ret < 0) + return ret; + dev->board_ptr = labpc_pci_find_boardinfo(pcidev); + if (!dev->board_ptr) + return -ENODEV; + devpriv->mite = mite_alloc(pcidev); + if (!devpriv->mite) + return -ENOMEM; + ret = mite_setup(devpriv->mite); + if (ret < 0) + return ret; + iobase = (unsigned long)devpriv->mite->daq_io_addr; + irq = mite_irq(devpriv->mite); + return labpc_common_attach(dev, iobase, irq, 0); +} + static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it) { unsigned long iobase = 0; unsigned int irq = 0; unsigned int dma_chan = 0; -#ifdef CONFIG_COMEDI_PCI_DRIVERS - int retval; -#endif /* allocate and initialize dev->private */ if (alloc_private(dev, sizeof(struct labpc_private)) < 0) @@ -740,34 +741,26 @@ static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it) irq = it->options[1]; dma_chan = it->options[2]; #else - printk(KERN_ERR " this driver has not been built with ISA DMA " - "support.\n"); + dev_err(dev->class_dev, + "ni_labpc driver has not been built with ISA DMA support.\n"); return -EINVAL; #endif break; case pci_bustype: #ifdef CONFIG_COMEDI_PCI_DRIVERS - retval = labpc_find_device(dev, it->options[0], it->options[1]); - if (retval < 0) - return retval; - retval = mite_setup(devpriv->mite); - if (retval < 0) - return retval; - iobase = (unsigned long)devpriv->mite->daq_io_addr; - irq = mite_irq(devpriv->mite); + dev_err(dev->class_dev, + "manual configuration of PCI board '%s' is not supported\n", + thisboard->name); + return -EINVAL; #else - printk(KERN_ERR " this driver has not been built with PCI " - "support.\n"); + dev_err(dev->class_dev, + "ni_labpc driver has not been built with PCI support.\n"); return -EINVAL; #endif break; - case pcmcia_bustype: - printk - (" this driver does not support pcmcia cards, use ni_labpc_cs.o\n"); - return -EINVAL; - break; default: - printk(KERN_ERR "bug! couldn't determine board type\n"); + dev_err(dev->class_dev, + "ni_labpc: bug! couldn't determine board type\n"); return -EINVAL; break; } @@ -775,42 +768,14 @@ static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it) return labpc_common_attach(dev, iobase, irq, dma_chan); } -/* adapted from ni_pcimio for finding mite based boards (pc-1200) */ -#ifdef CONFIG_COMEDI_PCI_DRIVERS -static int labpc_find_device(struct comedi_device *dev, int bus, int slot) -{ - struct mite_struct *mite; - int i; - for (mite = mite_devices; mite; mite = mite->next) { - if (mite->used) - continue; -/* if bus/slot are specified then make sure we have the right bus/slot */ - if (bus || slot) { - if (bus != mite->pcidev->bus->number - || slot != PCI_SLOT(mite->pcidev->devfn)) - continue; - } - for (i = 0; i < driver_labpc.num_names; i++) { - if (labpc_boards[i].bustype != pci_bustype) - continue; - if (mite_device_id(mite) == labpc_boards[i].device_id) { - devpriv->mite = mite; -/* fixup board pointer, in case we were using the dummy "ni_labpc" entry */ - dev->board_ptr = &labpc_boards[i]; - return 0; - } - } - } - printk(KERN_ERR "no device found\n"); - mite_list_devices(); - return -EIO; -} -#endif - void labpc_common_detach(struct comedi_device *dev) { - if (dev->subdevices) - subdev_8255_cleanup(dev, dev->subdevices + 2); + struct comedi_subdevice *s; + + if (dev->subdevices) { + s = &dev->subdevices[2]; + subdev_8255_cleanup(dev, s); + } #ifdef CONFIG_ISA_DMA_API /* only free stuff if it has been allocated by _attach */ kfree(devpriv->dma_buffer); @@ -822,8 +787,10 @@ void labpc_common_detach(struct comedi_device *dev) if (thisboard->bustype == isa_bustype && dev->iobase) release_region(dev->iobase, LABPC_SIZE); #ifdef CONFIG_COMEDI_PCI_DRIVERS - if (devpriv->mite) + if (devpriv->mite) { mite_unsetup(devpriv->mite); + mite_free(devpriv->mite); + } #endif }; EXPORT_SYMBOL_GPL(labpc_common_detach); @@ -868,21 +835,19 @@ static enum scan_mode labpc_ai_scan_mode(const struct comedi_cmd *cmd) if (CR_CHAN(cmd->chanlist[0]) > CR_CHAN(cmd->chanlist[1])) return MODE_MULT_CHAN_DOWN; - printk(KERN_ERR "ni_labpc: bug! this should never happen\n"); - + pr_err("ni_labpc: bug! cannot determine AI scan mode\n"); return 0; } static int labpc_ai_chanlist_invalid(const struct comedi_device *dev, - const struct comedi_cmd *cmd) + const struct comedi_cmd *cmd, + enum scan_mode mode) { - int mode, channel, range, aref, i; + int channel, range, aref, i; if (cmd->chanlist == NULL) return 0; - mode = labpc_ai_scan_mode(cmd); - if (mode == MODE_SINGLE_CHAN) return 0; @@ -924,7 +889,8 @@ static int labpc_ai_chanlist_invalid(const struct comedi_device *dev, } break; default: - printk(KERN_ERR "ni_labpc: bug! in chanlist check\n"); + dev_err(dev->class_dev, + "ni_labpc: bug! in chanlist check\n"); return 1; break; } @@ -945,9 +911,10 @@ static int labpc_ai_chanlist_invalid(const struct comedi_device *dev, return 0; } -static int labpc_use_continuous_mode(const struct comedi_cmd *cmd) +static int labpc_use_continuous_mode(const struct comedi_cmd *cmd, + enum scan_mode mode) { - if (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN) + if (mode == MODE_SINGLE_CHAN) return 1; if (cmd->scan_begin_src == TRIG_FOLLOW) @@ -956,24 +923,25 @@ static int labpc_use_continuous_mode(const struct comedi_cmd *cmd) return 0; } -static unsigned int labpc_ai_convert_period(const struct comedi_cmd *cmd) +static unsigned int labpc_ai_convert_period(const struct comedi_cmd *cmd, + enum scan_mode mode) { if (cmd->convert_src != TRIG_TIMER) return 0; - if (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN && - cmd->scan_begin_src == TRIG_TIMER) + if (mode == MODE_SINGLE_CHAN && cmd->scan_begin_src == TRIG_TIMER) return cmd->scan_begin_arg; return cmd->convert_arg; } -static void labpc_set_ai_convert_period(struct comedi_cmd *cmd, unsigned int ns) +static void labpc_set_ai_convert_period(struct comedi_cmd *cmd, + enum scan_mode mode, unsigned int ns) { if (cmd->convert_src != TRIG_TIMER) return; - if (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN && + if (mode == MODE_SINGLE_CHAN && cmd->scan_begin_src == TRIG_TIMER) { cmd->scan_begin_arg = ns; if (cmd->convert_arg > cmd->scan_begin_arg) @@ -982,25 +950,25 @@ static void labpc_set_ai_convert_period(struct comedi_cmd *cmd, unsigned int ns) cmd->convert_arg = ns; } -static unsigned int labpc_ai_scan_period(const struct comedi_cmd *cmd) +static unsigned int labpc_ai_scan_period(const struct comedi_cmd *cmd, + enum scan_mode mode) { if (cmd->scan_begin_src != TRIG_TIMER) return 0; - if (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN && - cmd->convert_src == TRIG_TIMER) + if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER) return 0; return cmd->scan_begin_arg; } -static void labpc_set_ai_scan_period(struct comedi_cmd *cmd, unsigned int ns) +static void labpc_set_ai_scan_period(struct comedi_cmd *cmd, + enum scan_mode mode, unsigned int ns) { if (cmd->scan_begin_src != TRIG_TIMER) return; - if (labpc_ai_scan_mode(cmd) == MODE_SINGLE_CHAN && - cmd->convert_src == TRIG_TIMER) + if (mode == MODE_SINGLE_CHAN && cmd->convert_src == TRIG_TIMER) return; cmd->scan_begin_arg = ns; @@ -1011,54 +979,33 @@ static int labpc_ai_cmdtest(struct comedi_device *dev, { int err = 0; int tmp, tmp2; - int stop_mask; + unsigned int stop_mask; + enum scan_mode mode; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; stop_mask = TRIG_COUNT | TRIG_NONE; if (thisboard->register_layout == labpc_1200_layout) stop_mask |= TRIG_EXT; - cmd->stop_src &= stop_mask; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->stop_src, stop_mask); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ - if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_EXT) - err++; - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_FOLLOW && - cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_COUNT && - cmd->stop_src != TRIG_EXT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ /* can't have external stop and start triggers at once */ if (cmd->start_src == TRIG_EXT && cmd->stop_src == TRIG_EXT) @@ -1133,14 +1080,15 @@ static int labpc_ai_cmdtest(struct comedi_device *dev, tmp = cmd->convert_arg; tmp2 = cmd->scan_begin_arg; - labpc_adc_timing(dev, cmd); + mode = labpc_ai_scan_mode(cmd); + labpc_adc_timing(dev, cmd, mode); if (tmp != cmd->convert_arg || tmp2 != cmd->scan_begin_arg) err++; if (err) return 4; - if (labpc_ai_chanlist_invalid(dev, cmd)) + if (labpc_ai_chanlist_invalid(dev, cmd, mode)) return 5; return 0; @@ -1156,6 +1104,7 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) struct comedi_async *async = s->async; struct comedi_cmd *cmd = &async->cmd; enum transfer_type xfer; + enum scan_mode mode; unsigned long flags; if (!dev->irq) { @@ -1221,6 +1170,7 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } else xfer = fifo_not_empty_transfer; devpriv->current_transfer = xfer; + mode = labpc_ai_scan_mode(cmd); /* setup command6 register for 1200 boards */ if (thisboard->register_layout == labpc_1200_layout) { @@ -1245,7 +1195,7 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) else devpriv->command6_bits &= ~A1_INTR_EN_BIT; /* are we scanning up or down through channels? */ - if (labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_UP) + if (mode == MODE_MULT_CHAN_UP) devpriv->command6_bits |= ADC_SCAN_UP_BIT; else devpriv->command6_bits &= ~ADC_SCAN_UP_BIT; @@ -1256,19 +1206,18 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) /* setup channel list, etc (command1 register) */ devpriv->command1_bits = 0; - if (labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_UP) + if (mode == MODE_MULT_CHAN_UP) channel = CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]); else channel = CR_CHAN(cmd->chanlist[0]); /* munge channel bits for differential / scan disabled mode */ - if (labpc_ai_scan_mode(cmd) != MODE_SINGLE_CHAN && aref == AREF_DIFF) + if (mode != MODE_SINGLE_CHAN && aref == AREF_DIFF) channel *= 2; devpriv->command1_bits |= ADC_CHAN_BITS(channel); devpriv->command1_bits |= thisboard->ai_range_code[range]; devpriv->write_byte(devpriv->command1_bits, dev->iobase + COMMAND1_REG); /* manual says to set scan enable bit on second pass */ - if (labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_UP || - labpc_ai_scan_mode(cmd) == MODE_MULT_CHAN_DOWN) { + if (mode == MODE_MULT_CHAN_UP || mode == MODE_MULT_CHAN_DOWN) { devpriv->command1_bits |= ADC_SCAN_EN_BIT; /* need a brief delay before enabling scan, or scan * list will get screwed when you switch @@ -1283,7 +1232,7 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) devpriv->command4_bits |= EXT_CONVERT_DISABLE_BIT; /* XXX should discard first scan when using interval scanning * since manual says it is not synced with scan clock */ - if (labpc_use_continuous_mode(cmd) == 0) { + if (labpc_use_continuous_mode(cmd, mode) == 0) { devpriv->command4_bits |= INTERVAL_SCAN_EN_BIT; if (cmd->scan_begin_src == TRIG_EXT) devpriv->command4_bits |= EXT_SCAN_EN_BIT; @@ -1301,7 +1250,7 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) if (cmd->convert_src == TRIG_TIMER || cmd->scan_begin_src == TRIG_TIMER) { /* set up pacing */ - labpc_adc_timing(dev, cmd); + labpc_adc_timing(dev, cmd, mode); /* load counter b0 in mode 3 */ ret = labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG, 0, devpriv->divisor_b0, 3); @@ -1311,7 +1260,7 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) } } /* set up conversion pacing */ - if (labpc_ai_convert_period(cmd)) { + if (labpc_ai_convert_period(cmd, mode)) { /* load counter a0 in mode 2 */ ret = labpc_counter_load(dev, dev->iobase + COUNTER_A_BASE_REG, 0, devpriv->divisor_a0, 2); @@ -1324,7 +1273,7 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) dev->iobase + COUNTER_A_CONTROL_REG); /* set up scan pacing */ - if (labpc_ai_scan_period(cmd)) { + if (labpc_ai_scan_period(cmd, mode)) { /* load counter b1 in mode 2 */ ret = labpc_counter_load(dev, dev->iobase + COUNTER_B_BASE_REG, 1, devpriv->divisor_b1, 2); @@ -1347,7 +1296,7 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s) set_dma_addr(devpriv->dma_chan, virt_to_bus(devpriv->dma_buffer)); /* set appropriate size of transfer */ - devpriv->dma_transfer_size = labpc_suggest_transfer_size(*cmd); + devpriv->dma_transfer_size = labpc_suggest_transfer_size(cmd); if (cmd->stop_src == TRIG_COUNT && devpriv->count * sample_size < devpriv->dma_transfer_size) { devpriv->dma_transfer_size = @@ -1786,8 +1735,8 @@ static int labpc_eeprom_write_insn(struct comedi_device *dev, /* only allow writes to user area of eeprom */ if (channel < 16 || channel > 127) { - printk - ("eeprom writes are only allowed to channels 16 through 127 (the pointer and user areas)"); + dev_dbg(dev->class_dev, + "eeprom writes are only allowed to channels 16 through 127 (the pointer and user areas)\n"); return -EINVAL; } @@ -1800,13 +1749,13 @@ static int labpc_eeprom_write_insn(struct comedi_device *dev, #ifdef CONFIG_ISA_DMA_API /* utility function that suggests a dma transfer size in bytes */ -static unsigned int labpc_suggest_transfer_size(struct comedi_cmd cmd) +static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd) { unsigned int size; unsigned int freq; - if (cmd.convert_src == TRIG_TIMER) - freq = 1000000000 / cmd.convert_arg; + if (cmd->convert_src == TRIG_TIMER) + freq = 1000000000 / cmd->convert_arg; /* return some default value */ else freq = 0xffffffff; @@ -1825,24 +1774,29 @@ static unsigned int labpc_suggest_transfer_size(struct comedi_cmd cmd) #endif /* figures out what counter values to use based on command */ -static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd) +static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd, + enum scan_mode mode) { /* max value for 16 bit counter in mode 2 */ const int max_counter_value = 0x10000; /* min value for 16 bit counter in mode 2 */ const int min_counter_value = 2; unsigned int base_period; + unsigned int scan_period; + unsigned int convert_period; /* * if both convert and scan triggers are TRIG_TIMER, then they * both rely on counter b0 */ - if (labpc_ai_convert_period(cmd) && labpc_ai_scan_period(cmd)) { + convert_period = labpc_ai_convert_period(cmd, mode); + scan_period = labpc_ai_scan_period(cmd, mode); + if (convert_period && scan_period) { /* * pick the lowest b0 divisor value we can (for maximum input * clock speed on convert and scan counters) */ - devpriv->divisor_b0 = (labpc_ai_scan_period(cmd) - 1) / + devpriv->divisor_b0 = (scan_period - 1) / (LABPC_TIMER_BASE * max_counter_value) + 1; if (devpriv->divisor_b0 < min_counter_value) devpriv->divisor_b0 = min_counter_value; @@ -1856,25 +1810,19 @@ static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd) default: case TRIG_ROUND_NEAREST: devpriv->divisor_a0 = - (labpc_ai_convert_period(cmd) + - (base_period / 2)) / base_period; + (convert_period + (base_period / 2)) / base_period; devpriv->divisor_b1 = - (labpc_ai_scan_period(cmd) + - (base_period / 2)) / base_period; + (scan_period + (base_period / 2)) / base_period; break; case TRIG_ROUND_UP: devpriv->divisor_a0 = - (labpc_ai_convert_period(cmd) + (base_period - - 1)) / base_period; + (convert_period + (base_period - 1)) / base_period; devpriv->divisor_b1 = - (labpc_ai_scan_period(cmd) + (base_period - - 1)) / base_period; + (scan_period + (base_period - 1)) / base_period; break; case TRIG_ROUND_DOWN: - devpriv->divisor_a0 = - labpc_ai_convert_period(cmd) / base_period; - devpriv->divisor_b1 = - labpc_ai_scan_period(cmd) / base_period; + devpriv->divisor_a0 = convert_period / base_period; + devpriv->divisor_b1 = scan_period / base_period; break; } /* make sure a0 and b1 values are acceptable */ @@ -1887,18 +1835,15 @@ static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd) if (devpriv->divisor_b1 > max_counter_value) devpriv->divisor_b1 = max_counter_value; /* write corrected timings to command */ - labpc_set_ai_convert_period(cmd, + labpc_set_ai_convert_period(cmd, mode, base_period * devpriv->divisor_a0); - labpc_set_ai_scan_period(cmd, + labpc_set_ai_scan_period(cmd, mode, base_period * devpriv->divisor_b1); /* * if only one TRIG_TIMER is used, we can employ the generic * cascaded timing functions */ - } else if (labpc_ai_scan_period(cmd)) { - unsigned int scan_period; - - scan_period = labpc_ai_scan_period(cmd); + } else if (scan_period) { /* * calculate cascaded counter values * that give desired scan timing @@ -1908,11 +1853,8 @@ static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd) &(devpriv->divisor_b0), &scan_period, cmd->flags & TRIG_ROUND_MASK); - labpc_set_ai_scan_period(cmd, scan_period); - } else if (labpc_ai_convert_period(cmd)) { - unsigned int convert_period; - - convert_period = labpc_ai_convert_period(cmd); + labpc_set_ai_scan_period(cmd, mode, scan_period); + } else if (convert_period) { /* * calculate cascaded counter values * that give desired conversion timing @@ -1922,7 +1864,7 @@ static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd) &(devpriv->divisor_b0), &convert_period, cmd->flags & TRIG_ROUND_MASK); - labpc_set_ai_convert_period(cmd, convert_period); + labpc_set_ai_convert_period(cmd, mode, convert_period); } } @@ -1930,10 +1872,10 @@ static int labpc_dio_mem_callback(int dir, int port, int data, unsigned long iobase) { if (dir) { - writeb(data, (void *)(iobase + port)); + writeb(data, (void __iomem *)(iobase + port)); return 0; } else { - return readb((void *)(iobase + port)); + return readb((void __iomem *)(iobase + port)); } } @@ -2136,57 +2078,44 @@ static void write_caldac(struct comedi_device *dev, unsigned int channel, devpriv->write_byte(devpriv->command5_bits, dev->iobase + COMMAND5_REG); } +static struct comedi_driver labpc_driver = { + .driver_name = DRV_NAME, + .module = THIS_MODULE, + .attach = labpc_attach, + .attach_pci = labpc_attach_pci, + .detach = labpc_common_detach, + .num_names = ARRAY_SIZE(labpc_boards), + .board_name = &labpc_boards[0].name, + .offset = sizeof(struct labpc_board_struct), +}; + #ifdef CONFIG_COMEDI_PCI_DRIVERS -static int __devinit driver_labpc_pci_probe(struct pci_dev *dev, - const struct pci_device_id *ent) +static DEFINE_PCI_DEVICE_TABLE(labpc_pci_table) = { + {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x161)}, + {0} +}; +MODULE_DEVICE_TABLE(pci, labpc_pci_table); + +static int __devinit labpc_pci_probe(struct pci_dev *dev, + const struct pci_device_id *ent) { - return comedi_pci_auto_config(dev, &driver_labpc); + return comedi_pci_auto_config(dev, &labpc_driver); } -static void __devexit driver_labpc_pci_remove(struct pci_dev *dev) +static void __devexit labpc_pci_remove(struct pci_dev *dev) { comedi_pci_auto_unconfig(dev); } -static struct pci_driver driver_labpc_pci_driver = { +static struct pci_driver labpc_pci_driver = { + .name = DRV_NAME, .id_table = labpc_pci_table, - .probe = &driver_labpc_pci_probe, - .remove = __devexit_p(&driver_labpc_pci_remove) + .probe = labpc_pci_probe, + .remove = __devexit_p(labpc_pci_remove) }; - -static int __init driver_labpc_init_module(void) -{ - int retval; - - retval = comedi_driver_register(&driver_labpc); - if (retval < 0) - return retval; - - driver_labpc_pci_driver.name = (char *)driver_labpc.driver_name; - return pci_register_driver(&driver_labpc_pci_driver); -} - -static void __exit driver_labpc_cleanup_module(void) -{ - pci_unregister_driver(&driver_labpc_pci_driver); - comedi_driver_unregister(&driver_labpc); -} - -module_init(driver_labpc_init_module); -module_exit(driver_labpc_cleanup_module); +module_comedi_pci_driver(labpc_driver, labpc_pci_driver); #else -static int __init driver_labpc_init_module(void) -{ - return comedi_driver_register(&driver_labpc); -} - -static void __exit driver_labpc_cleanup_module(void) -{ - comedi_driver_unregister(&driver_labpc); -} - -module_init(driver_labpc_init_module); -module_exit(driver_labpc_cleanup_module); +module_comedi_driver(labpc_driver); #endif diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c index dbb61b6b3ed1..eb0417eb6d7d 100644 --- a/drivers/staging/comedi/drivers/ni_labpc_cs.c +++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c @@ -270,7 +270,7 @@ MODULE_AUTHOR("Frank Mori Hess <fmhess@users.sourceforge.net>"); MODULE_DESCRIPTION("Comedi driver for National Instruments Lab-PC"); MODULE_LICENSE("GPL"); -struct pcmcia_driver labpc_cs_driver = { +static struct pcmcia_driver labpc_cs_driver = { .probe = labpc_cs_attach, .remove = labpc_cs_detach, .suspend = labpc_cs_suspend, @@ -291,7 +291,7 @@ static void __exit exit_labpc_cs(void) pcmcia_unregister_driver(&labpc_cs_driver); } -int __init labpc_init_module(void) +static int __init labpc_init_module(void) { int ret; @@ -302,7 +302,7 @@ int __init labpc_init_module(void) return comedi_driver_register(&driver_labpc_cs); } -void __exit labpc_exit_module(void) +static void __exit labpc_exit_module(void) { exit_labpc_cs(); comedi_driver_unregister(&driver_labpc_cs); diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c index cf0e0d147f8c..3e5fdae93163 100644 --- a/drivers/staging/comedi/drivers/ni_mio_common.c +++ b/drivers/staging/comedi/drivers/ni_mio_common.c @@ -644,10 +644,10 @@ static void ni_release_ao_mite_channel(struct comedi_device *dev) #endif /* PCIDMA */ } -void ni_release_gpct_mite_channel(struct comedi_device *dev, - unsigned gpct_index) -{ #ifdef PCIDMA +static void ni_release_gpct_mite_channel(struct comedi_device *dev, + unsigned gpct_index) +{ unsigned long flags; BUG_ON(gpct_index >= NUM_GPCT); @@ -663,8 +663,8 @@ void ni_release_gpct_mite_channel(struct comedi_device *dev, mite_release_channel(mite_chan); } spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); -#endif /* PCIDMA */ } +#endif /* PCIDMA */ static void ni_release_cdo_mite_channel(struct comedi_device *dev) { @@ -872,7 +872,7 @@ static irqreturn_t ni_E_interrupt(int irq, void *d) #ifdef PCIDMA static void ni_sync_ai_dma(struct comedi_device *dev) { - struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; + struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV]; unsigned long flags; spin_lock_irqsave(&devpriv->mite_channel_lock, flags); @@ -884,7 +884,7 @@ static void ni_sync_ai_dma(struct comedi_device *dev) static void mite_handle_b_linkc(struct mite_struct *mite, struct comedi_device *dev) { - struct comedi_subdevice *s = dev->subdevices + NI_AO_SUBDEV; + struct comedi_subdevice *s = &dev->subdevices[NI_AO_SUBDEV]; unsigned long flags; spin_lock_irqsave(&devpriv->mite_channel_lock, flags); @@ -942,7 +942,7 @@ static void ni_handle_eos(struct comedi_device *dev, struct comedi_subdevice *s) static void shutdown_ai_command(struct comedi_device *dev) { - struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; + struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV]; #ifdef PCIDMA ni_ai_drain_dma(dev); @@ -984,8 +984,9 @@ static void handle_gpct_interrupt(struct comedi_device *dev, unsigned short counter_index) { #ifdef PCIDMA - struct comedi_subdevice *s = - dev->subdevices + NI_GPCT_SUBDEV(counter_index); + struct comedi_subdevice *s; + + s = &dev->subdevices[NI_GPCT_SUBDEV(counter_index)]; ni_tio_handle_interrupt(&devpriv->counter_dev->counters[counter_index], s); @@ -1018,7 +1019,7 @@ static void ack_a_interrupt(struct comedi_device *dev, unsigned short a_status) static void handle_a_interrupt(struct comedi_device *dev, unsigned short status, unsigned ai_mite_status) { - struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; + struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV]; /* 67xx boards don't have ai subdevice, but their gpct0 might generate an a interrupt */ if (s->type == COMEDI_SUBD_UNUSED) @@ -1150,7 +1151,7 @@ static void ack_b_interrupt(struct comedi_device *dev, unsigned short b_status) static void handle_b_interrupt(struct comedi_device *dev, unsigned short b_status, unsigned ao_mite_status) { - struct comedi_subdevice *s = dev->subdevices + NI_AO_SUBDEV; + struct comedi_subdevice *s = &dev->subdevices[NI_AO_SUBDEV]; /* unsigned short ack=0; */ #ifdef DEBUG_INTERRUPT printk("ni_mio_common: interrupt: b_status=%04x m1_status=%08x\n", @@ -1422,7 +1423,7 @@ static void ni_ai_fifo_read(struct comedi_device *dev, static void ni_handle_fifo_half_full(struct comedi_device *dev) { int n; - struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; + struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV]; n = boardtype.ai_fifo_depth / 2; @@ -1470,7 +1471,7 @@ static int ni_ai_drain_dma(struct comedi_device *dev) */ static void ni_handle_fifo_dregs(struct comedi_device *dev) { - struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; + struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV]; short data[2]; u32 dl; short fifo_empty; @@ -1534,7 +1535,7 @@ static void ni_handle_fifo_dregs(struct comedi_device *dev) static void get_last_sample_611x(struct comedi_device *dev) { - struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; + struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV]; short data; u32 dl; @@ -1551,7 +1552,7 @@ static void get_last_sample_611x(struct comedi_device *dev) static void get_last_sample_6143(struct comedi_device *dev) { - struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; + struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV]; short data; u32 dl; @@ -1598,7 +1599,7 @@ static void ni_ai_munge(struct comedi_device *dev, struct comedi_subdevice *s, static int ni_ai_setup_MITE_dma(struct comedi_device *dev) { - struct comedi_subdevice *s = dev->subdevices + NI_AI_SUBDEV; + struct comedi_subdevice *s = &dev->subdevices[NI_AI_SUBDEV]; int retval; unsigned long flags; @@ -1637,7 +1638,7 @@ static int ni_ai_setup_MITE_dma(struct comedi_device *dev) static int ni_ao_setup_MITE_dma(struct comedi_device *dev) { - struct comedi_subdevice *s = dev->subdevices + NI_AO_SUBDEV; + struct comedi_subdevice *s = &dev->subdevices[NI_AO_SUBDEV]; int retval; unsigned long flags; @@ -1765,20 +1766,18 @@ static int ni_ai_reset(struct comedi_device *dev, struct comedi_subdevice *s) static int ni_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) { - unsigned long flags = 0; + unsigned long flags; int count; /* lock to avoid race with interrupt handler */ - if (in_interrupt() == 0) - spin_lock_irqsave(&dev->spinlock, flags); + spin_lock_irqsave(&dev->spinlock, flags); #ifndef PCIDMA ni_handle_fifo_dregs(dev); #else ni_sync_ai_dma(dev); #endif count = s->async->buf_write_count - s->async->buf_read_count; - if (in_interrupt() == 0) - spin_unlock_irqrestore(&dev->spinlock, flags); + spin_unlock_irqrestore(&dev->spinlock, flags); return count; } @@ -1880,7 +1879,7 @@ static int ni_ai_insn_read(struct comedi_device *dev, return insn->n; } -void ni_prime_channelgain_list(struct comedi_device *dev) +static void ni_prime_channelgain_list(struct comedi_device *dev) { int i; devpriv->stc_writew(dev, AI_CONVERT_Pulse, AI_Command_1_Register); @@ -2165,61 +2164,38 @@ static int ni_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, { int err = 0; int tmp; - int sources; + unsigned int sources; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - if ((cmd->flags & CMDF_WRITE)) { + if ((cmd->flags & CMDF_WRITE)) cmd->flags &= ~CMDF_WRITE; - } - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_INT | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, + TRIG_NOW | TRIG_INT | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_EXT); - tmp = cmd->convert_src; sources = TRIG_TIMER | TRIG_EXT; - if ((boardtype.reg_type == ni_reg_611x) - || (boardtype.reg_type == ni_reg_6143)) + if (boardtype.reg_type == ni_reg_611x || + boardtype.reg_type == ni_reg_6143) sources |= TRIG_NOW; - cmd->convert_src &= sources; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + err |= cfc_check_trigger_src(&cmd->convert_src, sources); - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ - /* note that mutual compatibility is not an issue here */ - if (cmd->start_src != TRIG_NOW && - cmd->start_src != TRIG_INT && cmd->start_src != TRIG_EXT) - err++; - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT && - cmd->scan_begin_src != TRIG_OTHER) - err++; - if (cmd->convert_src != TRIG_TIMER && - cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -3357,44 +3333,28 @@ static int ni_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, int err = 0; int tmp; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - if ((cmd->flags & CMDF_WRITE) == 0) { + if ((cmd->flags & CMDF_WRITE) == 0) cmd->flags |= CMDF_WRITE; - } - tmp = cmd->start_src; - cmd->start_src &= TRIG_INT | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -3644,51 +3604,21 @@ static int ni_cdio_cmdtest(struct comedi_device *dev, { int err = 0; int tmp; - int sources; unsigned i; - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - sources = TRIG_INT; - cmd->start_src &= sources; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique... */ - - if (cmd->start_src != TRIG_INT) - err++; - if (cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->convert_src != TRIG_NOW) - err++; - if (cmd->stop_src != TRIG_NONE) - err++; - /* ... and mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -3852,7 +3782,7 @@ static int ni_cdio_cancel(struct comedi_device *dev, struct comedi_subdevice *s) static void handle_cdio_interrupt(struct comedi_device *dev) { unsigned cdio_status; - struct comedi_subdevice *s = dev->subdevices + NI_DIO_SUBDEV; + struct comedi_subdevice *s = &dev->subdevices[NI_DIO_SUBDEV]; #ifdef PCIDMA unsigned long flags; #endif @@ -4101,13 +4031,17 @@ static int ni_serial_sw_readwrite8(struct comedi_device *dev, static void mio_common_detach(struct comedi_device *dev) { + struct comedi_subdevice *s; + if (dev->private) { if (devpriv->counter_dev) { ni_gpct_device_destroy(devpriv->counter_dev); } } - if (dev->subdevices && boardtype.has_8255) - subdev_8255_cleanup(dev, dev->subdevices + NI_8255_DIO_SUBDEV); + if (dev->subdevices && boardtype.has_8255) { + s = &dev->subdevices[NI_8255_DIO_SUBDEV]; + subdev_8255_cleanup(dev, s); + } } static void init_ao_67xx(struct comedi_device *dev, struct comedi_subdevice *s) @@ -4399,7 +4333,7 @@ static int ni_alloc_private(struct comedi_device *dev) return 0; }; -static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) +static int ni_E_init(struct comedi_device *dev) { struct comedi_subdevice *s; unsigned j; @@ -4417,7 +4351,7 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) /* analog input subdevice */ - s = dev->subdevices + NI_AI_SUBDEV; + s = &dev->subdevices[NI_AI_SUBDEV]; dev->read_subdev = s; if (boardtype.n_adchan) { s->type = COMEDI_SUBD_AI; @@ -4449,7 +4383,7 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) /* analog output subdevice */ - s = dev->subdevices + NI_AO_SUBDEV; + s = &dev->subdevices[NI_AO_SUBDEV]; if (boardtype.n_aochan) { s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE | SDF_DEGLITCH | SDF_GROUND; @@ -4488,7 +4422,7 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) /* digital i/o subdevice */ - s = dev->subdevices + NI_DIO_SUBDEV; + s = &dev->subdevices[NI_DIO_SUBDEV]; s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_WRITABLE | SDF_READABLE; s->maxdata = 1; @@ -4516,7 +4450,7 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) } /* 8255 device */ - s = dev->subdevices + NI_8255_DIO_SUBDEV; + s = &dev->subdevices[NI_8255_DIO_SUBDEV]; if (boardtype.has_8255) { subdev_8255_init(dev, s, ni_8255_callback, (unsigned long)dev); } else { @@ -4524,11 +4458,11 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) } /* formerly general purpose counter/timer device, but no longer used */ - s = dev->subdevices + NI_UNUSED_SUBDEV; + s = &dev->subdevices[NI_UNUSED_SUBDEV]; s->type = COMEDI_SUBD_UNUSED; /* calibration subdevice -- ai and ao */ - s = dev->subdevices + NI_CALIBRATION_SUBDEV; + s = &dev->subdevices[NI_CALIBRATION_SUBDEV]; s->type = COMEDI_SUBD_CALIB; if (boardtype.reg_type & ni_reg_m_series_mask) { /* internal PWM analog output used for AI nonlinearity calibration */ @@ -4551,7 +4485,7 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) } /* EEPROM */ - s = dev->subdevices + NI_EEPROM_SUBDEV; + s = &dev->subdevices[NI_EEPROM_SUBDEV]; s->type = COMEDI_SUBD_MEMORY; s->subdev_flags = SDF_READABLE | SDF_INTERNAL; s->maxdata = 0xff; @@ -4564,7 +4498,7 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) } /* PFI */ - s = dev->subdevices + NI_PFI_DIO_SUBDEV; + s = &dev->subdevices[NI_PFI_DIO_SUBDEV]; s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; if (boardtype.reg_type & ni_reg_m_series_mask) { @@ -4586,7 +4520,7 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) ni_set_bits(dev, IO_Bidirection_Pin_Register, ~0, 0); /* cs5529 calibration adc */ - s = dev->subdevices + NI_CS5529_CALIBRATION_SUBDEV; + s = &dev->subdevices[NI_CS5529_CALIBRATION_SUBDEV]; if (boardtype.reg_type & ni_reg_67xx_mask) { s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_INTERNAL; @@ -4602,7 +4536,7 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) } /* Serial */ - s = dev->subdevices + NI_SERIAL_SUBDEV; + s = &dev->subdevices[NI_SERIAL_SUBDEV]; s->type = COMEDI_SUBD_SERIAL; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; s->n_chan = 1; @@ -4612,7 +4546,7 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) devpriv->serial_hw_mode = 0; /* RTSI */ - s = dev->subdevices + NI_RTSI_SUBDEV; + s = &dev->subdevices[NI_RTSI_SUBDEV]; s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_INTERNAL; s->n_chan = 8; @@ -4633,7 +4567,7 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) NUM_GPCT); /* General purpose counters */ for (j = 0; j < NUM_GPCT; ++j) { - s = dev->subdevices + NI_GPCT_SUBDEV(j); + s = &dev->subdevices[NI_GPCT_SUBDEV(j)]; s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL | SDF_CMD_READ @@ -4659,7 +4593,7 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) } /* Frequency output */ - s = dev->subdevices + NI_FREQ_OUT_SUBDEV; + s = &dev->subdevices[NI_FREQ_OUT_SUBDEV]; s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = 1; @@ -4669,7 +4603,8 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_config = &ni_freq_out_insn_config; /* ai configuration */ - ni_ai_reset(dev, dev->subdevices + NI_AI_SUBDEV); + s = &dev->subdevices[NI_AI_SUBDEV]; + ni_ai_reset(dev, s); if ((boardtype.reg_type & ni_reg_6xxx_mask) == 0) { /* BEAM is this needed for PCI-6143 ?? */ devpriv->clock_and_fout = @@ -4688,7 +4623,8 @@ static int ni_E_init(struct comedi_device *dev, struct comedi_devconfig *it) Clock_and_FOUT_Register); /* analog output configuration */ - ni_ao_reset(dev, dev->subdevices + NI_AO_SUBDEV); + s = &dev->subdevices[NI_AO_SUBDEV]; + ni_ao_reset(dev, s); if (dev->irq) { devpriv->stc_writew(dev, diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c index b85765d266c2..ca4f8e06e75b 100644 --- a/drivers/staging/comedi/drivers/ni_mio_cs.c +++ b/drivers/staging/comedi/drivers/ni_mio_cs.c @@ -382,7 +382,7 @@ static int mio_cs_attach(struct comedi_device *dev, struct comedi_devconfig *it) devpriv->stc_writel = &win_out2; devpriv->stc_readl = &win_in2; - ret = ni_E_init(dev, it); + ret = ni_E_init(dev); if (ret < 0) return ret; @@ -421,7 +421,7 @@ MODULE_AUTHOR("David A. Schleef <ds@schleef.org>"); MODULE_DESCRIPTION("Comedi driver for National Instruments DAQCard E series"); MODULE_LICENSE("GPL"); -struct pcmcia_driver ni_mio_cs_driver = { +static struct pcmcia_driver ni_mio_cs_driver = { .probe = &cs_attach, .remove = &cs_detach, .suspend = &mio_cs_suspend, diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c index 0a55de968039..bc9313ec985c 100644 --- a/drivers/staging/comedi/drivers/ni_pcidio.c +++ b/drivers/staging/comedi/drivers/ni_pcidio.c @@ -1,8 +1,6 @@ /* comedi/drivers/ni_pcidio.c - driver for National Instruments PCI-DIO-96/PCI-6508 - National Instruments PCI-DIO-32HS - National Instruments PCI-6503 + driver for National Instruments PCI-DIO-32HS COMEDI - Linux Control and Measurement Device Interface Copyright (C) 1999,2002 David A. Schleef <ds@schleef.org> @@ -24,17 +22,14 @@ */ /* Driver: ni_pcidio -Description: National Instruments PCI-DIO32HS, PCI-DIO96, PCI-6533, PCI-6503 +Description: National Instruments PCI-DIO32HS, PCI-6533 Author: ds Status: works -Devices: [National Instruments] PCI-DIO-32HS (ni_pcidio), PXI-6533, - PCI-DIO-96, PCI-DIO-96B, PXI-6508, PCI-6503, PCI-6503B, PCI-6503X, - PXI-6503, PCI-6533, PCI-6534 +Devices: [National Instruments] PCI-DIO-32HS (ni_pcidio) + [National Instruments] PXI-6533, PCI-6533 (pxi-6533) + [National Instruments] PCI-6534 (pci-6534) Updated: Mon, 09 Jan 2012 14:27:23 +0000 -The DIO-96 appears as four 8255 subdevices. See the 8255 -driver notes for details. - The DIO32HS board appears as one subdevice, with 32 channels. Each channel is individually I/O configurable. The channel order is 0=A0, 1=A1, 2=A2, ... 8=B0, 16=C0, 24=D0. The driver only @@ -56,49 +51,28 @@ it are contained in the comedi_nonfree_firmware tarball available from http://www.comedi.org */ -/* - This driver is for both the NI PCI-DIO-32HS and the PCI-DIO-96, - which have very different architectures. But, since the '96 is - so simple, it is included here. - - Manuals (available from ftp://ftp.natinst.com/support/manuals) - - 320938c.pdf PCI-DIO-96/PXI-6508/PCI-6503 User Manual - 321464b.pdf AT/PCI-DIO-32HS User Manual - 341329A.pdf PCI-6533 Register-Level Programmer Manual - 341330A.pdf DAQ-DIO Technical Reference Manual - - */ - #define USE_DMA /* #define DEBUG 1 */ /* #define DEBUG_FLAGS */ #include <linux/interrupt.h> #include <linux/sched.h> +#include <linux/firmware.h> #include "../comedidev.h" +#include "comedi_fc.h" #include "mite.h" -#include "8255.h" #undef DPRINTK #ifdef DEBUG -#define DPRINTK(format, args...) printk(format, ## args) +#define DPRINTK(format, args...) pr_debug(format, ## args) #else -#define DPRINTK(format, args...) +#define DPRINTK(format, args...) do { } while (0) #endif #define PCI_DIO_SIZE 4096 #define PCI_MITE_SIZE 4096 -/* defines for the PCI-DIO-96 */ - -#define NIDIO_8255_BASE(x) ((x)*4) -#define NIDIO_A 0 -#define NIDIO_B 4 -#define NIDIO_C 8 -#define NIDIO_D 12 - /* defines for the PCI-DIO-32HS */ #define Window_Address 4 /* W */ @@ -258,6 +232,14 @@ static inline unsigned secondary_DMAChannel_bits(unsigned channel) #define Protocol_Register_8 88 /* 32 bit */ #define StartDelay Protocol_Register_8 +/* Firmware files for PCI-6524 */ +#define FW_PCI_6534_MAIN "ni6534a.bin" +#define FW_PCI_6534_SCARAB_DI "niscrb01.bin" +#define FW_PCI_6534_SCARAB_DO "niscrb02.bin" +MODULE_FIRMWARE(FW_PCI_6534_MAIN); +MODULE_FIRMWARE(FW_PCI_6534_SCARAB_DI); +MODULE_FIRMWARE(FW_PCI_6534_SCARAB_DO); + enum pci_6534_firmware_registers { /* 16 bit */ Firmware_Control_Register = 0x100, Firmware_Status_Register = 0x104, @@ -297,76 +279,23 @@ static int ni_pcidio_cancel(struct comedi_device *dev, struct comedi_subdevice *s); struct nidio_board { - int dev_id; const char *name; - int n_8255; - unsigned int is_diodaq:1; unsigned int uses_firmware:1; }; static const struct nidio_board nidio_boards[] = { { - .dev_id = 0x1150, - .name = "pci-dio-32hs", - .n_8255 = 0, - .is_diodaq = 1, - }, - { - .dev_id = 0x1320, - .name = "pxi-6533", - .n_8255 = 0, - .is_diodaq = 1, - }, - { - .dev_id = 0x12b0, - .name = "pci-6534", - .n_8255 = 0, - .is_diodaq = 1, - .uses_firmware = 1, - }, - { - .dev_id = 0x0160, - .name = "pci-dio-96", - .n_8255 = 4, - .is_diodaq = 0, - }, - { - .dev_id = 0x1630, - .name = "pci-dio-96b", - .n_8255 = 4, - .is_diodaq = 0, - }, - { - .dev_id = 0x13c0, - .name = "pxi-6508", - .n_8255 = 4, - .is_diodaq = 0, - }, - { - .dev_id = 0x0400, - .name = "pci-6503", - .n_8255 = 1, - .is_diodaq = 0, - }, - { - .dev_id = 0x1250, - .name = "pci-6503b", - .n_8255 = 1, - .is_diodaq = 0, - }, - { - .dev_id = 0x17d0, - .name = "pci-6503x", - .n_8255 = 1, - .is_diodaq = 0, - }, - { - .dev_id = 0x1800, - .name = "pxi-6503", - .n_8255 = 1, - .is_diodaq = 0, - }, + .dev_id = 0x1150, + .name = "pci-dio-32hs", + }, { + .dev_id = 0x1320, + .name = "pxi-6533", + }, { + .dev_id = 0x12b0, + .name = "pci-6534", + .uses_firmware = 1, + }, }; #define n_nidio_boards ARRAY_SIZE(nidio_boards) @@ -442,17 +371,8 @@ static void ni_pcidio_release_di_mite_channel(struct comedi_device *dev) spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags); } -static int nidio96_8255_cb(int dir, int port, int data, unsigned long iobase) -{ - if (dir) { - writeb(data, (void *)(iobase + port)); - return 0; - } else { - return readb((void *)(iobase + port)); - } -} - -void ni_pcidio_event(struct comedi_device *dev, struct comedi_subdevice *s) +static void ni_pcidio_event(struct comedi_device *dev, + struct comedi_subdevice *s) { if (s-> async->events & (COMEDI_CB_EOA | COMEDI_CB_ERROR | @@ -480,7 +400,7 @@ static int ni_pcidio_poll(struct comedi_device *dev, struct comedi_subdevice *s) static irqreturn_t nidio_interrupt(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices; + struct comedi_subdevice *s = &dev->subdevices[0]; struct comedi_async *async = s->async; struct mite_struct *mite = devpriv->mite; @@ -511,18 +431,12 @@ static irqreturn_t nidio_interrupt(int irq, void *d) ni_pcidio_print_flags(flags); ni_pcidio_print_status(status); - /* printk("buf[0]=%08x\n",*(unsigned int *)async->prealloc_buf); */ - /* printk("buf[4096]=%08x\n", - *(unsigned int *)(async->prealloc_buf+4096)); */ - spin_lock(&devpriv->mite_channel_lock); if (devpriv->di_mite_chan) m_status = mite_get_status(devpriv->di_mite_chan); #ifdef MITE_DEBUG mite_print_chsr(m_status); #endif - /* printk("mite_bytes_transferred: %d\n", - mite_bytes_transferred(mite,DI_DMA_CHAN)); */ /* mite_dump_regs(mite); */ if (m_status & CHSR_INT) { @@ -617,7 +531,7 @@ static irqreturn_t nidio_interrupt(int irq, void *d) } #if 0 else { - printk("ni_pcidio: unknown interrupt\n"); + DPRINTK("ni_pcidio: unknown interrupt\n"); async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA; writeb(0x00, devpriv->mite->daq_io_addr + @@ -648,38 +562,47 @@ out: } #ifdef DEBUG_FLAGS +static const char *bit_set_string(unsigned int bits, unsigned int bit, + const char *const strings[]) +{ + return (bits & (1U << bit)) ? strings[bit] : ""; +} + static const char *const flags_strings[] = { - "TransferReady", "CountExpired", "2", "3", - "4", "Waited", "PrimaryTC", "SecondaryTC", + " TransferReady", " CountExpired", " 2", " 3", + " 4", " Waited", " PrimaryTC", " SecondaryTC", }; + static void ni_pcidio_print_flags(unsigned int flags) { - int i; - - printk(KERN_INFO "group_1_flags:"); - for (i = 7; i >= 0; i--) { - if (flags & (1 << i)) - printk(" %s", flags_strings[i]); - } - printk("\n"); + pr_debug("group_1_flags:%s%s%s%s%s%s%s%s\n", + bit_set_string(flags, 7, flags_strings), + bit_set_string(flags, 6, flags_strings), + bit_set_string(flags, 5, flags_strings), + bit_set_string(flags, 4, flags_strings), + bit_set_string(flags, 3, flags_strings), + bit_set_string(flags, 2, flags_strings), + bit_set_string(flags, 1, flags_strings), + bit_set_string(flags, 0, flags_strings)); } -static char *status_strings[] = { - "DataLeft1", "Reserved1", "Req1", "StopTrig1", - "DataLeft2", "Reserved2", "Req2", "StopTrig2", +static const char *const status_strings[] = { + " DataLeft1", " Reserved1", " Req1", " StopTrig1", + " DataLeft2", " Reserved2", " Req2", " StopTrig2", }; static void ni_pcidio_print_status(unsigned int flags) { - int i; - - printk(KERN_INFO "group_status:"); - for (i = 7; i >= 0; i--) { - if (flags & (1 << i)) - printk(" %s", status_strings[i]); - } - printk("\n"); + pr_debug("group_status:%s%s%s%s%s%s%s%s\n", + bit_set_string(flags, 7, status_strings), + bit_set_string(flags, 6, status_strings), + bit_set_string(flags, 5, status_strings), + bit_set_string(flags, 4, status_strings), + bit_set_string(flags, 3, status_strings), + bit_set_string(flags, 2, status_strings), + bit_set_string(flags, 1, status_strings), + bit_set_string(flags, 0, status_strings)); } #endif @@ -761,45 +684,25 @@ static int ni_pcidio_cmdtest(struct comedi_device *dev, int err = 0; int tmp; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_INT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually - compatible */ + /* Step 2a : make sure trigger sources are unique */ - /* note that mutual compatibility is not an issue here */ - if (cmd->start_src != TRIG_NOW && cmd->start_src != TRIG_INT) - err++; - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT) - err++; + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -1065,10 +968,12 @@ static int ni_pcidio_change(struct comedi_device *dev, } static int pci_6534_load_fpga(struct comedi_device *dev, int fpga_index, - u8 *data, int data_len) + const u8 *data, size_t data_len) { static const int timeout = 1000; - int i, j; + int i; + size_t j; + writew(0x80 | fpga_index, devpriv->mite->daq_io_addr + Firmware_Control_Register); writew(0xc0 | fpga_index, @@ -1079,8 +984,9 @@ static int pci_6534_load_fpga(struct comedi_device *dev, int fpga_index, udelay(1); } if (i == timeout) { - printk(KERN_WARNING "ni_pcidio: failed to load fpga %i, " - "waiting for status 0x2\n", fpga_index); + dev_warn(dev->class_dev, + "ni_pcidio: failed to load fpga %i, waiting for status 0x2\n", + fpga_index); return -EIO; } writew(0x80 | fpga_index, @@ -1091,8 +997,9 @@ static int pci_6534_load_fpga(struct comedi_device *dev, int fpga_index, udelay(1); } if (i == timeout) { - printk(KERN_WARNING "ni_pcidio: failed to load fpga %i, " - "waiting for status 0x3\n", fpga_index); + dev_warn(dev->class_dev, + "ni_pcidio: failed to load fpga %i, waiting for status 0x3\n", + fpga_index); return -EIO; } for (j = 0; j + 1 < data_len;) { @@ -1107,8 +1014,9 @@ static int pci_6534_load_fpga(struct comedi_device *dev, int fpga_index, udelay(1); } if (i == timeout) { - printk("ni_pcidio: failed to load word into fpga %i\n", - fpga_index); + dev_warn(dev->class_dev, + "ni_pcidio: failed to load word into fpga %i\n", + fpga_index); return -EIO; } if (need_resched()) @@ -1147,85 +1055,72 @@ static void pci_6534_init_main_fpga(struct comedi_device *dev) writel(0, devpriv->mite->daq_io_addr + FPGA_SCBMS_Counter_Register); } -static int pci_6534_upload_firmware(struct comedi_device *dev, int options[]) +static int pci_6534_upload_firmware(struct comedi_device *dev) { int ret; - void *main_fpga_data, *scarab_a_data, *scarab_b_data; - int main_fpga_data_len, scarab_a_data_len, scarab_b_data_len; + const struct firmware *fw; + static const char *const fw_file[3] = { + FW_PCI_6534_SCARAB_DI, /* loaded into scarab A for DI */ + FW_PCI_6534_SCARAB_DO, /* loaded into scarab B for DO */ + FW_PCI_6534_MAIN, /* loaded into main FPGA */ + }; + int n; - if (options[COMEDI_DEVCONF_AUX_DATA_LENGTH] == 0) - return 0; ret = pci_6534_reset_fpgas(dev); if (ret < 0) return ret; - main_fpga_data = comedi_aux_data(options, 0); - main_fpga_data_len = options[COMEDI_DEVCONF_AUX_DATA0_LENGTH]; - ret = pci_6534_load_fpga(dev, 2, main_fpga_data, main_fpga_data_len); - if (ret < 0) - return ret; - pci_6534_init_main_fpga(dev); - scarab_a_data = comedi_aux_data(options, 1); - scarab_a_data_len = options[COMEDI_DEVCONF_AUX_DATA1_LENGTH]; - ret = pci_6534_load_fpga(dev, 0, scarab_a_data, scarab_a_data_len); - if (ret < 0) - return ret; - scarab_b_data = comedi_aux_data(options, 2); - scarab_b_data_len = options[COMEDI_DEVCONF_AUX_DATA2_LENGTH]; - ret = pci_6534_load_fpga(dev, 1, scarab_b_data, scarab_b_data_len); - if (ret < 0) - return ret; - return 0; + /* load main FPGA first, then the two scarabs */ + for (n = 2; n >= 0; n--) { + ret = request_firmware(&fw, fw_file[n], + &devpriv->mite->pcidev->dev); + if (ret == 0) { + ret = pci_6534_load_fpga(dev, n, fw->data, fw->size); + if (ret == 0 && n == 2) + pci_6534_init_main_fpga(dev); + release_firmware(fw); + } + if (ret < 0) + break; + } + return ret; } -static int nidio_find_device(struct comedi_device *dev, int bus, int slot) +static const struct nidio_board * +nidio_find_boardinfo(struct pci_dev *pcidev) { - struct mite_struct *mite; - int i; - - for (mite = mite_devices; mite; mite = mite->next) { - if (mite->used) - continue; - if (bus || slot) { - if (bus != mite->pcidev->bus->number || - slot != PCI_SLOT(mite->pcidev->devfn)) - continue; - } - for (i = 0; i < n_nidio_boards; i++) { - if (mite_device_id(mite) == nidio_boards[i].dev_id) { - dev->board_ptr = nidio_boards + i; - devpriv->mite = mite; + unsigned int dev_id = pcidev->device; + unsigned int n; - return 0; - } - } + for (n = 0; n < ARRAY_SIZE(nidio_boards); n++) { + const struct nidio_board *board = &nidio_boards[n]; + if (board->dev_id == dev_id) + return board; } - printk(KERN_WARNING "no device found\n"); - mite_list_devices(); - return -EIO; + return NULL; } -static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static int __devinit nidio_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) { struct comedi_subdevice *s; - int i; int ret; - int n_subdevices; unsigned int irq; - printk(KERN_INFO "comedi%d: nidio:", dev->minor); - ret = alloc_private(dev, sizeof(struct nidio96_private)); if (ret < 0) return ret; spin_lock_init(&devpriv->mite_channel_lock); - ret = nidio_find_device(dev, it->options[0], it->options[1]); - if (ret < 0) - return ret; + dev->board_ptr = nidio_find_boardinfo(pcidev); + if (!dev->board_ptr) + return -ENODEV; + devpriv->mite = mite_alloc(pcidev); + if (!devpriv->mite) + return -ENOMEM; ret = mite_setup(devpriv->mite); if (ret < 0) { - printk(KERN_WARNING "error setting up mite\n"); + dev_warn(dev->class_dev, "error setting up mite\n"); return ret; } comedi_set_hw_dev(dev, &devpriv->mite->pcidev->dev); @@ -1235,84 +1130,60 @@ static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it) dev->board_name = this_board->name; irq = mite_irq(devpriv->mite); - printk(KERN_INFO " %s", dev->board_name); if (this_board->uses_firmware) { - ret = pci_6534_upload_firmware(dev, it->options); + ret = pci_6534_upload_firmware(dev); if (ret < 0) return ret; } - if (!this_board->is_diodaq) - n_subdevices = this_board->n_8255; - else - n_subdevices = 1; - ret = comedi_alloc_subdevices(dev, n_subdevices); + ret = comedi_alloc_subdevices(dev, 1); if (ret) return ret; - if (!this_board->is_diodaq) { - for (i = 0; i < this_board->n_8255; i++) { - subdev_8255_init(dev, dev->subdevices + i, - nidio96_8255_cb, - (unsigned long)(devpriv->mite-> - daq_io_addr + - NIDIO_8255_BASE(i))); - } - } else { - - printk(KERN_INFO " rev=%d", - readb(devpriv->mite->daq_io_addr + Chip_Version)); - - s = dev->subdevices + 0; - - dev->read_subdev = s; - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = - SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL | SDF_PACKED | - SDF_CMD_READ; - s->n_chan = 32; - s->range_table = &range_digital; - s->maxdata = 1; - s->insn_config = &ni_pcidio_insn_config; - s->insn_bits = &ni_pcidio_insn_bits; - s->do_cmd = &ni_pcidio_cmd; - s->do_cmdtest = &ni_pcidio_cmdtest; - s->cancel = &ni_pcidio_cancel; - s->len_chanlist = 32; /* XXX */ - s->buf_change = &ni_pcidio_change; - s->async_dma_dir = DMA_BIDIRECTIONAL; - s->poll = &ni_pcidio_poll; - - writel(0, devpriv->mite->daq_io_addr + Port_IO(0)); - writel(0, devpriv->mite->daq_io_addr + Port_Pin_Directions(0)); - writel(0, devpriv->mite->daq_io_addr + Port_Pin_Mask(0)); - - /* disable interrupts on board */ - writeb(0x00, - devpriv->mite->daq_io_addr + - Master_DMA_And_Interrupt_Control); - - ret = request_irq(irq, nidio_interrupt, IRQF_SHARED, - "ni_pcidio", dev); - if (ret < 0) - printk(KERN_WARNING " irq not available"); + dev_info(dev->class_dev, "%s rev=%d\n", dev->board_name, + readb(devpriv->mite->daq_io_addr + Chip_Version)); + + s = &dev->subdevices[0]; + + dev->read_subdev = s; + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = + SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL | SDF_PACKED | + SDF_CMD_READ; + s->n_chan = 32; + s->range_table = &range_digital; + s->maxdata = 1; + s->insn_config = &ni_pcidio_insn_config; + s->insn_bits = &ni_pcidio_insn_bits; + s->do_cmd = &ni_pcidio_cmd; + s->do_cmdtest = &ni_pcidio_cmdtest; + s->cancel = &ni_pcidio_cancel; + s->len_chanlist = 32; /* XXX */ + s->buf_change = &ni_pcidio_change; + s->async_dma_dir = DMA_BIDIRECTIONAL; + s->poll = &ni_pcidio_poll; + + writel(0, devpriv->mite->daq_io_addr + Port_IO(0)); + writel(0, devpriv->mite->daq_io_addr + Port_Pin_Directions(0)); + writel(0, devpriv->mite->daq_io_addr + Port_Pin_Mask(0)); + + /* disable interrupts on board */ + writeb(0x00, + devpriv->mite->daq_io_addr + + Master_DMA_And_Interrupt_Control); - dev->irq = irq; - } + ret = request_irq(irq, nidio_interrupt, IRQF_SHARED, + "ni_pcidio", dev); + if (ret < 0) + dev_warn(dev->class_dev, "irq not available\n"); - printk("\n"); + dev->irq = irq; return 0; } static void nidio_detach(struct comedi_device *dev) { - int i; - - if (this_board && !this_board->is_diodaq) { - for (i = 0; i < this_board->n_8255; i++) - subdev_8255_cleanup(dev, dev->subdevices + i); - } if (dev->irq) free_irq(dev->irq, dev); if (devpriv) { @@ -1320,15 +1191,17 @@ static void nidio_detach(struct comedi_device *dev) mite_free_ring(devpriv->di_mite_ring); devpriv->di_mite_ring = NULL; } - if (devpriv->mite) + if (devpriv->mite) { mite_unsetup(devpriv->mite); + mite_free(devpriv->mite); + } } } static struct comedi_driver ni_pcidio_driver = { .driver_name = "ni_pcidio", .module = THIS_MODULE, - .attach = nidio_attach, + .attach_pci = nidio_attach_pci, .detach = nidio_detach, }; @@ -1347,13 +1220,6 @@ static DEFINE_PCI_DEVICE_TABLE(ni_pcidio_pci_table) = { { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1150) }, { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1320) }, { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x12b0) }, - { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0160) }, - { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1630) }, - { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x13c0) }, - { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x0400) }, - { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1250) }, - { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x17d0) }, - { PCI_DEVICE(PCI_VENDOR_ID_NI, 0x1800) }, { 0 } }; MODULE_DEVICE_TABLE(pci, ni_pcidio_pci_table); diff --git a/drivers/staging/comedi/drivers/ni_pcimio.c b/drivers/staging/comedi/drivers/ni_pcimio.c index 89f4d43c6d08..f284a90720ec 100644 --- a/drivers/staging/comedi/drivers/ni_pcimio.c +++ b/drivers/staging/comedi/drivers/ni_pcimio.c @@ -1188,8 +1188,6 @@ static const struct ni_board_struct ni_boards[] = { }, }; -#define n_pcimio_boards ARRAY_SIZE(ni_boards) - struct ni_private { NI_PRIVATE_COMMON}; #define devpriv ((struct ni_private *)dev->private) @@ -1502,7 +1500,6 @@ static uint32_t m_series_stc_readl(struct comedi_device *dev, int reg) #include "ni_mio_common.c" -static int pcimio_find_device(struct comedi_device *dev, int bus, int slot); static int pcimio_ai_change(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size); static int pcimio_ao_change(struct comedi_device *dev, @@ -1584,24 +1581,45 @@ static void pcimio_detach(struct comedi_device *dev) mite_free_ring(devpriv->cdo_mite_ring); mite_free_ring(devpriv->gpct_mite_ring[0]); mite_free_ring(devpriv->gpct_mite_ring[1]); - if (devpriv->mite) + if (devpriv->mite) { mite_unsetup(devpriv->mite); + mite_free(devpriv->mite); + } } } -static int pcimio_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static const struct ni_board_struct * +pcimio_find_boardinfo(struct pci_dev *pcidev) +{ + unsigned int device_id = pcidev->device; + unsigned int n; + + for (n = 0; n < ARRAY_SIZE(ni_boards); n++) { + const struct ni_board_struct *board = &ni_boards[n]; + if (board->device_id == device_id) + return board; + } + return NULL; +} + +static int __devinit pcimio_attach_pci(struct comedi_device *dev, + struct pci_dev *pcidev) { int ret; - dev_info(dev->class_dev, "ni_pcimio: attach\n"); + dev_info(dev->class_dev, "ni_pcimio: attach %s\n", pci_name(pcidev)); ret = ni_alloc_private(dev); if (ret < 0) return ret; - ret = pcimio_find_device(dev, it->options[0], it->options[1]); - if (ret < 0) - return ret; + dev->board_ptr = pcimio_find_boardinfo(pcidev); + if (!dev->board_ptr) + return -ENODEV; + + devpriv->mite = mite_alloc(pcidev); + if (!devpriv->mite) + return -ENOMEM; dev_dbg(dev->class_dev, "%s\n", boardtype.name); dev->board_name = boardtype.name; @@ -1659,7 +1677,7 @@ static int pcimio_attach(struct comedi_device *dev, struct comedi_devconfig *it) } } - ret = ni_E_init(dev, it); + ret = ni_E_init(dev); if (ret < 0) return ret; @@ -1672,34 +1690,6 @@ static int pcimio_attach(struct comedi_device *dev, struct comedi_devconfig *it) return ret; } -static int pcimio_find_device(struct comedi_device *dev, int bus, int slot) -{ - struct mite_struct *mite; - int i; - - for (mite = mite_devices; mite; mite = mite->next) { - if (mite->used) - continue; - if (bus || slot) { - if (bus != mite->pcidev->bus->number || - slot != PCI_SLOT(mite->pcidev->devfn)) - continue; - } - - for (i = 0; i < n_pcimio_boards; i++) { - if (mite_device_id(mite) == ni_boards[i].device_id) { - dev->board_ptr = ni_boards + i; - devpriv->mite = mite; - - return 0; - } - } - } - pr_warn("no device found\n"); - mite_list_devices(); - return -EIO; -} - static int pcimio_ai_change(struct comedi_device *dev, struct comedi_subdevice *s, unsigned long new_size) { @@ -1765,7 +1755,7 @@ static int pcimio_dio_change(struct comedi_device *dev, static struct comedi_driver ni_pcimio_driver = { .driver_name = "ni_pcimio", .module = THIS_MODULE, - .attach = pcimio_attach, + .attach_pci = pcimio_attach_pci, .detach = pcimio_detach, }; @@ -1844,7 +1834,7 @@ static struct pci_driver ni_pcimio_pci_driver = { .probe = ni_pcimio_pci_probe, .remove = __devexit_p(ni_pcimio_pci_remove) }; -module_comedi_pci_driver(ni_pcimio_driver, ni_pcimio_pci_driver) +module_comedi_pci_driver(ni_pcimio_driver, ni_pcimio_pci_driver); MODULE_AUTHOR("Comedi http://www.comedi.org"); MODULE_DESCRIPTION("Comedi low-level driver"); diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/staging/comedi/drivers/ni_tiocmd.c index a9611587460a..8ee93d359bed 100644 --- a/drivers/staging/comedi/drivers/ni_tiocmd.c +++ b/drivers/staging/comedi/drivers/ni_tiocmd.c @@ -48,6 +48,7 @@ TODO: Support use of both banks X and Y */ +#include "comedi_fc.h" #include "ni_tio_internal.h" #include "mite.h" @@ -237,61 +238,35 @@ EXPORT_SYMBOL_GPL(ni_tio_cmd); int ni_tio_cmdtest(struct ni_gpct *counter, struct comedi_cmd *cmd) { int err = 0; - int tmp; - int sources; + unsigned int sources; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; sources = TRIG_NOW | TRIG_INT | TRIG_OTHER; if (ni_tio_counting_mode_registers_present(counter->counter_dev)) sources |= TRIG_EXT; - cmd->start_src &= sources; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_FOLLOW | TRIG_EXT | TRIG_OTHER; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - sources = TRIG_NOW | TRIG_EXT | TRIG_OTHER; - cmd->convert_src &= sources; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, sources); - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_FOLLOW | TRIG_EXT | TRIG_OTHER); + err |= cfc_check_trigger_src(&cmd->convert_src, + TRIG_NOW | TRIG_EXT | TRIG_OTHER); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique... */ + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + + /* Step 2b : and mutually compatible */ - if (cmd->start_src != TRIG_NOW && - cmd->start_src != TRIG_INT && - cmd->start_src != TRIG_EXT && cmd->start_src != TRIG_OTHER) - err++; - if (cmd->scan_begin_src != TRIG_FOLLOW && - cmd->scan_begin_src != TRIG_EXT && - cmd->scan_begin_src != TRIG_OTHER) - err++; - if (cmd->convert_src != TRIG_OTHER && - cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW) - err++; - if (cmd->stop_src != TRIG_NONE) - err++; - /* ... and mutually compatible */ if (cmd->convert_src != TRIG_NOW && cmd->scan_begin_src != TRIG_FOLLOW) - err++; + err |= -EINVAL; if (err) return 2; diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c index bb72d0bc2975..89305a14eb5c 100644 --- a/drivers/staging/comedi/drivers/pcl711.c +++ b/drivers/staging/comedi/drivers/pcl711.c @@ -64,6 +64,7 @@ supported. #include <linux/ioport.h> #include <linux/delay.h> +#include "comedi_fc.h" #include "8253.h" #define PCL711_SIZE 16 @@ -168,7 +169,7 @@ static irqreturn_t pcl711_interrupt(int irq, void *d) int data; struct comedi_device *dev = d; const struct pcl711_board *board = comedi_board(dev); - struct comedi_subdevice *s = dev->subdevices + 0; + struct comedi_subdevice *s = &dev->subdevices[0]; if (!dev->attached) { comedi_error(dev, "spurious interrupt"); @@ -266,42 +267,24 @@ static int pcl711_ai_cmdtest(struct comedi_device *dev, int tmp; int err = 0; - /* step 1 */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2 */ + /* Step 2a : make sure trigger sources are unique */ - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -520,7 +503,7 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret < 0) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* AI subdevice */ s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND; @@ -536,7 +519,7 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->do_cmd = pcl711_ai_cmd; } - s++; + s = &dev->subdevices[1]; /* AO subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; @@ -547,7 +530,7 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_write = pcl711_ao_insn; s->insn_read = pcl711_ao_insn_read; - s++; + s = &dev->subdevices[2]; /* 16-bit digital input */ s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; @@ -557,7 +540,7 @@ static int pcl711_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->range_table = &range_digital; s->insn_bits = pcl711_di_insn_bits; - s++; + s = &dev->subdevices[3]; /* 16-bit digital out */ s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE; diff --git a/drivers/staging/comedi/drivers/pcl724.c b/drivers/staging/comedi/drivers/pcl724.c index c8fe23ca899d..7b3c4293c01b 100644 --- a/drivers/staging/comedi/drivers/pcl724.c +++ b/drivers/staging/comedi/drivers/pcl724.c @@ -99,6 +99,7 @@ static int subdev_8255mapped_cb(int dir, int port, int data, static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct pcl724_board *board = comedi_board(dev); + struct comedi_subdevice *s; unsigned long iobase; unsigned int iorange; int ret, i, n_subdevices; @@ -161,14 +162,13 @@ static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it) return ret; for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; if (board->is_pet48) { - subdev_8255_init(dev, dev->subdevices + i, - subdev_8255mapped_cb, + subdev_8255_init(dev, s, subdev_8255mapped_cb, (unsigned long)(dev->iobase + i * 0x1000)); } else - subdev_8255_init(dev, dev->subdevices + i, - subdev_8255_cb, + subdev_8255_init(dev, s, subdev_8255_cb, (unsigned long)(dev->iobase + SIZE_8255 * i)); } @@ -179,10 +179,13 @@ static int pcl724_attach(struct comedi_device *dev, struct comedi_devconfig *it) static void pcl724_detach(struct comedi_device *dev) { const struct pcl724_board *board = comedi_board(dev); + struct comedi_subdevice *s; int i; - for (i = 0; i < dev->n_subdevices; i++) - subdev_8255_cleanup(dev, dev->subdevices + i); + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + subdev_8255_cleanup(dev, s); + } #ifdef PCL724_IRQ if (dev->irq) free_irq(dev->irq, dev); diff --git a/drivers/staging/comedi/drivers/pcl725.c b/drivers/staging/comedi/drivers/pcl725.c index d5b60cf7c93f..21fbc1ae1e73 100644 --- a/drivers/staging/comedi/drivers/pcl725.c +++ b/drivers/staging/comedi/drivers/pcl725.c @@ -62,7 +62,7 @@ static int pcl725_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* do */ s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE; @@ -71,7 +71,7 @@ static int pcl725_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_bits = pcl725_do_insn; s->range_table = &range_digital; - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* di */ s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c index 2b10f1d83085..07e72de982ac 100644 --- a/drivers/staging/comedi/drivers/pcl726.c +++ b/drivers/staging/comedi/drivers/pcl726.c @@ -290,7 +290,7 @@ static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* ao */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND; @@ -316,7 +316,7 @@ static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it) devpriv->bipolar[i] = 1; /* bipolar range */ } - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* di */ if (!board->have_dio) { s->type = COMEDI_SUBD_UNUSED; @@ -330,7 +330,7 @@ static int pcl726_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->range_table = &range_digital; } - s = dev->subdevices + 2; + s = &dev->subdevices[2]; /* do */ if (!board->have_dio) { s->type = COMEDI_SUBD_UNUSED; diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c index 4675ec57082e..e3de49937452 100644 --- a/drivers/staging/comedi/drivers/pcl730.c +++ b/drivers/staging/comedi/drivers/pcl730.c @@ -84,7 +84,7 @@ static int pcl730_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* Isolated do */ s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE; @@ -94,7 +94,7 @@ static int pcl730_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->range_table = &range_digital; s->private = (void *)PCL730_IDIO_LO; - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* Isolated di */ s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; @@ -104,7 +104,7 @@ static int pcl730_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->range_table = &range_digital; s->private = (void *)PCL730_IDIO_LO; - s = dev->subdevices + 2; + s = &dev->subdevices[2]; /* TTL do */ s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE; @@ -114,7 +114,7 @@ static int pcl730_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->range_table = &range_digital; s->private = (void *)PCL730_DIO_LO; - s = dev->subdevices + 3; + s = &dev->subdevices[3]; /* TTL di */ s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c index 578fd8920be1..3cf55ff93083 100644 --- a/drivers/staging/comedi/drivers/pcl812.c +++ b/drivers/staging/comedi/drivers/pcl812.c @@ -117,6 +117,7 @@ #include <linux/io.h> #include <asm/dma.h> +#include "comedi_fc.h" #include "8253.h" /* hardware types of the cards */ @@ -533,49 +534,31 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev, { const struct pcl812_board *board = comedi_board(dev); int err = 0; + unsigned int flags; int tmp, divisor1, divisor2; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_FOLLOW; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW); - tmp = cmd->convert_src; if (devpriv->use_ext_trg) - cmd->convert_src &= TRIG_EXT; + flags = TRIG_EXT; else - cmd->convert_src &= TRIG_TIMER; - - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + flags = TRIG_TIMER; + err |= cfc_check_trigger_src(&cmd->convert_src, flags); - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* - * step 2: make sure trigger sources are - * unique and mutually compatible - */ + /* Step 2a : make sure trigger sources are unique */ - if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT) - err++; + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -806,7 +789,7 @@ static irqreturn_t interrupt_pcl812_ai_int(int irq, void *d) char err = 1; unsigned int mask, timeout; struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; + struct comedi_subdevice *s = &dev->subdevices[0]; unsigned int next_chan; s->async->events = 0; @@ -909,7 +892,7 @@ static void transfer_from_dma_buf(struct comedi_device *dev, static irqreturn_t interrupt_pcl812_ai_dma(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; + struct comedi_subdevice *s = &dev->subdevices[0]; unsigned long dma_flags; int len, bufptr; short *ptr; @@ -1267,7 +1250,7 @@ no_dma: /* analog input */ if (board->n_aichan > 0) { - s = dev->subdevices + subdev; + s = &dev->subdevices[subdev]; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE; switch (board->board_type) { @@ -1409,7 +1392,7 @@ no_dma: /* analog output */ if (board->n_aochan > 0) { - s = dev->subdevices + subdev; + s = &dev->subdevices[subdev]; s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE | SDF_GROUND; s->n_chan = board->n_aochan; @@ -1438,7 +1421,7 @@ no_dma: /* digital input */ if (board->n_dichan > 0) { - s = dev->subdevices + subdev; + s = &dev->subdevices[subdev]; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; s->n_chan = board->n_dichan; @@ -1451,7 +1434,7 @@ no_dma: /* digital output */ if (board->n_dochan > 0) { - s = dev->subdevices + subdev; + s = &dev->subdevices[subdev]; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE; s->n_chan = board->n_dochan; diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c index ba6911f063cb..0822de058e4d 100644 --- a/drivers/staging/comedi/drivers/pcl816.c +++ b/drivers/staging/comedi/drivers/pcl816.c @@ -41,6 +41,7 @@ Configuration Options: #include <linux/io.h> #include <asm/dma.h> +#include "comedi_fc.h" #include "8253.h" #define DEBUG(x) x @@ -258,7 +259,7 @@ static int pcl816_ai_insn_read(struct comedi_device *dev, static irqreturn_t interrupt_pcl816_ai_mode13_int(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; + struct comedi_subdevice *s = &dev->subdevices[0]; int low, hi; int timeout = 50; /* wait max 50us */ @@ -349,7 +350,7 @@ static void transfer_from_dma_buf(struct comedi_device *dev, static irqreturn_t interrupt_pcl816_ai_mode13_dma(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; + struct comedi_subdevice *s = &dev->subdevices[0]; int len, bufptr, this_dma_buf; unsigned long dma_flags; short *ptr; @@ -458,48 +459,23 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev, pcl816_cmdtest_out(-1, cmd); ); - /* step 1: make sure trigger sources are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_FOLLOW; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_EXT | TRIG_TIMER; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_EXT | TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; + /* Step 2a : make sure trigger sources are unique */ - /* - * step 2: make sure trigger sources - * are unique and mutually compatible - */ - - if (cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_TIMER) { - cmd->convert_src = TRIG_TIMER; - err++; - } + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); - if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT) - err++; + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -1183,7 +1159,7 @@ no_dma: if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; if (board->n_aichan > 0) { s->type = COMEDI_SUBD_AI; devpriv->sub_ai = s; diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c index 34169c16fb92..d4b0859d81f2 100644 --- a/drivers/staging/comedi/drivers/pcl818.c +++ b/drivers/staging/comedi/drivers/pcl818.c @@ -107,6 +107,7 @@ A word or two about DMA. Driver support DMA operations at two ways: #include <linux/io.h> #include <asm/dma.h> +#include "comedi_fc.h" #include "8253.h" /* #define PCL818_MODE13_AO 1 */ @@ -477,7 +478,7 @@ static int pcl818_do_insn_bits(struct comedi_device *dev, static irqreturn_t interrupt_pcl818_ai_mode13_int(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; + struct comedi_subdevice *s = &dev->subdevices[0]; int low; int timeout = 50; /* wait max 50us */ @@ -536,7 +537,7 @@ conv_finish: static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; + struct comedi_subdevice *s = &dev->subdevices[0]; int i, len, bufptr; unsigned long flags; short *ptr; @@ -615,7 +616,7 @@ static irqreturn_t interrupt_pcl818_ai_mode13_dma(int irq, void *d) static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; + struct comedi_subdevice *s = &dev->subdevices[0]; unsigned long tmp; unsigned int top1, top2, i, bufptr; long ofs_dats; @@ -720,7 +721,7 @@ static irqreturn_t interrupt_pcl818_ai_mode13_dma_rtc(int irq, void *d) static irqreturn_t interrupt_pcl818_ai_mode13_fifo(int irq, void *d) { struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; + struct comedi_subdevice *s = &dev->subdevices[0]; int i, len, lo; outb(0, dev->iobase + PCL818_FI_INTCLR); /* clear fifo int request */ @@ -811,7 +812,7 @@ static irqreturn_t interrupt_pcl818(int irq, void *d) being reprogrammed while a DMA transfer is in progress. */ - struct comedi_subdevice *s = dev->subdevices + 0; + struct comedi_subdevice *s = &dev->subdevices[0]; devpriv->ai_act_scan = 0; devpriv->neverending_ai = 0; pcl818_ai_cancel(dev, s); @@ -1261,43 +1262,23 @@ static int ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, int err = 0; int tmp, divisor1 = 0, divisor2 = 0; - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_FOLLOW; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); - if (cmd->stop_src != TRIG_NONE && cmd->stop_src != TRIG_COUNT) - err++; + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -1763,7 +1744,7 @@ no_dma: if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; if (!board->n_aichan_se) { s->type = COMEDI_SUBD_UNUSED; } else { @@ -1829,7 +1810,7 @@ no_dma: } } - s = dev->subdevices + 1; + s = &dev->subdevices[1]; if (!board->n_aochan) { s->type = COMEDI_SUBD_UNUSED; } else { @@ -1862,7 +1843,7 @@ no_dma: } } - s = dev->subdevices + 2; + s = &dev->subdevices[2]; if (!board->n_dichan) { s->type = COMEDI_SUBD_UNUSED; } else { @@ -1875,7 +1856,7 @@ no_dma: s->insn_bits = pcl818_di_insn_bits; } - s = dev->subdevices + 3; + s = &dev->subdevices[3]; if (!board->n_dochan) { s->type = COMEDI_SUBD_UNUSED; } else { diff --git a/drivers/staging/comedi/drivers/pcm3724.c b/drivers/staging/comedi/drivers/pcm3724.c index 62c22ccfb780..4102547dc6a8 100644 --- a/drivers/staging/comedi/drivers/pcm3724.c +++ b/drivers/staging/comedi/drivers/pcm3724.c @@ -119,6 +119,8 @@ static int compute_buffer(int config, int devno, struct comedi_subdevice *s) static void do_3724_config(struct comedi_device *dev, struct comedi_subdevice *s, int chanspec) { + struct comedi_subdevice *s_dio1 = &dev->subdevices[0]; + struct comedi_subdevice *s_dio2 = &dev->subdevices[1]; int config; int buffer_config; unsigned long port_8255_cfg; @@ -136,10 +138,10 @@ static void do_3724_config(struct comedi_device *dev, if (!(s->io_bits & 0xff0000)) config |= CR_C_IO; - buffer_config = compute_buffer(0, 0, dev->subdevices); - buffer_config = compute_buffer(buffer_config, 1, (dev->subdevices) + 1); + buffer_config = compute_buffer(0, 0, s_dio1); + buffer_config = compute_buffer(buffer_config, 1, s_dio2); - if (s == dev->subdevices) + if (s == s_dio1) port_8255_cfg = dev->iobase + _8255_CR; else port_8255_cfg = dev->iobase + SIZE_8255 + _8255_CR; @@ -154,6 +156,7 @@ static void do_3724_config(struct comedi_device *dev, static void enable_chan(struct comedi_device *dev, struct comedi_subdevice *s, int chanspec) { + struct comedi_subdevice *s_dio1 = &dev->subdevices[0]; unsigned int mask; int gatecfg; struct priv_pcm3724 *priv; @@ -162,9 +165,9 @@ static void enable_chan(struct comedi_device *dev, struct comedi_subdevice *s, priv = dev->private; mask = 1 << CR_CHAN(chanspec); - if (s == dev->subdevices) /* subdev 0 */ + if (s == s_dio1) priv->dio_1 |= mask; - else /* subdev 1 */ + else priv->dio_2 |= mask; if (priv->dio_1 & 0xff0000) @@ -231,6 +234,7 @@ static int pcm3724_attach(struct comedi_device *dev, struct comedi_devconfig *it) { const struct pcm3724_board *board = comedi_board(dev); + struct comedi_subdevice *s; unsigned long iobase; unsigned int iorange; int ret, i, n_subdevices; @@ -263,9 +267,10 @@ static int pcm3724_attach(struct comedi_device *dev, return ret; for (i = 0; i < dev->n_subdevices; i++) { - subdev_8255_init(dev, dev->subdevices + i, subdev_8255_cb, + s = &dev->subdevices[i]; + subdev_8255_init(dev, s, subdev_8255_cb, (unsigned long)(dev->iobase + SIZE_8255 * i)); - ((dev->subdevices) + i)->insn_config = subdev_3724_insn_config; + s->insn_config = subdev_3724_insn_config; } return 0; } @@ -273,11 +278,14 @@ static int pcm3724_attach(struct comedi_device *dev, static void pcm3724_detach(struct comedi_device *dev) { const struct pcm3724_board *board = comedi_board(dev); + struct comedi_subdevice *s; int i; if (dev->subdevices) { - for (i = 0; i < dev->n_subdevices; i++) - subdev_8255_cleanup(dev, dev->subdevices + i); + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; + subdev_8255_cleanup(dev, s); + } } if (dev->iobase) release_region(dev->iobase, board->io_range); diff --git a/drivers/staging/comedi/drivers/pcm3730.c b/drivers/staging/comedi/drivers/pcm3730.c index d65e0bda2c44..067f14d22610 100644 --- a/drivers/staging/comedi/drivers/pcm3730.c +++ b/drivers/staging/comedi/drivers/pcm3730.c @@ -72,7 +72,7 @@ static int pcm3730_attach(struct comedi_device *dev, if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE; s->maxdata = 1; @@ -81,7 +81,7 @@ static int pcm3730_attach(struct comedi_device *dev, s->range_table = &range_digital; s->private = (void *)PCM3730_DOA; - s = dev->subdevices + 1; + s = &dev->subdevices[1]; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE; s->maxdata = 1; @@ -90,7 +90,7 @@ static int pcm3730_attach(struct comedi_device *dev, s->range_table = &range_digital; s->private = (void *)PCM3730_DOB; - s = dev->subdevices + 2; + s = &dev->subdevices[2]; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE; s->maxdata = 1; @@ -99,7 +99,7 @@ static int pcm3730_attach(struct comedi_device *dev, s->range_table = &range_digital; s->private = (void *)PCM3730_DOC; - s = dev->subdevices + 3; + s = &dev->subdevices[3]; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; s->maxdata = 1; @@ -108,7 +108,7 @@ static int pcm3730_attach(struct comedi_device *dev, s->range_table = &range_digital; s->private = (void *)PCM3730_DIA; - s = dev->subdevices + 4; + s = &dev->subdevices[4]; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; s->maxdata = 1; @@ -117,7 +117,7 @@ static int pcm3730_attach(struct comedi_device *dev, s->range_table = &range_digital; s->private = (void *)PCM3730_DIB; - s = dev->subdevices + 5; + s = &dev->subdevices[5]; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; s->maxdata = 1; diff --git a/drivers/staging/comedi/drivers/pcm_common.c b/drivers/staging/comedi/drivers/pcm_common.c index 474af7bc6c8b..85ee05ece9c8 100644 --- a/drivers/staging/comedi/drivers/pcm_common.c +++ b/drivers/staging/comedi/drivers/pcm_common.c @@ -1,60 +1,30 @@ #include "../comedidev.h" + +#include "comedi_fc.h" #include "pcm_common.h" -/* - * 'do_cmdtest' function for an 'INTERRUPT' subdevice. This is for - * the PCM drivers. - */ int comedi_pcm_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { int err = 0; - unsigned int tmp; - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= (TRIG_NOW | TRIG_INT); - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->stop_src; - cmd->stop_src &= (TRIG_COUNT | TRIG_NONE); - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and - * mutually compatible */ + /* Step 2a : make sure trigger sources are unique */ - /* these tests are true if more than one _src bit is set */ - if ((cmd->start_src & (cmd->start_src - 1)) != 0) - err++; - if ((cmd->scan_begin_src & (cmd->scan_begin_src - 1)) != 0) - err++; - if ((cmd->convert_src & (cmd->convert_src - 1)) != 0) - err++; - if ((cmd->scan_end_src & (cmd->scan_end_src - 1)) != 0) - err++; - if ((cmd->stop_src & (cmd->stop_src - 1)) != 0) - err++; + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c index 54d19c943967..5efeb9205c2e 100644 --- a/drivers/staging/comedi/drivers/pcmad.c +++ b/drivers/staging/comedi/drivers/pcmad.c @@ -127,7 +127,7 @@ static int pcmad_attach(struct comedi_device *dev, struct comedi_devconfig *it) dev->board_name = board->name; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | AREF_GROUND; s->n_chan = 16; /* XXX */ diff --git a/drivers/staging/comedi/drivers/pcmda12.c b/drivers/staging/comedi/drivers/pcmda12.c index 291ce7c1bdb1..28af8f6873eb 100644 --- a/drivers/staging/comedi/drivers/pcmda12.c +++ b/drivers/staging/comedi/drivers/pcmda12.c @@ -195,7 +195,7 @@ static int pcmda12_attach(struct comedi_device *dev, if (ret) return ret; - s = dev->subdevices; + s = &dev->subdevices[0]; s->private = NULL; s->maxdata = (0x1 << BITS) - 1; s->range_table = &pcmda12_ranges; diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c index 3d2e6f01c4b7..a10bf0a2987f 100644 --- a/drivers/staging/comedi/drivers/pcmmio.c +++ b/drivers/staging/comedi/drivers/pcmmio.c @@ -526,6 +526,7 @@ static irqreturn_t interrupt_pcmmio(int irq, void *d) { int asic, got1 = 0; struct comedi_device *dev = (struct comedi_device *)d; + int i; for (asic = 0; asic < MAX_ASICS; ++asic) { if (irq == devpriv->asics[asic].irq) { @@ -583,9 +584,8 @@ static irqreturn_t interrupt_pcmmio(int irq, void *d) printk (KERN_DEBUG "got edge detect interrupt %d asic %d which_chans: %06x\n", irq, asic, triggered); - for (s = dev->subdevices + 2; - s < dev->subdevices + dev->n_subdevices; - ++s) { + for (i = 2; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; /* * this is an interrupt subdev, * and it matches this asic! @@ -1076,9 +1076,8 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it) return ret; /* First, AI */ - sdev_no = 0; - s = dev->subdevices + sdev_no; - s->private = devpriv->sprivs + sdev_no; + s = &dev->subdevices[0]; + s->private = &devpriv->sprivs[0]; s->maxdata = (1 << board->ai_bits) - 1; s->range_table = board->ai_range_table; s->subdev_flags = SDF_READABLE | SDF_GROUND | SDF_DIFF; @@ -1092,9 +1091,8 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it) outb(0, subpriv->iobase + 4 + 3); /* Next, AO */ - ++sdev_no; - s = dev->subdevices + sdev_no; - s->private = devpriv->sprivs + sdev_no; + s = &dev->subdevices[1]; + s->private = &devpriv->sprivs[1]; s->maxdata = (1 << board->ao_bits) - 1; s->range_table = board->ao_range_table; s->subdev_flags = SDF_READABLE; @@ -1108,14 +1106,13 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it) outb(0, subpriv->iobase + 3); outb(0, subpriv->iobase + 4 + 3); - ++sdev_no; port = 0; asic = 0; - for (; sdev_no < (int)dev->n_subdevices; ++sdev_no) { + for (sdev_no = 2; sdev_no < dev->n_subdevices; ++sdev_no) { int byte_no; - s = dev->subdevices + sdev_no; - s->private = devpriv->sprivs + sdev_no; + s = &dev->subdevices[sdev_no]; + s->private = &devpriv->sprivs[sdev_no]; s->maxdata = 1; s->range_table = &range_digital; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; @@ -1200,15 +1197,6 @@ static int pcmmio_attach(struct comedi_device *dev, struct comedi_devconfig *it) * multiple irqs.. */ - if (irq[0]) { - printk(KERN_DEBUG "comedi%d: irq: %u\n", dev->minor, irq[0]); - if (board->dio_num_asics == 2 && irq[1]) - printk(KERN_DEBUG "comedi%d: second ASIC irq: %u\n", - dev->minor, irq[1]); - } else { - printk(KERN_INFO "comedi%d: (IRQ mode disabled)\n", dev->minor); - } - printk(KERN_INFO "comedi%d: attached\n", dev->minor); return 1; diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c index feef3d02f35a..0e32119bc3f9 100644 --- a/drivers/staging/comedi/drivers/pcmuio.c +++ b/drivers/staging/comedi/drivers/pcmuio.c @@ -442,7 +442,7 @@ static void pcmuio_stop_intr(struct comedi_device *dev, subpriv->intr.enabled_mask = 0; subpriv->intr.active = 0; - s->async->inttrig = 0; + s->async->inttrig = NULL; nports = subpriv->intr.num_asic_chans / CHANS_PER_PORT; firstport = subpriv->intr.asic_chan / CHANS_PER_PORT; switch_page(dev, asic, PAGE_ENAB); @@ -456,6 +456,7 @@ static irqreturn_t interrupt_pcmuio(int irq, void *d) { int asic, got1 = 0; struct comedi_device *dev = (struct comedi_device *)d; + int i; for (asic = 0; asic < MAX_ASICS; ++asic) { if (irq == devpriv->asics[asic].irq) { @@ -507,9 +508,8 @@ static irqreturn_t interrupt_pcmuio(int irq, void *d) printk ("PCMUIO DEBUG: got edge detect interrupt %d asic %d which_chans: %06x\n", irq, asic, triggered); - for (s = dev->subdevices; - s < dev->subdevices + dev->n_subdevices; - ++s) { + for (i = 0; i < dev->n_subdevices; i++) { + s = &dev->subdevices[i]; if (subpriv->intr.asic == asic) { /* this is an interrupt subdev, and it matches this asic! */ unsigned long flags; unsigned oldevents; @@ -683,7 +683,7 @@ pcmuio_inttrig_start_intr(struct comedi_device *dev, struct comedi_subdevice *s, return -EINVAL; spin_lock_irqsave(&subpriv->intr.spinlock, flags); - s->async->inttrig = 0; + s->async->inttrig = NULL; if (subpriv->intr.active) event = pcmuio_start_intr(dev, s); @@ -811,8 +811,8 @@ static int pcmuio_attach(struct comedi_device *dev, struct comedi_devconfig *it) for (sdev_no = 0; sdev_no < (int)dev->n_subdevices; ++sdev_no) { int byte_no; - s = dev->subdevices + sdev_no; - s->private = devpriv->sprivs + sdev_no; + s = &dev->subdevices[sdev_no]; + s->private = &devpriv->sprivs[sdev_no]; s->maxdata = 1; s->range_table = &range_digital; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; diff --git a/drivers/staging/comedi/drivers/poc.c b/drivers/staging/comedi/drivers/poc.c index c253bb9ef335..78dfe167b147 100644 --- a/drivers/staging/comedi/drivers/poc.c +++ b/drivers/staging/comedi/drivers/poc.c @@ -164,7 +164,7 @@ static int poc_attach(struct comedi_device *dev, struct comedi_devconfig *it) return -ENOMEM; /* analog output subdevice */ - s = dev->subdevices + 0; + s = &dev->subdevices[0]; s->type = board->type; s->n_chan = board->n_chan; s->maxdata = (1 << board->n_bits) - 1; diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c index a029147c9b69..3e276f7a3380 100644 --- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c +++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c @@ -56,6 +56,8 @@ Devices: [Quatech] DAQP-208 (daqp), DAQP-308 #include <linux/completion.h> +#include "comedi_fc.h" + /* Maximum number of separate DAQP devices we'll allow */ #define MAX_DEV 4 @@ -456,51 +458,26 @@ static int daqp_ai_cmdtest(struct comedi_device *dev, int err = 0; int tmp; - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->convert_src, + TRIG_TIMER | TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* - * step 2: make sure trigger sources - * are unique and mutually compatible - */ + /* Step 2a : make sure trigger sources are unique */ - /* note that mutual compatibility is not an issue here */ - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_FOLLOW) - err++; - if (cmd->convert_src != TRIG_NOW && cmd->convert_src != TRIG_TIMER) - err++; - if (cmd->scan_begin_src == TRIG_FOLLOW && cmd->convert_src == TRIG_NOW) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -878,7 +855,7 @@ static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it) printk(KERN_INFO "comedi%d: attaching daqp%d (io 0x%04lx)\n", dev->minor, it->options[0], dev->iobase); - s = dev->subdevices + 0; + s = &dev->subdevices[0]; dev->read_subdev = s; s->private = local; s->type = COMEDI_SUBD_AI; @@ -892,7 +869,7 @@ static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->do_cmd = daqp_ai_cmd; s->cancel = daqp_ai_cancel; - s = dev->subdevices + 1; + s = &dev->subdevices[1]; dev->write_subdev = s; s->private = local; s->type = COMEDI_SUBD_AO; @@ -903,7 +880,7 @@ static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->range_table = &range_daqp_ao; s->insn_write = daqp_ao_insn_write; - s = dev->subdevices + 2; + s = &dev->subdevices[2]; s->private = local; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; @@ -911,7 +888,7 @@ static int daqp_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->len_chanlist = 1; s->insn_read = daqp_di_insn_read; - s = dev->subdevices + 3; + s = &dev->subdevices[3]; s->private = local; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITEABLE; diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c index 5aa8be1e7b92..41d24b08913b 100644 --- a/drivers/staging/comedi/drivers/rtd520.c +++ b/drivers/staging/comedi/drivers/rtd520.c @@ -106,6 +106,8 @@ Configuration options: #include "../comedidev.h" +#include "comedi_fc.h" + #define DRV_NAME "rtd520" /*====================================================================== @@ -783,7 +785,7 @@ static irqreturn_t rtd_interrupt(int irq, /* interrupt number (ignored) */ void *d) { /* our data *//* cpu context (ignored) */ struct comedi_device *dev = d; - struct comedi_subdevice *s = dev->subdevices + 0; /* analog in subdevice */ + struct comedi_subdevice *s = &dev->subdevices[0]; struct rtdPrivate *devpriv = dev->private; u32 overrun; u16 status; @@ -964,7 +966,7 @@ static int rtd_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s) /* cmdtest tests a particular command to see if it is valid. Using the cmdtest ioctl, a user can create a valid cmd - and then have it executed by the cmd ioctl (asyncronously). + and then have it executed by the cmd ioctl (asynchronously). cmdtest returns 1,2,3,4 or 0, depending on which tests the command passes. @@ -976,52 +978,25 @@ static int rtd_ai_cmdtest(struct comedi_device *dev, int err = 0; int tmp; - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + /* Step 1 : check if triggers are trivially valid */ + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique - and mutually compatible */ - /* note that mutual compatibility is not an issue here */ - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT) { - err++; - } - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; + /* Step 2a : make sure trigger sources are unique */ - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -1706,7 +1681,7 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; dev->read_subdev = s; /* analog input subdevice */ s->type = COMEDI_SUBD_AI; @@ -1726,7 +1701,7 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->cancel = rtd_ai_cancel; /* s->poll = rtd_ai_poll; *//* not ready yet */ - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* analog output subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; @@ -1736,7 +1711,7 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_write = rtd_ao_winsn; s->insn_read = rtd_ao_rinsn; - s = dev->subdevices + 2; + s = &dev->subdevices[2]; /* digital i/o subdevice */ s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; @@ -1748,7 +1723,7 @@ static int rtd_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_config = rtd_dio_insn_config; /* timer/counter subdevices (not currently supported) */ - s = dev->subdevices + 3; + s = &dev->subdevices[3]; s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = 3; diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c index f7fa940d9783..137885b1681a 100644 --- a/drivers/staging/comedi/drivers/rti800.c +++ b/drivers/staging/comedi/drivers/rti800.c @@ -360,7 +360,7 @@ static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it) devpriv->dac1_coding = it->options[8]; devpriv->muxgain_bits = -1; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* ai subdevice */ s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND; @@ -379,7 +379,7 @@ static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it) break; } - s++; + s = &dev->subdevices[1]; if (board->has_ao) { /* ao subdevice (only on rti815) */ s->type = COMEDI_SUBD_AO; @@ -409,7 +409,7 @@ static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->type = COMEDI_SUBD_UNUSED; } - s++; + s = &dev->subdevices[2]; /* di */ s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; @@ -418,7 +418,7 @@ static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = 1; s->range_table = &range_digital; - s++; + s = &dev->subdevices[3]; /* do */ s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITABLE; @@ -429,7 +429,7 @@ static int rti800_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* don't yet know how to deal with counter/timers */ #if 0 - s++; + s = &dev->subdevices[4]; /* do */ s->type = COMEDI_SUBD_TIMER; #endif diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c index fc16508181d4..3f9d0278be50 100644 --- a/drivers/staging/comedi/drivers/rti802.c +++ b/drivers/staging/comedi/drivers/rti802.c @@ -111,7 +111,7 @@ static int rti802_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - s = dev->subdevices; + s = &dev->subdevices[0]; /* ao subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; diff --git a/drivers/staging/comedi/drivers/s526.c b/drivers/staging/comedi/drivers/s526.c index 737a194dfce3..a1e256293bd6 100644 --- a/drivers/staging/comedi/drivers/s526.c +++ b/drivers/staging/comedi/drivers/s526.c @@ -83,36 +83,6 @@ comedi_config /dev/comedi0 s526 0x2C0,0x3 #define REG_EED 0x32 #define REG_EEC 0x34 -static const int s526_ports[] = { - REG_TCR, - REG_WDC, - REG_DAC, - REG_ADC, - REG_ADD, - REG_DIO, - REG_IER, - REG_ISR, - REG_MSC, - REG_C0L, - REG_C0H, - REG_C0M, - REG_C0C, - REG_C1L, - REG_C1H, - REG_C1M, - REG_C1C, - REG_C2L, - REG_C2H, - REG_C2M, - REG_C2C, - REG_C3L, - REG_C3H, - REG_C3M, - REG_C3C, - REG_EED, - REG_EEC -}; - struct counter_mode_register_t { #if defined(__LITTLE_ENDIAN_BITFIELD) unsigned short coutSource:1; @@ -148,122 +118,48 @@ union cmReg { unsigned short value; }; -#define MAX_GPCT_CONFIG_DATA 6 - -/* Different Application Classes for GPCT Subdevices */ -/* The list is not exhaustive and needs discussion! */ -enum S526_GPCT_APP_CLASS { - CountingAndTimeMeasurement, - SinglePulseGeneration, - PulseTrainGeneration, - PositionMeasurement, - Miscellaneous -}; - -/* Config struct for different GPCT subdevice Application Classes and - their options -*/ -struct s526GPCTConfig { - enum S526_GPCT_APP_CLASS app; - int data[MAX_GPCT_CONFIG_DATA]; -}; - -/* - * Board descriptions for two imaginary boards. Describing the - * boards in this way is optional, and completely driver-dependent. - * Some drivers use arrays such as this, other do not. - */ -struct s526_board { - const char *name; - int gpct_chans; - int gpct_bits; - int ad_chans; - int ad_bits; - int da_chans; - int da_bits; - int have_dio; -}; - -static const struct s526_board s526_boards[] = { - { - .name = "s526", - .gpct_chans = 4, - .gpct_bits = 24, - .ad_chans = 8, - .ad_bits = 16, - .da_chans = 4, - .da_bits = 16, - .have_dio = 1, - } -}; - -#define ADDR_REG(reg) (dev->iobase + (reg)) -#define ADDR_CHAN_REG(reg, chan) (dev->iobase + (reg) + (chan) * 8) - -/* this structure is for data unique to this hardware driver. If - several hardware drivers keep similar information in this structure, - feel free to suggest moving the variable to the struct comedi_device - struct. -*/ struct s526_private { unsigned int ao_readback[2]; - struct s526GPCTConfig s526_gpct_config[4]; - unsigned short s526_ai_config; + unsigned int gpct_config[4]; + unsigned short ai_config; }; -/* - * most drivers define the following macro to make it easy to - * access the private structure. - */ -#define devpriv ((struct s526_private *)dev->private) - static int s526_gpct_rinsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - int i; /* counts the Data */ - int counter_channel = CR_CHAN(insn->chanspec); - unsigned short datalow; - unsigned short datahigh; - - /* Check if (n > 0) */ - if (insn->n <= 0) { - printk(KERN_ERR "s526: INSN_READ: n should be > 0\n"); - return -EINVAL; - } - /* Read the low word first */ + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned long chan_iobase = dev->iobase + chan * 8; + unsigned int lo; + unsigned int hi; + int i; + for (i = 0; i < insn->n; i++) { - datalow = inw(ADDR_CHAN_REG(REG_C0L, counter_channel)); - datahigh = inw(ADDR_CHAN_REG(REG_C0H, counter_channel)); - data[i] = (int)(datahigh & 0x00FF); - data[i] = (data[i] << 16) | (datalow & 0xFFFF); - /* printk("s526 GPCT[%d]: %x(0x%04x, 0x%04x)\n", - counter_channel, data[i], datahigh, datalow); */ + /* Read the low word first */ + lo = inw(chan_iobase + REG_C0L) & 0xffff; + hi = inw(chan_iobase + REG_C0H) & 0xff; + + data[i] = (hi << 16) | lo; } - return i; + + return insn->n; } static int s526_gpct_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, - struct comedi_insn *insn, unsigned int *data) + struct comedi_insn *insn, + unsigned int *data) { - int subdev_channel = CR_CHAN(insn->chanspec); /* Unpack chanspec */ - int i; - short value; + struct s526_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned long chan_iobase = dev->iobase + chan * 8; + unsigned int val; union cmReg cmReg; - /* printk("s526: GPCT_INSN_CONFIG: Configuring Channel %d\n", - subdev_channel); */ - - for (i = 0; i < MAX_GPCT_CONFIG_DATA; i++) { - devpriv->s526_gpct_config[subdev_channel].data[i] = - insn->data[i]; -/* printk("data[%d]=%x\n", i, insn->data[i]); */ - } - /* Check what type of Counter the user requested, data[0] contains */ /* the Application type */ - switch (insn->data[0]) { + switch (data[0]) { case INSN_CONFIG_GPCT_QUADRATURE_ENCODER: /* data[0]: Application Type @@ -271,9 +167,7 @@ static int s526_gpct_insn_config(struct comedi_device *dev, data[2]: Pre-load Register Value data[3]: Conter Control Register */ - printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring Encoder\n"); - devpriv->s526_gpct_config[subdev_channel].app = - PositionMeasurement; + devpriv->gpct_config[chan] = data[0]; #if 0 /* Example of Counter Application */ @@ -290,34 +184,32 @@ static int s526_gpct_insn_config(struct comedi_device *dev, cmReg.reg.preloadRegSel = 0; /* PR0 */ cmReg.reg.reserved = 0; - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); + outw(cmReg.value, chan_iobase + REG_C0M); - outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel)); - outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel)); + outw(0x0001, chan_iobase + REG_C0H); + outw(0x3C68, chan_iobase + REG_C0L); /* Reset the counter */ - outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + outw(0x8000, chan_iobase + REG_C0C); /* Load the counter from PR0 */ - outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + outw(0x4000, chan_iobase + REG_C0C); /* Reset RCAP (fires one-shot) */ - outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + outw(0x0008, chan_iobase + REG_C0C); #endif #if 1 /* Set Counter Mode Register */ - cmReg.value = insn->data[1] & 0xFFFF; - -/* printk("s526: Counter Mode register=%x\n", cmReg.value); */ - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); + cmReg.value = data[1] & 0xffff; + outw(cmReg.value, chan_iobase + REG_C0M); /* Reset the counter if it is software preload */ if (cmReg.reg.autoLoadResetRcap == 0) { /* Reset the counter */ - outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + outw(0x8000, chan_iobase + REG_C0C); /* Load the counter from PR0 - * outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + * outw(0x4000, chan_iobase + REG_C0C); */ } #else @@ -325,47 +217,47 @@ static int s526_gpct_insn_config(struct comedi_device *dev, cmReg.reg.countDirCtrl = 0; /* data[1] contains GPCT_X1, GPCT_X2 or GPCT_X4 */ - if (insn->data[1] == GPCT_X2) + if (data[1] == GPCT_X2) cmReg.reg.clockSource = 1; - else if (insn->data[1] == GPCT_X4) + else if (data[1] == GPCT_X4) cmReg.reg.clockSource = 2; else cmReg.reg.clockSource = 0; /* When to take into account the indexpulse: */ - /*if (insn->data[2] == GPCT_IndexPhaseLowLow) { - } else if (insn->data[2] == GPCT_IndexPhaseLowHigh) { - } else if (insn->data[2] == GPCT_IndexPhaseHighLow) { - } else if (insn->data[2] == GPCT_IndexPhaseHighHigh) { + /*if (data[2] == GPCT_IndexPhaseLowLow) { + } else if (data[2] == GPCT_IndexPhaseLowHigh) { + } else if (data[2] == GPCT_IndexPhaseHighLow) { + } else if (data[2] == GPCT_IndexPhaseHighHigh) { }*/ /* Take into account the index pulse? */ - if (insn->data[3] == GPCT_RESET_COUNTER_ON_INDEX) + if (data[3] == GPCT_RESET_COUNTER_ON_INDEX) /* Auto load with INDEX^ */ cmReg.reg.autoLoadResetRcap = 4; /* Set Counter Mode Register */ - cmReg.value = (short)(insn->data[1] & 0xFFFF); - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); + cmReg.value = data[1] & 0xffff; + outw(cmReg.value, chan_iobase + REG_C0M); /* Load the pre-load register high word */ - value = (short)((insn->data[2] >> 16) & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); + val = (data[2] >> 16) & 0xffff; + outw(val, chan_iobase + REG_C0H); /* Load the pre-load register low word */ - value = (short)(insn->data[2] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); + val = data[2] & 0xffff; + outw(val, chan_iobase + REG_C0L); /* Write the Counter Control Register */ - if (insn->data[3] != 0) { - value = (short)(insn->data[3] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + if (data[3]) { + val = data[3] & 0xffff; + outw(val, chan_iobase + REG_C0C); } /* Reset the counter if it is software preload */ if (cmReg.reg.autoLoadResetRcap == 0) { /* Reset the counter */ - outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + outw(0x8000, chan_iobase + REG_C0C); /* Load the counter from PR0 */ - outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + outw(0x4000, chan_iobase + REG_C0C); } #endif break; @@ -378,40 +270,38 @@ static int s526_gpct_insn_config(struct comedi_device *dev, data[3]: Pre-load Register 1 Value data[4]: Conter Control Register */ - printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring SPG\n"); - devpriv->s526_gpct_config[subdev_channel].app = - SinglePulseGeneration; + devpriv->gpct_config[chan] = data[0]; /* Set Counter Mode Register */ - cmReg.value = (short)(insn->data[1] & 0xFFFF); + cmReg.value = data[1] & 0xffff; cmReg.reg.preloadRegSel = 0; /* PR0 */ - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); + outw(cmReg.value, chan_iobase + REG_C0M); /* Load the pre-load register 0 high word */ - value = (short)((insn->data[2] >> 16) & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); + val = (data[2] >> 16) & 0xffff; + outw(val, chan_iobase + REG_C0H); /* Load the pre-load register 0 low word */ - value = (short)(insn->data[2] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); + val = data[2] & 0xffff; + outw(val, chan_iobase + REG_C0L); /* Set Counter Mode Register */ - cmReg.value = (short)(insn->data[1] & 0xFFFF); + cmReg.value = data[1] & 0xffff; cmReg.reg.preloadRegSel = 1; /* PR1 */ - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); + outw(cmReg.value, chan_iobase + REG_C0M); /* Load the pre-load register 1 high word */ - value = (short)((insn->data[3] >> 16) & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); + val = (data[3] >> 16) & 0xffff; + outw(val, chan_iobase + REG_C0H); /* Load the pre-load register 1 low word */ - value = (short)(insn->data[3] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); + val = data[3] & 0xffff; + outw(val, chan_iobase + REG_C0L); /* Write the Counter Control Register */ - if (insn->data[4] != 0) { - value = (short)(insn->data[4] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + if (data[4]) { + val = data[4] & 0xffff; + outw(val, chan_iobase + REG_C0C); } break; @@ -423,45 +313,42 @@ static int s526_gpct_insn_config(struct comedi_device *dev, data[3]: Pre-load Register 1 Value data[4]: Conter Control Register */ - printk(KERN_INFO "s526: GPCT_INSN_CONFIG: Configuring PTG\n"); - devpriv->s526_gpct_config[subdev_channel].app = - PulseTrainGeneration; + devpriv->gpct_config[chan] = data[0]; /* Set Counter Mode Register */ - cmReg.value = (short)(insn->data[1] & 0xFFFF); + cmReg.value = data[1] & 0xffff; cmReg.reg.preloadRegSel = 0; /* PR0 */ - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); + outw(cmReg.value, chan_iobase + REG_C0M); /* Load the pre-load register 0 high word */ - value = (short)((insn->data[2] >> 16) & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); + val = (data[2] >> 16) & 0xffff; + outw(val, chan_iobase + REG_C0H); /* Load the pre-load register 0 low word */ - value = (short)(insn->data[2] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); + val = data[2] & 0xffff; + outw(val, chan_iobase + REG_C0L); /* Set Counter Mode Register */ - cmReg.value = (short)(insn->data[1] & 0xFFFF); + cmReg.value = data[1] & 0xffff; cmReg.reg.preloadRegSel = 1; /* PR1 */ - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); + outw(cmReg.value, chan_iobase + REG_C0M); /* Load the pre-load register 1 high word */ - value = (short)((insn->data[3] >> 16) & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); + val = (data[3] >> 16) & 0xffff; + outw(val, chan_iobase + REG_C0H); /* Load the pre-load register 1 low word */ - value = (short)(insn->data[3] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); + val = data[3] & 0xffff; + outw(val, chan_iobase + REG_C0L); /* Write the Counter Control Register */ - if (insn->data[4] != 0) { - value = (short)(insn->data[4] & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0C, subdev_channel)); + if (data[4]) { + val = data[4] & 0xffff; + outw(val, chan_iobase + REG_C0C); } break; default: - printk(KERN_ERR "s526: unsupported GPCT_insn_config\n"); return -EINVAL; break; } @@ -470,65 +357,40 @@ static int s526_gpct_insn_config(struct comedi_device *dev, } static int s526_gpct_winsn(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_insn *insn, + struct comedi_subdevice *s, + struct comedi_insn *insn, unsigned int *data) { - int subdev_channel = CR_CHAN(insn->chanspec); /* Unpack chanspec */ - short value; - union cmReg cmReg; - - printk(KERN_INFO "s526: GPCT_INSN_WRITE on channel %d\n", - subdev_channel); - cmReg.value = inw(ADDR_CHAN_REG(REG_C0M, subdev_channel)); - printk(KERN_INFO "s526: Counter Mode Register: %x\n", cmReg.value); - /* Check what Application of Counter this channel is configured for */ - switch (devpriv->s526_gpct_config[subdev_channel].app) { - case PositionMeasurement: - printk(KERN_INFO "S526: INSN_WRITE: PM\n"); - outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H, - subdev_channel)); - outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel)); - break; + struct s526_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); + unsigned long chan_iobase = dev->iobase + chan * 8; - case SinglePulseGeneration: - printk(KERN_INFO "S526: INSN_WRITE: SPG\n"); - outw(0xFFFF & ((*data) >> 16), ADDR_CHAN_REG(REG_C0H, - subdev_channel)); - outw(0xFFFF & (*data), ADDR_CHAN_REG(REG_C0L, subdev_channel)); - break; + inw(chan_iobase + REG_C0M); /* Is this read required? */ - case PulseTrainGeneration: + /* Check what Application of Counter this channel is configured for */ + switch (devpriv->gpct_config[chan]) { + case INSN_CONFIG_GPCT_PULSE_TRAIN_GENERATOR: /* data[0] contains the PULSE_WIDTH data[1] contains the PULSE_PERIOD @pre PULSE_PERIOD > PULSE_WIDTH > 0 The above periods must be expressed as a multiple of the pulse frequency on the selected source */ - printk(KERN_INFO "S526: INSN_WRITE: PTG\n"); - if ((insn->data[1] > insn->data[0]) && (insn->data[0] > 0)) { - (devpriv->s526_gpct_config[subdev_channel]).data[0] = - insn->data[0]; - (devpriv->s526_gpct_config[subdev_channel]).data[1] = - insn->data[1]; - } else { - printk(KERN_ERR "s526: INSN_WRITE: PTG: Problem with Pulse params -> %d %d\n", - insn->data[0], insn->data[1]); + if ((data[1] <= data[0]) || !data[0]) return -EINVAL; - } - value = (short)((*data >> 16) & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0H, subdev_channel)); - value = (short)(*data & 0xFFFF); - outw(value, ADDR_CHAN_REG(REG_C0L, subdev_channel)); + /* Fall thru to write the PULSE_WIDTH */ + + case INSN_CONFIG_GPCT_QUADRATURE_ENCODER: + case INSN_CONFIG_GPCT_SINGLE_PULSE_GENERATOR: + outw((data[0] >> 16) & 0xffff, chan_iobase + REG_C0H); + outw(data[0] & 0xffff, chan_iobase + REG_C0L); break; - default: /* Impossible */ - printk - ("s526: INSN_WRITE: Functionality %d not implemented yet\n", - devpriv->s526_gpct_config[subdev_channel].app); + + default: return -EINVAL; - break; } - /* return the number of samples written */ + return insn->n; } @@ -537,6 +399,7 @@ static int s526_ai_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct s526_private *devpriv = dev->private; int result = -EINVAL; if (insn->n < 1) @@ -552,62 +415,50 @@ static int s526_ai_insn_config(struct comedi_device *dev, * INSN_READ handler. */ /* Enable ADC interrupt */ - outw(ISR_ADC_DONE, ADDR_REG(REG_IER)); -/* printk("s526: ADC current value: 0x%04x\n", inw(ADDR_REG(REG_ADC))); */ - devpriv->s526_ai_config = (data[0] & 0x3FF) << 5; + outw(ISR_ADC_DONE, dev->iobase + REG_IER); + devpriv->ai_config = (data[0] & 0x3ff) << 5; if (data[1] > 0) - devpriv->s526_ai_config |= 0x8000; /* set the delay */ + devpriv->ai_config |= 0x8000; /* set the delay */ - devpriv->s526_ai_config |= 0x0001; /* ADC start bit. */ + devpriv->ai_config |= 0x0001; /* ADC start bit */ return result; } -/* - * "instructions" read/write data in "one-shot" or "software-triggered" - * mode. - */ static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct s526_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int n, i; - int chan = CR_CHAN(insn->chanspec); unsigned short value; unsigned int d; unsigned int status; /* Set configured delay, enable channel for this channel only, * select "ADC read" channel, set "ADC start" bit. */ - value = (devpriv->s526_ai_config & 0x8000) | - ((1 << 5) << chan) | (chan << 1) | 0x0001; + value = (devpriv->ai_config & 0x8000) | + ((1 << 5) << chan) | (chan << 1) | 0x0001; /* convert n samples */ for (n = 0; n < insn->n; n++) { /* trigger conversion */ - outw(value, ADDR_REG(REG_ADC)); -/* printk("s526: Wrote 0x%04x to ADC\n", value); */ -/* printk("s526: ADC reg=0x%04x\n", inw(ADDR_REG(REG_ADC))); */ + outw(value, dev->iobase + REG_ADC); #define TIMEOUT 100 /* wait for conversion to end */ for (i = 0; i < TIMEOUT; i++) { - status = inw(ADDR_REG(REG_ISR)); + status = inw(dev->iobase + REG_ISR); if (status & ISR_ADC_DONE) { - outw(ISR_ADC_DONE, ADDR_REG(REG_ISR)); + outw(ISR_ADC_DONE, dev->iobase + REG_ISR); break; } } - if (i == TIMEOUT) { - /* printk() should be used instead of printk() - * whenever the code can be called from real-time. */ - printk(KERN_ERR "s526: ADC(0x%04x) timeout\n", - inw(ADDR_REG(REG_ISR))); + if (i == TIMEOUT) return -ETIMEDOUT; - } /* read data */ - d = inw(ADDR_REG(REG_ADD)); -/* printk("AI[%d]=0x%04x\n", n, (unsigned short)(d & 0xFFFF)); */ + d = inw(dev->iobase + REG_ADD); /* munge data */ data[n] = d ^ 0x8000; @@ -620,40 +471,30 @@ static int s526_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, static int s526_ao_winsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int i; - int chan = CR_CHAN(insn->chanspec); + struct s526_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); unsigned short val; + int i; -/* printk("s526_ao_winsn\n"); */ val = chan << 1; -/* outw(val, dev->iobase + REG_DAC); */ - outw(val, ADDR_REG(REG_DAC)); + outw(val, dev->iobase + REG_DAC); - /* Writing a list of values to an AO channel is probably not - * very useful, but that's how the interface is defined. */ for (i = 0; i < insn->n; i++) { - /* a typical programming sequence */ - /* write the data to preload register - * outw(data[i], dev->iobase + REG_ADD); - */ - /* write the data to preload register */ - outw(data[i], ADDR_REG(REG_ADD)); + outw(data[i], dev->iobase + REG_ADD); devpriv->ao_readback[chan] = data[i]; -/* outw(val + 1, dev->iobase + REG_DAC); starts the D/A conversion. */ - outw(val + 1, ADDR_REG(REG_DAC)); /*starts the D/A conversion.*/ + /* starts the D/A conversion */ + outw(val + 1, dev->iobase + REG_DAC); } - /* return the number of samples read/written */ return i; } -/* AO subdevices should have a read insn as well as a write insn. - * Usually this means copying a value stored in devpriv. */ static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { + struct s526_private *devpriv = dev->private; + unsigned int chan = CR_CHAN(insn->chanspec); int i; - int chan = CR_CHAN(insn->chanspec); for (i = 0; i < insn->n; i++) data[i] = devpriv->ao_readback[chan]; @@ -661,30 +502,18 @@ static int s526_ao_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, return i; } -/* DIO devices are slightly special. Although it is possible to - * implement the insn_read/insn_write interface, it is much more - * useful to applications if you implement the insn_bits interface. - * This allows packed reading/writing of the DIO channels. The - * comedi core can convert between insn_bits and insn_read/write */ static int s526_dio_insn_bits(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - /* The insn data is a mask in data[0] and the new data - * in data[1], each channel cooresponding to a bit. */ if (data[0]) { s->state &= ~data[0]; s->state |= data[0] & data[1]; - /* Write out the new digital output lines */ - outw(s->state, ADDR_REG(REG_DIO)); + + outw(s->state, dev->iobase + REG_DIO); } - /* on return, data[1] contains the value of the digital - * input and output lines. */ - data[1] = inw(ADDR_REG(REG_DIO)) & 0xFF; /* low 8 bits are the data */ - /* or we could just return the software copy of the output values if - * it was a purely digital output subdevice */ - /* data[1]=s->state & 0xFF; */ + data[1] = inw(dev->iobase + REG_DIO) & 0xff; return insn->n; } @@ -693,16 +522,9 @@ static int s526_dio_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) { - int chan = CR_CHAN(insn->chanspec); + unsigned int chan = CR_CHAN(insn->chanspec); int group, mask; - printk(KERN_INFO "S526 DIO insn_config\n"); - - /* The input or output configuration of each digital line is - * configured by a special insn_config instruction. chanspec - * contains the channel to be changed, and data[0] contains the - * value COMEDI_INPUT or COMEDI_OUTPUT. */ - group = chan >> 2; mask = 0xF << (group << 2); switch (data[0]) { @@ -721,88 +543,60 @@ static int s526_dio_insn_config(struct comedi_device *dev, default: return -EINVAL; } - outw(s->state, ADDR_REG(REG_DIO)); + outw(s->state, dev->iobase + REG_DIO); return 1; } static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) { - const struct s526_board *board = comedi_board(dev); + struct s526_private *devpriv; struct comedi_subdevice *s; int iobase; - int i, n; int ret; -/* short value; */ -/* int subdev_channel = 0; */ - union cmReg cmReg; - printk(KERN_INFO "comedi%d: s526: ", dev->minor); + dev->board_name = dev->driver->driver_name; iobase = it->options[0]; - if (!iobase || !request_region(iobase, S526_IOSIZE, board->name)) { + if (!iobase || !request_region(iobase, S526_IOSIZE, dev->board_name)) { comedi_error(dev, "I/O port conflict"); return -EIO; } dev->iobase = iobase; - printk("iobase=0x%lx\n", dev->iobase); - - /*** make it a little quieter, exw, 8/29/06 - for (i = 0; i < S526_NUM_PORTS; i++) { - printk("0x%02x: 0x%04x\n", ADDR_REG(s526_ports[i]), - inw(ADDR_REG(s526_ports[i]))); - } - ***/ - - dev->board_name = board->name; - -/* - * Allocate the private structure area. alloc_private() is a - * convenient macro defined in comedidev.h. - */ - if (alloc_private(dev, sizeof(struct s526_private)) < 0) - return -ENOMEM; + ret = alloc_private(dev, sizeof(*devpriv)); + if (ret) + return ret; + devpriv = dev->private; ret = comedi_alloc_subdevices(dev, 4); if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* GENERAL-PURPOSE COUNTER/TIME (GPCT) */ s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = SDF_READABLE | SDF_WRITABLE | SDF_LSAMPL; - /* KG: What does SDF_LSAMPL (see multiq3.c) mean? */ - s->n_chan = board->gpct_chans; + s->n_chan = 4; s->maxdata = 0x00ffffff; /* 24 bit counter */ s->insn_read = s526_gpct_rinsn; s->insn_config = s526_gpct_insn_config; s->insn_write = s526_gpct_winsn; - /* Command are not implemented yet, however they are necessary to - allocate the necessary memory for the comedi_async struct (used - to trigger the GPCT in case of pulsegenerator function */ - /* s->do_cmd = s526_gpct_cmd; */ - /* s->do_cmdtest = s526_gpct_cmdtest; */ - /* s->cancel = s526_gpct_cancel; */ - - s = dev->subdevices + 1; - /* dev->read_subdev=s; */ + s = &dev->subdevices[1]; /* analog input subdevice */ s->type = COMEDI_SUBD_AI; - /* we support differential */ s->subdev_flags = SDF_READABLE | SDF_DIFF; /* channels 0 to 7 are the regular differential inputs */ /* channel 8 is "reference 0" (+10V), channel 9 is "reference 1" (0V) */ s->n_chan = 10; s->maxdata = 0xffff; s->range_table = &range_bipolar10; - s->len_chanlist = 16; /* This is the maximum chanlist length that - the board can handle */ + s->len_chanlist = 16; s->insn_read = s526_ai_rinsn; s->insn_config = s526_ai_insn_config; - s = dev->subdevices + 2; + s = &dev->subdevices[2]; /* analog output subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; @@ -812,105 +606,18 @@ static int s526_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_write = s526_ao_winsn; s->insn_read = s526_ao_rinsn; - s = dev->subdevices + 3; + s = &dev->subdevices[3]; /* digital i/o subdevice */ - if (board->have_dio) { - s->type = COMEDI_SUBD_DIO; - s->subdev_flags = SDF_READABLE | SDF_WRITABLE; - s->n_chan = 8; - s->maxdata = 1; - s->range_table = &range_digital; - s->insn_bits = s526_dio_insn_bits; - s->insn_config = s526_dio_insn_config; - } else { - s->type = COMEDI_SUBD_UNUSED; - } - - printk(KERN_INFO "attached\n"); - - return 1; - -#if 0 - /* Example of Counter Application */ - /* One-shot (software trigger) */ - cmReg.reg.coutSource = 0; /* out RCAP */ - cmReg.reg.coutPolarity = 1; /* Polarity inverted */ - cmReg.reg.autoLoadResetRcap = 1;/* Auto load 0:disabled, 1:enabled */ - cmReg.reg.hwCtEnableSource = 3; /* NOT RCAP */ - cmReg.reg.ctEnableCtrl = 2; /* Hardware */ - cmReg.reg.clockSource = 2; /* Internal */ - cmReg.reg.countDir = 1; /* Down */ - cmReg.reg.countDirCtrl = 1; /* Software */ - cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */ - cmReg.reg.preloadRegSel = 0; /* PR0 */ - cmReg.reg.reserved = 0; - - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, subdev_channel)); - - outw(0x0001, ADDR_CHAN_REG(REG_C0H, subdev_channel)); - outw(0x3C68, ADDR_CHAN_REG(REG_C0L, subdev_channel)); - - /* Reset the counter */ - outw(0x8000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); - /* Load the counter from PR0 */ - outw(0x4000, ADDR_CHAN_REG(REG_C0C, subdev_channel)); - /* Reset RCAP (fires one-shot) */ - outw(0x0008, ADDR_CHAN_REG(REG_C0C, subdev_channel)); - -#else - - /* Set Counter Mode Register */ - cmReg.reg.coutSource = 0; /* out RCAP */ - cmReg.reg.coutPolarity = 0; /* Polarity inverted */ - cmReg.reg.autoLoadResetRcap = 0; /* Auto load disabled */ - cmReg.reg.hwCtEnableSource = 2; /* NOT RCAP */ - cmReg.reg.ctEnableCtrl = 1; /* 1: Software, >1 : Hardware */ - cmReg.reg.clockSource = 3; /* x4 */ - cmReg.reg.countDir = 0; /* up */ - cmReg.reg.countDirCtrl = 0; /* quadrature */ - cmReg.reg.outputRegLatchCtrl = 0; /* latch on read */ - cmReg.reg.preloadRegSel = 0; /* PR0 */ - cmReg.reg.reserved = 0; - - n = 0; - printk(KERN_INFO "Mode reg=0x%04x, 0x%04lx\n", - cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); - udelay(1000); - printk(KERN_INFO "Read back mode reg=0x%04x\n", - inw(ADDR_CHAN_REG(REG_C0M, n))); - - /* Load the pre-load register high word */ -/* value = (short) (0x55); */ -/* outw(value, ADDR_CHAN_REG(REG_C0H, n)); */ - - /* Load the pre-load register low word */ -/* value = (short)(0xaa55); */ -/* outw(value, ADDR_CHAN_REG(REG_C0L, n)); */ - - /* Write the Counter Control Register */ -/* outw(value, ADDR_CHAN_REG(REG_C0C, 0)); */ - - /* Reset the counter if it is software preload */ - if (cmReg.reg.autoLoadResetRcap == 0) { - /* Reset the counter */ - outw(0x8000, ADDR_CHAN_REG(REG_C0C, n)); - /* Load the counter from PR0 */ - outw(0x4000, ADDR_CHAN_REG(REG_C0C, n)); - } + s->type = COMEDI_SUBD_DIO; + s->subdev_flags = SDF_READABLE | SDF_WRITABLE; + s->n_chan = 8; + s->maxdata = 1; + s->range_table = &range_digital; + s->insn_bits = s526_dio_insn_bits; + s->insn_config = s526_dio_insn_config; - outw(cmReg.value, ADDR_CHAN_REG(REG_C0M, n)); - udelay(1000); - printk(KERN_INFO "Read back mode reg=0x%04x\n", - inw(ADDR_CHAN_REG(REG_C0M, n))); + dev_info(dev->class_dev, "%s attached\n", dev->board_name); -#endif - printk(KERN_INFO "Current registres:\n"); - - for (i = 0; i < S526_NUM_PORTS; i++) { - printk(KERN_INFO "0x%02lx: 0x%04x\n", - ADDR_REG(s526_ports[i]), inw(ADDR_REG(s526_ports[i]))); - } return 1; } @@ -925,9 +632,6 @@ static struct comedi_driver s526_driver = { .module = THIS_MODULE, .attach = s526_attach, .detach = s526_detach, - .board_name = &s526_boards[0].name, - .offset = sizeof(struct s526_board), - .num_names = ARRAY_SIZE(s526_boards), }; module_comedi_driver(s526_driver); diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c index f90578e5e727..551d68b7837c 100644 --- a/drivers/staging/comedi/drivers/s626.c +++ b/drivers/staging/comedi/drivers/s626.c @@ -32,11 +32,7 @@ Authors: Gianluca Palli <gpalli@deis.unibo.it>, Updated: Fri, 15 Feb 2008 10:28:42 +0000 Status: experimental -Configuration options: - [0] - PCI bus of device (optional) - [1] - PCI slot of device (optional) - If bus/slot is not specified, the first supported - PCI device found will be used. +Configuration options: not applicable, uses PCI auto config INSN_CONFIG instructions: analog input: @@ -82,45 +78,8 @@ INSN_CONFIG instructions: #define PCI_SUBVENDOR_ID_S626 0x6000 #define PCI_SUBDEVICE_ID_S626 0x0272 -struct s626_board { - const char *name; - int vendor_id; - int device_id; - int subvendor_id; - int subdevice_id; - int ai_chans; - int ai_bits; - int ao_chans; - int ao_bits; - int dio_chans; - int dio_banks; - int enc_chans; -}; - -static const struct s626_board s626_boards[] = { - { - .name = "s626", - .vendor_id = PCI_VENDOR_ID_S626, - .device_id = PCI_DEVICE_ID_S626, - .subvendor_id = PCI_SUBVENDOR_ID_S626, - .subdevice_id = PCI_SUBDEVICE_ID_S626, - .ai_chans = S626_ADC_CHANNELS, - .ai_bits = 14, - .ao_chans = S626_DAC_CHANNELS, - .ao_bits = 13, - .dio_chans = S626_DIO_CHANNELS, - .dio_banks = S626_DIO_BANKS, - .enc_chans = S626_ENCODER_CHANNELS, - } -}; - -#define thisboard ((const struct s626_board *)dev->board_ptr) - struct s626_private { - struct pci_dev *pdev; void __iomem *base_addr; - int got_regions; - short allocatedBuf; uint8_t ai_cmd_running; /* ai_cmd is running */ uint8_t ai_continous; /* continous acquisition */ int ai_sample_count; /* number of samples to acquire */ @@ -139,9 +98,7 @@ struct s626_private { /* Pointer to logical adrs of DMA buffer used to hold DAC data. */ uint16_t Dacpol; /* Image of DAC polarity register. */ uint8_t TrimSetpoint[12]; /* Images of TrimDAC setpoints */ - uint16_t ChargeEnabled; /* Image of MISC2 Battery */ /* Charge Enabled (0 or WRMISC2_CHARGE_ENABLE). */ - uint16_t WDInterval; /* Image of MISC2 watchdog interval control bits. */ uint32_t I2CAdrs; /* I2C device address for onboard EEPROM (board rev dependent). */ /* short I2Cards; */ @@ -1548,56 +1505,28 @@ static int s626_ai_cmdtest(struct comedi_device *dev, int err = 0; int tmp; - /* cmdtest tests a particular command to see if it is valid. Using - * the cmdtest ioctl, a user can create a valid cmd and then have it - * executes by the cmd ioctl. - * - * cmdtest returns 1,2,3,4 or 0, depending on which tests the - * command passes. */ - - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_INT | TRIG_EXT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT | TRIG_FOLLOW; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT | TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, + TRIG_NOW | TRIG_INT | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_EXT | TRIG_FOLLOW); + err |= cfc_check_trigger_src(&cmd->convert_src, + TRIG_TIMER | TRIG_EXT | TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually - compatible */ + /* Step 2a : make sure trigger sources are unique */ - /* note that mutual compatibility is not an issue here */ - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT - && cmd->scan_begin_src != TRIG_FOLLOW) - err++; - if (cmd->convert_src != TRIG_TIMER && - cmd->convert_src != TRIG_EXT && cmd->convert_src != TRIG_NOW) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -1847,6 +1776,9 @@ static int s626_dio_insn_config(struct comedi_device *dev, /* Now this function initializes the value of the counter (data[0]) and set the subdevice. To complete with trigger and interrupt configuration */ +/* FIXME: data[0] is supposed to be an INSN_CONFIG_xxx constant indicating + * what is being configured, but this function appears to be using data[0] + * as a variable. */ static int s626_enc_insn_config(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_insn *insn, unsigned int *data) @@ -1868,7 +1800,7 @@ static int s626_enc_insn_config(struct comedi_device *dev, /* (data==NULL) ? (Preloadvalue=0) : (Preloadvalue=data[0]); */ k->SetMode(dev, k, Setup, TRUE); - Preload(dev, k, *(insn->data)); + Preload(dev, k, data[0]); k->PulseIndex(dev, k); SetLatchSource(dev, k, valueSrclatch); k->SetEnable(dev, k, (uint16_t) (enab != 0)); @@ -1920,6 +1852,7 @@ static void WriteMISC2(struct comedi_device *dev, uint16_t NewImage) static void CloseDMAB(struct comedi_device *dev, struct bufferDMA *pdma, size_t bsize) { + struct pci_dev *pcidev = comedi_to_pci_dev(dev); void *vbptr; dma_addr_t vpptr; @@ -1930,7 +1863,7 @@ static void CloseDMAB(struct comedi_device *dev, struct bufferDMA *pdma, vbptr = pdma->LogicalBase; vpptr = pdma->PhysicalBase; if (vbptr) { - pci_free_consistent(devpriv->pdev, bsize, vbptr, vpptr); + pci_free_consistent(pcidev, bsize, vbptr, vpptr); pdma->LogicalBase = NULL; pdma->PhysicalBase = 0; } @@ -2476,146 +2409,317 @@ static void CountersInit(struct comedi_device *dev) } } -static struct pci_dev *s626_find_pci(struct comedi_device *dev, - struct comedi_devconfig *it) +static int s626_allocate_dma_buffers(struct comedi_device *dev) { - struct pci_dev *pcidev = NULL; - int bus = it->options[0]; - int slot = it->options[1]; - int i; + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + void *addr; + dma_addr_t appdma; - for (i = 0; i < ARRAY_SIZE(s626_boards) && !pcidev; i++) { - do { - pcidev = pci_get_subsys(s626_boards[i].vendor_id, - s626_boards[i].device_id, - s626_boards[i].subvendor_id, - s626_boards[i].subdevice_id, - pcidev); - - if ((bus || slot) && pcidev) { - /* matches requested bus/slot */ - if (pcidev->bus->number == bus && - PCI_SLOT(pcidev->devfn) == slot) - break; - } else { - break; - } - } while (1); - } - return pcidev; + addr = pci_alloc_consistent(pcidev, DMABUF_SIZE, &appdma); + if (!addr) + return -ENOMEM; + devpriv->ANABuf.LogicalBase = addr; + devpriv->ANABuf.PhysicalBase = appdma; + + addr = pci_alloc_consistent(pcidev, DMABUF_SIZE, &appdma); + if (!addr) + return -ENOMEM; + devpriv->RPSBuf.LogicalBase = addr; + devpriv->RPSBuf.PhysicalBase = appdma; + + return 0; } -static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it) +static void s626_initialize(struct comedi_device *dev) { -/* uint8_t PollList; */ -/* uint16_t AdcData; */ -/* uint16_t StartVal; */ -/* uint16_t index; */ -/* unsigned int data[16]; */ - int result; + dma_addr_t pPhysBuf; + uint16_t chan; int i; - int ret; - resource_size_t resourceStart; - dma_addr_t appdma; - struct comedi_subdevice *s; - if (alloc_private(dev, sizeof(struct s626_private)) < 0) - return -ENOMEM; + /* Enable DEBI and audio pins, enable I2C interface */ + MC_ENABLE(P_MC1, MC1_DEBI | MC1_AUDIO | MC1_I2C); - devpriv->pdev = s626_find_pci(dev, it); - if (!devpriv->pdev) { - printk(KERN_ERR "s626_attach: Board not present!!!\n"); - return -ENODEV; - } + /* + * Configure DEBI operating mode + * + * Local bus is 16 bits wide + * Declare DEBI transfer timeout interval + * Set up byte lane steering + * Intel-compatible local bus (DEBI never times out) + */ + WR7146(P_DEBICFG, DEBI_CFG_SLAVE16 | + (DEBI_TOUT << DEBI_CFG_TOUT_BIT) | + DEBI_SWAP | DEBI_CFG_INTEL); + + /* Disable MMU paging */ + WR7146(P_DEBIPAGE, DEBI_PAGE_DISABLE); - result = comedi_pci_enable(devpriv->pdev, "s626"); - if (result < 0) { - printk(KERN_ERR "s626_attach: comedi_pci_enable fails\n"); - return -ENODEV; + /* Init GPIO so that ADC Start* is negated */ + WR7146(P_GPIO, GPIO_BASE | GPIO1_HI); + + /* I2C device address for onboard eeprom (revb) */ + devpriv->I2CAdrs = 0xA0; + + /* + * Issue an I2C ABORT command to halt any I2C + * operation in progress and reset BUSY flag. + */ + WR7146(P_I2CSTAT, I2C_CLKSEL | I2C_ABORT); + MC_ENABLE(P_MC2, MC2_UPLD_IIC); + while ((RR7146(P_MC2) & MC2_UPLD_IIC) == 0) + ; + + /* + * Per SAA7146 data sheet, write to STATUS + * reg twice to reset all I2C error flags. + */ + for (i = 0; i < 2; i++) { + WR7146(P_I2CSTAT, I2C_CLKSEL); + MC_ENABLE(P_MC2, MC2_UPLD_IIC); + while (!MC_TEST(P_MC2, MC2_UPLD_IIC)) + ; } - devpriv->got_regions = 1; - resourceStart = pci_resource_start(devpriv->pdev, 0); + /* + * Init audio interface functional attributes: set DAC/ADC + * serial clock rates, invert DAC serial clock so that + * DAC data setup times are satisfied, enable DAC serial + * clock out. + */ + WR7146(P_ACON2, ACON2_INIT); + + /* + * Set up TSL1 slot list, which is used to control the + * accumulation of ADC data: RSD1 = shift data in on SD1. + * SIB_A1 = store data uint8_t at next available location + * in FB BUFFER1 register. + */ + WR7146(P_TSL1, RSD1 | SIB_A1); + WR7146(P_TSL1 + 4, RSD1 | SIB_A1 | EOS); + + /* Enable TSL1 slot list so that it executes all the time */ + WR7146(P_ACON1, ACON1_ADCSTART); + + /* + * Initialize RPS registers used for ADC + */ + + /* Physical start of RPS program */ + WR7146(P_RPSADDR1, (uint32_t)devpriv->RPSBuf.PhysicalBase); + /* RPS program performs no explicit mem writes */ + WR7146(P_RPSPAGE1, 0); + /* Disable RPS timeouts */ + WR7146(P_RPS1_TOUT, 0); + +#if 0 + /* + * SAA7146 BUG WORKAROUND + * + * Initialize SAA7146 ADC interface to a known state by + * invoking ADCs until FB BUFFER 1 register shows that it + * is correctly receiving ADC data. This is necessary + * because the SAA7146 ADC interface does not start up in + * a defined state after a PCI reset. + */ + + { + uint8_t PollList; + uint16_t AdcData; + uint16_t StartVal; + uint16_t index; + unsigned int data[16]; + + /* Create a simple polling list for analog input channel 0 */ + PollList = EOPL; + ResetADC(dev, &PollList); - devpriv->base_addr = ioremap(resourceStart, SIZEOF_ADDRESS_SPACE); - if (devpriv->base_addr == NULL) { - printk(KERN_ERR "s626_attach: IOREMAP failed\n"); - return -ENODEV; + /* Get initial ADC value */ + s626_ai_rinsn(dev, dev->subdevices, NULL, data); + StartVal = data[0]; + + /* + * VERSION 2.01 CHANGE: TIMEOUT ADDED TO PREVENT HANGED EXECUTION. + * + * Invoke ADCs until the new ADC value differs from the initial + * value or a timeout occurs. The timeout protects against the + * possibility that the driver is restarting and the ADC data is a + * fixed value resulting from the applied ADC analog input being + * unusually quiet or at the rail. + */ + for (index = 0; index < 500; index++) { + s626_ai_rinsn(dev, dev->subdevices, NULL, data); + AdcData = data[0]; + if (AdcData != StartVal) + break; } - if (devpriv->base_addr) { - /* disable master interrupt */ - writel(0, devpriv->base_addr + P_IER); + } +#endif /* SAA7146 BUG WORKAROUND */ - /* soft reset */ - writel(MC1_SOFT_RESET, devpriv->base_addr + P_MC1); + /* + * Initialize the DAC interface + */ - /* DMA FIXME DMA// */ + /* + * Init Audio2's output DMAC attributes: + * burst length = 1 DWORD + * threshold = 1 DWORD. + */ + WR7146(P_PCI_BT_A, 0); - /* adc buffer allocation */ - devpriv->allocatedBuf = 0; + /* + * Init Audio2's output DMA physical addresses. The protection + * address is set to 1 DWORD past the base address so that a + * single DWORD will be transferred each time a DMA transfer is + * enabled. + */ + pPhysBuf = devpriv->ANABuf.PhysicalBase + + (DAC_WDMABUF_OS * sizeof(uint32_t)); + WR7146(P_BASEA2_OUT, (uint32_t) pPhysBuf); + WR7146(P_PROTA2_OUT, (uint32_t) (pPhysBuf + sizeof(uint32_t))); - devpriv->ANABuf.LogicalBase = - pci_alloc_consistent(devpriv->pdev, DMABUF_SIZE, &appdma); + /* + * Cache Audio2's output DMA buffer logical address. This is + * where DAC data is buffered for A2 output DMA transfers. + */ + devpriv->pDacWBuf = (uint32_t *)devpriv->ANABuf.LogicalBase + + DAC_WDMABUF_OS; - if (devpriv->ANABuf.LogicalBase == NULL) { - printk(KERN_ERR "s626_attach: DMA Memory mapping error\n"); - return -ENOMEM; - } + /* + * Audio2's output channels does not use paging. The + * protection violation handling bit is set so that the + * DMAC will automatically halt and its PCI address pointer + * will be reset when the protection address is reached. + */ + WR7146(P_PAGEA2_OUT, 8); - devpriv->ANABuf.PhysicalBase = appdma; + /* + * Initialize time slot list 2 (TSL2), which is used to control + * the clock generation for and serialization of data to be sent + * to the DAC devices. Slot 0 is a NOP that is used to trap TSL + * execution; this permits other slots to be safely modified + * without first turning off the TSL sequencer (which is + * apparently impossible to do). Also, SD3 (which is driven by a + * pull-up resistor) is shifted in and stored to the MSB of + * FB_BUFFER2 to be used as evidence that the slot sequence has + * not yet finished executing. + */ - devpriv->allocatedBuf++; + /* Slot 0: Trap TSL execution, shift 0xFF into FB_BUFFER2 */ + SETVECT(0, XSD2 | RSD3 | SIB_A2 | EOS); - devpriv->RPSBuf.LogicalBase = - pci_alloc_consistent(devpriv->pdev, DMABUF_SIZE, &appdma); + /* + * Initialize slot 1, which is constant. Slot 1 causes a + * DWORD to be transferred from audio channel 2's output FIFO + * to the FIFO's output buffer so that it can be serialized + * and sent to the DAC during subsequent slots. All remaining + * slots are dynamically populated as required by the target + * DAC device. + */ - if (devpriv->RPSBuf.LogicalBase == NULL) { - printk(KERN_ERR "s626_attach: DMA Memory mapping error\n"); - return -ENOMEM; - } + /* Slot 1: Fetch DWORD from Audio2's output FIFO */ + SETVECT(1, LF_A2); + + /* Start DAC's audio interface (TSL2) running */ + WR7146(P_ACON1, ACON1_DACSTART); + + /* + * Init Trim DACs to calibrated values. Do it twice because the + * SAA7146 audio channel does not always reset properly and + * sometimes causes the first few TrimDAC writes to malfunction. + */ + LoadTrimDACs(dev); + LoadTrimDACs(dev); + + /* + * Manually init all gate array hardware in case this is a soft + * reset (we have no way of determining whether this is a warm + * or cold start). This is necessary because the gate array will + * reset only in response to a PCI hard reset; there is no soft + * reset function. + */ - devpriv->RPSBuf.PhysicalBase = appdma; + /* + * Init all DAC outputs to 0V and init all DAC setpoint and + * polarity images. + */ + for (chan = 0; chan < S626_DAC_CHANNELS; chan++) + SetDAC(dev, chan, 0); - devpriv->allocatedBuf++; + /* Init counters */ + CountersInit(dev); - } + /* + * Without modifying the state of the Battery Backup enab, disable + * the watchdog timer, set DIO channels 0-5 to operate in the + * standard DIO (vs. counter overflow) mode, disable the battery + * charger, and reset the watchdog interval selector to zero. + */ + WriteMISC2(dev, (uint16_t)(DEBIread(dev, LP_RDMISC2) & + MISC2_BATT_ENABLE)); - dev->board_ptr = s626_boards; - dev->board_name = thisboard->name; + /* Initialize the digital I/O subsystem */ + s626_dio_init(dev); - ret = comedi_alloc_subdevices(dev, 6); + /* enable interrupt test */ + /* writel(IRQ_GPIO3 | IRQ_RPS1, devpriv->base_addr + P_IER); */ +} + +static int s626_attach_pci(struct comedi_device *dev, struct pci_dev *pcidev) +{ + struct comedi_subdevice *s; + int ret; + + comedi_set_hw_dev(dev, &pcidev->dev); + dev->board_name = dev->driver->driver_name; + + if (alloc_private(dev, sizeof(struct s626_private)) < 0) + return -ENOMEM; + + ret = comedi_pci_enable(pcidev, dev->board_name); if (ret) return ret; + dev->iobase = 1; /* detach needs this */ - dev->iobase = (unsigned long)devpriv->base_addr; - dev->irq = devpriv->pdev->irq; + devpriv->base_addr = ioremap(pci_resource_start(pcidev, 0), + pci_resource_len(pcidev, 0)); + if (!devpriv->base_addr) + return -ENOMEM; - /* set up interrupt handler */ - if (dev->irq == 0) { - printk(KERN_ERR " unknown irq (bad)\n"); - } else { - ret = request_irq(dev->irq, s626_irq_handler, IRQF_SHARED, - "s626", dev); + /* disable master interrupt */ + writel(0, devpriv->base_addr + P_IER); - if (ret < 0) { - printk(KERN_ERR " irq not available\n"); - dev->irq = 0; - } + /* soft reset */ + writel(MC1_SOFT_RESET, devpriv->base_addr + P_MC1); + + /* DMA FIXME DMA// */ + + ret = s626_allocate_dma_buffers(dev); + if (ret) + return ret; + + if (pcidev->irq) { + ret = request_irq(pcidev->irq, s626_irq_handler, IRQF_SHARED, + dev->board_name, dev); + + if (ret == 0) + dev->irq = pcidev->irq; } + ret = comedi_alloc_subdevices(dev, 6); + if (ret) + return ret; + s = dev->subdevices + 0; /* analog input subdevice */ dev->read_subdev = s; /* we support single-ended (ground) and differential */ s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_DIFF | SDF_CMD_READ; - s->n_chan = thisboard->ai_chans; + s->n_chan = S626_ADC_CHANNELS; s->maxdata = (0xffff >> 2); s->range_table = &s626_range_table; - s->len_chanlist = thisboard->ai_chans; /* This is the maximum chanlist - length that the board can - handle */ + s->len_chanlist = S626_ADC_CHANNELS; s->insn_config = s626_ai_insn_config; s->insn_read = s626_ai_insn_read; s->do_cmd = s626_ai_cmd; @@ -2626,7 +2730,7 @@ static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* analog output subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE | SDF_READABLE; - s->n_chan = thisboard->ao_chans; + s->n_chan = S626_DAC_CHANNELS; s->maxdata = (0x3fff); s->range_table = &range_bipolar10; s->insn_write = s626_ao_winsn; @@ -2672,7 +2776,7 @@ static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it) /* encoder (counter) subdevice */ s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = SDF_WRITABLE | SDF_READABLE | SDF_LSAMPL; - s->n_chan = thisboard->enc_chans; + s->n_chan = S626_ENCODER_CHANNELS; s->private = enc_private_data; s->insn_config = s626_enc_insn_config; s->insn_read = s626_enc_insn_read; @@ -2680,269 +2784,17 @@ static int s626_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->maxdata = 0xffffff; s->range_table = &range_unknown; - /* stop ai_command */ - devpriv->ai_cmd_running = 0; - - if (devpriv->base_addr && (devpriv->allocatedBuf == 2)) { - dma_addr_t pPhysBuf; - uint16_t chan; - - /* enab DEBI and audio pins, enable I2C interface. */ - MC_ENABLE(P_MC1, MC1_DEBI | MC1_AUDIO | MC1_I2C); - /* Configure DEBI operating mode. */ - WR7146(P_DEBICFG, DEBI_CFG_SLAVE16 /* Local bus is 16 */ - /* bits wide. */ - | (DEBI_TOUT << DEBI_CFG_TOUT_BIT) - - /* Declare DEBI */ - /* transfer timeout */ - /* interval. */ - |DEBI_SWAP /* Set up byte lane */ - /* steering. */ - | DEBI_CFG_INTEL); /* Intel-compatible */ - /* local bus (DEBI */ - /* never times out). */ - - /* DEBI INIT S626 WR7146( P_DEBICFG, DEBI_CFG_INTEL | DEBI_CFG_TOQ */ - /* | DEBI_CFG_INCQ| DEBI_CFG_16Q); //end */ - - /* Paging is disabled. */ - WR7146(P_DEBIPAGE, DEBI_PAGE_DISABLE); /* Disable MMU paging. */ - - /* Init GPIO so that ADC Start* is negated. */ - WR7146(P_GPIO, GPIO_BASE | GPIO1_HI); - - /* IsBoardRevA is a boolean that indicates whether the board is RevA. - * - * VERSION 2.01 CHANGE: REV A & B BOARDS NOW SUPPORTED BY DYNAMIC - * EEPROM ADDRESS SELECTION. Initialize the I2C interface, which - * is used to access the onboard serial EEPROM. The EEPROM's I2C - * DeviceAddress is hardwired to a value that is dependent on the - * 626 board revision. On all board revisions, the EEPROM stores - * TrimDAC calibration constants for analog I/O. On RevB and - * higher boards, the DeviceAddress is hardwired to 0 to enable - * the EEPROM to also store the PCI SubVendorID and SubDeviceID; - * this is the address at which the SAA7146 expects a - * configuration EEPROM to reside. On RevA boards, the EEPROM - * device address, which is hardwired to 4, prevents the SAA7146 - * from retrieving PCI sub-IDs, so the SAA7146 uses its built-in - * default values, instead. - */ - - /* devpriv->I2Cards= IsBoardRevA ? 0xA8 : 0xA0; // Set I2C EEPROM */ - /* DeviceType (0xA0) */ - /* and DeviceAddress<<1. */ - - devpriv->I2CAdrs = 0xA0; /* I2C device address for onboard */ - /* eeprom(revb) */ + s626_initialize(dev); - /* Issue an I2C ABORT command to halt any I2C operation in */ - /* progress and reset BUSY flag. */ - WR7146(P_I2CSTAT, I2C_CLKSEL | I2C_ABORT); - /* Write I2C control: abort any I2C activity. */ - MC_ENABLE(P_MC2, MC2_UPLD_IIC); - /* Invoke command upload */ - while ((RR7146(P_MC2) & MC2_UPLD_IIC) == 0) - ; - /* and wait for upload to complete. */ - - /* Per SAA7146 data sheet, write to STATUS reg twice to - * reset all I2C error flags. */ - for (i = 0; i < 2; i++) { - WR7146(P_I2CSTAT, I2C_CLKSEL); - /* Write I2C control: reset error flags. */ - MC_ENABLE(P_MC2, MC2_UPLD_IIC); /* Invoke command upload */ - while (!MC_TEST(P_MC2, MC2_UPLD_IIC)) - ; - /* and wait for upload to complete. */ - } - - /* Init audio interface functional attributes: set DAC/ADC - * serial clock rates, invert DAC serial clock so that - * DAC data setup times are satisfied, enable DAC serial - * clock out. - */ + dev_info(dev->class_dev, "%s attached\n", dev->board_name); - WR7146(P_ACON2, ACON2_INIT); - - /* Set up TSL1 slot list, which is used to control the - * accumulation of ADC data: RSD1 = shift data in on SD1. - * SIB_A1 = store data uint8_t at next available location in - * FB BUFFER1 register. */ - WR7146(P_TSL1, RSD1 | SIB_A1); - /* Fetch ADC high data uint8_t. */ - WR7146(P_TSL1 + 4, RSD1 | SIB_A1 | EOS); - /* Fetch ADC low data uint8_t; end of TSL1. */ - - /* enab TSL1 slot list so that it executes all the time. */ - WR7146(P_ACON1, ACON1_ADCSTART); - - /* Initialize RPS registers used for ADC. */ - - /* Physical start of RPS program. */ - WR7146(P_RPSADDR1, (uint32_t) devpriv->RPSBuf.PhysicalBase); - - WR7146(P_RPSPAGE1, 0); - /* RPS program performs no explicit mem writes. */ - WR7146(P_RPS1_TOUT, 0); /* Disable RPS timeouts. */ - - /* SAA7146 BUG WORKAROUND. Initialize SAA7146 ADC interface - * to a known state by invoking ADCs until FB BUFFER 1 - * register shows that it is correctly receiving ADC data. - * This is necessary because the SAA7146 ADC interface does - * not start up in a defined state after a PCI reset. - */ - -/* PollList = EOPL; // Create a simple polling */ -/* // list for analog input */ -/* // channel 0. */ -/* ResetADC( dev, &PollList ); */ - -/* s626_ai_rinsn(dev,dev->subdevices,NULL,data); //( &AdcData ); // */ -/* //Get initial ADC */ -/* //value. */ - -/* StartVal = data[0]; */ - -/* // VERSION 2.01 CHANGE: TIMEOUT ADDED TO PREVENT HANGED EXECUTION. */ -/* // Invoke ADCs until the new ADC value differs from the initial */ -/* // value or a timeout occurs. The timeout protects against the */ -/* // possibility that the driver is restarting and the ADC data is a */ -/* // fixed value resulting from the applied ADC analog input being */ -/* // unusually quiet or at the rail. */ - -/* for ( index = 0; index < 500; index++ ) */ -/* { */ -/* s626_ai_rinsn(dev,dev->subdevices,NULL,data); */ -/* AdcData = data[0]; //ReadADC( &AdcData ); */ -/* if ( AdcData != StartVal ) */ -/* break; */ -/* } */ - - /* end initADC */ - - /* init the DAC interface */ - - /* Init Audio2's output DMAC attributes: burst length = 1 - * DWORD, threshold = 1 DWORD. - */ - WR7146(P_PCI_BT_A, 0); - - /* Init Audio2's output DMA physical addresses. The protection - * address is set to 1 DWORD past the base address so that a - * single DWORD will be transferred each time a DMA transfer is - * enabled. */ - - pPhysBuf = - devpriv->ANABuf.PhysicalBase + - (DAC_WDMABUF_OS * sizeof(uint32_t)); - - WR7146(P_BASEA2_OUT, (uint32_t) pPhysBuf); /* Buffer base adrs. */ - WR7146(P_PROTA2_OUT, (uint32_t) (pPhysBuf + sizeof(uint32_t))); /* Protection address. */ - - /* Cache Audio2's output DMA buffer logical address. This is - * where DAC data is buffered for A2 output DMA transfers. */ - devpriv->pDacWBuf = - (uint32_t *) devpriv->ANABuf.LogicalBase + DAC_WDMABUF_OS; - - /* Audio2's output channels does not use paging. The protection - * violation handling bit is set so that the DMAC will - * automatically halt and its PCI address pointer will be reset - * when the protection address is reached. */ - - WR7146(P_PAGEA2_OUT, 8); - - /* Initialize time slot list 2 (TSL2), which is used to control - * the clock generation for and serialization of data to be sent - * to the DAC devices. Slot 0 is a NOP that is used to trap TSL - * execution; this permits other slots to be safely modified - * without first turning off the TSL sequencer (which is - * apparently impossible to do). Also, SD3 (which is driven by a - * pull-up resistor) is shifted in and stored to the MSB of - * FB_BUFFER2 to be used as evidence that the slot sequence has - * not yet finished executing. - */ - - SETVECT(0, XSD2 | RSD3 | SIB_A2 | EOS); - /* Slot 0: Trap TSL execution, shift 0xFF into FB_BUFFER2. */ - - /* Initialize slot 1, which is constant. Slot 1 causes a - * DWORD to be transferred from audio channel 2's output FIFO - * to the FIFO's output buffer so that it can be serialized - * and sent to the DAC during subsequent slots. All remaining - * slots are dynamically populated as required by the target - * DAC device. - */ - SETVECT(1, LF_A2); - /* Slot 1: Fetch DWORD from Audio2's output FIFO. */ - - /* Start DAC's audio interface (TSL2) running. */ - WR7146(P_ACON1, ACON1_DACSTART); - - /* end init DAC interface */ - - /* Init Trim DACs to calibrated values. Do it twice because the - * SAA7146 audio channel does not always reset properly and - * sometimes causes the first few TrimDAC writes to malfunction. - */ - - LoadTrimDACs(dev); - LoadTrimDACs(dev); /* Insurance. */ - - /* Manually init all gate array hardware in case this is a soft - * reset (we have no way of determining whether this is a warm - * or cold start). This is necessary because the gate array will - * reset only in response to a PCI hard reset; there is no soft - * reset function. */ - - /* Init all DAC outputs to 0V and init all DAC setpoint and - * polarity images. - */ - for (chan = 0; chan < S626_DAC_CHANNELS; chan++) - SetDAC(dev, chan, 0); - - /* Init image of WRMISC2 Battery Charger Enabled control bit. - * This image is used when the state of the charger control bit, - * which has no direct hardware readback mechanism, is queried. - */ - devpriv->ChargeEnabled = 0; - - /* Init image of watchdog timer interval in WRMISC2. This image - * maintains the value of the control bits of MISC2 are - * continuously reset to zero as long as the WD timer is disabled. - */ - devpriv->WDInterval = 0; - - /* Init Counter Interrupt enab mask for RDMISC2. This mask is - * applied against MISC2 when testing to determine which timer - * events are requesting interrupt service. - */ - devpriv->CounterIntEnabs = 0; - - /* Init counters. */ - CountersInit(dev); - - /* Without modifying the state of the Battery Backup enab, disable - * the watchdog timer, set DIO channels 0-5 to operate in the - * standard DIO (vs. counter overflow) mode, disable the battery - * charger, and reset the watchdog interval selector to zero. - */ - WriteMISC2(dev, (uint16_t) (DEBIread(dev, - LP_RDMISC2) & - MISC2_BATT_ENABLE)); - - /* Initialize the digital I/O subsystem. */ - s626_dio_init(dev); - - /* enable interrupt test */ - /* writel(IRQ_GPIO3 | IRQ_RPS1,devpriv->base_addr+P_IER); */ - } - - return 1; + return 0; } static void s626_detach(struct comedi_device *dev) { + struct pci_dev *pcidev = comedi_to_pci_dev(dev); + if (devpriv) { /* stop ai_command */ devpriv->ai_cmd_running = 0; @@ -2967,18 +2819,17 @@ static void s626_detach(struct comedi_device *dev) free_irq(dev->irq, dev); if (devpriv->base_addr) iounmap(devpriv->base_addr); - if (devpriv->pdev) { - if (devpriv->got_regions) - comedi_pci_disable(devpriv->pdev); - pci_dev_put(devpriv->pdev); - } + } + if (pcidev) { + if (dev->iobase) + comedi_pci_disable(pcidev); } } static struct comedi_driver s626_driver = { .driver_name = "s626", .module = THIS_MODULE, - .attach = s626_attach, + .attach_pci = s626_attach_pci, .detach = s626_detach, }; diff --git a/drivers/staging/comedi/drivers/s626.h b/drivers/staging/comedi/drivers/s626.h index 8a8f196cf153..ff4b3a5e4e5f 100644 --- a/drivers/staging/comedi/drivers/s626.h +++ b/drivers/staging/comedi/drivers/s626.h @@ -73,7 +73,6 @@ #include <linux/slab.h> #define S626_SIZE 0x0200 -#define SIZEOF_ADDRESS_SPACE 0x0200 #define DMABUF_SIZE 4096 /* 4k pages */ #define S626_ADC_CHANNELS 16 diff --git a/drivers/staging/comedi/drivers/serial2002.c b/drivers/staging/comedi/drivers/serial2002.c index c18314be8c82..5bf84cfbdceb 100644 --- a/drivers/staging/comedi/drivers/serial2002.c +++ b/drivers/staging/comedi/drivers/serial2002.c @@ -588,7 +588,9 @@ static int serial_2002_open(struct comedi_device *dev) kfree(s->range_table_list); s->range_table = NULL; s->range_table_list = NULL; - if (range) { + if (kind == 1 || kind == 2) { + s->range_table = &range_digital; + } else if (range) { s->range_table_list = range_table_list = kmalloc(sizeof (struct @@ -798,7 +800,7 @@ static int serial2002_attach(struct comedi_device *dev, return ret; /* digital input subdevice */ - s = dev->subdevices + 0; + s = &dev->subdevices[0]; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE; s->n_chan = 0; @@ -807,7 +809,7 @@ static int serial2002_attach(struct comedi_device *dev, s->insn_read = &serial2002_di_rinsn; /* digital output subdevice */ - s = dev->subdevices + 1; + s = &dev->subdevices[1]; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITEABLE; s->n_chan = 0; @@ -816,7 +818,7 @@ static int serial2002_attach(struct comedi_device *dev, s->insn_write = &serial2002_do_winsn; /* analog input subdevice */ - s = dev->subdevices + 2; + s = &dev->subdevices[2]; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND; s->n_chan = 0; @@ -825,7 +827,7 @@ static int serial2002_attach(struct comedi_device *dev, s->insn_read = &serial2002_ai_rinsn; /* analog output subdevice */ - s = dev->subdevices + 3; + s = &dev->subdevices[3]; s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITEABLE; s->n_chan = 0; @@ -835,7 +837,7 @@ static int serial2002_attach(struct comedi_device *dev, s->insn_read = &serial2002_ao_rinsn; /* encoder input subdevice */ - s = dev->subdevices + 4; + s = &dev->subdevices[4]; s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = SDF_READABLE | SDF_LSAMPL; s->n_chan = 0; diff --git a/drivers/staging/comedi/drivers/skel.c b/drivers/staging/comedi/drivers/skel.c index 9a68eebefca0..b70cdf300bbd 100644 --- a/drivers/staging/comedi/drivers/skel.c +++ b/drivers/staging/comedi/drivers/skel.c @@ -76,6 +76,8 @@ Configuration Options: #include <linux/pci.h> /* for PCI devices */ +#include "comedi_fc.h" + /* Imaginary registers for the imaginary board */ #define SKEL_SIZE 0 @@ -238,7 +240,7 @@ static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it) if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* dev->read_subdev=s; */ /* analog input subdevice */ s->type = COMEDI_SUBD_AI; @@ -256,7 +258,7 @@ static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it) */ s->do_cmdtest = skel_ai_cmdtest; - s = dev->subdevices + 1; + s = &dev->subdevices[1]; /* analog output subdevice */ s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITABLE; @@ -266,7 +268,7 @@ static int skel_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_write = skel_ao_winsn; s->insn_read = skel_ao_rinsn; - s = dev->subdevices + 2; + s = &dev->subdevices[2]; /* digital i/o subdevice */ if (thisboard->have_dio) { s->type = COMEDI_SUBD_DIO; @@ -349,60 +351,40 @@ static int skel_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s, return n; } +/* + * cmdtest tests a particular command to see if it is valid. + * Using the cmdtest ioctl, a user can create a valid cmd + * and then have it executes by the cmd ioctl. + * + * cmdtest returns 1,2,3,4 or 0, depending on which tests + * the command passes. + */ static int skel_ai_cmdtest(struct comedi_device *dev, - struct comedi_subdevice *s, struct comedi_cmd *cmd) + struct comedi_subdevice *s, + struct comedi_cmd *cmd) { int err = 0; int tmp; - /* cmdtest tests a particular command to see if it is valid. - * Using the cmdtest ioctl, a user can create a valid cmd - * and then have it executes by the cmd ioctl. - * - * cmdtest returns 1,2,3,4 or 0, depending on which tests - * the command passes. */ - - /* step 1: make sure trigger sources are trivially valid */ + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* step 2: make sure trigger sources are unique and mutually compatible - */ + /* Step 2a : make sure trigger sources are unique */ - /* note that mutual compatibility is not an issue here */ - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; diff --git a/drivers/staging/comedi/drivers/ssv_dnp.c b/drivers/staging/comedi/drivers/ssv_dnp.c index 84b9f2a4280b..ae3aa1c5caef 100644 --- a/drivers/staging/comedi/drivers/ssv_dnp.c +++ b/drivers/staging/comedi/drivers/ssv_dnp.c @@ -177,15 +177,13 @@ static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it) struct comedi_subdevice *s; int ret; - printk(KERN_INFO "comedi%d: dnp: ", dev->minor); - dev->board_name = board->name; ret = comedi_alloc_subdevices(dev, 1); if (ret) return ret; - s = dev->subdevices + 0; + s = &dev->subdevices[0]; /* digital i/o subdevice */ s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; @@ -195,8 +193,6 @@ static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it) s->insn_bits = dnp_dio_insn_bits; s->insn_config = dnp_dio_insn_config; - printk("attached\n"); - /* We use the I/O ports 0x22,0x23 and 0xa3-0xa9, which are always * allocated for the primary 8259, so we don't need to allocate them * ourselves. */ @@ -209,6 +205,7 @@ static int dnp_attach(struct comedi_device *dev, struct comedi_devconfig *it) outb(PCMR, CSCIR); outb((inb(CSCDR) & 0xAA), CSCDR); + dev_info(dev->class_dev, "%s: attached\n", dev->board_name); return 1; } diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c index 11ee83681da7..b536bba74351 100644 --- a/drivers/staging/comedi/drivers/usbdux.c +++ b/drivers/staging/comedi/drivers/usbdux.c @@ -98,6 +98,8 @@ sampling rate. If you sample two channels you get 4kHz and so on. #include "../comedidev.h" +#include "comedi_fc.h" + /* timeout for the USB-transfer in ms*/ #define BULK_TIMEOUT 1000 @@ -404,7 +406,7 @@ static void usbduxsub_ai_IsocIrq(struct urb *urb) /* the private structure of the subdevice is struct usbduxsub */ this_usbduxsub = this_comedidev->private; /* subdevice which is the AD converter */ - s = this_comedidev->subdevices + SUBDEV_AD; + s = &this_comedidev->subdevices[SUBDEV_AD]; /* first we test if something unusual has just happened */ switch (urb->status) { @@ -604,7 +606,7 @@ static void usbduxsub_ao_IsocIrq(struct urb *urb) /* the private structure of the subdevice is struct usbduxsub */ this_usbduxsub = this_comedidev->private; - s = this_comedidev->subdevices + SUBDEV_DA; + s = &this_comedidev->subdevices[SUBDEV_DA]; switch (urb->status) { case 0: @@ -929,9 +931,9 @@ static int usbduxsub_submit_OutURBs(struct usbduxsub *usbduxsub) static int usbdux_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - int err = 0, tmp, i; - unsigned int tmpTimer; struct usbduxsub *this_usbduxsub = dev->private; + int err = 0, i; + unsigned int tmpTimer; if (!(this_usbduxsub->probed)) return -ENODEV; @@ -939,51 +941,23 @@ static int usbdux_ai_cmdtest(struct comedi_device *dev, dev_dbg(&this_usbduxsub->interface->dev, "comedi%d: usbdux_ai_cmdtest\n", dev->minor); - /* make sure triggers are valid */ - /* Only immediate triggers are allowed */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_INT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - /* trigger should happen timed */ - tmp = cmd->scan_begin_src; - /* start a new _scan_ with a timer */ - cmd->scan_begin_src &= TRIG_TIMER; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - /* scanning is continuous */ - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - /* issue a trigger when scan is finished and start a new scan */ - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - /* trigger at the end of count events or not, stop condition or not */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* - * step 2: make sure trigger sources are unique and mutually compatible - * note that mutual compatibility is not an issue here - */ - if (cmd->scan_begin_src != TRIG_FOLLOW && - cmd->scan_begin_src != TRIG_EXT && - cmd->scan_begin_src != TRIG_TIMER) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -1488,8 +1462,9 @@ static int usbdux_ao_inttrig(struct comedi_device *dev, static int usbdux_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - int err = 0, tmp; struct usbduxsub *this_usbduxsub = dev->private; + int err = 0; + unsigned int flags; if (!this_usbduxsub) return -EFAULT; @@ -1500,69 +1475,46 @@ static int usbdux_ao_cmdtest(struct comedi_device *dev, dev_dbg(&this_usbduxsub->interface->dev, "comedi%d: usbdux_ao_cmdtest\n", dev->minor); - /* make sure triggers are valid */ - /* Only immediate triggers are allowed */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_INT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); - /* trigger should happen timed */ - tmp = cmd->scan_begin_src; - /* just now we scan also in the high speed mode every frame */ - /* this is due to ehci driver limitations */ if (0) { /* (this_usbduxsub->high_speed) */ - /* start immediately a new scan */ /* the sampling rate is set by the coversion rate */ - cmd->scan_begin_src &= TRIG_FOLLOW; + flags = TRIG_FOLLOW; } else { /* start a new scan (output at once) with a timer */ - cmd->scan_begin_src &= TRIG_TIMER; + flags = TRIG_TIMER; } - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; + err |= cfc_check_trigger_src(&cmd->scan_begin_src, flags); - /* scanning is continuous */ - tmp = cmd->convert_src; - /* we always output at 1kHz just now all channels at once */ if (0) { /* (this_usbduxsub->high_speed) */ /* - * in usb-2.0 only one conversion it transmitted but with 8kHz/n + * in usb-2.0 only one conversion it transmitted + * but with 8kHz/n */ - cmd->convert_src &= TRIG_TIMER; + flags = TRIG_TIMER; } else { - /* all conversion events happen simultaneously with a rate of - * 1kHz/n */ - cmd->convert_src &= TRIG_NOW; + /* + * all conversion events happen simultaneously with + * a rate of 1kHz/n + */ + flags = TRIG_NOW; } - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - /* issue a trigger when scan is finished and start a new scan */ - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; + err |= cfc_check_trigger_src(&cmd->convert_src, flags); - /* trigger at the end of count events or not, stop condition or not */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* - * step 2: make sure trigger sources are unique and mutually compatible - * note that mutual compatibility is not an issue here - */ - if (cmd->scan_begin_src != TRIG_FOLLOW && - cmd->scan_begin_src != TRIG_EXT && - cmd->scan_begin_src != TRIG_TIMER) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -1947,7 +1899,7 @@ static void usbduxsub_pwm_irq(struct urb *urb) /* the private structure of the subdevice is struct usbduxsub */ this_usbduxsub = this_comedidev->private; - s = this_comedidev->subdevices + SUBDEV_DA; + s = &this_comedidev->subdevices[SUBDEV_DA]; switch (urb->status) { case 0: @@ -2293,10 +2245,8 @@ static void tidy_up(struct usbduxsub *usbduxsub_tmp) usbduxsub_tmp->pwm_cmd_running = 0; } -/* common part of attach and attach_usb */ static int usbdux_attach_common(struct comedi_device *dev, - struct usbduxsub *udev, - void *aux_data, int aux_len) + struct usbduxsub *udev) { int ret; struct comedi_subdevice *s = NULL; @@ -2306,10 +2256,6 @@ static int usbdux_attach_common(struct comedi_device *dev, /* pointer back to the corresponding comedi device */ udev->comedidev = dev; - /* trying to upload the firmware into the chip */ - if (aux_data) - firmwareUpload(udev, aux_data, aux_len); - dev->board_name = "usbdux"; /* set number of subdevices */ @@ -2331,7 +2277,7 @@ static int usbdux_attach_common(struct comedi_device *dev, dev->private = udev; /* the first subdevice is the A/D converter */ - s = dev->subdevices + SUBDEV_AD; + s = &dev->subdevices[SUBDEV_AD]; /* the URBs get the comedi subdevice */ /* which is responsible for reading */ /* this is the subdevice which reads data */ @@ -2358,7 +2304,7 @@ static int usbdux_attach_common(struct comedi_device *dev, s->range_table = (&range_usbdux_ai_range); /* analog out */ - s = dev->subdevices + SUBDEV_DA; + s = &dev->subdevices[SUBDEV_DA]; /* analog out */ s->type = COMEDI_SUBD_AO; /* backward pointer */ @@ -2384,7 +2330,7 @@ static int usbdux_attach_common(struct comedi_device *dev, s->insn_write = usbdux_ao_insn_write; /* digital I/O */ - s = dev->subdevices + SUBDEV_DIO; + s = &dev->subdevices[SUBDEV_DIO]; s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; s->n_chan = 8; @@ -2396,7 +2342,7 @@ static int usbdux_attach_common(struct comedi_device *dev, s->private = NULL; /* counter */ - s = dev->subdevices + SUBDEV_COUNTER; + s = &dev->subdevices[SUBDEV_COUNTER]; s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = SDF_WRITABLE | SDF_READABLE; s->n_chan = 4; @@ -2407,7 +2353,7 @@ static int usbdux_attach_common(struct comedi_device *dev, if (udev->high_speed) { /* timer / pwm */ - s = dev->subdevices + SUBDEV_PWM; + s = &dev->subdevices[SUBDEV_PWM]; s->type = COMEDI_SUBD_PWM; s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE; s->n_chan = 8; @@ -2429,48 +2375,6 @@ static int usbdux_attach_common(struct comedi_device *dev, return 0; } -/* is called when comedi-config is called */ -static int usbdux_attach(struct comedi_device *dev, struct comedi_devconfig *it) -{ - int ret; - int index; - int i; - void *aux_data; - int aux_len; - - dev->private = NULL; - - aux_data = comedi_aux_data(it->options, 0); - aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]; - if (aux_data == NULL) - aux_len = 0; - else if (aux_len == 0) - aux_data = NULL; - - down(&start_stop_sem); - /* find a valid device which has been detected by the probe function of - * the usb */ - index = -1; - for (i = 0; i < NUMUSBDUX; i++) { - if ((usbduxsub[i].probed) && (!usbduxsub[i].attached)) { - index = i; - break; - } - } - - if (index < 0) { - printk(KERN_ERR - "comedi%d: usbdux: error: attach failed, no usbdux devs connected to the usb bus.\n", - dev->minor); - ret = -ENODEV; - } else - ret = usbdux_attach_common(dev, &usbduxsub[index], - aux_data, aux_len); - up(&start_stop_sem); - return ret; -} - -/* is called from comedi_usb_auto_config() */ static int usbdux_attach_usb(struct comedi_device *dev, struct usb_interface *uinterf) { @@ -2492,7 +2396,7 @@ static int usbdux_attach_usb(struct comedi_device *dev, dev->minor); ret = -ENODEV; } else - ret = usbdux_attach_common(dev, this_usbduxsub, NULL, 0); + ret = usbdux_attach_common(dev, this_usbduxsub); up(&start_stop_sem); return ret; } @@ -2513,9 +2417,8 @@ static void usbdux_detach(struct comedi_device *dev) static struct comedi_driver usbdux_driver = { .driver_name = "usbdux", .module = THIS_MODULE, - .attach = usbdux_attach, - .detach = usbdux_detach, .attach_usb = usbdux_attach_usb, + .detach = usbdux_detach, }; static void usbdux_firmware_request_complete_handler(const struct firmware *fw, diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c index 8eb41257c6ce..1154a7e2895d 100644 --- a/drivers/staging/comedi/drivers/usbduxfast.c +++ b/drivers/staging/comedi/drivers/usbduxfast.c @@ -346,7 +346,7 @@ static void usbduxfastsub_ai_Irq(struct urb *urb) return; } /* subdevice which is the AD converter */ - s = this_comedidev->subdevices + SUBDEV_AD; + s = &this_comedidev->subdevices[SUBDEV_AD]; /* first we test if something unusual has just happened */ switch (urb->status) { @@ -549,10 +549,10 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - int err = 0, stop_mask = 0; + struct usbduxfastsub_s *udfs = dev->private; + int err = 0; long int steps, tmp; int minSamplPer; - struct usbduxfastsub_s *udfs = dev->private; if (!udfs->probed) return -ENODEV; @@ -563,57 +563,31 @@ static int usbduxfast_ai_cmdtest(struct comedi_device *dev, "scan_begin_arg=%u\n", dev->minor, cmd->convert_arg, cmd->scan_begin_arg); #endif - /* step 1: make sure trigger sources are trivially valid */ - - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_EXT | TRIG_INT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - tmp = cmd->scan_begin_src; - cmd->scan_begin_src &= TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_TIMER | TRIG_EXT; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - tmp = cmd->stop_src; - stop_mask = TRIG_COUNT | TRIG_NONE; - cmd->stop_src &= stop_mask; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, + TRIG_NOW | TRIG_EXT | TRIG_INT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, + TRIG_TIMER | TRIG_FOLLOW | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_TIMER | TRIG_EXT); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* - * step 2: make sure trigger sources are unique and mutually compatible - */ + /* Step 2a : make sure trigger sources are unique */ - if (cmd->start_src != TRIG_NOW && - cmd->start_src != TRIG_EXT && cmd->start_src != TRIG_INT) - err++; - if (cmd->scan_begin_src != TRIG_TIMER && - cmd->scan_begin_src != TRIG_FOLLOW && - cmd->scan_begin_src != TRIG_EXT) - err++; - if (cmd->convert_src != TRIG_TIMER && cmd->convert_src != TRIG_EXT) - err++; - if (cmd->stop_src != TRIG_COUNT && - cmd->stop_src != TRIG_EXT && cmd->stop_src != TRIG_NONE) - err++; + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->scan_begin_src); + err |= cfc_check_trigger_is_unique(cmd->convert_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ /* can't have external stop and start triggers at once */ if (cmd->start_src == TRIG_EXT && cmd->stop_src == TRIG_EXT) - err++; + err |= -EINVAL; if (err) return 2; @@ -1430,10 +1404,8 @@ static void tidy_up(struct usbduxfastsub_s *udfs) udfs->ai_cmd_running = 0; } -/* common part of attach and attach_usb */ static int usbduxfast_attach_common(struct comedi_device *dev, - struct usbduxfastsub_s *udfs, - void *aux_data, int aux_len) + struct usbduxfastsub_s *udfs) { int ret; struct comedi_subdevice *s; @@ -1441,9 +1413,6 @@ static int usbduxfast_attach_common(struct comedi_device *dev, down(&udfs->sem); /* pointer back to the corresponding comedi device */ udfs->comedidev = dev; - /* trying to upload the firmware into the chip */ - if (aux_data) - firmwareUpload(udfs, aux_data, aux_len); dev->board_name = "usbduxfast"; ret = comedi_alloc_subdevices(dev, 1); if (ret) { @@ -1453,7 +1422,7 @@ static int usbduxfast_attach_common(struct comedi_device *dev, /* private structure is also simply the usb-structure */ dev->private = udfs; /* the first subdevice is the A/D converter */ - s = dev->subdevices + SUBDEV_AD; + s = &dev->subdevices[SUBDEV_AD]; /* * the URBs get the comedi subdevice which is responsible for reading * this is the subdevice which reads data @@ -1485,48 +1454,6 @@ static int usbduxfast_attach_common(struct comedi_device *dev, return 0; } -/* is called for COMEDI_DEVCONFIG ioctl (when comedi_config is run) */ -static int usbduxfast_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - int ret; - int index; - int i; - void *aux_data; - int aux_len; - - dev->private = NULL; - - aux_data = comedi_aux_data(it->options, 0); - aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]; - if (aux_data == NULL) - aux_len = 0; - else if (aux_len == 0) - aux_data = NULL; - down(&start_stop_sem); - /* - * find a valid device which has been detected by the - * probe function of the usb - */ - index = -1; - for (i = 0; i < NUMUSBDUXFAST; i++) { - if (usbduxfastsub[i].probed && !usbduxfastsub[i].attached) { - index = i; - break; - } - } - if (index < 0) { - dev_err(dev->class_dev, - "usbduxfast: error: attach failed, no usbduxfast devs connected to the usb bus.\n"); - ret = -ENODEV; - } else - ret = usbduxfast_attach_common(dev, &usbduxfastsub[index], - aux_data, aux_len); - up(&start_stop_sem); - return ret; -} - -/* is called from comedi_usb_auto_config() */ static int usbduxfast_attach_usb(struct comedi_device *dev, struct usb_interface *uinterf) { @@ -1545,7 +1472,7 @@ static int usbduxfast_attach_usb(struct comedi_device *dev, "usbduxfast: error: attach_usb failed, already attached\n"); ret = -ENODEV; } else - ret = usbduxfast_attach_common(dev, udfs, NULL, 0); + ret = usbduxfast_attach_common(dev, udfs); up(&start_stop_sem); return ret; } @@ -1568,9 +1495,8 @@ static void usbduxfast_detach(struct comedi_device *dev) static struct comedi_driver usbduxfast_driver = { .driver_name = "usbduxfast", .module = THIS_MODULE, - .attach = usbduxfast_attach, - .detach = usbduxfast_detach, .attach_usb = usbduxfast_attach_usb, + .detach = usbduxfast_detach, }; static void usbduxfast_firmware_request_complete_handler(const struct firmware diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c index f54ab8c2fcfd..b1694121f845 100644 --- a/drivers/staging/comedi/drivers/usbduxsigma.c +++ b/drivers/staging/comedi/drivers/usbduxsigma.c @@ -356,7 +356,7 @@ static void usbduxsub_ai_IsocIrq(struct urb *urb) /* the private structure of the subdevice is struct usbduxsub */ this_usbduxsub = this_comedidev->private; /* subdevice which is the AD converter */ - s = this_comedidev->subdevices + SUBDEV_AD; + s = &this_comedidev->subdevices[SUBDEV_AD]; /* first we test if something unusual has just happened */ switch (urb->status) { @@ -558,7 +558,7 @@ static void usbduxsub_ao_IsocIrq(struct urb *urb) /* the private structure of the subdevice is struct usbduxsub */ this_usbduxsub = this_comedidev->private; - s = this_comedidev->subdevices + SUBDEV_DA; + s = &this_comedidev->subdevices[SUBDEV_DA]; switch (urb->status) { case 0: @@ -897,9 +897,9 @@ static int usbdux_ai_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - int err = 0, tmp, i; - unsigned int tmpTimer; struct usbduxsub *this_usbduxsub = dev->private; + int err = 0, i; + unsigned int tmpTimer; if (!(this_usbduxsub->probed)) return -ENODEV; @@ -907,51 +907,23 @@ static int usbdux_ai_cmdtest(struct comedi_device *dev, dev_dbg(&this_usbduxsub->interface->dev, "comedi%d: usbdux_ai_cmdtest\n", dev->minor); - /* make sure triggers are valid */ - /* Only immediate triggers are allowed */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_INT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; - - /* trigger should happen timed */ - tmp = cmd->scan_begin_src; - /* start a new _scan_ with a timer */ - cmd->scan_begin_src &= TRIG_TIMER; - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - /* scanning is continuous */ - tmp = cmd->convert_src; - cmd->convert_src &= TRIG_NOW; - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; + /* Step 1 : check if triggers are trivially valid */ - /* issue a trigger when scan is finished and start a new scan */ - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - /* trigger at the end of count events or not, stop condition or not */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); + err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_TIMER); + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* - * step 2: make sure trigger sources are unique and mutually compatible - * note that mutual compatibility is not an issue here - */ - if (cmd->scan_begin_src != TRIG_FOLLOW && - cmd->scan_begin_src != TRIG_EXT && - cmd->scan_begin_src != TRIG_TIMER) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -1558,8 +1530,9 @@ static int usbdux_ao_cmdtest(struct comedi_device *dev, struct comedi_subdevice *s, struct comedi_cmd *cmd) { - int err = 0, tmp; struct usbduxsub *this_usbduxsub = dev->private; + int err = 0; + unsigned int flags; if (!this_usbduxsub) return -EFAULT; @@ -1570,63 +1543,35 @@ static int usbdux_ao_cmdtest(struct comedi_device *dev, dev_dbg(&this_usbduxsub->interface->dev, "comedi%d: usbdux_ao_cmdtest\n", dev->minor); - /* make sure triggers are valid */ - /* Only immediate triggers are allowed */ - tmp = cmd->start_src; - cmd->start_src &= TRIG_NOW | TRIG_INT; - if (!cmd->start_src || tmp != cmd->start_src) - err++; + /* Step 1 : check if triggers are trivially valid */ + + err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW | TRIG_INT); - /* trigger should happen timed */ - tmp = cmd->scan_begin_src; - /* just now we scan also in the high speed mode every frame */ - /* this is due to ehci driver limitations */ if (0) { /* (this_usbduxsub->high_speed) */ - /* start immediately a new scan */ - /* the sampling rate is set by the coversion rate */ - cmd->scan_begin_src &= TRIG_FOLLOW; + /* + * start immediately a new scan + * the sampling rate is set by the coversion rate + */ + flags = TRIG_FOLLOW; } else { /* start a new scan (output at once) with a timer */ - cmd->scan_begin_src &= TRIG_TIMER; + flags = TRIG_TIMER; } - if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src) - err++; - - /* scanning is continuous */ - tmp = cmd->convert_src; + err |= cfc_check_trigger_src(&cmd->scan_begin_src, flags); - /* all conversion events happen simultaneously */ - cmd->convert_src &= TRIG_NOW; - - if (!cmd->convert_src || tmp != cmd->convert_src) - err++; - - /* issue a trigger when scan is finished and start a new scan */ - tmp = cmd->scan_end_src; - cmd->scan_end_src &= TRIG_COUNT; - if (!cmd->scan_end_src || tmp != cmd->scan_end_src) - err++; - - /* trigger at the end of count events or not, stop condition or not */ - tmp = cmd->stop_src; - cmd->stop_src &= TRIG_COUNT | TRIG_NONE; - if (!cmd->stop_src || tmp != cmd->stop_src) - err++; + err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_NOW); + err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT); + err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_COUNT | TRIG_NONE); if (err) return 1; - /* - * step 2: make sure trigger sources - * are unique and mutually compatible - * note that mutual compatibility is not an issue here - */ - if (cmd->scan_begin_src != TRIG_FOLLOW && - cmd->scan_begin_src != TRIG_EXT && - cmd->scan_begin_src != TRIG_TIMER) - err++; - if (cmd->stop_src != TRIG_COUNT && cmd->stop_src != TRIG_NONE) - err++; + /* Step 2a : make sure trigger sources are unique */ + + err |= cfc_check_trigger_is_unique(cmd->start_src); + err |= cfc_check_trigger_is_unique(cmd->stop_src); + + /* Step 2b : and mutually compatible */ if (err) return 2; @@ -1950,7 +1895,7 @@ static void usbduxsub_pwm_irq(struct urb *urb) /* the private structure of the subdevice is struct usbduxsub */ this_usbduxsub = this_comedidev->private; - s = this_comedidev->subdevices + SUBDEV_DA; + s = &this_comedidev->subdevices[SUBDEV_DA]; switch (urb->status) { case 0: @@ -2301,10 +2246,8 @@ static void tidy_up(struct usbduxsub *usbduxsub_tmp) usbduxsub_tmp->pwm_cmd_running = 0; } -/* common part of attach and attach_usb */ static int usbduxsigma_attach_common(struct comedi_device *dev, - struct usbduxsub *uds, - void *aux_data, int aux_len) + struct usbduxsub *uds) { int ret; struct comedi_subdevice *s; @@ -2314,9 +2257,6 @@ static int usbduxsigma_attach_common(struct comedi_device *dev, down(&uds->sem); /* pointer back to the corresponding comedi device */ uds->comedidev = dev; - /* trying to upload the firmware into the FX2 */ - if (aux_data) - firmwareUpload(uds, aux_data, aux_len); dev->board_name = "usbduxsigma"; /* set number of subdevices */ if (uds->high_speed) @@ -2331,7 +2271,7 @@ static int usbduxsigma_attach_common(struct comedi_device *dev, /* private structure is also simply the usb-structure */ dev->private = uds; /* the first subdevice is the A/D converter */ - s = dev->subdevices + SUBDEV_AD; + s = &dev->subdevices[SUBDEV_AD]; /* the URBs get the comedi subdevice */ /* which is responsible for reading */ /* this is the subdevice which reads data */ @@ -2358,7 +2298,7 @@ static int usbduxsigma_attach_common(struct comedi_device *dev, /* range table to convert to physical units */ s->range_table = (&range_usbdux_ai_range); /* analog output subdevice */ - s = dev->subdevices + SUBDEV_DA; + s = &dev->subdevices[SUBDEV_DA]; /* analog out */ s->type = COMEDI_SUBD_AO; /* backward pointer */ @@ -2383,7 +2323,7 @@ static int usbduxsigma_attach_common(struct comedi_device *dev, s->insn_read = usbdux_ao_insn_read; s->insn_write = usbdux_ao_insn_write; /* digital I/O subdevice */ - s = dev->subdevices + SUBDEV_DIO; + s = &dev->subdevices[SUBDEV_DIO]; s->type = COMEDI_SUBD_DIO; s->subdev_flags = SDF_READABLE | SDF_WRITABLE; /* 8 external and 16 internal channels */ @@ -2396,7 +2336,7 @@ static int usbduxsigma_attach_common(struct comedi_device *dev, s->private = NULL; if (uds->high_speed) { /* timer / pwm subdevice */ - s = dev->subdevices + SUBDEV_PWM; + s = &dev->subdevices[SUBDEV_PWM]; s->type = COMEDI_SUBD_PWM; s->subdev_flags = SDF_WRITABLE | SDF_PWM_HBRIDGE; s->n_chan = 8; @@ -2419,47 +2359,6 @@ static int usbduxsigma_attach_common(struct comedi_device *dev, return 0; } -/* is called for COMEDI_DEVCONFIG ioctl (when comedi_config is run) */ -static int usbduxsigma_attach(struct comedi_device *dev, - struct comedi_devconfig *it) -{ - int ret; - int index; - int i; - void *aux_data; - int aux_len; - - dev->private = NULL; - - aux_data = comedi_aux_data(it->options, 0); - aux_len = it->options[COMEDI_DEVCONF_AUX_DATA_LENGTH]; - if (aux_data == NULL) - aux_len = 0; - else if (aux_len == 0) - aux_data = NULL; - - down(&start_stop_sem); - /* find a valid device which has been detected by the probe function of - * the usb */ - index = -1; - for (i = 0; i < NUMUSBDUX; i++) { - if ((usbduxsub[i].probed) && (!usbduxsub[i].attached)) { - index = i; - break; - } - } - if (index < 0) { - dev_err(dev->class_dev, - "usbduxsigma: error: attach failed, dev not connected to the usb bus.\n"); - ret = -ENODEV; - } else - ret = usbduxsigma_attach_common(dev, &usbduxsub[index], - aux_data, aux_len); - up(&start_stop_sem); - return ret; -} - -/* is called from comedi_usb_auto_config() */ static int usbduxsigma_attach_usb(struct comedi_device *dev, struct usb_interface *uinterf) { @@ -2478,7 +2377,7 @@ static int usbduxsigma_attach_usb(struct comedi_device *dev, "usbduxsigma: error: attach_usb failed, already attached\n"); ret = -ENODEV; } else - ret = usbduxsigma_attach_common(dev, uds, NULL, 0); + ret = usbduxsigma_attach_common(dev, uds); up(&start_stop_sem); return ret; } @@ -2499,9 +2398,8 @@ static void usbduxsigma_detach(struct comedi_device *dev) static struct comedi_driver usbduxsigma_driver = { .driver_name = "usbduxsigma", .module = THIS_MODULE, - .attach = usbduxsigma_attach, - .detach = usbduxsigma_detach, .attach_usb = usbduxsigma_attach_usb, + .detach = usbduxsigma_detach, }; static void usbdux_firmware_request_complete_handler(const struct firmware *fw, diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c index 94010fc05905..df277aa591bb 100644 --- a/drivers/staging/comedi/drivers/vmk80xx.c +++ b/drivers/staging/comedi/drivers/vmk80xx.c @@ -546,6 +546,7 @@ static int vmk80xx_ai_rinsn(struct comedi_device *cdev, reg[0] = VMK8055_AI2_REG; break; case VMK8061_MODEL: + default: reg[0] = VMK8061_AI_REG1; reg[1] = VMK8061_AI_REG2; dev->usb_tx_buf[0] = VMK8061_CMD_RD_AI; @@ -904,6 +905,7 @@ static int vmk80xx_cnt_rinsn(struct comedi_device *cdev, reg[0] = VMK8055_CNT2_REG; break; case VMK8061_MODEL: + default: reg[0] = VMK8061_CNT_REG; reg[1] = VMK8061_CNT_REG; dev->usb_tx_buf[0] = VMK8061_CMD_RD_CNT; @@ -1119,7 +1121,7 @@ static int vmk80xx_attach_common(struct comedi_device *cdev, return ret; } /* Analog input subdevice */ - s = cdev->subdevices + VMK80XX_SUBD_AI; + s = &cdev->subdevices[VMK80XX_SUBD_AI]; s->type = COMEDI_SUBD_AI; s->subdev_flags = SDF_READABLE | SDF_GROUND; s->n_chan = dev->board.ai_chans; @@ -1127,7 +1129,7 @@ static int vmk80xx_attach_common(struct comedi_device *cdev, s->range_table = dev->board.range; s->insn_read = vmk80xx_ai_rinsn; /* Analog output subdevice */ - s = cdev->subdevices + VMK80XX_SUBD_AO; + s = &cdev->subdevices[VMK80XX_SUBD_AO]; s->type = COMEDI_SUBD_AO; s->subdev_flags = SDF_WRITEABLE | SDF_GROUND; s->n_chan = dev->board.ao_chans; @@ -1139,7 +1141,7 @@ static int vmk80xx_attach_common(struct comedi_device *cdev, s->insn_read = vmk80xx_ao_rinsn; } /* Digital input subdevice */ - s = cdev->subdevices + VMK80XX_SUBD_DI; + s = &cdev->subdevices[VMK80XX_SUBD_DI]; s->type = COMEDI_SUBD_DI; s->subdev_flags = SDF_READABLE | SDF_GROUND; s->n_chan = dev->board.di_chans; @@ -1147,7 +1149,7 @@ static int vmk80xx_attach_common(struct comedi_device *cdev, s->insn_read = vmk80xx_di_rinsn; s->insn_bits = vmk80xx_di_bits; /* Digital output subdevice */ - s = cdev->subdevices + VMK80XX_SUBD_DO; + s = &cdev->subdevices[VMK80XX_SUBD_DO]; s->type = COMEDI_SUBD_DO; s->subdev_flags = SDF_WRITEABLE | SDF_GROUND; s->n_chan = dev->board.do_chans; @@ -1159,7 +1161,7 @@ static int vmk80xx_attach_common(struct comedi_device *cdev, s->insn_read = vmk80xx_do_rinsn; } /* Counter subdevice */ - s = cdev->subdevices + VMK80XX_SUBD_CNT; + s = &cdev->subdevices[VMK80XX_SUBD_CNT]; s->type = COMEDI_SUBD_COUNTER; s->subdev_flags = SDF_READABLE; s->n_chan = dev->board.cnt_chans; @@ -1172,7 +1174,7 @@ static int vmk80xx_attach_common(struct comedi_device *cdev, } /* PWM subdevice */ if (dev->board.model == VMK8061_MODEL) { - s = cdev->subdevices + VMK80XX_SUBD_PWM; + s = &cdev->subdevices[VMK80XX_SUBD_PWM]; s->type = COMEDI_SUBD_PWM; s->subdev_flags = SDF_READABLE | SDF_WRITEABLE; s->n_chan = dev->board.pwm_chans; diff --git a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c index 0252b4408851..3f20ea55b8d0 100644 --- a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c +++ b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c @@ -80,7 +80,9 @@ int comedi_close(struct comedi_device *d) } EXPORT_SYMBOL(comedi_close); -static int comedi_do_insn(struct comedi_device *dev, struct comedi_insn *insn) +static int comedi_do_insn(struct comedi_device *dev, + struct comedi_insn *insn, + unsigned int *data) { struct comedi_subdevice *s; int ret = 0; @@ -90,7 +92,7 @@ static int comedi_do_insn(struct comedi_device *dev, struct comedi_insn *insn) ret = -EINVAL; goto error; } - s = dev->subdevices + insn->subdev; + s = &dev->subdevices[insn->subdev]; if (s->type == COMEDI_SUBD_UNUSED) { printk(KERN_ERR "%d not useable subdevice\n", insn->subdev); @@ -115,11 +117,11 @@ static int comedi_do_insn(struct comedi_device *dev, struct comedi_insn *insn) switch (insn->insn) { case INSN_BITS: - ret = s->insn_bits(dev, s, insn, insn->data); + ret = s->insn_bits(dev, s, insn, data); break; case INSN_CONFIG: /* XXX should check instruction length */ - ret = s->insn_config(dev, s, insn, insn->data); + ret = s->insn_config(dev, s, insn, data); break; default: ret = -EINVAL; @@ -140,11 +142,10 @@ int comedi_dio_config(struct comedi_device *dev, unsigned int subdev, memset(&insn, 0, sizeof(insn)); insn.insn = INSN_CONFIG; insn.n = 1; - insn.data = &io; insn.subdev = subdev; insn.chanspec = CR_PACK(chan, 0, 0); - return comedi_do_insn(dev, &insn); + return comedi_do_insn(dev, &insn, &io); } EXPORT_SYMBOL(comedi_dio_config); @@ -158,13 +159,12 @@ int comedi_dio_bitfield(struct comedi_device *dev, unsigned int subdev, memset(&insn, 0, sizeof(insn)); insn.insn = INSN_BITS; insn.n = 2; - insn.data = data; insn.subdev = subdev; data[0] = mask; data[1] = *bits; - ret = comedi_do_insn(dev, &insn); + ret = comedi_do_insn(dev, &insn, data); *bits = data[1]; @@ -175,11 +175,14 @@ EXPORT_SYMBOL(comedi_dio_bitfield); int comedi_find_subdevice_by_type(struct comedi_device *dev, int type, unsigned int subd) { + struct comedi_subdevice *s; + if (subd > dev->n_subdevices) return -ENODEV; for (; subd < dev->n_subdevices; subd++) { - if (dev->subdevices[subd].type == type) + s = &dev->subdevices[subd]; + if (s->type == type) return subd; } return -1; @@ -188,7 +191,7 @@ EXPORT_SYMBOL(comedi_find_subdevice_by_type); int comedi_get_n_channels(struct comedi_device *dev, unsigned int subdevice) { - struct comedi_subdevice *s = dev->subdevices + subdevice; + struct comedi_subdevice *s = &dev->subdevices[subdevice]; return s->n_chan; } diff --git a/drivers/staging/comedi/range.c b/drivers/staging/comedi/range.c index 41f95237789d..59ff0cf73381 100644 --- a/drivers/staging/comedi/range.c +++ b/drivers/staging/comedi/range.c @@ -68,7 +68,7 @@ int do_rangeinfo_ioctl(struct comedi_device *dev, return -EINVAL; if (subd >= dev->n_subdevices) return -EINVAL; - s = dev->subdevices + subd; + s = &dev->subdevices[subd]; if (s->range_table) { lr = s->range_table; } else if (s->range_table_list) { @@ -131,6 +131,7 @@ static int aref_invalid(struct comedi_subdevice *s, unsigned int chanspec) int comedi_check_chanlist(struct comedi_subdevice *s, int n, unsigned int *chanlist) { + struct comedi_device *dev = s->device; int i; int chan; @@ -139,10 +140,10 @@ int comedi_check_chanlist(struct comedi_subdevice *s, int n, if (CR_CHAN(chanlist[i]) >= s->n_chan || CR_RANGE(chanlist[i]) >= s->range_table->length || aref_invalid(s, chanlist[i])) { - printk(KERN_ERR "bad chanlist[%d]=0x%08x " - "in_chan=%d range length=%d\n", i, - chanlist[i], s->n_chan, - s->range_table->length); + dev_warn(dev->class_dev, + "bad chanlist[%d]=0x%08x in_chan=%d range length=%d\n", + i, chanlist[i], s->n_chan, + s->range_table->length); return -EINVAL; } } else if (s->range_table_list) { @@ -152,13 +153,14 @@ int comedi_check_chanlist(struct comedi_subdevice *s, int n, CR_RANGE(chanlist[i]) >= s->range_table_list[chan]->length || aref_invalid(s, chanlist[i])) { - printk(KERN_ERR "bad chanlist[%d]=0x%08x\n", - i, chanlist[i]); + dev_warn(dev->class_dev, + "bad chanlist[%d]=0x%08x\n", + i, chanlist[i]); return -EINVAL; } } } else { - printk(KERN_ERR "comedi: (bug) no range type list!\n"); + dev_err(dev->class_dev, "(bug) no range type list!\n"); return -EINVAL; } return 0; diff --git a/drivers/staging/cptm1217/clearpad_tm1217.c b/drivers/staging/cptm1217/clearpad_tm1217.c index 0d924d3a2ab1..a49b0da60049 100644 --- a/drivers/staging/cptm1217/clearpad_tm1217.c +++ b/drivers/staging/cptm1217/clearpad_tm1217.c @@ -658,18 +658,7 @@ static struct i2c_driver cp_tm1217_driver = { .resume = cp_tm1217_resume, }; -static int __init clearpad_tm1217_init(void) -{ - return i2c_add_driver(&cp_tm1217_driver); -} - -static void __exit clearpad_tm1217_exit(void) -{ - i2c_del_driver(&cp_tm1217_driver); -} - -module_init(clearpad_tm1217_init); -module_exit(clearpad_tm1217_exit); +module_i2c_driver(cp_tm1217_driver); MODULE_AUTHOR("Ramesh Agarwal <ramesh.agarwal@intel.com>"); MODULE_DESCRIPTION("Synaptics TM1217 TouchScreen Driver"); diff --git a/drivers/staging/crystalhd/crystalhd_lnx.c b/drivers/staging/crystalhd/crystalhd_lnx.c index d9e3d618f7f4..166203aeb7b4 100644 --- a/drivers/staging/crystalhd/crystalhd_lnx.c +++ b/drivers/staging/crystalhd/crystalhd_lnx.c @@ -373,13 +373,15 @@ static int __devinit chd_dec_init_chdev(struct crystalhd_adp *adp) /* register crystalhd class */ crystalhd_class = class_create(THIS_MODULE, "crystalhd"); if (IS_ERR(crystalhd_class)) { + rc = PTR_ERR(crystalhd_class); BCMLOG_ERR("failed to create class\n"); - goto fail; + goto class_create_fail; } dev = device_create(crystalhd_class, NULL, MKDEV(adp->chd_dec_major, 0), NULL, "crystalhd"); if (IS_ERR(dev)) { + rc = PTR_ERR(dev); BCMLOG_ERR("failed to create device\n"); goto device_create_fail; } @@ -410,6 +412,8 @@ elem_pool_fail: device_destroy(crystalhd_class, MKDEV(adp->chd_dec_major, 0)); device_create_fail: class_destroy(crystalhd_class); +class_create_fail: + unregister_chrdev(adp->chd_dec_major, CRYSTALHD_API_NAME); fail: return rc; } diff --git a/drivers/staging/csr/Makefile b/drivers/staging/csr/Makefile index afda44b0a925..ab626edc5ba4 100644 --- a/drivers/staging/csr/Makefile +++ b/drivers/staging/csr/Makefile @@ -25,7 +25,6 @@ csr_wifi-y := bh.o \ unifi_event.o \ unifi_pdu_processing.o \ unifi_sme.o \ - csr_formatted_io.o \ csr_wifi_hip_card_sdio.o \ csr_wifi_hip_card_sdio_intr.o \ csr_wifi_hip_card_sdio_mem.o \ diff --git a/drivers/staging/csr/bh.c b/drivers/staging/csr/bh.c index b089c28d5610..addee05a4516 100644 --- a/drivers/staging/csr/bh.c +++ b/drivers/staging/csr/bh.c @@ -32,45 +32,49 @@ * 0 on success or else a Linux error code. * --------------------------------------------------------------------------- */ -int -uf_start_thread(unifi_priv_t *priv, struct uf_thread *thread, int (*func)(void *)) +int uf_start_thread(unifi_priv_t *priv, + struct uf_thread *thread, int (*func)(void *)) { - if (thread->thread_task != NULL) { - unifi_error(priv, "%s thread already started\n", thread->name); - return 0; - } - - /* Start the kernel thread that handles all h/w accesses. */ - thread->thread_task = kthread_run(func, priv, "%s", thread->name); - if (IS_ERR(thread->thread_task)) { - return PTR_ERR(thread->thread_task); - } - - /* Module parameter overides the thread priority */ - if (bh_priority != -1) { - if (bh_priority >= 0 && bh_priority <= MAX_RT_PRIO) { - struct sched_param param; - priv->bh_thread.prio = bh_priority; - unifi_trace(priv, UDBG1, "%s thread (RT) priority = %d\n", - thread->name, bh_priority); - param.sched_priority = bh_priority; - sched_setscheduler(thread->thread_task, SCHED_FIFO, ¶m); - } else if (bh_priority > MAX_RT_PRIO && bh_priority <= MAX_PRIO) { - priv->bh_thread.prio = bh_priority; - unifi_trace(priv, UDBG1, "%s thread priority = %d\n", - thread->name, PRIO_TO_NICE(bh_priority)); - set_user_nice(thread->thread_task, PRIO_TO_NICE(bh_priority)); - } else { - priv->bh_thread.prio = DEFAULT_PRIO; - unifi_warning(priv, "%s thread unsupported (%d) priority\n", - thread->name, bh_priority); - } - } else { - priv->bh_thread.prio = DEFAULT_PRIO; - } - unifi_trace(priv, UDBG2, "Started %s thread\n", thread->name); - - return 0; + if (thread->thread_task != NULL) { + unifi_error(priv, "%s thread already started\n", thread->name); + return 0; + } + + /* Start the kernel thread that handles all h/w accesses. */ + thread->thread_task = kthread_run(func, priv, "%s", thread->name); + if (IS_ERR(thread->thread_task)) + return PTR_ERR(thread->thread_task); + + /* Module parameter overides the thread priority */ + if (bh_priority != -1) { + if (bh_priority >= 0 && bh_priority <= MAX_RT_PRIO) { + struct sched_param param; + priv->bh_thread.prio = bh_priority; + unifi_trace(priv, UDBG1, + "%s thread (RT) priority = %d\n", + thread->name, bh_priority); + param.sched_priority = bh_priority; + sched_setscheduler(thread->thread_task, + SCHED_FIFO, ¶m); + } else if (bh_priority > MAX_RT_PRIO && + bh_priority <= MAX_PRIO) { + priv->bh_thread.prio = bh_priority; + unifi_trace(priv, UDBG1, "%s thread priority = %d\n", + thread->name, + PRIO_TO_NICE(bh_priority)); + set_user_nice(thread->thread_task, + PRIO_TO_NICE(bh_priority)); + } else { + priv->bh_thread.prio = DEFAULT_PRIO; + unifi_warning(priv, + "%s thread unsupported (%d) priority\n", + thread->name, bh_priority); + } + } else + priv->bh_thread.prio = DEFAULT_PRIO; + unifi_trace(priv, UDBG2, "Started %s thread\n", thread->name); + + return 0; } /* uf_start_thread() */ @@ -88,18 +92,18 @@ uf_start_thread(unifi_priv_t *priv, struct uf_thread *thread, int (*func)(void * * * --------------------------------------------------------------------------- */ - void -uf_stop_thread(unifi_priv_t *priv, struct uf_thread *thread) +void uf_stop_thread(unifi_priv_t *priv, struct uf_thread *thread) { - if (!thread->thread_task) { - unifi_notice(priv, "%s thread is already stopped\n", thread->name); - return; - } + if (!thread->thread_task) { + unifi_notice(priv, "%s thread is already stopped\n", + thread->name); + return; + } - unifi_trace(priv, UDBG2, "Stopping %s thread\n", thread->name); + unifi_trace(priv, UDBG2, "Stopping %s thread\n", thread->name); - kthread_stop(thread->thread_task); - thread->thread_task = NULL; + kthread_stop(thread->thread_task); + thread->thread_task = NULL; } /* uf_stop_thread() */ @@ -118,23 +122,24 @@ uf_stop_thread(unifi_priv_t *priv, struct uf_thread *thread) * * --------------------------------------------------------------------------- */ - void +void uf_wait_for_thread_to_stop(unifi_priv_t *priv, struct uf_thread *thread) { - /* - * kthread_stop() cannot handle the thread exiting while - * kthread_should_stop() is false, so sleep until kthread_stop() - * wakes us up. - */ - unifi_trace(priv, UDBG2, "%s waiting for the stop signal.\n", thread->name); - set_current_state(TASK_INTERRUPTIBLE); - if (!kthread_should_stop()) { - unifi_trace(priv, UDBG2, "%s schedule....\n", thread->name); - schedule(); - } - - thread->thread_task = NULL; - unifi_trace(priv, UDBG2, "%s exiting....\n", thread->name); + /* + * kthread_stop() cannot handle the thread exiting while + * kthread_should_stop() is false, so sleep until kthread_stop() + * wakes us up + */ + unifi_trace(priv, UDBG2, "%s waiting for the stop signal.\n", + thread->name); + set_current_state(TASK_INTERRUPTIBLE); + if (!kthread_should_stop()) { + unifi_trace(priv, UDBG2, "%s schedule....\n", thread->name); + schedule(); + } + + thread->thread_task = NULL; + unifi_trace(priv, UDBG2, "%s exiting....\n", thread->name); } /* uf_wait_for_thread_to_stop() */ @@ -155,39 +160,41 @@ uf_wait_for_thread_to_stop(unifi_priv_t *priv, struct uf_thread *thread) * None. * --------------------------------------------------------------------------- */ - static void +static void handle_bh_error(unifi_priv_t *priv) { - u8 conf_param = CONFIG_IND_ERROR; - u8 interfaceTag = 0; /* used as a loop counter */ + netInterface_priv_t *interfacePriv; + u8 conf_param = CONFIG_IND_ERROR; + u8 interfaceTag; - /* Block unifi_run_bh() until the error has been handled. */ - priv->bh_thread.block_thread = 1; + /* Block unifi_run_bh() until the error has been handled. */ + priv->bh_thread.block_thread = 1; - /* Consider UniFi to be uninitialised */ - priv->init_progress = UNIFI_INIT_NONE; + /* Consider UniFi to be uninitialised */ + priv->init_progress = UNIFI_INIT_NONE; - /* Stop the network traffic */ - for( interfaceTag =0; interfaceTag <CSR_WIFI_NUM_INTERFACES;interfaceTag ++) { - netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag]; - if (interfacePriv->netdev_registered == 1) { - netif_carrier_off(priv->netdev[interfaceTag]); - } - } + /* Stop the network traffic */ + for (interfaceTag = 0; + interfaceTag < CSR_WIFI_NUM_INTERFACES; interfaceTag++) { + interfacePriv = priv->interfacePriv[interfaceTag]; + if (interfacePriv->netdev_registered) + netif_carrier_off(priv->netdev[interfaceTag]); + } #ifdef CSR_NATIVE_LINUX - /* Force any client waiting on an mlme_wait_for_reply() to abort. */ - uf_abort_mlme(priv); + /* Force any client waiting on an mlme_wait_for_reply() to abort. */ + uf_abort_mlme(priv); - /* Cancel any pending workqueue tasks */ - flush_workqueue(priv->unifi_workqueue); + /* Cancel any pending workqueue tasks */ + flush_workqueue(priv->unifi_workqueue); #endif /* CSR_NATIVE_LINUX */ - unifi_error(priv, "handle_bh_error: fatal error is reported to the SME.\n"); - /* Notify the clients (SME or unifi_manager) for the error. */ - ul_log_config_ind(priv, &conf_param, sizeof(u8)); + unifi_error(priv, + "handle_bh_error: fatal error is reported to the SME.\n"); + /* Notify the clients (SME or unifi_manager) for the error. */ + ul_log_config_ind(priv, &conf_param, sizeof(u8)); } /* handle_bh_error() */ diff --git a/drivers/staging/csr/csr_formatted_io.c b/drivers/staging/csr/csr_formatted_io.c deleted file mode 100644 index 7213cc8fb577..000000000000 --- a/drivers/staging/csr/csr_formatted_io.c +++ /dev/null @@ -1,27 +0,0 @@ -/***************************************************************************** - - (c) Cambridge Silicon Radio Limited 2010 - All rights reserved and confidential information of CSR - - Refer to LICENSE.txt included with this source for details - on the license terms. - -*****************************************************************************/ -#include <linux/kernel.h> -#include "csr_formatted_io.h" - -s32 CsrSnprintf(char *dest, size_t n, const char *fmt, ...) -{ - s32 r; - va_list args; - va_start(args, fmt); - r = vsnprintf(dest, n, fmt, args); - va_end(args); - - if (dest && (n > 0)) - { - dest[n - 1] = '\0'; - } - - return r; -} diff --git a/drivers/staging/csr/csr_formatted_io.h b/drivers/staging/csr/csr_formatted_io.h deleted file mode 100644 index 2e238cb98d51..000000000000 --- a/drivers/staging/csr/csr_formatted_io.h +++ /dev/null @@ -1,25 +0,0 @@ -#ifndef CSR_FORMATTED_IO_H__ -#define CSR_FORMATTED_IO_H__ -/***************************************************************************** - - (c) Cambridge Silicon Radio Limited 2010 - All rights reserved and confidential information of CSR - - Refer to LICENSE.txt included with this source for details - on the license terms. - -*****************************************************************************/ - -#ifdef __cplusplus -extern "C" { -#endif - -#include <linux/types.h> - -s32 CsrSnprintf(char *dest, size_t n, const char *fmt, ...); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/drivers/staging/csr/csr_framework_ext.c b/drivers/staging/csr/csr_framework_ext.c index 12e7ddf3220a..f91a4bf4e68f 100644 --- a/drivers/staging/csr/csr_framework_ext.c +++ b/drivers/staging/csr/csr_framework_ext.c @@ -12,20 +12,9 @@ #include <linux/version.h> #include <linux/kthread.h> #include <linux/module.h> - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34) -#include <linux/slab.h> -#endif - -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 19) #include <linux/freezer.h> -#endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) -#include <asm/semaphore.h> -#else #include <linux/semaphore.h> -#endif - +#include <linux/slab.h> #include <linux/bitops.h> #include "csr_framework_ext.h" diff --git a/drivers/staging/csr/csr_panic.c b/drivers/staging/csr/csr_panic.c index 353a829bb74c..095f7fa3ae2c 100644 --- a/drivers/staging/csr/csr_panic.c +++ b/drivers/staging/csr/csr_panic.c @@ -9,7 +9,6 @@ *****************************************************************************/ #include <linux/kernel.h> -#include <linux/version.h> #include <linux/module.h> #include "csr_panic.h" diff --git a/drivers/staging/csr/csr_time.c b/drivers/staging/csr/csr_time.c index 83586ca34e8c..7b597f7622a2 100644 --- a/drivers/staging/csr/csr_time.c +++ b/drivers/staging/csr/csr_time.c @@ -10,13 +10,6 @@ #include <linux/kernel.h> #include <linux/version.h> - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 16) -#include <linux/autoconf.h> -#include <linux/config.h> -#endif - #include <linux/time.h> #include <linux/module.h> @@ -24,20 +17,18 @@ CsrTime CsrTimeGet(CsrTime *high) { - struct timespec ts; - u64 time; - CsrTime low; + struct timespec ts; + u64 time; + CsrTime low; - ts = current_kernel_time(); - time = (u64) ts.tv_sec * 1000000 + ts.tv_nsec / 1000; + ts = current_kernel_time(); + time = (u64) ts.tv_sec * 1000000 + ts.tv_nsec / 1000; - if (high != NULL) - { - *high = (CsrTime) ((time >> 32) & 0xFFFFFFFF); - } + if (high != NULL) + *high = (CsrTime) ((time >> 32) & 0xFFFFFFFF); - low = (CsrTime) (time & 0xFFFFFFFF); + low = (CsrTime) (time & 0xFFFFFFFF); - return low; + return low; } EXPORT_SYMBOL_GPL(CsrTimeGet); diff --git a/drivers/staging/csr/csr_wifi_hip_card_sdio.c b/drivers/staging/csr/csr_wifi_hip_card_sdio.c index 44ab00c53fec..cf148a0fec6a 100644 --- a/drivers/staging/csr/csr_wifi_hip_card_sdio.c +++ b/drivers/staging/csr/csr_wifi_hip_card_sdio.c @@ -1612,13 +1612,13 @@ static CsrResult card_allocate_memory_resources(card_t *card) /* Reset any state carried forward from a previous life */ card->fh_command_queue.q_rd_ptr = 0; card->fh_command_queue.q_wr_ptr = 0; - (void)CsrSnprintf(card->fh_command_queue.name, UNIFI_QUEUE_NAME_MAX_LENGTH, + (void)scnprintf(card->fh_command_queue.name, UNIFI_QUEUE_NAME_MAX_LENGTH, "fh_cmd_q"); for (i = 0; i < UNIFI_NO_OF_TX_QS; i++) { card->fh_traffic_queue[i].q_rd_ptr = 0; card->fh_traffic_queue[i].q_wr_ptr = 0; - (void)CsrSnprintf(card->fh_traffic_queue[i].name, + (void)scnprintf(card->fh_traffic_queue[i].name, UNIFI_QUEUE_NAME_MAX_LENGTH, "fh_data_q%d", i); } #ifndef CSR_WIFI_HIP_TA_DISABLE @@ -1826,13 +1826,13 @@ static void card_init_soft_queues(card_t *card) /* Reset any state carried forward from a previous life */ card->fh_command_queue.q_rd_ptr = 0; card->fh_command_queue.q_wr_ptr = 0; - (void)CsrSnprintf(card->fh_command_queue.name, UNIFI_QUEUE_NAME_MAX_LENGTH, + (void)scnprintf(card->fh_command_queue.name, UNIFI_QUEUE_NAME_MAX_LENGTH, "fh_cmd_q"); for (i = 0; i < UNIFI_NO_OF_TX_QS; i++) { card->fh_traffic_queue[i].q_rd_ptr = 0; card->fh_traffic_queue[i].q_wr_ptr = 0; - (void)CsrSnprintf(card->fh_traffic_queue[i].name, + (void)scnprintf(card->fh_traffic_queue[i].name, UNIFI_QUEUE_NAME_MAX_LENGTH, "fh_data_q%d", i); } #ifndef CSR_WIFI_HIP_TA_DISABLE diff --git a/drivers/staging/csr/csr_wifi_hip_download.c b/drivers/staging/csr/csr_wifi_hip_download.c index 8e4a4608ba5c..6db672caaa02 100644 --- a/drivers/staging/csr/csr_wifi_hip_download.c +++ b/drivers/staging/csr/csr_wifi_hip_download.c @@ -250,6 +250,7 @@ static CsrResult do_patch_convert_download(card_t *card, void *dlpriv, xbv1_t *p if (r != CSR_RESULT_SUCCESS) { unifi_error(card->ospriv, "Failed to find BOOT_LOADER_CONTROL\n"); + kfree(pfw); return CSR_RESULT_FAILURE; } @@ -265,6 +266,7 @@ static CsrResult do_patch_convert_download(card_t *card, void *dlpriv, xbv1_t *p desc = unifi_fw_open_buffer(card->ospriv, pfw, psize); if (!desc) { + kfree(pfw); return CSR_WIFI_HIP_RESULT_NO_MEMORY; } diff --git a/drivers/staging/csr/csr_wifi_hip_send.c b/drivers/staging/csr/csr_wifi_hip_send.c index 684d30459d75..86aa23cefe30 100644 --- a/drivers/staging/csr/csr_wifi_hip_send.c +++ b/drivers/staging/csr/csr_wifi_hip_send.c @@ -172,13 +172,8 @@ static CsrResult send_signal(card_t *card, const u8 *sigptr, u32 siglen, { const u8 *sig = sigptr; - unifi_error(card->ospriv, "Signal(%d): %02x %02x %02x %02x %02x %02x %02x %02x" - " %02x %02x %02x %02x %02x %02x %02x %02x\n", - siglen, - sig[0], sig[1], sig[2], sig[3], - sig[4], sig[5], sig[6], sig[7], - sig[8], sig[9], sig[10], sig[11], - sig[12], sig[13], sig[14], sig[15]); + unifi_error(card->ospriv, "Signal(%d): %*ph\n", siglen, + 16, sig); unifi_error(card->ospriv, "Bulkdata pointer %p(%d), %p(%d)\n", bulkdata != NULL?bulkdata->d[0].os_data_ptr : NULL, bulkdata != NULL?bulkdata->d[0].data_length : 0, diff --git a/drivers/staging/csr/csr_wifi_hip_udi.c b/drivers/staging/csr/csr_wifi_hip_udi.c index 07cfd36c4971..a65b822db698 100644 --- a/drivers/staging/csr/csr_wifi_hip_udi.c +++ b/drivers/staging/csr/csr_wifi_hip_udi.c @@ -64,104 +64,104 @@ s32 unifi_print_status(card_t *card, char *str, s32 *remain) } i = n = 0; - written = CsrSnprintf(p, remaining, "Chip ID %u\n", + written = scnprintf(p, remaining, "Chip ID %u\n", (u16)card->chip_id); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "Chip Version %04X\n", + written = scnprintf(p, remaining, "Chip Version %04X\n", card->chip_version); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "HIP v%u.%u\n", + written = scnprintf(p, remaining, "HIP v%u.%u\n", (card->config_data.version >> 8) & 0xFF, card->config_data.version & 0xFF); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "Build %lu: %s\n", + written = scnprintf(p, remaining, "Build %u: %s\n", card->build_id, card->build_id_string); UNIFI_SNPRINTF_RET(p, remaining, written); cfg = &card->config_data; - written = CsrSnprintf(p, remaining, "sdio ctrl offset %u\n", + written = scnprintf(p, remaining, "sdio ctrl offset %u\n", cfg->sdio_ctrl_offset); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "fromhost sigbuf handle %u\n", + written = scnprintf(p, remaining, "fromhost sigbuf handle %u\n", cfg->fromhost_sigbuf_handle); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "tohost_sigbuf_handle %u\n", + written = scnprintf(p, remaining, "tohost_sigbuf_handle %u\n", cfg->tohost_sigbuf_handle); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "num_fromhost_sig_frags %u\n", + written = scnprintf(p, remaining, "num_fromhost_sig_frags %u\n", cfg->num_fromhost_sig_frags); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "num_tohost_sig_frags %u\n", + written = scnprintf(p, remaining, "num_tohost_sig_frags %u\n", cfg->num_tohost_sig_frags); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "num_fromhost_data_slots %u\n", + written = scnprintf(p, remaining, "num_fromhost_data_slots %u\n", cfg->num_fromhost_data_slots); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "num_tohost_data_slots %u\n", + written = scnprintf(p, remaining, "num_tohost_data_slots %u\n", cfg->num_tohost_data_slots); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "data_slot_size %u\n", + written = scnprintf(p, remaining, "data_slot_size %u\n", cfg->data_slot_size); UNIFI_SNPRINTF_RET(p, remaining, written); /* Added by protocol version 0x0001 */ - written = CsrSnprintf(p, remaining, "overlay_size %u\n", + written = scnprintf(p, remaining, "overlay_size %u\n", (u16)cfg->overlay_size); UNIFI_SNPRINTF_RET(p, remaining, written); /* Added by protocol version 0x0300 */ - written = CsrSnprintf(p, remaining, "data_slot_round %u\n", + written = scnprintf(p, remaining, "data_slot_round %u\n", cfg->data_slot_round); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "sig_frag_size %u\n", + written = scnprintf(p, remaining, "sig_frag_size %u\n", cfg->sig_frag_size); UNIFI_SNPRINTF_RET(p, remaining, written); /* Added by protocol version 0x0300 */ - written = CsrSnprintf(p, remaining, "tohost_sig_pad %u\n", + written = scnprintf(p, remaining, "tohost_sig_pad %u\n", cfg->tohost_signal_padding); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "\nInternal state:\n"); + written = scnprintf(p, remaining, "\nInternal state:\n"); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "Last PHY PANIC: %04x:%04x\n", + written = scnprintf(p, remaining, "Last PHY PANIC: %04x:%04x\n", card->last_phy_panic_code, card->last_phy_panic_arg); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "Last MAC PANIC: %04x:%04x\n", + written = scnprintf(p, remaining, "Last MAC PANIC: %04x:%04x\n", card->last_mac_panic_code, card->last_mac_panic_arg); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "fhsr: %u\n", + written = scnprintf(p, remaining, "fhsr: %u\n", (u16)card->from_host_signals_r); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "fhsw: %u\n", + written = scnprintf(p, remaining, "fhsw: %u\n", (u16)card->from_host_signals_w); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "thsr: %u\n", + written = scnprintf(p, remaining, "thsr: %u\n", (u16)card->to_host_signals_r); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "thsw: %u\n", + written = scnprintf(p, remaining, "thsw: %u\n", (u16)card->to_host_signals_w); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, - "fh buffer contains: %u signals, %u bytes\n", + written = scnprintf(p, remaining, + "fh buffer contains: %d signals, %td bytes\n", card->fh_buffer.count, card->fh_buffer.ptr - card->fh_buffer.buf); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "paused: "); + written = scnprintf(p, remaining, "paused: "); UNIFI_SNPRINTF_RET(p, remaining, written); for (i = 0; i < sizeof(card->tx_q_paused_flag) / sizeof(card->tx_q_paused_flag[0]); i++) { - written = CsrSnprintf(p, remaining, card->tx_q_paused_flag[i]?"1" : "0"); + written = scnprintf(p, remaining, card->tx_q_paused_flag[i]?"1" : "0"); UNIFI_SNPRINTF_RET(p, remaining, written); } - written = CsrSnprintf(p, remaining, "\n"); + written = scnprintf(p, remaining, "\n"); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, + written = scnprintf(p, remaining, "fh command q: %u waiting, %u free of %u:\n", CSR_WIFI_HIP_Q_SLOTS_USED(&card->fh_command_queue), CSR_WIFI_HIP_Q_SLOTS_FREE(&card->fh_command_queue), @@ -169,7 +169,7 @@ s32 unifi_print_status(card_t *card, char *str, s32 *remain) UNIFI_SNPRINTF_RET(p, remaining, written); for (i = 0; i < UNIFI_NO_OF_TX_QS; i++) { - written = CsrSnprintf(p, remaining, + written = scnprintf(p, remaining, "fh traffic q[%u]: %u waiting, %u free of %u:\n", i, CSR_WIFI_HIP_Q_SLOTS_USED(&card->fh_traffic_queue[i]), @@ -178,58 +178,58 @@ s32 unifi_print_status(card_t *card, char *str, s32 *remain) UNIFI_SNPRINTF_RET(p, remaining, written); } - written = CsrSnprintf(p, remaining, "fh data slots free: %u\n", + written = scnprintf(p, remaining, "fh data slots free: %u\n", card->from_host_data?CardGetFreeFromHostDataSlots(card) : 0); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "From host data slots:"); + written = scnprintf(p, remaining, "From host data slots:"); UNIFI_SNPRINTF_RET(p, remaining, written); n = card->config_data.num_fromhost_data_slots; for (i = 0; i < n && card->from_host_data; i++) { - written = CsrSnprintf(p, remaining, " %u", + written = scnprintf(p, remaining, " %u", (u16)card->from_host_data[i].bd.data_length); UNIFI_SNPRINTF_RET(p, remaining, written); } - written = CsrSnprintf(p, remaining, "\n"); + written = scnprintf(p, remaining, "\n"); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "To host data slots:"); + written = scnprintf(p, remaining, "To host data slots:"); UNIFI_SNPRINTF_RET(p, remaining, written); n = card->config_data.num_tohost_data_slots; for (i = 0; i < n && card->to_host_data; i++) { - written = CsrSnprintf(p, remaining, " %u", + written = scnprintf(p, remaining, " %u", (u16)card->to_host_data[i].data_length); UNIFI_SNPRINTF_RET(p, remaining, written); } - written = CsrSnprintf(p, remaining, "\n"); + written = scnprintf(p, remaining, "\n"); UNIFI_SNPRINTF_RET(p, remaining, written); #ifdef CSR_UNSAFE_SDIO_ACCESS - written = CsrSnprintf(p, remaining, "Host State: %s\n", states[card->host_state]); + written = scnprintf(p, remaining, "Host State: %s\n", states[card->host_state]); UNIFI_SNPRINTF_RET(p, remaining, written); r = unifi_check_io_status(card, &iostate); if (iostate == 1) { - written = CsrSnprintf(p, remaining, "I/O Check: F1 disabled\n"); + written = scnprintf(p, remaining, "I/O Check: F1 disabled\n"); UNIFI_SNPRINTF_RET(p, remaining, written); } else { if (iostate == 1) { - written = CsrSnprintf(p, remaining, "I/O Check: pending interrupt\n"); + written = scnprintf(p, remaining, "I/O Check: pending interrupt\n"); UNIFI_SNPRINTF_RET(p, remaining, written); } - written = CsrSnprintf(p, remaining, "BH reason interrupt = %d\n", + written = scnprintf(p, remaining, "BH reason interrupt = %d\n", card->bh_reason_unifi); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "BH reason host = %d\n", + written = scnprintf(p, remaining, "BH reason host = %d\n", card->bh_reason_host); UNIFI_SNPRINTF_RET(p, remaining, written); @@ -238,26 +238,26 @@ s32 unifi_print_status(card_t *card, char *str, s32 *remain) r = unifi_read_8_or_16(card, card->sdio_ctrl_addr + 2, &b); if ((r == CSR_RESULT_SUCCESS) && (!(b & 0x80))) { - written = CsrSnprintf(p, remaining, "fhsr: %u (driver thinks is %u)\n", + written = scnprintf(p, remaining, "fhsr: %u (driver thinks is %u)\n", b, card->from_host_signals_r); UNIFI_SNPRINTF_RET(p, remaining, written); break; } } iostate = unifi_read_shared_count(card, card->sdio_ctrl_addr + 4); - written = CsrSnprintf(p, remaining, "thsw: %u (driver thinks is %u)\n", + written = scnprintf(p, remaining, "thsw: %u (driver thinks is %u)\n", iostate, card->to_host_signals_w); UNIFI_SNPRINTF_RET(p, remaining, written); } #endif - written = CsrSnprintf(p, remaining, "\nStats:\n"); + written = scnprintf(p, remaining, "\nStats:\n"); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "Total SDIO bytes: R=%lu W=%lu\n", + written = scnprintf(p, remaining, "Total SDIO bytes: R=%u W=%u\n", card->sdio_bytes_read, card->sdio_bytes_written); UNIFI_SNPRINTF_RET(p, remaining, written); - written = CsrSnprintf(p, remaining, "Interrupts generated on card: %lu\n", + written = scnprintf(p, remaining, "Interrupts generated on card: %u\n", card->unifi_interrupt_seq); UNIFI_SNPRINTF_RET(p, remaining, written); diff --git a/drivers/staging/csr/csr_wifi_hip_unifi.h b/drivers/staging/csr/csr_wifi_hip_unifi.h index dc3c60b49702..2923e2ef12f2 100644 --- a/drivers/staging/csr/csr_wifi_hip_unifi.h +++ b/drivers/staging/csr/csr_wifi_hip_unifi.h @@ -98,7 +98,6 @@ extern "C" { #include "csr_framework_ext.h" /* from the synergy porting folder */ #include "csr_sdio.h" /* from the synergy porting folder */ #include "csr_macro.h" /* from the synergy porting folder */ -#include "csr_formatted_io.h" /* from the synergy gsp folder */ #include "csr_wifi_result.h" /* Utility MACROS. Note that UNIFI_MAC_ADDRESS_CMP returns TRUE on success */ diff --git a/drivers/staging/csr/drv.c b/drivers/staging/csr/drv.c index b2c27f4f03d4..249758076a75 100644 --- a/drivers/staging/csr/drv.c +++ b/drivers/staging/csr/drv.c @@ -15,8 +15,6 @@ * --------------------------------------------------------------------------- */ - - /* * Porting Notes: * Part of this file contains an example for how to glue the OS layer @@ -37,6 +35,7 @@ #include <linux/poll.h> #include <asm/uaccess.h> #include <linux/jiffies.h> +#include <linux/version.h> #include "csr_wifi_hip_unifiversion.h" #include "unifi_priv.h" @@ -124,11 +123,7 @@ static void udi_set_log_filter(ul_client_t *pcli, /* Mutex to protect access to priv->sme_cli */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) DEFINE_SEMAPHORE(udi_mutex); -#else -DECLARE_MUTEX(udi_mutex); -#endif s32 CsrHipResultToStatus(CsrResult csrResult) { @@ -1980,18 +1975,6 @@ uf_sme_queue_message(unifi_priv_t *priv, u8 *buffer, int length) } /* uf_sme_queue_message() */ #endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) -#define UF_DEVICE_CREATE(_class, _parent, _devno, _priv, _fmt, _args) \ - device_create(_class, _parent, _devno, _priv, _fmt, _args) -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) -#define UF_DEVICE_CREATE(_class, _parent, _devno, _priv, _fmt, _args) \ - device_create_drvdata(_class, _parent, _devno, _priv, _fmt, _args) -#else -#define UF_DEVICE_CREATE(_class, _parent, _devno, _priv, _fmt, _args) \ - device_create(_class, _parent, _devno, _fmt, _args) -#endif - /* **************************************************************************** * @@ -2009,17 +1992,6 @@ static struct file_operations unifi_fops = { .poll = unifi_poll, }; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) -#define UF_DEVICE_CREATE(_class, _parent, _devno, _priv, _fmt, _args) \ - device_create(_class, _parent, _devno, _priv, _fmt, _args) -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26) -#define UF_DEVICE_CREATE(_class, _parent, _devno, _priv, _fmt, _args) \ - device_create_drvdata(_class, _parent, _devno, _priv, _fmt, _args) -#else -#define UF_DEVICE_CREATE(_class, _parent, _devno, _priv, _fmt, _args) \ - device_create(_class, _parent, _devno, _fmt, _args) -#endif - static dev_t unifi_first_devno; static struct class *unifi_class; @@ -2042,11 +2014,11 @@ int uf_create_device_nodes(unifi_priv_t *priv, int bus_id) } #ifdef SDIO_EXPORTS_STRUCT_DEVICE - if (!UF_DEVICE_CREATE(unifi_class, priv->unifi_device, - devno, priv, "unifi%d", bus_id)) { + if (!device_create(unifi_class, priv->unifi_device, + devno, priv, "unifi%d", bus_id)) { #else - priv->unifi_device = UF_DEVICE_CREATE(unifi_class, NULL, - devno, priv, "unifi%d", bus_id); + priv->unifi_device = device_create(unifi_class, NULL, + devno, priv, "unifi%d", bus_id); if (priv->unifi_device == NULL) { #endif /* SDIO_EXPORTS_STRUCT_DEVICE */ @@ -2068,13 +2040,13 @@ int uf_create_device_nodes(unifi_priv_t *priv, int bus_id) return r; } - if (!UF_DEVICE_CREATE(unifi_class, + if (!device_create(unifi_class, #ifdef SDIO_EXPORTS_STRUCT_DEVICE - priv->unifi_device, + priv->unifi_device, #else - NULL, + NULL, #endif /* SDIO_EXPORTS_STRUCT_DEVICE */ - devno, priv, "unifiudi%d", bus_id)) { + devno, priv, "unifiudi%d", bus_id)) { device_destroy(unifi_class, priv->unifi_cdev.dev); cdev_del(&priv->unifiudi_cdev); cdev_del(&priv->unifi_cdev); diff --git a/drivers/staging/csr/firmware.c b/drivers/staging/csr/firmware.c index d14e11839618..b6d8a6e52915 100644 --- a/drivers/staging/csr/firmware.c +++ b/drivers/staging/csr/firmware.c @@ -286,7 +286,7 @@ uf_run_unifihelper(unifi_priv_t *priv) unifi_trace(priv, UDBG2, "running %s %s %s\n", argv[0], argv[1], argv[2]); - r = call_usermodehelper(argv[0], argv, envp, 0); + r = call_usermodehelper(argv[0], argv, envp, UMH_WAIT_EXEC); return r; #else @@ -402,9 +402,7 @@ int uf_release_firmware_files(unifi_priv_t *priv) int uf_release_firmware(unifi_priv_t *priv, struct dlpriv *to_free) { if (to_free != NULL) { - if (to_free->fw_desc != NULL) { - release_firmware((const struct firmware *)to_free->fw_desc); - } + release_firmware((const struct firmware *)to_free->fw_desc); to_free->fw_desc = NULL; to_free->dl_data = NULL; to_free->dl_len = 0; diff --git a/drivers/staging/csr/io.c b/drivers/staging/csr/io.c index e6503d9620a4..caf48e3120ca 100644 --- a/drivers/staging/csr/io.c +++ b/drivers/staging/csr/io.c @@ -31,6 +31,7 @@ * --------------------------------------------------------------------------- */ #include <linux/proc_fs.h> +#include <linux/version.h> #include "csr_wifi_hip_unifi.h" #include "csr_wifi_hip_unifiversion.h" @@ -38,7 +39,6 @@ #include "unifiio.h" #include "unifi_priv.h" - /* * Array of pointers to context structs for unifi devices that are present. * The index in the array corresponds to the wlan interface number @@ -70,11 +70,7 @@ static int In_use[MAX_UNIFI_DEVS]; * Mutex to prevent UDI clients to open the character device before the priv * is created and initialised. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) DEFINE_SEMAPHORE(Unifi_instance_mutex); -#else -DECLARE_MUTEX(Unifi_instance_mutex); -#endif /* * When the device is removed, unregister waits on Unifi_cleanup_wq * until all the UDI clients release the character device. @@ -177,21 +173,6 @@ uf_register_netdev(unifi_priv_t *priv, int interfaceTag) /* The device is registed */ interfacePriv->netdev_registered = 1; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) -#ifdef CONFIG_NET_SCHED - /* - * IMPORTANT: - * uf_install_qdisc() holds the network device lock, we can not - * install the qdisk before the network device is registered. - */ - r = uf_install_qdisc(priv->netdev[interfaceTag]); - if (r) { - unifi_error(priv, "Failed to install qdisc\n"); - return r; - } -#endif /* CONFIG_NET_SCHED */ -#endif /* LINUX_VERSION_CODE */ - #ifdef CSR_SUPPORT_SME /* * Register the inet handler; it notifies us for changes in the IP address. @@ -347,7 +328,7 @@ register_unifi_sdio(CsrSdioFunction *sdio_dev, int bus_id, struct device *dev) /* * We use the slot number as unifi device index. */ - snprintf(priv->proc_entry_name, 64, "driver/unifi%d", priv->instance); + scnprintf(priv->proc_entry_name, 64, "driver/unifi%d", priv->instance); /* * The following complex casting is in place in order to eliminate 64-bit compilation warning * "cast to/from pointer from/to integer of different size" @@ -669,7 +650,7 @@ unregister_unifi_sdio(int bus_id) if(interfacePriv->netdev_registered) { netif_carrier_off(priv->netdev[interfaceTag]); - UF_NETIF_TX_STOP_ALL_QUEUES(priv->netdev[interfaceTag]); + netif_tx_stop_all_queues(priv->netdev[interfaceTag]); } } @@ -904,54 +885,54 @@ uf_read_proc(char *page, char **start, off_t offset, int count, orig_p = p; - written = CsrSnprintf(p, remain, "UniFi SDIO Driver: %s %s %s\n", + written = scnprintf(p, remain, "UniFi SDIO Driver: %s %s %s\n", CSR_WIFI_VERSION, __DATE__, __TIME__); UNIFI_SNPRINTF_RET(p, remain, written); #ifdef CSR_SME_USERSPACE - written = CsrSnprintf(p, remain, "SME: CSR userspace "); + written = scnprintf(p, remain, "SME: CSR userspace "); UNIFI_SNPRINTF_RET(p, remain, written); #ifdef CSR_SUPPORT_WEXT - written = CsrSnprintf(p, remain, "with WEXT support\n"); + written = scnprintf(p, remain, "with WEXT support\n"); #else - written = CsrSnprintf(p, remain, "\n"); + written = scnprintf(p, remain, "\n"); #endif /* CSR_SUPPORT_WEXT */ UNIFI_SNPRINTF_RET(p, remain, written); #endif /* CSR_SME_USERSPACE */ #ifdef CSR_NATIVE_LINUX - written = CsrSnprintf(p, remain, "SME: native\n"); + written = scnprintf(p, remain, "SME: native\n"); UNIFI_SNPRINTF_RET(p, remain, written); #endif #ifdef CSR_SUPPORT_SME - written = CsrSnprintf(p, remain, - "Firmware (ROM) build:%lu, Patch:%lu\n", + written = scnprintf(p, remain, + "Firmware (ROM) build:%u, Patch:%u\n", priv->card_info.fw_build, priv->sme_versions.firmwarePatch); UNIFI_SNPRINTF_RET(p, remain, written); #endif p += unifi_print_status(priv->card, p, &remain); - written = CsrSnprintf(p, remain, "Last dbg str: %s\n", + written = scnprintf(p, remain, "Last dbg str: %s\n", priv->last_debug_string); UNIFI_SNPRINTF_RET(p, remain, written); - written = CsrSnprintf(p, remain, "Last dbg16:"); + written = scnprintf(p, remain, "Last dbg16:"); UNIFI_SNPRINTF_RET(p, remain, written); for (i = 0; i < 8; i++) { - written = CsrSnprintf(p, remain, " %04X", + written = scnprintf(p, remain, " %04X", priv->last_debug_word16[i]); UNIFI_SNPRINTF_RET(p, remain, written); } - written = CsrSnprintf(p, remain, "\n"); + written = scnprintf(p, remain, "\n"); UNIFI_SNPRINTF_RET(p, remain, written); - written = CsrSnprintf(p, remain, " "); + written = scnprintf(p, remain, " "); UNIFI_SNPRINTF_RET(p, remain, written); for (; i < 16; i++) { - written = CsrSnprintf(p, remain, " %04X", + written = scnprintf(p, remain, " %04X", priv->last_debug_word16[i]); UNIFI_SNPRINTF_RET(p, remain, written); } - written = CsrSnprintf(p, remain, "\n"); + written = scnprintf(p, remain, "\n"); UNIFI_SNPRINTF_RET(p, remain, written); *start = page; diff --git a/drivers/staging/csr/monitor.c b/drivers/staging/csr/monitor.c index 628782ad641e..7c524a18958e 100644 --- a/drivers/staging/csr/monitor.c +++ b/drivers/staging/csr/monitor.c @@ -10,6 +10,7 @@ * --------------------------------------------------------------------------- */ +#include <linux/version.h> #include "unifi_priv.h" #ifdef UNIFI_SNIFF_ARPHRD @@ -23,8 +24,6 @@ #define ETH_P_80211_RAW ETH_P_ALL #endif - - /* * --------------------------------------------------------------------------- * uf_start_sniff @@ -192,11 +191,7 @@ netrx_radiotap(unifi_priv_t *priv, skb->dev = dev; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22) skb->mac_header = skb->data; -#else - skb->mac.raw = skb->data; -#endif skb->pkt_type = PACKET_OTHERHOST; skb->protocol = __constant_htons(ETH_P_80211_RAW); memset(skb->cb, 0, sizeof(skb->cb)); diff --git a/drivers/staging/csr/netdev.c b/drivers/staging/csr/netdev.c index 1e6e111a8e15..9a52ab408e1a 100644 --- a/drivers/staging/csr/netdev.c +++ b/drivers/staging/csr/netdev.c @@ -15,7 +15,6 @@ * --------------------------------------------------------------------------- */ - /* * Porting Notes: * This file implements the data plane of the UniFi linux driver. @@ -48,59 +47,14 @@ #include <linux/etherdevice.h> #include <linux/mutex.h> #include <linux/semaphore.h> - +#include <linux/version.h> #include <linux/vmalloc.h> #include "csr_wifi_hip_unifi.h" #include "csr_wifi_hip_conversions.h" #include "unifi_priv.h" -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) -#include <net/iw_handler.h> -#endif #include <net/pkt_sched.h> -/* ALLOW_Q_PAUSE: Pre 2.6.28 kernels do not support multiple driver queues (required for QoS). - * In order to support QoS in these kernels, multiple queues are implemented in the driver. But since - * there is only a single queue in the kernel (leading to multiple queues in the driver) there is no possibility - * of stopping a particular queue in the kernel. Stopping the single kernel queue leads to undesirable starvation - * of driver queues. One of the proposals is to not stop the kernel queue but to prevent dequeuing from the - * 'stopped' driver queue. Allow q pause is an experimental implementation of this scheme for pre 2.6.28 kernels. - * When NOT defined, queues are paused locally in the driver and packets are dequeued for transmission only from the - * unpaused queues. When Allow q pause is defined the kernel queue is stopped whenever any driver queue is paused. - */ -#define ALLOW_Q_PAUSE - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) -#ifdef UNIFI_NET_NAME -#define UF_ALLOC_NETDEV(_dev, _size, _name, _setup, _num_of_queues) \ - do { \ - static char name[8]; \ - sprintf(name, "%s%s", UNIFI_NET_NAME, _name); \ - _dev = alloc_netdev_mq(_size, name, _setup, _num_of_queues); \ - } while (0); -#else -#define UF_ALLOC_NETDEV(_dev, _size, _name, _setup, _num_of_queues) \ - do { \ - _dev = alloc_etherdev_mq(_size, _num_of_queues); \ - } while (0); -#endif /* UNIFI_NET_NAME */ -#else -#ifdef UNIFI_NET_NAME -#define UF_ALLOC_NETDEV(_dev, _size, _name, _setup, _num_of_queues) \ - do { \ - static char name[8]; \ - sprintf(name, "%s%s", UNIFI_NET_NAME, _name); \ - _dev = alloc_netdev(_size, name, _setup); \ - } while (0); -#else -#define UF_ALLOC_NETDEV(_dev, _size, _name, _setup, _num_of_queues) \ - do { \ - _dev = alloc_etherdev(_size); \ - } while (0); -#endif /* UNIFI_NET_NAME */ -#endif /* LINUX_VERSION_CODE */ - - /* Wext handler is suported only if CSR_SUPPORT_WEXT is defined */ #ifdef CSR_SUPPORT_WEXT extern struct iw_handler_def unifi_iw_handler_def; @@ -119,20 +73,8 @@ static int uf_net_open(struct net_device *dev); static int uf_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); static int uf_net_stop(struct net_device *dev); static struct net_device_stats *uf_net_get_stats(struct net_device *dev); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) static u16 uf_net_select_queue(struct net_device *dev, struct sk_buff *skb); -#endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) static netdev_tx_t uf_net_xmit(struct sk_buff *skb, struct net_device *dev); -#else -static int uf_net_xmit(struct sk_buff *skb, struct net_device *dev); -#ifndef NETDEV_TX_OK -#define NETDEV_TX_OK 0 -#endif -#ifndef NETDEV_TX_BUSY -#define NETDEV_TX_BUSY 1 -#endif -#endif static void uf_set_multicast_list(struct net_device *dev); @@ -182,62 +124,8 @@ struct uf_tx_packet_data { unsigned long host_tag; }; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) -static int uf_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd); -static int uf_qdiscop_requeue(struct sk_buff *skb, struct Qdisc* qd); -static struct sk_buff *uf_qdiscop_dequeue(struct Qdisc* qd); -static void uf_qdiscop_reset(struct Qdisc* qd); -static void uf_qdiscop_destroy(struct Qdisc* qd); -static int uf_qdiscop_dump(struct Qdisc *qd, struct sk_buff *skb); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25) -static int uf_qdiscop_tune(struct Qdisc *qd, struct nlattr *opt); -static int uf_qdiscop_init(struct Qdisc *qd, struct nlattr *opt); -#else -static int uf_qdiscop_tune(struct Qdisc *qd, struct rtattr *opt); -static int uf_qdiscop_init(struct Qdisc *qd, struct rtattr *opt); -#endif -#endif - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) -/* queueing discipline operations */ -static struct Qdisc_ops uf_qdisc_ops = -{ - .next = NULL, - .cl_ops = NULL, - .id = "UniFi Qdisc", - .priv_size = sizeof(struct uf_sched_data), - - .enqueue = uf_qdiscop_enqueue, - .dequeue = uf_qdiscop_dequeue, - .requeue = uf_qdiscop_requeue, - .drop = NULL, /* drop not needed since we are always the root qdisc */ - - .init = uf_qdiscop_init, - .reset = uf_qdiscop_reset, - .destroy = uf_qdiscop_destroy, - .change = uf_qdiscop_tune, - - .dump = uf_qdiscop_dump, -}; -#endif /* LINUX_VERSION_CODE */ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) -#define UF_QDISC_CREATE_DFLT(_dev, _ops, _root) -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) -#define UF_QDISC_CREATE_DFLT(_dev, _ops, _root) \ - qdisc_create_dflt(dev, netdev_get_tx_queue(_dev, 0), _ops, _root) -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20) -#define UF_QDISC_CREATE_DFLT(_dev, _ops, _root) \ - qdisc_create_dflt(dev, _ops, _root) -#else -#define UF_QDISC_CREATE_DFLT(_dev, _ops, _root) \ - qdisc_create_dflt(dev, _ops) -#endif /* LINUX_VERSION_CODE */ - #endif /* CONFIG_NET_SCHED */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) static const struct net_device_ops uf_netdev_ops = { .ndo_open = uf_net_open, @@ -248,7 +136,6 @@ static const struct net_device_ops uf_netdev_ops = .ndo_set_rx_mode = uf_set_multicast_list, .ndo_select_queue = uf_net_select_queue, }; -#endif static u8 oui_rfc1042[P80211_OUI_LEN] = { 0x00, 0x00, 0x00 }; static u8 oui_8021h[P80211_OUI_LEN] = { 0x00, 0x00, 0xf8 }; @@ -310,7 +197,7 @@ uf_alloc_netdevice(CsrSdioFunction *sdio_dev, int bus_id) * The RedHat 9 redhat-config-network tool doesn't recognise wlan* devices, * so use "eth*" (like other wireless extns drivers). */ - UF_ALLOC_NETDEV(dev, sizeof(unifi_priv_t)+sizeof(netInterface_priv_t), "%d", ether_setup, UNIFI_TRAFFIC_Q_MAX); + dev = alloc_etherdev_mq(sizeof(unifi_priv_t) + sizeof(netInterface_priv_t), UNIFI_TRAFFIC_Q_MAX); if (dev == NULL) { return NULL; @@ -332,22 +219,7 @@ uf_alloc_netdevice(CsrSdioFunction *sdio_dev, int bus_id) priv->interfacePriv[0] = interfacePriv; /* Setup / override net_device fields */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) dev->netdev_ops = &uf_netdev_ops; -#else - dev->open = uf_net_open; - dev->stop = uf_net_stop; - dev->hard_start_xmit = uf_net_xmit; - dev->do_ioctl = uf_net_ioctl; - - /* called by /proc/net/dev */ - dev->get_stats = uf_net_get_stats; - - dev->set_multicast_list = uf_set_multicast_list; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) - dev->select_queue = uf_net_select_queue; -#endif -#endif #ifdef CSR_SUPPORT_WEXT dev->wireless_handlers = &unifi_iw_handler_def; @@ -440,21 +312,13 @@ uf_alloc_netdevice(CsrSdioFunction *sdio_dev, int bus_id) interfacePriv->connected = UnifiConnectedUnknown; /* -1 unknown, 0 no, 1 yes */ #ifdef USE_DRIVER_LOCK -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) sema_init(&priv->lock, 1); -#else - init_MUTEX(&priv->lock); -#endif #endif /* USE_DRIVER_LOCK */ spin_lock_init(&priv->send_signal_lock); spin_lock_init(&priv->m4_lock); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) sema_init(&priv->ba_mutex, 1); -#else - init_MUTEX(&priv->ba_mutex); -#endif #if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION)) spin_lock_init(&priv->wapi_lock); @@ -487,16 +351,8 @@ uf_alloc_netdevice(CsrSdioFunction *sdio_dev, int bus_id) #endif #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) -#ifdef CONFIG_NET_SCHED - /* Register the qdisc operations */ - register_qdisc(&uf_qdisc_ops); -#endif /* CONFIG_NET_SCHED */ -#endif /* LINUX_VERSION_CODE */ - priv->ref_count = 1; - priv->amp_client = NULL; priv->coredump_mode = 0; priv->ptest_mode = 0; @@ -566,7 +422,7 @@ uf_alloc_netdevice_for_other_interfaces(unifi_priv_t *priv, u16 interfaceTag) * The RedHat 9 redhat-config-network tool doesn't recognise wlan* devices, * so use "eth*" (like other wireless extns drivers). */ - UF_ALLOC_NETDEV(dev, sizeof(netInterface_priv_t), "%d", ether_setup, 1); + dev = alloc_etherdev_mq(sizeof(netInterface_priv_t), 1); if (dev == NULL) { return FALSE; } @@ -589,19 +445,7 @@ uf_alloc_netdevice_for_other_interfaces(unifi_priv_t *priv, u16 interfaceTag) INIT_LIST_HEAD(&interfacePriv->rx_controlled_list); /* Setup / override net_device fields */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,29) dev->netdev_ops = &uf_netdev_ops; -#else - dev->open = uf_net_open; - dev->stop = uf_net_stop; - dev->hard_start_xmit = uf_net_xmit; - dev->do_ioctl = uf_net_ioctl; - - /* called by /proc/net/dev */ - dev->get_stats = uf_net_get_stats; - - dev->set_multicast_list = uf_set_multicast_list; -#endif #ifdef CSR_SUPPORT_WEXT dev->wireless_handlers = &unifi_iw_handler_def; @@ -686,13 +530,6 @@ uf_free_netdevice(unifi_priv_t *priv) spin_unlock_irqrestore(&priv->wapi_lock, flags); #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) -#ifdef CONFIG_NET_SCHED - /* Unregister the qdisc operations */ - unregister_qdisc(&uf_qdisc_ops); -#endif /* CONFIG_NET_SCHED */ -#endif /* LINUX_VERSION_CODE */ - #ifdef CSR_SUPPORT_WEXT /* Unregister callback for netdevice state changes */ unregister_netdevice_notifier(&uf_netdev_notifier); @@ -700,10 +537,8 @@ uf_free_netdevice(unifi_priv_t *priv) #ifdef CSR_SUPPORT_SME /* Cancel work items and destroy the workqueue */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) cancel_work_sync(&priv->multicast_list_task); #endif -#endif /* Destroy the workqueues. */ flush_workqueue(priv->unifi_workqueue); destroy_workqueue(priv->unifi_workqueue); @@ -778,7 +613,7 @@ uf_net_open(struct net_device *dev) } #endif - UF_NETIF_TX_START_ALL_QUEUES(dev); + netif_tx_start_all_queues(dev); func_exit(); return 0; @@ -808,7 +643,7 @@ uf_net_stop(struct net_device *dev) func_enter(); #endif - UF_NETIF_TX_STOP_ALL_QUEUES(dev); + netif_tx_stop_all_queues(dev); func_exit(); return 0; @@ -957,7 +792,6 @@ get_packet_priority(unifi_priv_t *priv, struct sk_buff *skb, const struct ethhdr return priority; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) /* * --------------------------------------------------------------------------- * uf_net_select_queue @@ -1005,7 +839,6 @@ uf_net_select_queue(struct net_device *dev, struct sk_buff *skb) func_exit(); return (u16)queue; } /* uf_net_select_queue() */ -#endif int skb_add_llc_snap(struct net_device *dev, struct sk_buff *skb, int proto) @@ -1915,11 +1748,7 @@ send_ma_pkt_request(unifi_priv_t *priv, struct sk_buff *skb, const struct ethhdr * The controlled port is handled in the qdisc dequeue handler. * --------------------------------------------------------------------------- */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) static netdev_tx_t -#else -static int -#endif uf_net_xmit(struct sk_buff *skb, struct net_device *dev) { netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); @@ -1929,9 +1758,7 @@ uf_net_xmit(struct sk_buff *skb, struct net_device *dev) int result; static tx_signal_handler tx_handler; CSR_PRIORITY priority; -#if !defined (CONFIG_NET_SCHED) || (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28)) CsrWifiRouterCtrlPortAction port_action; -#endif /* CONFIG_NET_SCHED */ func_enter(); @@ -1956,11 +1783,6 @@ uf_net_xmit(struct sk_buff *skb, struct net_device *dev) port = UF_UNCONTROLLED_PORT_Q; } -#if defined (CONFIG_NET_SCHED) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)) - /* Remove the ethernet header */ - skb_pull(skb, ETH_HLEN); - result = tx_handler(priv, skb, &ehdr, priority); -#else /* Uncontrolled port rules apply */ port_action = verify_port(priv , (((CSR_WIFI_ROUTER_CTRL_MODE_STA == interfacePriv->interfaceMode)||(CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI== interfacePriv->interfaceMode))? interfacePriv->bssid.a: ehdr.h_dest) @@ -1986,7 +1808,6 @@ uf_net_xmit(struct sk_buff *skb, struct net_device *dev) func_exit(); return NETDEV_TX_OK; } -#endif /* CONFIG_NET_SCHED */ if (result == NETDEV_TX_OK) { #if (defined(CSR_WIFI_SECURITY_WAPI_ENABLE) && defined(CSR_WIFI_SECURITY_WAPI_SW_ENCRYPTION)) @@ -2059,7 +1880,6 @@ unifi_pause_xmit(void *ospriv, unifi_TrafficQueue queue) func_enter(); unifi_trace(priv, UDBG2, "Stopping queue %d\n", queue); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) for(i=0;i<CSR_WIFI_NUM_INTERFACES;i++) { if (netif_running(priv->netdev[i])) @@ -2067,24 +1887,6 @@ unifi_pause_xmit(void *ospriv, unifi_TrafficQueue queue) netif_stop_subqueue(priv->netdev[i], (u16)queue); } } -#else -#ifdef ALLOW_Q_PAUSE - unifi_trace(priv, UDBG2, "Stopping netif\n"); - /* stop the traffic from all the interfaces. */ - for(i=0;i<CSR_WIFI_NUM_INTERFACES;i++) - { - if (netif_running(priv->netdev[i])) { - UF_NETIF_TX_STOP_ALL_QUEUES(priv->netdev[i]); - } - } -#else - if (net_is_tx_q_paused(priv, queue)) { - unifi_trace(priv, UDBG2, "Queue already stopped\n"); - return; - } - net_tx_q_pause(priv, queue); -#endif -#endif #ifdef CSR_SUPPORT_SME if(queue<=3) { @@ -2108,7 +1910,6 @@ unifi_restart_xmit(void *ospriv, unifi_TrafficQueue queue) func_enter(); unifi_trace(priv, UDBG2, "Waking queue %d\n", queue); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) for(i=0;i<CSR_WIFI_NUM_INTERFACES;i++) { if (netif_running(priv->netdev[i])) @@ -2116,25 +1917,6 @@ unifi_restart_xmit(void *ospriv, unifi_TrafficQueue queue) netif_wake_subqueue(priv->netdev[i], (u16)queue); } } -#else -#ifdef ALLOW_Q_PAUSE - /* Need to supply queue number depending on Kernel support */ - /* Resume the traffic from all the interfaces */ - for(i=0;i<CSR_WIFI_NUM_INTERFACES;i++) - { - if (netif_running(priv->netdev[i])) { - UF_NETIF_TX_WAKE_ALL_QUEUES(priv->netdev[i]); - } - } -#else - if (!(net_is_tx_q_paused(priv, queue))) { - unifi_trace(priv, UDBG2, "Queue already running\n"); - func_exit(); - return; - } - net_tx_q_unpause(priv, queue); -#endif -#endif #ifdef CSR_SUPPORT_SME if(queue <=3) { @@ -2349,13 +2131,7 @@ uf_resume_data_plane(unifi_priv_t *priv, int queue, { #ifdef CONFIG_NET_SCHED if (netif_running(priv->netdev[interfaceTag])) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28) netif_tx_schedule_all(priv->netdev[interfaceTag]); -#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) - netif_schedule_queue(netdev_get_tx_queue(priv->netdev[interfaceTag], 0)); -#else - netif_schedule(priv->netdev[interfaceTag]); -#endif /* LINUX_VERSION_CODE */ } #endif uf_process_rx_pending_queue(priv, queue, peer_address, 1,interfaceTag); @@ -2998,19 +2774,13 @@ uf_set_multicast_list(struct net_device *dev) #else u8 *mc_list = interfacePriv->mc_list; -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) struct netdev_hw_addr *mc_addr; int mc_addr_count; -#else - struct dev_mc_list *p; /* Pointer to the addresses structure. */ - int i; -#endif if (priv->init_progress != UNIFI_INIT_COMPLETED) { return; } -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,34) mc_addr_count = netdev_mc_count(dev); unifi_trace(priv, UDBG3, @@ -3029,25 +2799,6 @@ uf_set_multicast_list(struct net_device *dev) mc_list += ETH_ALEN; } -#else - unifi_trace(priv, UDBG3, - "uf_set_multicast_list (count=%d)\n", dev->mc_count); - - /* Not enough space? */ - if (dev->mc_count > UNIFI_MAX_MULTICAST_ADDRESSES) { - return; - } - - /* Store the list to be processed by the work item. */ - interfacePriv->mc_list_count = dev->mc_count; - p = dev->mc_list; - for (i = 0; i < dev->mc_count; i++) { - memcpy(mc_list, p->dmi_addr, ETH_ALEN); - p = p->next; - mc_list += ETH_ALEN; - } -#endif - /* Send a message to the workqueue */ queue_work(priv->unifi_workqueue, &priv->multicast_list_task); #endif @@ -3181,375 +2932,6 @@ void uf_net_get_name(struct net_device *dev, char *name, int len) } /* uf_net_get_name */ - - - - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) -#ifdef CONFIG_NET_SCHED - -/* - * --------------------------------------------------------------------------- - * uf_install_qdisc - * - * Creates a root qdisc, registers our qdisc handlers and - * overrides the device's qdisc_sleeping to prevent the system - * from creating a new one for our network device. - * - * Arguments: - * dev Pointer to the network device. - * - * Returns: - * 0 on success, Linux error code otherwise. - * - * Notes: - * This function holds the qdisk lock so it needs to be called - * after registering the network device in uf_register_netdev(). - * Also, the qdisc_create_dflt() API has changed in 2.6.20 to - * include the parentid. - * --------------------------------------------------------------------------- - */ -int uf_install_qdisc(struct net_device *dev) -{ - struct Qdisc *qdisc; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) - struct netdev_queue *queue0; -#endif /* LINUX_VERSION_CODE */ - - - func_enter(); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27) - /* - * check that there is no qdisc currently attached to device - * this ensures that we will be the root qdisc. (I can't find a better - * way to test this explicitly) - */ - if (dev->qdisc_sleeping != &noop_qdisc) { - func_exit_r(-EFAULT); - return -EINVAL; - } -#endif /* LINUX_VERSION_CODE */ - - qdisc = UF_QDISC_CREATE_DFLT(dev, &uf_qdisc_ops, TC_H_ROOT); - if (!qdisc) { - unifi_error(NULL, "%s: qdisc installation failed\n", dev->name); - func_exit_r(-EFAULT); - return -EFAULT; - } - unifi_trace(NULL, UDBG5, "%s: parent qdisc=0x%p\n", - dev->name, qdisc); - - qdisc->handle = 0x80020000; - qdisc->flags = 0x0; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) - queue0 = netdev_get_tx_queue(dev, 0); - if (queue0 == NULL) { - unifi_error(NULL, "%s: netdev_get_tx_queue returned no queue\n", - dev->name); - func_exit_r(-EFAULT); - return -EFAULT; - } - queue0->qdisc = qdisc; - queue0->qdisc_sleeping = qdisc; -#else - qdisc_lock_tree(dev); - list_add_tail(&qdisc->list, &dev->qdisc_list); - dev->qdisc_sleeping = qdisc; - qdisc_unlock_tree(dev); -#endif /* LINUX_VERSION_CODE */ - - func_exit_r(0); - return 0; - -} /* uf_install_qdisc() */ - -static int uf_qdiscop_enqueue(struct sk_buff *skb, struct Qdisc* qd) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) - netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(qd->dev_queue->dev); -#else - netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(qd->dev); -#endif /* LINUX_VERSION_CODE */ - unifi_priv_t *priv = interfacePriv->privPtr; - struct uf_sched_data *q = qdisc_priv(qd); - struct uf_tx_packet_data *pkt_data = (struct uf_tx_packet_data *) skb->cb; - struct ethhdr ehdr; - struct Qdisc *qdisc; - int r, proto; - - func_enter(); - - memcpy(&ehdr, skb->data, ETH_HLEN); - proto = ntohs(ehdr.h_proto); - - /* 802.1x - apply controlled/uncontrolled port rules */ - if ((proto != ETH_P_PAE) -#ifdef CSR_WIFI_SECURITY_WAPI_ENABLE - && (proto != ETH_P_WAI) -#endif - ) { - /* queues 0 - 3 */ - pkt_data->priority = get_packet_priority(priv, skb, &ehdr, interfacePriv); - pkt_data->queue = unifi_frame_priority_to_queue(pkt_data->priority); - } else { - pkt_data->queue = UNIFI_TRAFFIC_Q_EAPOL; - } - - qdisc = q->queues[pkt_data->queue]; - r = qdisc->enqueue(skb, qdisc); - if (r == NET_XMIT_SUCCESS) { - qd->q.qlen++; - qd->bstats.bytes += skb->len; - qd->bstats.packets++; - func_exit_r(NET_XMIT_SUCCESS); - return NET_XMIT_SUCCESS; - } - - unifi_error(priv, "uf_qdiscop_enqueue: dropped\n"); - qd->qstats.drops++; - - func_exit_r(r); - return r; - -} /* uf_qdiscop_enqueue() */ - - -static int uf_qdiscop_requeue(struct sk_buff *skb, struct Qdisc* qd) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) - netInterface_priv_t *interfacePriv = (netInterface_priv_t*)netdev_priv(qd->dev_queue->dev); -#else - netInterface_priv_t *interfacePriv = (netInterface_priv_t*)netdev_priv(qd->dev); -#endif /* LINUX_VERSION_CODE */ - unifi_priv_t *priv = interfacePriv->privPtr; - struct uf_sched_data *q = qdisc_priv(qd); - struct uf_tx_packet_data *pkt_data = (struct uf_tx_packet_data *) skb->cb; - struct Qdisc *qdisc; - int r; - - func_enter(); - - unifi_trace(priv, UDBG5, "uf_qdiscop_requeue: (q=%d), tag=%u\n", - pkt_data->queue, pkt_data->host_tag); - - /* we recorded which queue to use earlier! */ - qdisc = q->queues[pkt_data->queue]; - - if ((r = qdisc->ops->requeue(skb, qdisc)) == 0) { - qd->q.qlen++; - func_exit_r(0); - return 0; - } - - unifi_error(priv, "uf_qdiscop_requeue: dropped\n"); - qd->qstats.drops++; - - func_exit_r(r); - return r; -} /* uf_qdiscop_requeue() */ - -static struct sk_buff *uf_qdiscop_dequeue(struct Qdisc* qd) -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) - netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(qd->dev_queue->dev); -#else - netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(qd->dev); -#endif /* LINUX_VERSION_CODE */ - unifi_priv_t *priv = interfacePriv->privPtr; - struct uf_sched_data *q = qdisc_priv(qd); - struct sk_buff *skb; - struct Qdisc *qdisc; - int queue, i; - struct ethhdr ehdr; - struct uf_tx_packet_data *pkt_data; - CsrWifiRouterCtrlPortAction port_action; - - func_enter(); - - /* check all the queues */ - for (i = UNIFI_TRAFFIC_Q_MAX - 1; i >= 0; i--) { - - if (i != UNIFI_TRAFFIC_Q_EAPOL) { - queue = priv->prev_queue; - if (++priv->prev_queue >= UNIFI_TRAFFIC_Q_EAPOL) { - priv->prev_queue = 0; - } - } else { - queue = i; - } - -#ifndef ALLOW_Q_PAUSE - /* If queue is paused, do not dequeue */ - if (net_is_tx_q_paused(priv, queue)) { - unifi_trace(priv, UDBG5, - "uf_qdiscop_dequeue: tx queue paused (q=%d)\n", queue); - continue; - } -#endif - - qdisc = q->queues[queue]; - skb = qdisc->dequeue(qdisc); - if (skb) { - /* A packet has been dequeued, decrease the queued packets count */ - qd->q.qlen--; - - pkt_data = (struct uf_tx_packet_data *) skb->cb; - - /* Check the (un)controlled port status */ - memcpy(&ehdr, skb->data, ETH_HLEN); - - port_action = verify_port(priv - , (((CSR_WIFI_ROUTER_CTRL_MODE_STA == interfacePriv->interfaceMode) ||(CSR_WIFI_ROUTER_CTRL_MODE_P2PCLI == interfacePriv->interfaceMode))? interfacePriv->bssid.a: ehdr.h_dest) - , (UNIFI_TRAFFIC_Q_EAPOL == queue? UF_UNCONTROLLED_PORT_Q: UF_CONTROLLED_PORT_Q) - , interfacePriv->InterfaceTag); - - /* Dequeue packet if port is open */ - if (port_action == CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_OPEN) { - unifi_trace(priv, UDBG5, - "uf_qdiscop_dequeue: new (q=%d), tag=%u\n", - queue, pkt_data->host_tag); - - func_exit(); - return skb; - } - - /* Discard or block the packet if necessary */ - if (port_action == CSR_WIFI_ROUTER_CTRL_PORT_ACTION_8021X_PORT_CLOSED_DISCARD) { - unifi_trace(priv, UDBG5, - "uf_qdiscop_dequeue: drop (q=%d), tag=%u\n", - queue, pkt_data->host_tag); - kfree_skb(skb); - break; - } - - /* We can not send the packet now, put it back to the queue */ - if (qdisc->ops->requeue(skb, qdisc) != 0) { - unifi_error(priv, - "uf_qdiscop_dequeue: requeue (q=%d) failed, tag=%u, drop it\n", - queue, pkt_data->host_tag); - - /* Requeue failed, drop the packet */ - kfree_skb(skb); - break; - } - /* We requeued the packet, increase the queued packets count */ - qd->q.qlen++; - - unifi_trace(priv, UDBG5, - "uf_qdiscop_dequeue: skip (q=%d), tag=%u\n", - queue, pkt_data->host_tag); - } - } - - func_exit(); - return NULL; -} /* uf_qdiscop_dequeue() */ - - -static void uf_qdiscop_reset(struct Qdisc* qd) -{ - struct uf_sched_data *q = qdisc_priv(qd); - int queue; - func_enter(); - - for (queue = 0; queue < UNIFI_TRAFFIC_Q_MAX; queue++) { - qdisc_reset(q->queues[queue]); - } - qd->q.qlen = 0; - - func_exit(); -} /* uf_qdiscop_reset() */ - - -static void uf_qdiscop_destroy(struct Qdisc* qd) -{ - struct uf_sched_data *q = qdisc_priv(qd); - int queue; - - func_enter(); - - for (queue=0; queue < UNIFI_TRAFFIC_Q_MAX; queue++) { - qdisc_destroy(q->queues[queue]); - q->queues[queue] = &noop_qdisc; - } - - func_exit(); -} /* uf_qdiscop_destroy() */ - - -/* called whenever parameters are updated on existing qdisc */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25) -static int uf_qdiscop_tune(struct Qdisc *qd, struct nlattr *opt) -#else -static int uf_qdiscop_tune(struct Qdisc *qd, struct rtattr *opt) -#endif -{ - func_enter(); - func_exit(); - return 0; -} /* uf_qdiscop_tune() */ - - -/* called during initial creation of qdisc on device */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25) -static int uf_qdiscop_init(struct Qdisc *qd, struct nlattr *opt) -#else -static int uf_qdiscop_init(struct Qdisc *qd, struct rtattr *opt) -#endif -{ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) - struct net_device *dev = qd->dev_queue->dev; -#else - struct net_device *dev = qd->dev; -#endif /* LINUX_VERSION_CODE */ - netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); - unifi_priv_t *priv = interfacePriv->privPtr; - struct uf_sched_data *q = qdisc_priv(qd); - int err = 0, i; - - func_enter(); - - /* make sure we do not mess with the ingress qdisc */ - if (qd->flags & TCQ_F_INGRESS) { - func_exit(); - return -EINVAL; - } - - /* if options were passed in, set them */ - if (opt) { - err = uf_qdiscop_tune(qd, opt); - } - - /* create child queues */ - for (i = 0; i < UNIFI_TRAFFIC_Q_MAX; i++) { - q->queues[i] = UF_QDISC_CREATE_DFLT(dev, &pfifo_qdisc_ops, - qd->handle); - if (!q->queues[i]) { - q->queues[i] = &noop_qdisc; - unifi_error(priv, "%s child qdisc %i creation failed\n"); - } - - unifi_trace(priv, UDBG5, "%s: child qdisc=0x%p\n", - dev->name, q->queues[i]); - } - - func_exit_r(err); - return err; -} /* uf_qdiscop_init() */ - - -static int uf_qdiscop_dump(struct Qdisc *qd, struct sk_buff *skb) -{ - func_enter(); - func_exit_r(skb->len); - return skb->len; -} /* uf_qdiscop_dump() */ - -#endif /* CONFIG_NET_SCHED */ -#endif /* LINUX_VERSION_CODE */ - #ifdef CSR_SUPPORT_WEXT /* @@ -3595,7 +2977,7 @@ uf_netdev_event(struct notifier_block *notif, unsigned long event, void* ptr) { interfacePriv->wait_netdev_change ? "" : "not"); if (interfacePriv->wait_netdev_change) { - UF_NETIF_TX_WAKE_ALL_QUEUES(priv->netdev[interfacePriv->InterfaceTag]); + netif_tx_wake_all_queues(priv->netdev[interfacePriv->InterfaceTag]); interfacePriv->connected = UnifiConnected; interfacePriv->wait_netdev_change = FALSE; /* Note: passing the broadcast address here will allow anyone to attempt to join our adhoc network */ diff --git a/drivers/staging/csr/sdio_events.c b/drivers/staging/csr/sdio_events.c index 6892c2e281bc..2a80b9eb0200 100644 --- a/drivers/staging/csr/sdio_events.c +++ b/drivers/staging/csr/sdio_events.c @@ -66,7 +66,7 @@ void unifi_suspend(void *ospriv) unifi_trace(priv, UDBG1, "unifi_suspend: netif_carrier_off"); netif_carrier_off(priv->netdev[interfaceTag]); } - UF_NETIF_TX_STOP_ALL_QUEUES(priv->netdev[interfaceTag]); + netif_tx_stop_all_queues(priv->netdev[interfaceTag]); } } @@ -119,7 +119,7 @@ void unifi_resume(void *ospriv) if (interfacePriv->netdev_registered == 1) { netif_carrier_on(priv->netdev[interfaceTag]); - UF_NETIF_TX_START_ALL_QUEUES(priv->netdev[interfaceTag]); + netif_tx_start_all_queues(priv->netdev[interfaceTag]); } } diff --git a/drivers/staging/csr/sdio_mmc.c b/drivers/staging/csr/sdio_mmc.c index d3fd57cdde0b..af3e40bb5010 100644 --- a/drivers/staging/csr/sdio_mmc.c +++ b/drivers/staging/csr/sdio_mmc.c @@ -14,7 +14,7 @@ #include <linux/kernel.h> #include <linux/mutex.h> #include <linux/gfp.h> - +#include <linux/version.h> #include <linux/mmc/core.h> #include <linux/mmc/card.h> #include <linux/mmc/host.h> @@ -31,7 +31,6 @@ struct wake_lock unifi_sdio_wake_lock; /* wakelock to prevent suspend while resu static CsrSdioFunctionDriver *sdio_func_drv; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) #ifdef CONFIG_PM static int uf_sdio_mmc_power_event(struct notifier_block *this, unsigned long event, void *ptr); #endif @@ -45,7 +44,6 @@ static int uf_sdio_mmc_power_event(struct notifier_block *this, unsigned long ev * returning immediately (at least on x86). */ static int card_is_powered = 1; -#endif /* 2.6.32 */ /* MMC uses ENOMEDIUM to indicate card gone away */ @@ -637,7 +635,6 @@ CsrSdioFunctionIdle(CsrSdioFunction *function) CsrResult CsrSdioPowerOn(CsrSdioFunction *function) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) struct sdio_func *func = (struct sdio_func *)function->priv; struct mmc_host *host = func->card->host; @@ -649,7 +646,6 @@ CsrSdioPowerOn(CsrSdioFunction *function) printk(KERN_INFO "SDIO: Skip power on; card is already powered.\n"); } _sdio_release_host(func); -#endif /* 2.6.32 */ return CSR_RESULT_SUCCESS; } /* CsrSdioPowerOn() */ @@ -667,7 +663,6 @@ CsrSdioPowerOn(CsrSdioFunction *function) void CsrSdioPowerOff(CsrSdioFunction *function) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) struct sdio_func *func = (struct sdio_func *)function->priv; struct mmc_host *host = func->card->host; @@ -679,7 +674,6 @@ CsrSdioPowerOff(CsrSdioFunction *function) printk(KERN_INFO "SDIO: Skip power off; card is already powered off.\n"); } _sdio_release_host(func); -#endif /* 2.6.32 */ } /* CsrSdioPowerOff() */ @@ -845,19 +839,18 @@ uf_glue_sdio_int_handler(struct sdio_func *func) * Status of the removal. * --------------------------------------------------------------------------- */ -int -csr_sdio_linux_remove_irq(CsrSdioFunction *function) +int csr_sdio_linux_remove_irq(CsrSdioFunction *function) { - struct sdio_func *func = (struct sdio_func *)function->priv; - int r; + struct sdio_func *func = (struct sdio_func *)function->priv; + int r; - unifi_trace(NULL, UDBG1, "csr_sdio_linux_remove_irq\n"); + unifi_trace(NULL, UDBG1, "csr_sdio_linux_remove_irq\n"); - sdio_claim_host(func); - r = sdio_release_irq(func); - sdio_release_host(func); + sdio_claim_host(func); + r = sdio_release_irq(func); + sdio_release_host(func); - return r; + return r; } /* csr_sdio_linux_remove_irq() */ @@ -876,28 +869,25 @@ csr_sdio_linux_remove_irq(CsrSdioFunction *function) * Status of the removal. * --------------------------------------------------------------------------- */ -int -csr_sdio_linux_install_irq(CsrSdioFunction *function) +int csr_sdio_linux_install_irq(CsrSdioFunction *function) { - struct sdio_func *func = (struct sdio_func *)function->priv; - int r; + struct sdio_func *func = (struct sdio_func *)function->priv; + int r; - unifi_trace(NULL, UDBG1, "csr_sdio_linux_install_irq\n"); + unifi_trace(NULL, UDBG1, "csr_sdio_linux_install_irq\n"); - /* Register our interrupt handle */ - sdio_claim_host(func); - r = sdio_claim_irq(func, uf_glue_sdio_int_handler); - sdio_release_host(func); + /* Register our interrupt handle */ + sdio_claim_host(func); + r = sdio_claim_irq(func, uf_glue_sdio_int_handler); + sdio_release_host(func); - /* If the interrupt was installed earlier, is fine */ - if (r == -EBUSY) { - r = 0; - } + /* If the interrupt was installed earlier, is fine */ + if (r == -EBUSY) + r = 0; - return r; + return r; } /* csr_sdio_linux_install_irq() */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) #ifdef CONFIG_PM /* @@ -1023,7 +1013,6 @@ uf_sdio_mmc_power_event(struct notifier_block *this, unsigned long event, void * } #endif /* CONFIG_PM */ -#endif /* 2.6.32 */ /* * --------------------------------------------------------------------------- @@ -1050,10 +1039,8 @@ uf_glue_sdio_probe(struct sdio_func *func, /* First of all claim the SDIO driver */ sdio_claim_host(func); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) /* Assume that the card is already powered */ card_is_powered = 1; -#endif /* Assumes one card per host, which is true for SDIO */ instance = func->card->host->index; @@ -1093,14 +1080,12 @@ uf_glue_sdio_probe(struct sdio_func *func, /* Pass context to the SDIO driver */ sdio_set_drvdata(func, sdio_ctx); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) #ifdef CONFIG_PM /* Register to get PM events */ if (uf_sdio_mmc_register_pm_notifier(sdio_ctx) == NULL) { unifi_error(NULL, "%s: Failed to register for PM events\n", __FUNCTION__); } #endif -#endif /* Register this device with the SDIO function driver */ /* Call the main UniFi driver inserted handler */ @@ -1156,12 +1141,10 @@ uf_glue_sdio_remove(struct sdio_func *func) sdio_func_drv->removed(sdio_ctx); } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) #ifdef CONFIG_PM /* Unregister for PM events */ uf_sdio_mmc_unregister_pm_notifier(sdio_ctx); #endif -#endif kfree(sdio_ctx); @@ -1182,7 +1165,6 @@ static const struct sdio_device_id unifi_ids[] = { MODULE_DEVICE_TABLE(sdio, unifi_ids); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) #ifdef CONFIG_PM /* @@ -1252,16 +1234,13 @@ static struct dev_pm_ops unifi_pm_ops = { #define UNIFI_PM_OPS NULL #endif /* CONFIG_PM */ -#endif /* 2.6.32 */ static struct sdio_driver unifi_driver = { .probe = uf_glue_sdio_probe, .remove = uf_glue_sdio_remove, .name = "unifi", .id_table = unifi_ids, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) .drv.pm = UNIFI_PM_OPS, -#endif /* 2.6.32 */ }; @@ -1305,12 +1284,10 @@ CsrSdioFunctionDriverRegister(CsrSdioFunctionDriver *sdio_drv) */ sdio_func_drv = sdio_drv; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,32) #ifdef CONFIG_PM /* Initialise PM notifier list */ INIT_LIST_HEAD(&uf_sdio_mmc_pm_notifiers.list); #endif -#endif /* Register ourself with mmc_core */ r = sdio_register_driver(&unifi_driver); diff --git a/drivers/staging/csr/sme_blocking.c b/drivers/staging/csr/sme_blocking.c index acf0f0fe3b37..543e8f2c407a 100644 --- a/drivers/staging/csr/sme_blocking.c +++ b/drivers/staging/csr/sme_blocking.c @@ -18,10 +18,10 @@ /* - * This file also contains the implementation of the asyncronous + * This file also contains the implementation of the asynchronous * requests to the SME. * - * Before calling an asyncronous SME function, we call sme_init_request() + * Before calling an asynchronous SME function, we call sme_init_request() * which gets hold of the SME semaphore and updates the request status. * The semaphore makes sure that there is only one pending request to * the SME at a time. diff --git a/drivers/staging/csr/sme_native.c b/drivers/staging/csr/sme_native.c index 229268fd746c..d7a5125d9a8e 100644 --- a/drivers/staging/csr/sme_native.c +++ b/drivers/staging/csr/sme_native.c @@ -12,7 +12,7 @@ */ #include <linux/netdevice.h> - +#include <linux/version.h> #include "unifi_priv.h" #include "csr_wifi_hip_unifi.h" #include "csr_wifi_hip_conversions.h" @@ -24,11 +24,7 @@ uf_sme_init(unifi_priv_t *priv) { func_enter(); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) sema_init(&priv->mlme_blocking_mutex, 1); -#else - init_MUTEX(&priv->mlme_blocking_mutex); -#endif #ifdef CSR_SUPPORT_WEXT { diff --git a/drivers/staging/csr/sme_sys.c b/drivers/staging/csr/sme_sys.c index 99de27e678d2..5b26c41c01f6 100644 --- a/drivers/staging/csr/sme_sys.c +++ b/drivers/staging/csr/sme_sys.c @@ -14,6 +14,7 @@ * --------------------------------------------------------------------------- */ +#include <linux/version.h> #include "csr_wifi_hip_unifiversion.h" #include "unifi_priv.h" #include "csr_wifi_hip_conversions.h" @@ -21,7 +22,6 @@ #include "csr_wifi_sme_sef.h" #endif - /* * This file implements the SME SYS API and contains the following functions: * CsrWifiRouterCtrlMediaStatusReqHandler() @@ -192,7 +192,7 @@ void CsrWifiRouterCtrlMediaStatusReqHandler(void* drvpriv, CsrWifiFsmEvent* msg) #endif unifi_trace(priv, UDBG1, "CsrWifiRouterCtrlMediaStatusReqHandler: AP/P2PGO setting netif_carrier_on\n"); - UF_NETIF_TX_WAKE_ALL_QUEUES(priv->netdev[req->interfaceTag]); + netif_tx_wake_all_queues(priv->netdev[req->interfaceTag]); break; default: @@ -226,7 +226,7 @@ void CsrWifiRouterCtrlMediaStatusReqHandler(void* drvpriv, CsrWifiFsmEvent* msg) unifi_trace(priv, UDBG1, "CsrWifiRouterMediaStatusReqHandler: UnifiConnected && netif_carrier_on\n"); netif_carrier_on(priv->netdev[req->interfaceTag]); - UF_NETIF_TX_WAKE_ALL_QUEUES(priv->netdev[req->interfaceTag]); + netif_tx_wake_all_queues(priv->netdev[req->interfaceTag]); uf_process_rx_pending_queue(priv, UF_UNCONTROLLED_PORT_Q, broadcast_address, 1, interfacePriv->InterfaceTag); uf_process_rx_pending_queue(priv, UF_CONTROLLED_PORT_Q, broadcast_address, 1, interfacePriv->InterfaceTag); } @@ -869,7 +869,6 @@ wifi_off(unifi_priv_t *priv) unifi_trace(priv, UDBG1, "wifi_off\n"); /* Destroy the Traffic Analysis Module */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23) cancel_work_sync(&priv->ta_ind_work.task); cancel_work_sync(&priv->ta_sample_ind_work.task); #ifdef CSR_SUPPORT_WEXT @@ -884,7 +883,6 @@ wifi_off(unifi_priv_t *priv) cancel_work_sync(&netpriv->send_m4_ready_task); } } -#endif flush_workqueue(priv->unifi_workqueue); /* fw_init parameter can prevent power off UniFi, for debugging */ @@ -955,7 +953,7 @@ void CsrWifiRouterCtrlWifiOffReqHandler(void* drvpriv, CsrWifiFsmEvent* msg) netInterface_priv_t *interfacePriv = priv->interfacePriv[i]; if (interfacePriv->netdev_registered == 1) { netif_carrier_off(priv->netdev[i]); - UF_NETIF_TX_STOP_ALL_QUEUES(priv->netdev[i]); + netif_tx_stop_all_queues(priv->netdev[i]); interfacePriv->connected = UnifiConnectedUnknown; } interfacePriv->interfaceMode = 0; @@ -2123,7 +2121,7 @@ static int peer_add_new_record(unifi_priv_t *priv,CsrWifiRouterCtrlPeerAddReq *r /* Allocate for the new station record , to avoid race condition would happen between ADD_PEER & * DEL_PEER the allocation made atomic memory rather than kernel memory */ - newRecord = (CsrWifiRouterCtrlStaInfo_t *) kmalloc(sizeof(CsrWifiRouterCtrlStaInfo_t), GFP_ATOMIC); + newRecord = kmalloc(sizeof(CsrWifiRouterCtrlStaInfo_t), GFP_ATOMIC); if (!newRecord) { unifi_error(priv, "failed to allocate the %d bytes of mem for station record\n", sizeof(CsrWifiRouterCtrlStaInfo_t)); @@ -2815,12 +2813,11 @@ u8 blockack_session_start(unifi_priv_t *priv, } /* create and populate the new BA session structure */ - ba_session_tx = kmalloc(sizeof(ba_session_tx_struct), GFP_KERNEL); + ba_session_tx = kzalloc(sizeof(ba_session_tx_struct), GFP_KERNEL); if (!ba_session_tx) { unifi_error(priv, "%s: kmalloc failed for ba_session_tx\n", __FUNCTION__); return FALSE; } - memset(ba_session_tx, 0, sizeof(ba_session_tx_struct)); ba_session_tx->interfacePriv = interfacePriv; ba_session_tx->tID = tID; @@ -2905,26 +2902,23 @@ u8 blockack_session_start(unifi_priv_t *priv, return FALSE; } - ba_session_rx = kmalloc(sizeof(ba_session_rx_struct), GFP_KERNEL); + ba_session_rx = kzalloc(sizeof(ba_session_rx_struct), GFP_KERNEL); if (!ba_session_rx) { unifi_error(priv, "%s: kmalloc failed for ba_session_rx\n", __FUNCTION__); return FALSE; } - memset(ba_session_rx, 0, sizeof(ba_session_rx_struct)); ba_session_rx->wind_size = wind_size; ba_session_rx->start_sn = ba_session_rx->expected_sn = start_sn; ba_session_rx->trigger_ba_after_ssn = FALSE; - ba_session_rx->buffer = kmalloc(ba_session_rx->wind_size*sizeof(frame_desc_struct), GFP_KERNEL); + ba_session_rx->buffer = kzalloc(ba_session_rx->wind_size*sizeof(frame_desc_struct), GFP_KERNEL); if (!ba_session_rx->buffer) { kfree(ba_session_rx); unifi_error(priv, "%s: kmalloc failed for buffer\n", __FUNCTION__); return FALSE; } - memset(ba_session_rx->buffer, 0, ba_session_rx->wind_size*sizeof(frame_desc_struct)); - INIT_WORK(&ba_session_rx->send_ba_err_task, uf_send_ba_err_wq); if (timeout) { ba_session_rx->timeout = timeout; diff --git a/drivers/staging/csr/sme_wext.c b/drivers/staging/csr/sme_wext.c index 7e85907e29a3..b58c0c6b171c 100644 --- a/drivers/staging/csr/sme_wext.c +++ b/drivers/staging/csr/sme_wext.c @@ -1191,8 +1191,6 @@ unifi_siwap(struct net_device *dev, struct iw_request_info *info, netInterface_priv_t *interfacePriv = (netInterface_priv_t *)netdev_priv(dev); unifi_priv_t *priv = interfacePriv->privPtr; int err = 0; - const unsigned char zero_bssid[ETH_ALEN] = {0x00, 0x00, 0x00, - 0x00, 0x00, 0x00}; func_enter(); @@ -1213,7 +1211,7 @@ unifi_siwap(struct net_device *dev, struct iw_request_info *info, unifi_trace(priv, UDBG1, "unifi_siwap: asked for %pM\n", wrqu->ap_addr.sa_data); - if (!memcmp(wrqu->ap_addr.sa_data, zero_bssid, ETH_ALEN)) { + if (is_zero_ether_addr(wrqu->ap_addr.sa_data)) { priv->ignore_bssid_join = FALSE; err = sme_mgt_disconnect(priv); if (err) { @@ -3043,8 +3041,8 @@ _unifi_siwencodeext(struct net_device *dev, struct iw_request_info *info, memcpy(sme_key.address.a, ext->addr.sa_data, ETH_ALEN); if (ext->ext_flags & IW_ENCODE_EXT_RX_SEQ_VALID) { - unifi_trace(priv, UDBG5, "RSC first 6 bytes = %02X:%02X:%02X:%02X:%02X:%02X\n", - ext->rx_seq[0], ext->rx_seq[1], ext->rx_seq[2], ext->rx_seq[3], ext->rx_seq[4], ext->rx_seq[5]); + unifi_trace(priv, UDBG5, "RSC first 6 bytes = %*phC\n", + 6, ext->rx_seq); /* memcpy((u8*)(&sme_key.keyRsc), ext->rx_seq, 8); */ sme_key.keyRsc[0] = ext->rx_seq[1] << 8 | ext->rx_seq[0]; diff --git a/drivers/staging/csr/ul_int.c b/drivers/staging/csr/ul_int.c index 46d3507fd8f1..4013d021ebbf 100644 --- a/drivers/staging/csr/ul_int.c +++ b/drivers/staging/csr/ul_int.c @@ -12,6 +12,7 @@ * * *************************************************************************** */ +#include <linux/version.h> #include "csr_wifi_hip_unifi.h" #include "csr_wifi_hip_conversions.h" #include "unifi_priv.h" @@ -44,11 +45,7 @@ ul_init_clients(unifi_priv_t *priv) int id; ul_client_t *ul_clients; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 37) sema_init(&priv->udi_logging_mutex, 1); -#else - init_MUTEX(&priv->udi_logging_mutex); -#endif priv->logging_client = NULL; ul_clients = priv->ul_clients; diff --git a/drivers/staging/csr/unifi_pdu_processing.c b/drivers/staging/csr/unifi_pdu_processing.c index 7c7e8d49ae42..ae7c8fc94092 100644 --- a/drivers/staging/csr/unifi_pdu_processing.c +++ b/drivers/staging/csr/unifi_pdu_processing.c @@ -14,7 +14,7 @@ * --------------------------------------------------------------------------- */ - +#include <linux/version.h> #include <linux/types.h> #include <linux/etherdevice.h> #include <linux/vmalloc.h> @@ -23,9 +23,6 @@ #include "csr_wifi_hip_conversions.h" #include "csr_time.h" #include "unifi_priv.h" -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,13) -#include <net/iw_handler.h> -#endif #include <net/pkt_sched.h> #ifdef CSR_SUPPORT_SME diff --git a/drivers/staging/csr/unifi_priv.h b/drivers/staging/csr/unifi_priv.h index 6d6b46191a1a..aec8e28fb60d 100644 --- a/drivers/staging/csr/unifi_priv.h +++ b/drivers/staging/csr/unifi_priv.h @@ -29,9 +29,7 @@ #include <linux/wireless.h> #include <linux/cdev.h> #include <linux/kthread.h> -#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,19) #include <linux/freezer.h> -#endif #ifdef CSR_WIFI_SUPPORT_MMC_DRIVER #include <linux/mmc/core.h> @@ -73,33 +71,6 @@ extern struct wake_lock unifi_sdio_wake_lock; #include "unifi_clients.h" - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20) -#include <linux/workqueue.h> - -#undef INIT_WORK -#define INIT_WORK(_work, _func) \ - do { \ - INIT_LIST_HEAD(&(_work)->entry); \ - (_work)->pending = 0; \ - PREPARE_WORK((_work), (_func), (_work)); \ - init_timer(&(_work)->timer); \ - } while(0) - -#endif /* Linux kernel < 2.6.20 */ - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27) -#define UF_NETIF_TX_WAKE_ALL_QUEUES(_netdev) netif_tx_wake_all_queues(_netdev) -#define UF_NETIF_TX_START_ALL_QUEUES(_netdev) netif_tx_start_all_queues(_netdev) -#define UF_NETIF_TX_STOP_ALL_QUEUES(_netdev) netif_tx_stop_all_queues(_netdev) -#else -#define UF_NETIF_TX_WAKE_ALL_QUEUES(_netdev) netif_wake_queue(_netdev) -#define UF_NETIF_TX_START_ALL_QUEUES(_netdev) netif_start_queue(_netdev) -#define UF_NETIF_TX_STOP_ALL_QUEUES(_netdev) netif_stop_queue(_netdev) -#endif /* Linux kernel >= 2.6.27 */ - - #ifdef CSR_NATIVE_LINUX #include "sme_native/unifi_native.h" #else @@ -634,12 +605,10 @@ struct unifi_priv { spinlock_t wapi_lock; #endif -#ifndef ALLOW_Q_PAUSE /* Array to indicate if a particular Tx queue is paused, this may not be * required in a multiqueue implementation since we can directly stop kernel * queues */ u8 tx_q_paused_flag[UNIFI_TRAFFIC_Q_MAX]; -#endif #ifdef CSR_WIFI_RX_PATH_SPLIT struct workqueue_struct *rx_workqueue; @@ -798,12 +767,6 @@ typedef struct netInterface_priv u8 bcTimSetReqQueued; } netInterface_priv_t; -#ifndef ALLOW_Q_PAUSE -#define net_is_tx_q_paused(priv, q) (priv->tx_q_paused_flag[q]) -#define net_tx_q_unpause(priv, q) (priv->tx_q_paused_flag[q] = 0) -#define net_tx_q_pause(priv, q) (priv->tx_q_paused_flag[q] = 1) -#endif - #ifdef CSR_SUPPORT_SME #define routerStartBuffering(priv,queue) priv->routerBufferEnable[(queue)] = TRUE; #define routerStopBuffering(priv,queue) priv->routerBufferEnable[(queue)] = FALSE; @@ -1088,9 +1051,6 @@ CsrWifiRouterCtrlStaInfo_t * CsrWifiRouterCtrlGetStationRecordFromHandle(unifi_p void uf_update_sta_activity(unifi_priv_t *priv, u16 interfaceTag, const u8 *peerMacAddress); void uf_process_ma_pkt_cfm_for_ap(unifi_priv_t *priv,u16 interfaceTag, const CSR_MA_PACKET_CONFIRM *pkt_cfm); #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28) -int uf_install_qdisc(struct net_device *dev); -#endif void uf_resume_data_plane(unifi_priv_t *priv, int queue, CsrWifiMacAddress peer_address, diff --git a/drivers/staging/csr/unifi_wext.h b/drivers/staging/csr/unifi_wext.h index 6d7a99595083..6834c43abfbb 100644 --- a/drivers/staging/csr/unifi_wext.h +++ b/drivers/staging/csr/unifi_wext.h @@ -16,6 +16,7 @@ #define __LINUX_UNIFI_WEXT_H__ 1 #include <linux/kernel.h> +#include <linux/version.h> #include <net/iw_handler.h> #include "csr_wifi_sme_prim.h" @@ -70,15 +71,9 @@ uf_iwe_stream_add_point(struct iw_request_info *info, char *start, char *stop, { char *new_start; - new_start = iwe_stream_add_point( -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) || defined (IW_REQUEST_FLAG_COMPAT) - info, -#endif - start, stop, piwe, extra); + new_start = iwe_stream_add_point(info, start, stop, piwe, extra); if (unlikely(new_start == start)) - { return -E2BIG; - } return (new_start - start); } @@ -90,14 +85,9 @@ uf_iwe_stream_add_event(struct iw_request_info *info, char *start, char *stop, { char *new_start; - new_start = iwe_stream_add_event( -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) || defined(IW_REQUEST_FLAG_COMPAT) - info, -#endif - start, stop, piwe, len); - if (unlikely(new_start == start)) { + new_start = iwe_stream_add_event(info, start, stop, piwe, len); + if (unlikely(new_start == start)) return -E2BIG; - } return (new_start - start); } @@ -108,14 +98,9 @@ uf_iwe_stream_add_value(struct iw_request_info *info, char *stream, char *start, { char *new_start; - new_start = iwe_stream_add_value( -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 27) || defined(IW_REQUEST_FLAG_COMPAT) - info, -#endif - stream, start, stop, piwe, len); - if (unlikely(new_start == start)) { + new_start = iwe_stream_add_value(info, stream, start, stop, piwe, len); + if (unlikely(new_start == start)) return -E2BIG; - } return (new_start - start); } diff --git a/drivers/staging/csr/wext_events.c b/drivers/staging/csr/wext_events.c index d356887ac4c6..9860ea30da25 100644 --- a/drivers/staging/csr/wext_events.c +++ b/drivers/staging/csr/wext_events.c @@ -194,11 +194,9 @@ _send_michaelmicfailure_event(struct net_device *dev, union iwreq_data wrqu; char buf[128]; - sprintf(buf, - "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr=%02x:%02x:%02x:%02x:%02x:%02x)", - key_idx, (key_type == CSR_GROUP) ? "broad" : "uni", - macaddr[0], macaddr[1], macaddr[2], - macaddr[3], macaddr[4], macaddr[5]); + sprintf(buf, + "MLME-MICHAELMICFAILURE.indication(keyid=%d %scast addr=%pM)", + key_idx, (key_type == CSR_GROUP) ? "broad" : "uni", macaddr); memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = strlen(buf); wireless_send_event(dev, IWEVCUSTOM, &wrqu, buf); diff --git a/drivers/staging/cxt1e1/linux.c b/drivers/staging/cxt1e1/linux.c index 911c0e4375fd..0ff2865edec8 100644 --- a/drivers/staging/cxt1e1/linux.c +++ b/drivers/staging/cxt1e1/linux.c @@ -405,7 +405,7 @@ c4_linux_xmit (struct sk_buff * skb, struct net_device * ndev) priv = hdlc->priv; rval = musycc_start_xmit (priv->ci, priv->channum, skb); - return -rval; + return rval; } static const struct net_device_ops chan_ops = { @@ -1169,11 +1169,11 @@ cleanup_hdlc (void) STATIC void __exit c4_mod_remove (void) { - cleanup_hdlc (); /* delete any missed channels */ - cleanup_devs (); - c4_cleanup (); - cleanup_ioremap (); - pr_info("SBE - driver removed.\n"); + cleanup_hdlc(); /* delete any missed channels */ + cleanup_devs(); + c4_cleanup(); + cleanup_ioremap(); + pr_info("SBE - driver removed.\n"); } module_init (c4_mod_init); diff --git a/drivers/staging/cxt1e1/musycc.c b/drivers/staging/cxt1e1/musycc.c index 90c0f1e30f65..ba721c604061 100644 --- a/drivers/staging/cxt1e1/musycc.c +++ b/drivers/staging/cxt1e1/musycc.c @@ -1761,15 +1761,15 @@ musycc_start_xmit (ci_t * ci, int channum, void *mem_token) u_int32_t len; if (!(ch = sd_find_chan (ci, channum))) - return ENOENT; + return -ENOENT; if (ci->state != C_RUNNING) /* full interrupt processing available */ - return EINVAL; + return -EINVAL; if (ch->state != UP) - return EINVAL; + return -EINVAL; if (!(ch->status & TX_ENABLED)) - return EROFS; /* how else to flag unwritable state ? */ + return -EROFS; /* how else to flag unwritable state ? */ #ifdef RLD_TRANS_DEBUGx if (1 || cxt1e1_log_level >= LOG_MONITOR2) @@ -1836,7 +1836,7 @@ musycc_start_xmit (ci_t * ci, int channum, void *mem_token) #if 0 spin_unlock_irqrestore (&ch->ch_txlock, flags); #endif - return EBUSY; /* tell user to try again later */ + return -EBUSY; /* tell user to try again later */ } /**************************************************/ /** Put the user data into MUSYCC data buffer(s) **/ diff --git a/drivers/staging/et131x/et131x.c b/drivers/staging/et131x/et131x.c index 49553f88c7b3..413da0d6b9f6 100644 --- a/drivers/staging/et131x/et131x.c +++ b/drivers/staging/et131x/et131x.c @@ -3955,12 +3955,7 @@ static void et131x_hwaddr_init(struct et131x_adapter *adapter) * EEPROM then we need to generate the last octet and set it on the * device */ - if (adapter->rom_addr[0] == 0x00 && - adapter->rom_addr[1] == 0x00 && - adapter->rom_addr[2] == 0x00 && - adapter->rom_addr[3] == 0x00 && - adapter->rom_addr[4] == 0x00 && - adapter->rom_addr[5] == 0x00) { + if (is_zero_ether_addr(adapter->rom_addr)) { /* * We need to randomly generate the last octet so we * decrease our chances of setting the mac address to diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_dnld.c b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_dnld.c index f8b8e71284d9..47cc365c630b 100644 --- a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_dnld.c +++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_dnld.c @@ -94,27 +94,27 @@ void put_request_value(struct net_device *dev, long lvalue); u16 hdr_checksum(struct pseudo_hdr *pHdr); struct dsp_file_hdr { - u32 version_id; // Version ID of this image format. - u32 package_id; // Package ID of code release. - u32 build_date; // Date/time stamp when file was built. - u32 commands_offset; // Offset to attached commands in Pseudo Hdr format. - u32 loader_offset; // Offset to bootloader code. - u32 loader_code_address; // Start address of bootloader. - u32 loader_code_end; // Where bootloader code ends. + u32 version_id; /* Version ID of this image format. */ + u32 package_id; /* Package ID of code release. */ + u32 build_date; /* Date/time stamp when file was built. */ + u32 commands_offset; /* Offset to attached commands in Pseudo Hdr format. */ + u32 loader_offset; /* Offset to bootloader code. */ + u32 loader_code_address; /* Start address of bootloader. */ + u32 loader_code_end; /* Where bootloader code ends. */ u32 loader_code_size; - u32 version_data_offset; // Offset were scrambled version data begins. - u32 version_data_size; // Size, in words, of scrambled version data. - u32 nDspImages; // Number of DSP images in file. + u32 version_data_offset; /* Offset were scrambled version data begins. */ + u32 version_data_size; /* Size, in words, of scrambled version data. */ + u32 nDspImages; /* Number of DSP images in file. */ } __attribute__ ((packed)); struct dsp_image_info { - u32 coff_date; // Date/time when DSP Coff image was built. - u32 begin_offset; // Offset in file where image begins. - u32 end_offset; // Offset in file where image begins. - u32 run_address; // On chip Start address of DSP code. - u32 image_size; // Size of image. - u32 version; // Embedded version # of DSP code. - unsigned short checksum; // Dsp File checksum + u32 coff_date; /* Date/time when DSP Coff image was built. */ + u32 begin_offset; /* Offset in file where image begins. */ + u32 end_offset; /* Offset in file where image begins. */ + u32 run_address; /* On chip Start address of DSP code. */ + u32 image_size; /* Size of image. */ + u32 version; /* Embedded version # of DSP code. */ + unsigned short checksum; /* Dsp File checksum */ unsigned short pad1; } __attribute__ ((packed)); diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c index 31929ef5332d..809fa4886961 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c @@ -73,7 +73,7 @@ static int ft1000_control(struct ft1000_device *ft1000dev, unsigned int pipe, } ret = usb_control_msg(ft1000dev->dev, pipe, request, requesttype, - value, index, data, size, LARGE_TIMEOUT); + value, index, data, size, timeout); if (ret > 0) ret = 0; @@ -110,7 +110,7 @@ int ft1000_read_register(struct ft1000_device *ft1000dev, u16* Data, nRegIndx, Data, 2, - LARGE_TIMEOUT); + USB_CTRL_GET_TIMEOUT); return ret; } @@ -143,7 +143,7 @@ int ft1000_write_register(struct ft1000_device *ft1000dev, u16 value, nRegIndx, NULL, 0, - LARGE_TIMEOUT); + USB_CTRL_SET_TIMEOUT); return ret; } @@ -178,7 +178,7 @@ int ft1000_read_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer, indx, buffer, cnt, - LARGE_TIMEOUT); + USB_CTRL_GET_TIMEOUT); return ret; } @@ -215,7 +215,7 @@ int ft1000_write_dpram32(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer, indx, buffer, cnt, - LARGE_TIMEOUT); + USB_CTRL_SET_TIMEOUT); return ret; } @@ -255,7 +255,7 @@ int ft1000_read_dpram16(struct ft1000_device *ft1000dev, u16 indx, u8 *buffer, indx, buffer, 2, - LARGE_TIMEOUT); + USB_CTRL_GET_TIMEOUT); return ret; } @@ -294,7 +294,7 @@ int ft1000_write_dpram16(struct ft1000_device *ft1000dev, u16 indx, u16 value, u indx, NULL, 0, - LARGE_TIMEOUT); + USB_CTRL_SET_TIMEOUT); return ret; } diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h index 642bb89942f5..2aa6a1c7fd38 100644 --- a/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h +++ b/drivers/staging/ft1000/ft1000-usb/ft1000_usb.h @@ -36,8 +36,6 @@ struct app_info_block { #define FT1000_STATUS_CLOSING 0x01 -#define LARGE_TIMEOUT 5000 - #define DSPBCMSGID 0x10 /* Electrabuzz specific DPRAM mapping */ diff --git a/drivers/staging/gdm72xx/gdm_qos.c b/drivers/staging/gdm72xx/gdm_qos.c index 80bde053fbc2..e26c6a8b2627 100644 --- a/drivers/staging/gdm72xx/gdm_qos.c +++ b/drivers/staging/gdm72xx/gdm_qos.c @@ -106,8 +106,8 @@ void gdm_qos_init(void *nic_ptr) for (i = 0 ; i < QOS_MAX; i++) { INIT_LIST_HEAD(&qcb->qos_list[i]); - qcb->csr[i].QoSBufCount = 0; - qcb->csr[i].Enabled = 0; + qcb->csr[i].qos_buf_count = 0; + qcb->csr[i].enabled = 0; } qcb->qos_list_cnt = 0; @@ -133,8 +133,8 @@ void gdm_qos_release_list(void *nic_ptr) spin_lock_irqsave(&qcb->qos_lock, flags); for (i = 0; i < QOS_MAX; i++) { - qcb->csr[i].QoSBufCount = 0; - qcb->csr[i].Enabled = 0; + qcb->csr[i].qos_buf_count = 0; + qcb->csr[i].enabled = 0; } qcb->qos_list_cnt = 0; @@ -153,42 +153,42 @@ static u32 chk_ipv4_rule(struct gdm_wimax_csr_s *csr, u8 *Stream, u8 *port) { int i; - if (csr->ClassifierRuleEnable&IPTYPEOFSERVICE) { - if (((Stream[1] & csr->IPToSMask) < csr->IPToSLow) || - ((Stream[1] & csr->IPToSMask) > csr->IPToSHigh)) + if (csr->classifier_rule_en&IPTYPEOFSERVICE) { + if (((Stream[1] & csr->ip2s_mask) < csr->ip2s_lo) || + ((Stream[1] & csr->ip2s_mask) > csr->ip2s_hi)) return 1; } - if (csr->ClassifierRuleEnable&PROTOCOL) { - if (Stream[9] != csr->Protocol) + if (csr->classifier_rule_en&PROTOCOL) { + if (Stream[9] != csr->protocol) return 1; } - if (csr->ClassifierRuleEnable&IPMASKEDSRCADDRESS) { + if (csr->classifier_rule_en&IPMASKEDSRCADDRESS) { for (i = 0; i < 4; i++) { - if ((Stream[12 + i] & csr->IPSrcAddrMask[i]) != - (csr->IPSrcAddr[i] & csr->IPSrcAddrMask[i])) + if ((Stream[12 + i] & csr->ipsrc_addrmask[i]) != + (csr->ipsrc_addr[i] & csr->ipsrc_addrmask[i])) return 1; } } - if (csr->ClassifierRuleEnable&IPMASKEDDSTADDRESS) { + if (csr->classifier_rule_en&IPMASKEDDSTADDRESS) { for (i = 0; i < 4; i++) { - if ((Stream[16 + i] & csr->IPDstAddrMask[i]) != - (csr->IPDstAddr[i] & csr->IPDstAddrMask[i])) + if ((Stream[16 + i] & csr->ipdst_addrmask[i]) != + (csr->ipdst_addr[i] & csr->ipdst_addrmask[i])) return 1; } } - if (csr->ClassifierRuleEnable&PROTOCOLSRCPORTRANGE) { + if (csr->classifier_rule_en&PROTOCOLSRCPORTRANGE) { i = ((port[0]<<8)&0xff00)+port[1]; - if ((i < csr->SrcPortLow) || (i > csr->SrcPortHigh)) + if ((i < csr->srcport_lo) || (i > csr->srcport_hi)) return 1; } - if (csr->ClassifierRuleEnable&PROTOCOLDSTPORTRANGE) { + if (csr->classifier_rule_en&PROTOCOLDSTPORTRANGE) { i = ((port[2]<<8)&0xff00)+port[3]; - if ((i < csr->DstPortLow) || (i > csr->DstPortHigh)) + if ((i < csr->dstport_lo) || (i > csr->dstport_hi)) return 1; } @@ -208,8 +208,8 @@ static u32 get_qos_index(struct nic *nic, u8 *iph, u8 *tcpudph) if (IP_Ver == 4) { for (i = 0; i < QOS_MAX; i++) { - if (qcb->csr[i].Enabled) { - if (qcb->csr[i].ClassifierRuleEnable) { + if (qcb->csr[i].enabled) { + if (qcb->csr[i].classifier_rule_en) { if (chk_ipv4_rule(&qcb->csr[i], iph, tcpudph) == 0) return i; @@ -230,14 +230,14 @@ static u32 extract_qos_list(struct nic *nic, struct list_head *head) INIT_LIST_HEAD(head); for (i = 0; i < QOS_MAX; i++) { - if (qcb->csr[i].Enabled) { - if (qcb->csr[i].QoSBufCount < qcb->qos_limit_size) { + if (qcb->csr[i].enabled) { + if (qcb->csr[i].qos_buf_count < qcb->qos_limit_size) { if (!list_empty(&qcb->qos_list[i])) { entry = list_entry( qcb->qos_list[i].prev, struct qos_entry_s, list); list_move_tail(&entry->list, head); - qcb->csr[i].QoSBufCount++; + qcb->csr[i].qos_buf_count++; if (!list_empty(&qcb->qos_list[i])) wprintk("QoS Index(%d) is piled!!\n", i); @@ -322,8 +322,8 @@ static u32 get_csr(struct qos_cb_s *qcb, u32 SFID, int mode) if (mode) { for (i = 0; i < QOS_MAX; i++) { - if (qcb->csr[i].Enabled == 0) { - qcb->csr[i].Enabled = 1; + if (qcb->csr[i].enabled == 0) { + qcb->csr[i].enabled = 1; qcb->qos_list_cnt++; return i; } @@ -365,7 +365,7 @@ void gdm_recv_qos_hci_packet(void *nic_ptr, u8 *buf, int size) eprintk("QoS ERROR: No SF\n"); return; } - qcb->csr[index].QoSBufCount = buf[(i*5)+10]; + qcb->csr[index].qos_buf_count = buf[(i*5)+10]; } extract_qos_list(nic, &send_list); @@ -391,38 +391,38 @@ void gdm_recv_qos_hci_packet(void *nic_ptr, u8 *buf, int size) spin_lock_irqsave(&qcb->qos_lock, flags); qcb->csr[index].SFID = SFID; - qcb->csr[index].ClassifierRuleEnable = ((buf[pos++]<<8)&0xff00); - qcb->csr[index].ClassifierRuleEnable += buf[pos++]; - if (qcb->csr[index].ClassifierRuleEnable == 0) + qcb->csr[index].classifier_rule_en = ((buf[pos++]<<8)&0xff00); + qcb->csr[index].classifier_rule_en += buf[pos++]; + if (qcb->csr[index].classifier_rule_en == 0) qcb->qos_null_idx = index; - qcb->csr[index].IPToSMask = buf[pos++]; - qcb->csr[index].IPToSLow = buf[pos++]; - qcb->csr[index].IPToSHigh = buf[pos++]; - qcb->csr[index].Protocol = buf[pos++]; - qcb->csr[index].IPSrcAddrMask[0] = buf[pos++]; - qcb->csr[index].IPSrcAddrMask[1] = buf[pos++]; - qcb->csr[index].IPSrcAddrMask[2] = buf[pos++]; - qcb->csr[index].IPSrcAddrMask[3] = buf[pos++]; - qcb->csr[index].IPSrcAddr[0] = buf[pos++]; - qcb->csr[index].IPSrcAddr[1] = buf[pos++]; - qcb->csr[index].IPSrcAddr[2] = buf[pos++]; - qcb->csr[index].IPSrcAddr[3] = buf[pos++]; - qcb->csr[index].IPDstAddrMask[0] = buf[pos++]; - qcb->csr[index].IPDstAddrMask[1] = buf[pos++]; - qcb->csr[index].IPDstAddrMask[2] = buf[pos++]; - qcb->csr[index].IPDstAddrMask[3] = buf[pos++]; - qcb->csr[index].IPDstAddr[0] = buf[pos++]; - qcb->csr[index].IPDstAddr[1] = buf[pos++]; - qcb->csr[index].IPDstAddr[2] = buf[pos++]; - qcb->csr[index].IPDstAddr[3] = buf[pos++]; - qcb->csr[index].SrcPortLow = ((buf[pos++]<<8)&0xff00); - qcb->csr[index].SrcPortLow += buf[pos++]; - qcb->csr[index].SrcPortHigh = ((buf[pos++]<<8)&0xff00); - qcb->csr[index].SrcPortHigh += buf[pos++]; - qcb->csr[index].DstPortLow = ((buf[pos++]<<8)&0xff00); - qcb->csr[index].DstPortLow += buf[pos++]; - qcb->csr[index].DstPortHigh = ((buf[pos++]<<8)&0xff00); - qcb->csr[index].DstPortHigh += buf[pos++]; + qcb->csr[index].ip2s_mask = buf[pos++]; + qcb->csr[index].ip2s_lo = buf[pos++]; + qcb->csr[index].ip2s_hi = buf[pos++]; + qcb->csr[index].protocol = buf[pos++]; + qcb->csr[index].ipsrc_addrmask[0] = buf[pos++]; + qcb->csr[index].ipsrc_addrmask[1] = buf[pos++]; + qcb->csr[index].ipsrc_addrmask[2] = buf[pos++]; + qcb->csr[index].ipsrc_addrmask[3] = buf[pos++]; + qcb->csr[index].ipsrc_addr[0] = buf[pos++]; + qcb->csr[index].ipsrc_addr[1] = buf[pos++]; + qcb->csr[index].ipsrc_addr[2] = buf[pos++]; + qcb->csr[index].ipsrc_addr[3] = buf[pos++]; + qcb->csr[index].ipdst_addrmask[0] = buf[pos++]; + qcb->csr[index].ipdst_addrmask[1] = buf[pos++]; + qcb->csr[index].ipdst_addrmask[2] = buf[pos++]; + qcb->csr[index].ipdst_addrmask[3] = buf[pos++]; + qcb->csr[index].ipdst_addr[0] = buf[pos++]; + qcb->csr[index].ipdst_addr[1] = buf[pos++]; + qcb->csr[index].ipdst_addr[2] = buf[pos++]; + qcb->csr[index].ipdst_addr[3] = buf[pos++]; + qcb->csr[index].srcport_lo = ((buf[pos++]<<8)&0xff00); + qcb->csr[index].srcport_lo += buf[pos++]; + qcb->csr[index].srcport_hi = ((buf[pos++]<<8)&0xff00); + qcb->csr[index].srcport_hi += buf[pos++]; + qcb->csr[index].dstport_lo = ((buf[pos++]<<8)&0xff00); + qcb->csr[index].dstport_lo += buf[pos++]; + qcb->csr[index].dstport_hi = ((buf[pos++]<<8)&0xff00); + qcb->csr[index].dstport_hi += buf[pos++]; qcb->qos_limit_size = 254/qcb->qos_list_cnt; spin_unlock_irqrestore(&qcb->qos_lock, flags); @@ -444,7 +444,7 @@ void gdm_recv_qos_hci_packet(void *nic_ptr, u8 *buf, int size) INIT_LIST_HEAD(&free_list); spin_lock_irqsave(&qcb->qos_lock, flags); - qcb->csr[index].Enabled = 0; + qcb->csr[index].enabled = 0; qcb->qos_list_cnt--; qcb->qos_limit_size = 254/qcb->qos_list_cnt; diff --git a/drivers/staging/gdm72xx/gdm_qos.h b/drivers/staging/gdm72xx/gdm_qos.h index 33f2bd4cee32..8f18119d22a9 100644 --- a/drivers/staging/gdm72xx/gdm_qos.h +++ b/drivers/staging/gdm72xx/gdm_qos.h @@ -20,18 +20,18 @@ #define BOOLEAN u8 -#define QOS_MAX 16 -#define IPTYPEOFSERVICE 0x8000 -#define PROTOCOL 0x4000 -#define IPMASKEDSRCADDRESS 0x2000 -#define IPMASKEDDSTADDRESS 0x1000 +#define QOS_MAX 16 +#define IPTYPEOFSERVICE 0x8000 +#define PROTOCOL 0x4000 +#define IPMASKEDSRCADDRESS 0x2000 +#define IPMASKEDDSTADDRESS 0x1000 #define PROTOCOLSRCPORTRANGE 0x800 #define PROTOCOLDSTPORTRANGE 0x400 -#define DSTMACADDR 0x200 -#define SRCMACADDR 0x100 -#define ETHERTYPE 0x80 +#define DSTMACADDR 0x200 +#define SRCMACADDR 0x100 +#define ETHERTYPE 0x80 #define IEEE802_1DUSERPRIORITY 0x40 -#define IEEE802_1QVLANID 0x10 +#define IEEE802_1QVLANID 0x10 struct gdm_wimax_csr_s { /* union{ @@ -51,28 +51,28 @@ struct gdm_wimax_csr_s { Reserved:5; } fields; } */ - BOOLEAN Enabled; - u32 SFID; - u8 QoSBufCount; - u16 ClassifierRuleEnable; - u8 IPToSLow; - u8 IPToSHigh; - u8 IPToSMask; - u8 Protocol; - u8 IPSrcAddr[16]; - u8 IPSrcAddrMask[16]; - u8 IPDstAddr[16]; - u8 IPDstAddrMask[16]; - u16 SrcPortLow; - u16 SrcPortHigh; - u16 DstPortLow; - u16 DstPortHigh; + BOOLEAN enabled; + u32 SFID; + u8 qos_buf_count; + u16 classifier_rule_en; + u8 ip2s_lo; + u8 ip2s_hi; + u8 ip2s_mask; + u8 protocol; + u8 ipsrc_addr[16]; + u8 ipsrc_addrmask[16]; + u8 ipdst_addr[16]; + u8 ipdst_addrmask[16]; + u16 srcport_lo; + u16 srcport_hi; + u16 dstport_lo; + u16 dstport_hi; }; struct qos_entry_s { - struct list_head list; - struct sk_buff *skb; - struct net_device *dev; + struct list_head list; + struct sk_buff *skb; + struct net_device *dev; }; @@ -81,7 +81,7 @@ struct qos_cb_s { u32 qos_list_cnt; u32 qos_null_idx; struct gdm_wimax_csr_s csr[QOS_MAX]; - spinlock_t qos_lock; + spinlock_t qos_lock; u32 qos_limit_size; }; diff --git a/drivers/staging/gdm72xx/gdm_sdio.c b/drivers/staging/gdm72xx/gdm_sdio.c index 3e43c012ef27..ca38d719a1f8 100644 --- a/drivers/staging/gdm72xx/gdm_sdio.c +++ b/drivers/staging/gdm72xx/gdm_sdio.c @@ -60,27 +60,20 @@ static void hexdump(char *title, u8 *data, int len) static struct sdio_tx *alloc_tx_struct(struct tx_cxt *tx) { - struct sdio_tx *t = NULL; - - t = kmalloc(sizeof(*t), GFP_ATOMIC); - if (t == NULL) - goto out; + struct sdio_tx *t = kzalloc(sizeof(*t), GFP_ATOMIC); - memset(t, 0, sizeof(*t)); + if (!t) + return NULL; t->buf = kmalloc(TX_BUF_SIZE, GFP_ATOMIC); - if (t->buf == NULL) - goto out; + if (!t->buf) { + kfree(t); + return NULL; + } t->tx_cxt = tx; return t; -out: - if (t) { - kfree(t->buf); - kfree(t); - } - return NULL; } static void free_tx_struct(struct sdio_tx *t) @@ -93,20 +86,12 @@ static void free_tx_struct(struct sdio_tx *t) static struct sdio_rx *alloc_rx_struct(struct rx_cxt *rx) { - struct sdio_rx *r = NULL; + struct sdio_rx *r = kzalloc(sizeof(*r), GFP_ATOMIC); - r = kmalloc(sizeof(*r), GFP_ATOMIC); - if (r == NULL) - goto out; - - memset(r, 0, sizeof(*r)); - - r->rx_cxt = rx; + if (r) + r->rx_cxt = rx; return r; -out: - kfree(r); - return NULL; } static void free_rx_struct(struct sdio_rx *r) @@ -680,7 +665,7 @@ static int sdio_wimax_probe(struct sdio_func *func, phy_dev->rcv_func = gdm_sdio_receive; ret = init_sdio(sdev); - if (sdev < 0) + if (ret < 0) goto out; sdev->func = func; diff --git a/drivers/staging/gdm72xx/gdm_usb.c b/drivers/staging/gdm72xx/gdm_usb.c index d48d49c145ee..0c9e8958009b 100644 --- a/drivers/staging/gdm72xx/gdm_usb.c +++ b/drivers/staging/gdm72xx/gdm_usb.c @@ -26,11 +26,11 @@ MODULE_DEVICE_TABLE(usb, id_table); -#define TX_BUF_SIZE 2048 +#define TX_BUF_SIZE 2048 #if defined(CONFIG_WIMAX_GDM72XX_WIMAX2) -#define RX_BUF_SIZE (128*1024) /* For packet aggregation */ +#define RX_BUF_SIZE (128*1024) /* For packet aggregation */ #else -#define RX_BUF_SIZE 2048 +#define RX_BUF_SIZE 2048 #endif #define GDM7205_PADDING 256 @@ -39,7 +39,7 @@ MODULE_DEVICE_TABLE(usb, id_table); #define B2H(x) __be16_to_cpu(x) #define DB2H(x) __be32_to_cpu(x) -#define DOWNLOAD_CONF_VALUE 0x21 +#define DOWNLOAD_CONF_VALUE 0x21 #ifdef CONFIG_WIMAX_GDM72XX_K_MODE @@ -48,7 +48,7 @@ static LIST_HEAD(k_list); static DEFINE_SPINLOCK(k_lock); static int k_mode_stop; -#define K_WAIT_TIME (2 * HZ / 100) +#define K_WAIT_TIME (2 * HZ / 100) #endif /* CONFIG_WIMAX_GDM72XX_K_MODE */ @@ -73,29 +73,23 @@ static void hexdump(char *title, u8 *data, int len) static struct usb_tx *alloc_tx_struct(struct tx_cxt *tx) { - struct usb_tx *t = NULL; + struct usb_tx *t = kzalloc(sizeof(*t), GFP_ATOMIC); - t = kmalloc(sizeof(*t), GFP_ATOMIC); - if (t == NULL) - goto out; - - memset(t, 0, sizeof(*t)); + if (!t) + return NULL; t->urb = usb_alloc_urb(0, GFP_ATOMIC); t->buf = kmalloc(TX_BUF_SIZE, GFP_ATOMIC); - if (t->urb == NULL || t->buf == NULL) - goto out; - - t->tx_cxt = tx; - - return t; -out: - if (t) { + if (!t->urb || !t->buf) { usb_free_urb(t->urb); kfree(t->buf); kfree(t); + return NULL; } - return NULL; + + t->tx_cxt = tx; + + return t; } static void free_tx_struct(struct usb_tx *t) @@ -109,28 +103,22 @@ static void free_tx_struct(struct usb_tx *t) static struct usb_rx *alloc_rx_struct(struct rx_cxt *rx) { - struct usb_rx *r = NULL; + struct usb_rx *r = kzalloc(sizeof(*r), GFP_ATOMIC); - r = kmalloc(sizeof(*r), GFP_ATOMIC); - if (r == NULL) - goto out; - - memset(r, 0, sizeof(*r)); + if (!r) + return NULL; r->urb = usb_alloc_urb(0, GFP_ATOMIC); r->buf = kmalloc(RX_BUF_SIZE, GFP_ATOMIC); - if (r->urb == NULL || r->buf == NULL) - goto out; - - r->rx_cxt = rx; - return r; -out: - if (r) { + if (!r->urb || !r->buf) { usb_free_urb(r->urb); kfree(r->buf); kfree(r); + return NULL; } - return NULL; + + r->rx_cxt = rx; + return r; } static void free_rx_struct(struct usb_rx *r) @@ -180,8 +168,7 @@ static struct usb_rx *get_rx_struct(struct rx_cxt *rx) } r = list_entry(rx->free_list.next, struct usb_rx, list); - list_del(&r->list); - list_add_tail(&r->list, &rx->used_list); + list_move_tail(&r->list, &rx->used_list); return r; } @@ -189,8 +176,7 @@ static struct usb_rx *get_rx_struct(struct rx_cxt *rx) /* Before this function is called, spin lock should be locked. */ static void put_rx_struct(struct rx_cxt *rx, struct usb_rx *r) { - list_del(&r->list); - list_add(&r->list, &rx->free_list); + list_move(&r->list, &rx->free_list); } static int init_usb(struct usbwm_dev *udev) diff --git a/drivers/staging/gdm72xx/gdm_usb.h b/drivers/staging/gdm72xx/gdm_usb.h index ecb891f6a599..f2c54511bb96 100644 --- a/drivers/staging/gdm72xx/gdm_usb.h +++ b/drivers/staging/gdm72xx/gdm_usb.h @@ -18,8 +18,8 @@ #include <linux/usb.h> #include <linux/list.h> -#define B_DIFF_DL_DRV (1<<4) -#define B_DOWNLOAD (1 << 5) +#define B_DIFF_DL_DRV (1 << 4) +#define B_DOWNLOAD (1 << 5) #define MAX_NR_SDU_BUF 64 struct usb_tx { @@ -29,7 +29,7 @@ struct usb_tx { #endif struct tx_cxt *tx_cxt; - struct urb *urb; + struct urb *urb; u8 *buf; void (*callback)(void *cb_data); @@ -44,14 +44,14 @@ struct tx_cxt { struct list_head pending_list; #endif - spinlock_t lock; + spinlock_t lock; }; struct usb_rx { struct list_head list; struct rx_cxt *rx_cxt; - struct urb *urb; + struct urb *urb; u8 *buf; void (*callback)(void *cb_data, void *data, int len); @@ -61,7 +61,7 @@ struct usb_rx { struct rx_cxt { struct list_head free_list; struct list_head used_list; - spinlock_t lock; + spinlock_t lock; }; struct usbwm_dev { @@ -76,8 +76,8 @@ struct usbwm_dev { struct list_head list; #endif - struct tx_cxt tx; - struct rx_cxt rx; + struct tx_cxt tx; + struct rx_cxt rx; int padding; }; diff --git a/drivers/staging/gdm72xx/gdm_wimax.c b/drivers/staging/gdm72xx/gdm_wimax.c index 0716efc1817d..6cb810701a3e 100644 --- a/drivers/staging/gdm72xx/gdm_wimax.c +++ b/drivers/staging/gdm72xx/gdm_wimax.c @@ -258,12 +258,16 @@ static int gdm_wimax_event_init(void) if (!wm_event.ref_cnt) { wm_event.sock = netlink_init(NETLINK_WIMAX, gdm_wimax_event_rcv); - if (wm_event.sock) - wm_event.ref_cnt++; - INIT_LIST_HEAD(&wm_event.evtq); - INIT_LIST_HEAD(&wm_event.freeq); - INIT_WORK(&wm_event.ws, __gdm_wimax_event_send); - spin_lock_init(&wm_event.evt_lock); + if (wm_event.sock) { + INIT_LIST_HEAD(&wm_event.evtq); + INIT_LIST_HEAD(&wm_event.freeq); + INIT_WORK(&wm_event.ws, __gdm_wimax_event_send); + spin_lock_init(&wm_event.evt_lock); + } + } + + if (wm_event.sock) { + wm_event.ref_cnt++; return 0; } diff --git a/drivers/staging/gdm72xx/usb_boot.c b/drivers/staging/gdm72xx/usb_boot.c index e3dbd5a552ca..0787188728aa 100644 --- a/drivers/staging/gdm72xx/usb_boot.c +++ b/drivers/staging/gdm72xx/usb_boot.c @@ -18,25 +18,22 @@ #include <linux/usb.h> #include <linux/unistd.h> #include <linux/slab.h> +#include <linux/firmware.h> #include <asm/byteorder.h> #include "gdm_usb.h" #include "usb_boot.h" -#define DN_KERNEL_MAGIC_NUMBER 0x10760001 -#define DN_ROOTFS_MAGIC_NUMBER 0x10760002 +#define DN_KERNEL_MAGIC_NUMBER 0x10760001 +#define DN_ROOTFS_MAGIC_NUMBER 0x10760002 -#define DOWNLOAD_SIZE 1024 - -#define DH2B(x) __cpu_to_be32(x) -#define DL2H(x) __le32_to_cpu(x) - -#define MIN(a, b) ((a) > (b) ? (b) : (a)) +#define DOWNLOAD_SIZE 1024 #define MAX_IMG_CNT 16 -#define UIMG_PATH "/lib/firmware/gdm72xx/gdmuimg.bin" -#define KERN_PATH "/lib/firmware/gdm72xx/zImage" -#define FS_PATH "/lib/firmware/gdm72xx/ramdisk.jffs2" +#define FW_DIR "gdm72xx/" +#define FW_UIMG "gdmuimg.bin" +#define FW_KERN "zImage" +#define FW_FS "ramdisk.jffs2" struct dn_header { u32 magic_num; @@ -44,23 +41,23 @@ struct dn_header { }; struct img_header { - u32 magic_code; - u32 count; - u32 len; - u32 offset[MAX_IMG_CNT]; + u32 magic_code; + u32 count; + u32 len; + u32 offset[MAX_IMG_CNT]; char hostname[32]; char date[32]; }; struct fw_info { - u32 id; - u32 len; - u32 kernel_len; - u32 rootfs_len; - u32 kernel_offset; - u32 rootfs_offset; - u32 fw_ver; - u32 mac_ver; + u32 id; + u32 len; + u32 kernel_len; + u32 rootfs_len; + u32 kernel_offset; + u32 rootfs_offset; + u32 fw_ver; + u32 mac_ver; char hostname[32]; char userid[16]; char date[32]; @@ -71,7 +68,7 @@ static void array_le32_to_cpu(u32 *arr, int num) { int i; for (i = 0; i < num; i++, arr++) - *arr = DL2H(*arr); + *arr = __le32_to_cpu(*arr); } static u8 *tx_buf; @@ -107,44 +104,37 @@ static int gdm_wibro_recv(struct usb_device *usbdev, void *data, int len) return 0; } -static int download_image(struct usb_device *usbdev, struct file *filp, - loff_t *pos, u32 img_len, u32 magic_num) +static int download_image(struct usb_device *usbdev, + const struct firmware *firm, + loff_t pos, u32 img_len, u32 magic_num) { struct dn_header h; int ret = 0; u32 size; - int len, readn; - size = (img_len + DOWNLOAD_SIZE - 1) & ~(DOWNLOAD_SIZE - 1); - h.magic_num = DH2B(magic_num); - h.file_size = DH2B(size); + size = ALIGN(img_len, DOWNLOAD_SIZE); + h.magic_num = __cpu_to_be32(magic_num); + h.file_size = __cpu_to_be32(size); ret = gdm_wibro_send(usbdev, &h, sizeof(h)); if (ret < 0) - goto out; + return ret; - readn = 0; - while ((len = filp->f_op->read(filp, tx_buf, DOWNLOAD_SIZE, pos))) { + while (img_len > 0) { + if (img_len > DOWNLOAD_SIZE) + size = DOWNLOAD_SIZE; + else + size = img_len; /* the last chunk of data */ - if (len < 0) { - ret = -1; - goto out; - } - readn += len; + memcpy(tx_buf, firm->data + pos, size); + ret = gdm_wibro_send(usbdev, tx_buf, size); - ret = gdm_wibro_send(usbdev, tx_buf, DOWNLOAD_SIZE); if (ret < 0) - goto out; - if (readn >= img_len) - break; - } + return ret; - if (readn < img_len) { - printk(KERN_ERR "gdmwm: Cannot read to the requested size. " - "Read = %d Requested = %d\n", readn, img_len); - ret = -EIO; + img_len -= size; + pos += size; } -out: return ret; } @@ -152,14 +142,19 @@ out: int usb_boot(struct usb_device *usbdev, u16 pid) { int i, ret = 0; - struct file *filp = NULL; - struct inode *inode = NULL; - static mm_segment_t fs; struct img_header hdr; struct fw_info fw_info; loff_t pos = 0; - char *img_name = UIMG_PATH; - int len; + char *img_name = FW_DIR FW_UIMG; + const struct firmware *firm; + + ret = request_firmware(&firm, img_name, &usbdev->dev); + if (ret < 0) { + printk(KERN_ERR + "requesting firmware %s failed with error %d\n", + img_name, ret); + return ret; + } tx_buf = kmalloc(DOWNLOAD_SIZE, GFP_KERNEL); if (tx_buf == NULL) { @@ -167,29 +162,12 @@ int usb_boot(struct usb_device *usbdev, u16 pid) return -ENOMEM; } - fs = get_fs(); - set_fs(get_ds()); - - filp = filp_open(img_name, O_RDONLY | O_LARGEFILE, 0); - if (IS_ERR(filp)) { - printk(KERN_ERR "Can't find %s.\n", img_name); - ret = PTR_ERR(filp); - goto restore_fs; - } - - inode = filp->f_dentry->d_inode; - if (!S_ISREG(inode->i_mode)) { - printk(KERN_ERR "Invalid file type: %s\n", img_name); - ret = -EINVAL; - goto out; - } - - len = filp->f_op->read(filp, (u8 *)&hdr, sizeof(hdr), &pos); - if (len != sizeof(hdr)) { + if (firm->size < sizeof(hdr)) { printk(KERN_ERR "gdmwm: Cannot read the image info.\n"); ret = -EIO; goto out; } + memcpy(&hdr, firm->data, sizeof(hdr)); array_le32_to_cpu((u32 *)&hdr, 19); #if 0 @@ -217,13 +195,12 @@ int usb_boot(struct usb_device *usbdev, u16 pid) } pos = hdr.offset[i]; - len = filp->f_op->read(filp, (u8 *)&fw_info, sizeof(fw_info), - &pos); - if (len != sizeof(fw_info)) { + if (firm->size < sizeof(fw_info) + pos) { printk(KERN_ERR "gdmwm: Cannot read the FW info.\n"); ret = -EIO; goto out; } + memcpy(&fw_info, firm->data + pos, sizeof(fw_info)); array_le32_to_cpu((u32 *)&fw_info, 8); #if 0 @@ -239,14 +216,23 @@ int usb_boot(struct usb_device *usbdev, u16 pid) continue; pos = hdr.offset[i] + fw_info.kernel_offset; - ret = download_image(usbdev, filp, &pos, fw_info.kernel_len, - DN_KERNEL_MAGIC_NUMBER); + if (firm->size < fw_info.kernel_len + pos) { + printk(KERN_ERR "gdmwm: Kernel FW is too small.\n"); + goto out; + } + + ret = download_image(usbdev, firm, pos, + fw_info.kernel_len, DN_KERNEL_MAGIC_NUMBER); if (ret < 0) goto out; printk(KERN_INFO "GCT: Kernel download success.\n"); pos = hdr.offset[i] + fw_info.rootfs_offset; - ret = download_image(usbdev, filp, &pos, fw_info.rootfs_len, + if (firm->size < fw_info.rootfs_len + pos) { + printk(KERN_ERR "gdmwm: Filesystem FW is too small.\n"); + goto out; + } + ret = download_image(usbdev, firm, pos, fw_info.rootfs_len, DN_ROOTFS_MAGIC_NUMBER); if (ret < 0) goto out; @@ -260,10 +246,7 @@ int usb_boot(struct usb_device *usbdev, u16 pid) ret = -EINVAL; } out: - filp_close(filp, NULL); - -restore_fs: - set_fs(fs); + release_firmware(firm); kfree(tx_buf); return ret; } @@ -293,38 +276,27 @@ out: return ret; } -static int em_download_image(struct usb_device *usbdev, char *path, +static int em_download_image(struct usb_device *usbdev, const char *img_name, char *type_string) { - struct file *filp; - struct inode *inode; - static mm_segment_t fs; char *buf = NULL; loff_t pos = 0; int ret = 0; - int len, readn = 0; + int len; + int img_len; + const struct firmware *firm; #if defined(GDM7205_PADDING) const int pad_size = GDM7205_PADDING; #else const int pad_size = 0; #endif - fs = get_fs(); - set_fs(get_ds()); - - filp = filp_open(path, O_RDONLY | O_LARGEFILE, 0); - if (IS_ERR(filp)) { - printk(KERN_ERR "Can't find %s.\n", path); - set_fs(fs); - ret = -ENOENT; - goto restore_fs; - } - - inode = filp->f_dentry->d_inode; - if (!S_ISREG(inode->i_mode)) { - printk(KERN_ERR "Invalid file type: %s\n", path); - ret = -EINVAL; - goto out; + ret = request_firmware(&firm, img_name, &usbdev->dev); + if (ret < 0) { + printk(KERN_ERR + "requesting firmware %s failed with error %d\n", + img_name, ret); + return ret; } buf = kmalloc(DOWNLOAD_CHUCK + pad_size, GFP_KERNEL); @@ -338,18 +310,28 @@ static int em_download_image(struct usb_device *usbdev, char *path, if (ret < 0) goto out; - while ((len = filp->f_op->read(filp, buf+pad_size, DOWNLOAD_CHUCK, - &pos))) { - if (len < 0) { - ret = -1; - goto out; - } - readn += len; + img_len = firm->size; + + if (img_len <= 0) { + ret = -1; + goto out; + } + while (img_len > 0) { + if (img_len > DOWNLOAD_CHUCK) + len = DOWNLOAD_CHUCK; + else + len = img_len; /* the last chunk of data */ + + memcpy(buf+pad_size, firm->data + pos, len); ret = gdm_wibro_send(usbdev, buf, len+pad_size); + if (ret < 0) goto out; + img_len -= DOWNLOAD_CHUCK; + pos += DOWNLOAD_CHUCK; + ret = em_wait_ack(usbdev, ((len+pad_size) % 512 == 0)); if (ret < 0) goto out; @@ -360,11 +342,7 @@ static int em_download_image(struct usb_device *usbdev, char *path, goto out; out: - filp_close(filp, NULL); - -restore_fs: - set_fs(fs); - + release_firmware(firm); kfree(buf); return ret; @@ -382,18 +360,20 @@ static int em_fw_reset(struct usb_device *usbdev) int usb_emergency(struct usb_device *usbdev) { int ret; + const char *kern_name = FW_DIR FW_KERN; + const char *fs_name = FW_DIR FW_FS; - ret = em_download_image(usbdev, KERN_PATH, KERNEL_TYPE_STRING); + ret = em_download_image(usbdev, kern_name, KERNEL_TYPE_STRING); if (ret < 0) - goto out; + return ret; printk(KERN_INFO "GCT Emergency: Kernel download success.\n"); - ret = em_download_image(usbdev, FS_PATH, FS_TYPE_STRING); + ret = em_download_image(usbdev, fs_name, FS_TYPE_STRING); if (ret < 0) - goto out; + return ret; printk(KERN_INFO "GCT Emergency: Filesystem download success.\n"); ret = em_fw_reset(usbdev); -out: + return ret; } diff --git a/drivers/staging/iio/Documentation/generic_buffer.c b/drivers/staging/iio/Documentation/generic_buffer.c index 827e92de8e30..40d0ecac047f 100644 --- a/drivers/staging/iio/Documentation/generic_buffer.c +++ b/drivers/staging/iio/Documentation/generic_buffer.c @@ -104,6 +104,16 @@ void process_scan(char *data, print2byte(*(uint16_t *)(data + channels[k].location), &channels[k]); break; + case 4: + if (!channels[k].is_signed) { + uint32_t val = *(uint32_t *) + (data + channels[k].location); + printf("%05f ", ((float)val + + channels[k].offset)* + channels[k].scale); + + } + break; case 8: if (channels[k].is_signed) { int64_t val = *(int64_t *) diff --git a/drivers/staging/iio/Documentation/inkernel.txt b/drivers/staging/iio/Documentation/inkernel.txt index a05823e955d2..ab528409bba6 100644 --- a/drivers/staging/iio/Documentation/inkernel.txt +++ b/drivers/staging/iio/Documentation/inkernel.txt @@ -48,11 +48,11 @@ There are then a number of functions that can be used to get information about this channel such as it's current reading. e.g. -iio_st_read_channel_raw() - get a reading -iio_st_read_channel_type() - get the type of channel +iio_read_channel_raw() - get a reading +iio_get_channel_type() - get the type of channel There is also provision for retrieving all of the channels associated with a given consumer. This is useful for generic drivers such as iio_hwmon where the number and naming of channels is not known by the -consumer driver. To do this, use iio_st_channel_get_all. +consumer driver. To do this, use iio_channel_get_all. diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig index 04cd6ec1f70f..ca56c75a35fc 100644 --- a/drivers/staging/iio/Kconfig +++ b/drivers/staging/iio/Kconfig @@ -1,5 +1,5 @@ # -# Industrial I/O subsytem configuration +# Industrial I/O subsystem configuration # menu "IIO staging drivers" depends on IIO diff --git a/drivers/staging/iio/TODO b/drivers/staging/iio/TODO index cf3f9489b9da..04c23262f8e2 100644 --- a/drivers/staging/iio/TODO +++ b/drivers/staging/iio/TODO @@ -69,5 +69,5 @@ Documentation 1) Lots of cleanup and expansion. 2) Some device require individual docs. -Contact: Jonathan Cameron <jic23@cam.ac.uk>. +Contact: Jonathan Cameron <jic23@kernel.org>. Mailing list: linux-iio@vger.kernel.org diff --git a/drivers/staging/iio/accel/adis16201_core.c b/drivers/staging/iio/accel/adis16201_core.c index 204106b72d24..8e37d6e04277 100644 --- a/drivers/staging/iio/accel/adis16201_core.c +++ b/drivers/staging/iio/accel/adis16201_core.c @@ -390,7 +390,7 @@ static int adis16201_write_raw(struct iio_dev *indio_dev, return -EINVAL; } -static struct iio_chan_spec adis16201_channels[] = { +static const struct iio_chan_spec adis16201_channels[] = { { .type = IIO_VOLTAGE, .indexed = 1, @@ -565,7 +565,7 @@ error_ret: return ret; } -static int adis16201_remove(struct spi_device *spi) +static int __devexit adis16201_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); diff --git a/drivers/staging/iio/accel/adis16201_ring.c b/drivers/staging/iio/accel/adis16201_ring.c index 03fcf6e319db..97c09f0c26ae 100644 --- a/drivers/staging/iio/accel/adis16201_ring.c +++ b/drivers/staging/iio/accel/adis16201_ring.c @@ -62,7 +62,6 @@ static irqreturn_t adis16201_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct adis16201_state *st = iio_priv(indio_dev); - struct iio_buffer *ring = indio_dev->buffer; int i = 0; s16 *data; @@ -83,7 +82,7 @@ static irqreturn_t adis16201_trigger_handler(int irq, void *p) if (indio_dev->scan_timestamp) *((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp; - ring->access->store_to(ring, (u8 *)data, pf->timestamp); + iio_push_to_buffer(indio_dev->buffer, (u8 *)data); kfree(data); done: diff --git a/drivers/staging/iio/accel/adis16203_core.c b/drivers/staging/iio/accel/adis16203_core.c index 22085e9dfd16..002fa9dfc375 100644 --- a/drivers/staging/iio/accel/adis16203_core.c +++ b/drivers/staging/iio/accel/adis16203_core.c @@ -355,7 +355,7 @@ static int adis16203_read_raw(struct iio_dev *indio_dev, } } -static struct iio_chan_spec adis16203_channels[] = { +static const struct iio_chan_spec adis16203_channels[] = { { .type = IIO_VOLTAGE, .indexed = 1, @@ -500,7 +500,7 @@ error_ret: return ret; } -static int adis16203_remove(struct spi_device *spi) +static int __devexit adis16203_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); diff --git a/drivers/staging/iio/accel/adis16203_ring.c b/drivers/staging/iio/accel/adis16203_ring.c index c16b2b7323ac..7507e1a04591 100644 --- a/drivers/staging/iio/accel/adis16203_ring.c +++ b/drivers/staging/iio/accel/adis16203_ring.c @@ -61,7 +61,6 @@ static irqreturn_t adis16203_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct adis16203_state *st = iio_priv(indio_dev); - struct iio_buffer *ring = indio_dev->buffer; int i = 0; s16 *data; @@ -82,9 +81,7 @@ static irqreturn_t adis16203_trigger_handler(int irq, void *p) if (indio_dev->scan_timestamp) *((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp; - ring->access->store_to(ring, - (u8 *)data, - pf->timestamp); + iio_push_to_buffer(indio_dev->buffer, (u8 *)data); kfree(data); done: diff --git a/drivers/staging/iio/accel/adis16204_core.c b/drivers/staging/iio/accel/adis16204_core.c index 5f2e5f11c543..05bdb7c2c8e3 100644 --- a/drivers/staging/iio/accel/adis16204_core.c +++ b/drivers/staging/iio/accel/adis16204_core.c @@ -397,7 +397,7 @@ static int adis16204_write_raw(struct iio_dev *indio_dev, return -EINVAL; } -static struct iio_chan_spec adis16204_channels[] = { +static const struct iio_chan_spec adis16204_channels[] = { { .type = IIO_VOLTAGE, .indexed = 1, /* Note was not previously indexed */ @@ -558,7 +558,7 @@ error_ret: return ret; } -static int adis16204_remove(struct spi_device *spi) +static int __devexit adis16204_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); diff --git a/drivers/staging/iio/accel/adis16204_ring.c b/drivers/staging/iio/accel/adis16204_ring.c index 1d2b31cc849e..4c976bec986b 100644 --- a/drivers/staging/iio/accel/adis16204_ring.c +++ b/drivers/staging/iio/accel/adis16204_ring.c @@ -59,7 +59,6 @@ static irqreturn_t adis16204_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct adis16204_state *st = iio_priv(indio_dev); - struct iio_buffer *ring = indio_dev->buffer; int i = 0; s16 *data; @@ -79,7 +78,7 @@ static irqreturn_t adis16204_trigger_handler(int irq, void *p) if (indio_dev->scan_timestamp) *((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp; - ring->access->store_to(ring, (u8 *)data, pf->timestamp); + iio_push_to_buffer(indio_dev->buffer, (u8 *)data); kfree(data); done: diff --git a/drivers/staging/iio/accel/adis16209_core.c b/drivers/staging/iio/accel/adis16209_core.c index 494570508c36..b7333bfe0b2f 100644 --- a/drivers/staging/iio/accel/adis16209_core.c +++ b/drivers/staging/iio/accel/adis16209_core.c @@ -390,7 +390,7 @@ static int adis16209_read_raw(struct iio_dev *indio_dev, return -EINVAL; } -static struct iio_chan_spec adis16209_channels[] = { +static const struct iio_chan_spec adis16209_channels[] = { { .type = IIO_VOLTAGE, .indexed = 1, @@ -573,7 +573,7 @@ error_ret: return ret; } -static int adis16209_remove(struct spi_device *spi) +static int __devexit adis16209_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); diff --git a/drivers/staging/iio/accel/adis16209_ring.c b/drivers/staging/iio/accel/adis16209_ring.c index 1a4a55c27c7c..f939e29d6c82 100644 --- a/drivers/staging/iio/accel/adis16209_ring.c +++ b/drivers/staging/iio/accel/adis16209_ring.c @@ -59,7 +59,6 @@ static irqreturn_t adis16209_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct adis16209_state *st = iio_priv(indio_dev); - struct iio_buffer *ring = indio_dev->buffer; int i = 0; s16 *data; @@ -79,7 +78,7 @@ static irqreturn_t adis16209_trigger_handler(int irq, void *p) if (indio_dev->scan_timestamp) *((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp; - ring->access->store_to(ring, (u8 *)data, pf->timestamp); + iio_push_to_buffer(indio_dev->buffer, (u8 *)data); kfree(data); done: diff --git a/drivers/staging/iio/accel/adis16220_core.c b/drivers/staging/iio/accel/adis16220_core.c index 575f1af25d5d..c755089c7117 100644 --- a/drivers/staging/iio/accel/adis16220_core.c +++ b/drivers/staging/iio/accel/adis16220_core.c @@ -372,8 +372,7 @@ static ssize_t adis16220_accel_bin_read(struct file *filp, struct kobject *kobj, loff_t off, size_t count) { - struct device *dev = container_of(kobj, struct device, kobj); - struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(kobj_to_dev(kobj)); return adis16220_capture_buffer_read(indio_dev, buf, off, count, @@ -394,8 +393,7 @@ static ssize_t adis16220_adc1_bin_read(struct file *filp, struct kobject *kobj, char *buf, loff_t off, size_t count) { - struct device *dev = container_of(kobj, struct device, kobj); - struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(kobj_to_dev(kobj)); return adis16220_capture_buffer_read(indio_dev, buf, off, count, @@ -416,8 +414,7 @@ static ssize_t adis16220_adc2_bin_read(struct file *filp, struct kobject *kobj, char *buf, loff_t off, size_t count) { - struct device *dev = container_of(kobj, struct device, kobj); - struct iio_dev *indio_dev = dev_to_iio_dev(dev); + struct iio_dev *indio_dev = dev_to_iio_dev(kobj_to_dev(kobj)); return adis16220_capture_buffer_read(indio_dev, buf, off, count, @@ -666,7 +663,7 @@ error_ret: return ret; } -static int adis16220_remove(struct spi_device *spi) +static int __devexit adis16220_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); diff --git a/drivers/staging/iio/accel/adis16240_core.c b/drivers/staging/iio/accel/adis16240_core.c index b30b7874ffb0..0fc26a49d681 100644 --- a/drivers/staging/iio/accel/adis16240_core.c +++ b/drivers/staging/iio/accel/adis16240_core.c @@ -448,7 +448,7 @@ static int adis16240_write_raw(struct iio_dev *indio_dev, return -EINVAL; } -static struct iio_chan_spec adis16240_channels[] = { +static const struct iio_chan_spec adis16240_channels[] = { { .type = IIO_VOLTAGE, .indexed = 1, @@ -619,7 +619,7 @@ error_ret: return ret; } -static int adis16240_remove(struct spi_device *spi) +static int __devexit adis16240_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); diff --git a/drivers/staging/iio/accel/adis16240_ring.c b/drivers/staging/iio/accel/adis16240_ring.c index 360dfed6d4d1..caff8e25e0a2 100644 --- a/drivers/staging/iio/accel/adis16240_ring.c +++ b/drivers/staging/iio/accel/adis16240_ring.c @@ -56,7 +56,6 @@ static irqreturn_t adis16240_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct adis16240_state *st = iio_priv(indio_dev); - struct iio_buffer *ring = indio_dev->buffer; int i = 0; s16 *data; @@ -77,7 +76,7 @@ static irqreturn_t adis16240_trigger_handler(int irq, void *p) if (indio_dev->scan_timestamp) *((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp; - ring->access->store_to(ring, (u8 *)data, pf->timestamp); + iio_push_to_buffer(indio_dev->buffer, (u8 *)data); kfree(data); done: diff --git a/drivers/staging/iio/accel/kxsd9.c b/drivers/staging/iio/accel/kxsd9.c index 8cf7cd943c90..fdd5fbded660 100644 --- a/drivers/staging/iio/accel/kxsd9.c +++ b/drivers/staging/iio/accel/kxsd9.c @@ -2,7 +2,7 @@ * kxsd9.c simple support for the Kionix KXSD9 3D * accelerometer. * - * Copyright (c) 2008-2009 Jonathan Cameron <jic23@cam.ac.uk> + * Copyright (c) 2008-2009 Jonathan Cameron <jic23@kernel.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -186,7 +186,7 @@ error_ret: .address = KXSD9_REG_##axis, \ } -static struct iio_chan_spec kxsd9_channels[] = { +static const struct iio_chan_spec kxsd9_channels[] = { KXSD9_ACCEL_CHAN(X), KXSD9_ACCEL_CHAN(Y), KXSD9_ACCEL_CHAN(Z), { .type = IIO_VOLTAGE, @@ -286,6 +286,6 @@ static struct spi_driver kxsd9_driver = { }; module_spi_driver(kxsd9_driver); -MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>"); +MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); MODULE_DESCRIPTION("Kionix KXSD9 SPI driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/accel/lis3l02dq.h b/drivers/staging/iio/accel/lis3l02dq.h index ae5f225b4bb2..f9bcd41f7188 100644 --- a/drivers/staging/iio/accel/lis3l02dq.h +++ b/drivers/staging/iio/accel/lis3l02dq.h @@ -2,7 +2,7 @@ * LISL02DQ.h -- support STMicroelectronics LISD02DQ * 3d 2g Linear Accelerometers via SPI * - * Copyright (c) 2007 Jonathan Cameron <jic23@cam.ac.uk> + * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org> * * Loosely based upon tle62x0.c * @@ -28,7 +28,7 @@ /* Control Register (1 of 2) */ #define LIS3L02DQ_REG_CTRL_1_ADDR 0x20 /* Power ctrl - either bit set corresponds to on*/ -#define LIS3L02DQ_REG_CTRL_1_PD_ON 0xC0 +#define LIS3L02DQ_REG_CTRL_1_PD_ON 0xC0 /* Decimation Factor */ #define LIS3L02DQ_DEC_MASK 0x30 @@ -73,14 +73,14 @@ /* Interrupt related stuff */ #define LIS3L02DQ_REG_WAKE_UP_CFG_ADDR 0x23 -/* Switch from or combination fo conditions to and */ +/* Switch from or combination of conditions to and */ #define LIS3L02DQ_REG_WAKE_UP_CFG_BOOLEAN_AND 0x80 /* Latch interrupt request, * if on ack must be given by reading the ack register */ #define LIS3L02DQ_REG_WAKE_UP_CFG_LATCH_SRC 0x40 -/* Z Interrupt on High (above threshold)*/ +/* Z Interrupt on High (above threshold) */ #define LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_Z_HIGH 0x20 /* Z Interrupt on Low */ #define LIS3L02DQ_REG_WAKE_UP_CFG_INTERRUPT_Z_LOW 0x10 @@ -117,13 +117,13 @@ #define LIS3L02DQ_REG_STATUS_Y_OVERRUN 0x20 #define LIS3L02DQ_REG_STATUS_X_OVERRUN 0x10 /* XYZ new data available - first is all 3 available? */ -#define LIS3L02DQ_REG_STATUS_XYZ_NEW_DATA 0x08 +#define LIS3L02DQ_REG_STATUS_XYZ_NEW_DATA 0x08 #define LIS3L02DQ_REG_STATUS_Z_NEW_DATA 0x04 #define LIS3L02DQ_REG_STATUS_Y_NEW_DATA 0x02 #define LIS3L02DQ_REG_STATUS_X_NEW_DATA 0x01 /* The accelerometer readings - low and high bytes. -Form of high byte dependent on justification set in ctrl reg */ + * Form of high byte dependent on justification set in ctrl reg */ #define LIS3L02DQ_REG_OUT_X_L_ADDR 0x28 #define LIS3L02DQ_REG_OUT_X_H_ADDR 0x29 #define LIS3L02DQ_REG_OUT_Y_L_ADDR 0x2A @@ -150,9 +150,9 @@ Form of high byte dependent on justification set in ctrl reg */ * struct lis3l02dq_state - device instance specific data * @us: actual spi_device * @trig: data ready trigger registered with iio + * @buf_lock: mutex to protect tx and rx * @tx: transmit buffer * @rx: receive buffer - * @buf_lock: mutex to protect tx and rx **/ struct lis3l02dq_state { struct spi_device *us; diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c index 9d263484fb86..21b0469f8bc2 100644 --- a/drivers/staging/iio/accel/lis3l02dq_core.c +++ b/drivers/staging/iio/accel/lis3l02dq_core.c @@ -2,7 +2,7 @@ * lis3l02dq.c support STMicroelectronics LISD02DQ * 3d 2g Linear Accelerometers via SPI * - * Copyright (c) 2007 Jonathan Cameron <jic23@cam.ac.uk> + * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -392,7 +392,7 @@ static int lis3l02dq_initial_setup(struct iio_dev *indio_dev) dev_err(&st->us->dev, "problem with setup control register 1"); goto err_ret; } - /* Repeat as sometimes doesn't work first time?*/ + /* Repeat as sometimes doesn't work first time? */ ret = lis3l02dq_spi_write_reg_8(indio_dev, LIS3L02DQ_REG_CTRL_1_ADDR, val); @@ -538,7 +538,7 @@ static irqreturn_t lis3l02dq_event_handler(int irq, void *private) .event_mask = LIS3L02DQ_EVENT_MASK, \ } -static struct iio_chan_spec lis3l02dq_channels[] = { +static const struct iio_chan_spec lis3l02dq_channels[] = { LIS3L02DQ_CHAN(0, IIO_MOD_X), LIS3L02DQ_CHAN(1, IIO_MOD_Y), LIS3L02DQ_CHAN(2, IIO_MOD_Z), @@ -686,7 +686,7 @@ static int __devinit lis3l02dq_probe(struct spi_device *spi) goto error_ret; } st = iio_priv(indio_dev); - /* this is only used tor removal purposes */ + /* this is only used for removal purposes */ spi_set_drvdata(spi, indio_dev); st->us = spi; @@ -780,21 +780,15 @@ err_ret: } /* fixme, confirm ordering in this function */ -static int lis3l02dq_remove(struct spi_device *spi) +static int __devexit lis3l02dq_remove(struct spi_device *spi) { - int ret; struct iio_dev *indio_dev = spi_get_drvdata(spi); struct lis3l02dq_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); - ret = lis3l02dq_disable_all_events(indio_dev); - if (ret) - goto err_ret; - - ret = lis3l02dq_stop_device(indio_dev); - if (ret) - goto err_ret; + lis3l02dq_disable_all_events(indio_dev); + lis3l02dq_stop_device(indio_dev); if (spi->irq && gpio_is_valid(irq_to_gpio(spi->irq)) > 0) free_irq(st->us->irq, indio_dev); @@ -804,8 +798,8 @@ static int lis3l02dq_remove(struct spi_device *spi) lis3l02dq_unconfigure_buffer(indio_dev); iio_device_free(indio_dev); -err_ret: - return ret; + + return 0; } static struct spi_driver lis3l02dq_driver = { @@ -818,7 +812,7 @@ static struct spi_driver lis3l02dq_driver = { }; module_spi_driver(lis3l02dq_driver); -MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>"); +MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); MODULE_DESCRIPTION("ST LIS3L02DQ Accelerometer SPI driver"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("spi:lis3l02dq"); diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c index f3da59063ed2..fa4190d96247 100644 --- a/drivers/staging/iio/accel/lis3l02dq_ring.c +++ b/drivers/staging/iio/accel/lis3l02dq_ring.c @@ -14,7 +14,7 @@ #include "lis3l02dq.h" /** - * combine_8_to_16() utility function to munge to u8s into u16 + * combine_8_to_16() utility function to munge two u8s into u16 **/ static inline u16 combine_8_to_16(u8 lower, u8 upper) { @@ -49,7 +49,7 @@ static const u8 read_all_tx_array[] = { /** * lis3l02dq_read_all() Reads all channels currently selected - * @st: device specific state + * @indio_dev: IIO device state * @rx_array: (dma capable) receive array, must be at least * 4*number of channels **/ @@ -137,7 +137,6 @@ static irqreturn_t lis3l02dq_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; - struct iio_buffer *buffer = indio_dev->buffer; int len = 0; char *data; @@ -155,7 +154,7 @@ static irqreturn_t lis3l02dq_trigger_handler(int irq, void *p) if (indio_dev->scan_timestamp) *(s64 *)((u8 *)data + ALIGN(len, sizeof(s64))) = pf->timestamp; - buffer->access->store_to(buffer, (u8 *)data, pf->timestamp); + iio_push_to_buffer(indio_dev->buffer, (u8 *)data); kfree(data); done: @@ -172,22 +171,22 @@ __lis3l02dq_write_data_ready_config(struct iio_dev *indio_dev, bool state) bool currentlyset; struct lis3l02dq_state *st = iio_priv(indio_dev); -/* Get the current event mask register */ + /* Get the current event mask register */ ret = lis3l02dq_spi_read_reg_8(indio_dev, LIS3L02DQ_REG_CTRL_2_ADDR, &valold); if (ret) goto error_ret; -/* Find out if data ready is already on */ + /* Find out if data ready is already on */ currentlyset = valold & LIS3L02DQ_REG_CTRL_2_ENABLE_DATA_READY_GENERATION; -/* Disable requested */ + /* Disable requested */ if (!state && currentlyset) { - /* disable the data ready signal */ + /* Disable the data ready signal */ valold &= ~LIS3L02DQ_REG_CTRL_2_ENABLE_DATA_READY_GENERATION; - /* The double write is to overcome a hardware bug?*/ + /* The double write is to overcome a hardware bug? */ ret = lis3l02dq_spi_write_reg_8(indio_dev, LIS3L02DQ_REG_CTRL_2_ADDR, valold); @@ -199,10 +198,10 @@ __lis3l02dq_write_data_ready_config(struct iio_dev *indio_dev, bool state) if (ret) goto error_ret; st->trigger_on = false; -/* Enable requested */ + /* Enable requested */ } else if (state && !currentlyset) { - /* if not set, enable requested */ - /* first disable all events */ + /* If not set, enable requested + * first disable all events */ ret = lis3l02dq_disable_all_events(indio_dev); if (ret < 0) goto error_ret; @@ -241,7 +240,7 @@ static int lis3l02dq_data_rdy_trigger_set_state(struct iio_trigger *trig, if (state == false) { /* * A possible quirk with the handler is currently worked around - * by ensuring outstanding read events are cleared. + * by ensuring outstanding read events are cleared. */ ret = lis3l02dq_read_all(indio_dev, NULL); } @@ -252,7 +251,7 @@ static int lis3l02dq_data_rdy_trigger_set_state(struct iio_trigger *trig, } /** - * lis3l02dq_trig_try_reen() try renabling irq for data rdy trigger + * lis3l02dq_trig_try_reen() try reenabling irq for data rdy trigger * @trig: the datardy trigger */ static int lis3l02dq_trig_try_reen(struct iio_trigger *trig) @@ -261,8 +260,8 @@ static int lis3l02dq_trig_try_reen(struct iio_trigger *trig) struct lis3l02dq_state *st = iio_priv(indio_dev); int i; - /* If gpio still high (or high again) */ - /* In theory possible we will need to do this several times */ + /* If gpio still high (or high again) + * In theory possible we will need to do this several times */ for (i = 0; i < 5; i++) if (gpio_get_value(irq_to_gpio(st->us->irq))) lis3l02dq_read_all(indio_dev, NULL); diff --git a/drivers/staging/iio/accel/sca3000.h b/drivers/staging/iio/accel/sca3000.h index 131daac90012..c1016c510dae 100644 --- a/drivers/staging/iio/accel/sca3000.h +++ b/drivers/staging/iio/accel/sca3000.h @@ -2,7 +2,7 @@ * sca3000.c -- support VTI sca3000 series accelerometers * via SPI * - * Copyright (c) 2007 Jonathan Cameron <jic23@cam.ac.uk> + * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org> * * Partly based upon tle62x0.c * diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c index c218d71abf1f..ffd1697a9db0 100644 --- a/drivers/staging/iio/accel/sca3000_core.c +++ b/drivers/staging/iio/accel/sca3000_core.c @@ -5,7 +5,7 @@ * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. * - * Copyright (c) 2009 Jonathan Cameron <jic23@cam.ac.uk> + * Copyright (c) 2009 Jonathan Cameron <jic23@kernel.org> * * See industrialio/accels/sca3000.h for comments. */ @@ -450,7 +450,7 @@ static IIO_DEVICE_ATTR(revision, S_IRUGO, sca3000_show_rev, NULL, 0); .event_mask = SCA3000_EVENT_MASK, \ } -static struct iio_chan_spec sca3000_channels[] = { +static const struct iio_chan_spec sca3000_channels[] = { SCA3000_CHAN(0, IIO_MOD_X), SCA3000_CHAN(1, IIO_MOD_Y), SCA3000_CHAN(2, IIO_MOD_Z), @@ -1233,15 +1233,13 @@ error_ret: return ret; } -static int sca3000_remove(struct spi_device *spi) +static int __devexit sca3000_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct sca3000_state *st = iio_priv(indio_dev); - int ret; + /* Must ensure no interrupts can be generated after this!*/ - ret = sca3000_stop_all_interrupts(st); - if (ret) - return ret; + sca3000_stop_all_interrupts(st); if (spi->irq) free_irq(spi->irq, indio_dev); iio_device_unregister(indio_dev); @@ -1272,6 +1270,6 @@ static struct spi_driver sca3000_driver = { }; module_spi_driver(sca3000_driver); -MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>"); +MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); MODULE_DESCRIPTION("VTI SCA3000 Series Accelerometers SPI driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c index b7e1a002630a..cbec2f1665e5 100644 --- a/drivers/staging/iio/accel/sca3000_ring.c +++ b/drivers/staging/iio/accel/sca3000_ring.c @@ -5,7 +5,7 @@ * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. * - * Copyright (c) 2009 Jonathan Cameron <jic23@cam.ac.uk> + * Copyright (c) 2009 Jonathan Cameron <jic23@kernel.org> * */ diff --git a/drivers/staging/iio/adc/Kconfig b/drivers/staging/iio/adc/Kconfig index 67711b7d718a..a525143ecbea 100644 --- a/drivers/staging/iio/adc/Kconfig +++ b/drivers/staging/iio/adc/Kconfig @@ -68,20 +68,6 @@ config AD799X_RING_BUFFER Say yes here to include ring buffer support in the AD799X ADC driver. -config AD7476 - tristate "Analog Devices AD7475/6/7/8 AD7466/7/8 and AD7495 ADC driver" - depends on SPI - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER - help - Say yes here to build support for Analog Devices - AD7475, AD7476, AD7477, AD7478, AD7466, AD7467, AD7468, AD7495 - SPI analog to digital converters (ADC). - If unsure, say N (but it's safe to say "Y"). - - To compile this driver as a module, choose M here: the - module will be called ad7476. - config AD7887 tristate "Analog Devices AD7887 ADC driver" depends on SPI @@ -96,11 +82,12 @@ config AD7887 module will be called ad7887. config AD7780 - tristate "Analog Devices AD7780 AD7781 ADC driver" + tristate "Analog Devices AD7780 and similar ADCs driver" depends on SPI depends on GPIOLIB + select AD_SIGMA_DELTA help - Say yes here to build support for Analog Devices + Say yes here to build support for Analog Devices AD7170, AD7171, AD7780 and AD7781 SPI analog to digital converters (ADC). If unsure, say N (but it's safe to say "Y"). @@ -108,13 +95,12 @@ config AD7780 module will be called ad7780. config AD7793 - tristate "Analog Devices AD7792 AD7793 ADC driver" + tristate "Analog Devices AD7793 and similar ADCs driver" depends on SPI - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER + select AD_SIGMA_DELTA help - Say yes here to build support for Analog Devices - AD7792 and AD7793 SPI analog to digital converters (ADC). + Say yes here to build support for Analog Devices AD7785, AD7792, AD7793, + AD7794 and AD7795 SPI analog to digital converters (ADC). If unsure, say N (but it's safe to say "Y"). To compile this driver as a module, choose M here: the @@ -131,8 +117,7 @@ config AD7816 config AD7192 tristate "Analog Devices AD7190 AD7192 AD7195 ADC driver" depends on SPI - select IIO_BUFFER - select IIO_TRIGGERED_BUFFER + select AD_SIGMA_DELTA help Say yes here to build support for Analog Devices AD7190, AD7192 or AD7195 SPI analog to digital converters (ADC). @@ -200,6 +185,18 @@ config LPC32XX_ADC activate only one via device tree selection. Provides direct access via sysfs. +config MXS_LRADC + tristate "Freescale i.MX28 LRADC" + depends on ARCH_MXS + select IIO_BUFFER + select IIO_TRIGGERED_BUFFER + help + Say yes here to build support for i.MX28 LRADC convertor + built into these chips. + + To compile this driver as a module, choose M here: the + module will be called mxs-lradc. + config SPEAR_ADC tristate "ST SPEAr ADC" depends on PLAT_SPEAR diff --git a/drivers/staging/iio/adc/Makefile b/drivers/staging/iio/adc/Makefile index 14e98b62b70a..62ee02e80cf9 100644 --- a/drivers/staging/iio/adc/Makefile +++ b/drivers/staging/iio/adc/Makefile @@ -17,10 +17,6 @@ ad799x-y := ad799x_core.o ad799x-$(CONFIG_AD799X_RING_BUFFER) += ad799x_ring.o obj-$(CONFIG_AD799X) += ad799x.o -ad7476-y := ad7476_core.o -ad7476-$(CONFIG_IIO_BUFFER) += ad7476_ring.o -obj-$(CONFIG_AD7476) += ad7476.o - ad7887-y := ad7887_core.o ad7887-$(CONFIG_IIO_BUFFER) += ad7887_ring.o obj-$(CONFIG_AD7887) += ad7887.o @@ -38,4 +34,5 @@ obj-$(CONFIG_ADT7310) += adt7310.o obj-$(CONFIG_ADT7410) += adt7410.o obj-$(CONFIG_AD7280) += ad7280a.o obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o +obj-$(CONFIG_MXS_LRADC) += mxs-lradc.o obj-$(CONFIG_SPEAR_ADC) += spear_adc.o diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c index 19a064d649e3..aeaa61d49f51 100644 --- a/drivers/staging/iio/adc/ad7192.c +++ b/drivers/staging/iio/adc/ad7192.c @@ -23,6 +23,7 @@ #include <linux/iio/trigger.h> #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> +#include <linux/iio/adc/ad_sigma_delta.h> #include "ad7192.h" @@ -57,6 +58,7 @@ /* Mode Register Bit Designations (AD7192_REG_MODE) */ #define AD7192_MODE_SEL(x) (((x) & 0x7) << 21) /* Operation Mode Select */ +#define AD7192_MODE_SEL_MASK (0x7 << 21) /* Operation Mode Select Mask */ #define AD7192_MODE_DAT_STA (1 << 20) /* Status Register transmission */ #define AD7192_MODE_CLKSRC(x) (((x) & 0x3) << 18) /* Clock Source Select */ #define AD7192_MODE_SINC3 (1 << 15) /* SINC3 Filter Select */ @@ -91,7 +93,8 @@ #define AD7192_CONF_CHOP (1 << 23) /* CHOP enable */ #define AD7192_CONF_REFSEL (1 << 20) /* REFIN1/REFIN2 Reference Select */ -#define AD7192_CONF_CHAN(x) (((x) & 0xFF) << 8) /* Channel select */ +#define AD7192_CONF_CHAN(x) (((1 << (x)) & 0xFF) << 8) /* Channel select */ +#define AD7192_CONF_CHAN_MASK (0xFF << 8) /* Channel select mask */ #define AD7192_CONF_BURN (1 << 7) /* Burnout current enable */ #define AD7192_CONF_REFDET (1 << 6) /* Reference detect enable */ #define AD7192_CONF_BUF (1 << 4) /* Buffered Mode Enable */ @@ -133,13 +136,7 @@ */ struct ad7192_state { - struct spi_device *spi; - struct iio_trigger *trig; struct regulator *reg; - struct ad7192_platform_data *pdata; - wait_queue_head_t wq_data_avail; - bool done; - bool irq_dis; u16 int_vref_mv; u32 mclk; u32 f_order; @@ -148,178 +145,45 @@ struct ad7192_state { u32 scale_avail[8][2]; u8 gpocon; u8 devid; - /* - * DMA (thus cache coherency maintenance) requires the - * transfer buffers to live in their own cache lines. - */ - u8 data[4] ____cacheline_aligned; -}; - -static int __ad7192_write_reg(struct ad7192_state *st, bool locked, - bool cs_change, unsigned char reg, - unsigned size, unsigned val) -{ - u8 *data = st->data; - struct spi_transfer t = { - .tx_buf = data, - .len = size + 1, - .cs_change = cs_change, - }; - struct spi_message m; - - data[0] = AD7192_COMM_WRITE | AD7192_COMM_ADDR(reg); - - switch (size) { - case 3: - data[1] = val >> 16; - data[2] = val >> 8; - data[3] = val; - break; - case 2: - data[1] = val >> 8; - data[2] = val; - break; - case 1: - data[1] = val; - break; - default: - return -EINVAL; - } - - spi_message_init(&m); - spi_message_add_tail(&t, &m); - if (locked) - return spi_sync_locked(st->spi, &m); - else - return spi_sync(st->spi, &m); -} + struct ad_sigma_delta sd; +}; -static int ad7192_write_reg(struct ad7192_state *st, - unsigned reg, unsigned size, unsigned val) +static struct ad7192_state *ad_sigma_delta_to_ad7192(struct ad_sigma_delta *sd) { - return __ad7192_write_reg(st, false, false, reg, size, val); + return container_of(sd, struct ad7192_state, sd); } -static int __ad7192_read_reg(struct ad7192_state *st, bool locked, - bool cs_change, unsigned char reg, - int *val, unsigned size) +static int ad7192_set_channel(struct ad_sigma_delta *sd, unsigned int channel) { - u8 *data = st->data; - int ret; - struct spi_transfer t[] = { - { - .tx_buf = data, - .len = 1, - }, { - .rx_buf = data, - .len = size, - .cs_change = cs_change, - }, - }; - struct spi_message m; - - data[0] = AD7192_COMM_READ | AD7192_COMM_ADDR(reg); - - spi_message_init(&m); - spi_message_add_tail(&t[0], &m); - spi_message_add_tail(&t[1], &m); - - if (locked) - ret = spi_sync_locked(st->spi, &m); - else - ret = spi_sync(st->spi, &m); - - if (ret < 0) - return ret; - - switch (size) { - case 3: - *val = data[0] << 16 | data[1] << 8 | data[2]; - break; - case 2: - *val = data[0] << 8 | data[1]; - break; - case 1: - *val = data[0]; - break; - default: - return -EINVAL; - } + struct ad7192_state *st = ad_sigma_delta_to_ad7192(sd); - return 0; -} + st->conf &= ~AD7192_CONF_CHAN_MASK; + st->conf |= AD7192_CONF_CHAN(channel); -static int ad7192_read_reg(struct ad7192_state *st, - unsigned reg, int *val, unsigned size) -{ - return __ad7192_read_reg(st, 0, 0, reg, val, size); + return ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, st->conf); } -static int ad7192_read(struct ad7192_state *st, unsigned ch, - unsigned len, int *val) +static int ad7192_set_mode(struct ad_sigma_delta *sd, + enum ad_sigma_delta_mode mode) { - int ret; - st->conf = (st->conf & ~AD7192_CONF_CHAN(-1)) | - AD7192_CONF_CHAN(1 << ch); - st->mode = (st->mode & ~AD7192_MODE_SEL(-1)) | - AD7192_MODE_SEL(AD7192_MODE_SINGLE); + struct ad7192_state *st = ad_sigma_delta_to_ad7192(sd); - ad7192_write_reg(st, AD7192_REG_CONF, 3, st->conf); + st->mode &= ~AD7192_MODE_SEL_MASK; + st->mode |= AD7192_MODE_SEL(mode); - spi_bus_lock(st->spi->master); - st->done = false; - - ret = __ad7192_write_reg(st, 1, 1, AD7192_REG_MODE, 3, st->mode); - if (ret < 0) - goto out; - - st->irq_dis = false; - enable_irq(st->spi->irq); - wait_event_interruptible(st->wq_data_avail, st->done); - - ret = __ad7192_read_reg(st, 1, 0, AD7192_REG_DATA, val, len); -out: - spi_bus_unlock(st->spi->master); - - return ret; + return ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode); } -static int ad7192_calibrate(struct ad7192_state *st, unsigned mode, unsigned ch) -{ - int ret; - - st->conf = (st->conf & ~AD7192_CONF_CHAN(-1)) | - AD7192_CONF_CHAN(1 << ch); - st->mode = (st->mode & ~AD7192_MODE_SEL(-1)) | AD7192_MODE_SEL(mode); - - ad7192_write_reg(st, AD7192_REG_CONF, 3, st->conf); - - spi_bus_lock(st->spi->master); - st->done = false; - - ret = __ad7192_write_reg(st, 1, 1, AD7192_REG_MODE, 3, - (st->devid != ID_AD7195) ? - st->mode | AD7192_MODE_CLKDIV : - st->mode); - if (ret < 0) - goto out; - - st->irq_dis = false; - enable_irq(st->spi->irq); - wait_event_interruptible(st->wq_data_avail, st->done); - - st->mode = (st->mode & ~AD7192_MODE_SEL(-1)) | - AD7192_MODE_SEL(AD7192_MODE_IDLE); - - ret = __ad7192_write_reg(st, 1, 0, AD7192_REG_MODE, 3, st->mode); -out: - spi_bus_unlock(st->spi->master); - - return ret; -} +static const struct ad_sigma_delta_info ad7192_sigma_delta_info = { + .set_channel = ad7192_set_channel, + .set_mode = ad7192_set_mode, + .has_registers = true, + .addr_shift = 3, + .read_mask = BIT(6), +}; -static const u8 ad7192_calib_arr[8][2] = { +static const struct ad_sd_calib_data ad7192_calib_arr[8] = { {AD7192_MODE_CAL_INT_ZERO, AD7192_CH_AIN1}, {AD7192_MODE_CAL_INT_FULL, AD7192_CH_AIN1}, {AD7192_MODE_CAL_INT_ZERO, AD7192_CH_AIN2}, @@ -332,45 +196,34 @@ static const u8 ad7192_calib_arr[8][2] = { static int ad7192_calibrate_all(struct ad7192_state *st) { - int i, ret; - - for (i = 0; i < ARRAY_SIZE(ad7192_calib_arr); i++) { - ret = ad7192_calibrate(st, ad7192_calib_arr[i][0], - ad7192_calib_arr[i][1]); - if (ret) - goto out; - } - - return 0; -out: - dev_err(&st->spi->dev, "Calibration failed\n"); - return ret; + return ad_sd_calibrate_all(&st->sd, ad7192_calib_arr, + ARRAY_SIZE(ad7192_calib_arr)); } -static int ad7192_setup(struct ad7192_state *st) +static int ad7192_setup(struct ad7192_state *st, + const struct ad7192_platform_data *pdata) { - struct iio_dev *indio_dev = spi_get_drvdata(st->spi); - struct ad7192_platform_data *pdata = st->pdata; + struct iio_dev *indio_dev = spi_get_drvdata(st->sd.spi); unsigned long long scale_uv; int i, ret, id; u8 ones[6]; /* reset the serial interface */ memset(&ones, 0xFF, 6); - ret = spi_write(st->spi, &ones, 6); + ret = spi_write(st->sd.spi, &ones, 6); if (ret < 0) goto out; msleep(1); /* Wait for at least 500us */ /* write/read test for device presence */ - ret = ad7192_read_reg(st, AD7192_REG_ID, &id, 1); + ret = ad_sd_read_reg(&st->sd, AD7192_REG_ID, 1, &id); if (ret) goto out; id &= AD7192_ID_MASK; if (id != st->devid) - dev_warn(&st->spi->dev, "device ID query failed (0x%X)\n", id); + dev_warn(&st->sd.spi->dev, "device ID query failed (0x%X)\n", id); switch (pdata->clock_source_sel) { case AD7192_CLK_EXT_MCLK1_2: @@ -423,11 +276,11 @@ static int ad7192_setup(struct ad7192_state *st) if (pdata->burnout_curr_en) st->conf |= AD7192_CONF_BURN; - ret = ad7192_write_reg(st, AD7192_REG_MODE, 3, st->mode); + ret = ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode); if (ret) goto out; - ret = ad7192_write_reg(st, AD7192_REG_CONF, 3, st->conf); + ret = ad_sd_write_reg(&st->sd, AD7192_REG_CONF, 3, st->conf); if (ret) goto out; @@ -448,181 +301,10 @@ static int ad7192_setup(struct ad7192_state *st) return 0; out: - dev_err(&st->spi->dev, "setup failed\n"); + dev_err(&st->sd.spi->dev, "setup failed\n"); return ret; } -static int ad7192_ring_preenable(struct iio_dev *indio_dev) -{ - struct ad7192_state *st = iio_priv(indio_dev); - unsigned channel; - int ret; - - if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) - return -EINVAL; - - ret = iio_sw_buffer_preenable(indio_dev); - if (ret < 0) - return ret; - - channel = find_first_bit(indio_dev->active_scan_mask, - indio_dev->masklength); - - st->mode = (st->mode & ~AD7192_MODE_SEL(-1)) | - AD7192_MODE_SEL(AD7192_MODE_CONT); - st->conf = (st->conf & ~AD7192_CONF_CHAN(-1)) | - AD7192_CONF_CHAN(1 << indio_dev->channels[channel].address); - - ad7192_write_reg(st, AD7192_REG_CONF, 3, st->conf); - - spi_bus_lock(st->spi->master); - __ad7192_write_reg(st, 1, 1, AD7192_REG_MODE, 3, st->mode); - - st->irq_dis = false; - enable_irq(st->spi->irq); - - return 0; -} - -static int ad7192_ring_postdisable(struct iio_dev *indio_dev) -{ - struct ad7192_state *st = iio_priv(indio_dev); - - st->mode = (st->mode & ~AD7192_MODE_SEL(-1)) | - AD7192_MODE_SEL(AD7192_MODE_IDLE); - - st->done = false; - wait_event_interruptible(st->wq_data_avail, st->done); - - if (!st->irq_dis) - disable_irq_nosync(st->spi->irq); - - __ad7192_write_reg(st, 1, 0, AD7192_REG_MODE, 3, st->mode); - - return spi_bus_unlock(st->spi->master); -} - -/** - * ad7192_trigger_handler() bh of trigger launched polling to ring buffer - **/ -static irqreturn_t ad7192_trigger_handler(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - struct iio_buffer *ring = indio_dev->buffer; - struct ad7192_state *st = iio_priv(indio_dev); - s64 dat64[2]; - s32 *dat32 = (s32 *)dat64; - - if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) - __ad7192_read_reg(st, 1, 1, AD7192_REG_DATA, - dat32, - indio_dev->channels[0].scan_type.realbits/8); - - /* Guaranteed to be aligned with 8 byte boundary */ - if (indio_dev->scan_timestamp) - dat64[1] = pf->timestamp; - - ring->access->store_to(ring, (u8 *)dat64, pf->timestamp); - - iio_trigger_notify_done(indio_dev->trig); - st->irq_dis = false; - enable_irq(st->spi->irq); - - return IRQ_HANDLED; -} - -static const struct iio_buffer_setup_ops ad7192_ring_setup_ops = { - .preenable = &ad7192_ring_preenable, - .postenable = &iio_triggered_buffer_postenable, - .predisable = &iio_triggered_buffer_predisable, - .postdisable = &ad7192_ring_postdisable, - .validate_scan_mask = &iio_validate_scan_mask_onehot, -}; - -static int ad7192_register_ring_funcs_and_init(struct iio_dev *indio_dev) -{ - return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, - &ad7192_trigger_handler, &ad7192_ring_setup_ops); -} - -static void ad7192_ring_cleanup(struct iio_dev *indio_dev) -{ - iio_triggered_buffer_cleanup(indio_dev); -} - -/** - * ad7192_data_rdy_trig_poll() the event handler for the data rdy trig - **/ -static irqreturn_t ad7192_data_rdy_trig_poll(int irq, void *private) -{ - struct ad7192_state *st = iio_priv(private); - - st->done = true; - wake_up_interruptible(&st->wq_data_avail); - disable_irq_nosync(irq); - st->irq_dis = true; - iio_trigger_poll(st->trig, iio_get_time_ns()); - - return IRQ_HANDLED; -} - -static struct iio_trigger_ops ad7192_trigger_ops = { - .owner = THIS_MODULE, -}; - -static int ad7192_probe_trigger(struct iio_dev *indio_dev) -{ - struct ad7192_state *st = iio_priv(indio_dev); - int ret; - - st->trig = iio_trigger_alloc("%s-dev%d", - spi_get_device_id(st->spi)->name, - indio_dev->id); - if (st->trig == NULL) { - ret = -ENOMEM; - goto error_ret; - } - st->trig->ops = &ad7192_trigger_ops; - ret = request_irq(st->spi->irq, - ad7192_data_rdy_trig_poll, - IRQF_TRIGGER_LOW, - spi_get_device_id(st->spi)->name, - indio_dev); - if (ret) - goto error_free_trig; - - disable_irq_nosync(st->spi->irq); - st->irq_dis = true; - st->trig->dev.parent = &st->spi->dev; - st->trig->private_data = indio_dev; - - ret = iio_trigger_register(st->trig); - - /* select default trigger */ - indio_dev->trig = st->trig; - if (ret) - goto error_free_irq; - - return 0; - -error_free_irq: - free_irq(st->spi->irq, indio_dev); -error_free_trig: - iio_trigger_free(st->trig); -error_ret: - return ret; -} - -static void ad7192_remove_trigger(struct iio_dev *indio_dev) -{ - struct ad7192_state *st = iio_priv(indio_dev); - - iio_trigger_unregister(st->trig); - free_irq(st->spi->irq, indio_dev); - iio_trigger_free(st->trig); -} - static ssize_t ad7192_read_frequency(struct device *dev, struct device_attribute *attr, char *buf) @@ -664,7 +346,7 @@ static ssize_t ad7192_write_frequency(struct device *dev, st->mode &= ~AD7192_MODE_RATE(-1); st->mode |= AD7192_MODE_RATE(div); - ad7192_write_reg(st, AD7192_REG_MODE, 3, st->mode); + ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode); out: mutex_unlock(&indio_dev->mlock); @@ -676,7 +358,6 @@ static IIO_DEV_ATTR_SAMP_FREQ(S_IWUSR | S_IRUGO, ad7192_read_frequency, ad7192_write_frequency); - static ssize_t ad7192_show_scale_available(struct device *dev, struct device_attribute *attr, char *buf) { @@ -748,7 +429,7 @@ static ssize_t ad7192_set(struct device *dev, else st->gpocon &= ~AD7192_GPOCON_BPDSW; - ad7192_write_reg(st, AD7192_REG_GPOCON, 1, st->gpocon); + ad_sd_write_reg(&st->sd, AD7192_REG_GPOCON, 1, st->gpocon); break; case AD7192_REG_MODE: if (val) @@ -756,7 +437,7 @@ static ssize_t ad7192_set(struct device *dev, else st->mode &= ~AD7192_MODE_ACX; - ad7192_write_reg(st, AD7192_REG_MODE, 3, st->mode); + ad_sd_write_reg(&st->sd, AD7192_REG_MODE, 3, st->mode); break; default: ret = -EINVAL; @@ -812,27 +493,11 @@ static int ad7192_read_raw(struct iio_dev *indio_dev, long m) { struct ad7192_state *st = iio_priv(indio_dev); - int ret, smpl = 0; bool unipolar = !!(st->conf & AD7192_CONF_UNIPOLAR); switch (m) { case IIO_CHAN_INFO_RAW: - mutex_lock(&indio_dev->mlock); - if (iio_buffer_enabled(indio_dev)) - ret = -EBUSY; - else - ret = ad7192_read(st, chan->address, - chan->scan_type.realbits / 8, &smpl); - mutex_unlock(&indio_dev->mlock); - - if (ret < 0) - return ret; - - *val = (smpl >> chan->scan_type.shift) & - ((1 << (chan->scan_type.realbits)) - 1); - - return IIO_VAL_INT; - + return ad_sigma_delta_single_conversion(indio_dev, chan, val); case IIO_CHAN_INFO_SCALE: switch (chan->type) { case IIO_VOLTAGE: @@ -883,16 +548,16 @@ static int ad7192_write_raw(struct iio_dev *indio_dev, ret = -EINVAL; for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) if (val2 == st->scale_avail[i][1]) { + ret = 0; tmp = st->conf; st->conf &= ~AD7192_CONF_GAIN(-1); st->conf |= AD7192_CONF_GAIN(i); - - if (tmp != st->conf) { - ad7192_write_reg(st, AD7192_REG_CONF, - 3, st->conf); - ad7192_calibrate_all(st); - } - ret = 0; + if (tmp == st->conf) + break; + ad_sd_write_reg(&st->sd, AD7192_REG_CONF, + 3, st->conf); + ad7192_calibrate_all(st); + break; } break; default: @@ -904,15 +569,6 @@ static int ad7192_write_raw(struct iio_dev *indio_dev, return ret; } -static int ad7192_validate_trigger(struct iio_dev *indio_dev, - struct iio_trigger *trig) -{ - if (indio_dev->trig != trig) - return -EINVAL; - - return 0; -} - static int ad7192_write_raw_get_fmt(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, long mask) @@ -925,7 +581,7 @@ static const struct iio_info ad7192_info = { .write_raw = &ad7192_write_raw, .write_raw_get_fmt = &ad7192_write_raw_get_fmt, .attrs = &ad7192_attribute_group, - .validate_trigger = ad7192_validate_trigger, + .validate_trigger = ad_sd_validate_trigger, .driver_module = THIS_MODULE, }; @@ -934,60 +590,25 @@ static const struct iio_info ad7195_info = { .write_raw = &ad7192_write_raw, .write_raw_get_fmt = &ad7192_write_raw_get_fmt, .attrs = &ad7195_attribute_group, - .validate_trigger = ad7192_validate_trigger, + .validate_trigger = ad_sd_validate_trigger, .driver_module = THIS_MODULE, }; -#define AD7192_CHAN_DIFF(_chan, _chan2, _name, _address, _si) \ - { .type = IIO_VOLTAGE, \ - .differential = 1, \ - .indexed = 1, \ - .extend_name = _name, \ - .channel = _chan, \ - .channel2 = _chan2, \ - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ - IIO_CHAN_INFO_SCALE_SHARED_BIT | \ - IIO_CHAN_INFO_OFFSET_SHARED_BIT, \ - .address = _address, \ - .scan_index = _si, \ - .scan_type = IIO_ST('u', 24, 32, 0)} - -#define AD7192_CHAN(_chan, _address, _si) \ - { .type = IIO_VOLTAGE, \ - .indexed = 1, \ - .channel = _chan, \ - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ - IIO_CHAN_INFO_SCALE_SHARED_BIT | \ - IIO_CHAN_INFO_OFFSET_SHARED_BIT, \ - .address = _address, \ - .scan_index = _si, \ - .scan_type = IIO_ST('u', 24, 32, 0)} - -#define AD7192_CHAN_TEMP(_chan, _address, _si) \ - { .type = IIO_TEMP, \ - .indexed = 1, \ - .channel = _chan, \ - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \ - .address = _address, \ - .scan_index = _si, \ - .scan_type = IIO_ST('u', 24, 32, 0)} - -static struct iio_chan_spec ad7192_channels[] = { - AD7192_CHAN_DIFF(1, 2, NULL, AD7192_CH_AIN1P_AIN2M, 0), - AD7192_CHAN_DIFF(3, 4, NULL, AD7192_CH_AIN3P_AIN4M, 1), - AD7192_CHAN_TEMP(0, AD7192_CH_TEMP, 2), - AD7192_CHAN_DIFF(2, 2, "shorted", AD7192_CH_AIN2P_AIN2M, 3), - AD7192_CHAN(1, AD7192_CH_AIN1, 4), - AD7192_CHAN(2, AD7192_CH_AIN2, 5), - AD7192_CHAN(3, AD7192_CH_AIN3, 6), - AD7192_CHAN(4, AD7192_CH_AIN4, 7), +static const struct iio_chan_spec ad7192_channels[] = { + AD_SD_DIFF_CHANNEL(0, 1, 2, AD7192_CH_AIN1P_AIN2M, 24, 32, 0), + AD_SD_DIFF_CHANNEL(1, 3, 4, AD7192_CH_AIN3P_AIN4M, 24, 32, 0), + AD_SD_TEMP_CHANNEL(2, AD7192_CH_TEMP, 24, 32, 0), + AD_SD_SHORTED_CHANNEL(3, 2, AD7192_CH_AIN2P_AIN2M, 24, 32, 0), + AD_SD_CHANNEL(4, 1, AD7192_CH_AIN1, 24, 32, 0), + AD_SD_CHANNEL(5, 2, AD7192_CH_AIN2, 24, 32, 0), + AD_SD_CHANNEL(6, 3, AD7192_CH_AIN3, 24, 32, 0), + AD_SD_CHANNEL(7, 4, AD7192_CH_AIN4, 24, 32, 0), IIO_CHAN_SOFT_TIMESTAMP(8), }; static int __devinit ad7192_probe(struct spi_device *spi) { - struct ad7192_platform_data *pdata = spi->dev.platform_data; + const struct ad7192_platform_data *pdata = spi->dev.platform_data; struct ad7192_state *st; struct iio_dev *indio_dev; int ret , voltage_uv = 0; @@ -1017,8 +638,6 @@ static int __devinit ad7192_probe(struct spi_device *spi) voltage_uv = regulator_get_voltage(st->reg); } - st->pdata = pdata; - if (pdata && pdata->vref_mv) st->int_vref_mv = pdata->vref_mv; else if (voltage_uv) @@ -1027,7 +646,6 @@ static int __devinit ad7192_probe(struct spi_device *spi) dev_warn(&spi->dev, "reference voltage undefined\n"); spi_set_drvdata(spi, indio_dev); - st->spi = spi; st->devid = spi_get_device_id(spi)->driver_data; indio_dev->dev.parent = &spi->dev; indio_dev->name = spi_get_device_id(spi)->name; @@ -1039,17 +657,13 @@ static int __devinit ad7192_probe(struct spi_device *spi) else indio_dev->info = &ad7192_info; - init_waitqueue_head(&st->wq_data_avail); + ad_sd_init(&st->sd, indio_dev, spi, &ad7192_sigma_delta_info); - ret = ad7192_register_ring_funcs_and_init(indio_dev); + ret = ad_sd_setup_buffer_and_trigger(indio_dev); if (ret) goto error_disable_reg; - ret = ad7192_probe_trigger(indio_dev); - if (ret) - goto error_ring_cleanup; - - ret = ad7192_setup(st); + ret = ad7192_setup(st, pdata); if (ret) goto error_remove_trigger; @@ -1059,9 +673,7 @@ static int __devinit ad7192_probe(struct spi_device *spi) return 0; error_remove_trigger: - ad7192_remove_trigger(indio_dev); -error_ring_cleanup: - ad7192_ring_cleanup(indio_dev); + ad_sd_cleanup_buffer_and_trigger(indio_dev); error_disable_reg: if (!IS_ERR(st->reg)) regulator_disable(st->reg); @@ -1074,14 +686,13 @@ error_put_reg: return ret; } -static int ad7192_remove(struct spi_device *spi) +static int __devexit ad7192_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct ad7192_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); - ad7192_remove_trigger(indio_dev); - ad7192_ring_cleanup(indio_dev); + ad_sd_cleanup_buffer_and_trigger(indio_dev); if (!IS_ERR(st->reg)) { regulator_disable(st->reg); diff --git a/drivers/staging/iio/adc/ad7298_core.c b/drivers/staging/iio/adc/ad7298_core.c index 6141f4a70cfa..4c75114e7d7c 100644 --- a/drivers/staging/iio/adc/ad7298_core.c +++ b/drivers/staging/iio/adc/ad7298_core.c @@ -38,7 +38,7 @@ }, \ } -static struct iio_chan_spec ad7298_channels[] = { +static const struct iio_chan_spec ad7298_channels[] = { { .type = IIO_TEMP, .indexed = 1, diff --git a/drivers/staging/iio/adc/ad7298_ring.c b/drivers/staging/iio/adc/ad7298_ring.c index 506016f01593..c2906a85fedb 100644 --- a/drivers/staging/iio/adc/ad7298_ring.c +++ b/drivers/staging/iio/adc/ad7298_ring.c @@ -75,7 +75,6 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct ad7298_state *st = iio_priv(indio_dev); - struct iio_buffer *ring = indio_dev->buffer; s64 time_ns = 0; __u16 buf[16]; int b_sent, i; @@ -94,7 +93,7 @@ static irqreturn_t ad7298_trigger_handler(int irq, void *p) indio_dev->masklength); i++) buf[i] = be16_to_cpu(st->rx_buf[i]); - indio_dev->buffer->access->store_to(ring, (u8 *)buf, time_ns); + iio_push_to_buffer(indio_dev->buffer, (u8 *)buf); done: iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/staging/iio/adc/ad7476.h b/drivers/staging/iio/adc/ad7476.h deleted file mode 100644 index b1dd9317fe1f..000000000000 --- a/drivers/staging/iio/adc/ad7476.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * AD7476/5/7/8 (A) SPI ADC driver - * - * Copyright 2010 Analog Devices Inc. - * - * Licensed under the GPL-2 or later. - */ -#ifndef IIO_ADC_AD7476_H_ -#define IIO_ADC_AD7476_H_ - -#define RES_MASK(bits) ((1 << (bits)) - 1) - -/* - * TODO: struct ad7476_platform_data needs to go into include/linux/iio - */ - -struct ad7476_platform_data { - u16 vref_mv; -}; - -struct ad7476_chip_info { - u16 int_vref_mv; - struct iio_chan_spec channel[2]; -}; - -struct ad7476_state { - struct spi_device *spi; - const struct ad7476_chip_info *chip_info; - struct regulator *reg; - u16 int_vref_mv; - struct spi_transfer xfer; - struct spi_message msg; - /* - * DMA (thus cache coherency maintenance) requires the - * transfer buffers to live in their own cache lines. - */ - unsigned char data[2] ____cacheline_aligned; -}; - -enum ad7476_supported_device_ids { - ID_AD7466, - ID_AD7467, - ID_AD7468, - ID_AD7475, - ID_AD7476, - ID_AD7477, - ID_AD7478, - ID_AD7495 -}; - -#ifdef CONFIG_IIO_BUFFER -int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev); -void ad7476_ring_cleanup(struct iio_dev *indio_dev); -#else /* CONFIG_IIO_BUFFER */ - -static inline int -ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev) -{ - return 0; -} - -static inline void ad7476_ring_cleanup(struct iio_dev *indio_dev) -{ -} -#endif /* CONFIG_IIO_BUFFER */ -#endif /* IIO_ADC_AD7476_H_ */ diff --git a/drivers/staging/iio/adc/ad7476_ring.c b/drivers/staging/iio/adc/ad7476_ring.c deleted file mode 100644 index d087b21c51f6..000000000000 --- a/drivers/staging/iio/adc/ad7476_ring.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2010-2012 Analog Devices Inc. - * Copyright (C) 2008 Jonathan Cameron - * - * Licensed under the GPL-2 or later. - * - * ad7476_ring.c - */ - -#include <linux/interrupt.h> -#include <linux/device.h> -#include <linux/kernel.h> -#include <linux/slab.h> -#include <linux/spi/spi.h> - -#include <linux/iio/iio.h> -#include <linux/iio/buffer.h> -#include <linux/iio/trigger_consumer.h> -#include <linux/iio/triggered_buffer.h> - -#include "ad7476.h" - -static irqreturn_t ad7476_trigger_handler(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - struct ad7476_state *st = iio_priv(indio_dev); - s64 time_ns; - __u8 *rxbuf; - int b_sent; - - rxbuf = kzalloc(indio_dev->scan_bytes, GFP_KERNEL); - if (rxbuf == NULL) - goto done; - - b_sent = spi_read(st->spi, rxbuf, - st->chip_info->channel[0].scan_type.storagebits / 8); - if (b_sent < 0) - goto done; - - time_ns = iio_get_time_ns(); - - if (indio_dev->scan_timestamp) - memcpy(rxbuf + indio_dev->scan_bytes - sizeof(s64), - &time_ns, sizeof(time_ns)); - - indio_dev->buffer->access->store_to(indio_dev->buffer, rxbuf, time_ns); -done: - iio_trigger_notify_done(indio_dev->trig); - kfree(rxbuf); - - return IRQ_HANDLED; -} - -int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev) -{ - return iio_triggered_buffer_setup(indio_dev, NULL, - &ad7476_trigger_handler, NULL); -} - -void ad7476_ring_cleanup(struct iio_dev *indio_dev) -{ - iio_triggered_buffer_cleanup(indio_dev); -} diff --git a/drivers/staging/iio/adc/ad7606.h b/drivers/staging/iio/adc/ad7606.h index 10f59896597f..9221a74efd18 100644 --- a/drivers/staging/iio/adc/ad7606.h +++ b/drivers/staging/iio/adc/ad7606.h @@ -51,7 +51,7 @@ struct ad7606_platform_data { struct ad7606_chip_info { const char *name; u16 int_vref_mv; - struct iio_chan_spec *channels; + const struct iio_chan_spec *channels; unsigned num_channels; }; diff --git a/drivers/staging/iio/adc/ad7606_core.c b/drivers/staging/iio/adc/ad7606_core.c index ccb97fecdea7..bae61cbe9212 100644 --- a/drivers/staging/iio/adc/ad7606_core.c +++ b/drivers/staging/iio/adc/ad7606_core.c @@ -241,7 +241,7 @@ static const struct attribute_group ad7606_attribute_group_range = { .scan_type = IIO_ST('s', 16, 16, 0), \ } -static struct iio_chan_spec ad7606_8_channels[] = { +static const struct iio_chan_spec ad7606_8_channels[] = { AD7606_CHANNEL(0), AD7606_CHANNEL(1), AD7606_CHANNEL(2), @@ -253,7 +253,7 @@ static struct iio_chan_spec ad7606_8_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(8), }; -static struct iio_chan_spec ad7606_6_channels[] = { +static const struct iio_chan_spec ad7606_6_channels[] = { AD7606_CHANNEL(0), AD7606_CHANNEL(1), AD7606_CHANNEL(2), @@ -263,7 +263,7 @@ static struct iio_chan_spec ad7606_6_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(6), }; -static struct iio_chan_spec ad7606_4_channels[] = { +static const struct iio_chan_spec ad7606_4_channels[] = { AD7606_CHANNEL(0), AD7606_CHANNEL(1), AD7606_CHANNEL(2), diff --git a/drivers/staging/iio/adc/ad7606_ring.c b/drivers/staging/iio/adc/ad7606_ring.c index f15afe47c20d..ba04d0ffd4f4 100644 --- a/drivers/staging/iio/adc/ad7606_ring.c +++ b/drivers/staging/iio/adc/ad7606_ring.c @@ -46,7 +46,6 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s) struct ad7606_state *st = container_of(work_s, struct ad7606_state, poll_work); struct iio_dev *indio_dev = iio_priv_to_dev(st); - struct iio_buffer *ring = indio_dev->buffer; s64 time_ns; __u8 *buf; int ret; @@ -84,7 +83,7 @@ static void ad7606_poll_bh_to_ring(struct work_struct *work_s) if (indio_dev->scan_timestamp) *((s64 *)(buf + indio_dev->scan_bytes - sizeof(s64))) = time_ns; - ring->access->store_to(indio_dev->buffer, buf, time_ns); + iio_push_to_buffer(indio_dev->buffer, buf); done: gpio_set_value(st->pdata->gpio_convst, 0); iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/staging/iio/adc/ad7780.c b/drivers/staging/iio/adc/ad7780.c index 19ee49c95de4..0a1328b8657f 100644 --- a/drivers/staging/iio/adc/ad7780.c +++ b/drivers/staging/iio/adc/ad7780.c @@ -1,5 +1,5 @@ /* - * AD7780/AD7781 SPI ADC driver + * AD7170/AD7171 and AD7780/AD7781 SPI ADC driver * * Copyright 2011 Analog Devices Inc. * @@ -20,6 +20,7 @@ #include <linux/iio/iio.h> #include <linux/iio/sysfs.h> +#include <linux/iio/adc/ad_sigma_delta.h> #include "ad7780.h" @@ -33,53 +34,53 @@ #define AD7780_PAT0 (1 << 0) struct ad7780_chip_info { - struct iio_chan_spec channel; + struct iio_chan_spec channel; + unsigned int pattern_mask; + unsigned int pattern; }; struct ad7780_state { - struct spi_device *spi; const struct ad7780_chip_info *chip_info; struct regulator *reg; - struct ad7780_platform_data *pdata; - wait_queue_head_t wq_data_avail; - bool done; + int powerdown_gpio; + unsigned int gain; u16 int_vref_mv; - struct spi_transfer xfer; - struct spi_message msg; - /* - * DMA (thus cache coherency maintenance) requires the - * transfer buffers to live in their own cache lines. - */ - unsigned int data ____cacheline_aligned; + + struct ad_sigma_delta sd; }; enum ad7780_supported_device_ids { + ID_AD7170, + ID_AD7171, ID_AD7780, ID_AD7781, }; -static int ad7780_read(struct ad7780_state *st, int *val) +static struct ad7780_state *ad_sigma_delta_to_ad7780(struct ad_sigma_delta *sd) { - int ret; - - spi_bus_lock(st->spi->master); - - enable_irq(st->spi->irq); - st->done = false; - gpio_set_value(st->pdata->gpio_pdrst, 1); + return container_of(sd, struct ad7780_state, sd); +} - ret = wait_event_interruptible(st->wq_data_avail, st->done); - disable_irq_nosync(st->spi->irq); - if (ret) - goto out; +static int ad7780_set_mode(struct ad_sigma_delta *sigma_delta, + enum ad_sigma_delta_mode mode) +{ + struct ad7780_state *st = ad_sigma_delta_to_ad7780(sigma_delta); + unsigned val; + + switch (mode) { + case AD_SD_MODE_SINGLE: + case AD_SD_MODE_CONTINUOUS: + val = 1; + break; + default: + val = 0; + break; + } - ret = spi_sync_locked(st->spi, &st->msg); - *val = be32_to_cpu(st->data); -out: - gpio_set_value(st->pdata->gpio_pdrst, 0); - spi_bus_unlock(st->spi->master); + if (gpio_is_valid(st->powerdown_gpio)) + gpio_set_value(st->powerdown_gpio, val); - return ret; + return 0; } static int ad7780_read_raw(struct iio_dev *indio_dev, @@ -89,89 +90,75 @@ static int ad7780_read_raw(struct iio_dev *indio_dev, long m) { struct ad7780_state *st = iio_priv(indio_dev); - struct iio_chan_spec channel = st->chip_info->channel; - int ret, smpl = 0; unsigned long scale_uv; switch (m) { case IIO_CHAN_INFO_RAW: - mutex_lock(&indio_dev->mlock); - ret = ad7780_read(st, &smpl); - mutex_unlock(&indio_dev->mlock); - - if (ret < 0) - return ret; - - if ((smpl & AD7780_ERR) || - !((smpl & AD7780_PAT0) && !(smpl & AD7780_PAT1))) - return -EIO; - - *val = (smpl >> channel.scan_type.shift) & - ((1 << (channel.scan_type.realbits)) - 1); - *val -= (1 << (channel.scan_type.realbits - 1)); - - if (!(smpl & AD7780_GAIN)) - *val *= 128; - - return IIO_VAL_INT; + return ad_sigma_delta_single_conversion(indio_dev, chan, val); case IIO_CHAN_INFO_SCALE: - scale_uv = (st->int_vref_mv * 100000) - >> (channel.scan_type.realbits - 1); + scale_uv = (st->int_vref_mv * 100000 * st->gain) + >> (chan->scan_type.realbits - 1); *val = scale_uv / 100000; *val2 = (scale_uv % 100000) * 10; return IIO_VAL_INT_PLUS_MICRO; + case IIO_CHAN_INFO_OFFSET: + *val -= (1 << (chan->scan_type.realbits - 1)); + return IIO_VAL_INT; } + return -EINVAL; } +static int ad7780_postprocess_sample(struct ad_sigma_delta *sigma_delta, + unsigned int raw_sample) +{ + struct ad7780_state *st = ad_sigma_delta_to_ad7780(sigma_delta); + const struct ad7780_chip_info *chip_info = st->chip_info; + + if ((raw_sample & AD7780_ERR) || + ((raw_sample & chip_info->pattern_mask) != chip_info->pattern)) + return -EIO; + + if (raw_sample & AD7780_GAIN) + st->gain = 1; + else + st->gain = 128; + + return 0; +} + +static const struct ad_sigma_delta_info ad7780_sigma_delta_info = { + .set_mode = ad7780_set_mode, + .postprocess_sample = ad7780_postprocess_sample, + .has_registers = false, +}; + +#define AD7780_CHANNEL(bits, wordsize) \ + AD_SD_CHANNEL(1, 0, 0, bits, 32, wordsize - bits) + static const struct ad7780_chip_info ad7780_chip_info_tbl[] = { + [ID_AD7170] = { + .channel = AD7780_CHANNEL(12, 24), + .pattern = 0x5, + .pattern_mask = 0x7, + }, + [ID_AD7171] = { + .channel = AD7780_CHANNEL(16, 24), + .pattern = 0x5, + .pattern_mask = 0x7, + }, [ID_AD7780] = { - .channel = { - .type = IIO_VOLTAGE, - .indexed = 1, - .channel = 0, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_OFFSET_SHARED_BIT, - .scan_type = { - .sign = 'u', - .realbits = 24, - .storagebits = 32, - .shift = 8, - }, - }, + .channel = AD7780_CHANNEL(24, 32), + .pattern = 0x1, + .pattern_mask = 0x3, }, [ID_AD7781] = { - .channel = { - .type = IIO_VOLTAGE, - .indexed = 1, - .channel = 0, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_OFFSET_SHARED_BIT, - .scan_type = { - .sign = 'u', - .realbits = 20, - .storagebits = 32, - .shift = 12, - }, - }, + .channel = AD7780_CHANNEL(20, 32), + .pattern = 0x1, + .pattern_mask = 0x3, }, }; -/** - * Interrupt handler - */ -static irqreturn_t ad7780_interrupt(int irq, void *dev_id) -{ - struct ad7780_state *st = dev_id; - - st->done = true; - wake_up_interruptible(&st->wq_data_avail); - - return IRQ_HANDLED; -}; - static const struct iio_info ad7780_info = { .read_raw = &ad7780_read_raw, .driver_module = THIS_MODULE, @@ -184,16 +171,14 @@ static int __devinit ad7780_probe(struct spi_device *spi) struct iio_dev *indio_dev; int ret, voltage_uv = 0; - if (!pdata) { - dev_dbg(&spi->dev, "no platform data?\n"); - return -ENODEV; - } - indio_dev = iio_device_alloc(sizeof(*st)); if (indio_dev == NULL) return -ENOMEM; st = iio_priv(indio_dev); + st->gain = 1; + + ad_sd_init(&st->sd, indio_dev, spi, &ad7780_sigma_delta_info); st->reg = regulator_get(&spi->dev, "vcc"); if (!IS_ERR(st->reg)) { @@ -207,8 +192,6 @@ static int __devinit ad7780_probe(struct spi_device *spi) st->chip_info = &ad7780_chip_info_tbl[spi_get_device_id(spi)->driver_data]; - st->pdata = pdata; - if (pdata && pdata->vref_mv) st->int_vref_mv = pdata->vref_mv; else if (voltage_uv) @@ -217,7 +200,6 @@ static int __devinit ad7780_probe(struct spi_device *spi) dev_warn(&spi->dev, "reference voltage unspecified\n"); spi_set_drvdata(spi, indio_dev); - st->spi = spi; indio_dev->dev.parent = &spi->dev; indio_dev->name = spi_get_device_id(spi)->name; @@ -226,40 +208,34 @@ static int __devinit ad7780_probe(struct spi_device *spi) indio_dev->num_channels = 1; indio_dev->info = &ad7780_info; - init_waitqueue_head(&st->wq_data_avail); - - /* Setup default message */ + if (pdata && gpio_is_valid(pdata->gpio_pdrst)) { - st->xfer.rx_buf = &st->data; - st->xfer.len = st->chip_info->channel.scan_type.storagebits / 8; - - spi_message_init(&st->msg); - spi_message_add_tail(&st->xfer, &st->msg); - - ret = gpio_request_one(st->pdata->gpio_pdrst, GPIOF_OUT_INIT_LOW, + ret = gpio_request_one(pdata->gpio_pdrst, GPIOF_OUT_INIT_LOW, "AD7780 /PDRST"); - if (ret) { - dev_err(&spi->dev, "failed to request GPIO PDRST\n"); - goto error_disable_reg; + if (ret) { + dev_err(&spi->dev, "failed to request GPIO PDRST\n"); + goto error_disable_reg; + } + st->powerdown_gpio = pdata->gpio_pdrst; + } else { + st->powerdown_gpio = -1; } - ret = request_irq(spi->irq, ad7780_interrupt, - IRQF_TRIGGER_FALLING, spi_get_device_id(spi)->name, st); + ret = ad_sd_setup_buffer_and_trigger(indio_dev); if (ret) goto error_free_gpio; - disable_irq(spi->irq); - ret = iio_device_register(indio_dev); if (ret) - goto error_free_irq; + goto error_cleanup_buffer_and_trigger; return 0; -error_free_irq: - free_irq(spi->irq, st); +error_cleanup_buffer_and_trigger: + ad_sd_cleanup_buffer_and_trigger(indio_dev); error_free_gpio: - gpio_free(st->pdata->gpio_pdrst); + if (pdata && gpio_is_valid(pdata->gpio_pdrst)) + gpio_free(pdata->gpio_pdrst); error_disable_reg: if (!IS_ERR(st->reg)) regulator_disable(st->reg); @@ -272,14 +248,17 @@ error_put_reg: return ret; } -static int ad7780_remove(struct spi_device *spi) +static int __devexit ad7780_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct ad7780_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); - free_irq(spi->irq, st); - gpio_free(st->pdata->gpio_pdrst); + ad_sd_cleanup_buffer_and_trigger(indio_dev); + + if (gpio_is_valid(st->powerdown_gpio)) + gpio_free(st->powerdown_gpio); + if (!IS_ERR(st->reg)) { regulator_disable(st->reg); regulator_put(st->reg); @@ -290,6 +269,8 @@ static int ad7780_remove(struct spi_device *spi) } static const struct spi_device_id ad7780_id[] = { + {"ad7170", ID_AD7170}, + {"ad7171", ID_AD7171}, {"ad7780", ID_AD7780}, {"ad7781", ID_AD7781}, {} @@ -308,5 +289,5 @@ static struct spi_driver ad7780_driver = { module_spi_driver(ad7780_driver); MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); -MODULE_DESCRIPTION("Analog Devices AD7780/1 ADC"); +MODULE_DESCRIPTION("Analog Devices AD7780 and similar ADCs"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/adc/ad7793.c b/drivers/staging/iio/adc/ad7793.c index 112e2b7b5bc4..691a7be6f5cb 100644 --- a/drivers/staging/iio/adc/ad7793.c +++ b/drivers/staging/iio/adc/ad7793.c @@ -1,5 +1,5 @@ /* - * AD7792/AD7793 SPI ADC driver + * AD7785/AD7792/AD7793/AD7794/AD7795 SPI ADC driver * * Copyright 2011-2012 Analog Devices Inc. * @@ -24,6 +24,7 @@ #include <linux/iio/trigger.h> #include <linux/iio/trigger_consumer.h> #include <linux/iio/triggered_buffer.h> +#include <linux/iio/adc/ad_sigma_delta.h> #include "ad7793.h" @@ -36,198 +37,65 @@ */ struct ad7793_chip_info { - struct iio_chan_spec channel[7]; + const struct iio_chan_spec *channels; + unsigned int num_channels; }; struct ad7793_state { - struct spi_device *spi; - struct iio_trigger *trig; const struct ad7793_chip_info *chip_info; struct regulator *reg; - struct ad7793_platform_data *pdata; - wait_queue_head_t wq_data_avail; - bool done; - bool irq_dis; u16 int_vref_mv; u16 mode; u16 conf; u32 scale_avail[8][2]; - /* - * DMA (thus cache coherency maintenance) requires the - * transfer buffers to live in their own cache lines. - */ - u8 data[4] ____cacheline_aligned; + struct ad_sigma_delta sd; + }; enum ad7793_supported_device_ids { + ID_AD7785, ID_AD7792, ID_AD7793, + ID_AD7794, + ID_AD7795, }; -static int __ad7793_write_reg(struct ad7793_state *st, bool locked, - bool cs_change, unsigned char reg, - unsigned size, unsigned val) -{ - u8 *data = st->data; - struct spi_transfer t = { - .tx_buf = data, - .len = size + 1, - .cs_change = cs_change, - }; - struct spi_message m; - - data[0] = AD7793_COMM_WRITE | AD7793_COMM_ADDR(reg); - - switch (size) { - case 3: - data[1] = val >> 16; - data[2] = val >> 8; - data[3] = val; - break; - case 2: - data[1] = val >> 8; - data[2] = val; - break; - case 1: - data[1] = val; - break; - default: - return -EINVAL; - } - - spi_message_init(&m); - spi_message_add_tail(&t, &m); - - if (locked) - return spi_sync_locked(st->spi, &m); - else - return spi_sync(st->spi, &m); -} - -static int ad7793_write_reg(struct ad7793_state *st, - unsigned reg, unsigned size, unsigned val) +static struct ad7793_state *ad_sigma_delta_to_ad7793(struct ad_sigma_delta *sd) { - return __ad7793_write_reg(st, false, false, reg, size, val); + return container_of(sd, struct ad7793_state, sd); } -static int __ad7793_read_reg(struct ad7793_state *st, bool locked, - bool cs_change, unsigned char reg, - int *val, unsigned size) +static int ad7793_set_channel(struct ad_sigma_delta *sd, unsigned int channel) { - u8 *data = st->data; - int ret; - struct spi_transfer t[] = { - { - .tx_buf = data, - .len = 1, - }, { - .rx_buf = data, - .len = size, - .cs_change = cs_change, - }, - }; - struct spi_message m; - - data[0] = AD7793_COMM_READ | AD7793_COMM_ADDR(reg); - - spi_message_init(&m); - spi_message_add_tail(&t[0], &m); - spi_message_add_tail(&t[1], &m); - - if (locked) - ret = spi_sync_locked(st->spi, &m); - else - ret = spi_sync(st->spi, &m); - - if (ret < 0) - return ret; - - switch (size) { - case 3: - *val = data[0] << 16 | data[1] << 8 | data[2]; - break; - case 2: - *val = data[0] << 8 | data[1]; - break; - case 1: - *val = data[0]; - break; - default: - return -EINVAL; - } + struct ad7793_state *st = ad_sigma_delta_to_ad7793(sd); - return 0; -} + st->conf &= ~AD7793_CONF_CHAN_MASK; + st->conf |= AD7793_CONF_CHAN(channel); -static int ad7793_read_reg(struct ad7793_state *st, - unsigned reg, int *val, unsigned size) -{ - return __ad7793_read_reg(st, 0, 0, reg, val, size); + return ad_sd_write_reg(&st->sd, AD7793_REG_CONF, 2, st->conf); } -static int ad7793_read(struct ad7793_state *st, unsigned ch, - unsigned len, int *val) +static int ad7793_set_mode(struct ad_sigma_delta *sd, + enum ad_sigma_delta_mode mode) { - int ret; - st->conf = (st->conf & ~AD7793_CONF_CHAN(-1)) | AD7793_CONF_CHAN(ch); - st->mode = (st->mode & ~AD7793_MODE_SEL(-1)) | - AD7793_MODE_SEL(AD7793_MODE_SINGLE); - - ad7793_write_reg(st, AD7793_REG_CONF, sizeof(st->conf), st->conf); - - spi_bus_lock(st->spi->master); - st->done = false; - - ret = __ad7793_write_reg(st, 1, 1, AD7793_REG_MODE, - sizeof(st->mode), st->mode); - if (ret < 0) - goto out; + struct ad7793_state *st = ad_sigma_delta_to_ad7793(sd); - st->irq_dis = false; - enable_irq(st->spi->irq); - wait_event_interruptible(st->wq_data_avail, st->done); + st->mode &= ~AD7793_MODE_SEL_MASK; + st->mode |= AD7793_MODE_SEL(mode); - ret = __ad7793_read_reg(st, 1, 0, AD7793_REG_DATA, val, len); -out: - spi_bus_unlock(st->spi->master); - - return ret; + return ad_sd_write_reg(&st->sd, AD7793_REG_MODE, 2, st->mode); } -static int ad7793_calibrate(struct ad7793_state *st, unsigned mode, unsigned ch) -{ - int ret; - - st->conf = (st->conf & ~AD7793_CONF_CHAN(-1)) | AD7793_CONF_CHAN(ch); - st->mode = (st->mode & ~AD7793_MODE_SEL(-1)) | AD7793_MODE_SEL(mode); - - ad7793_write_reg(st, AD7793_REG_CONF, sizeof(st->conf), st->conf); - - spi_bus_lock(st->spi->master); - st->done = false; - - ret = __ad7793_write_reg(st, 1, 1, AD7793_REG_MODE, - sizeof(st->mode), st->mode); - if (ret < 0) - goto out; - - st->irq_dis = false; - enable_irq(st->spi->irq); - wait_event_interruptible(st->wq_data_avail, st->done); - - st->mode = (st->mode & ~AD7793_MODE_SEL(-1)) | - AD7793_MODE_SEL(AD7793_MODE_IDLE); - - ret = __ad7793_write_reg(st, 1, 0, AD7793_REG_MODE, - sizeof(st->mode), st->mode); -out: - spi_bus_unlock(st->spi->master); - - return ret; -} +static const struct ad_sigma_delta_info ad7793_sigma_delta_info = { + .set_channel = ad7793_set_channel, + .set_mode = ad7793_set_mode, + .has_registers = true, + .addr_shift = 3, + .read_mask = BIT(6), +}; -static const u8 ad7793_calib_arr[6][2] = { +static const struct ad_sd_calib_data ad7793_calib_arr[6] = { {AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN1P_AIN1M}, {AD7793_MODE_CAL_INT_FULL, AD7793_CH_AIN1P_AIN1M}, {AD7793_MODE_CAL_INT_ZERO, AD7793_CH_AIN2P_AIN2M}, @@ -238,59 +106,49 @@ static const u8 ad7793_calib_arr[6][2] = { static int ad7793_calibrate_all(struct ad7793_state *st) { - int i, ret; - - for (i = 0; i < ARRAY_SIZE(ad7793_calib_arr); i++) { - ret = ad7793_calibrate(st, ad7793_calib_arr[i][0], - ad7793_calib_arr[i][1]); - if (ret) - goto out; - } - - return 0; -out: - dev_err(&st->spi->dev, "Calibration failed\n"); - return ret; + return ad_sd_calibrate_all(&st->sd, ad7793_calib_arr, + ARRAY_SIZE(ad7793_calib_arr)); } -static int ad7793_setup(struct ad7793_state *st) +static int ad7793_setup(struct iio_dev *indio_dev, + const struct ad7793_platform_data *pdata) { + struct ad7793_state *st = iio_priv(indio_dev); int i, ret = -1; unsigned long long scale_uv; u32 id; /* reset the serial interface */ - ret = spi_write(st->spi, (u8 *)&ret, sizeof(ret)); + ret = spi_write(st->sd.spi, (u8 *)&ret, sizeof(ret)); if (ret < 0) goto out; msleep(1); /* Wait for at least 500us */ /* write/read test for device presence */ - ret = ad7793_read_reg(st, AD7793_REG_ID, &id, 1); + ret = ad_sd_read_reg(&st->sd, AD7793_REG_ID, 1, &id); if (ret) goto out; id &= AD7793_ID_MASK; - if (!((id == AD7792_ID) || (id == AD7793_ID))) { - dev_err(&st->spi->dev, "device ID query failed\n"); + if (!((id == AD7792_ID) || (id == AD7793_ID) || (id == AD7795_ID))) { + dev_err(&st->sd.spi->dev, "device ID query failed\n"); goto out; } - st->mode = (st->pdata->mode & ~AD7793_MODE_SEL(-1)) | - AD7793_MODE_SEL(AD7793_MODE_IDLE); - st->conf = st->pdata->conf & ~AD7793_CONF_CHAN(-1); + st->mode = pdata->mode; + st->conf = pdata->conf; - ret = ad7793_write_reg(st, AD7793_REG_MODE, sizeof(st->mode), st->mode); + ret = ad7793_set_mode(&st->sd, AD_SD_MODE_IDLE); if (ret) goto out; - ret = ad7793_write_reg(st, AD7793_REG_CONF, sizeof(st->conf), st->conf); + ret = ad7793_set_channel(&st->sd, 0); if (ret) goto out; - ret = ad7793_write_reg(st, AD7793_REG_IO, - sizeof(st->pdata->io), st->pdata->io); + ret = ad_sd_write_reg(&st->sd, AD7793_REG_IO, + sizeof(pdata->io), pdata->io); if (ret) goto out; @@ -301,7 +159,7 @@ static int ad7793_setup(struct ad7793_state *st) /* Populate available ADC input ranges */ for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) { scale_uv = ((u64)st->int_vref_mv * 100000000) - >> (st->chip_info->channel[0].scan_type.realbits - + >> (st->chip_info->channels[0].scan_type.realbits - (!!(st->conf & AD7793_CONF_UNIPOLAR) ? 0 : 1)); scale_uv >>= i; @@ -311,184 +169,10 @@ static int ad7793_setup(struct ad7793_state *st) return 0; out: - dev_err(&st->spi->dev, "setup failed\n"); + dev_err(&st->sd.spi->dev, "setup failed\n"); return ret; } -static int ad7793_ring_preenable(struct iio_dev *indio_dev) -{ - struct ad7793_state *st = iio_priv(indio_dev); - unsigned channel; - int ret; - - if (bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) - return -EINVAL; - ret = iio_sw_buffer_preenable(indio_dev); - if (ret < 0) - return ret; - - channel = find_first_bit(indio_dev->active_scan_mask, - indio_dev->masklength); - - st->mode = (st->mode & ~AD7793_MODE_SEL(-1)) | - AD7793_MODE_SEL(AD7793_MODE_CONT); - st->conf = (st->conf & ~AD7793_CONF_CHAN(-1)) | - AD7793_CONF_CHAN(indio_dev->channels[channel].address); - - ad7793_write_reg(st, AD7793_REG_CONF, sizeof(st->conf), st->conf); - - spi_bus_lock(st->spi->master); - __ad7793_write_reg(st, 1, 1, AD7793_REG_MODE, - sizeof(st->mode), st->mode); - - st->irq_dis = false; - enable_irq(st->spi->irq); - - return 0; -} - -static int ad7793_ring_postdisable(struct iio_dev *indio_dev) -{ - struct ad7793_state *st = iio_priv(indio_dev); - - st->mode = (st->mode & ~AD7793_MODE_SEL(-1)) | - AD7793_MODE_SEL(AD7793_MODE_IDLE); - - st->done = false; - wait_event_interruptible(st->wq_data_avail, st->done); - - if (!st->irq_dis) - disable_irq_nosync(st->spi->irq); - - __ad7793_write_reg(st, 1, 0, AD7793_REG_MODE, - sizeof(st->mode), st->mode); - - return spi_bus_unlock(st->spi->master); -} - -/** - * ad7793_trigger_handler() bh of trigger launched polling to ring buffer - **/ - -static irqreturn_t ad7793_trigger_handler(int irq, void *p) -{ - struct iio_poll_func *pf = p; - struct iio_dev *indio_dev = pf->indio_dev; - struct iio_buffer *ring = indio_dev->buffer; - struct ad7793_state *st = iio_priv(indio_dev); - s64 dat64[2]; - s32 *dat32 = (s32 *)dat64; - - if (!bitmap_empty(indio_dev->active_scan_mask, indio_dev->masklength)) - __ad7793_read_reg(st, 1, 1, AD7793_REG_DATA, - dat32, - indio_dev->channels[0].scan_type.realbits/8); - - /* Guaranteed to be aligned with 8 byte boundary */ - if (indio_dev->scan_timestamp) - dat64[1] = pf->timestamp; - - ring->access->store_to(ring, (u8 *)dat64, pf->timestamp); - - iio_trigger_notify_done(indio_dev->trig); - st->irq_dis = false; - enable_irq(st->spi->irq); - - return IRQ_HANDLED; -} - -static const struct iio_buffer_setup_ops ad7793_ring_setup_ops = { - .preenable = &ad7793_ring_preenable, - .postenable = &iio_triggered_buffer_postenable, - .predisable = &iio_triggered_buffer_predisable, - .postdisable = &ad7793_ring_postdisable, - .validate_scan_mask = &iio_validate_scan_mask_onehot, -}; - -static int ad7793_register_ring_funcs_and_init(struct iio_dev *indio_dev) -{ - return iio_triggered_buffer_setup(indio_dev, &iio_pollfunc_store_time, - &ad7793_trigger_handler, &ad7793_ring_setup_ops); -} - -static void ad7793_ring_cleanup(struct iio_dev *indio_dev) -{ - iio_triggered_buffer_cleanup(indio_dev); -} - -/** - * ad7793_data_rdy_trig_poll() the event handler for the data rdy trig - **/ -static irqreturn_t ad7793_data_rdy_trig_poll(int irq, void *private) -{ - struct ad7793_state *st = iio_priv(private); - - st->done = true; - wake_up_interruptible(&st->wq_data_avail); - disable_irq_nosync(irq); - st->irq_dis = true; - iio_trigger_poll(st->trig, iio_get_time_ns()); - - return IRQ_HANDLED; -} - -static struct iio_trigger_ops ad7793_trigger_ops = { - .owner = THIS_MODULE, -}; - -static int ad7793_probe_trigger(struct iio_dev *indio_dev) -{ - struct ad7793_state *st = iio_priv(indio_dev); - int ret; - - st->trig = iio_trigger_alloc("%s-dev%d", - spi_get_device_id(st->spi)->name, - indio_dev->id); - if (st->trig == NULL) { - ret = -ENOMEM; - goto error_ret; - } - st->trig->ops = &ad7793_trigger_ops; - - ret = request_irq(st->spi->irq, - ad7793_data_rdy_trig_poll, - IRQF_TRIGGER_LOW, - spi_get_device_id(st->spi)->name, - indio_dev); - if (ret) - goto error_free_trig; - - disable_irq_nosync(st->spi->irq); - st->irq_dis = true; - st->trig->dev.parent = &st->spi->dev; - st->trig->private_data = indio_dev; - - ret = iio_trigger_register(st->trig); - - /* select default trigger */ - indio_dev->trig = st->trig; - if (ret) - goto error_free_irq; - - return 0; - -error_free_irq: - free_irq(st->spi->irq, indio_dev); -error_free_trig: - iio_trigger_free(st->trig); -error_ret: - return ret; -} - -static void ad7793_remove_trigger(struct iio_dev *indio_dev) -{ - struct ad7793_state *st = iio_priv(indio_dev); - - iio_trigger_unregister(st->trig); - free_irq(st->spi->irq, indio_dev); - iio_trigger_free(st->trig); -} - static const u16 sample_freq_avail[16] = {0, 470, 242, 123, 62, 50, 39, 33, 19, 17, 16, 12, 10, 8, 6, 4}; @@ -531,7 +215,7 @@ static ssize_t ad7793_write_frequency(struct device *dev, mutex_lock(&indio_dev->mlock); st->mode &= ~AD7793_MODE_RATE(-1); st->mode |= AD7793_MODE_RATE(i); - ad7793_write_reg(st, AD7793_REG_MODE, + ad_sd_write_reg(&st->sd, AD7793_REG_MODE, sizeof(st->mode), st->mode); mutex_unlock(&indio_dev->mlock); ret = 0; @@ -585,26 +269,16 @@ static int ad7793_read_raw(struct iio_dev *indio_dev, long m) { struct ad7793_state *st = iio_priv(indio_dev); - int ret, smpl = 0; + int ret; unsigned long long scale_uv; bool unipolar = !!(st->conf & AD7793_CONF_UNIPOLAR); switch (m) { case IIO_CHAN_INFO_RAW: - mutex_lock(&indio_dev->mlock); - if (iio_buffer_enabled(indio_dev)) - ret = -EBUSY; - else - ret = ad7793_read(st, chan->address, - chan->scan_type.realbits / 8, &smpl); - mutex_unlock(&indio_dev->mlock); - + ret = ad_sigma_delta_single_conversion(indio_dev, chan, val); if (ret < 0) return ret; - *val = (smpl >> chan->scan_type.shift) & - ((1 << (chan->scan_type.realbits)) - 1); - return IIO_VAL_INT; case IIO_CHAN_INFO_SCALE: @@ -675,17 +349,18 @@ static int ad7793_write_raw(struct iio_dev *indio_dev, ret = -EINVAL; for (i = 0; i < ARRAY_SIZE(st->scale_avail); i++) if (val2 == st->scale_avail[i][1]) { + ret = 0; tmp = st->conf; st->conf &= ~AD7793_CONF_GAIN(-1); st->conf |= AD7793_CONF_GAIN(i); - if (tmp != st->conf) { - ad7793_write_reg(st, AD7793_REG_CONF, - sizeof(st->conf), - st->conf); - ad7793_calibrate_all(st); - } - ret = 0; + if (tmp == st->conf) + break; + + ad_sd_write_reg(&st->sd, AD7793_REG_CONF, + sizeof(st->conf), st->conf); + ad7793_calibrate_all(st); + break; } break; default: @@ -696,15 +371,6 @@ static int ad7793_write_raw(struct iio_dev *indio_dev, return ret; } -static int ad7793_validate_trigger(struct iio_dev *indio_dev, - struct iio_trigger *trig) -{ - if (indio_dev->trig != trig) - return -EINVAL; - - return 0; -} - static int ad7793_write_raw_get_fmt(struct iio_dev *indio_dev, struct iio_chan_spec const *chan, long mask) @@ -717,172 +383,67 @@ static const struct iio_info ad7793_info = { .write_raw = &ad7793_write_raw, .write_raw_get_fmt = &ad7793_write_raw_get_fmt, .attrs = &ad7793_attribute_group, - .validate_trigger = ad7793_validate_trigger, + .validate_trigger = ad_sd_validate_trigger, .driver_module = THIS_MODULE, }; +#define DECLARE_AD7793_CHANNELS(_name, _b, _sb, _s) \ +const struct iio_chan_spec _name##_channels[] = { \ + AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), (_s)), \ + AD_SD_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), (_s)), \ + AD_SD_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), (_s)), \ + AD_SD_SHORTED_CHANNEL(3, 0, AD7793_CH_AIN1M_AIN1M, (_b), (_sb), (_s)), \ + AD_SD_TEMP_CHANNEL(4, AD7793_CH_TEMP, (_b), (_sb), (_s)), \ + AD_SD_SUPPLY_CHANNEL(5, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), (_s)), \ + IIO_CHAN_SOFT_TIMESTAMP(6), \ +} + +#define DECLARE_AD7795_CHANNELS(_name, _b, _sb) \ +const struct iio_chan_spec _name##_channels[] = { \ + AD_SD_DIFF_CHANNEL(0, 0, 0, AD7793_CH_AIN1P_AIN1M, (_b), (_sb), 0), \ + AD_SD_DIFF_CHANNEL(1, 1, 1, AD7793_CH_AIN2P_AIN2M, (_b), (_sb), 0), \ + AD_SD_DIFF_CHANNEL(2, 2, 2, AD7793_CH_AIN3P_AIN3M, (_b), (_sb), 0), \ + AD_SD_DIFF_CHANNEL(3, 3, 3, AD7795_CH_AIN4P_AIN4M, (_b), (_sb), 0), \ + AD_SD_DIFF_CHANNEL(4, 4, 4, AD7795_CH_AIN5P_AIN5M, (_b), (_sb), 0), \ + AD_SD_DIFF_CHANNEL(5, 5, 5, AD7795_CH_AIN6P_AIN6M, (_b), (_sb), 0), \ + AD_SD_SHORTED_CHANNEL(6, 0, AD7795_CH_AIN1M_AIN1M, (_b), (_sb), 0), \ + AD_SD_TEMP_CHANNEL(7, AD7793_CH_TEMP, (_b), (_sb), 0), \ + AD_SD_SUPPLY_CHANNEL(8, 3, AD7793_CH_AVDD_MONITOR, (_b), (_sb), 0), \ + IIO_CHAN_SOFT_TIMESTAMP(9), \ +} + +static DECLARE_AD7793_CHANNELS(ad7785, 20, 32, 4); +static DECLARE_AD7793_CHANNELS(ad7792, 16, 32, 0); +static DECLARE_AD7793_CHANNELS(ad7793, 24, 32, 0); +static DECLARE_AD7795_CHANNELS(ad7794, 16, 32); +static DECLARE_AD7795_CHANNELS(ad7795, 24, 32); + static const struct ad7793_chip_info ad7793_chip_info_tbl[] = { - [ID_AD7793] = { - .channel[0] = { - .type = IIO_VOLTAGE, - .differential = 1, - .indexed = 1, - .channel = 0, - .channel2 = 0, - .address = AD7793_CH_AIN1P_AIN1M, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_OFFSET_SHARED_BIT, - .scan_index = 0, - .scan_type = IIO_ST('u', 24, 32, 0) - }, - .channel[1] = { - .type = IIO_VOLTAGE, - .differential = 1, - .indexed = 1, - .channel = 1, - .channel2 = 1, - .address = AD7793_CH_AIN2P_AIN2M, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_OFFSET_SHARED_BIT, - .scan_index = 1, - .scan_type = IIO_ST('u', 24, 32, 0) - }, - .channel[2] = { - .type = IIO_VOLTAGE, - .differential = 1, - .indexed = 1, - .channel = 2, - .channel2 = 2, - .address = AD7793_CH_AIN3P_AIN3M, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_OFFSET_SHARED_BIT, - .scan_index = 2, - .scan_type = IIO_ST('u', 24, 32, 0) - }, - .channel[3] = { - .type = IIO_VOLTAGE, - .differential = 1, - .extend_name = "shorted", - .indexed = 1, - .channel = 2, - .channel2 = 2, - .address = AD7793_CH_AIN1M_AIN1M, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_OFFSET_SHARED_BIT, - .scan_index = 3, - .scan_type = IIO_ST('u', 24, 32, 0) - }, - .channel[4] = { - .type = IIO_TEMP, - .indexed = 1, - .channel = 0, - .address = AD7793_CH_TEMP, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - .scan_index = 4, - .scan_type = IIO_ST('u', 24, 32, 0), - }, - .channel[5] = { - .type = IIO_VOLTAGE, - .extend_name = "supply", - .indexed = 1, - .channel = 4, - .address = AD7793_CH_AVDD_MONITOR, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SEPARATE_BIT | - IIO_CHAN_INFO_OFFSET_SHARED_BIT, - .scan_index = 5, - .scan_type = IIO_ST('u', 24, 32, 0), - }, - .channel[6] = IIO_CHAN_SOFT_TIMESTAMP(6), + [ID_AD7785] = { + .channels = ad7785_channels, + .num_channels = ARRAY_SIZE(ad7785_channels), }, [ID_AD7792] = { - .channel[0] = { - .type = IIO_VOLTAGE, - .differential = 1, - .indexed = 1, - .channel = 0, - .channel2 = 0, - .address = AD7793_CH_AIN1P_AIN1M, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_OFFSET_SHARED_BIT, - .scan_index = 0, - .scan_type = IIO_ST('u', 16, 32, 0) - }, - .channel[1] = { - .type = IIO_VOLTAGE, - .differential = 1, - .indexed = 1, - .channel = 1, - .channel2 = 1, - .address = AD7793_CH_AIN2P_AIN2M, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_OFFSET_SHARED_BIT, - .scan_index = 1, - .scan_type = IIO_ST('u', 16, 32, 0) - }, - .channel[2] = { - .type = IIO_VOLTAGE, - .differential = 1, - .indexed = 1, - .channel = 2, - .channel2 = 2, - .address = AD7793_CH_AIN3P_AIN3M, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_OFFSET_SHARED_BIT, - .scan_index = 2, - .scan_type = IIO_ST('u', 16, 32, 0) - }, - .channel[3] = { - .type = IIO_VOLTAGE, - .differential = 1, - .extend_name = "shorted", - .indexed = 1, - .channel = 2, - .channel2 = 2, - .address = AD7793_CH_AIN1M_AIN1M, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SHARED_BIT | - IIO_CHAN_INFO_OFFSET_SHARED_BIT, - .scan_index = 3, - .scan_type = IIO_ST('u', 16, 32, 0) - }, - .channel[4] = { - .type = IIO_TEMP, - .indexed = 1, - .channel = 0, - .address = AD7793_CH_TEMP, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SEPARATE_BIT, - .scan_index = 4, - .scan_type = IIO_ST('u', 16, 32, 0), - }, - .channel[5] = { - .type = IIO_VOLTAGE, - .extend_name = "supply", - .indexed = 1, - .channel = 4, - .address = AD7793_CH_AVDD_MONITOR, - .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | - IIO_CHAN_INFO_SCALE_SEPARATE_BIT | - IIO_CHAN_INFO_OFFSET_SHARED_BIT, - .scan_index = 5, - .scan_type = IIO_ST('u', 16, 32, 0), - }, - .channel[6] = IIO_CHAN_SOFT_TIMESTAMP(6), + .channels = ad7792_channels, + .num_channels = ARRAY_SIZE(ad7792_channels), + }, + [ID_AD7793] = { + .channels = ad7793_channels, + .num_channels = ARRAY_SIZE(ad7793_channels), + }, + [ID_AD7794] = { + .channels = ad7794_channels, + .num_channels = ARRAY_SIZE(ad7794_channels), + }, + [ID_AD7795] = { + .channels = ad7795_channels, + .num_channels = ARRAY_SIZE(ad7795_channels), }, }; static int __devinit ad7793_probe(struct spi_device *spi) { - struct ad7793_platform_data *pdata = spi->dev.platform_data; + const struct ad7793_platform_data *pdata = spi->dev.platform_data; struct ad7793_state *st; struct iio_dev *indio_dev; int ret, voltage_uv = 0; @@ -903,6 +464,8 @@ static int __devinit ad7793_probe(struct spi_device *spi) st = iio_priv(indio_dev); + ad_sd_init(&st->sd, indio_dev, spi, &ad7793_sigma_delta_info); + st->reg = regulator_get(&spi->dev, "vcc"); if (!IS_ERR(st->reg)) { ret = regulator_enable(st->reg); @@ -915,8 +478,6 @@ static int __devinit ad7793_probe(struct spi_device *spi) st->chip_info = &ad7793_chip_info_tbl[spi_get_device_id(spi)->driver_data]; - st->pdata = pdata; - if (pdata && pdata->vref_mv) st->int_vref_mv = pdata->vref_mv; else if (voltage_uv) @@ -925,26 +486,19 @@ static int __devinit ad7793_probe(struct spi_device *spi) st->int_vref_mv = 1170; /* Build-in ref */ spi_set_drvdata(spi, indio_dev); - st->spi = spi; indio_dev->dev.parent = &spi->dev; indio_dev->name = spi_get_device_id(spi)->name; indio_dev->modes = INDIO_DIRECT_MODE; - indio_dev->channels = st->chip_info->channel; - indio_dev->num_channels = 7; + indio_dev->channels = st->chip_info->channels; + indio_dev->num_channels = st->chip_info->num_channels; indio_dev->info = &ad7793_info; - init_waitqueue_head(&st->wq_data_avail); - - ret = ad7793_register_ring_funcs_and_init(indio_dev); + ret = ad_sd_setup_buffer_and_trigger(indio_dev); if (ret) goto error_disable_reg; - ret = ad7793_probe_trigger(indio_dev); - if (ret) - goto error_unreg_ring; - - ret = ad7793_setup(st); + ret = ad7793_setup(indio_dev, pdata); if (ret) goto error_remove_trigger; @@ -955,9 +509,7 @@ static int __devinit ad7793_probe(struct spi_device *spi) return 0; error_remove_trigger: - ad7793_remove_trigger(indio_dev); -error_unreg_ring: - ad7793_ring_cleanup(indio_dev); + ad_sd_cleanup_buffer_and_trigger(indio_dev); error_disable_reg: if (!IS_ERR(st->reg)) regulator_disable(st->reg); @@ -970,14 +522,13 @@ error_put_reg: return ret; } -static int ad7793_remove(struct spi_device *spi) +static int __devexit ad7793_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct ad7793_state *st = iio_priv(indio_dev); iio_device_unregister(indio_dev); - ad7793_remove_trigger(indio_dev); - ad7793_ring_cleanup(indio_dev); + ad_sd_cleanup_buffer_and_trigger(indio_dev); if (!IS_ERR(st->reg)) { regulator_disable(st->reg); @@ -990,8 +541,11 @@ static int ad7793_remove(struct spi_device *spi) } static const struct spi_device_id ad7793_id[] = { + {"ad7785", ID_AD7785}, {"ad7792", ID_AD7792}, {"ad7793", ID_AD7793}, + {"ad7794", ID_AD7794}, + {"ad7795", ID_AD7795}, {} }; MODULE_DEVICE_TABLE(spi, ad7793_id); @@ -1008,5 +562,5 @@ static struct spi_driver ad7793_driver = { module_spi_driver(ad7793_driver); MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>"); -MODULE_DESCRIPTION("Analog Devices AD7792/3 ADC"); +MODULE_DESCRIPTION("Analog Devices AD7793 and simialr ADCs"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/adc/ad7793.h b/drivers/staging/iio/adc/ad7793.h index 64f7d41dc453..8fdd450a2cd9 100644 --- a/drivers/staging/iio/adc/ad7793.h +++ b/drivers/staging/iio/adc/ad7793.h @@ -41,6 +41,7 @@ /* Mode Register Bit Designations (AD7793_REG_MODE) */ #define AD7793_MODE_SEL(x) (((x) & 0x7) << 13) /* Operation Mode Select */ +#define AD7793_MODE_SEL_MASK (0x7 << 13) /* Operation Mode Select mask */ #define AD7793_MODE_CLKSRC(x) (((x) & 0x3) << 6) /* ADC Clock Source Select */ #define AD7793_MODE_RATE(x) ((x) & 0xF) /* Filter Update Rate Select */ @@ -69,7 +70,8 @@ #define AD7793_CONF_GAIN(x) (((x) & 0x7) << 8) /* Gain Select */ #define AD7793_CONF_REFSEL (1 << 7) /* INT/EXT Reference Select */ #define AD7793_CONF_BUF (1 << 4) /* Buffered Mode Enable */ -#define AD7793_CONF_CHAN(x) ((x) & 0x7) /* Channel select */ +#define AD7793_CONF_CHAN(x) ((x) & 0xf) /* Channel select */ +#define AD7793_CONF_CHAN_MASK 0xf /* Channel select mask */ #define AD7793_CH_AIN1P_AIN1M 0 /* AIN1(+) - AIN1(-) */ #define AD7793_CH_AIN2P_AIN2M 1 /* AIN2(+) - AIN2(-) */ @@ -78,9 +80,15 @@ #define AD7793_CH_TEMP 6 /* Temp Sensor */ #define AD7793_CH_AVDD_MONITOR 7 /* AVDD Monitor */ +#define AD7795_CH_AIN4P_AIN4M 4 /* AIN4(+) - AIN4(-) */ +#define AD7795_CH_AIN5P_AIN5M 5 /* AIN5(+) - AIN5(-) */ +#define AD7795_CH_AIN6P_AIN6M 6 /* AIN6(+) - AIN6(-) */ +#define AD7795_CH_AIN1M_AIN1M 8 /* AIN1(-) - AIN1(-) */ + /* ID Register Bit Designations (AD7793_REG_ID) */ #define AD7792_ID 0xA #define AD7793_ID 0xB +#define AD7795_ID 0xF #define AD7793_ID_MASK 0xF /* IO (Excitation Current Sources) Register Bit Designations (AD7793_REG_IO) */ diff --git a/drivers/staging/iio/adc/ad7887_core.c b/drivers/staging/iio/adc/ad7887_core.c index 397b84947155..551790584a12 100644 --- a/drivers/staging/iio/adc/ad7887_core.c +++ b/drivers/staging/iio/adc/ad7887_core.c @@ -219,7 +219,7 @@ error_put_reg: return ret; } -static int ad7887_remove(struct spi_device *spi) +static int __devexit ad7887_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct ad7887_state *st = iio_priv(indio_dev); diff --git a/drivers/staging/iio/adc/ad7887_ring.c b/drivers/staging/iio/adc/ad7887_ring.c index c76fdb5081c2..b39923bbeedc 100644 --- a/drivers/staging/iio/adc/ad7887_ring.c +++ b/drivers/staging/iio/adc/ad7887_ring.c @@ -95,7 +95,7 @@ static irqreturn_t ad7887_trigger_handler(int irq, void *p) memcpy(buf + indio_dev->scan_bytes - sizeof(s64), &time_ns, sizeof(time_ns)); - indio_dev->buffer->access->store_to(indio_dev->buffer, buf, time_ns); + iio_push_to_buffer(indio_dev->buffer, buf); done: kfree(buf); iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/staging/iio/adc/ad799x_ring.c b/drivers/staging/iio/adc/ad799x_ring.c index 858a685e3889..86026d9b20bc 100644 --- a/drivers/staging/iio/adc/ad799x_ring.c +++ b/drivers/staging/iio/adc/ad799x_ring.c @@ -35,7 +35,6 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct ad799x_state *st = iio_priv(indio_dev); - struct iio_buffer *ring = indio_dev->buffer; s64 time_ns; __u8 *rxbuf; int b_sent; @@ -78,7 +77,7 @@ static irqreturn_t ad799x_trigger_handler(int irq, void *p) memcpy(rxbuf + indio_dev->scan_bytes - sizeof(s64), &time_ns, sizeof(time_ns)); - ring->access->store_to(indio_dev->buffer, rxbuf, time_ns); + iio_push_to_buffer(indio_dev->buffer, rxbuf); done: kfree(rxbuf); out: diff --git a/drivers/staging/iio/adc/lpc32xx_adc.c b/drivers/staging/iio/adc/lpc32xx_adc.c index 348d051fc2f8..7e9bd0001cc7 100644 --- a/drivers/staging/iio/adc/lpc32xx_adc.c +++ b/drivers/staging/iio/adc/lpc32xx_adc.c @@ -108,7 +108,7 @@ static const struct iio_info lpc32xx_adc_iio_info = { .scan_index = _index, \ } -static struct iio_chan_spec lpc32xx_adc_iio_channels[] = { +static const struct iio_chan_spec lpc32xx_adc_iio_channels[] = { LPC32XX_ADC_CHANNEL(0), LPC32XX_ADC_CHANNEL(1), LPC32XX_ADC_CHANNEL(2), diff --git a/drivers/staging/iio/adc/max1363.h b/drivers/staging/iio/adc/max1363.h index 2cd0112067b2..c746918683f1 100644 --- a/drivers/staging/iio/adc/max1363.h +++ b/drivers/staging/iio/adc/max1363.h @@ -100,7 +100,7 @@ enum max1363_modes { */ struct max1363_chip_info { const struct iio_info *info; - struct iio_chan_spec *channels; + const struct iio_chan_spec *channels; int num_channels; const enum max1363_modes *mode_list; enum max1363_modes default_mode; diff --git a/drivers/staging/iio/adc/max1363_core.c b/drivers/staging/iio/adc/max1363_core.c index 6799ce23a395..d7b4ffcfa052 100644 --- a/drivers/staging/iio/adc/max1363_core.c +++ b/drivers/staging/iio/adc/max1363_core.c @@ -335,12 +335,12 @@ static const enum max1363_modes max1363_mode_list[] = { IIO_CHAN_SOFT_TIMESTAMP(8) \ } -static struct iio_chan_spec max1036_channels[] = MAX1363_4X_CHANS(8, 0); -static struct iio_chan_spec max1136_channels[] = MAX1363_4X_CHANS(10, 0); -static struct iio_chan_spec max1236_channels[] = MAX1363_4X_CHANS(12, 0); -static struct iio_chan_spec max1361_channels[] = +static const struct iio_chan_spec max1036_channels[] = MAX1363_4X_CHANS(8, 0); +static const struct iio_chan_spec max1136_channels[] = MAX1363_4X_CHANS(10, 0); +static const struct iio_chan_spec max1236_channels[] = MAX1363_4X_CHANS(12, 0); +static const struct iio_chan_spec max1361_channels[] = MAX1363_4X_CHANS(10, MAX1363_EV_M); -static struct iio_chan_spec max1363_channels[] = +static const struct iio_chan_spec max1363_channels[] = MAX1363_4X_CHANS(12, MAX1363_EV_M); /* Applies to max1236, max1237 */ @@ -392,9 +392,9 @@ static const enum max1363_modes max1238_mode_list[] = { MAX1363_CHAN_B(11, 10, d11m10, 23, bits, 0), \ IIO_CHAN_SOFT_TIMESTAMP(24) \ } -static struct iio_chan_spec max1038_channels[] = MAX1363_12X_CHANS(8); -static struct iio_chan_spec max1138_channels[] = MAX1363_12X_CHANS(10); -static struct iio_chan_spec max1238_channels[] = MAX1363_12X_CHANS(12); +static const struct iio_chan_spec max1038_channels[] = MAX1363_12X_CHANS(8); +static const struct iio_chan_spec max1138_channels[] = MAX1363_12X_CHANS(10); +static const struct iio_chan_spec max1238_channels[] = MAX1363_12X_CHANS(12); static const enum max1363_modes max11607_mode_list[] = { _s0, _s1, _s2, _s3, @@ -433,9 +433,9 @@ static const enum max1363_modes max11608_mode_list[] = { MAX1363_CHAN_B(7, 6, d7m6, 15, bits, 0), \ IIO_CHAN_SOFT_TIMESTAMP(16) \ } -static struct iio_chan_spec max11602_channels[] = MAX1363_8X_CHANS(8); -static struct iio_chan_spec max11608_channels[] = MAX1363_8X_CHANS(10); -static struct iio_chan_spec max11614_channels[] = MAX1363_8X_CHANS(12); +static const struct iio_chan_spec max11602_channels[] = MAX1363_8X_CHANS(8); +static const struct iio_chan_spec max11608_channels[] = MAX1363_8X_CHANS(10); +static const struct iio_chan_spec max11614_channels[] = MAX1363_8X_CHANS(12); static const enum max1363_modes max11644_mode_list[] = { _s0, _s1, s0to1, d0m1, d1m0, @@ -449,8 +449,8 @@ static const enum max1363_modes max11644_mode_list[] = { IIO_CHAN_SOFT_TIMESTAMP(4) \ } -static struct iio_chan_spec max11646_channels[] = MAX1363_2X_CHANS(10); -static struct iio_chan_spec max11644_channels[] = MAX1363_2X_CHANS(12); +static const struct iio_chan_spec max11646_channels[] = MAX1363_2X_CHANS(10); +static const struct iio_chan_spec max11644_channels[] = MAX1363_2X_CHANS(12); enum { max1361, max1362, @@ -1367,7 +1367,7 @@ error_out: return ret; } -static int max1363_remove(struct i2c_client *client) +static int __devexit max1363_remove(struct i2c_client *client) { struct iio_dev *indio_dev = i2c_get_clientdata(client); struct max1363_state *st = iio_priv(indio_dev); @@ -1434,11 +1434,11 @@ static struct i2c_driver max1363_driver = { .name = "max1363", }, .probe = max1363_probe, - .remove = max1363_remove, + .remove = __devexit_p(max1363_remove), .id_table = max1363_id, }; module_i2c_driver(max1363_driver); -MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>"); +MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); MODULE_DESCRIPTION("Maxim 1363 ADC"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/adc/max1363_ring.c b/drivers/staging/iio/adc/max1363_ring.c index 774ae1b63550..5f74f3b7671a 100644 --- a/drivers/staging/iio/adc/max1363_ring.c +++ b/drivers/staging/iio/adc/max1363_ring.c @@ -80,7 +80,7 @@ static irqreturn_t max1363_trigger_handler(int irq, void *p) if (indio_dev->scan_timestamp) memcpy(rxbuf + d_size - sizeof(s64), &time_ns, sizeof(time_ns)); - iio_push_to_buffer(indio_dev->buffer, rxbuf, time_ns); + iio_push_to_buffer(indio_dev->buffer, rxbuf); done_free: kfree(rxbuf); diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c new file mode 100644 index 000000000000..ca7c1fa88e71 --- /dev/null +++ b/drivers/staging/iio/adc/mxs-lradc.c @@ -0,0 +1,590 @@ +/* + * Freescale i.MX28 LRADC driver + * + * Copyright (c) 2012 DENX Software Engineering, GmbH. + * Marek Vasut <marex@denx.de> + * + * 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/interrupt.h> +#include <linux/device.h> +#include <linux/kernel.h> +#include <linux/slab.h> +#include <linux/of.h> +#include <linux/of_device.h> +#include <linux/sysfs.h> +#include <linux/list.h> +#include <linux/io.h> +#include <linux/module.h> +#include <linux/platform_device.h> +#include <linux/spinlock.h> +#include <linux/wait.h> +#include <linux/sched.h> +#include <linux/stmp_device.h> +#include <linux/bitops.h> +#include <linux/completion.h> + +#include <mach/mxs.h> +#include <mach/common.h> + +#include <linux/iio/iio.h> +#include <linux/iio/buffer.h> +#include <linux/iio/trigger.h> +#include <linux/iio/trigger_consumer.h> +#include <linux/iio/triggered_buffer.h> + +#define DRIVER_NAME "mxs-lradc" + +#define LRADC_MAX_DELAY_CHANS 4 +#define LRADC_MAX_MAPPED_CHANS 8 +#define LRADC_MAX_TOTAL_CHANS 16 + +#define LRADC_DELAY_TIMER_HZ 2000 + +/* + * Make this runtime configurable if necessary. Currently, if the buffered mode + * is enabled, the LRADC takes LRADC_DELAY_TIMER_LOOP samples of data before + * triggering IRQ. The sampling happens every (LRADC_DELAY_TIMER_PER / 2000) + * seconds. The result is that the samples arrive every 500mS. + */ +#define LRADC_DELAY_TIMER_PER 200 +#define LRADC_DELAY_TIMER_LOOP 5 + +static const char * const mxs_lradc_irq_name[] = { + "mxs-lradc-touchscreen", + "mxs-lradc-thresh0", + "mxs-lradc-thresh1", + "mxs-lradc-channel0", + "mxs-lradc-channel1", + "mxs-lradc-channel2", + "mxs-lradc-channel3", + "mxs-lradc-channel4", + "mxs-lradc-channel5", + "mxs-lradc-channel6", + "mxs-lradc-channel7", + "mxs-lradc-button0", + "mxs-lradc-button1", +}; + +struct mxs_lradc_chan { + uint8_t slot; + uint8_t flags; +}; + +struct mxs_lradc { + struct device *dev; + void __iomem *base; + int irq[13]; + + uint32_t *buffer; + struct iio_trigger *trig; + + struct mutex lock; + + uint8_t enable; + + struct completion completion; +}; + +#define LRADC_CTRL0 0x00 +#define LRADC_CTRL0_TOUCH_DETECT_ENABLE (1 << 23) +#define LRADC_CTRL0_TOUCH_SCREEN_TYPE (1 << 22) + +#define LRADC_CTRL1 0x10 +#define LRADC_CTRL1_LRADC_IRQ(n) (1 << (n)) +#define LRADC_CTRL1_LRADC_IRQ_MASK 0x1fff +#define LRADC_CTRL1_LRADC_IRQ_EN(n) (1 << ((n) + 16)) +#define LRADC_CTRL1_LRADC_IRQ_EN_MASK (0x1fff << 16) + +#define LRADC_CTRL2 0x20 +#define LRADC_CTRL2_TEMPSENSE_PWD (1 << 15) + +#define LRADC_CH(n) (0x50 + (0x10 * (n))) +#define LRADC_CH_ACCUMULATE (1 << 29) +#define LRADC_CH_NUM_SAMPLES_MASK (0x1f << 24) +#define LRADC_CH_NUM_SAMPLES_OFFSET 24 +#define LRADC_CH_VALUE_MASK 0x3ffff +#define LRADC_CH_VALUE_OFFSET 0 + +#define LRADC_DELAY(n) (0xd0 + (0x10 * (n))) +#define LRADC_DELAY_TRIGGER_LRADCS_MASK (0xff << 24) +#define LRADC_DELAY_TRIGGER_LRADCS_OFFSET 24 +#define LRADC_DELAY_KICK (1 << 20) +#define LRADC_DELAY_TRIGGER_DELAYS_MASK (0xf << 16) +#define LRADC_DELAY_TRIGGER_DELAYS_OFFSET 16 +#define LRADC_DELAY_LOOP_COUNT_MASK (0x1f << 11) +#define LRADC_DELAY_LOOP_COUNT_OFFSET 11 +#define LRADC_DELAY_DELAY_MASK 0x7ff +#define LRADC_DELAY_DELAY_OFFSET 0 + +#define LRADC_CTRL4 0x140 +#define LRADC_CTRL4_LRADCSELECT_MASK(n) (0xf << ((n) * 4)) +#define LRADC_CTRL4_LRADCSELECT_OFFSET(n) ((n) * 4) + +/* + * Raw I/O operations + */ +static int mxs_lradc_read_raw(struct iio_dev *iio_dev, + const struct iio_chan_spec *chan, + int *val, int *val2, long m) +{ + struct mxs_lradc *lradc = iio_priv(iio_dev); + int ret; + + if (m != IIO_CHAN_INFO_RAW) + return -EINVAL; + + /* Check for invalid channel */ + if (chan->channel > LRADC_MAX_TOTAL_CHANS) + return -EINVAL; + + /* + * See if there is no buffered operation in progess. If there is, simply + * bail out. This can be improved to support both buffered and raw IO at + * the same time, yet the code becomes horribly complicated. Therefore I + * applied KISS principle here. + */ + ret = mutex_trylock(&lradc->lock); + if (!ret) + return -EBUSY; + + INIT_COMPLETION(lradc->completion); + + /* + * No buffered operation in progress, map the channel and trigger it. + * Virtual channel 0 is always used here as the others are always not + * used if doing raw sampling. + */ + writel(LRADC_CTRL1_LRADC_IRQ_EN_MASK, + lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); + writel(0xff, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); + + writel(chan->channel, lradc->base + LRADC_CTRL4); + writel(0, lradc->base + LRADC_CH(0)); + + /* Enable the IRQ and start sampling the channel. */ + writel(LRADC_CTRL1_LRADC_IRQ_EN(0), + lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET); + writel(1 << 0, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_SET); + + /* Wait for completion on the channel, 1 second max. */ + ret = wait_for_completion_killable_timeout(&lradc->completion, HZ); + if (!ret) + ret = -ETIMEDOUT; + if (ret < 0) + goto err; + + /* Read the data. */ + *val = readl(lradc->base + LRADC_CH(0)) & LRADC_CH_VALUE_MASK; + ret = IIO_VAL_INT; + +err: + writel(LRADC_CTRL1_LRADC_IRQ_EN(0), + lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); + + mutex_unlock(&lradc->lock); + + return ret; +} + +static const struct iio_info mxs_lradc_iio_info = { + .driver_module = THIS_MODULE, + .read_raw = mxs_lradc_read_raw, +}; + +/* + * IRQ Handling + */ +static irqreturn_t mxs_lradc_handle_irq(int irq, void *data) +{ + struct iio_dev *iio = data; + struct mxs_lradc *lradc = iio_priv(iio); + unsigned long reg = readl(lradc->base + LRADC_CTRL1); + + if (!(reg & LRADC_CTRL1_LRADC_IRQ_MASK)) + return IRQ_NONE; + + /* + * Touchscreen IRQ handling code shall probably have priority + * and therefore shall be placed here. + */ + + if (iio_buffer_enabled(iio)) + iio_trigger_poll(iio->trig, iio_get_time_ns()); + else if (reg & LRADC_CTRL1_LRADC_IRQ(0)) + complete(&lradc->completion); + + writel(reg & LRADC_CTRL1_LRADC_IRQ_MASK, + lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); + + return IRQ_HANDLED; +} + +/* + * Trigger handling + */ +static irqreturn_t mxs_lradc_trigger_handler(int irq, void *p) +{ + struct iio_poll_func *pf = p; + struct iio_dev *iio = pf->indio_dev; + struct mxs_lradc *lradc = iio_priv(iio); + struct iio_buffer *buffer = iio->buffer; + const uint32_t chan_value = LRADC_CH_ACCUMULATE | + ((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET); + int i, j = 0; + + for_each_set_bit(i, iio->active_scan_mask, iio->masklength) { + lradc->buffer[j] = readl(lradc->base + LRADC_CH(j)); + writel(chan_value, lradc->base + LRADC_CH(j)); + lradc->buffer[j] &= LRADC_CH_VALUE_MASK; + lradc->buffer[j] /= LRADC_DELAY_TIMER_LOOP; + j++; + } + + if (iio->scan_timestamp) { + s64 *timestamp = (s64 *)((u8 *)lradc->buffer + + ALIGN(j, sizeof(s64))); + *timestamp = pf->timestamp; + } + + iio_push_to_buffer(buffer, (u8 *)lradc->buffer); + + iio_trigger_notify_done(iio->trig); + + return IRQ_HANDLED; +} + +static int mxs_lradc_configure_trigger(struct iio_trigger *trig, bool state) +{ + struct iio_dev *iio = trig->private_data; + struct mxs_lradc *lradc = iio_priv(iio); + const uint32_t st = state ? STMP_OFFSET_REG_SET : STMP_OFFSET_REG_CLR; + + writel(LRADC_DELAY_KICK, lradc->base + LRADC_DELAY(0) + st); + + return 0; +} + +static const struct iio_trigger_ops mxs_lradc_trigger_ops = { + .owner = THIS_MODULE, + .set_trigger_state = &mxs_lradc_configure_trigger, +}; + +static int mxs_lradc_trigger_init(struct iio_dev *iio) +{ + int ret; + struct iio_trigger *trig; + + trig = iio_trigger_alloc("%s-dev%i", iio->name, iio->id); + if (trig == NULL) + return -ENOMEM; + + trig->dev.parent = iio->dev.parent; + trig->private_data = iio; + trig->ops = &mxs_lradc_trigger_ops; + + ret = iio_trigger_register(trig); + if (ret) { + iio_trigger_free(trig); + return ret; + } + + iio->trig = trig; + + return 0; +} + +static void mxs_lradc_trigger_remove(struct iio_dev *iio) +{ + iio_trigger_unregister(iio->trig); + iio_trigger_free(iio->trig); +} + +static int mxs_lradc_buffer_preenable(struct iio_dev *iio) +{ + struct mxs_lradc *lradc = iio_priv(iio); + struct iio_buffer *buffer = iio->buffer; + int ret = 0, chan, ofs = 0, enable = 0; + uint32_t ctrl4 = 0; + uint32_t ctrl1_irq = 0; + const uint32_t chan_value = LRADC_CH_ACCUMULATE | + ((LRADC_DELAY_TIMER_LOOP - 1) << LRADC_CH_NUM_SAMPLES_OFFSET); + const int len = bitmap_weight(buffer->scan_mask, LRADC_MAX_TOTAL_CHANS); + + if (!len) + return -EINVAL; + + /* + * Lock the driver so raw access can not be done during buffered + * operation. This simplifies the code a lot. + */ + ret = mutex_trylock(&lradc->lock); + if (!ret) + return -EBUSY; + + lradc->buffer = kmalloc(len * sizeof(*lradc->buffer), GFP_KERNEL); + if (!lradc->buffer) { + ret = -ENOMEM; + goto err_mem; + } + + ret = iio_sw_buffer_preenable(iio); + if (ret < 0) + goto err_buf; + + writel(LRADC_CTRL1_LRADC_IRQ_EN_MASK, + lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); + writel(0xff, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); + + for_each_set_bit(chan, buffer->scan_mask, LRADC_MAX_TOTAL_CHANS) { + ctrl4 |= chan << LRADC_CTRL4_LRADCSELECT_OFFSET(ofs); + ctrl1_irq |= LRADC_CTRL1_LRADC_IRQ_EN(ofs); + writel(chan_value, lradc->base + LRADC_CH(ofs)); + enable |= 1 << ofs; + ofs++; + }; + + writel(LRADC_DELAY_TRIGGER_LRADCS_MASK | LRADC_DELAY_KICK, + lradc->base + LRADC_DELAY(0) + STMP_OFFSET_REG_CLR); + + writel(ctrl4, lradc->base + LRADC_CTRL4); + writel(ctrl1_irq, lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_SET); + + writel(enable << LRADC_DELAY_TRIGGER_LRADCS_OFFSET, + lradc->base + LRADC_DELAY(0) + STMP_OFFSET_REG_SET); + + return 0; + +err_buf: + kfree(lradc->buffer); +err_mem: + mutex_unlock(&lradc->lock); + return ret; +} + +static int mxs_lradc_buffer_postdisable(struct iio_dev *iio) +{ + struct mxs_lradc *lradc = iio_priv(iio); + + writel(LRADC_DELAY_TRIGGER_LRADCS_MASK | LRADC_DELAY_KICK, + lradc->base + LRADC_DELAY(0) + STMP_OFFSET_REG_CLR); + + writel(0xff, lradc->base + LRADC_CTRL0 + STMP_OFFSET_REG_CLR); + writel(LRADC_CTRL1_LRADC_IRQ_EN_MASK, + lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); + + kfree(lradc->buffer); + mutex_unlock(&lradc->lock); + + return 0; +} + +static bool mxs_lradc_validate_scan_mask(struct iio_dev *iio, + const unsigned long *mask) +{ + const int mw = bitmap_weight(mask, iio->masklength); + + return mw <= LRADC_MAX_MAPPED_CHANS; +} + +static const struct iio_buffer_setup_ops mxs_lradc_buffer_ops = { + .preenable = &mxs_lradc_buffer_preenable, + .postenable = &iio_triggered_buffer_postenable, + .predisable = &iio_triggered_buffer_predisable, + .postdisable = &mxs_lradc_buffer_postdisable, + .validate_scan_mask = &mxs_lradc_validate_scan_mask, +}; + +/* + * Driver initialization + */ + +#define MXS_ADC_CHAN(idx, chan_type) { \ + .type = (chan_type), \ + .indexed = 1, \ + .scan_index = (idx), \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT, \ + .channel = (idx), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = 18, \ + .storagebits = 32, \ + }, \ +} + +static const struct iio_chan_spec mxs_lradc_chan_spec[] = { + MXS_ADC_CHAN(0, IIO_VOLTAGE), + MXS_ADC_CHAN(1, IIO_VOLTAGE), + MXS_ADC_CHAN(2, IIO_VOLTAGE), + MXS_ADC_CHAN(3, IIO_VOLTAGE), + MXS_ADC_CHAN(4, IIO_VOLTAGE), + MXS_ADC_CHAN(5, IIO_VOLTAGE), + MXS_ADC_CHAN(6, IIO_VOLTAGE), + MXS_ADC_CHAN(7, IIO_VOLTAGE), /* VBATT */ + MXS_ADC_CHAN(8, IIO_TEMP), /* Temp sense 0 */ + MXS_ADC_CHAN(9, IIO_TEMP), /* Temp sense 1 */ + MXS_ADC_CHAN(10, IIO_VOLTAGE), /* VDDIO */ + MXS_ADC_CHAN(11, IIO_VOLTAGE), /* VTH */ + MXS_ADC_CHAN(12, IIO_VOLTAGE), /* VDDA */ + MXS_ADC_CHAN(13, IIO_VOLTAGE), /* VDDD */ + MXS_ADC_CHAN(14, IIO_VOLTAGE), /* VBG */ + MXS_ADC_CHAN(15, IIO_VOLTAGE), /* VDD5V */ +}; + +static void mxs_lradc_hw_init(struct mxs_lradc *lradc) +{ + int i; + const uint32_t cfg = + (LRADC_DELAY_TIMER_PER << LRADC_DELAY_DELAY_OFFSET); + + stmp_reset_block(lradc->base); + + for (i = 0; i < LRADC_MAX_DELAY_CHANS; i++) + writel(cfg | (1 << (LRADC_DELAY_TRIGGER_DELAYS_OFFSET + i)), + lradc->base + LRADC_DELAY(i)); + + /* Start internal temperature sensing. */ + writel(0, lradc->base + LRADC_CTRL2); +} + +static void mxs_lradc_hw_stop(struct mxs_lradc *lradc) +{ + int i; + + writel(LRADC_CTRL1_LRADC_IRQ_EN_MASK, + lradc->base + LRADC_CTRL1 + STMP_OFFSET_REG_CLR); + + for (i = 0; i < LRADC_MAX_DELAY_CHANS; i++) + writel(0, lradc->base + LRADC_DELAY(i)); +} + +static int __devinit mxs_lradc_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mxs_lradc *lradc; + struct iio_dev *iio; + struct resource *iores; + int ret = 0; + int i; + + /* Allocate the IIO device. */ + iio = iio_device_alloc(sizeof(*lradc)); + if (!iio) { + dev_err(dev, "Failed to allocate IIO device\n"); + return -ENOMEM; + } + + lradc = iio_priv(iio); + + /* Grab the memory area */ + iores = platform_get_resource(pdev, IORESOURCE_MEM, 0); + lradc->dev = &pdev->dev; + lradc->base = devm_request_and_ioremap(dev, iores); + if (!lradc->base) { + ret = -EADDRNOTAVAIL; + goto err_addr; + } + + /* Grab all IRQ sources */ + for (i = 0; i < 13; i++) { + lradc->irq[i] = platform_get_irq(pdev, i); + if (lradc->irq[i] < 0) { + ret = -EINVAL; + goto err_addr; + } + + ret = devm_request_irq(dev, lradc->irq[i], + mxs_lradc_handle_irq, 0, + mxs_lradc_irq_name[i], iio); + if (ret) + goto err_addr; + } + + platform_set_drvdata(pdev, iio); + + init_completion(&lradc->completion); + mutex_init(&lradc->lock); + + iio->name = pdev->name; + iio->dev.parent = &pdev->dev; + iio->info = &mxs_lradc_iio_info; + iio->modes = INDIO_DIRECT_MODE; + iio->channels = mxs_lradc_chan_spec; + iio->num_channels = ARRAY_SIZE(mxs_lradc_chan_spec); + + ret = iio_triggered_buffer_setup(iio, &iio_pollfunc_store_time, + &mxs_lradc_trigger_handler, + &mxs_lradc_buffer_ops); + if (ret) + goto err_addr; + + ret = mxs_lradc_trigger_init(iio); + if (ret) + goto err_trig; + + /* Register IIO device. */ + ret = iio_device_register(iio); + if (ret) { + dev_err(dev, "Failed to register IIO device\n"); + goto err_dev; + } + + /* Configure the hardware. */ + mxs_lradc_hw_init(lradc); + + return 0; + +err_dev: + mxs_lradc_trigger_remove(iio); +err_trig: + iio_triggered_buffer_cleanup(iio); +err_addr: + iio_device_free(iio); + return ret; +} + +static int __devexit mxs_lradc_remove(struct platform_device *pdev) +{ + struct iio_dev *iio = platform_get_drvdata(pdev); + struct mxs_lradc *lradc = iio_priv(iio); + + mxs_lradc_hw_stop(lradc); + + iio_device_unregister(iio); + iio_triggered_buffer_cleanup(iio); + mxs_lradc_trigger_remove(iio); + iio_device_free(iio); + + return 0; +} + +static const struct of_device_id mxs_lradc_dt_ids[] = { + { .compatible = "fsl,imx28-lradc", }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, mxs_lradc_dt_ids); + +static struct platform_driver mxs_lradc_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = mxs_lradc_dt_ids, + }, + .probe = mxs_lradc_probe, + .remove = __devexit_p(mxs_lradc_remove), +}; + +module_platform_driver(mxs_lradc_driver); + +MODULE_AUTHOR("Marek Vasut <marex@denx.de>"); +MODULE_DESCRIPTION("Freescale i.MX28 LRADC driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/adc/spear_adc.c b/drivers/staging/iio/adc/spear_adc.c index 64d630e6fe29..0b83e2e1f410 100644 --- a/drivers/staging/iio/adc/spear_adc.c +++ b/drivers/staging/iio/adc/spear_adc.c @@ -189,7 +189,7 @@ static int spear_read_raw(struct iio_dev *indio_dev, }, \ } -static struct iio_chan_spec spear_adc_iio_channels[] = { +static const struct iio_chan_spec spear_adc_iio_channels[] = { SPEAR_ADC_CHAN(0), SPEAR_ADC_CHAN(1), SPEAR_ADC_CHAN(2), @@ -330,36 +330,30 @@ static int __devinit spear_adc_probe(struct platform_device *pdev) goto errout3; } - ret = clk_prepare(info->clk); - if (ret) { - dev_err(dev, "failed preparing clock\n"); - goto errout4; - } - - ret = clk_enable(info->clk); + ret = clk_prepare_enable(info->clk); if (ret) { dev_err(dev, "failed enabling clock\n"); - goto errout5; + goto errout4; } irq = platform_get_irq(pdev, 0); if ((irq < 0) || (irq >= NR_IRQS)) { dev_err(dev, "failed getting interrupt resource\n"); ret = -EINVAL; - goto errout6; + goto errout5; } ret = devm_request_irq(dev, irq, spear_adc_isr, 0, MOD_NAME, info); if (ret < 0) { dev_err(dev, "failed requesting interrupt\n"); - goto errout6; + goto errout5; } if (of_property_read_u32(np, "sampling-frequency", &info->sampling_freq)) { dev_err(dev, "sampling-frequency missing in DT\n"); ret = -EINVAL; - goto errout6; + goto errout5; } /* @@ -389,16 +383,14 @@ static int __devinit spear_adc_probe(struct platform_device *pdev) ret = iio_device_register(iodev); if (ret) - goto errout6; + goto errout5; dev_info(dev, "SPEAR ADC driver loaded, IRQ %d\n", irq); return 0; -errout6: - clk_disable(info->clk); errout5: - clk_unprepare(info->clk); + clk_disable_unprepare(info->clk); errout4: clk_put(info->clk); errout3: @@ -416,8 +408,7 @@ static int __devexit spear_adc_remove(struct platform_device *pdev) iio_device_unregister(iodev); platform_set_drvdata(pdev, NULL); - clk_disable(info->clk); - clk_unprepare(info->clk); + clk_disable_unprepare(info->clk); clk_put(info->clk); iounmap(info->adc_base_spear6xx); iio_device_free(iodev); diff --git a/drivers/staging/iio/gyro/adis16060_core.c b/drivers/staging/iio/gyro/adis16060_core.c index 9931e2060e1f..87151a7cff04 100644 --- a/drivers/staging/iio/gyro/adis16060_core.c +++ b/drivers/staging/iio/gyro/adis16060_core.c @@ -184,7 +184,7 @@ error_ret: } /* fixme, confirm ordering in this function */ -static int adis16060_r_remove(struct spi_device *spi) +static int __devexit adis16060_r_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); iio_device_free(spi_get_drvdata(spi)); @@ -210,7 +210,7 @@ error_ret: return ret; } -static int adis16060_w_remove(struct spi_device *spi) +static int __devexit adis16060_w_remove(struct spi_device *spi) { return 0; } diff --git a/drivers/staging/iio/gyro/adis16080_core.c b/drivers/staging/iio/gyro/adis16080_core.c index 345e4fa778ba..a73902573f79 100644 --- a/drivers/staging/iio/gyro/adis16080_core.c +++ b/drivers/staging/iio/gyro/adis16080_core.c @@ -177,7 +177,7 @@ error_ret: } /* fixme, confirm ordering in this function */ -static int adis16080_remove(struct spi_device *spi) +static int __devexit adis16080_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); iio_device_free(spi_get_drvdata(spi)); diff --git a/drivers/staging/iio/gyro/adis16130_core.c b/drivers/staging/iio/gyro/adis16130_core.c index bf61cd0b5bbc..fbf96b0b6ee8 100644 --- a/drivers/staging/iio/gyro/adis16130_core.c +++ b/drivers/staging/iio/gyro/adis16130_core.c @@ -154,7 +154,7 @@ error_ret: } /* fixme, confirm ordering in this function */ -static int adis16130_remove(struct spi_device *spi) +static int __devexit adis16130_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); iio_device_free(spi_get_drvdata(spi)); diff --git a/drivers/staging/iio/gyro/adis16260_core.c b/drivers/staging/iio/gyro/adis16260_core.c index eb8e9d69efd3..9571c03aa4cc 100644 --- a/drivers/staging/iio/gyro/adis16260_core.c +++ b/drivers/staging/iio/gyro/adis16260_core.c @@ -700,24 +700,18 @@ error_ret: return ret; } -static int adis16260_remove(struct spi_device *spi) +static int __devexit adis16260_remove(struct spi_device *spi) { - int ret; struct iio_dev *indio_dev = spi_get_drvdata(spi); iio_device_unregister(indio_dev); - - ret = adis16260_stop_device(indio_dev); - if (ret) - goto err_ret; - + adis16260_stop_device(indio_dev); adis16260_remove_trigger(indio_dev); iio_buffer_unregister(indio_dev); adis16260_unconfigure_ring(indio_dev); iio_device_free(indio_dev); -err_ret: - return ret; + return 0; } /* diff --git a/drivers/staging/iio/gyro/adis16260_ring.c b/drivers/staging/iio/gyro/adis16260_ring.c index eeee8e760e6c..e294cb49736d 100644 --- a/drivers/staging/iio/gyro/adis16260_ring.c +++ b/drivers/staging/iio/gyro/adis16260_ring.c @@ -62,7 +62,6 @@ static irqreturn_t adis16260_trigger_handler(int irq, void *p) struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; struct adis16260_state *st = iio_priv(indio_dev); - struct iio_buffer *ring = indio_dev->buffer; int i = 0; s16 *data; @@ -82,7 +81,7 @@ static irqreturn_t adis16260_trigger_handler(int irq, void *p) if (indio_dev->scan_timestamp) *((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp; - ring->access->store_to(ring, (u8 *)data, pf->timestamp); + iio_push_to_buffer(indio_dev->buffer, (u8 *)data); kfree(data); done: diff --git a/drivers/staging/iio/gyro/adxrs450_core.c b/drivers/staging/iio/gyro/adxrs450_core.c index 6513119b1e90..d93527d15917 100644 --- a/drivers/staging/iio/gyro/adxrs450_core.c +++ b/drivers/staging/iio/gyro/adxrs450_core.c @@ -409,7 +409,7 @@ error_ret: return ret; } -static int adxrs450_remove(struct spi_device *spi) +static int __devexit adxrs450_remove(struct spi_device *spi) { iio_device_unregister(spi_get_drvdata(spi)); iio_device_free(spi_get_drvdata(spi)); diff --git a/drivers/staging/iio/iio_dummy_evgen.c b/drivers/staging/iio/iio_dummy_evgen.c index 0cd4fe916bf9..74e24e8aa876 100644 --- a/drivers/staging/iio/iio_dummy_evgen.c +++ b/drivers/staging/iio/iio_dummy_evgen.c @@ -216,6 +216,6 @@ static __exit void iio_dummy_evgen_exit(void) } module_exit(iio_dummy_evgen_exit); -MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>"); +MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); MODULE_DESCRIPTION("IIO dummy driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/iio_hwmon.c b/drivers/staging/iio/iio_hwmon.c index 27d27ec9521f..5d491227e01b 100644 --- a/drivers/staging/iio/iio_hwmon.c +++ b/drivers/staging/iio/iio_hwmon.c @@ -42,40 +42,17 @@ static ssize_t iio_hwmon_read_val(struct device *dev, struct device_attribute *attr, char *buf) { - long result; - int val, ret, scaleint, scalepart; + int result; + int ret; struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr); struct iio_hwmon_state *state = dev_get_drvdata(dev); - /* - * No locking between this pair, so theoretically possible - * the scale has changed. - */ - ret = iio_read_channel_raw(&state->channels[sattr->index], - &val); + ret = iio_read_channel_processed(&state->channels[sattr->index], + &result); if (ret < 0) return ret; - ret = iio_read_channel_scale(&state->channels[sattr->index], - &scaleint, &scalepart); - if (ret < 0) - return ret; - switch (ret) { - case IIO_VAL_INT: - result = val * scaleint; - break; - case IIO_VAL_INT_PLUS_MICRO: - result = (s64)val * (s64)scaleint + - div_s64((s64)val * (s64)scalepart, 1000000LL); - break; - case IIO_VAL_INT_PLUS_NANO: - result = (s64)val * (s64)scaleint + - div_s64((s64)val * (s64)scalepart, 1000000000LL); - break; - default: - return -EINVAL; - } - return sprintf(buf, "%ld\n", result); + return sprintf(buf, "%d\n", result); } static void iio_hwmon_free_attrs(struct iio_hwmon_state *st) @@ -215,18 +192,8 @@ static struct platform_driver __refdata iio_hwmon_driver = { .remove = __devexit_p(iio_hwmon_remove), }; -static int iio_inkern_init(void) -{ - return platform_driver_register(&iio_hwmon_driver); -} -module_init(iio_inkern_init); - -static void iio_inkern_exit(void) -{ - platform_driver_unregister(&iio_hwmon_driver); -} -module_exit(iio_inkern_exit); +module_platform_driver(iio_hwmon_driver); -MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>"); +MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); MODULE_DESCRIPTION("IIO to hwmon driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/iio_simple_dummy.c b/drivers/staging/iio/iio_simple_dummy.c index 155a49a9da7e..dc6c728ea47a 100644 --- a/drivers/staging/iio/iio_simple_dummy.c +++ b/drivers/staging/iio/iio_simple_dummy.c @@ -63,7 +63,7 @@ static const struct iio_dummy_accel_calibscale dummy_scales[] = { * This array of structures tells the IIO core about what the device * actually provides for a given channel. */ -static struct iio_chan_spec iio_dummy_channels[] = { +static const struct iio_chan_spec iio_dummy_channels[] = { /* indexed ADC channel in_voltage0_raw etc */ { .type = IIO_VOLTAGE, @@ -445,26 +445,20 @@ static int __devinit iio_dummy_probe(int index) if (ret < 0) goto error_free_device; - /* Configure buffered capture support. */ - ret = iio_simple_dummy_configure_buffer(indio_dev); - if (ret < 0) - goto error_unregister_events; - /* - * Register the channels with the buffer, but avoid the output - * channel being registered by reducing the number of channels by 1. + * Configure buffered capture support and register the channels with the + * buffer, but avoid the output channel being registered by reducing the + * number of channels by 1. */ - ret = iio_buffer_register(indio_dev, iio_dummy_channels, 5); + ret = iio_simple_dummy_configure_buffer(indio_dev, iio_dummy_channels, 5); if (ret < 0) - goto error_unconfigure_buffer; + goto error_unregister_events; ret = iio_device_register(indio_dev); if (ret < 0) - goto error_unregister_buffer; + goto error_unconfigure_buffer; return 0; -error_unregister_buffer: - iio_buffer_unregister(indio_dev); error_unconfigure_buffer: iio_simple_dummy_unconfigure_buffer(indio_dev); error_unregister_events: @@ -499,7 +493,6 @@ static int iio_dummy_remove(int index) /* Device specific code to power down etc */ /* Buffered capture related cleanup */ - iio_buffer_unregister(indio_dev); iio_simple_dummy_unconfigure_buffer(indio_dev); ret = iio_simple_dummy_events_unregister(indio_dev); @@ -530,6 +523,7 @@ static __init int iio_dummy_init(void) instances = 1; return -EINVAL; } + /* Fake a bus */ iio_dummy_devs = kcalloc(instances, sizeof(*iio_dummy_devs), GFP_KERNEL); @@ -558,6 +552,6 @@ static __exit void iio_dummy_exit(void) } module_exit(iio_dummy_exit); -MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>"); +MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); MODULE_DESCRIPTION("IIO dummy driver"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/iio_simple_dummy.h b/drivers/staging/iio/iio_simple_dummy.h index 53975d916fc9..c9e8702caca4 100644 --- a/drivers/staging/iio/iio_simple_dummy.h +++ b/drivers/staging/iio/iio_simple_dummy.h @@ -95,10 +95,12 @@ enum iio_simple_dummy_scan_elements { }; #ifdef CONFIG_IIO_SIMPLE_DUMMY_BUFFER -int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev); +int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev, + const struct iio_chan_spec *channels, unsigned int num_channels); void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev); #else -static inline int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev) +static inline int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev, + const struct iio_chan_spec *channels, unsigned int num_channels) { return 0; }; diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/staging/iio/iio_simple_dummy_buffer.c index bd628de472a9..697d9700db2f 100644 --- a/drivers/staging/iio/iio_simple_dummy_buffer.c +++ b/drivers/staging/iio/iio_simple_dummy_buffer.c @@ -87,7 +87,7 @@ static irqreturn_t iio_simple_dummy_trigger_h(int irq, void *p) if (indio_dev->scan_timestamp) *(s64 *)((u8 *)data + ALIGN(len, sizeof(s64))) = iio_get_time_ns(); - buffer->access->store_to(buffer, (u8 *)data, pf->timestamp); + iio_push_to_buffer(buffer, (u8 *)data); kfree(data); @@ -126,7 +126,8 @@ static const struct iio_buffer_setup_ops iio_simple_dummy_buffer_setup_ops = { .predisable = &iio_triggered_buffer_predisable, }; -int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev) +int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev, + const struct iio_chan_spec *channels, unsigned int num_channels) { int ret; struct iio_buffer *buffer; @@ -182,8 +183,15 @@ int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev) * driven by a trigger. */ indio_dev->modes |= INDIO_BUFFER_TRIGGERED; + + ret = iio_buffer_register(indio_dev, channels, num_channels); + if (ret) + goto error_dealloc_pollfunc; + return 0; +error_dealloc_pollfunc: + iio_dealloc_pollfunc(indio_dev->pollfunc); error_free_buffer: iio_kfifo_free(indio_dev->buffer); error_ret: @@ -197,6 +205,7 @@ error_ret: */ void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev) { + iio_buffer_unregister(indio_dev); iio_dealloc_pollfunc(indio_dev->pollfunc); iio_kfifo_free(indio_dev->buffer); } diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c index a8e51bc04439..de21d47f33e9 100644 --- a/drivers/staging/iio/impedance-analyzer/ad5933.c +++ b/drivers/staging/iio/impedance-analyzer/ad5933.c @@ -108,7 +108,7 @@ static struct ad5933_platform_data ad5933_default_pdata = { .vref_mv = 3300, }; -static struct iio_chan_spec ad5933_channels[] = { +static const struct iio_chan_spec ad5933_channels[] = { { .type = IIO_TEMP, .indexed = 1, @@ -678,7 +678,7 @@ static void ad5933_work(struct work_struct *work) buf[0] = be16_to_cpu(buf[0]); } /* save datum to the ring */ - ring->access->store_to(ring, (u8 *)buf, iio_get_time_ns()); + iio_push_to_buffer(ring, (u8 *)buf); } else { /* no data available - try again later */ schedule_delayed_work(&st->work, st->poll_time_jiffies); diff --git a/drivers/staging/iio/imu/adis16400.h b/drivers/staging/iio/imu/adis16400.h index 9dd9f1459a4d..d59d7ac856a9 100644 --- a/drivers/staging/iio/imu/adis16400.h +++ b/drivers/staging/iio/imu/adis16400.h @@ -5,7 +5,7 @@ * 3d 2.5gauss magnetometers via SPI * * Copyright (c) 2009 Manuel Stahl <manuel.stahl@iis.fraunhofer.de> - * Copyright (c) 2007 Jonathan Cameron <jic23@cam.ac.uk> + * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org> * * Loosely based upon lis3l02dq.h * diff --git a/drivers/staging/iio/imu/adis16400_core.c b/drivers/staging/iio/imu/adis16400_core.c index a618327e06ed..b302c9ba2712 100644 --- a/drivers/staging/iio/imu/adis16400_core.c +++ b/drivers/staging/iio/imu/adis16400_core.c @@ -5,7 +5,7 @@ * 3d Magnetometers via SPI * * Copyright (c) 2009 Manuel Stahl <manuel.stahl@iis.fraunhofer.de> - * Copyright (c) 2007 Jonathan Cameron <jic23@cam.ac.uk> + * Copyright (c) 2007 Jonathan Cameron <jic23@kernel.org> * Copyright (c) 2011 Analog Devices Inc. * * This program is free software; you can redistribute it and/or modify @@ -612,7 +612,7 @@ static int adis16400_read_raw(struct iio_dev *indio_dev, } } -static struct iio_chan_spec adis16400_channels[] = { +static const struct iio_chan_spec adis16400_channels[] = { { .type = IIO_VOLTAGE, .indexed = 1, @@ -742,7 +742,7 @@ static struct iio_chan_spec adis16400_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(12) }; -static struct iio_chan_spec adis16350_channels[] = { +static const struct iio_chan_spec adis16350_channels[] = { { .type = IIO_VOLTAGE, .indexed = 1, @@ -867,7 +867,7 @@ static struct iio_chan_spec adis16350_channels[] = { IIO_CHAN_SOFT_TIMESTAMP(11) }; -static struct iio_chan_spec adis16300_channels[] = { +static const struct iio_chan_spec adis16300_channels[] = { { .type = IIO_VOLTAGE, .indexed = 1, @@ -1206,15 +1206,12 @@ error_ret: } /* fixme, confirm ordering in this function */ -static int adis16400_remove(struct spi_device *spi) +static int __devexit adis16400_remove(struct spi_device *spi) { - int ret; struct iio_dev *indio_dev = spi_get_drvdata(spi); iio_device_unregister(indio_dev); - ret = adis16400_stop_device(indio_dev); - if (ret) - goto err_ret; + adis16400_stop_device(indio_dev); adis16400_remove_trigger(indio_dev); iio_buffer_unregister(indio_dev); @@ -1222,9 +1219,6 @@ static int adis16400_remove(struct spi_device *spi) iio_device_free(indio_dev); return 0; - -err_ret: - return ret; } static const struct spi_device_id adis16400_id[] = { diff --git a/drivers/staging/iio/imu/adis16400_ring.c b/drivers/staging/iio/imu/adis16400_ring.c index beec650ddbdb..260bdd1a4681 100644 --- a/drivers/staging/iio/imu/adis16400_ring.c +++ b/drivers/staging/iio/imu/adis16400_ring.c @@ -150,7 +150,7 @@ static irqreturn_t adis16400_trigger_handler(int irq, void *p) /* Guaranteed to be aligned with 8 byte boundary */ if (ring->scan_timestamp) *((s64 *)(data + ((i + 3)/4)*4)) = pf->timestamp; - ring->access->store_to(indio_dev->buffer, (u8 *) data, pf->timestamp); + iio_push_to_buffer(ring, (u8 *) data); done: kfree(data); diff --git a/drivers/staging/iio/light/isl29018.c b/drivers/staging/iio/light/isl29018.c index 31d22f5591ca..6ee5567d9813 100644 --- a/drivers/staging/iio/light/isl29018.c +++ b/drivers/staging/iio/light/isl29018.c @@ -63,6 +63,7 @@ struct isl29018_chip { struct regmap *regmap; struct mutex lock; unsigned int lux_scale; + unsigned int lux_uscale; unsigned int range; unsigned int adc_bit; int prox_scheme; @@ -145,13 +146,22 @@ static int isl29018_read_sensor_input(struct isl29018_chip *chip, int mode) static int isl29018_read_lux(struct isl29018_chip *chip, int *lux) { int lux_data; + unsigned int data_x_range, lux_unshifted; lux_data = isl29018_read_sensor_input(chip, COMMMAND1_OPMODE_ALS_ONCE); if (lux_data < 0) return lux_data; - *lux = (lux_data * chip->range * chip->lux_scale) >> chip->adc_bit; + /* To support fractional scaling, separate the unshifted lux + * into two calculations: int scaling and micro-scaling. + * lux_uscale ranges from 0-999999, so about 20 bits. Split + * the /1,000,000 in two to reduce the risk of over/underflow. + */ + data_x_range = lux_data * chip->range; + lux_unshifted = data_x_range * chip->lux_scale; + lux_unshifted += data_x_range / 1000 * chip->lux_uscale / 1000; + *lux = lux_unshifted >> chip->adc_bit; return 0; } @@ -339,6 +349,8 @@ static int isl29018_write_raw(struct iio_dev *indio_dev, mutex_lock(&chip->lock); if (mask == IIO_CHAN_INFO_CALIBSCALE && chan->type == IIO_LIGHT) { chip->lux_scale = val; + /* With no write_raw_get_fmt(), val2 is a MICRO fraction. */ + chip->lux_uscale = val2; ret = 0; } mutex_unlock(&chip->lock); @@ -379,7 +391,8 @@ static int isl29018_read_raw(struct iio_dev *indio_dev, case IIO_CHAN_INFO_CALIBSCALE: if (chan->type == IIO_LIGHT) { *val = chip->lux_scale; - ret = IIO_VAL_INT; + *val2 = chip->lux_uscale; + ret = IIO_VAL_INT_PLUS_MICRO; } break; default: diff --git a/drivers/staging/iio/light/tsl2563.c b/drivers/staging/iio/light/tsl2563.c index 9d740be43a82..954ca2c172c6 100644 --- a/drivers/staging/iio/light/tsl2563.c +++ b/drivers/staging/iio/light/tsl2563.c @@ -805,7 +805,7 @@ fail1: return err; } -static int tsl2563_remove(struct i2c_client *client) +static int __devexit tsl2563_remove(struct i2c_client *client) { struct tsl2563_chip *chip = i2c_get_clientdata(client); struct iio_dev *indio_dev = iio_priv_to_dev(chip); diff --git a/drivers/staging/iio/magnetometer/hmc5843.c b/drivers/staging/iio/magnetometer/hmc5843.c index 6c3e50f7c0d8..10e095486e54 100644 --- a/drivers/staging/iio/magnetometer/hmc5843.c +++ b/drivers/staging/iio/magnetometer/hmc5843.c @@ -1,6 +1,6 @@ /* Copyright (C) 2010 Texas Instruments Author: Shubhrajyoti Datta <shubhrajyoti@ti.com> - Acknowledgement: Jonathan Cameron <jic23@cam.ac.uk> for valuable inputs. + Acknowledgement: Jonathan Cameron <jic23@kernel.org> for valuable inputs. Support for HMC5883 and HMC5883L by Peter Meerwald <pmeerw@pmeerw.net>. diff --git a/drivers/staging/iio/meter/ade7753.c b/drivers/staging/iio/meter/ade7753.c index 3ccff189f258..8b9eceb66b37 100644 --- a/drivers/staging/iio/meter/ade7753.c +++ b/drivers/staging/iio/meter/ade7753.c @@ -555,20 +555,15 @@ error_ret: } /* fixme, confirm ordering in this function */ -static int ade7753_remove(struct spi_device *spi) +static int __devexit ade7753_remove(struct spi_device *spi) { - int ret; struct iio_dev *indio_dev = spi_get_drvdata(spi); iio_device_unregister(indio_dev); - - ret = ade7753_stop_device(&(indio_dev->dev)); - if (ret) - goto err_ret; - + ade7753_stop_device(&indio_dev->dev); iio_device_free(indio_dev); -err_ret: - return ret; + + return 0; } static struct spi_driver ade7753_driver = { diff --git a/drivers/staging/iio/meter/ade7754.c b/drivers/staging/iio/meter/ade7754.c index abb1e9c8d094..76e0adee96ea 100644 --- a/drivers/staging/iio/meter/ade7754.c +++ b/drivers/staging/iio/meter/ade7754.c @@ -577,21 +577,15 @@ error_ret: } /* fixme, confirm ordering in this function */ -static int ade7754_remove(struct spi_device *spi) +static int __devexit ade7754_remove(struct spi_device *spi) { - int ret; struct iio_dev *indio_dev = spi_get_drvdata(spi); iio_device_unregister(indio_dev); - ret = ade7754_stop_device(&(indio_dev->dev)); - if (ret) - goto err_ret; - + ade7754_stop_device(&indio_dev->dev); iio_device_free(indio_dev); -err_ret: - return ret; - + return 0; } static struct spi_driver ade7754_driver = { diff --git a/drivers/staging/iio/meter/ade7758.h b/drivers/staging/iio/meter/ade7758.h index ec202b4ecfb2..1e11ad5ae5a4 100644 --- a/drivers/staging/iio/meter/ade7758.h +++ b/drivers/staging/iio/meter/ade7758.h @@ -122,7 +122,7 @@ struct ade7758_state { u8 *tx; u8 *rx; struct mutex buf_lock; - struct iio_chan_spec *ade7758_ring_channels; + const struct iio_chan_spec *ade7758_ring_channels; struct spi_transfer ring_xfer[4]; struct spi_message ring_msg; /* diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c index 7014a0078446..a0fef77d8e5e 100644 --- a/drivers/staging/iio/meter/ade7758_core.c +++ b/drivers/staging/iio/meter/ade7758_core.c @@ -661,7 +661,7 @@ static const struct attribute_group ade7758_attribute_group = { .attrs = ade7758_attributes, }; -static struct iio_chan_spec ade7758_channels[] = { +static const struct iio_chan_spec ade7758_channels[] = { { .type = IIO_VOLTAGE, .indexed = 1, @@ -962,17 +962,13 @@ error_ret: return ret; } -static int ade7758_remove(struct spi_device *spi) +static int __devexit ade7758_remove(struct spi_device *spi) { struct iio_dev *indio_dev = spi_get_drvdata(spi); struct ade7758_state *st = iio_priv(indio_dev); - int ret; iio_device_unregister(indio_dev); - ret = ade7758_stop_device(&indio_dev->dev); - if (ret) - goto err_ret; - + ade7758_stop_device(&indio_dev->dev); ade7758_remove_trigger(indio_dev); ade7758_uninitialize_ring(indio_dev); ade7758_unconfigure_ring(indio_dev); @@ -981,8 +977,7 @@ static int ade7758_remove(struct spi_device *spi) iio_device_free(indio_dev); -err_ret: - return ret; + return 0; } static const struct spi_device_id ade7758_id[] = { diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c index 1ce10b21f4d6..9e49baccf660 100644 --- a/drivers/staging/iio/meter/ade7758_ring.c +++ b/drivers/staging/iio/meter/ade7758_ring.c @@ -61,7 +61,6 @@ static irqreturn_t ade7758_trigger_handler(int irq, void *p) { struct iio_poll_func *pf = p; struct iio_dev *indio_dev = pf->indio_dev; - struct iio_buffer *ring = indio_dev->buffer; struct ade7758_state *st = iio_priv(indio_dev); s64 dat64[2]; u32 *dat32 = (u32 *)dat64; @@ -74,7 +73,7 @@ static irqreturn_t ade7758_trigger_handler(int irq, void *p) if (indio_dev->scan_timestamp) dat64[1] = pf->timestamp; - ring->access->store_to(ring, (u8 *)dat64, pf->timestamp); + iio_push_to_buffer(indio_dev->buffer, (u8 *)dat64); iio_trigger_notify_done(indio_dev->trig); diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c index eb0a2a98f388..cb0707cbc347 100644 --- a/drivers/staging/iio/meter/ade7759.c +++ b/drivers/staging/iio/meter/ade7759.c @@ -499,20 +499,15 @@ error_ret: } /* fixme, confirm ordering in this function */ -static int ade7759_remove(struct spi_device *spi) +static int __devexit ade7759_remove(struct spi_device *spi) { - int ret; struct iio_dev *indio_dev = spi_get_drvdata(spi); iio_device_unregister(indio_dev); - ret = ade7759_stop_device(&(indio_dev->dev)); - if (ret) - goto err_ret; - + ade7759_stop_device(&indio_dev->dev); iio_device_free(indio_dev); -err_ret: - return ret; + return 0; } static struct spi_driver ade7759_driver = { diff --git a/drivers/staging/iio/meter/ade7854-spi.c b/drivers/staging/iio/meter/ade7854-spi.c index 9fb2f8bfca81..7dae03573428 100644 --- a/drivers/staging/iio/meter/ade7854-spi.c +++ b/drivers/staging/iio/meter/ade7854-spi.c @@ -330,7 +330,7 @@ static int __devinit ade7854_spi_probe(struct spi_device *spi) return 0; } -static int ade7854_spi_remove(struct spi_device *spi) +static int __devexit ade7854_spi_remove(struct spi_device *spi) { ade7854_remove(spi_get_drvdata(spi)); diff --git a/drivers/staging/iio/resolver/ad2s1210.c b/drivers/staging/iio/resolver/ad2s1210.c index f313859476c1..4ba4d05ed423 100644 --- a/drivers/staging/iio/resolver/ad2s1210.c +++ b/drivers/staging/iio/resolver/ad2s1210.c @@ -575,7 +575,7 @@ static IIO_DEVICE_ATTR(lot_low_thrd, S_IRUGO | S_IWUSR, AD2S1210_REG_LOT_LOW_THRD); -static struct iio_chan_spec ad2s1210_channels[] = { +static const struct iio_chan_spec ad2s1210_channels[] = { { .type = IIO_ANGL, .indexed = 1, diff --git a/drivers/staging/iio/ring_hw.h b/drivers/staging/iio/ring_hw.h index cad8a2ed9b68..39c14a715868 100644 --- a/drivers/staging/iio/ring_hw.h +++ b/drivers/staging/iio/ring_hw.h @@ -5,7 +5,7 @@ * under the terms of the GNU General Public License version 2 as published by * the Free Software Foundation. * - * Copyright (c) 2009 Jonathan Cameron <jic23@cam.ac.uk> + * Copyright (c) 2009 Jonathan Cameron <jic23@kernel.org> * */ diff --git a/drivers/staging/iio/ring_sw.c b/drivers/staging/iio/ring_sw.c index f61c8fdaab06..3a45f9a52de8 100644 --- a/drivers/staging/iio/ring_sw.c +++ b/drivers/staging/iio/ring_sw.c @@ -65,7 +65,7 @@ static inline void __iio_free_sw_ring_buffer(struct iio_sw_ring_buffer *ring) /* Lock always held if their is a chance this may be called */ /* Only one of these per ring may run concurrently - enforced by drivers */ static int iio_store_to_sw_ring(struct iio_sw_ring_buffer *ring, - unsigned char *data, s64 timestamp) + unsigned char *data) { int ret = 0; unsigned char *temp_ptr, *change_test_ptr; @@ -256,11 +256,10 @@ error_ret: } static int iio_store_to_sw_rb(struct iio_buffer *r, - u8 *data, - s64 timestamp) + u8 *data) { struct iio_sw_ring_buffer *ring = iio_to_sw_ring(r); - return iio_store_to_sw_ring(ring, data, timestamp); + return iio_store_to_sw_ring(ring, data); } static int iio_request_update_sw_rb(struct iio_buffer *r) diff --git a/drivers/staging/iio/trigger/Kconfig b/drivers/staging/iio/trigger/Kconfig index b8abf5473ddc..7d3207559265 100644 --- a/drivers/staging/iio/trigger/Kconfig +++ b/drivers/staging/iio/trigger/Kconfig @@ -21,6 +21,8 @@ config IIO_GPIO_TRIGGER config IIO_SYSFS_TRIGGER tristate "SYSFS trigger" depends on SYSFS + depends on HAVE_IRQ_WORK + select IRQ_WORK help Provides support for using SYSFS entry as IIO triggers. If unsure, say N (but it's safe to say "Y"). diff --git a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c index ce6a7b1b8860..52062d786f84 100644 --- a/drivers/staging/iio/trigger/iio-trig-bfin-timer.c +++ b/drivers/staging/iio/trigger/iio-trig-bfin-timer.c @@ -14,14 +14,18 @@ #include <linux/delay.h> #include <asm/gptimers.h> +#include <asm/portmux.h> #include <linux/iio/iio.h> #include <linux/iio/trigger.h> +#include "iio-trig-bfin-timer.h" + struct bfin_timer { unsigned short id, bit; unsigned long irqbit; int irq; + int pin; }; /* @@ -30,22 +34,22 @@ struct bfin_timer { */ static struct bfin_timer iio_bfin_timer_code[MAX_BLACKFIN_GPTIMERS] = { - {TIMER0_id, TIMER0bit, TIMER_STATUS_TIMIL0, IRQ_TIMER0}, - {TIMER1_id, TIMER1bit, TIMER_STATUS_TIMIL1, IRQ_TIMER1}, - {TIMER2_id, TIMER2bit, TIMER_STATUS_TIMIL2, IRQ_TIMER2}, + {TIMER0_id, TIMER0bit, TIMER_STATUS_TIMIL0, IRQ_TIMER0, P_TMR0}, + {TIMER1_id, TIMER1bit, TIMER_STATUS_TIMIL1, IRQ_TIMER1, P_TMR1}, + {TIMER2_id, TIMER2bit, TIMER_STATUS_TIMIL2, IRQ_TIMER2, P_TMR2}, #if (MAX_BLACKFIN_GPTIMERS > 3) - {TIMER3_id, TIMER3bit, TIMER_STATUS_TIMIL3, IRQ_TIMER3}, - {TIMER4_id, TIMER4bit, TIMER_STATUS_TIMIL4, IRQ_TIMER4}, - {TIMER5_id, TIMER5bit, TIMER_STATUS_TIMIL5, IRQ_TIMER5}, - {TIMER6_id, TIMER6bit, TIMER_STATUS_TIMIL6, IRQ_TIMER6}, - {TIMER7_id, TIMER7bit, TIMER_STATUS_TIMIL7, IRQ_TIMER7}, + {TIMER3_id, TIMER3bit, TIMER_STATUS_TIMIL3, IRQ_TIMER3, P_TMR3}, + {TIMER4_id, TIMER4bit, TIMER_STATUS_TIMIL4, IRQ_TIMER4, P_TMR4}, + {TIMER5_id, TIMER5bit, TIMER_STATUS_TIMIL5, IRQ_TIMER5, P_TMR5}, + {TIMER6_id, TIMER6bit, TIMER_STATUS_TIMIL6, IRQ_TIMER6, P_TMR6}, + {TIMER7_id, TIMER7bit, TIMER_STATUS_TIMIL7, IRQ_TIMER7, P_TMR7}, #endif #if (MAX_BLACKFIN_GPTIMERS > 8) - {TIMER8_id, TIMER8bit, TIMER_STATUS_TIMIL8, IRQ_TIMER8}, - {TIMER9_id, TIMER9bit, TIMER_STATUS_TIMIL9, IRQ_TIMER9}, - {TIMER10_id, TIMER10bit, TIMER_STATUS_TIMIL10, IRQ_TIMER10}, + {TIMER8_id, TIMER8bit, TIMER_STATUS_TIMIL8, IRQ_TIMER8, P_TMR8}, + {TIMER9_id, TIMER9bit, TIMER_STATUS_TIMIL9, IRQ_TIMER9, P_TMR9}, + {TIMER10_id, TIMER10bit, TIMER_STATUS_TIMIL10, IRQ_TIMER10, P_TMR10}, #if (MAX_BLACKFIN_GPTIMERS > 11) - {TIMER11_id, TIMER11bit, TIMER_STATUS_TIMIL11, IRQ_TIMER11}, + {TIMER11_id, TIMER11bit, TIMER_STATUS_TIMIL11, IRQ_TIMER11, P_TMR11}, #endif #endif }; @@ -54,15 +58,33 @@ struct bfin_tmr_state { struct iio_trigger *trig; struct bfin_timer *t; unsigned timer_num; + bool output_enable; + unsigned int duty; int irq; }; +static int iio_bfin_tmr_set_state(struct iio_trigger *trig, bool state) +{ + struct bfin_tmr_state *st = trig->private_data; + + if (get_gptimer_period(st->t->id) == 0) + return -EINVAL; + + if (state) + enable_gptimers(st->t->bit); + else + disable_gptimers(st->t->bit); + + return 0; +} + static ssize_t iio_bfin_tmr_frequency_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct iio_trigger *trig = to_iio_trigger(dev); struct bfin_tmr_state *st = trig->private_data; - long val; + unsigned long val; + bool enabled; int ret; ret = strict_strtoul(buf, 10, &val); @@ -74,20 +96,25 @@ static ssize_t iio_bfin_tmr_frequency_store(struct device *dev, goto error_ret; } - disable_gptimers(st->t->bit); + enabled = get_enabled_gptimers() & st->t->bit; + + if (enabled) + disable_gptimers(st->t->bit); if (!val) goto error_ret; val = get_sclk() / val; - if (val <= 4) { + if (val <= 4 || val <= st->duty) { ret = -EINVAL; goto error_ret; } set_gptimer_period(st->t->id, val); - set_gptimer_pwidth(st->t->id, 1); - enable_gptimers(st->t->bit); + set_gptimer_pwidth(st->t->id, val - st->duty); + + if (enabled) + enable_gptimers(st->t->bit); error_ret: return ret ? ret : count; @@ -99,9 +126,15 @@ static ssize_t iio_bfin_tmr_frequency_show(struct device *dev, { struct iio_trigger *trig = to_iio_trigger(dev); struct bfin_tmr_state *st = trig->private_data; + unsigned int period = get_gptimer_period(st->t->id); + unsigned long val; + + if (period == 0) + val = 0; + else + val = get_sclk() / get_gptimer_period(st->t->id); - return sprintf(buf, "%lu\n", - get_sclk() / get_gptimer_period(st->t->id)); + return sprintf(buf, "%lu\n", val); } static DEVICE_ATTR(frequency, S_IRUGO | S_IWUSR, iio_bfin_tmr_frequency_show, @@ -121,7 +154,6 @@ static const struct attribute_group *iio_bfin_tmr_trigger_attr_groups[] = { NULL }; - static irqreturn_t iio_bfin_tmr_trigger_isr(int irq, void *devid) { struct bfin_tmr_state *st = devid; @@ -145,11 +177,14 @@ static int iio_bfin_tmr_get_number(int irq) static const struct iio_trigger_ops iio_bfin_tmr_trigger_ops = { .owner = THIS_MODULE, + .set_trigger_state = iio_bfin_tmr_set_state, }; static int __devinit iio_bfin_tmr_trigger_probe(struct platform_device *pdev) { + struct iio_bfin_timer_trigger_pdata *pdata = pdev->dev.platform_data; struct bfin_tmr_state *st; + unsigned int config; int ret; st = kzalloc(sizeof(*st), GFP_KERNEL); @@ -193,13 +228,43 @@ static int __devinit iio_bfin_tmr_trigger_probe(struct platform_device *pdev) goto out4; } - set_gptimer_config(st->t->id, OUT_DIS | PWM_OUT | PERIOD_CNT | IRQ_ENA); + config = PWM_OUT | PERIOD_CNT | IRQ_ENA; + + if (pdata && pdata->output_enable) { + unsigned long long val; + + st->output_enable = true; + + ret = peripheral_request(st->t->pin, st->trig->name); + if (ret) + goto out_free_irq; + + val = (unsigned long long)get_sclk() * pdata->duty_ns; + do_div(val, NSEC_PER_SEC); + st->duty = val; + + /** + * The interrupt will be generated at the end of the period, + * since we want the interrupt to be generated at end of the + * pulse we invert both polarity and duty cycle, so that the + * pulse will be generated directly before the interrupt. + */ + if (pdata->active_low) + config |= PULSE_HI; + } else { + st->duty = 1; + config |= OUT_DIS; + } + + set_gptimer_config(st->t->id, config); dev_info(&pdev->dev, "iio trigger Blackfin TMR%d, IRQ-%d", st->timer_num, st->irq); platform_set_drvdata(pdev, st); return 0; +out_free_irq: + free_irq(st->irq, st); out4: iio_trigger_unregister(st->trig); out2: @@ -215,6 +280,8 @@ static int __devexit iio_bfin_tmr_trigger_remove(struct platform_device *pdev) struct bfin_tmr_state *st = platform_get_drvdata(pdev); disable_gptimers(st->t->bit); + if (st->output_enable) + peripheral_free(st->t->pin); free_irq(st->irq, st); iio_trigger_unregister(st->trig); iio_trigger_put(st->trig); diff --git a/drivers/staging/iio/trigger/iio-trig-bfin-timer.h b/drivers/staging/iio/trigger/iio-trig-bfin-timer.h new file mode 100644 index 000000000000..c07321f8d94c --- /dev/null +++ b/drivers/staging/iio/trigger/iio-trig-bfin-timer.h @@ -0,0 +1,24 @@ +#ifndef __IIO_BFIN_TIMER_TRIGGER_H__ +#define __IIO_BFIN_TIMER_TRIGGER_H__ + +/** + * struct iio_bfin_timer_trigger_pdata - timer trigger platform data + * @output_enable: Enable external trigger pulse generation. + * @active_low: Whether the trigger pulse is active low. + * @duty_ns: Length of the trigger pulse in nanoseconds. + * + * This struct is used to configure the output pulse generation of the blackfin + * timer trigger. If output_enable is set to true an external trigger signal + * will generated on the pin corresponding to the timer. This is useful for + * converters which needs an external signal to start conversion. active_low and + * duty_ns are used to configure the type of the trigger pulse. If output_enable + * is set to false no external trigger pulse will be generated and active_low + * and duty_ns are ignored. + **/ +struct iio_bfin_timer_trigger_pdata { + bool output_enable; + bool active_low; + unsigned int duty_ns; +}; + +#endif diff --git a/drivers/staging/iio/trigger/iio-trig-gpio.c b/drivers/staging/iio/trigger/iio-trig-gpio.c index 90b26846fc6b..5ff4d7fa20fa 100644 --- a/drivers/staging/iio/trigger/iio-trig-gpio.c +++ b/drivers/staging/iio/trigger/iio-trig-gpio.c @@ -51,7 +51,7 @@ static const struct iio_trigger_ops iio_gpio_trigger_ops = { .owner = THIS_MODULE, }; -static int iio_gpio_trigger_probe(struct platform_device *pdev) +static int __devinit iio_gpio_trigger_probe(struct platform_device *pdev) { struct iio_gpio_trigger_info *trig_info; struct iio_trigger *trig, *trig2; @@ -130,7 +130,7 @@ error_free_completed_registrations: return ret; } -static int iio_gpio_trigger_remove(struct platform_device *pdev) +static int __devexit iio_gpio_trigger_remove(struct platform_device *pdev) { struct iio_trigger *trig, *trig2; struct iio_gpio_trigger_info *trig_info; @@ -153,7 +153,7 @@ static int iio_gpio_trigger_remove(struct platform_device *pdev) static struct platform_driver iio_gpio_trigger_driver = { .probe = iio_gpio_trigger_probe, - .remove = iio_gpio_trigger_remove, + .remove = __devexit_p(iio_gpio_trigger_remove), .driver = { .name = "iio_gpio_trigger", .owner = THIS_MODULE, @@ -162,6 +162,6 @@ static struct platform_driver iio_gpio_trigger_driver = { module_platform_driver(iio_gpio_trigger_driver); -MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>"); +MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); MODULE_DESCRIPTION("Example gpio trigger for the iio subsystem"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c index 4ceaa18ef9f4..a3de76d70cdc 100644 --- a/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c +++ b/drivers/staging/iio/trigger/iio-trig-periodic-rtc.c @@ -101,7 +101,7 @@ static const struct iio_trigger_ops iio_prtc_trigger_ops = { .set_trigger_state = &iio_trig_periodic_rtc_set_state, }; -static int iio_trig_periodic_rtc_probe(struct platform_device *dev) +static int __devinit iio_trig_periodic_rtc_probe(struct platform_device *dev) { char **pdata = dev->dev.platform_data; struct iio_prtc_trigger_info *trig_info; @@ -167,7 +167,7 @@ error_free_completed_registrations: return ret; } -static int iio_trig_periodic_rtc_remove(struct platform_device *dev) +static int __devexit iio_trig_periodic_rtc_remove(struct platform_device *dev) { struct iio_trigger *trig, *trig2; struct iio_prtc_trigger_info *trig_info; @@ -188,7 +188,7 @@ static int iio_trig_periodic_rtc_remove(struct platform_device *dev) static struct platform_driver iio_trig_periodic_rtc_driver = { .probe = iio_trig_periodic_rtc_probe, - .remove = iio_trig_periodic_rtc_remove, + .remove = __devexit_p(iio_trig_periodic_rtc_remove), .driver = { .name = "iio_prtc_trigger", .owner = THIS_MODULE, @@ -197,6 +197,6 @@ static struct platform_driver iio_trig_periodic_rtc_driver = { module_platform_driver(iio_trig_periodic_rtc_driver); -MODULE_AUTHOR("Jonathan Cameron <jic23@cam.ac.uk>"); +MODULE_AUTHOR("Jonathan Cameron <jic23@kernel.org>"); MODULE_DESCRIPTION("Periodic realtime clock trigger for the iio subsystem"); MODULE_LICENSE("GPL v2"); diff --git a/drivers/staging/iio/trigger/iio-trig-sysfs.c b/drivers/staging/iio/trigger/iio-trig-sysfs.c index fee474648108..3bac97224bf4 100644 --- a/drivers/staging/iio/trigger/iio-trig-sysfs.c +++ b/drivers/staging/iio/trigger/iio-trig-sysfs.c @@ -10,12 +10,14 @@ #include <linux/platform_device.h> #include <linux/slab.h> #include <linux/list.h> +#include <linux/irq_work.h> #include <linux/iio/iio.h> #include <linux/iio/trigger.h> struct iio_sysfs_trig { struct iio_trigger *trig; + struct irq_work work; int id; struct list_head l; }; @@ -89,11 +91,21 @@ static struct device iio_sysfs_trig_dev = { .release = &iio_trigger_sysfs_release, }; +static void iio_sysfs_trigger_work(struct irq_work *work) +{ + struct iio_sysfs_trig *trig = container_of(work, struct iio_sysfs_trig, + work); + + iio_trigger_poll(trig->trig, 0); +} + static ssize_t iio_sysfs_trigger_poll(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct iio_trigger *trig = to_iio_trigger(dev); - iio_trigger_poll_chained(trig, 0); + struct iio_sysfs_trig *sysfs_trig = trig->private_data; + + irq_work_queue(&sysfs_trig->work); return count; } @@ -148,6 +160,9 @@ static int iio_sysfs_trigger_probe(int id) t->trig->dev.groups = iio_sysfs_trigger_attr_groups; t->trig->ops = &iio_sysfs_trigger_ops; t->trig->dev.parent = &iio_sysfs_trig_dev; + t->trig->private_data = t; + + init_irq_work(&t->work, iio_sysfs_trigger_work); ret = iio_trigger_register(t->trig); if (ret) diff --git a/drivers/staging/imx-drm/Kconfig b/drivers/staging/imx-drm/Kconfig new file mode 100644 index 000000000000..14b4449df234 --- /dev/null +++ b/drivers/staging/imx-drm/Kconfig @@ -0,0 +1,35 @@ +config DRM_IMX + tristate "DRM Support for Freescale i.MX" + select DRM_KMS_HELPER + select DRM_GEM_CMA_HELPER + select DRM_KMS_CMA_HELPER + depends on DRM && ARCH_MXC + help + enable i.MX graphics support + +config DRM_IMX_FB_HELPER + tristate "provide legacy framebuffer /dev/fb0" + select DRM_KMS_CMA_HELPER + depends on DRM_IMX + help + The DRM framework can provide a legacy /dev/fb0 framebuffer + for your device. This is necessary to get a framebuffer console + and also for appplications using the legacy framebuffer API + +config DRM_IMX_PARALLEL_DISPLAY + tristate "Support for parallel displays" + depends on DRM_IMX + +config DRM_IMX_IPUV3_CORE + tristate "IPUv3 core support" + depends on DRM_IMX + help + Choose this if you have a i.MX5/6 system and want + to use the IPU. This option only enables IPU base + support. + +config DRM_IMX_IPUV3 + tristate "DRM Support for i.MX IPUv3" + depends on DRM_IMX + help + Choose this if you have a i.MX5 or i.MX6 processor. diff --git a/drivers/staging/imx-drm/Makefile b/drivers/staging/imx-drm/Makefile new file mode 100644 index 000000000000..83a9056546e6 --- /dev/null +++ b/drivers/staging/imx-drm/Makefile @@ -0,0 +1,9 @@ + +imxdrm-objs := imx-drm-core.o imx-fb.o + +obj-$(CONFIG_DRM_IMX) += imxdrm.o + +obj-$(CONFIG_DRM_IMX_PARALLEL_DISPLAY) += parallel-display.o +obj-$(CONFIG_DRM_IMX_FB_HELPER) += imx-fbdev.o +obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += ipu-v3/ +obj-$(CONFIG_DRM_IMX_IPUV3) += ipuv3-crtc.o diff --git a/drivers/staging/imx-drm/TODO b/drivers/staging/imx-drm/TODO new file mode 100644 index 000000000000..e52adc44e607 --- /dev/null +++ b/drivers/staging/imx-drm/TODO @@ -0,0 +1,22 @@ +TODO: +- get DRM Maintainer review for this code +- Factor out more code to common helper functions +- decide where to put the base driver. It is not specific to a subsystem + and would be used by DRM/KMS and media/V4L2 +- convert irq driver to irq_domain_add_linear + +Missing features (not necessarily for moving out of staging): + +- Add KMS plane support for CRTC driver +- Add LDB (LVDS Display Bridge) support +- Add i.MX6 HDMI support +- Add support for IC (Image converter) +- Add support for CSI (CMOS Sensor interface) +- Add support for VDIC (Video Deinterlacer) + +Many work-in-progress patches for the above features exist. Contact +Sascha Hauer <kernel@pengutronix.de> if you are interested in working +on a specific feature. + +Please send any patches to Greg Kroah-Hartman <gregkh@linuxfoundation.org> and +Sascha Hauer <kernel@pengutronix.de> diff --git a/drivers/staging/imx-drm/imx-drm-core.c b/drivers/staging/imx-drm/imx-drm-core.c new file mode 100644 index 000000000000..1913199ba16e --- /dev/null +++ b/drivers/staging/imx-drm/imx-drm-core.c @@ -0,0 +1,884 @@ +/* + * Freescale i.MX drm driver + * + * Copyright (C) 2011 Sascha Hauer, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/device.h> +#include <linux/platform_device.h> +#include <drm/drmP.h> +#include <drm/drm_fb_helper.h> +#include <drm/drm_crtc_helper.h> +#include <linux/fb.h> +#include <linux/module.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_fb_cma_helper.h> + +#include "imx-drm.h" + +#define MAX_CRTC 4 + +struct crtc_cookie { + void *cookie; + int id; + struct list_head list; +}; + +struct imx_drm_device { + struct drm_device *drm; + struct device *dev; + struct list_head crtc_list; + struct list_head encoder_list; + struct list_head connector_list; + struct mutex mutex; + int references; + int pipes; + struct drm_fbdev_cma *fbhelper; +}; + +struct imx_drm_crtc { + struct drm_crtc *crtc; + struct list_head list; + struct imx_drm_device *imxdrm; + int pipe; + struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs; + struct module *owner; + struct crtc_cookie cookie; +}; + +struct imx_drm_encoder { + struct drm_encoder *encoder; + struct list_head list; + struct module *owner; + struct list_head possible_crtcs; +}; + +struct imx_drm_connector { + struct drm_connector *connector; + struct list_head list; + struct module *owner; +}; + +static int imx_drm_driver_firstopen(struct drm_device *drm) +{ + if (!imx_drm_device_get()) + return -EINVAL; + + return 0; +} + +static void imx_drm_driver_lastclose(struct drm_device *drm) +{ + struct imx_drm_device *imxdrm = drm->dev_private; + + if (imxdrm->fbhelper) + drm_fbdev_cma_restore_mode(imxdrm->fbhelper); + + imx_drm_device_put(); +} + +static int imx_drm_driver_unload(struct drm_device *drm) +{ + struct imx_drm_device *imxdrm = drm->dev_private; + + drm_mode_config_cleanup(imxdrm->drm); + drm_kms_helper_poll_fini(imxdrm->drm); + + return 0; +} + +/* + * We don't care at all for crtc numbers, but the core expects the + * crtcs to be numbered + */ +static struct imx_drm_crtc *imx_drm_crtc_by_num(struct imx_drm_device *imxdrm, + int num) +{ + struct imx_drm_crtc *imx_drm_crtc; + + list_for_each_entry(imx_drm_crtc, &imxdrm->crtc_list, list) + if (imx_drm_crtc->pipe == num) + return imx_drm_crtc; + return NULL; +} + +int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type, + u32 interface_pix_fmt) +{ + struct imx_drm_device *imxdrm = crtc->dev->dev_private; + struct imx_drm_crtc *imx_crtc; + struct imx_drm_crtc_helper_funcs *helper; + + mutex_lock(&imxdrm->mutex); + + list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list) + if (imx_crtc->crtc == crtc) + goto found; + + mutex_unlock(&imxdrm->mutex); + + return -EINVAL; +found: + mutex_unlock(&imxdrm->mutex); + + helper = &imx_crtc->imx_drm_helper_funcs; + if (helper->set_interface_pix_fmt) + return helper->set_interface_pix_fmt(crtc, + encoder_type, interface_pix_fmt); + return 0; +} +EXPORT_SYMBOL_GPL(imx_drm_crtc_panel_format); + +int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc) +{ + return drm_vblank_get(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe); +} +EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_get); + +void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc) +{ + drm_vblank_put(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe); +} +EXPORT_SYMBOL_GPL(imx_drm_crtc_vblank_put); + +void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc) +{ + drm_handle_vblank(imx_drm_crtc->imxdrm->drm, imx_drm_crtc->pipe); +} +EXPORT_SYMBOL_GPL(imx_drm_handle_vblank); + +static int imx_drm_enable_vblank(struct drm_device *drm, int crtc) +{ + struct imx_drm_device *imxdrm = drm->dev_private; + struct imx_drm_crtc *imx_drm_crtc; + int ret; + + imx_drm_crtc = imx_drm_crtc_by_num(imxdrm, crtc); + if (!imx_drm_crtc) + return -EINVAL; + + if (!imx_drm_crtc->imx_drm_helper_funcs.enable_vblank) + return -ENOSYS; + + ret = imx_drm_crtc->imx_drm_helper_funcs.enable_vblank( + imx_drm_crtc->crtc); + + return ret; +} + +static void imx_drm_disable_vblank(struct drm_device *drm, int crtc) +{ + struct imx_drm_device *imxdrm = drm->dev_private; + struct imx_drm_crtc *imx_drm_crtc; + + imx_drm_crtc = imx_drm_crtc_by_num(imxdrm, crtc); + if (!imx_drm_crtc) + return; + + if (!imx_drm_crtc->imx_drm_helper_funcs.disable_vblank) + return; + + imx_drm_crtc->imx_drm_helper_funcs.disable_vblank(imx_drm_crtc->crtc); +} + +static const struct file_operations imx_drm_driver_fops = { + .owner = THIS_MODULE, + .open = drm_open, + .release = drm_release, + .unlocked_ioctl = drm_ioctl, + .mmap = drm_gem_cma_mmap, + .poll = drm_poll, + .fasync = drm_fasync, + .read = drm_read, + .llseek = noop_llseek, +}; + +static struct imx_drm_device *imx_drm_device; + +static struct imx_drm_device *__imx_drm_device(void) +{ + return imx_drm_device; +} + +struct drm_device *imx_drm_device_get(void) +{ + struct imx_drm_device *imxdrm = __imx_drm_device(); + struct imx_drm_encoder *enc; + struct imx_drm_connector *con; + struct imx_drm_crtc *crtc; + + mutex_lock(&imxdrm->mutex); + + list_for_each_entry(enc, &imxdrm->encoder_list, list) { + if (!try_module_get(enc->owner)) { + dev_err(imxdrm->dev, "could not get module %s\n", + module_name(enc->owner)); + goto unwind_enc; + } + } + + list_for_each_entry(con, &imxdrm->connector_list, list) { + if (!try_module_get(con->owner)) { + dev_err(imxdrm->dev, "could not get module %s\n", + module_name(con->owner)); + goto unwind_con; + } + } + + list_for_each_entry(crtc, &imxdrm->crtc_list, list) { + if (!try_module_get(crtc->owner)) { + dev_err(imxdrm->dev, "could not get module %s\n", + module_name(crtc->owner)); + goto unwind_crtc; + } + } + + imxdrm->references++; + + mutex_unlock(&imxdrm->mutex); + + return imxdrm->drm; + +unwind_crtc: + list_for_each_entry_continue_reverse(crtc, &imxdrm->crtc_list, list) + module_put(crtc->owner); +unwind_con: + list_for_each_entry_continue_reverse(con, &imxdrm->connector_list, list) + module_put(con->owner); +unwind_enc: + list_for_each_entry_continue_reverse(enc, &imxdrm->encoder_list, list) + module_put(enc->owner); + + mutex_unlock(&imxdrm->mutex); + + return NULL; + +} +EXPORT_SYMBOL_GPL(imx_drm_device_get); + +void imx_drm_device_put(void) +{ + struct imx_drm_device *imxdrm = __imx_drm_device(); + struct imx_drm_encoder *enc; + struct imx_drm_connector *con; + struct imx_drm_crtc *crtc; + + mutex_lock(&imxdrm->mutex); + + list_for_each_entry(crtc, &imxdrm->crtc_list, list) + module_put(crtc->owner); + + list_for_each_entry(con, &imxdrm->connector_list, list) + module_put(con->owner); + + list_for_each_entry(enc, &imxdrm->encoder_list, list) + module_put(enc->owner); + + imxdrm->references--; + + mutex_unlock(&imxdrm->mutex); +} +EXPORT_SYMBOL_GPL(imx_drm_device_put); + +static int drm_mode_group_reinit(struct drm_device *dev) +{ + struct drm_mode_group *group = &dev->primary->mode_group; + uint32_t *id_list = group->id_list; + int ret; + + ret = drm_mode_group_init_legacy_group(dev, group); + if (ret < 0) + return ret; + + kfree(id_list); + return 0; +} + +/* + * register an encoder to the drm core + */ +static int imx_drm_encoder_register(struct imx_drm_encoder *imx_drm_encoder) +{ + struct imx_drm_device *imxdrm = __imx_drm_device(); + + INIT_LIST_HEAD(&imx_drm_encoder->possible_crtcs); + + drm_encoder_init(imxdrm->drm, imx_drm_encoder->encoder, + imx_drm_encoder->encoder->funcs, + imx_drm_encoder->encoder->encoder_type); + + drm_mode_group_reinit(imxdrm->drm); + + return 0; +} + +/* + * unregister an encoder from the drm core + */ +static void imx_drm_encoder_unregister(struct imx_drm_encoder + *imx_drm_encoder) +{ + struct imx_drm_device *imxdrm = __imx_drm_device(); + + drm_encoder_cleanup(imx_drm_encoder->encoder); + + drm_mode_group_reinit(imxdrm->drm); +} + +/* + * register a connector to the drm core + */ +static int imx_drm_connector_register( + struct imx_drm_connector *imx_drm_connector) +{ + struct imx_drm_device *imxdrm = __imx_drm_device(); + + drm_connector_init(imxdrm->drm, imx_drm_connector->connector, + imx_drm_connector->connector->funcs, + imx_drm_connector->connector->connector_type); + drm_mode_group_reinit(imxdrm->drm); + + return drm_sysfs_connector_add(imx_drm_connector->connector); +} + +/* + * unregister a connector from the drm core + */ +static void imx_drm_connector_unregister( + struct imx_drm_connector *imx_drm_connector) +{ + struct imx_drm_device *imxdrm = __imx_drm_device(); + + drm_sysfs_connector_remove(imx_drm_connector->connector); + drm_connector_cleanup(imx_drm_connector->connector); + + drm_mode_group_reinit(imxdrm->drm); +} + +/* + * register a crtc to the drm core + */ +static int imx_drm_crtc_register(struct imx_drm_crtc *imx_drm_crtc) +{ + struct imx_drm_device *imxdrm = __imx_drm_device(); + int ret; + + drm_crtc_init(imxdrm->drm, imx_drm_crtc->crtc, + imx_drm_crtc->imx_drm_helper_funcs.crtc_funcs); + ret = drm_mode_crtc_set_gamma_size(imx_drm_crtc->crtc, 256); + if (ret) + return ret; + + drm_crtc_helper_add(imx_drm_crtc->crtc, + imx_drm_crtc->imx_drm_helper_funcs.crtc_helper_funcs); + + drm_mode_group_reinit(imxdrm->drm); + + return 0; +} + +/* + * Called by the CRTC driver when all CRTCs are registered. This + * puts all the pieces together and initializes the driver. + * Once this is called no more CRTCs can be registered since + * the drm core has hardcoded the number of crtcs in several + * places. + */ +static int imx_drm_driver_load(struct drm_device *drm, unsigned long flags) +{ + struct imx_drm_device *imxdrm = __imx_drm_device(); + int ret; + + imxdrm->drm = drm; + + drm->dev_private = imxdrm; + + /* + * enable drm irq mode. + * - with irq_enabled = 1, we can use the vblank feature. + * + * P.S. note that we wouldn't use drm irq handler but + * just specific driver own one instead because + * drm framework supports only one irq handler and + * drivers can well take care of their interrupts + */ + drm->irq_enabled = 1; + + drm_mode_config_init(drm); + imx_drm_mode_config_init(drm); + + mutex_lock(&imxdrm->mutex); + + drm_kms_helper_poll_init(imxdrm->drm); + + /* setup the grouping for the legacy output */ + ret = drm_mode_group_init_legacy_group(imxdrm->drm, + &imxdrm->drm->primary->mode_group); + if (ret) + goto err_init; + + ret = drm_vblank_init(imxdrm->drm, MAX_CRTC); + if (ret) + goto err_init; + + /* + * with vblank_disable_allowed = 1, vblank interrupt will be disabled + * by drm timer once a current process gives up ownership of + * vblank event.(after drm_vblank_put function is called) + */ + imxdrm->drm->vblank_disable_allowed = 1; + + ret = 0; + +err_init: + mutex_unlock(&imxdrm->mutex); + + return ret; +} + +static void imx_drm_update_possible_crtcs(void) +{ + struct imx_drm_device *imxdrm = __imx_drm_device(); + struct imx_drm_crtc *imx_drm_crtc; + struct imx_drm_encoder *enc; + struct crtc_cookie *cookie; + + list_for_each_entry(enc, &imxdrm->encoder_list, list) { + u32 possible_crtcs = 0; + + list_for_each_entry(cookie, &enc->possible_crtcs, list) { + list_for_each_entry(imx_drm_crtc, &imxdrm->crtc_list, list) { + if (imx_drm_crtc->cookie.cookie == cookie->cookie && + imx_drm_crtc->cookie.id == cookie->id) { + possible_crtcs |= 1 << imx_drm_crtc->pipe; + } + } + } + enc->encoder->possible_crtcs = possible_crtcs; + enc->encoder->possible_clones = possible_crtcs; + } +} + +/* + * imx_drm_add_crtc - add a new crtc + * + * The return value if !NULL is a cookie for the caller to pass to + * imx_drm_remove_crtc later. + */ +int imx_drm_add_crtc(struct drm_crtc *crtc, + struct imx_drm_crtc **new_crtc, + const struct imx_drm_crtc_helper_funcs *imx_drm_helper_funcs, + struct module *owner, void *cookie, int id) +{ + struct imx_drm_device *imxdrm = __imx_drm_device(); + struct imx_drm_crtc *imx_drm_crtc; + const struct drm_crtc_funcs *crtc_funcs; + int ret; + + mutex_lock(&imxdrm->mutex); + + if (imxdrm->references) { + ret = -EBUSY; + goto err_busy; + } + + imx_drm_crtc = kzalloc(sizeof(*imx_drm_crtc), GFP_KERNEL); + if (!imx_drm_crtc) { + ret = -ENOMEM; + goto err_alloc; + } + + imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs; + imx_drm_crtc->pipe = imxdrm->pipes++; + imx_drm_crtc->cookie.cookie = cookie; + imx_drm_crtc->cookie.id = id; + + crtc_funcs = imx_drm_helper_funcs->crtc_funcs; + + imx_drm_crtc->crtc = crtc; + imx_drm_crtc->imxdrm = imxdrm; + + imx_drm_crtc->owner = owner; + + list_add_tail(&imx_drm_crtc->list, &imxdrm->crtc_list); + + *new_crtc = imx_drm_crtc; + + ret = imx_drm_crtc_register(imx_drm_crtc); + if (ret) + goto err_register; + + imx_drm_update_possible_crtcs(); + + mutex_unlock(&imxdrm->mutex); + + return 0; + +err_register: + kfree(imx_drm_crtc); +err_alloc: +err_busy: + mutex_unlock(&imxdrm->mutex); + return ret; +} +EXPORT_SYMBOL_GPL(imx_drm_add_crtc); + +/* + * imx_drm_remove_crtc - remove a crtc + */ +int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc) +{ + struct imx_drm_device *imxdrm = imx_drm_crtc->imxdrm; + + mutex_lock(&imxdrm->mutex); + + drm_crtc_cleanup(imx_drm_crtc->crtc); + + list_del(&imx_drm_crtc->list); + + drm_mode_group_reinit(imxdrm->drm); + + mutex_unlock(&imxdrm->mutex); + + kfree(imx_drm_crtc); + + return 0; +} +EXPORT_SYMBOL_GPL(imx_drm_remove_crtc); + +/* + * imx_drm_add_encoder - add a new encoder + */ +int imx_drm_add_encoder(struct drm_encoder *encoder, + struct imx_drm_encoder **newenc, struct module *owner) +{ + struct imx_drm_device *imxdrm = __imx_drm_device(); + struct imx_drm_encoder *imx_drm_encoder; + int ret; + + mutex_lock(&imxdrm->mutex); + + if (imxdrm->references) { + ret = -EBUSY; + goto err_busy; + } + + imx_drm_encoder = kzalloc(sizeof(*imx_drm_encoder), GFP_KERNEL); + if (!imx_drm_encoder) { + ret = -ENOMEM; + goto err_alloc; + } + + imx_drm_encoder->encoder = encoder; + imx_drm_encoder->owner = owner; + + ret = imx_drm_encoder_register(imx_drm_encoder); + if (ret) { + kfree(imx_drm_encoder); + ret = -ENOMEM; + goto err_register; + } + + list_add_tail(&imx_drm_encoder->list, &imxdrm->encoder_list); + + *newenc = imx_drm_encoder; + + mutex_unlock(&imxdrm->mutex); + + return 0; + +err_register: + kfree(imx_drm_encoder); +err_alloc: +err_busy: + mutex_unlock(&imxdrm->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(imx_drm_add_encoder); + +int imx_drm_encoder_add_possible_crtcs( + struct imx_drm_encoder *imx_drm_encoder, + struct device_node *np) +{ + struct imx_drm_device *imxdrm = __imx_drm_device(); + struct of_phandle_args args; + struct crtc_cookie *c; + int ret = 0; + int i; + + if (!list_empty(&imx_drm_encoder->possible_crtcs)) + return -EBUSY; + + for (i = 0; !ret; i++) { + ret = of_parse_phandle_with_args(np, "crtcs", + "#crtc-cells", i, &args); + if (ret < 0) + break; + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) { + of_node_put(args.np); + return -ENOMEM; + } + + c->cookie = args.np; + c->id = args.args_count > 0 ? args.args[0] : 0; + + of_node_put(args.np); + + mutex_lock(&imxdrm->mutex); + + list_add_tail(&c->list, &imx_drm_encoder->possible_crtcs); + + mutex_unlock(&imxdrm->mutex); + } + + imx_drm_update_possible_crtcs(); + + return 0; +} +EXPORT_SYMBOL_GPL(imx_drm_encoder_add_possible_crtcs); + +int imx_drm_encoder_get_mux_id(struct imx_drm_encoder *imx_drm_encoder, + struct drm_crtc *crtc) +{ + struct imx_drm_device *imxdrm = __imx_drm_device(); + struct imx_drm_crtc *imx_crtc; + int i = 0; + + mutex_lock(&imxdrm->mutex); + + list_for_each_entry(imx_crtc, &imxdrm->crtc_list, list) { + if (imx_crtc->crtc == crtc) + goto found; + i++; + } + + mutex_unlock(&imxdrm->mutex); + + return -EINVAL; +found: + mutex_unlock(&imxdrm->mutex); + + return i; +} + +/* + * imx_drm_remove_encoder - remove an encoder + */ +int imx_drm_remove_encoder(struct imx_drm_encoder *imx_drm_encoder) +{ + struct imx_drm_device *imxdrm = __imx_drm_device(); + struct crtc_cookie *c, *tmp; + + mutex_lock(&imxdrm->mutex); + + imx_drm_encoder_unregister(imx_drm_encoder); + + list_del(&imx_drm_encoder->list); + + list_for_each_entry_safe(c, tmp, &imx_drm_encoder->possible_crtcs, + list) + kfree(c); + + mutex_unlock(&imxdrm->mutex); + + kfree(imx_drm_encoder); + + return 0; +} +EXPORT_SYMBOL_GPL(imx_drm_remove_encoder); + +/* + * imx_drm_add_connector - add a connector + */ +int imx_drm_add_connector(struct drm_connector *connector, + struct imx_drm_connector **new_con, + struct module *owner) +{ + struct imx_drm_device *imxdrm = __imx_drm_device(); + struct imx_drm_connector *imx_drm_connector; + int ret; + + mutex_lock(&imxdrm->mutex); + + if (imxdrm->references) { + ret = -EBUSY; + goto err_busy; + } + + imx_drm_connector = kzalloc(sizeof(*imx_drm_connector), GFP_KERNEL); + if (!imx_drm_connector) { + ret = -ENOMEM; + goto err_alloc; + } + + imx_drm_connector->connector = connector; + imx_drm_connector->owner = owner; + + ret = imx_drm_connector_register(imx_drm_connector); + if (ret) + goto err_register; + + list_add_tail(&imx_drm_connector->list, &imxdrm->connector_list); + + *new_con = imx_drm_connector; + + mutex_unlock(&imxdrm->mutex); + + return 0; + +err_register: + kfree(imx_drm_connector); +err_alloc: +err_busy: + mutex_unlock(&imxdrm->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(imx_drm_add_connector); + +void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper) +{ + struct imx_drm_device *imxdrm = __imx_drm_device(); + + imxdrm->fbhelper = fbdev_helper; +} +EXPORT_SYMBOL_GPL(imx_drm_fb_helper_set); + +/* + * imx_drm_remove_connector - remove a connector + */ +int imx_drm_remove_connector(struct imx_drm_connector *imx_drm_connector) +{ + struct imx_drm_device *imxdrm = __imx_drm_device(); + + mutex_lock(&imxdrm->mutex); + + imx_drm_connector_unregister(imx_drm_connector); + + list_del(&imx_drm_connector->list); + + mutex_unlock(&imxdrm->mutex); + + kfree(imx_drm_connector); + + return 0; +} +EXPORT_SYMBOL_GPL(imx_drm_remove_connector); + +static struct drm_ioctl_desc imx_drm_ioctls[] = { + /* none so far */ +}; + +static struct drm_driver imx_drm_driver = { + .driver_features = DRIVER_MODESET | DRIVER_GEM, + .load = imx_drm_driver_load, + .unload = imx_drm_driver_unload, + .firstopen = imx_drm_driver_firstopen, + .lastclose = imx_drm_driver_lastclose, + .gem_free_object = drm_gem_cma_free_object, + .gem_vm_ops = &drm_gem_cma_vm_ops, + .dumb_create = drm_gem_cma_dumb_create, + .dumb_map_offset = drm_gem_cma_dumb_map_offset, + .dumb_destroy = drm_gem_cma_dumb_destroy, + + .get_vblank_counter = drm_vblank_count, + .enable_vblank = imx_drm_enable_vblank, + .disable_vblank = imx_drm_disable_vblank, + .ioctls = imx_drm_ioctls, + .num_ioctls = ARRAY_SIZE(imx_drm_ioctls), + .fops = &imx_drm_driver_fops, + .name = "imx-drm", + .desc = "i.MX DRM graphics", + .date = "20120507", + .major = 1, + .minor = 0, + .patchlevel = 0, +}; + +static int imx_drm_platform_probe(struct platform_device *pdev) +{ + imx_drm_device->dev = &pdev->dev; + + return drm_platform_init(&imx_drm_driver, pdev); +} + +static int imx_drm_platform_remove(struct platform_device *pdev) +{ + drm_platform_exit(&imx_drm_driver, pdev); + + return 0; +} + +static struct platform_driver imx_drm_pdrv = { + .probe = imx_drm_platform_probe, + .remove = __devexit_p(imx_drm_platform_remove), + .driver = { + .owner = THIS_MODULE, + .name = "imx-drm", + }, +}; + +static struct platform_device *imx_drm_pdev; + +static int __init imx_drm_init(void) +{ + int ret; + + imx_drm_device = kzalloc(sizeof(*imx_drm_device), GFP_KERNEL); + if (!imx_drm_device) + return -ENOMEM; + + mutex_init(&imx_drm_device->mutex); + INIT_LIST_HEAD(&imx_drm_device->crtc_list); + INIT_LIST_HEAD(&imx_drm_device->connector_list); + INIT_LIST_HEAD(&imx_drm_device->encoder_list); + + imx_drm_pdev = platform_device_register_simple("imx-drm", -1, NULL, 0); + if (!imx_drm_pdev) { + ret = -EINVAL; + goto err_pdev; + } + + imx_drm_pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32), + + ret = platform_driver_register(&imx_drm_pdrv); + if (ret) + goto err_pdrv; + + return 0; + +err_pdrv: + platform_device_unregister(imx_drm_pdev); +err_pdev: + kfree(imx_drm_device); + + return ret; +} + +static void __exit imx_drm_exit(void) +{ + platform_device_unregister(imx_drm_pdev); + platform_driver_unregister(&imx_drm_pdrv); + + kfree(imx_drm_device); +} + +module_init(imx_drm_init); +module_exit(imx_drm_exit); + +MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); +MODULE_DESCRIPTION("i.MX drm driver core"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/imx-drm/imx-drm.h b/drivers/staging/imx-drm/imx-drm.h new file mode 100644 index 000000000000..ae28a490c445 --- /dev/null +++ b/drivers/staging/imx-drm/imx-drm.h @@ -0,0 +1,58 @@ +#ifndef _IMX_DRM_H_ +#define _IMX_DRM_H_ + +struct imx_drm_crtc; +struct drm_fbdev_cma; + +struct imx_drm_crtc_helper_funcs { + int (*enable_vblank)(struct drm_crtc *crtc); + void (*disable_vblank)(struct drm_crtc *crtc); + int (*set_interface_pix_fmt)(struct drm_crtc *crtc, u32 encoder_type, + u32 pix_fmt); + const struct drm_crtc_helper_funcs *crtc_helper_funcs; + const struct drm_crtc_funcs *crtc_funcs; +}; + +int imx_drm_add_crtc(struct drm_crtc *crtc, + struct imx_drm_crtc **new_crtc, + const struct imx_drm_crtc_helper_funcs *imx_helper_funcs, + struct module *owner, void *cookie, int id); +int imx_drm_remove_crtc(struct imx_drm_crtc *); +int imx_drm_init_drm(struct platform_device *pdev, + int preferred_bpp); +int imx_drm_exit_drm(void); + +int imx_drm_crtc_vblank_get(struct imx_drm_crtc *imx_drm_crtc); +void imx_drm_crtc_vblank_put(struct imx_drm_crtc *imx_drm_crtc); +void imx_drm_handle_vblank(struct imx_drm_crtc *imx_drm_crtc); + +struct imx_drm_encoder; +int imx_drm_add_encoder(struct drm_encoder *encoder, + struct imx_drm_encoder **new_enc, + struct module *owner); +int imx_drm_remove_encoder(struct imx_drm_encoder *); + +struct imx_drm_connector; +int imx_drm_add_connector(struct drm_connector *connector, + struct imx_drm_connector **new_con, + struct module *owner); +int imx_drm_remove_connector(struct imx_drm_connector *); + +void imx_drm_mode_config_init(struct drm_device *drm); + +struct drm_gem_cma_object *imx_drm_fb_get_obj(struct drm_framebuffer *fb); + +struct drm_device *imx_drm_device_get(void); +void imx_drm_device_put(void); +int imx_drm_crtc_panel_format(struct drm_crtc *crtc, u32 encoder_type, + u32 interface_pix_fmt); +void imx_drm_fb_helper_set(struct drm_fbdev_cma *fbdev_helper); + +struct device_node; + +int imx_drm_encoder_get_mux_id(struct imx_drm_encoder *imx_drm_encoder, + struct drm_crtc *crtc); +int imx_drm_encoder_add_possible_crtcs(struct imx_drm_encoder *imx_drm_encoder, + struct device_node *np); + +#endif /* _IMX_DRM_H_ */ diff --git a/drivers/staging/imx-drm/imx-fb.c b/drivers/staging/imx-drm/imx-fb.c new file mode 100644 index 000000000000..03a7b4e14f67 --- /dev/null +++ b/drivers/staging/imx-drm/imx-fb.c @@ -0,0 +1,47 @@ +/* + * i.MX drm driver + * + * Copyright (C) 2012 Sascha Hauer, Pengutronix + * + * Based on Samsung Exynos code + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include <linux/module.h> +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_fb_cma_helper.h> + +#include "imx-drm.h" + +static struct drm_mode_config_funcs imx_drm_mode_config_funcs = { + .fb_create = drm_fb_cma_create, +}; + +void imx_drm_mode_config_init(struct drm_device *dev) +{ + dev->mode_config.min_width = 64; + dev->mode_config.min_height = 64; + + /* + * set max width and height as default value(4096x4096). + * this value would be used to check framebuffer size limitation + * at drm_mode_addfb(). + */ + dev->mode_config.max_width = 4096; + dev->mode_config.max_height = 4096; + + dev->mode_config.funcs = &imx_drm_mode_config_funcs; +} diff --git a/drivers/staging/imx-drm/imx-fbdev.c b/drivers/staging/imx-drm/imx-fbdev.c new file mode 100644 index 000000000000..8331739c3d08 --- /dev/null +++ b/drivers/staging/imx-drm/imx-fbdev.c @@ -0,0 +1,74 @@ +/* + * i.MX drm driver + * + * Copyright (C) 2012 Sascha Hauer, Pengutronix + * + * Based on Samsung Exynos code + * + * Copyright (c) 2011 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ +#include <linux/module.h> +#include <drm/drmP.h> +#include <drm/drm_crtc.h> +#include <drm/drm_crtc_helper.h> +#include <drm/drm_fb_cma_helper.h> + +#include "imx-drm.h" + +#define MAX_CONNECTOR 4 +#define PREFERRED_BPP 16 + +static struct drm_fbdev_cma *fbdev_cma; + +static int legacyfb_depth = 16; + +module_param(legacyfb_depth, int, 0444); + +static int __init imx_fb_helper_init(void) +{ + struct drm_device *drm = imx_drm_device_get(); + + if (!drm) + return -EINVAL; + + if (legacyfb_depth != 16 && legacyfb_depth != 32) { + pr_warn("i.MX legacyfb: invalid legacyfb_depth setting. defaulting to 16bpp\n"); + legacyfb_depth = 16; + } + + fbdev_cma = drm_fbdev_cma_init(drm, legacyfb_depth, + drm->mode_config.num_crtc, MAX_CONNECTOR); + + if (IS_ERR(fbdev_cma)) { + imx_drm_device_put(); + return PTR_ERR(fbdev_cma); + } + + imx_drm_fb_helper_set(fbdev_cma); + + return 0; +} + +static void __exit imx_fb_helper_exit(void) +{ + imx_drm_fb_helper_set(NULL); + drm_fbdev_cma_fini(fbdev_cma); + imx_drm_device_put(); +} + +late_initcall(imx_fb_helper_init); +module_exit(imx_fb_helper_exit); + +MODULE_DESCRIPTION("Freescale i.MX legacy fb driver"); +MODULE_AUTHOR("Sascha Hauer, Pengutronix"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/imx-drm/ipu-v3/Makefile b/drivers/staging/imx-drm/ipu-v3/Makefile new file mode 100644 index 000000000000..28ed72e98a96 --- /dev/null +++ b/drivers/staging/imx-drm/ipu-v3/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_DRM_IMX_IPUV3_CORE) += imx-ipu-v3.o + +imx-ipu-v3-objs := ipu-common.o ipu-dc.o ipu-di.o ipu-dp.o ipu-dmfc.o diff --git a/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h new file mode 100644 index 000000000000..74158dd73758 --- /dev/null +++ b/drivers/staging/imx-drm/ipu-v3/imx-ipu-v3.h @@ -0,0 +1,318 @@ +/* + * Copyright 2005-2009 Freescale Semiconductor, Inc. + * + * The code contained herein is licensed under the GNU Lesser General + * Public License. You may obtain a copy of the GNU Lesser General + * Public License Version 2.1 or later at the following locations: + * + * http://www.opensource.org/licenses/lgpl-license.html + * http://www.gnu.org/copyleft/lgpl.html + */ + +#ifndef __DRM_IPU_H__ +#define __DRM_IPU_H__ + +#include <linux/types.h> +#include <linux/videodev2.h> +#include <linux/bitmap.h> +#include <linux/fb.h> +#include <linux/videodev2.h> + +struct ipu_soc; + +enum ipuv3_type { + IPUV3EX, + IPUV3M, + IPUV3H, +}; + +/* + * Bitfield of Display Interface signal polarities. + */ +struct ipu_di_signal_cfg { + unsigned datamask_en:1; + unsigned interlaced:1; + unsigned odd_field_first:1; + unsigned clksel_en:1; + unsigned clkidle_en:1; + unsigned data_pol:1; /* true = inverted */ + unsigned clk_pol:1; /* true = rising edge */ + unsigned enable_pol:1; + unsigned Hsync_pol:1; /* true = active high */ + unsigned Vsync_pol:1; + + u16 width; + u16 height; + u32 pixel_fmt; + u16 h_start_width; + u16 h_sync_width; + u16 h_end_width; + u16 v_start_width; + u16 v_sync_width; + u16 v_end_width; + u32 v_to_h_sync; + unsigned long pixelclock; +#define IPU_DI_CLKMODE_SYNC (1 << 0) +#define IPU_DI_CLKMODE_EXT (1 << 1) + unsigned long clkflags; +}; + +enum ipu_color_space { + IPUV3_COLORSPACE_RGB, + IPUV3_COLORSPACE_YUV, + IPUV3_COLORSPACE_UNKNOWN, +}; + +struct ipuv3_channel; + +enum ipu_channel_irq { + IPU_IRQ_EOF = 0, + IPU_IRQ_NFACK = 64, + IPU_IRQ_NFB4EOF = 128, + IPU_IRQ_EOS = 192, +}; + +int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel, + enum ipu_channel_irq irq); + +#define IPU_IRQ_DP_SF_START (448 + 2) +#define IPU_IRQ_DP_SF_END (448 + 3) +#define IPU_IRQ_BG_SF_END IPU_IRQ_DP_SF_END, +#define IPU_IRQ_DC_FC_0 (448 + 8) +#define IPU_IRQ_DC_FC_1 (448 + 9) +#define IPU_IRQ_DC_FC_2 (448 + 10) +#define IPU_IRQ_DC_FC_3 (448 + 11) +#define IPU_IRQ_DC_FC_4 (448 + 12) +#define IPU_IRQ_DC_FC_6 (448 + 13) +#define IPU_IRQ_VSYNC_PRE_0 (448 + 14) +#define IPU_IRQ_VSYNC_PRE_1 (448 + 15) + +/* + * IPU Image DMA Controller (idmac) functions + */ +struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned channel); +void ipu_idmac_put(struct ipuv3_channel *); + +int ipu_idmac_enable_channel(struct ipuv3_channel *channel); +int ipu_idmac_disable_channel(struct ipuv3_channel *channel); + +void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel, + bool doublebuffer); +void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num); + +/* + * IPU Display Controller (dc) functions + */ +struct ipu_dc; +struct ipu_di; +struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel); +void ipu_dc_put(struct ipu_dc *dc); +int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced, + u32 pixel_fmt, u32 width); +void ipu_dc_enable_channel(struct ipu_dc *dc); +void ipu_dc_disable_channel(struct ipu_dc *dc); + +/* + * IPU Display Interface (di) functions + */ +struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp); +void ipu_di_put(struct ipu_di *); +int ipu_di_disable(struct ipu_di *); +int ipu_di_enable(struct ipu_di *); +int ipu_di_get_num(struct ipu_di *); +int ipu_di_init_sync_panel(struct ipu_di *, struct ipu_di_signal_cfg *sig); + +/* + * IPU Display Multi FIFO Controller (dmfc) functions + */ +struct dmfc_channel; +int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc); +void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc); +int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc, + unsigned long bandwidth_mbs, int burstsize); +void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc); +int ipu_dmfc_init_channel(struct dmfc_channel *dmfc, int width); +struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipuv3_channel); +void ipu_dmfc_put(struct dmfc_channel *dmfc); + +/* + * IPU Display Processor (dp) functions + */ +#define IPU_DP_FLOW_SYNC_BG 0 +#define IPU_DP_FLOW_SYNC_FG 1 +#define IPU_DP_FLOW_ASYNC0_BG 2 +#define IPU_DP_FLOW_ASYNC0_FG 3 +#define IPU_DP_FLOW_ASYNC1_BG 4 +#define IPU_DP_FLOW_ASYNC1_FG 5 + +struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow); +void ipu_dp_put(struct ipu_dp *); +int ipu_dp_enable_channel(struct ipu_dp *dp); +void ipu_dp_disable_channel(struct ipu_dp *dp); +int ipu_dp_setup_channel(struct ipu_dp *dp, + enum ipu_color_space in, enum ipu_color_space out); +int ipu_dp_set_window_pos(struct ipu_dp *, u16 x_pos, u16 y_pos); +int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, u8 alpha, + bool bg_chan); + +#define IPU_CPMEM_WORD(word, ofs, size) ((((word) * 160 + (ofs)) << 8) | (size)) + +#define IPU_FIELD_UBO IPU_CPMEM_WORD(0, 46, 22) +#define IPU_FIELD_VBO IPU_CPMEM_WORD(0, 68, 22) +#define IPU_FIELD_IOX IPU_CPMEM_WORD(0, 90, 4) +#define IPU_FIELD_RDRW IPU_CPMEM_WORD(0, 94, 1) +#define IPU_FIELD_SO IPU_CPMEM_WORD(0, 113, 1) +#define IPU_FIELD_SLY IPU_CPMEM_WORD(1, 102, 14) +#define IPU_FIELD_SLUV IPU_CPMEM_WORD(1, 128, 14) + +#define IPU_FIELD_XV IPU_CPMEM_WORD(0, 0, 10) +#define IPU_FIELD_YV IPU_CPMEM_WORD(0, 10, 9) +#define IPU_FIELD_XB IPU_CPMEM_WORD(0, 19, 13) +#define IPU_FIELD_YB IPU_CPMEM_WORD(0, 32, 12) +#define IPU_FIELD_NSB_B IPU_CPMEM_WORD(0, 44, 1) +#define IPU_FIELD_CF IPU_CPMEM_WORD(0, 45, 1) +#define IPU_FIELD_SX IPU_CPMEM_WORD(0, 46, 12) +#define IPU_FIELD_SY IPU_CPMEM_WORD(0, 58, 11) +#define IPU_FIELD_NS IPU_CPMEM_WORD(0, 69, 10) +#define IPU_FIELD_SDX IPU_CPMEM_WORD(0, 79, 7) +#define IPU_FIELD_SM IPU_CPMEM_WORD(0, 86, 10) +#define IPU_FIELD_SCC IPU_CPMEM_WORD(0, 96, 1) +#define IPU_FIELD_SCE IPU_CPMEM_WORD(0, 97, 1) +#define IPU_FIELD_SDY IPU_CPMEM_WORD(0, 98, 7) +#define IPU_FIELD_SDRX IPU_CPMEM_WORD(0, 105, 1) +#define IPU_FIELD_SDRY IPU_CPMEM_WORD(0, 106, 1) +#define IPU_FIELD_BPP IPU_CPMEM_WORD(0, 107, 3) +#define IPU_FIELD_DEC_SEL IPU_CPMEM_WORD(0, 110, 2) +#define IPU_FIELD_DIM IPU_CPMEM_WORD(0, 112, 1) +#define IPU_FIELD_BNDM IPU_CPMEM_WORD(0, 114, 3) +#define IPU_FIELD_BM IPU_CPMEM_WORD(0, 117, 2) +#define IPU_FIELD_ROT IPU_CPMEM_WORD(0, 119, 1) +#define IPU_FIELD_HF IPU_CPMEM_WORD(0, 120, 1) +#define IPU_FIELD_VF IPU_CPMEM_WORD(0, 121, 1) +#define IPU_FIELD_THE IPU_CPMEM_WORD(0, 122, 1) +#define IPU_FIELD_CAP IPU_CPMEM_WORD(0, 123, 1) +#define IPU_FIELD_CAE IPU_CPMEM_WORD(0, 124, 1) +#define IPU_FIELD_FW IPU_CPMEM_WORD(0, 125, 13) +#define IPU_FIELD_FH IPU_CPMEM_WORD(0, 138, 12) +#define IPU_FIELD_EBA0 IPU_CPMEM_WORD(1, 0, 29) +#define IPU_FIELD_EBA1 IPU_CPMEM_WORD(1, 29, 29) +#define IPU_FIELD_ILO IPU_CPMEM_WORD(1, 58, 20) +#define IPU_FIELD_NPB IPU_CPMEM_WORD(1, 78, 7) +#define IPU_FIELD_PFS IPU_CPMEM_WORD(1, 85, 4) +#define IPU_FIELD_ALU IPU_CPMEM_WORD(1, 89, 1) +#define IPU_FIELD_ALBM IPU_CPMEM_WORD(1, 90, 3) +#define IPU_FIELD_ID IPU_CPMEM_WORD(1, 93, 2) +#define IPU_FIELD_TH IPU_CPMEM_WORD(1, 95, 7) +#define IPU_FIELD_SL IPU_CPMEM_WORD(1, 102, 14) +#define IPU_FIELD_WID0 IPU_CPMEM_WORD(1, 116, 3) +#define IPU_FIELD_WID1 IPU_CPMEM_WORD(1, 119, 3) +#define IPU_FIELD_WID2 IPU_CPMEM_WORD(1, 122, 3) +#define IPU_FIELD_WID3 IPU_CPMEM_WORD(1, 125, 3) +#define IPU_FIELD_OFS0 IPU_CPMEM_WORD(1, 128, 5) +#define IPU_FIELD_OFS1 IPU_CPMEM_WORD(1, 133, 5) +#define IPU_FIELD_OFS2 IPU_CPMEM_WORD(1, 138, 5) +#define IPU_FIELD_OFS3 IPU_CPMEM_WORD(1, 143, 5) +#define IPU_FIELD_SXYS IPU_CPMEM_WORD(1, 148, 1) +#define IPU_FIELD_CRE IPU_CPMEM_WORD(1, 149, 1) +#define IPU_FIELD_DEC_SEL2 IPU_CPMEM_WORD(1, 150, 1) + +struct ipu_cpmem_word { + u32 data[5]; + u32 res[3]; +}; + +struct ipu_ch_param { + struct ipu_cpmem_word word[2]; +}; + +void ipu_ch_param_write_field(struct ipu_ch_param __iomem *base, u32 wbs, u32 v); +u32 ipu_ch_param_read_field(struct ipu_ch_param __iomem *base, u32 wbs); +struct ipu_ch_param __iomem *ipu_get_cpmem(struct ipuv3_channel *channel); +void ipu_ch_param_dump(struct ipu_ch_param __iomem *p); + +static inline void ipu_ch_param_zero(struct ipu_ch_param __iomem *p) +{ + int i; + void __iomem *base = p; + + for (i = 0; i < sizeof(*p) / sizeof(u32); i++) + writel(0, base + i * sizeof(u32)); +} + +static inline void ipu_cpmem_set_buffer(struct ipu_ch_param __iomem *p, + int bufnum, dma_addr_t buf) +{ + if (bufnum) + ipu_ch_param_write_field(p, IPU_FIELD_EBA1, buf >> 3); + else + ipu_ch_param_write_field(p, IPU_FIELD_EBA0, buf >> 3); +} + +static inline void ipu_cpmem_set_resolution(struct ipu_ch_param __iomem *p, + int xres, int yres) +{ + ipu_ch_param_write_field(p, IPU_FIELD_FW, xres - 1); + ipu_ch_param_write_field(p, IPU_FIELD_FH, yres - 1); +} + +static inline void ipu_cpmem_set_stride(struct ipu_ch_param __iomem *p, + int stride) +{ + ipu_ch_param_write_field(p, IPU_FIELD_SLY, stride - 1); +} + +void ipu_cpmem_set_high_priority(struct ipuv3_channel *channel); + +struct ipu_rgb { + struct fb_bitfield red; + struct fb_bitfield green; + struct fb_bitfield blue; + struct fb_bitfield transp; + int bits_per_pixel; +}; + +struct ipu_image { + struct v4l2_pix_format pix; + struct v4l2_rect rect; + dma_addr_t phys; +}; + +int ipu_cpmem_set_format_passthrough(struct ipu_ch_param __iomem *p, + int width); + +int ipu_cpmem_set_format_rgb(struct ipu_ch_param __iomem *, + struct ipu_rgb *rgb); + +static inline void ipu_cpmem_interlaced_scan(struct ipu_ch_param *p, + int stride) +{ + ipu_ch_param_write_field(p, IPU_FIELD_SO, 1); + ipu_ch_param_write_field(p, IPU_FIELD_ILO, stride / 8); + ipu_ch_param_write_field(p, IPU_FIELD_SLY, (stride * 2) - 1); +}; + +void ipu_cpmem_set_yuv_planar(struct ipu_ch_param __iomem *p, u32 pixel_format, + int stride, int height); +void ipu_cpmem_set_yuv_planar_full(struct ipu_ch_param __iomem *p, + u32 pixel_format, int stride, int u_offset, int v_offset); +int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 pixelformat); +int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem, + struct ipu_image *image); + +enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat); + +static inline void ipu_cpmem_set_burstsize(struct ipu_ch_param __iomem *p, + int burstsize) +{ + ipu_ch_param_write_field(p, IPU_FIELD_NPB, burstsize - 1); +}; + +struct ipu_client_platformdata { + int di; + int dc; + int dp; + int dmfc; + int dma[2]; +}; + +#endif /* __DRM_IPU_H__ */ diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-common.c b/drivers/staging/imx-drm/ipu-v3/ipu-common.c new file mode 100644 index 000000000000..f381960f42b0 --- /dev/null +++ b/drivers/staging/imx-drm/ipu-v3/ipu-common.c @@ -0,0 +1,1143 @@ +/* + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de> + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ +#include <linux/module.h> +#include <linux/export.h> +#include <linux/types.h> +#include <linux/init.h> +#include <linux/platform_device.h> +#include <linux/err.h> +#include <linux/spinlock.h> +#include <linux/delay.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/clk.h> +#include <linux/list.h> +#include <linux/irq.h> +#include <linux/of_device.h> +#include <asm/mach/irq.h> + +#include "imx-ipu-v3.h" +#include "ipu-prv.h" + +static inline u32 ipu_cm_read(struct ipu_soc *ipu, unsigned offset) +{ + return readl(ipu->cm_reg + offset); +} + +static inline void ipu_cm_write(struct ipu_soc *ipu, u32 value, unsigned offset) +{ + writel(value, ipu->cm_reg + offset); +} + +static inline u32 ipu_idmac_read(struct ipu_soc *ipu, unsigned offset) +{ + return readl(ipu->idmac_reg + offset); +} + +static inline void ipu_idmac_write(struct ipu_soc *ipu, u32 value, + unsigned offset) +{ + writel(value, ipu->idmac_reg + offset); +} + +void ipu_srm_dp_sync_update(struct ipu_soc *ipu) +{ + u32 val; + + val = ipu_cm_read(ipu, IPU_SRM_PRI2); + val |= 0x8; + ipu_cm_write(ipu, val, IPU_SRM_PRI2); +} +EXPORT_SYMBOL_GPL(ipu_srm_dp_sync_update); + +struct ipu_ch_param __iomem *ipu_get_cpmem(struct ipuv3_channel *channel) +{ + struct ipu_soc *ipu = channel->ipu; + + return ipu->cpmem_base + channel->num; +} +EXPORT_SYMBOL_GPL(ipu_get_cpmem); + +void ipu_cpmem_set_high_priority(struct ipuv3_channel *channel) +{ + struct ipu_soc *ipu = channel->ipu; + struct ipu_ch_param __iomem *p = ipu_get_cpmem(channel); + u32 val; + + if (ipu->ipu_type == IPUV3EX) + ipu_ch_param_write_field(p, IPU_FIELD_ID, 1); + + val = ipu_idmac_read(ipu, IDMAC_CHA_PRI(channel->num)); + val |= 1 << (channel->num % 32); + ipu_idmac_write(ipu, val, IDMAC_CHA_PRI(channel->num)); +}; +EXPORT_SYMBOL_GPL(ipu_cpmem_set_high_priority); + +void ipu_ch_param_write_field(struct ipu_ch_param __iomem *base, u32 wbs, u32 v) +{ + u32 bit = (wbs >> 8) % 160; + u32 size = wbs & 0xff; + u32 word = (wbs >> 8) / 160; + u32 i = bit / 32; + u32 ofs = bit % 32; + u32 mask = (1 << size) - 1; + u32 val; + + pr_debug("%s %d %d %d\n", __func__, word, bit , size); + + val = readl(&base->word[word].data[i]); + val &= ~(mask << ofs); + val |= v << ofs; + writel(val, &base->word[word].data[i]); + + if ((bit + size - 1) / 32 > i) { + val = readl(&base->word[word].data[i + 1]); + val &= ~(mask >> (ofs ? (32 - ofs) : 0)); + val |= v >> (ofs ? (32 - ofs) : 0); + writel(val, &base->word[word].data[i + 1]); + } +} +EXPORT_SYMBOL_GPL(ipu_ch_param_write_field); + +u32 ipu_ch_param_read_field(struct ipu_ch_param __iomem *base, u32 wbs) +{ + u32 bit = (wbs >> 8) % 160; + u32 size = wbs & 0xff; + u32 word = (wbs >> 8) / 160; + u32 i = bit / 32; + u32 ofs = bit % 32; + u32 mask = (1 << size) - 1; + u32 val = 0; + + pr_debug("%s %d %d %d\n", __func__, word, bit , size); + + val = (readl(&base->word[word].data[i]) >> ofs) & mask; + + if ((bit + size - 1) / 32 > i) { + u32 tmp; + tmp = readl(&base->word[word].data[i + 1]); + tmp &= mask >> (ofs ? (32 - ofs) : 0); + val |= tmp << (ofs ? (32 - ofs) : 0); + } + + return val; +} +EXPORT_SYMBOL_GPL(ipu_ch_param_read_field); + +int ipu_cpmem_set_format_rgb(struct ipu_ch_param __iomem *p, + struct ipu_rgb *rgb) +{ + int bpp = 0, npb = 0, ro, go, bo, to; + + ro = rgb->bits_per_pixel - rgb->red.length - rgb->red.offset; + go = rgb->bits_per_pixel - rgb->green.length - rgb->green.offset; + bo = rgb->bits_per_pixel - rgb->blue.length - rgb->blue.offset; + to = rgb->bits_per_pixel - rgb->transp.length - rgb->transp.offset; + + ipu_ch_param_write_field(p, IPU_FIELD_WID0, rgb->red.length - 1); + ipu_ch_param_write_field(p, IPU_FIELD_OFS0, ro); + ipu_ch_param_write_field(p, IPU_FIELD_WID1, rgb->green.length - 1); + ipu_ch_param_write_field(p, IPU_FIELD_OFS1, go); + ipu_ch_param_write_field(p, IPU_FIELD_WID2, rgb->blue.length - 1); + ipu_ch_param_write_field(p, IPU_FIELD_OFS2, bo); + + if (rgb->transp.length) { + ipu_ch_param_write_field(p, IPU_FIELD_WID3, + rgb->transp.length - 1); + ipu_ch_param_write_field(p, IPU_FIELD_OFS3, to); + } else { + ipu_ch_param_write_field(p, IPU_FIELD_WID3, 7); + ipu_ch_param_write_field(p, IPU_FIELD_OFS3, + rgb->bits_per_pixel); + } + + switch (rgb->bits_per_pixel) { + case 32: + bpp = 0; + npb = 15; + break; + case 24: + bpp = 1; + npb = 19; + break; + case 16: + bpp = 3; + npb = 31; + break; + case 8: + bpp = 5; + npb = 63; + break; + default: + return -EINVAL; + } + ipu_ch_param_write_field(p, IPU_FIELD_BPP, bpp); + ipu_ch_param_write_field(p, IPU_FIELD_NPB, npb); + ipu_ch_param_write_field(p, IPU_FIELD_PFS, 7); /* rgb mode */ + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_rgb); + +int ipu_cpmem_set_format_passthrough(struct ipu_ch_param __iomem *p, + int width) +{ + int bpp = 0, npb = 0; + + switch (width) { + case 32: + bpp = 0; + npb = 15; + break; + case 24: + bpp = 1; + npb = 19; + break; + case 16: + bpp = 3; + npb = 31; + break; + case 8: + bpp = 5; + npb = 63; + break; + default: + return -EINVAL; + } + + ipu_ch_param_write_field(p, IPU_FIELD_BPP, bpp); + ipu_ch_param_write_field(p, IPU_FIELD_NPB, npb); + ipu_ch_param_write_field(p, IPU_FIELD_PFS, 6); /* raw mode */ + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_cpmem_set_format_passthrough); + +void ipu_cpmem_set_yuv_planar_full(struct ipu_ch_param __iomem *p, + u32 pixel_format, int stride, int u_offset, int v_offset) +{ + switch (pixel_format) { + case V4L2_PIX_FMT_YUV420: + ipu_ch_param_write_field(p, IPU_FIELD_SLUV, (stride / 2) - 1); + ipu_ch_param_write_field(p, IPU_FIELD_UBO, u_offset / 8); + ipu_ch_param_write_field(p, IPU_FIELD_VBO, v_offset / 8); + break; + } +} +EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar_full); + +void ipu_cpmem_set_yuv_planar(struct ipu_ch_param __iomem *p, u32 pixel_format, + int stride, int height) +{ + int u_offset, v_offset; + int uv_stride = 0; + + switch (pixel_format) { + case V4L2_PIX_FMT_YUV420: + uv_stride = stride / 2; + u_offset = stride * height; + v_offset = u_offset + (uv_stride * height / 2); + ipu_cpmem_set_yuv_planar_full(p, V4L2_PIX_FMT_YUV420, stride, + u_offset, v_offset); + break; + } +} +EXPORT_SYMBOL_GPL(ipu_cpmem_set_yuv_planar); + +static struct ipu_rgb def_rgb_32 = { + .red = { .offset = 16, .length = 8, }, + .green = { .offset = 8, .length = 8, }, + .blue = { .offset = 0, .length = 8, }, + .transp = { .offset = 24, .length = 8, }, + .bits_per_pixel = 32, +}; + +static struct ipu_rgb def_bgr_32 = { + .red = { .offset = 16, .length = 8, }, + .green = { .offset = 8, .length = 8, }, + .blue = { .offset = 0, .length = 8, }, + .transp = { .offset = 24, .length = 8, }, + .bits_per_pixel = 32, +}; + +static struct ipu_rgb def_rgb_24 = { + .red = { .offset = 0, .length = 8, }, + .green = { .offset = 8, .length = 8, }, + .blue = { .offset = 16, .length = 8, }, + .transp = { .offset = 0, .length = 0, }, + .bits_per_pixel = 24, +}; + +static struct ipu_rgb def_bgr_24 = { + .red = { .offset = 16, .length = 8, }, + .green = { .offset = 8, .length = 8, }, + .blue = { .offset = 0, .length = 8, }, + .transp = { .offset = 0, .length = 0, }, + .bits_per_pixel = 24, +}; + +static struct ipu_rgb def_rgb_16 = { + .red = { .offset = 11, .length = 5, }, + .green = { .offset = 5, .length = 6, }, + .blue = { .offset = 0, .length = 5, }, + .transp = { .offset = 0, .length = 0, }, + .bits_per_pixel = 16, +}; + +#define Y_OFFSET(pix, x, y) ((x) + pix->width * (y)) +#define U_OFFSET(pix, x, y) ((pix->width * pix->height) + \ + (pix->width * (y) / 4) + (x) / 2) +#define V_OFFSET(pix, x, y) ((pix->width * pix->height) + \ + (pix->width * pix->height / 4) + \ + (pix->width * (y) / 4) + (x) / 2) + +int ipu_cpmem_set_fmt(struct ipu_ch_param __iomem *cpmem, u32 pixelformat) +{ + switch (pixelformat) { + case V4L2_PIX_FMT_YUV420: + /* pix format */ + ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 2); + /* burst size */ + ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 63); + break; + case V4L2_PIX_FMT_UYVY: + /* bits/pixel */ + ipu_ch_param_write_field(cpmem, IPU_FIELD_BPP, 3); + /* pix format */ + ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 0xA); + /* burst size */ + ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 31); + break; + case V4L2_PIX_FMT_YUYV: + /* bits/pixel */ + ipu_ch_param_write_field(cpmem, IPU_FIELD_BPP, 3); + /* pix format */ + ipu_ch_param_write_field(cpmem, IPU_FIELD_PFS, 0x8); + /* burst size */ + ipu_ch_param_write_field(cpmem, IPU_FIELD_NPB, 31); + break; + case V4L2_PIX_FMT_RGB32: + ipu_cpmem_set_format_rgb(cpmem, &def_rgb_32); + break; + case V4L2_PIX_FMT_RGB565: + ipu_cpmem_set_format_rgb(cpmem, &def_rgb_16); + break; + case V4L2_PIX_FMT_BGR32: + ipu_cpmem_set_format_rgb(cpmem, &def_bgr_32); + break; + case V4L2_PIX_FMT_RGB24: + ipu_cpmem_set_format_rgb(cpmem, &def_rgb_24); + break; + case V4L2_PIX_FMT_BGR24: + ipu_cpmem_set_format_rgb(cpmem, &def_bgr_24); + break; + default: + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_cpmem_set_fmt); + +int ipu_cpmem_set_image(struct ipu_ch_param __iomem *cpmem, + struct ipu_image *image) +{ + struct v4l2_pix_format *pix = &image->pix; + int y_offset, u_offset, v_offset; + + pr_debug("%s: resolution: %dx%d stride: %d\n", + __func__, pix->width, pix->height, + pix->bytesperline); + + ipu_cpmem_set_resolution(cpmem, image->rect.width, + image->rect.height); + ipu_cpmem_set_stride(cpmem, pix->bytesperline); + + ipu_cpmem_set_fmt(cpmem, pix->pixelformat); + + switch (pix->pixelformat) { + case V4L2_PIX_FMT_YUV420: + y_offset = Y_OFFSET(pix, image->rect.left, image->rect.top); + u_offset = U_OFFSET(pix, image->rect.left, + image->rect.top) - y_offset; + v_offset = V_OFFSET(pix, image->rect.left, + image->rect.top) - y_offset; + + ipu_cpmem_set_yuv_planar_full(cpmem, pix->pixelformat, + pix->bytesperline, u_offset, v_offset); + ipu_cpmem_set_buffer(cpmem, 0, image->phys + y_offset); + break; + case V4L2_PIX_FMT_UYVY: + ipu_cpmem_set_buffer(cpmem, 0, image->phys + + image->rect.left * 2 + + image->rect.top * image->pix.bytesperline); + break; + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_BGR32: + ipu_cpmem_set_buffer(cpmem, 0, image->phys + + image->rect.left * 4 + + image->rect.top * image->pix.bytesperline); + break; + case V4L2_PIX_FMT_RGB565: + ipu_cpmem_set_buffer(cpmem, 0, image->phys + + image->rect.left * 2 + + image->rect.top * image->pix.bytesperline); + break; + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + ipu_cpmem_set_buffer(cpmem, 0, image->phys + + image->rect.left * 3 + + image->rect.top * image->pix.bytesperline); + break; + default: + return -EINVAL; + } + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_cpmem_set_image); + +enum ipu_color_space ipu_pixelformat_to_colorspace(u32 pixelformat) +{ + switch (pixelformat) { + case V4L2_PIX_FMT_YUV420: + case V4L2_PIX_FMT_UYVY: + case V4L2_PIX_FMT_YVYU: + return IPUV3_COLORSPACE_YUV; + case V4L2_PIX_FMT_RGB32: + case V4L2_PIX_FMT_BGR32: + case V4L2_PIX_FMT_RGB24: + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_RGB565: + return IPUV3_COLORSPACE_RGB; + default: + return IPUV3_COLORSPACE_UNKNOWN; + } +} +EXPORT_SYMBOL_GPL(ipu_pixelformat_to_colorspace); + +struct ipuv3_channel *ipu_idmac_get(struct ipu_soc *ipu, unsigned num) +{ + struct ipuv3_channel *channel; + + dev_dbg(ipu->dev, "%s %d\n", __func__, num); + + if (num > 63) + return ERR_PTR(-ENODEV); + + mutex_lock(&ipu->channel_lock); + + channel = &ipu->channel[num]; + + if (channel->busy) { + channel = ERR_PTR(-EBUSY); + goto out; + } + + channel->busy = 1; + channel->num = num; + +out: + mutex_unlock(&ipu->channel_lock); + + return channel; +} +EXPORT_SYMBOL_GPL(ipu_idmac_get); + +void ipu_idmac_put(struct ipuv3_channel *channel) +{ + struct ipu_soc *ipu = channel->ipu; + + dev_dbg(ipu->dev, "%s %d\n", __func__, channel->num); + + mutex_lock(&ipu->channel_lock); + + channel->busy = 0; + + mutex_unlock(&ipu->channel_lock); +} +EXPORT_SYMBOL_GPL(ipu_idmac_put); + +#define idma_mask(ch) (1 << (ch & 0x1f)) + +void ipu_idmac_set_double_buffer(struct ipuv3_channel *channel, + bool doublebuffer) +{ + struct ipu_soc *ipu = channel->ipu; + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&ipu->lock, flags); + + reg = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num)); + if (doublebuffer) + reg |= idma_mask(channel->num); + else + reg &= ~idma_mask(channel->num); + ipu_cm_write(ipu, reg, IPU_CHA_DB_MODE_SEL(channel->num)); + + spin_unlock_irqrestore(&ipu->lock, flags); +} +EXPORT_SYMBOL_GPL(ipu_idmac_set_double_buffer); + +int ipu_module_enable(struct ipu_soc *ipu, u32 mask) +{ + unsigned long lock_flags; + u32 val; + + spin_lock_irqsave(&ipu->lock, lock_flags); + + val = ipu_cm_read(ipu, IPU_DISP_GEN); + + if (mask & IPU_CONF_DI0_EN) + val |= IPU_DI0_COUNTER_RELEASE; + if (mask & IPU_CONF_DI1_EN) + val |= IPU_DI1_COUNTER_RELEASE; + + ipu_cm_write(ipu, val, IPU_DISP_GEN); + + val = ipu_cm_read(ipu, IPU_CONF); + val |= mask; + ipu_cm_write(ipu, val, IPU_CONF); + + spin_unlock_irqrestore(&ipu->lock, lock_flags); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_module_enable); + +int ipu_module_disable(struct ipu_soc *ipu, u32 mask) +{ + unsigned long lock_flags; + u32 val; + + spin_lock_irqsave(&ipu->lock, lock_flags); + + val = ipu_cm_read(ipu, IPU_CONF); + val &= ~mask; + ipu_cm_write(ipu, val, IPU_CONF); + + val = ipu_cm_read(ipu, IPU_DISP_GEN); + + if (mask & IPU_CONF_DI0_EN) + val &= ~IPU_DI0_COUNTER_RELEASE; + if (mask & IPU_CONF_DI1_EN) + val &= ~IPU_DI1_COUNTER_RELEASE; + + ipu_cm_write(ipu, val, IPU_DISP_GEN); + + spin_unlock_irqrestore(&ipu->lock, lock_flags); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_module_disable); + +void ipu_idmac_select_buffer(struct ipuv3_channel *channel, u32 buf_num) +{ + struct ipu_soc *ipu = channel->ipu; + unsigned int chno = channel->num; + unsigned long flags; + + spin_lock_irqsave(&ipu->lock, flags); + + /* Mark buffer as ready. */ + if (buf_num == 0) + ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF0_RDY(chno)); + else + ipu_cm_write(ipu, idma_mask(chno), IPU_CHA_BUF1_RDY(chno)); + + spin_unlock_irqrestore(&ipu->lock, flags); +} +EXPORT_SYMBOL_GPL(ipu_idmac_select_buffer); + +int ipu_idmac_enable_channel(struct ipuv3_channel *channel) +{ + struct ipu_soc *ipu = channel->ipu; + u32 val; + unsigned long flags; + + spin_lock_irqsave(&ipu->lock, flags); + + val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num)); + val |= idma_mask(channel->num); + ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num)); + + spin_unlock_irqrestore(&ipu->lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_idmac_enable_channel); + +int ipu_idmac_disable_channel(struct ipuv3_channel *channel) +{ + struct ipu_soc *ipu = channel->ipu; + u32 val; + unsigned long flags; + unsigned long timeout; + + timeout = jiffies + msecs_to_jiffies(50); + while (ipu_idmac_read(ipu, IDMAC_CHA_BUSY(channel->num)) & + idma_mask(channel->num)) { + if (time_after(jiffies, timeout)) { + dev_warn(ipu->dev, "disabling busy idmac channel %d\n", + channel->num); + break; + } + cpu_relax(); + } + + spin_lock_irqsave(&ipu->lock, flags); + + /* Disable DMA channel(s) */ + val = ipu_idmac_read(ipu, IDMAC_CHA_EN(channel->num)); + val &= ~idma_mask(channel->num); + ipu_idmac_write(ipu, val, IDMAC_CHA_EN(channel->num)); + + /* Set channel buffers NOT to be ready */ + ipu_cm_write(ipu, 0xf0000000, IPU_GPR); /* write one to clear */ + + if (ipu_cm_read(ipu, IPU_CHA_BUF0_RDY(channel->num)) & + idma_mask(channel->num)) { + ipu_cm_write(ipu, idma_mask(channel->num), + IPU_CHA_BUF0_RDY(channel->num)); + } + + if (ipu_cm_read(ipu, IPU_CHA_BUF1_RDY(channel->num)) & + idma_mask(channel->num)) { + ipu_cm_write(ipu, idma_mask(channel->num), + IPU_CHA_BUF1_RDY(channel->num)); + } + + ipu_cm_write(ipu, 0x0, IPU_GPR); /* write one to set */ + + /* Reset the double buffer */ + val = ipu_cm_read(ipu, IPU_CHA_DB_MODE_SEL(channel->num)); + val &= ~idma_mask(channel->num); + ipu_cm_write(ipu, val, IPU_CHA_DB_MODE_SEL(channel->num)); + + spin_unlock_irqrestore(&ipu->lock, flags); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_idmac_disable_channel); + +static int ipu_reset(struct ipu_soc *ipu) +{ + unsigned long timeout; + + ipu_cm_write(ipu, 0x807FFFFF, IPU_MEM_RST); + + timeout = jiffies + msecs_to_jiffies(1000); + while (ipu_cm_read(ipu, IPU_MEM_RST) & 0x80000000) { + if (time_after(jiffies, timeout)) + return -ETIME; + cpu_relax(); + } + + mdelay(300); + + return 0; +} + +struct ipu_devtype { + const char *name; + unsigned long cm_ofs; + unsigned long cpmem_ofs; + unsigned long srm_ofs; + unsigned long tpm_ofs; + unsigned long disp0_ofs; + unsigned long disp1_ofs; + unsigned long dc_tmpl_ofs; + unsigned long vdi_ofs; + enum ipuv3_type type; +}; + +static struct ipu_devtype ipu_type_imx51 = { + .name = "IPUv3EX", + .cm_ofs = 0x1e000000, + .cpmem_ofs = 0x1f000000, + .srm_ofs = 0x1f040000, + .tpm_ofs = 0x1f060000, + .disp0_ofs = 0x1e040000, + .disp1_ofs = 0x1e048000, + .dc_tmpl_ofs = 0x1f080000, + .vdi_ofs = 0x1e068000, + .type = IPUV3EX, +}; + +static struct ipu_devtype ipu_type_imx53 = { + .name = "IPUv3M", + .cm_ofs = 0x06000000, + .cpmem_ofs = 0x07000000, + .srm_ofs = 0x07040000, + .tpm_ofs = 0x07060000, + .disp0_ofs = 0x06040000, + .disp1_ofs = 0x06048000, + .dc_tmpl_ofs = 0x07080000, + .vdi_ofs = 0x06068000, + .type = IPUV3M, +}; + +static struct ipu_devtype ipu_type_imx6q = { + .name = "IPUv3H", + .cm_ofs = 0x00200000, + .cpmem_ofs = 0x00300000, + .srm_ofs = 0x00340000, + .tpm_ofs = 0x00360000, + .disp0_ofs = 0x00240000, + .disp1_ofs = 0x00248000, + .dc_tmpl_ofs = 0x00380000, + .vdi_ofs = 0x00268000, + .type = IPUV3H, +}; + +static const struct of_device_id imx_ipu_dt_ids[] = { + { .compatible = "fsl,imx51-ipu", .data = &ipu_type_imx51, }, + { .compatible = "fsl,imx53-ipu", .data = &ipu_type_imx53, }, + { .compatible = "fsl,imx6q-ipu", .data = &ipu_type_imx6q, }, + { /* sentinel */ } +}; +MODULE_DEVICE_TABLE(of, imx_ipu_dt_ids); + +static int ipu_submodules_init(struct ipu_soc *ipu, + struct platform_device *pdev, unsigned long ipu_base, + struct clk *ipu_clk) +{ + char *unit; + int ret; + struct device *dev = &pdev->dev; + const struct ipu_devtype *devtype = ipu->devtype; + + ret = ipu_di_init(ipu, dev, 0, ipu_base + devtype->disp0_ofs, + IPU_CONF_DI0_EN, ipu_clk); + if (ret) { + unit = "di0"; + goto err_di_0; + } + + ret = ipu_di_init(ipu, dev, 1, ipu_base + devtype->disp1_ofs, + IPU_CONF_DI1_EN, ipu_clk); + if (ret) { + unit = "di1"; + goto err_di_1; + } + + ret = ipu_dc_init(ipu, dev, ipu_base + devtype->cm_ofs + + IPU_CM_DC_REG_OFS, ipu_base + devtype->dc_tmpl_ofs); + if (ret) { + unit = "dc_template"; + goto err_dc; + } + + ret = ipu_dmfc_init(ipu, dev, ipu_base + + devtype->cm_ofs + IPU_CM_DMFC_REG_OFS, ipu_clk); + if (ret) { + unit = "dmfc"; + goto err_dmfc; + } + + ret = ipu_dp_init(ipu, dev, ipu_base + devtype->srm_ofs); + if (ret) { + unit = "dp"; + goto err_dp; + } + + return 0; + +err_dp: + ipu_dmfc_exit(ipu); +err_dmfc: + ipu_dc_exit(ipu); +err_dc: + ipu_di_exit(ipu, 1); +err_di_1: + ipu_di_exit(ipu, 0); +err_di_0: + dev_err(&pdev->dev, "init %s failed with %d\n", unit, ret); + return ret; +} + +static void ipu_irq_handle(struct ipu_soc *ipu, const int *regs, int num_regs) +{ + unsigned long status; + int i, bit, irq_base; + + for (i = 0; i < num_regs; i++) { + + status = ipu_cm_read(ipu, IPU_INT_STAT(regs[i])); + status &= ipu_cm_read(ipu, IPU_INT_CTRL(regs[i])); + + irq_base = ipu->irq_start + regs[i] * 32; + for_each_set_bit(bit, &status, 32) + generic_handle_irq(irq_base + bit); + } +} + +static void ipu_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + struct ipu_soc *ipu = irq_desc_get_handler_data(desc); + const int int_reg[] = { 0, 1, 2, 3, 10, 11, 12, 13, 14}; + struct irq_chip *chip = irq_get_chip(irq); + + chained_irq_enter(chip, desc); + + ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg)); + + chained_irq_exit(chip, desc); +} + +static void ipu_err_irq_handler(unsigned int irq, struct irq_desc *desc) +{ + struct ipu_soc *ipu = irq_desc_get_handler_data(desc); + const int int_reg[] = { 4, 5, 8, 9}; + struct irq_chip *chip = irq_get_chip(irq); + + chained_irq_enter(chip, desc); + + ipu_irq_handle(ipu, int_reg, ARRAY_SIZE(int_reg)); + + chained_irq_exit(chip, desc); +} + +static void ipu_ack_irq(struct irq_data *d) +{ + struct ipu_soc *ipu = irq_data_get_irq_chip_data(d); + unsigned int irq = d->irq - ipu->irq_start; + + ipu_cm_write(ipu, 1 << (irq % 32), IPU_INT_STAT(irq / 32)); +} + +static void ipu_unmask_irq(struct irq_data *d) +{ + struct ipu_soc *ipu = irq_data_get_irq_chip_data(d); + unsigned int irq = d->irq - ipu->irq_start; + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&ipu->lock, flags); + + reg = ipu_cm_read(ipu, IPU_INT_CTRL(irq / 32)); + reg |= 1 << (irq % 32); + ipu_cm_write(ipu, reg, IPU_INT_CTRL(irq / 32)); + + spin_unlock_irqrestore(&ipu->lock, flags); +} + +static void ipu_mask_irq(struct irq_data *d) +{ + struct ipu_soc *ipu = irq_data_get_irq_chip_data(d); + unsigned int irq = d->irq - ipu->irq_start; + unsigned long flags; + u32 reg; + + spin_lock_irqsave(&ipu->lock, flags); + + reg = ipu_cm_read(ipu, IPU_INT_CTRL(irq / 32)); + reg &= ~(1 << (irq % 32)); + ipu_cm_write(ipu, reg, IPU_INT_CTRL(irq / 32)); + + spin_unlock_irqrestore(&ipu->lock, flags); +} + +static struct irq_chip ipu_irq_chip = { + .name = "IPU", + .irq_ack = ipu_ack_irq, + .irq_mask = ipu_mask_irq, + .irq_unmask = ipu_unmask_irq, +}; + +int ipu_idmac_channel_irq(struct ipu_soc *ipu, struct ipuv3_channel *channel, + enum ipu_channel_irq irq_type) +{ + return ipu->irq_start + irq_type + channel->num; +} +EXPORT_SYMBOL_GPL(ipu_idmac_channel_irq); + +static void ipu_submodules_exit(struct ipu_soc *ipu) +{ + ipu_dp_exit(ipu); + ipu_dmfc_exit(ipu); + ipu_dc_exit(ipu); + ipu_di_exit(ipu, 1); + ipu_di_exit(ipu, 0); +} + +static int platform_remove_devices_fn(struct device *dev, void *unused) +{ + struct platform_device *pdev = to_platform_device(dev); + + platform_device_unregister(pdev); + + return 0; +} + +static void platform_device_unregister_children(struct platform_device *pdev) +{ + device_for_each_child(&pdev->dev, NULL, platform_remove_devices_fn); +} + +struct ipu_platform_reg { + struct ipu_client_platformdata pdata; + const char *name; +}; + +static const struct ipu_platform_reg client_reg[] = { + { + .pdata = { + .di = 0, + .dc = 5, + .dp = IPU_DP_FLOW_SYNC_BG, + .dma[0] = IPUV3_CHANNEL_MEM_BG_SYNC, + .dma[1] = -EINVAL, + }, + .name = "imx-ipuv3-crtc", + }, { + .pdata = { + .di = 1, + .dc = 1, + .dp = -EINVAL, + .dma[0] = IPUV3_CHANNEL_MEM_DC_SYNC, + .dma[1] = -EINVAL, + }, + .name = "imx-ipuv3-crtc", + }, +}; + +static int ipu_client_id; + +static int ipu_add_subdevice_pdata(struct device *dev, + const struct ipu_platform_reg *reg) +{ + struct platform_device *pdev; + + pdev = platform_device_register_data(dev, reg->name, ipu_client_id++, + ®->pdata, sizeof(struct ipu_platform_reg)); + + return pdev ? 0 : -EINVAL; +} + +static int ipu_add_client_devices(struct ipu_soc *ipu) +{ + int ret; + int i; + + for (i = 0; i < ARRAY_SIZE(client_reg); i++) { + const struct ipu_platform_reg *reg = &client_reg[i]; + ret = ipu_add_subdevice_pdata(ipu->dev, reg); + if (ret) + goto err_register; + } + + return 0; + +err_register: + platform_device_unregister_children(to_platform_device(ipu->dev)); + + return ret; +} + +static int ipu_irq_init(struct ipu_soc *ipu) +{ + int i; + + ipu->irq_start = irq_alloc_descs(-1, 0, IPU_NUM_IRQS, 0); + if (ipu->irq_start < 0) + return ipu->irq_start; + + for (i = ipu->irq_start; i < ipu->irq_start + IPU_NUM_IRQS; i++) { + irq_set_chip_and_handler(i, &ipu_irq_chip, handle_level_irq); + set_irq_flags(i, IRQF_VALID); + irq_set_chip_data(i, ipu); + } + + irq_set_chained_handler(ipu->irq_sync, ipu_irq_handler); + irq_set_handler_data(ipu->irq_sync, ipu); + irq_set_chained_handler(ipu->irq_err, ipu_err_irq_handler); + irq_set_handler_data(ipu->irq_err, ipu); + + return 0; +} + +static void ipu_irq_exit(struct ipu_soc *ipu) +{ + int i; + + irq_set_chained_handler(ipu->irq_err, NULL); + irq_set_handler_data(ipu->irq_err, NULL); + irq_set_chained_handler(ipu->irq_sync, NULL); + irq_set_handler_data(ipu->irq_sync, NULL); + + for (i = ipu->irq_start; i < ipu->irq_start + IPU_NUM_IRQS; i++) { + set_irq_flags(i, 0); + irq_set_chip(i, NULL); + irq_set_chip_data(i, NULL); + } + + irq_free_descs(ipu->irq_start, IPU_NUM_IRQS); +} + +static int __devinit ipu_probe(struct platform_device *pdev) +{ + const struct of_device_id *of_id = + of_match_device(imx_ipu_dt_ids, &pdev->dev); + struct ipu_soc *ipu; + struct resource *res; + unsigned long ipu_base; + int i, ret, irq_sync, irq_err; + const struct ipu_devtype *devtype; + + devtype = of_id->data; + + dev_info(&pdev->dev, "Initializing %s\n", devtype->name); + + irq_sync = platform_get_irq(pdev, 0); + irq_err = platform_get_irq(pdev, 1); + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + dev_info(&pdev->dev, "irq_sync: %d irq_err: %d\n", + irq_sync, irq_err); + + if (!res || irq_sync < 0 || irq_err < 0) + return -ENODEV; + + ipu_base = res->start; + + ipu = devm_kzalloc(&pdev->dev, sizeof(*ipu), GFP_KERNEL); + if (!ipu) + return -ENODEV; + + for (i = 0; i < 64; i++) + ipu->channel[i].ipu = ipu; + ipu->devtype = devtype; + ipu->ipu_type = devtype->type; + + spin_lock_init(&ipu->lock); + mutex_init(&ipu->channel_lock); + + dev_info(&pdev->dev, "cm_reg: 0x%08lx\n", + ipu_base + devtype->cm_ofs); + dev_info(&pdev->dev, "idmac: 0x%08lx\n", + ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS); + dev_info(&pdev->dev, "cpmem: 0x%08lx\n", + ipu_base + devtype->cpmem_ofs); + dev_info(&pdev->dev, "disp0: 0x%08lx\n", + ipu_base + devtype->disp0_ofs); + dev_info(&pdev->dev, "disp1: 0x%08lx\n", + ipu_base + devtype->disp1_ofs); + dev_info(&pdev->dev, "srm: 0x%08lx\n", + ipu_base + devtype->srm_ofs); + dev_info(&pdev->dev, "tpm: 0x%08lx\n", + ipu_base + devtype->tpm_ofs); + dev_info(&pdev->dev, "dc: 0x%08lx\n", + ipu_base + devtype->cm_ofs + IPU_CM_DC_REG_OFS); + dev_info(&pdev->dev, "ic: 0x%08lx\n", + ipu_base + devtype->cm_ofs + IPU_CM_IC_REG_OFS); + dev_info(&pdev->dev, "dmfc: 0x%08lx\n", + ipu_base + devtype->cm_ofs + IPU_CM_DMFC_REG_OFS); + dev_info(&pdev->dev, "vdi: 0x%08lx\n", + ipu_base + devtype->vdi_ofs); + + ipu->cm_reg = devm_ioremap(&pdev->dev, + ipu_base + devtype->cm_ofs, PAGE_SIZE); + ipu->idmac_reg = devm_ioremap(&pdev->dev, + ipu_base + devtype->cm_ofs + IPU_CM_IDMAC_REG_OFS, + PAGE_SIZE); + ipu->cpmem_base = devm_ioremap(&pdev->dev, + ipu_base + devtype->cpmem_ofs, PAGE_SIZE); + + if (!ipu->cm_reg || !ipu->idmac_reg || !ipu->cpmem_base) { + ret = -ENOMEM; + goto failed_ioremap; + } + + ipu->clk = devm_clk_get(&pdev->dev, "bus"); + if (IS_ERR(ipu->clk)) { + ret = PTR_ERR(ipu->clk); + dev_err(&pdev->dev, "clk_get failed with %d", ret); + goto failed_clk_get; + } + + platform_set_drvdata(pdev, ipu); + + clk_prepare_enable(ipu->clk); + + ipu->dev = &pdev->dev; + ipu->irq_sync = irq_sync; + ipu->irq_err = irq_err; + + ret = ipu_irq_init(ipu); + if (ret) + goto out_failed_irq; + + ipu_reset(ipu); + + /* Set MCU_T to divide MCU access window into 2 */ + ipu_cm_write(ipu, 0x00400000L | (IPU_MCU_T_DEFAULT << 18), + IPU_DISP_GEN); + + ret = ipu_submodules_init(ipu, pdev, ipu_base, ipu->clk); + if (ret) + goto failed_submodules_init; + + ret = ipu_add_client_devices(ipu); + if (ret) { + dev_err(&pdev->dev, "adding client devices failed with %d\n", + ret); + goto failed_add_clients; + } + + return 0; + +failed_add_clients: + ipu_submodules_exit(ipu); +failed_submodules_init: + ipu_irq_exit(ipu); +out_failed_irq: + clk_disable_unprepare(ipu->clk); +failed_clk_get: +failed_ioremap: + return ret; +} + +static int __devexit ipu_remove(struct platform_device *pdev) +{ + struct ipu_soc *ipu = platform_get_drvdata(pdev); + struct resource *res; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + platform_device_unregister_children(pdev); + ipu_submodules_exit(ipu); + ipu_irq_exit(ipu); + + clk_disable_unprepare(ipu->clk); + + return 0; +} + +static struct platform_driver imx_ipu_driver = { + .driver = { + .name = "imx-ipuv3", + .of_match_table = imx_ipu_dt_ids, + }, + .probe = ipu_probe, + .remove = __devexit_p(ipu_remove), +}; + +module_platform_driver(imx_ipu_driver); + +MODULE_DESCRIPTION("i.MX IPU v3 driver"); +MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c new file mode 100644 index 000000000000..93c7579417be --- /dev/null +++ b/drivers/staging/imx-drm/ipu-v3/ipu-dc.c @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de> + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include <linux/export.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/delay.h> +#include <linux/io.h> + +#include "imx-ipu-v3.h" +#include "ipu-prv.h" + +#define DC_MAP_CONF_PTR(n) (0x108 + ((n) & ~0x1) * 2) +#define DC_MAP_CONF_VAL(n) (0x144 + ((n) & ~0x1) * 2) + +#define DC_EVT_NF 0 +#define DC_EVT_NL 1 +#define DC_EVT_EOF 2 +#define DC_EVT_NFIELD 3 +#define DC_EVT_EOL 4 +#define DC_EVT_EOFIELD 5 +#define DC_EVT_NEW_ADDR 6 +#define DC_EVT_NEW_CHAN 7 +#define DC_EVT_NEW_DATA 8 + +#define DC_EVT_NEW_ADDR_W_0 0 +#define DC_EVT_NEW_ADDR_W_1 1 +#define DC_EVT_NEW_CHAN_W_0 2 +#define DC_EVT_NEW_CHAN_W_1 3 +#define DC_EVT_NEW_DATA_W_0 4 +#define DC_EVT_NEW_DATA_W_1 5 +#define DC_EVT_NEW_ADDR_R_0 6 +#define DC_EVT_NEW_ADDR_R_1 7 +#define DC_EVT_NEW_CHAN_R_0 8 +#define DC_EVT_NEW_CHAN_R_1 9 +#define DC_EVT_NEW_DATA_R_0 10 +#define DC_EVT_NEW_DATA_R_1 11 + +#define DC_WR_CH_CONF 0x0 +#define DC_WR_CH_ADDR 0x4 +#define DC_RL_CH(evt) (8 + ((evt) & ~0x1) * 2) + +#define DC_GEN 0xd4 +#define DC_DISP_CONF1(disp) (0xd8 + (disp) * 4) +#define DC_DISP_CONF2(disp) (0xe8 + (disp) * 4) +#define DC_STAT 0x1c8 + +#define WROD(lf) (0x18 | ((lf) << 1)) +#define WRG 0x01 + +#define SYNC_WAVE 0 + +#define DC_GEN_SYNC_1_6_SYNC (2 << 1) +#define DC_GEN_SYNC_PRIORITY_1 (1 << 7) + +#define DC_WR_CH_CONF_WORD_SIZE_8 (0 << 0) +#define DC_WR_CH_CONF_WORD_SIZE_16 (1 << 0) +#define DC_WR_CH_CONF_WORD_SIZE_24 (2 << 0) +#define DC_WR_CH_CONF_WORD_SIZE_32 (3 << 0) +#define DC_WR_CH_CONF_DISP_ID_PARALLEL(i) (((i) & 0x1) << 3) +#define DC_WR_CH_CONF_DISP_ID_SERIAL (2 << 3) +#define DC_WR_CH_CONF_DISP_ID_ASYNC (3 << 4) +#define DC_WR_CH_CONF_FIELD_MODE (1 << 9) +#define DC_WR_CH_CONF_PROG_TYPE_NORMAL (4 << 5) +#define DC_WR_CH_CONF_PROG_TYPE_MASK (7 << 5) +#define DC_WR_CH_CONF_PROG_DI_ID (1 << 2) +#define DC_WR_CH_CONF_PROG_DISP_ID(i) (((i) & 0x1) << 3) + +#define IPU_DC_NUM_CHANNELS 10 + +struct ipu_dc_priv; + +enum ipu_dc_map { + IPU_DC_MAP_RGB24, + IPU_DC_MAP_RGB565, +}; + +struct ipu_dc { + /* The display interface number assigned to this dc channel */ + unsigned int di; + void __iomem *base; + struct ipu_dc_priv *priv; + int chno; + bool in_use; +}; + +struct ipu_dc_priv { + void __iomem *dc_reg; + void __iomem *dc_tmpl_reg; + struct ipu_soc *ipu; + struct device *dev; + struct ipu_dc channels[IPU_DC_NUM_CHANNELS]; + struct mutex mutex; +}; + +static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority) +{ + u32 reg; + + reg = readl(dc->base + DC_RL_CH(event)); + reg &= ~(0xffff << (16 * (event & 0x1))); + reg |= ((addr << 8) | priority) << (16 * (event & 0x1)); + writel(reg, dc->base + DC_RL_CH(event)); +} + +static void dc_write_tmpl(struct ipu_dc *dc, int word, u32 opcode, u32 operand, + int map, int wave, int glue, int sync) +{ + struct ipu_dc_priv *priv = dc->priv; + u32 reg; + int stop = 1; + + reg = sync | glue << 4 | ++wave << 11 | ++map << 15 | ((operand << 20) & 0xfff00000); + writel(reg, priv->dc_tmpl_reg + word * 8); + reg = operand >> 12 | opcode << 4 | stop << 9; + writel(reg, priv->dc_tmpl_reg + word * 8 + 4); +} + +static int ipu_pixfmt_to_map(u32 fmt) +{ + switch (fmt) { + case V4L2_PIX_FMT_RGB24: + return IPU_DC_MAP_RGB24; + case V4L2_PIX_FMT_RGB565: + return IPU_DC_MAP_RGB565; + default: + return -EINVAL; + } +} + +int ipu_dc_init_sync(struct ipu_dc *dc, struct ipu_di *di, bool interlaced, + u32 pixel_fmt, u32 width) +{ + struct ipu_dc_priv *priv = dc->priv; + u32 reg = 0, map; + + dc->di = ipu_di_get_num(di); + + map = ipu_pixfmt_to_map(pixel_fmt); + if (map < 0) { + dev_dbg(priv->dev, "IPU_DISP: No MAP\n"); + return -EINVAL; + } + + if (interlaced) { + dc_link_event(dc, DC_EVT_NL, 0, 3); + dc_link_event(dc, DC_EVT_EOL, 0, 2); + dc_link_event(dc, DC_EVT_NEW_DATA, 0, 1); + + /* Init template microcode */ + dc_write_tmpl(dc, 0, WROD(0), 0, map, SYNC_WAVE, 0, 8); + } else { + if (dc->di) { + dc_link_event(dc, DC_EVT_NL, 2, 3); + dc_link_event(dc, DC_EVT_EOL, 3, 2); + dc_link_event(dc, DC_EVT_NEW_DATA, 4, 1); + /* Init template microcode */ + dc_write_tmpl(dc, 2, WROD(0), 0, map, SYNC_WAVE, 8, 5); + dc_write_tmpl(dc, 3, WROD(0), 0, map, SYNC_WAVE, 4, 5); + dc_write_tmpl(dc, 4, WROD(0), 0, map, SYNC_WAVE, 0, 5); + } else { + dc_link_event(dc, DC_EVT_NL, 5, 3); + dc_link_event(dc, DC_EVT_EOL, 6, 2); + dc_link_event(dc, DC_EVT_NEW_DATA, 7, 1); + /* Init template microcode */ + dc_write_tmpl(dc, 5, WROD(0), 0, map, SYNC_WAVE, 8, 5); + dc_write_tmpl(dc, 6, WROD(0), 0, map, SYNC_WAVE, 4, 5); + dc_write_tmpl(dc, 7, WROD(0), 0, map, SYNC_WAVE, 0, 5); + } + } + dc_link_event(dc, DC_EVT_NF, 0, 0); + dc_link_event(dc, DC_EVT_NFIELD, 0, 0); + dc_link_event(dc, DC_EVT_EOF, 0, 0); + dc_link_event(dc, DC_EVT_EOFIELD, 0, 0); + dc_link_event(dc, DC_EVT_NEW_CHAN, 0, 0); + dc_link_event(dc, DC_EVT_NEW_ADDR, 0, 0); + + reg = readl(dc->base + DC_WR_CH_CONF); + if (interlaced) + reg |= DC_WR_CH_CONF_FIELD_MODE; + else + reg &= ~DC_WR_CH_CONF_FIELD_MODE; + writel(reg, dc->base + DC_WR_CH_CONF); + + writel(0x0, dc->base + DC_WR_CH_ADDR); + writel(width, priv->dc_reg + DC_DISP_CONF2(dc->di)); + + ipu_module_enable(priv->ipu, IPU_CONF_DC_EN); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_dc_init_sync); + +void ipu_dc_enable_channel(struct ipu_dc *dc) +{ + int di; + u32 reg; + + di = dc->di; + + reg = readl(dc->base + DC_WR_CH_CONF); + reg |= DC_WR_CH_CONF_PROG_TYPE_NORMAL; + writel(reg, dc->base + DC_WR_CH_CONF); +} +EXPORT_SYMBOL_GPL(ipu_dc_enable_channel); + +void ipu_dc_disable_channel(struct ipu_dc *dc) +{ + struct ipu_dc_priv *priv = dc->priv; + u32 val; + int irq = 0, timeout = 50; + + if (dc->chno == 1) + irq = IPU_IRQ_DC_FC_1; + else if (dc->chno == 5) + irq = IPU_IRQ_DP_SF_END; + else + return; + + /* should wait for the interrupt here */ + mdelay(50); + + if (dc->di == 0) + val = 0x00000002; + else + val = 0x00000020; + + /* Wait for DC triple buffer to empty */ + while ((readl(priv->dc_reg + DC_STAT) & val) != val) { + msleep(2); + timeout -= 2; + if (timeout <= 0) + break; + } + + val = readl(dc->base + DC_WR_CH_CONF); + val &= ~DC_WR_CH_CONF_PROG_TYPE_MASK; + writel(val, dc->base + DC_WR_CH_CONF); +} +EXPORT_SYMBOL_GPL(ipu_dc_disable_channel); + +static void ipu_dc_map_config(struct ipu_dc_priv *priv, enum ipu_dc_map map, + int byte_num, int offset, int mask) +{ + int ptr = map * 3 + byte_num; + u32 reg; + + reg = readl(priv->dc_reg + DC_MAP_CONF_VAL(ptr)); + reg &= ~(0xffff << (16 * (ptr & 0x1))); + reg |= ((offset << 8) | mask) << (16 * (ptr & 0x1)); + writel(reg, priv->dc_reg + DC_MAP_CONF_VAL(ptr)); + + reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map)); + reg &= ~(0x1f << ((16 * (map & 0x1)) + (5 * byte_num))); + reg |= ptr << ((16 * (map & 0x1)) + (5 * byte_num)); + writel(reg, priv->dc_reg + DC_MAP_CONF_PTR(map)); +} + +static void ipu_dc_map_clear(struct ipu_dc_priv *priv, int map) +{ + u32 reg = readl(priv->dc_reg + DC_MAP_CONF_PTR(map)); + + writel(reg & ~(0xffff << (16 * (map & 0x1))), + priv->dc_reg + DC_MAP_CONF_PTR(map)); +} + +struct ipu_dc *ipu_dc_get(struct ipu_soc *ipu, int channel) +{ + struct ipu_dc_priv *priv = ipu->dc_priv; + struct ipu_dc *dc; + + if (channel >= IPU_DC_NUM_CHANNELS) + return ERR_PTR(-ENODEV); + + dc = &priv->channels[channel]; + + mutex_lock(&priv->mutex); + + if (dc->in_use) { + mutex_unlock(&priv->mutex); + return ERR_PTR(-EBUSY); + } + + dc->in_use = 1; + + mutex_unlock(&priv->mutex); + + return dc; +} +EXPORT_SYMBOL_GPL(ipu_dc_get); + +void ipu_dc_put(struct ipu_dc *dc) +{ + struct ipu_dc_priv *priv = dc->priv; + + mutex_lock(&priv->mutex); + dc->in_use = 0; + mutex_unlock(&priv->mutex); +} +EXPORT_SYMBOL_GPL(ipu_dc_put); + +int ipu_dc_init(struct ipu_soc *ipu, struct device *dev, + unsigned long base, unsigned long template_base) +{ + struct ipu_dc_priv *priv; + static int channel_offsets[] = { 0, 0x1c, 0x38, 0x54, 0x58, 0x5c, + 0x78, 0, 0x94, 0xb4}; + int i; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + mutex_init(&priv->mutex); + + priv->dev = dev; + priv->ipu = ipu; + priv->dc_reg = devm_ioremap(dev, base, PAGE_SIZE); + priv->dc_tmpl_reg = devm_ioremap(dev, template_base, PAGE_SIZE); + if (!priv->dc_reg || !priv->dc_tmpl_reg) + return -ENOMEM; + + for (i = 0; i < IPU_DC_NUM_CHANNELS; i++) { + priv->channels[i].chno = i; + priv->channels[i].priv = priv; + priv->channels[i].base = priv->dc_reg + channel_offsets[i]; + } + + writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(1) | + DC_WR_CH_CONF_PROG_DI_ID, + priv->channels[1].base + DC_WR_CH_CONF); + writel(DC_WR_CH_CONF_WORD_SIZE_24 | DC_WR_CH_CONF_DISP_ID_PARALLEL(0), + priv->channels[5].base + DC_WR_CH_CONF); + + writel(DC_GEN_SYNC_1_6_SYNC | DC_GEN_SYNC_PRIORITY_1, priv->dc_reg + DC_GEN); + + ipu->dc_priv = priv; + + dev_dbg(dev, "DC base: 0x%08lx template base: 0x%08lx\n", + base, template_base); + + /* rgb24 */ + ipu_dc_map_clear(priv, IPU_DC_MAP_RGB24); + ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 0, 7, 0xff); /* blue */ + ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 1, 15, 0xff); /* green */ + ipu_dc_map_config(priv, IPU_DC_MAP_RGB24, 2, 23, 0xff); /* red */ + + /* rgb565 */ + ipu_dc_map_clear(priv, IPU_DC_MAP_RGB565); + ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 0, 4, 0xf8); /* blue */ + ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 1, 10, 0xfc); /* green */ + ipu_dc_map_config(priv, IPU_DC_MAP_RGB565, 2, 15, 0xf8); /* red */ + + return 0; +} + +void ipu_dc_exit(struct ipu_soc *ipu) +{ +} diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-di.c b/drivers/staging/imx-drm/ipu-v3/ipu-di.c new file mode 100644 index 000000000000..67d974f7be36 --- /dev/null +++ b/drivers/staging/imx-drm/ipu-v3/ipu-di.c @@ -0,0 +1,700 @@ +/* + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de> + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ +#include <linux/export.h> +#include <linux/module.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/io.h> +#include <linux/err.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/clk-provider.h> +#include <linux/clkdev.h> + +#include "imx-ipu-v3.h" +#include "ipu-prv.h" + +struct ipu_di { + void __iomem *base; + int id; + u32 module; + struct clk *clk_di; /* display input clock */ + struct clk *clk_ipu; /* IPU bus clock */ + struct clk *clk_di_pixel; /* resulting pixel clock */ + struct clk_hw clk_hw_out; + char *clk_name; + bool inuse; + unsigned long clkflags; + struct ipu_soc *ipu; +}; + +static DEFINE_MUTEX(di_mutex); + +struct di_sync_config { + int run_count; + int run_src; + int offset_count; + int offset_src; + int repeat_count; + int cnt_clr_src; + int cnt_polarity_gen_en; + int cnt_polarity_clr_src; + int cnt_polarity_trigger_src; + int cnt_up; + int cnt_down; +}; + +enum di_pins { + DI_PIN11 = 0, + DI_PIN12 = 1, + DI_PIN13 = 2, + DI_PIN14 = 3, + DI_PIN15 = 4, + DI_PIN16 = 5, + DI_PIN17 = 6, + DI_PIN_CS = 7, + + DI_PIN_SER_CLK = 0, + DI_PIN_SER_RS = 1, +}; + +enum di_sync_wave { + DI_SYNC_NONE = 0, + DI_SYNC_CLK = 1, + DI_SYNC_INT_HSYNC = 2, + DI_SYNC_HSYNC = 3, + DI_SYNC_VSYNC = 4, + DI_SYNC_DE = 6, +}; + +#define SYNC_WAVE 0 + +#define DI_GENERAL 0x0000 +#define DI_BS_CLKGEN0 0x0004 +#define DI_BS_CLKGEN1 0x0008 +#define DI_SW_GEN0(gen) (0x000c + 4 * ((gen) - 1)) +#define DI_SW_GEN1(gen) (0x0030 + 4 * ((gen) - 1)) +#define DI_STP_REP(gen) (0x0148 + 4 * (((gen) - 1)/2)) +#define DI_SYNC_AS_GEN 0x0054 +#define DI_DW_GEN(gen) (0x0058 + 4 * (gen)) +#define DI_DW_SET(gen, set) (0x0088 + 4 * ((gen) + 0xc * (set))) +#define DI_SER_CONF 0x015c +#define DI_SSC 0x0160 +#define DI_POL 0x0164 +#define DI_AW0 0x0168 +#define DI_AW1 0x016c +#define DI_SCR_CONF 0x0170 +#define DI_STAT 0x0174 + +#define DI_SW_GEN0_RUN_COUNT(x) ((x) << 19) +#define DI_SW_GEN0_RUN_SRC(x) ((x) << 16) +#define DI_SW_GEN0_OFFSET_COUNT(x) ((x) << 3) +#define DI_SW_GEN0_OFFSET_SRC(x) ((x) << 0) + +#define DI_SW_GEN1_CNT_POL_GEN_EN(x) ((x) << 29) +#define DI_SW_GEN1_CNT_CLR_SRC(x) ((x) << 25) +#define DI_SW_GEN1_CNT_POL_TRIGGER_SRC(x) ((x) << 12) +#define DI_SW_GEN1_CNT_POL_CLR_SRC(x) ((x) << 9) +#define DI_SW_GEN1_CNT_DOWN(x) ((x) << 16) +#define DI_SW_GEN1_CNT_UP(x) (x) +#define DI_SW_GEN1_AUTO_RELOAD (0x10000000) + +#define DI_DW_GEN_ACCESS_SIZE_OFFSET 24 +#define DI_DW_GEN_COMPONENT_SIZE_OFFSET 16 + +#define DI_GEN_POLARITY_1 (1 << 0) +#define DI_GEN_POLARITY_2 (1 << 1) +#define DI_GEN_POLARITY_3 (1 << 2) +#define DI_GEN_POLARITY_4 (1 << 3) +#define DI_GEN_POLARITY_5 (1 << 4) +#define DI_GEN_POLARITY_6 (1 << 5) +#define DI_GEN_POLARITY_7 (1 << 6) +#define DI_GEN_POLARITY_8 (1 << 7) +#define DI_GEN_POLARITY_DISP_CLK (1 << 17) +#define DI_GEN_DI_CLK_EXT (1 << 20) +#define DI_GEN_DI_VSYNC_EXT (1 << 21) + +#define DI_POL_DRDY_DATA_POLARITY (1 << 7) +#define DI_POL_DRDY_POLARITY_15 (1 << 4) + +#define DI_VSYNC_SEL_OFFSET 13 + +static inline u32 ipu_di_read(struct ipu_di *di, unsigned offset) +{ + return readl(di->base + offset); +} + +static inline void ipu_di_write(struct ipu_di *di, u32 value, unsigned offset) +{ + writel(value, di->base + offset); +} + +static int ipu_di_clk_calc_div(unsigned long inrate, unsigned long outrate) +{ + u64 tmp = inrate; + int div; + + tmp *= 16; + + do_div(tmp, outrate); + + div = tmp; + + if (div < 0x10) + div = 0x10; + +#ifdef WTF_IS_THIS + /* + * Freescale has this in their Kernel. It is neither clear what + * it does nor why it does it + */ + if (div & 0x10) + div &= ~0x7; + else { + /* Round up divider if it gets us closer to desired pix clk */ + if ((div & 0xC) == 0xC) { + div += 0x10; + div &= ~0xF; + } + } +#endif + return div; +} + +static unsigned long clk_di_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out); + unsigned long outrate; + u32 div = ipu_di_read(di, DI_BS_CLKGEN0); + + if (div < 0x10) + div = 0x10; + + outrate = (parent_rate / div) * 16; + + return outrate; +} + +static long clk_di_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *prate) +{ + struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out); + unsigned long outrate; + int div; + u32 val; + + div = ipu_di_clk_calc_div(*prate, rate); + + outrate = (*prate / div) * 16; + + val = ipu_di_read(di, DI_GENERAL); + + if (!(val & DI_GEN_DI_CLK_EXT) && outrate > *prate / 2) + outrate = *prate / 2; + + dev_dbg(di->ipu->dev, + "%s: inrate: %ld div: 0x%08x outrate: %ld wanted: %ld\n", + __func__, *prate, div, outrate, rate); + + return outrate; +} + +static int clk_di_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out); + int div; + u32 clkgen0; + + clkgen0 = ipu_di_read(di, DI_BS_CLKGEN0) & ~0xfff; + + div = ipu_di_clk_calc_div(parent_rate, rate); + + ipu_di_write(di, clkgen0 | div, DI_BS_CLKGEN0); + + dev_dbg(di->ipu->dev, "%s: inrate: %ld desired: %ld div: 0x%08x\n", + __func__, parent_rate, rate, div); + return 0; +} + +static u8 clk_di_get_parent(struct clk_hw *hw) +{ + struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out); + u32 val; + + val = ipu_di_read(di, DI_GENERAL); + + return val & DI_GEN_DI_CLK_EXT ? 1 : 0; +} + +static int clk_di_set_parent(struct clk_hw *hw, u8 index) +{ + struct ipu_di *di = container_of(hw, struct ipu_di, clk_hw_out); + u32 val; + + val = ipu_di_read(di, DI_GENERAL); + + if (index) + val |= DI_GEN_DI_CLK_EXT; + else + val &= ~DI_GEN_DI_CLK_EXT; + + ipu_di_write(di, val, DI_GENERAL); + + return 0; +} + +static struct clk_ops clk_di_ops = { + .round_rate = clk_di_round_rate, + .set_rate = clk_di_set_rate, + .recalc_rate = clk_di_recalc_rate, + .set_parent = clk_di_set_parent, + .get_parent = clk_di_get_parent, +}; + +static void ipu_di_data_wave_config(struct ipu_di *di, + int wave_gen, + int access_size, int component_size) +{ + u32 reg; + reg = (access_size << DI_DW_GEN_ACCESS_SIZE_OFFSET) | + (component_size << DI_DW_GEN_COMPONENT_SIZE_OFFSET); + ipu_di_write(di, reg, DI_DW_GEN(wave_gen)); +} + +static void ipu_di_data_pin_config(struct ipu_di *di, int wave_gen, int di_pin, + int set, int up, int down) +{ + u32 reg; + + reg = ipu_di_read(di, DI_DW_GEN(wave_gen)); + reg &= ~(0x3 << (di_pin * 2)); + reg |= set << (di_pin * 2); + ipu_di_write(di, reg, DI_DW_GEN(wave_gen)); + + ipu_di_write(di, (down << 16) | up, DI_DW_SET(wave_gen, set)); +} + +static void ipu_di_sync_config(struct ipu_di *di, struct di_sync_config *config, + int start, int count) +{ + u32 reg; + int i; + + for (i = 0; i < count; i++) { + struct di_sync_config *c = &config[i]; + int wave_gen = start + i + 1; + + if ((c->run_count >= 0x1000) || (c->offset_count >= 0x1000) || + (c->repeat_count >= 0x1000) || + (c->cnt_up >= 0x400) || + (c->cnt_down >= 0x400)) { + dev_err(di->ipu->dev, "DI%d counters out of range.\n", + di->id); + return; + } + + reg = DI_SW_GEN0_RUN_COUNT(c->run_count) | + DI_SW_GEN0_RUN_SRC(c->run_src) | + DI_SW_GEN0_OFFSET_COUNT(c->offset_count) | + DI_SW_GEN0_OFFSET_SRC(c->offset_src); + ipu_di_write(di, reg, DI_SW_GEN0(wave_gen)); + + reg = DI_SW_GEN1_CNT_POL_GEN_EN(c->cnt_polarity_gen_en) | + DI_SW_GEN1_CNT_CLR_SRC(c->cnt_clr_src) | + DI_SW_GEN1_CNT_POL_TRIGGER_SRC( + c->cnt_polarity_trigger_src) | + DI_SW_GEN1_CNT_POL_CLR_SRC(c->cnt_polarity_clr_src) | + DI_SW_GEN1_CNT_DOWN(c->cnt_down) | + DI_SW_GEN1_CNT_UP(c->cnt_up); + + /* Enable auto reload */ + if (c->repeat_count == 0) + reg |= DI_SW_GEN1_AUTO_RELOAD; + + ipu_di_write(di, reg, DI_SW_GEN1(wave_gen)); + + reg = ipu_di_read(di, DI_STP_REP(wave_gen)); + reg &= ~(0xffff << (16 * ((wave_gen - 1) & 0x1))); + reg |= c->repeat_count << (16 * ((wave_gen - 1) & 0x1)); + ipu_di_write(di, reg, DI_STP_REP(wave_gen)); + } +} + +static void ipu_di_sync_config_interlaced(struct ipu_di *di, + struct ipu_di_signal_cfg *sig) +{ + u32 h_total = sig->width + sig->h_sync_width + + sig->h_start_width + sig->h_end_width; + u32 v_total = sig->height + sig->v_sync_width + + sig->v_start_width + sig->v_end_width; + u32 reg; + struct di_sync_config cfg[] = { + { + .run_count = h_total / 2 - 1, + .run_src = DI_SYNC_CLK, + }, { + .run_count = h_total - 11, + .run_src = DI_SYNC_CLK, + .cnt_down = 4, + }, { + .run_count = v_total * 2 - 1, + .run_src = DI_SYNC_INT_HSYNC, + .offset_count = 1, + .offset_src = DI_SYNC_INT_HSYNC, + .cnt_down = 4, + }, { + .run_count = v_total / 2 - 1, + .run_src = DI_SYNC_HSYNC, + .offset_count = sig->v_start_width, + .offset_src = DI_SYNC_HSYNC, + .repeat_count = 2, + .cnt_clr_src = DI_SYNC_VSYNC, + }, { + .run_src = DI_SYNC_HSYNC, + .repeat_count = sig->height / 2, + .cnt_clr_src = 4, + }, { + .run_count = v_total - 1, + .run_src = DI_SYNC_HSYNC, + }, { + .run_count = v_total / 2 - 1, + .run_src = DI_SYNC_HSYNC, + .offset_count = 9, + .offset_src = DI_SYNC_HSYNC, + .repeat_count = 2, + .cnt_clr_src = DI_SYNC_VSYNC, + }, { + .run_src = DI_SYNC_CLK, + .offset_count = sig->h_start_width, + .offset_src = DI_SYNC_CLK, + .repeat_count = sig->width, + .cnt_clr_src = 5, + }, { + .run_count = v_total - 1, + .run_src = DI_SYNC_INT_HSYNC, + .offset_count = v_total / 2, + .offset_src = DI_SYNC_INT_HSYNC, + .cnt_clr_src = DI_SYNC_HSYNC, + .cnt_down = 4, + } + }; + + ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg)); + + /* set gentime select and tag sel */ + reg = ipu_di_read(di, DI_SW_GEN1(9)); + reg &= 0x1FFFFFFF; + reg |= (3 - 1) << 29 | 0x00008000; + ipu_di_write(di, reg, DI_SW_GEN1(9)); + + ipu_di_write(di, v_total / 2 - 1, DI_SCR_CONF); +} + +static void ipu_di_sync_config_noninterlaced(struct ipu_di *di, + struct ipu_di_signal_cfg *sig, int div) +{ + u32 h_total = sig->width + sig->h_sync_width + sig->h_start_width + + sig->h_end_width; + u32 v_total = sig->height + sig->v_sync_width + sig->v_start_width + + sig->v_end_width; + struct di_sync_config cfg[] = { + { + .run_count = h_total - 1, + .run_src = DI_SYNC_CLK, + } , { + .run_count = h_total - 1, + .run_src = DI_SYNC_CLK, + .offset_count = div * sig->v_to_h_sync, + .offset_src = DI_SYNC_CLK, + .cnt_polarity_gen_en = 1, + .cnt_polarity_trigger_src = DI_SYNC_CLK, + .cnt_down = sig->h_sync_width * 2, + } , { + .run_count = v_total - 1, + .run_src = DI_SYNC_INT_HSYNC, + .cnt_polarity_gen_en = 1, + .cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC, + .cnt_down = sig->v_sync_width * 2, + } , { + .run_src = DI_SYNC_HSYNC, + .offset_count = sig->v_sync_width + sig->v_start_width, + .offset_src = DI_SYNC_HSYNC, + .repeat_count = sig->height, + .cnt_clr_src = DI_SYNC_VSYNC, + } , { + .run_src = DI_SYNC_CLK, + .offset_count = sig->h_sync_width + sig->h_start_width, + .offset_src = DI_SYNC_CLK, + .repeat_count = sig->width, + .cnt_clr_src = 5, + } , { + /* unused */ + } , { + /* unused */ + } , { + /* unused */ + } , { + /* unused */ + }, + }; + + ipu_di_write(di, v_total - 1, DI_SCR_CONF); + ipu_di_sync_config(di, cfg, 0, ARRAY_SIZE(cfg)); +} + +int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig) +{ + u32 reg; + u32 di_gen, vsync_cnt; + u32 div; + u32 h_total, v_total; + int ret; + unsigned long round; + struct clk *parent; + + dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n", + di->id, sig->width, sig->height); + + if ((sig->v_sync_width == 0) || (sig->h_sync_width == 0)) + return -EINVAL; + + if (sig->clkflags & IPU_DI_CLKMODE_EXT) + parent = di->clk_di; + else + parent = di->clk_ipu; + + ret = clk_set_parent(di->clk_di_pixel, parent); + if (ret) { + dev_err(di->ipu->dev, + "setting pixel clock to parent %s failed with %d\n", + __clk_get_name(parent), ret); + return ret; + } + + if (sig->clkflags & IPU_DI_CLKMODE_SYNC) + round = clk_get_rate(parent); + else + round = clk_round_rate(di->clk_di_pixel, sig->pixelclock); + + ret = clk_set_rate(di->clk_di_pixel, round); + + h_total = sig->width + sig->h_sync_width + sig->h_start_width + + sig->h_end_width; + v_total = sig->height + sig->v_sync_width + sig->v_start_width + + sig->v_end_width; + + mutex_lock(&di_mutex); + + div = ipu_di_read(di, DI_BS_CLKGEN0) & 0xfff; + div = div / 16; /* Now divider is integer portion */ + + /* Setup pixel clock timing */ + /* Down time is half of period */ + ipu_di_write(di, (div << 16), DI_BS_CLKGEN1); + + ipu_di_data_wave_config(di, SYNC_WAVE, div - 1, div - 1); + ipu_di_data_pin_config(di, SYNC_WAVE, DI_PIN15, 3, 0, div * 2); + + di_gen = ipu_di_read(di, DI_GENERAL) & DI_GEN_DI_CLK_EXT; + di_gen |= DI_GEN_DI_VSYNC_EXT; + + if (sig->interlaced) { + ipu_di_sync_config_interlaced(di, sig); + + /* set y_sel = 1 */ + di_gen |= 0x10000000; + di_gen |= DI_GEN_POLARITY_5; + di_gen |= DI_GEN_POLARITY_8; + + vsync_cnt = 7; + + if (sig->Hsync_pol) + di_gen |= DI_GEN_POLARITY_3; + if (sig->Vsync_pol) + di_gen |= DI_GEN_POLARITY_2; + } else { + ipu_di_sync_config_noninterlaced(di, sig, div); + + vsync_cnt = 3; + + if (sig->Hsync_pol) + di_gen |= DI_GEN_POLARITY_2; + if (sig->Vsync_pol) + di_gen |= DI_GEN_POLARITY_3; + } + + if (!sig->clk_pol) + di_gen |= DI_GEN_POLARITY_DISP_CLK; + + ipu_di_write(di, di_gen, DI_GENERAL); + + ipu_di_write(di, (--vsync_cnt << DI_VSYNC_SEL_OFFSET) | 0x00000002, + DI_SYNC_AS_GEN); + + reg = ipu_di_read(di, DI_POL); + reg &= ~(DI_POL_DRDY_DATA_POLARITY | DI_POL_DRDY_POLARITY_15); + + if (sig->enable_pol) + reg |= DI_POL_DRDY_POLARITY_15; + if (sig->data_pol) + reg |= DI_POL_DRDY_DATA_POLARITY; + + ipu_di_write(di, reg, DI_POL); + + mutex_unlock(&di_mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_di_init_sync_panel); + +int ipu_di_enable(struct ipu_di *di) +{ + clk_prepare_enable(di->clk_di_pixel); + + ipu_module_enable(di->ipu, di->module); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_di_enable); + +int ipu_di_disable(struct ipu_di *di) +{ + ipu_module_disable(di->ipu, di->module); + + clk_disable_unprepare(di->clk_di_pixel); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_di_disable); + +int ipu_di_get_num(struct ipu_di *di) +{ + return di->id; +} +EXPORT_SYMBOL_GPL(ipu_di_get_num); + +static DEFINE_MUTEX(ipu_di_lock); + +struct ipu_di *ipu_di_get(struct ipu_soc *ipu, int disp) +{ + struct ipu_di *di; + + if (disp > 1) + return ERR_PTR(-EINVAL); + + di = ipu->di_priv[disp]; + + mutex_lock(&ipu_di_lock); + + if (di->inuse) { + di = ERR_PTR(-EBUSY); + goto out; + } + + di->inuse = true; +out: + mutex_unlock(&ipu_di_lock); + + return di; +} +EXPORT_SYMBOL_GPL(ipu_di_get); + +void ipu_di_put(struct ipu_di *di) +{ + mutex_lock(&ipu_di_lock); + + di->inuse = false; + + mutex_unlock(&ipu_di_lock); +} +EXPORT_SYMBOL_GPL(ipu_di_put); + +int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id, + unsigned long base, + u32 module, struct clk *clk_ipu) +{ + struct ipu_di *di; + int ret; + const char *di_parent[2]; + struct clk_init_data init = { + .ops = &clk_di_ops, + .num_parents = 2, + .flags = 0, + }; + + if (id > 1) + return -ENODEV; + + di = devm_kzalloc(dev, sizeof(*di), GFP_KERNEL); + if (!di) + return -ENOMEM; + + ipu->di_priv[id] = di; + + di->clk_di = devm_clk_get(dev, id ? "di1" : "di0"); + if (IS_ERR(di->clk_di)) + return PTR_ERR(di->clk_di); + + di->module = module; + di->id = id; + di->clk_ipu = clk_ipu; + di->base = devm_ioremap(dev, base, PAGE_SIZE); + if (!di->base) + return -ENOMEM; + + di_parent[0] = __clk_get_name(di->clk_ipu); + di_parent[1] = __clk_get_name(di->clk_di); + + ipu_di_write(di, 0x10, DI_BS_CLKGEN0); + + init.parent_names = (const char **)&di_parent; + di->clk_name = kasprintf(GFP_KERNEL, "%s_di%d_pixel", + dev_name(dev), id); + if (!di->clk_name) + return -ENOMEM; + + init.name = di->clk_name; + + di->clk_hw_out.init = &init; + di->clk_di_pixel = clk_register(dev, &di->clk_hw_out); + + if (IS_ERR(di->clk_di_pixel)) { + ret = PTR_ERR(di->clk_di_pixel); + goto failed_clk_register; + } + + dev_info(dev, "DI%d base: 0x%08lx remapped to %p\n", + id, base, di->base); + di->inuse = false; + di->ipu = ipu; + + return 0; + +failed_clk_register: + + kfree(di->clk_name); + + return ret; +} + +void ipu_di_exit(struct ipu_soc *ipu, int id) +{ + struct ipu_di *di = ipu->di_priv[id]; + + clk_unregister(di->clk_di_pixel); + kfree(di->clk_name); +} diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c new file mode 100644 index 000000000000..91821bc30f41 --- /dev/null +++ b/drivers/staging/imx-drm/ipu-v3/ipu-dmfc.c @@ -0,0 +1,408 @@ +/* + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de> + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ +#include <linux/export.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/io.h> + +#include "imx-ipu-v3.h" +#include "ipu-prv.h" + +#define DMFC_RD_CHAN 0x0000 +#define DMFC_WR_CHAN 0x0004 +#define DMFC_WR_CHAN_DEF 0x0008 +#define DMFC_DP_CHAN 0x000c +#define DMFC_DP_CHAN_DEF 0x0010 +#define DMFC_GENERAL1 0x0014 +#define DMFC_GENERAL2 0x0018 +#define DMFC_IC_CTRL 0x001c +#define DMFC_STAT 0x0020 + +#define DMFC_WR_CHAN_1_28 0 +#define DMFC_WR_CHAN_2_41 8 +#define DMFC_WR_CHAN_1C_42 16 +#define DMFC_WR_CHAN_2C_43 24 + +#define DMFC_DP_CHAN_5B_23 0 +#define DMFC_DP_CHAN_5F_27 8 +#define DMFC_DP_CHAN_6B_24 16 +#define DMFC_DP_CHAN_6F_29 24 + +#define DMFC_FIFO_SIZE_64 (3 << 3) +#define DMFC_FIFO_SIZE_128 (2 << 3) +#define DMFC_FIFO_SIZE_256 (1 << 3) +#define DMFC_FIFO_SIZE_512 (0 << 3) + +#define DMFC_SEGMENT(x) ((x & 0x7) << 0) +#define DMFC_BURSTSIZE_128 (0 << 6) +#define DMFC_BURSTSIZE_64 (1 << 6) +#define DMFC_BURSTSIZE_32 (2 << 6) +#define DMFC_BURSTSIZE_16 (3 << 6) + +struct dmfc_channel_data { + int ipu_channel; + unsigned long channel_reg; + unsigned long shift; + unsigned eot_shift; + unsigned max_fifo_lines; +}; + +static const struct dmfc_channel_data dmfcdata[] = { + { + .ipu_channel = 23, + .channel_reg = DMFC_DP_CHAN, + .shift = DMFC_DP_CHAN_5B_23, + .eot_shift = 20, + .max_fifo_lines = 3, + }, { + .ipu_channel = 24, + .channel_reg = DMFC_DP_CHAN, + .shift = DMFC_DP_CHAN_6B_24, + .eot_shift = 22, + .max_fifo_lines = 1, + }, { + .ipu_channel = 27, + .channel_reg = DMFC_DP_CHAN, + .shift = DMFC_DP_CHAN_5F_27, + .eot_shift = 21, + .max_fifo_lines = 2, + }, { + .ipu_channel = 28, + .channel_reg = DMFC_WR_CHAN, + .shift = DMFC_WR_CHAN_1_28, + .eot_shift = 16, + .max_fifo_lines = 2, + }, { + .ipu_channel = 29, + .channel_reg = DMFC_DP_CHAN, + .shift = DMFC_DP_CHAN_6F_29, + .eot_shift = 23, + .max_fifo_lines = 1, + }, +}; + +#define DMFC_NUM_CHANNELS ARRAY_SIZE(dmfcdata) + +struct ipu_dmfc_priv; + +struct dmfc_channel { + unsigned slots; + unsigned slotmask; + unsigned segment; + int burstsize; + struct ipu_soc *ipu; + struct ipu_dmfc_priv *priv; + const struct dmfc_channel_data *data; +}; + +struct ipu_dmfc_priv { + struct ipu_soc *ipu; + struct device *dev; + struct dmfc_channel channels[DMFC_NUM_CHANNELS]; + struct mutex mutex; + unsigned long bandwidth_per_slot; + void __iomem *base; + int use_count; +}; + +int ipu_dmfc_enable_channel(struct dmfc_channel *dmfc) +{ + struct ipu_dmfc_priv *priv = dmfc->priv; + mutex_lock(&priv->mutex); + + if (!priv->use_count) + ipu_module_enable(priv->ipu, IPU_CONF_DMFC_EN); + + priv->use_count++; + + mutex_unlock(&priv->mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_dmfc_enable_channel); + +void ipu_dmfc_disable_channel(struct dmfc_channel *dmfc) +{ + struct ipu_dmfc_priv *priv = dmfc->priv; + + mutex_lock(&priv->mutex); + + priv->use_count--; + + if (!priv->use_count) + ipu_module_disable(priv->ipu, IPU_CONF_DMFC_EN); + + if (priv->use_count < 0) + priv->use_count = 0; + + mutex_unlock(&priv->mutex); +} +EXPORT_SYMBOL_GPL(ipu_dmfc_disable_channel); + +static int ipu_dmfc_setup_channel(struct dmfc_channel *dmfc, int slots, + int segment, int burstsize) +{ + struct ipu_dmfc_priv *priv = dmfc->priv; + u32 val, field; + + dev_dbg(priv->dev, + "dmfc: using %d slots starting from segment %d for IPU channel %d\n", + slots, segment, dmfc->data->ipu_channel); + + if (!dmfc) + return -EINVAL; + + switch (slots) { + case 1: + field = DMFC_FIFO_SIZE_64; + break; + case 2: + field = DMFC_FIFO_SIZE_128; + break; + case 4: + field = DMFC_FIFO_SIZE_256; + break; + case 8: + field = DMFC_FIFO_SIZE_512; + break; + default: + return -EINVAL; + } + + switch (burstsize) { + case 16: + field |= DMFC_BURSTSIZE_16; + break; + case 32: + field |= DMFC_BURSTSIZE_32; + break; + case 64: + field |= DMFC_BURSTSIZE_64; + break; + case 128: + field |= DMFC_BURSTSIZE_128; + break; + } + + field |= DMFC_SEGMENT(segment); + + val = readl(priv->base + dmfc->data->channel_reg); + + val &= ~(0xff << dmfc->data->shift); + val |= field << dmfc->data->shift; + + writel(val, priv->base + dmfc->data->channel_reg); + + dmfc->slots = slots; + dmfc->segment = segment; + dmfc->burstsize = burstsize; + dmfc->slotmask = ((1 << slots) - 1) << segment; + + return 0; +} + +static int dmfc_bandwidth_to_slots(struct ipu_dmfc_priv *priv, + unsigned long bandwidth) +{ + int slots = 1; + + while (slots * priv->bandwidth_per_slot < bandwidth) + slots *= 2; + + return slots; +} + +static int dmfc_find_slots(struct ipu_dmfc_priv *priv, int slots) +{ + unsigned slotmask_need, slotmask_used = 0; + int i, segment = 0; + + slotmask_need = (1 << slots) - 1; + + for (i = 0; i < DMFC_NUM_CHANNELS; i++) + slotmask_used |= priv->channels[i].slotmask; + + while (slotmask_need <= 0xff) { + if (!(slotmask_used & slotmask_need)) + return segment; + + slotmask_need <<= 1; + segment++; + } + + return -EBUSY; +} + +void ipu_dmfc_free_bandwidth(struct dmfc_channel *dmfc) +{ + struct ipu_dmfc_priv *priv = dmfc->priv; + int i; + + dev_dbg(priv->dev, "dmfc: freeing %d slots starting from segment %d\n", + dmfc->slots, dmfc->segment); + + mutex_lock(&priv->mutex); + + if (!dmfc->slots) + goto out; + + dmfc->slotmask = 0; + dmfc->slots = 0; + dmfc->segment = 0; + + for (i = 0; i < DMFC_NUM_CHANNELS; i++) + priv->channels[i].slotmask = 0; + + for (i = 0; i < DMFC_NUM_CHANNELS; i++) { + if (priv->channels[i].slots > 0) { + priv->channels[i].segment = + dmfc_find_slots(priv, priv->channels[i].slots); + priv->channels[i].slotmask = + ((1 << priv->channels[i].slots) - 1) << + priv->channels[i].segment; + } + } + + for (i = 0; i < DMFC_NUM_CHANNELS; i++) { + if (priv->channels[i].slots > 0) + ipu_dmfc_setup_channel(&priv->channels[i], + priv->channels[i].slots, + priv->channels[i].segment, + priv->channels[i].burstsize); + } +out: + mutex_unlock(&priv->mutex); +} +EXPORT_SYMBOL_GPL(ipu_dmfc_free_bandwidth); + +int ipu_dmfc_alloc_bandwidth(struct dmfc_channel *dmfc, + unsigned long bandwidth_pixel_per_second, int burstsize) +{ + struct ipu_dmfc_priv *priv = dmfc->priv; + int slots = dmfc_bandwidth_to_slots(priv, bandwidth_pixel_per_second); + int segment = 0, ret = 0; + + dev_dbg(priv->dev, "dmfc: trying to allocate %ldMpixel/s for IPU channel %d\n", + bandwidth_pixel_per_second / 1000000, + dmfc->data->ipu_channel); + + ipu_dmfc_free_bandwidth(dmfc); + + mutex_lock(&priv->mutex); + + if (slots > 8) { + ret = -EBUSY; + goto out; + } + + segment = dmfc_find_slots(priv, slots); + if (segment < 0) { + ret = -EBUSY; + goto out; + } + + ipu_dmfc_setup_channel(dmfc, slots, segment, burstsize); + +out: + mutex_unlock(&priv->mutex); + + return ret; +} +EXPORT_SYMBOL_GPL(ipu_dmfc_alloc_bandwidth); + +int ipu_dmfc_init_channel(struct dmfc_channel *dmfc, int width) +{ + struct ipu_dmfc_priv *priv = dmfc->priv; + u32 dmfc_gen1; + + dmfc_gen1 = readl(priv->base + DMFC_GENERAL1); + + if ((dmfc->slots * 64 * 4) / width > dmfc->data->max_fifo_lines) + dmfc_gen1 |= 1 << dmfc->data->eot_shift; + else + dmfc_gen1 &= ~(1 << dmfc->data->eot_shift); + + writel(dmfc_gen1, priv->base + DMFC_GENERAL1); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_dmfc_init_channel); + +struct dmfc_channel *ipu_dmfc_get(struct ipu_soc *ipu, int ipu_channel) +{ + struct ipu_dmfc_priv *priv = ipu->dmfc_priv; + int i; + + for (i = 0; i < DMFC_NUM_CHANNELS; i++) + if (dmfcdata[i].ipu_channel == ipu_channel) + return &priv->channels[i]; + return ERR_PTR(-ENODEV); +} +EXPORT_SYMBOL_GPL(ipu_dmfc_get); + +void ipu_dmfc_put(struct dmfc_channel *dmfc) +{ + ipu_dmfc_free_bandwidth(dmfc); +} +EXPORT_SYMBOL_GPL(ipu_dmfc_put); + +int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base, + struct clk *ipu_clk) +{ + struct ipu_dmfc_priv *priv; + int i; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->base = devm_ioremap(dev, base, PAGE_SIZE); + if (!priv->base) + return -ENOMEM; + + priv->dev = dev; + priv->ipu = ipu; + mutex_init(&priv->mutex); + + ipu->dmfc_priv = priv; + + for (i = 0; i < DMFC_NUM_CHANNELS; i++) { + priv->channels[i].priv = priv; + priv->channels[i].ipu = ipu; + priv->channels[i].data = &dmfcdata[i]; + } + + writel(0x0, priv->base + DMFC_WR_CHAN); + writel(0x0, priv->base + DMFC_DP_CHAN); + + /* + * We have a total bandwidth of clkrate * 4pixel divided + * into 8 slots. + */ + priv->bandwidth_per_slot = clk_get_rate(ipu_clk) / 8; + + dev_dbg(dev, "dmfc: 8 slots with %ldMpixel/s bandwidth each\n", + priv->bandwidth_per_slot / 1000000); + + writel(0x202020f6, priv->base + DMFC_WR_CHAN_DEF); + writel(0x2020f6f6, priv->base + DMFC_DP_CHAN_DEF); + writel(0x00000003, priv->base + DMFC_GENERAL1); + + return 0; +} + +void ipu_dmfc_exit(struct ipu_soc *ipu) +{ +} diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-dp.c b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c new file mode 100644 index 000000000000..26aecaf9677f --- /dev/null +++ b/drivers/staging/imx-drm/ipu-v3/ipu-dp.c @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de> + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ +#include <linux/export.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/errno.h> +#include <linux/io.h> +#include <linux/err.h> + +#include "imx-ipu-v3.h" +#include "ipu-prv.h" + +#define DP_SYNC 0 +#define DP_ASYNC0 0x60 +#define DP_ASYNC1 0xBC + +#define DP_COM_CONF 0x0 +#define DP_GRAPH_WIND_CTRL 0x0004 +#define DP_FG_POS 0x0008 +#define DP_CSC_A_0 0x0044 +#define DP_CSC_A_1 0x0048 +#define DP_CSC_A_2 0x004C +#define DP_CSC_A_3 0x0050 +#define DP_CSC_0 0x0054 +#define DP_CSC_1 0x0058 + +#define DP_COM_CONF_FG_EN (1 << 0) +#define DP_COM_CONF_GWSEL (1 << 1) +#define DP_COM_CONF_GWAM (1 << 2) +#define DP_COM_CONF_GWCKE (1 << 3) +#define DP_COM_CONF_CSC_DEF_MASK (3 << 8) +#define DP_COM_CONF_CSC_DEF_OFFSET 8 +#define DP_COM_CONF_CSC_DEF_FG (3 << 8) +#define DP_COM_CONF_CSC_DEF_BG (2 << 8) +#define DP_COM_CONF_CSC_DEF_BOTH (1 << 8) + +struct ipu_dp_priv; + +struct ipu_dp { + u32 flow; + bool in_use; + bool foreground; + enum ipu_color_space in_cs; +}; + +struct ipu_flow { + struct ipu_dp foreground; + struct ipu_dp background; + enum ipu_color_space out_cs; + void __iomem *base; + struct ipu_dp_priv *priv; +}; + +struct ipu_dp_priv { + struct ipu_soc *ipu; + struct device *dev; + void __iomem *base; + struct ipu_flow flow[3]; + struct mutex mutex; + int use_count; +}; + +static u32 ipu_dp_flow_base[] = {DP_SYNC, DP_ASYNC0, DP_ASYNC1}; + +static inline struct ipu_flow *to_flow(struct ipu_dp *dp) +{ + if (dp->foreground) + return container_of(dp, struct ipu_flow, foreground); + else + return container_of(dp, struct ipu_flow, background); +} + +int ipu_dp_set_global_alpha(struct ipu_dp *dp, bool enable, + u8 alpha, bool bg_chan) +{ + struct ipu_flow *flow = to_flow(dp); + struct ipu_dp_priv *priv = flow->priv; + u32 reg; + + mutex_lock(&priv->mutex); + + reg = readl(flow->base + DP_COM_CONF); + if (bg_chan) + reg &= ~DP_COM_CONF_GWSEL; + else + reg |= DP_COM_CONF_GWSEL; + writel(reg, flow->base + DP_COM_CONF); + + if (enable) { + reg = readl(flow->base + DP_GRAPH_WIND_CTRL) & 0x00FFFFFFL; + writel(reg | ((u32) alpha << 24), + flow->base + DP_GRAPH_WIND_CTRL); + + reg = readl(flow->base + DP_COM_CONF); + writel(reg | DP_COM_CONF_GWAM, flow->base + DP_COM_CONF); + } else { + reg = readl(flow->base + DP_COM_CONF); + writel(reg & ~DP_COM_CONF_GWAM, flow->base + DP_COM_CONF); + } + + ipu_srm_dp_sync_update(priv->ipu); + + mutex_unlock(&priv->mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_dp_set_global_alpha); + +int ipu_dp_set_window_pos(struct ipu_dp *dp, u16 x_pos, u16 y_pos) +{ + struct ipu_flow *flow = to_flow(dp); + struct ipu_dp_priv *priv = flow->priv; + + writel((x_pos << 16) | y_pos, flow->base + DP_FG_POS); + + ipu_srm_dp_sync_update(priv->ipu); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_dp_set_window_pos); + +static void ipu_dp_csc_init(struct ipu_flow *flow, + enum ipu_color_space in, + enum ipu_color_space out, + u32 place) +{ + u32 reg; + + reg = readl(flow->base + DP_COM_CONF); + reg &= ~DP_COM_CONF_CSC_DEF_MASK; + + if (in == out) { + writel(reg, flow->base + DP_COM_CONF); + return; + } + + if (in == IPUV3_COLORSPACE_RGB && out == IPUV3_COLORSPACE_YUV) { + writel(0x099 | (0x12d << 16), flow->base + DP_CSC_A_0); + writel(0x03a | (0x3a9 << 16), flow->base + DP_CSC_A_1); + writel(0x356 | (0x100 << 16), flow->base + DP_CSC_A_2); + writel(0x100 | (0x329 << 16), flow->base + DP_CSC_A_3); + writel(0x3d6 | (0x0000 << 16) | (2 << 30), + flow->base + DP_CSC_0); + writel(0x200 | (2 << 14) | (0x200 << 16) | (2 << 30), + flow->base + DP_CSC_1); + } else { + writel(0x095 | (0x000 << 16), flow->base + DP_CSC_A_0); + writel(0x0cc | (0x095 << 16), flow->base + DP_CSC_A_1); + writel(0x3ce | (0x398 << 16), flow->base + DP_CSC_A_2); + writel(0x095 | (0x0ff << 16), flow->base + DP_CSC_A_3); + writel(0x000 | (0x3e42 << 16) | (1 << 30), + flow->base + DP_CSC_0); + writel(0x10a | (1 << 14) | (0x3dd6 << 16) | (1 << 30), + flow->base + DP_CSC_1); + } + + reg |= place; + + writel(reg, flow->base + DP_COM_CONF); +} + +int ipu_dp_setup_channel(struct ipu_dp *dp, + enum ipu_color_space in, + enum ipu_color_space out) +{ + struct ipu_flow *flow = to_flow(dp); + struct ipu_dp_priv *priv = flow->priv; + + mutex_lock(&priv->mutex); + + dp->in_cs = in; + + if (!dp->foreground) + flow->out_cs = out; + + if (flow->foreground.in_cs == flow->background.in_cs) { + /* + * foreground and background are of same colorspace, put + * colorspace converter after combining unit. + */ + ipu_dp_csc_init(flow, flow->foreground.in_cs, flow->out_cs, + DP_COM_CONF_CSC_DEF_BOTH); + } else { + if (flow->foreground.in_cs == flow->out_cs) + /* + * foreground identical to output, apply color + * conversion on background + */ + ipu_dp_csc_init(flow, flow->background.in_cs, + flow->out_cs, DP_COM_CONF_CSC_DEF_BG); + else + ipu_dp_csc_init(flow, flow->foreground.in_cs, + flow->out_cs, DP_COM_CONF_CSC_DEF_FG); + } + + ipu_srm_dp_sync_update(priv->ipu); + + mutex_unlock(&priv->mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_dp_setup_channel); + +int ipu_dp_enable_channel(struct ipu_dp *dp) +{ + struct ipu_flow *flow = to_flow(dp); + struct ipu_dp_priv *priv = flow->priv; + + mutex_lock(&priv->mutex); + + if (!priv->use_count) + ipu_module_enable(priv->ipu, IPU_CONF_DP_EN); + + priv->use_count++; + + if (dp->foreground) { + u32 reg; + + reg = readl(flow->base + DP_COM_CONF); + reg |= DP_COM_CONF_FG_EN; + writel(reg, flow->base + DP_COM_CONF); + + ipu_srm_dp_sync_update(priv->ipu); + } + + mutex_unlock(&priv->mutex); + + return 0; +} +EXPORT_SYMBOL_GPL(ipu_dp_enable_channel); + +void ipu_dp_disable_channel(struct ipu_dp *dp) +{ + struct ipu_flow *flow = to_flow(dp); + struct ipu_dp_priv *priv = flow->priv; + + mutex_lock(&priv->mutex); + + priv->use_count--; + + if (dp->foreground) { + u32 reg, csc; + + reg = readl(flow->base + DP_COM_CONF); + csc = reg & DP_COM_CONF_CSC_DEF_MASK; + if (csc == DP_COM_CONF_CSC_DEF_FG) + reg &= ~DP_COM_CONF_CSC_DEF_MASK; + + reg &= ~DP_COM_CONF_FG_EN; + writel(reg, flow->base + DP_COM_CONF); + + writel(0, flow->base + DP_FG_POS); + ipu_srm_dp_sync_update(priv->ipu); + } + + if (!priv->use_count) + ipu_module_disable(priv->ipu, IPU_CONF_DP_EN); + + if (priv->use_count < 0) + priv->use_count = 0; + + mutex_unlock(&priv->mutex); +} +EXPORT_SYMBOL_GPL(ipu_dp_disable_channel); + +struct ipu_dp *ipu_dp_get(struct ipu_soc *ipu, unsigned int flow) +{ + struct ipu_dp_priv *priv = ipu->dp_priv; + struct ipu_dp *dp; + + if (flow > 5) + return ERR_PTR(-EINVAL); + + if (flow & 1) + dp = &priv->flow[flow >> 1].foreground; + else + dp = &priv->flow[flow >> 1].background; + + if (dp->in_use) + return ERR_PTR(-EBUSY); + + dp->in_use = true; + + return dp; +} +EXPORT_SYMBOL_GPL(ipu_dp_get); + +void ipu_dp_put(struct ipu_dp *dp) +{ + dp->in_use = false; +} +EXPORT_SYMBOL_GPL(ipu_dp_put); + +int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base) +{ + struct ipu_dp_priv *priv; + int i; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + priv->dev = dev; + priv->ipu = ipu; + + ipu->dp_priv = priv; + + priv->base = devm_ioremap(dev, base, PAGE_SIZE); + if (!priv->base) { + kfree(priv); + return -ENOMEM; + } + + mutex_init(&priv->mutex); + + for (i = 0; i < 3; i++) { + priv->flow[i].foreground.foreground = 1; + priv->flow[i].base = priv->base + ipu_dp_flow_base[i]; + priv->flow[i].priv = priv; + } + + return 0; +} + +void ipu_dp_exit(struct ipu_soc *ipu) +{ +} diff --git a/drivers/staging/imx-drm/ipu-v3/ipu-prv.h b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h new file mode 100644 index 000000000000..551802863fd5 --- /dev/null +++ b/drivers/staging/imx-drm/ipu-v3/ipu-prv.h @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2010 Sascha Hauer <s.hauer@pengutronix.de> + * Copyright (C) 2005-2009 Freescale Semiconductor, Inc. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ +#ifndef __IPU_PRV_H__ +#define __IPU_PRV_H__ + +struct ipu_soc; + +#include <linux/types.h> +#include <linux/device.h> +#include <linux/clk.h> +#include <linux/platform_device.h> + +#include "imx-ipu-v3.h" + +#define IPUV3_CHANNEL_CSI0 0 +#define IPUV3_CHANNEL_CSI1 1 +#define IPUV3_CHANNEL_CSI2 2 +#define IPUV3_CHANNEL_CSI3 3 +#define IPUV3_CHANNEL_MEM_BG_SYNC 23 +#define IPUV3_CHANNEL_MEM_FG_SYNC 27 +#define IPUV3_CHANNEL_MEM_DC_SYNC 28 +#define IPUV3_CHANNEL_MEM_FG_SYNC_ALPHA 31 +#define IPUV3_CHANNEL_MEM_DC_ASYNC 41 +#define IPUV3_CHANNEL_ROT_ENC_MEM 45 +#define IPUV3_CHANNEL_ROT_VF_MEM 46 +#define IPUV3_CHANNEL_ROT_PP_MEM 47 +#define IPUV3_CHANNEL_ROT_ENC_MEM_OUT 48 +#define IPUV3_CHANNEL_ROT_VF_MEM_OUT 49 +#define IPUV3_CHANNEL_ROT_PP_MEM_OUT 50 +#define IPUV3_CHANNEL_MEM_BG_SYNC_ALPHA 51 + +#define IPU_MCU_T_DEFAULT 8 +#define IPU_CM_IDMAC_REG_OFS 0x00008000 +#define IPU_CM_IC_REG_OFS 0x00020000 +#define IPU_CM_IRT_REG_OFS 0x00028000 +#define IPU_CM_CSI0_REG_OFS 0x00030000 +#define IPU_CM_CSI1_REG_OFS 0x00038000 +#define IPU_CM_SMFC_REG_OFS 0x00050000 +#define IPU_CM_DC_REG_OFS 0x00058000 +#define IPU_CM_DMFC_REG_OFS 0x00060000 + +/* Register addresses */ +/* IPU Common registers */ +#define IPU_CM_REG(offset) (offset) + +#define IPU_CONF IPU_CM_REG(0) + +#define IPU_SRM_PRI1 IPU_CM_REG(0x00a0) +#define IPU_SRM_PRI2 IPU_CM_REG(0x00a4) +#define IPU_FS_PROC_FLOW1 IPU_CM_REG(0x00a8) +#define IPU_FS_PROC_FLOW2 IPU_CM_REG(0x00ac) +#define IPU_FS_PROC_FLOW3 IPU_CM_REG(0x00b0) +#define IPU_FS_DISP_FLOW1 IPU_CM_REG(0x00b4) +#define IPU_FS_DISP_FLOW2 IPU_CM_REG(0x00b8) +#define IPU_SKIP IPU_CM_REG(0x00bc) +#define IPU_DISP_ALT_CONF IPU_CM_REG(0x00c0) +#define IPU_DISP_GEN IPU_CM_REG(0x00c4) +#define IPU_DISP_ALT1 IPU_CM_REG(0x00c8) +#define IPU_DISP_ALT2 IPU_CM_REG(0x00cc) +#define IPU_DISP_ALT3 IPU_CM_REG(0x00d0) +#define IPU_DISP_ALT4 IPU_CM_REG(0x00d4) +#define IPU_SNOOP IPU_CM_REG(0x00d8) +#define IPU_MEM_RST IPU_CM_REG(0x00dc) +#define IPU_PM IPU_CM_REG(0x00e0) +#define IPU_GPR IPU_CM_REG(0x00e4) +#define IPU_CHA_DB_MODE_SEL(ch) IPU_CM_REG(0x0150 + 4 * ((ch) / 32)) +#define IPU_ALT_CHA_DB_MODE_SEL(ch) IPU_CM_REG(0x0168 + 4 * ((ch) / 32)) +#define IPU_CHA_CUR_BUF(ch) IPU_CM_REG(0x023C + 4 * ((ch) / 32)) +#define IPU_ALT_CUR_BUF0 IPU_CM_REG(0x0244) +#define IPU_ALT_CUR_BUF1 IPU_CM_REG(0x0248) +#define IPU_SRM_STAT IPU_CM_REG(0x024C) +#define IPU_PROC_TASK_STAT IPU_CM_REG(0x0250) +#define IPU_DISP_TASK_STAT IPU_CM_REG(0x0254) +#define IPU_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0268 + 4 * ((ch) / 32)) +#define IPU_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0270 + 4 * ((ch) / 32)) +#define IPU_ALT_CHA_BUF0_RDY(ch) IPU_CM_REG(0x0278 + 4 * ((ch) / 32)) +#define IPU_ALT_CHA_BUF1_RDY(ch) IPU_CM_REG(0x0280 + 4 * ((ch) / 32)) + +#define IPU_INT_CTRL(n) IPU_CM_REG(0x003C + 4 * (n)) +#define IPU_INT_STAT(n) IPU_CM_REG(0x0200 + 4 * (n)) + +#define IPU_DI0_COUNTER_RELEASE (1 << 24) +#define IPU_DI1_COUNTER_RELEASE (1 << 25) + +#define IPU_IDMAC_REG(offset) (offset) + +#define IDMAC_CONF IPU_IDMAC_REG(0x0000) +#define IDMAC_CHA_EN(ch) IPU_IDMAC_REG(0x0004 + 4 * ((ch) / 32)) +#define IDMAC_SEP_ALPHA IPU_IDMAC_REG(0x000c) +#define IDMAC_ALT_SEP_ALPHA IPU_IDMAC_REG(0x0010) +#define IDMAC_CHA_PRI(ch) IPU_IDMAC_REG(0x0014 + 4 * ((ch) / 32)) +#define IDMAC_WM_EN(ch) IPU_IDMAC_REG(0x001c + 4 * ((ch) / 32)) +#define IDMAC_CH_LOCK_EN_1 IPU_IDMAC_REG(0x0024) +#define IDMAC_CH_LOCK_EN_2 IPU_IDMAC_REG(0x0028) +#define IDMAC_SUB_ADDR_0 IPU_IDMAC_REG(0x002c) +#define IDMAC_SUB_ADDR_1 IPU_IDMAC_REG(0x0030) +#define IDMAC_SUB_ADDR_2 IPU_IDMAC_REG(0x0034) +#define IDMAC_BAND_EN(ch) IPU_IDMAC_REG(0x0040 + 4 * ((ch) / 32)) +#define IDMAC_CHA_BUSY(ch) IPU_IDMAC_REG(0x0100 + 4 * ((ch) / 32)) + +#define IPU_NUM_IRQS (32 * 5) + +enum ipu_modules { + IPU_CONF_CSI0_EN = (1 << 0), + IPU_CONF_CSI1_EN = (1 << 1), + IPU_CONF_IC_EN = (1 << 2), + IPU_CONF_ROT_EN = (1 << 3), + IPU_CONF_ISP_EN = (1 << 4), + IPU_CONF_DP_EN = (1 << 5), + IPU_CONF_DI0_EN = (1 << 6), + IPU_CONF_DI1_EN = (1 << 7), + IPU_CONF_SMFC_EN = (1 << 8), + IPU_CONF_DC_EN = (1 << 9), + IPU_CONF_DMFC_EN = (1 << 10), + + IPU_CONF_VDI_EN = (1 << 12), + + IPU_CONF_IDMAC_DIS = (1 << 22), + + IPU_CONF_IC_DMFC_SEL = (1 << 25), + IPU_CONF_IC_DMFC_SYNC = (1 << 26), + IPU_CONF_VDI_DMFC_SYNC = (1 << 27), + + IPU_CONF_CSI0_DATA_SOURCE = (1 << 28), + IPU_CONF_CSI1_DATA_SOURCE = (1 << 29), + IPU_CONF_IC_INPUT = (1 << 30), + IPU_CONF_CSI_SEL = (1 << 31), +}; + +struct ipuv3_channel { + unsigned int num; + + bool enabled; + bool busy; + + struct ipu_soc *ipu; +}; + +struct ipu_dc_priv; +struct ipu_dmfc_priv; +struct ipu_di; +struct ipu_devtype; + +struct ipu_soc { + struct device *dev; + const struct ipu_devtype *devtype; + enum ipuv3_type ipu_type; + spinlock_t lock; + struct mutex channel_lock; + + void __iomem *cm_reg; + void __iomem *idmac_reg; + struct ipu_ch_param __iomem *cpmem_base; + + int usecount; + + struct clk *clk; + + struct ipuv3_channel channel[64]; + + int irq_start; + int irq_sync; + int irq_err; + + struct ipu_dc_priv *dc_priv; + struct ipu_dp_priv *dp_priv; + struct ipu_dmfc_priv *dmfc_priv; + struct ipu_di *di_priv[2]; +}; + +void ipu_srm_dp_sync_update(struct ipu_soc *ipu); + +int ipu_module_enable(struct ipu_soc *ipu, u32 mask); +int ipu_module_disable(struct ipu_soc *ipu, u32 mask); + +int ipu_di_init(struct ipu_soc *ipu, struct device *dev, int id, + unsigned long base, u32 module, struct clk *ipu_clk); +void ipu_di_exit(struct ipu_soc *ipu, int id); + +int ipu_dmfc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base, + struct clk *ipu_clk); +void ipu_dmfc_exit(struct ipu_soc *ipu); + +int ipu_dp_init(struct ipu_soc *ipu, struct device *dev, unsigned long base); +void ipu_dp_exit(struct ipu_soc *ipu); + +int ipu_dc_init(struct ipu_soc *ipu, struct device *dev, unsigned long base, + unsigned long template_base); +void ipu_dc_exit(struct ipu_soc *ipu); + +int ipu_cpmem_init(struct ipu_soc *ipu, struct device *dev, unsigned long base); +void ipu_cpmem_exit(struct ipu_soc *ipu); + +#endif /* __IPU_PRV_H__ */ diff --git a/drivers/staging/imx-drm/ipuv3-crtc.c b/drivers/staging/imx-drm/ipuv3-crtc.c new file mode 100644 index 000000000000..78d3edac75c1 --- /dev/null +++ b/drivers/staging/imx-drm/ipuv3-crtc.c @@ -0,0 +1,579 @@ +/* + * i.MX IPUv3 Graphics driver + * + * Copyright (C) 2011 Sascha Hauer, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ +#include <linux/module.h> +#include <linux/export.h> +#include <linux/device.h> +#include <linux/platform_device.h> +#include <drm/drmP.h> +#include <drm/drm_fb_helper.h> +#include <drm/drm_crtc_helper.h> +#include <linux/fb.h> +#include <linux/clk.h> +#include <drm/drm_gem_cma_helper.h> +#include <drm/drm_fb_cma_helper.h> + +#include "ipu-v3/imx-ipu-v3.h" +#include "imx-drm.h" + +#define DRIVER_DESC "i.MX IPUv3 Graphics" + +struct ipu_framebuffer { + struct drm_framebuffer base; + void *virt; + dma_addr_t phys; + size_t len; +}; + +struct ipu_crtc { + struct drm_fb_helper fb_helper; + struct ipu_framebuffer ifb; + int num_crtcs; + struct device *dev; + struct drm_crtc base; + struct imx_drm_crtc *imx_crtc; + struct ipuv3_channel *ipu_ch; + struct ipu_dc *dc; + struct ipu_dp *dp; + struct dmfc_channel *dmfc; + struct ipu_di *di; + int enabled; + struct ipu_priv *ipu_priv; + struct drm_pending_vblank_event *page_flip_event; + struct drm_framebuffer *newfb; + int irq; + u32 interface_pix_fmt; + unsigned long di_clkflags; +}; + +#define to_ipu_crtc(x) container_of(x, struct ipu_crtc, base) + +static int calc_vref(struct drm_display_mode *mode) +{ + unsigned long htotal, vtotal; + + htotal = mode->htotal; + vtotal = mode->vtotal; + + if (!htotal || !vtotal) + return 60; + + return mode->clock * 1000 / vtotal / htotal; +} + +static int calc_bandwidth(struct drm_display_mode *mode, unsigned int vref) +{ + return mode->hdisplay * mode->vdisplay * vref; +} + +static void ipu_fb_enable(struct ipu_crtc *ipu_crtc) +{ + if (ipu_crtc->enabled) + return; + + ipu_di_enable(ipu_crtc->di); + ipu_dmfc_enable_channel(ipu_crtc->dmfc); + ipu_idmac_enable_channel(ipu_crtc->ipu_ch); + ipu_dc_enable_channel(ipu_crtc->dc); + if (ipu_crtc->dp) + ipu_dp_enable_channel(ipu_crtc->dp); + + ipu_crtc->enabled = 1; +} + +static void ipu_fb_disable(struct ipu_crtc *ipu_crtc) +{ + if (!ipu_crtc->enabled) + return; + + if (ipu_crtc->dp) + ipu_dp_disable_channel(ipu_crtc->dp); + ipu_dc_disable_channel(ipu_crtc->dc); + ipu_idmac_disable_channel(ipu_crtc->ipu_ch); + ipu_dmfc_disable_channel(ipu_crtc->dmfc); + ipu_di_disable(ipu_crtc->di); + + ipu_crtc->enabled = 0; +} + +static void ipu_crtc_dpms(struct drm_crtc *crtc, int mode) +{ + struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); + + dev_info(ipu_crtc->dev, "%s mode: %d\n", __func__, mode); + + switch (mode) { + case DRM_MODE_DPMS_ON: + ipu_fb_enable(ipu_crtc); + break; + case DRM_MODE_DPMS_STANDBY: + case DRM_MODE_DPMS_SUSPEND: + case DRM_MODE_DPMS_OFF: + ipu_fb_disable(ipu_crtc); + break; + } +} + +static int ipu_page_flip(struct drm_crtc *crtc, + struct drm_framebuffer *fb, + struct drm_pending_vblank_event *event) +{ + struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); + int ret; + + if (ipu_crtc->newfb) + return -EBUSY; + + ret = imx_drm_crtc_vblank_get(ipu_crtc->imx_crtc); + if (ret) { + dev_dbg(ipu_crtc->dev, "failed to acquire vblank counter\n"); + list_del(&event->base.link); + + return ret; + } + + ipu_crtc->newfb = fb; + ipu_crtc->page_flip_event = event; + + return 0; +} + +static const struct drm_crtc_funcs ipu_crtc_funcs = { + .set_config = drm_crtc_helper_set_config, + .destroy = drm_crtc_cleanup, + .page_flip = ipu_page_flip, +}; + +static int ipu_drm_set_base(struct drm_crtc *crtc, int x, int y) +{ + struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); + struct drm_gem_cma_object *cma_obj; + struct drm_framebuffer *fb = crtc->fb; + unsigned long phys; + + cma_obj = drm_fb_cma_get_gem_obj(fb, 0); + if (!cma_obj) { + DRM_LOG_KMS("entry is null.\n"); + return -EFAULT; + } + + phys = cma_obj->paddr; + phys += x * (fb->bits_per_pixel >> 3); + phys += y * fb->pitches[0]; + + dev_dbg(ipu_crtc->dev, "%s: phys: 0x%lx\n", __func__, phys); + dev_dbg(ipu_crtc->dev, "%s: xy: %dx%d\n", __func__, x, y); + + ipu_cpmem_set_stride(ipu_get_cpmem(ipu_crtc->ipu_ch), fb->pitches[0]); + ipu_cpmem_set_buffer(ipu_get_cpmem(ipu_crtc->ipu_ch), + 0, phys); + + return 0; +} + +static int ipu_crtc_mode_set(struct drm_crtc *crtc, + struct drm_display_mode *orig_mode, + struct drm_display_mode *mode, + int x, int y, + struct drm_framebuffer *old_fb) +{ + struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); + struct drm_framebuffer *fb = ipu_crtc->base.fb; + int ret; + struct ipu_di_signal_cfg sig_cfg = {}; + u32 out_pixel_fmt; + struct ipu_ch_param __iomem *cpmem = ipu_get_cpmem(ipu_crtc->ipu_ch); + int bpp; + u32 v4l2_fmt; + + dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__, + mode->hdisplay); + dev_dbg(ipu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__, + mode->vdisplay); + + ipu_ch_param_zero(cpmem); + + switch (fb->pixel_format) { + case DRM_FORMAT_XRGB8888: + case DRM_FORMAT_ARGB8888: + v4l2_fmt = V4L2_PIX_FMT_RGB32; + bpp = 32; + break; + case DRM_FORMAT_RGB565: + v4l2_fmt = V4L2_PIX_FMT_RGB565; + bpp = 16; + break; + case DRM_FORMAT_RGB888: + v4l2_fmt = V4L2_PIX_FMT_RGB24; + bpp = 24; + break; + default: + dev_err(ipu_crtc->dev, "unsupported pixel format 0x%08x\n", + fb->pixel_format); + return -EINVAL; + } + + out_pixel_fmt = ipu_crtc->interface_pix_fmt; + + if (mode->flags & DRM_MODE_FLAG_INTERLACE) + sig_cfg.interlaced = 1; + if (mode->flags & DRM_MODE_FLAG_PHSYNC) + sig_cfg.Hsync_pol = 1; + if (mode->flags & DRM_MODE_FLAG_PVSYNC) + sig_cfg.Vsync_pol = 1; + + sig_cfg.enable_pol = 1; + sig_cfg.clk_pol = 0; + sig_cfg.width = mode->hdisplay; + sig_cfg.height = mode->vdisplay; + sig_cfg.pixel_fmt = out_pixel_fmt; + sig_cfg.h_start_width = mode->htotal - mode->hsync_end; + sig_cfg.h_sync_width = mode->hsync_end - mode->hsync_start; + sig_cfg.h_end_width = mode->hsync_start - mode->hdisplay; + + sig_cfg.v_start_width = mode->vtotal - mode->vsync_end; + sig_cfg.v_sync_width = mode->vsync_end - mode->vsync_start; + sig_cfg.v_end_width = mode->vsync_start - mode->vdisplay; + sig_cfg.pixelclock = mode->clock * 1000; + sig_cfg.clkflags = ipu_crtc->di_clkflags; + + sig_cfg.v_to_h_sync = 0; + + if (ipu_crtc->dp) { + ret = ipu_dp_setup_channel(ipu_crtc->dp, IPUV3_COLORSPACE_RGB, + IPUV3_COLORSPACE_RGB); + if (ret) { + dev_err(ipu_crtc->dev, + "initializing display processor failed with %d\n", + ret); + return ret; + } + ipu_dp_set_global_alpha(ipu_crtc->dp, 1, 0, 1); + } + + ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, sig_cfg.interlaced, + out_pixel_fmt, mode->hdisplay); + if (ret) { + dev_err(ipu_crtc->dev, + "initializing display controller failed with %d\n", + ret); + return ret; + } + + ret = ipu_di_init_sync_panel(ipu_crtc->di, &sig_cfg); + if (ret) { + dev_err(ipu_crtc->dev, + "initializing panel failed with %d\n", ret); + return ret; + } + + ipu_cpmem_set_resolution(cpmem, mode->hdisplay, mode->vdisplay); + ipu_cpmem_set_fmt(cpmem, v4l2_fmt); + ipu_cpmem_set_high_priority(ipu_crtc->ipu_ch); + + ret = ipu_dmfc_init_channel(ipu_crtc->dmfc, mode->hdisplay); + if (ret) { + dev_err(ipu_crtc->dev, + "initializing dmfc channel failed with %d\n", + ret); + return ret; + } + + ret = ipu_dmfc_alloc_bandwidth(ipu_crtc->dmfc, + calc_bandwidth(mode, calc_vref(mode)), 64); + if (ret) { + dev_err(ipu_crtc->dev, + "allocating dmfc bandwidth failed with %d\n", + ret); + return ret; + } + + ipu_drm_set_base(crtc, x, y); + + return 0; +} + +static void ipu_crtc_handle_pageflip(struct ipu_crtc *ipu_crtc) +{ + struct drm_pending_vblank_event *e; + struct timeval now; + unsigned long flags; + struct drm_device *drm = ipu_crtc->base.dev; + + spin_lock_irqsave(&drm->event_lock, flags); + + e = ipu_crtc->page_flip_event; + if (!e) { + spin_unlock_irqrestore(&drm->event_lock, flags); + return; + } + + do_gettimeofday(&now); + e->event.sequence = 0; + e->event.tv_sec = now.tv_sec; + e->event.tv_usec = now.tv_usec; + ipu_crtc->page_flip_event = NULL; + + imx_drm_crtc_vblank_put(ipu_crtc->imx_crtc); + + list_add_tail(&e->base.link, &e->base.file_priv->event_list); + + wake_up_interruptible(&e->base.file_priv->event_wait); + + spin_unlock_irqrestore(&drm->event_lock, flags); +} + +static irqreturn_t ipu_irq_handler(int irq, void *dev_id) +{ + struct ipu_crtc *ipu_crtc = dev_id; + + imx_drm_handle_vblank(ipu_crtc->imx_crtc); + + if (ipu_crtc->newfb) { + ipu_crtc->base.fb = ipu_crtc->newfb; + ipu_crtc->newfb = NULL; + ipu_drm_set_base(&ipu_crtc->base, 0, 0); + ipu_crtc_handle_pageflip(ipu_crtc); + } + + return IRQ_HANDLED; +} + +static bool ipu_crtc_mode_fixup(struct drm_crtc *crtc, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void ipu_crtc_prepare(struct drm_crtc *crtc) +{ + struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); + + ipu_fb_disable(ipu_crtc); +} + +static void ipu_crtc_commit(struct drm_crtc *crtc) +{ + struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); + + ipu_fb_enable(ipu_crtc); +} + +static void ipu_crtc_load_lut(struct drm_crtc *crtc) +{ +} + +static struct drm_crtc_helper_funcs ipu_helper_funcs = { + .dpms = ipu_crtc_dpms, + .mode_fixup = ipu_crtc_mode_fixup, + .mode_set = ipu_crtc_mode_set, + .prepare = ipu_crtc_prepare, + .commit = ipu_crtc_commit, + .load_lut = ipu_crtc_load_lut, +}; + +static int ipu_enable_vblank(struct drm_crtc *crtc) +{ + struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); + + enable_irq(ipu_crtc->irq); + + return 0; +} + +static void ipu_disable_vblank(struct drm_crtc *crtc) +{ + struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); + + disable_irq(ipu_crtc->irq); +} + +static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type, + u32 pixfmt) +{ + struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc); + + ipu_crtc->interface_pix_fmt = pixfmt; + + switch (encoder_type) { + case DRM_MODE_ENCODER_LVDS: + ipu_crtc->di_clkflags = IPU_DI_CLKMODE_SYNC | + IPU_DI_CLKMODE_EXT; + break; + case DRM_MODE_ENCODER_NONE: + ipu_crtc->di_clkflags = 0; + break; + } + + return 0; +} + +static const struct imx_drm_crtc_helper_funcs ipu_crtc_helper_funcs = { + .enable_vblank = ipu_enable_vblank, + .disable_vblank = ipu_disable_vblank, + .set_interface_pix_fmt = ipu_set_interface_pix_fmt, + .crtc_funcs = &ipu_crtc_funcs, + .crtc_helper_funcs = &ipu_helper_funcs, +}; + +static void ipu_put_resources(struct ipu_crtc *ipu_crtc) +{ + if (!IS_ERR_OR_NULL(ipu_crtc->ipu_ch)) + ipu_idmac_put(ipu_crtc->ipu_ch); + if (!IS_ERR_OR_NULL(ipu_crtc->dmfc)) + ipu_dmfc_put(ipu_crtc->dmfc); + if (!IS_ERR_OR_NULL(ipu_crtc->dp)) + ipu_dp_put(ipu_crtc->dp); + if (!IS_ERR_OR_NULL(ipu_crtc->di)) + ipu_di_put(ipu_crtc->di); +} + +static int ipu_get_resources(struct ipu_crtc *ipu_crtc, + struct ipu_client_platformdata *pdata) +{ + struct ipu_soc *ipu = dev_get_drvdata(ipu_crtc->dev->parent); + int ret; + + ipu_crtc->ipu_ch = ipu_idmac_get(ipu, pdata->dma[0]); + if (IS_ERR_OR_NULL(ipu_crtc->ipu_ch)) { + ret = PTR_ERR(ipu_crtc->ipu_ch); + goto err_out; + } + + ipu_crtc->dc = ipu_dc_get(ipu, pdata->dc); + if (IS_ERR(ipu_crtc->dc)) { + ret = PTR_ERR(ipu_crtc->dc); + goto err_out; + } + + ipu_crtc->dmfc = ipu_dmfc_get(ipu, pdata->dma[0]); + if (IS_ERR(ipu_crtc->dmfc)) { + ret = PTR_ERR(ipu_crtc->dmfc); + goto err_out; + } + + if (pdata->dp >= 0) { + ipu_crtc->dp = ipu_dp_get(ipu, pdata->dp); + if (IS_ERR(ipu_crtc->dp)) { + ret = PTR_ERR(ipu_crtc->ipu_ch); + goto err_out; + } + } + + ipu_crtc->di = ipu_di_get(ipu, pdata->di); + if (IS_ERR(ipu_crtc->di)) { + ret = PTR_ERR(ipu_crtc->di); + goto err_out; + } + + ipu_crtc->irq = ipu_idmac_channel_irq(ipu, ipu_crtc->ipu_ch, + IPU_IRQ_EOF); + ret = devm_request_irq(ipu_crtc->dev, ipu_crtc->irq, ipu_irq_handler, 0, + "imx_drm", ipu_crtc); + if (ret < 0) { + dev_err(ipu_crtc->dev, "irq request failed with %d.\n", ret); + goto err_out; + } + + disable_irq(ipu_crtc->irq); + + return 0; +err_out: + ipu_put_resources(ipu_crtc); + + return ret; +} + +static int ipu_crtc_init(struct ipu_crtc *ipu_crtc, + struct ipu_client_platformdata *pdata) +{ + int ret; + + ret = ipu_get_resources(ipu_crtc, pdata); + if (ret) { + dev_err(ipu_crtc->dev, "getting resources failed with %d.\n", + ret); + return ret; + } + + ret = imx_drm_add_crtc(&ipu_crtc->base, + &ipu_crtc->imx_crtc, + &ipu_crtc_helper_funcs, THIS_MODULE, + ipu_crtc->dev->parent->of_node, pdata->di); + if (ret) { + dev_err(ipu_crtc->dev, "adding crtc failed with %d.\n", ret); + goto err_put_resources; + } + + return 0; + +err_put_resources: + ipu_put_resources(ipu_crtc); + + return ret; +} + +static int __devinit ipu_drm_probe(struct platform_device *pdev) +{ + struct ipu_client_platformdata *pdata = pdev->dev.platform_data; + struct ipu_crtc *ipu_crtc; + int ret; + + if (!pdata) + return -EINVAL; + + pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32); + + ipu_crtc = devm_kzalloc(&pdev->dev, sizeof(*ipu_crtc), GFP_KERNEL); + if (!ipu_crtc) + return -ENOMEM; + + ipu_crtc->dev = &pdev->dev; + + ret = ipu_crtc_init(ipu_crtc, pdata); + + platform_set_drvdata(pdev, ipu_crtc); + + return 0; +} + +static int __devexit ipu_drm_remove(struct platform_device *pdev) +{ + struct ipu_crtc *ipu_crtc = platform_get_drvdata(pdev); + + imx_drm_remove_crtc(ipu_crtc->imx_crtc); + + ipu_put_resources(ipu_crtc); + + return 0; +} + +static struct platform_driver ipu_drm_driver = { + .driver = { + .name = "imx-ipuv3-crtc", + }, + .probe = ipu_drm_probe, + .remove = __devexit_p(ipu_drm_remove), +}; +module_platform_driver(ipu_drm_driver); + +MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>"); +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/imx-drm/parallel-display.c b/drivers/staging/imx-drm/parallel-display.c new file mode 100644 index 000000000000..9b51d732eefa --- /dev/null +++ b/drivers/staging/imx-drm/parallel-display.c @@ -0,0 +1,261 @@ +/* + * i.MX drm driver - parallel display implementation + * + * Copyright (C) 2012 Sascha Hauer, Pengutronix + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include <linux/module.h> +#include <drm/drmP.h> +#include <drm/drm_fb_helper.h> +#include <drm/drm_crtc_helper.h> +#include <linux/videodev2.h> + +#include "imx-drm.h" + +#define con_to_imxpd(x) container_of(x, struct imx_parallel_display, connector) +#define enc_to_imxpd(x) container_of(x, struct imx_parallel_display, encoder) + +struct imx_parallel_display { + struct drm_connector connector; + struct imx_drm_connector *imx_drm_connector; + struct drm_encoder encoder; + struct imx_drm_encoder *imx_drm_encoder; + struct device *dev; + void *edid; + int edid_len; + u32 interface_pix_fmt; + int mode_valid; + struct drm_display_mode mode; +}; + +static enum drm_connector_status imx_pd_connector_detect( + struct drm_connector *connector, bool force) +{ + return connector_status_connected; +} + +static void imx_pd_connector_destroy(struct drm_connector *connector) +{ + /* do not free here */ +} + +static int imx_pd_connector_get_modes(struct drm_connector *connector) +{ + struct imx_parallel_display *imxpd = con_to_imxpd(connector); + int num_modes = 0; + + if (imxpd->edid) { + drm_mode_connector_update_edid_property(connector, imxpd->edid); + num_modes = drm_add_edid_modes(connector, imxpd->edid); + } + + if (imxpd->mode_valid) { + struct drm_display_mode *mode = drm_mode_create(connector->dev); + drm_mode_copy(mode, &imxpd->mode); + mode->type |= DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED, + drm_mode_probed_add(connector, mode); + num_modes++; + } + + return num_modes; +} + +static int imx_pd_connector_mode_valid(struct drm_connector *connector, + struct drm_display_mode *mode) +{ + return 0; +} + +static struct drm_encoder *imx_pd_connector_best_encoder( + struct drm_connector *connector) +{ + struct imx_parallel_display *imxpd = con_to_imxpd(connector); + + return &imxpd->encoder; +} + +static void imx_pd_encoder_dpms(struct drm_encoder *encoder, int mode) +{ +} + +static bool imx_pd_encoder_mode_fixup(struct drm_encoder *encoder, + const struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ + return true; +} + +static void imx_pd_encoder_prepare(struct drm_encoder *encoder) +{ + struct imx_parallel_display *imxpd = enc_to_imxpd(encoder); + + imx_drm_crtc_panel_format(encoder->crtc, DRM_MODE_ENCODER_NONE, + imxpd->interface_pix_fmt); +} + +static void imx_pd_encoder_commit(struct drm_encoder *encoder) +{ +} + +static void imx_pd_encoder_mode_set(struct drm_encoder *encoder, + struct drm_display_mode *mode, + struct drm_display_mode *adjusted_mode) +{ +} + +static void imx_pd_encoder_disable(struct drm_encoder *encoder) +{ +} + +static void imx_pd_encoder_destroy(struct drm_encoder *encoder) +{ + /* do not free here */ +} + +static struct drm_connector_funcs imx_pd_connector_funcs = { + .dpms = drm_helper_connector_dpms, + .fill_modes = drm_helper_probe_single_connector_modes, + .detect = imx_pd_connector_detect, + .destroy = imx_pd_connector_destroy, +}; + +static struct drm_connector_helper_funcs imx_pd_connector_helper_funcs = { + .get_modes = imx_pd_connector_get_modes, + .best_encoder = imx_pd_connector_best_encoder, + .mode_valid = imx_pd_connector_mode_valid, +}; + +static struct drm_encoder_funcs imx_pd_encoder_funcs = { + .destroy = imx_pd_encoder_destroy, +}; + +static struct drm_encoder_helper_funcs imx_pd_encoder_helper_funcs = { + .dpms = imx_pd_encoder_dpms, + .mode_fixup = imx_pd_encoder_mode_fixup, + .prepare = imx_pd_encoder_prepare, + .commit = imx_pd_encoder_commit, + .mode_set = imx_pd_encoder_mode_set, + .disable = imx_pd_encoder_disable, +}; + +static int imx_pd_register(struct imx_parallel_display *imxpd) +{ + int ret; + + drm_mode_connector_attach_encoder(&imxpd->connector, &imxpd->encoder); + + imxpd->connector.funcs = &imx_pd_connector_funcs; + imxpd->encoder.funcs = &imx_pd_encoder_funcs; + + imxpd->encoder.encoder_type = DRM_MODE_ENCODER_NONE; + imxpd->connector.connector_type = DRM_MODE_CONNECTOR_VGA; + + drm_encoder_helper_add(&imxpd->encoder, &imx_pd_encoder_helper_funcs); + ret = imx_drm_add_encoder(&imxpd->encoder, &imxpd->imx_drm_encoder, + THIS_MODULE); + if (ret) { + dev_err(imxpd->dev, "adding encoder failed with %d\n", ret); + return ret; + } + + drm_connector_helper_add(&imxpd->connector, + &imx_pd_connector_helper_funcs); + + ret = imx_drm_add_connector(&imxpd->connector, + &imxpd->imx_drm_connector, THIS_MODULE); + if (ret) { + imx_drm_remove_encoder(imxpd->imx_drm_encoder); + dev_err(imxpd->dev, "adding connector failed with %d\n", ret); + return ret; + } + + imxpd->connector.encoder = &imxpd->encoder; + + return 0; +} + +static int __devinit imx_pd_probe(struct platform_device *pdev) +{ + struct device_node *np = pdev->dev.of_node; + const u8 *edidp; + struct imx_parallel_display *imxpd; + int ret; + const char *fmt; + + imxpd = devm_kzalloc(&pdev->dev, sizeof(*imxpd), GFP_KERNEL); + if (!imxpd) + return -ENOMEM; + + edidp = of_get_property(np, "edid", &imxpd->edid_len); + if (edidp) + imxpd->edid = kmemdup(edidp, imxpd->edid_len, GFP_KERNEL); + + ret = of_property_read_string(np, "interface-pix-fmt", &fmt); + if (!ret) { + if (!strcmp(fmt, "rgb24")) + imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB24; + else if (!strcmp(fmt, "rgb565")) + imxpd->interface_pix_fmt = V4L2_PIX_FMT_RGB565; + } + + imxpd->dev = &pdev->dev; + + ret = imx_pd_register(imxpd); + if (ret) + return ret; + + ret = imx_drm_encoder_add_possible_crtcs(imxpd->imx_drm_encoder, np); + + platform_set_drvdata(pdev, imxpd); + + return 0; +} + +static int __devexit imx_pd_remove(struct platform_device *pdev) +{ + struct imx_parallel_display *imxpd = platform_get_drvdata(pdev); + struct drm_connector *connector = &imxpd->connector; + struct drm_encoder *encoder = &imxpd->encoder; + + drm_mode_connector_detach_encoder(connector, encoder); + + imx_drm_remove_connector(imxpd->imx_drm_connector); + imx_drm_remove_encoder(imxpd->imx_drm_encoder); + + return 0; +} + +static const struct of_device_id imx_pd_dt_ids[] = { + { .compatible = "fsl,imx-parallel-display", }, + { /* sentinel */ } +}; + +static struct platform_driver imx_pd_driver = { + .probe = imx_pd_probe, + .remove = __devexit_p(imx_pd_remove), + .driver = { + .of_match_table = imx_pd_dt_ids, + .name = "imx-parallel-display", + .owner = THIS_MODULE, + }, +}; + +module_platform_driver(imx_pd_driver); + +MODULE_DESCRIPTION("i.MX parallel display driver"); +MODULE_AUTHOR("Sascha Hauer, Pengutronix"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/ipack/Kconfig b/drivers/staging/ipack/Kconfig index af321789dddb..4cf47066140c 100644 --- a/drivers/staging/ipack/Kconfig +++ b/drivers/staging/ipack/Kconfig @@ -4,6 +4,7 @@ menuconfig IPACK_BUS tristate "IndustryPack bus support" + depends on HAS_IOMEM ---help--- If you say Y here you get support for the IndustryPack Framework for drivers for many types of boards that support this industrial diff --git a/drivers/staging/ipack/TODO b/drivers/staging/ipack/TODO index b21d33ab144a..ffafe6911a77 100644 --- a/drivers/staging/ipack/TODO +++ b/drivers/staging/ipack/TODO @@ -12,29 +12,8 @@ operations between the two kind of boards. TODO ==== -TPCI-200 --------- - -* It has a linked list with the tpci200 devices it is managing. Get rid of it - and use driver_for_each_device() instead. - -IP-OCTAL --------- - -* It has a linked list which saves the devices it is currently - managing. It should use the driver_for_each_device() function. It is not there - due to the impossibility of using container_of macro to recover the - corresponding "struct ipoctal" because the attribute "struct ipack_device" is - a pointer. This code should be refactored. - -Ipack ------ - -* The structures and API exported can be improved a lot. For example, the - way to unregistering IP module devices, doing the IP module driver a call to - remove_device() to notify the carrier driver, or the opposite with the call to - the ipack_driver_ops' remove() function could be improved. - +checkpatch.pl warnings +cleanup Contact ======= diff --git a/drivers/staging/ipack/bridges/tpci200.c b/drivers/staging/ipack/bridges/tpci200.c index 2b83fa8e550a..bb8aa70281cd 100644 --- a/drivers/staging/ipack/bridges/tpci200.c +++ b/drivers/staging/ipack/bridges/tpci200.c @@ -14,38 +14,32 @@ #include <linux/module.h> #include "tpci200.h" -static struct ipack_bus_ops tpci200_bus_ops; - -/* TPCI200 controls registers */ -static int control_reg[] = { - TPCI200_CONTROL_A_REG, - TPCI200_CONTROL_B_REG, - TPCI200_CONTROL_C_REG, - TPCI200_CONTROL_D_REG +static u16 tpci200_status_timeout[] = { + TPCI200_A_TIMEOUT, + TPCI200_B_TIMEOUT, + TPCI200_C_TIMEOUT, + TPCI200_D_TIMEOUT, }; -/* Linked list to save the registered devices */ -static LIST_HEAD(tpci200_list); - -static int tpci200_slot_unregister(struct ipack_device *dev); +static u16 tpci200_status_error[] = { + TPCI200_A_ERROR, + TPCI200_B_ERROR, + TPCI200_C_ERROR, + TPCI200_D_ERROR, +}; static struct tpci200_board *check_slot(struct ipack_device *dev) { struct tpci200_board *tpci200; - int found = 0; if (dev == NULL) return NULL; - list_for_each_entry(tpci200, &tpci200_list, list) { - if (tpci200->number == dev->bus_nr) { - found = 1; - break; - } - } - if (!found) { - dev_err(&dev->dev, "Carrier not found\n"); + tpci200 = dev_get_drvdata(dev->bus->parent); + + if (tpci200 == NULL) { + dev_info(&dev->dev, "carrier board not found\n"); return NULL; } @@ -59,296 +53,190 @@ static struct tpci200_board *check_slot(struct ipack_device *dev) return tpci200; } -static inline unsigned char __tpci200_read8(void __iomem *address, - unsigned long offset) -{ - return ioread8(address + (offset^1)); -} - -static inline unsigned short __tpci200_read16(void __iomem *address, - unsigned long offset) +static void tpci200_clear_mask(struct tpci200_board *tpci200, + __le16 __iomem *addr, u16 mask) { - return ioread16(address + offset); + unsigned long flags; + spin_lock_irqsave(&tpci200->regs_lock, flags); + iowrite16(ioread16(addr) & (~mask), addr); + spin_unlock_irqrestore(&tpci200->regs_lock, flags); } -static inline unsigned int __tpci200_read32(void __iomem *address, - unsigned long offset) +static void tpci200_set_mask(struct tpci200_board *tpci200, + __le16 __iomem *addr, u16 mask) { - return swahw32(ioread32(address + offset)); + unsigned long flags; + spin_lock_irqsave(&tpci200->regs_lock, flags); + iowrite16(ioread16(addr) | mask, addr); + spin_unlock_irqrestore(&tpci200->regs_lock, flags); } -static inline void __tpci200_write8(unsigned char value, - void __iomem *address, unsigned long offset) +static void tpci200_unregister(struct tpci200_board *tpci200) { - iowrite8(value, address+(offset^1)); -} + int i; -static inline void __tpci200_write16(unsigned short value, - void __iomem *address, - unsigned long offset) -{ - iowrite16(value, address+offset); -} + free_irq(tpci200->info->pdev->irq, (void *) tpci200); -static inline void __tpci200_write32(unsigned int value, - void __iomem *address, - unsigned long offset) -{ - iowrite32(swahw32(value), address+offset); -} + pci_iounmap(tpci200->info->pdev, tpci200->info->interface_regs); + pci_iounmap(tpci200->info->pdev, tpci200->info->ioidint_space); + pci_iounmap(tpci200->info->pdev, tpci200->info->mem8_space); + pci_iounmap(tpci200->info->pdev, tpci200->info->cfg_regs); -static struct ipack_addr_space *get_slot_address_space(struct ipack_device *dev, - int space) -{ - struct ipack_addr_space *addr; + pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR); + pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR); + pci_release_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR); + pci_release_region(tpci200->info->pdev, TPCI200_CFG_MEM_BAR); - switch (space) { - case IPACK_IO_SPACE: - addr = &dev->io_space; - break; - case IPACK_ID_SPACE: - addr = &dev->id_space; - break; - case IPACK_MEM_SPACE: - addr = &dev->mem_space; - break; - default: - dev_err(&dev->dev, - "Slot [%d:%d] space number %d doesn't exist !\n", - dev->bus_nr, dev->slot, space); - return NULL; - break; - } + pci_disable_device(tpci200->info->pdev); + pci_dev_put(tpci200->info->pdev); - if ((addr->size == 0) || (addr->address == NULL)) { - dev_err(&dev->dev, "Error, slot space not mapped !\n"); - return NULL; + for (i = 0; i < TPCI200_NB_SLOT; i++) { + tpci200->slots[i].io_phys.address = NULL; + tpci200->slots[i].io_phys.size = 0; + tpci200->slots[i].id_phys.address = NULL; + tpci200->slots[i].id_phys.size = 0; + tpci200->slots[i].int_phys.address = NULL; + tpci200->slots[i].int_phys.size = 0; + tpci200->slots[i].mem_phys.address = NULL; + tpci200->slots[i].mem_phys.size = 0; } - - return addr; } -static int tpci200_read8(struct ipack_device *dev, int space, - unsigned long offset, unsigned char *value) +static void tpci200_enable_irq(struct tpci200_board *tpci200, + int islot) { - struct ipack_addr_space *addr; - struct tpci200_board *tpci200; - - tpci200 = check_slot(dev); - if (tpci200 == NULL) - return -EINVAL; - - addr = get_slot_address_space(dev, space); - if (addr == NULL) - return -EINVAL; - - if (offset >= addr->size) { - dev_err(&dev->dev, "Error, slot space offset error !\n"); - return -EFAULT; - } - - *value = __tpci200_read8(addr->address, offset); - - return 0; + tpci200_set_mask(tpci200, + &tpci200->info->interface_regs->control[islot], + TPCI200_INT0_EN | TPCI200_INT1_EN); } -static int tpci200_read16(struct ipack_device *dev, int space, - unsigned long offset, unsigned short *value) +static void tpci200_disable_irq(struct tpci200_board *tpci200, + int islot) { - struct ipack_addr_space *addr; - struct tpci200_board *tpci200; - - tpci200 = check_slot(dev); - if (tpci200 == NULL) - return -EINVAL; - - addr = get_slot_address_space(dev, space); - if (addr == NULL) - return -EINVAL; - - if ((offset+2) >= addr->size) { - dev_err(&dev->dev, "Error, slot space offset error !\n"); - return -EFAULT; - } - *value = __tpci200_read16(addr->address, offset); - - return 0; + tpci200_clear_mask(tpci200, + &tpci200->info->interface_regs->control[islot], + TPCI200_INT0_EN | TPCI200_INT1_EN); } -static int tpci200_read32(struct ipack_device *dev, int space, - unsigned long offset, unsigned int *value) +static irqreturn_t tpci200_slot_irq(struct slot_irq *slot_irq) { - struct ipack_addr_space *addr; - struct tpci200_board *tpci200; - - tpci200 = check_slot(dev); - if (tpci200 == NULL) - return -EINVAL; - - addr = get_slot_address_space(dev, space); - if (addr == NULL) - return -EINVAL; + irqreturn_t ret; - if ((offset+4) >= addr->size) { - dev_err(&dev->dev, "Error, slot space offset error !\n"); - return -EFAULT; - } - - *value = __tpci200_read32(addr->address, offset); + if (!slot_irq) + return -ENODEV; + ret = slot_irq->handler(slot_irq->arg); - return 0; + return ret; } -static int tpci200_write8(struct ipack_device *dev, int space, - unsigned long offset, unsigned char value) +static irqreturn_t tpci200_interrupt(int irq, void *dev_id) { - struct ipack_addr_space *addr; - struct tpci200_board *tpci200; + struct tpci200_board *tpci200 = (struct tpci200_board *) dev_id; + struct slot_irq *slot_irq; + irqreturn_t ret; + u16 status_reg; + int i; - tpci200 = check_slot(dev); - if (tpci200 == NULL) - return -EINVAL; + /* Read status register */ + status_reg = ioread16(&tpci200->info->interface_regs->status); - addr = get_slot_address_space(dev, space); - if (addr == NULL) - return -EINVAL; + /* Did we cause the interrupt? */ + if (!(status_reg & TPCI200_SLOT_INT_MASK)) + return IRQ_NONE; - if (offset >= addr->size) { - dev_err(&dev->dev, "Error, slot space offset error !\n"); - return -EFAULT; + /* callback to the IRQ handler for the corresponding slot */ + rcu_read_lock(); + for (i = 0; i < TPCI200_NB_SLOT; i++) { + if (!(status_reg & ((TPCI200_A_INT0 | TPCI200_A_INT1) << (2 * i)))) + continue; + slot_irq = rcu_dereference(tpci200->slots[i].irq); + ret = tpci200_slot_irq(slot_irq); + if (ret == -ENODEV) { + dev_info(&tpci200->info->pdev->dev, + "No registered ISR for slot [%d:%d]!. IRQ will be disabled.\n", + tpci200->number, i); + tpci200_disable_irq(tpci200, i); + } } + rcu_read_unlock(); - __tpci200_write8(value, addr->address, offset); - - return 0; + return IRQ_HANDLED; } -static int tpci200_write16(struct ipack_device *dev, int space, - unsigned long offset, unsigned short value) +static int tpci200_free_irq(struct ipack_device *dev) { - struct ipack_addr_space *addr; + struct slot_irq *slot_irq; struct tpci200_board *tpci200; tpci200 = check_slot(dev); if (tpci200 == NULL) return -EINVAL; - addr = get_slot_address_space(dev, space); - if (addr == NULL) - return -EINVAL; + if (mutex_lock_interruptible(&tpci200->mutex)) + return -ERESTARTSYS; - if ((offset+2) >= addr->size) { - dev_err(&dev->dev, "Error, slot space offset error !\n"); - return -EFAULT; + if (tpci200->slots[dev->slot].irq == NULL) { + mutex_unlock(&tpci200->mutex); + return -EINVAL; } - __tpci200_write16(value, addr->address, offset); - + tpci200_disable_irq(tpci200, dev->slot); + slot_irq = tpci200->slots[dev->slot].irq; + /* uninstall handler */ + RCU_INIT_POINTER(tpci200->slots[dev->slot].irq, NULL); + synchronize_rcu(); + kfree(slot_irq); + mutex_unlock(&tpci200->mutex); return 0; } -static int tpci200_write32(struct ipack_device *dev, int space, - unsigned long offset, unsigned int value) +static int tpci200_request_irq(struct ipack_device *dev, + irqreturn_t (*handler)(void *), void *arg) { - struct ipack_addr_space *addr; + int res = 0; + struct slot_irq *slot_irq; struct tpci200_board *tpci200; tpci200 = check_slot(dev); if (tpci200 == NULL) return -EINVAL; - addr = get_slot_address_space(dev, space); - if (addr == NULL) - return -EINVAL; + if (mutex_lock_interruptible(&tpci200->mutex)) + return -ERESTARTSYS; - if ((offset+4) >= addr->size) { - dev_err(&dev->dev, "Error, slot space offset error !\n"); - return -EFAULT; + if (tpci200->slots[dev->slot].irq != NULL) { + dev_err(&dev->dev, + "Slot [%d:%d] IRQ already registered !\n", dev->bus_nr, + dev->slot); + res = -EINVAL; + goto out_unlock; } - __tpci200_write32(value, addr->address, offset); - - return 0; -} - -static void tpci200_unregister(struct tpci200_board *tpci200) -{ - int i; - - free_irq(tpci200->info->pdev->irq, (void *) tpci200); - - pci_iounmap(tpci200->info->pdev, tpci200->info->interface_regs); - pci_iounmap(tpci200->info->pdev, tpci200->info->ioidint_space); - pci_iounmap(tpci200->info->pdev, tpci200->info->mem8_space); - - pci_release_region(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR); - pci_release_region(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR); - pci_release_region(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR); - - pci_disable_device(tpci200->info->pdev); - pci_dev_put(tpci200->info->pdev); - - for (i = 0; i < TPCI200_NB_SLOT; i++) { - tpci200->slots[i].io_phys.address = NULL; - tpci200->slots[i].io_phys.size = 0; - tpci200->slots[i].id_phys.address = NULL; - tpci200->slots[i].id_phys.size = 0; - tpci200->slots[i].mem_phys.address = NULL; - tpci200->slots[i].mem_phys.size = 0; + slot_irq = kzalloc(sizeof(struct slot_irq), GFP_KERNEL); + if (slot_irq == NULL) { + dev_err(&dev->dev, + "Slot [%d:%d] unable to allocate memory for IRQ !\n", + dev->bus_nr, dev->slot); + res = -ENOMEM; + goto out_unlock; } -} -static irqreturn_t tpci200_interrupt(int irq, void *dev_id) -{ - struct tpci200_board *tpci200 = (struct tpci200_board *) dev_id; - int i; - unsigned short status_reg, reg_value; - unsigned short unhandled_ints = 0; - irqreturn_t ret = IRQ_NONE; + /* + * WARNING: Setup Interrupt Vector in the IndustryPack device + * before an IRQ request. + * Read the User Manual of your IndustryPack device to know + * where to write the vector in memory. + */ + slot_irq->handler = handler; + slot_irq->arg = arg; + slot_irq->holder = dev; - /* Read status register */ - status_reg = readw(tpci200->info->interface_regs + - TPCI200_STATUS_REG); - - if (status_reg & TPCI200_SLOT_INT_MASK) { - unhandled_ints = status_reg & TPCI200_SLOT_INT_MASK; - /* callback to the IRQ handler for the corresponding slot */ - for (i = 0; i < TPCI200_NB_SLOT; i++) { - if ((tpci200->slots[i].irq != NULL) && - (status_reg & ((TPCI200_A_INT0 | TPCI200_A_INT1) << (2*i)))) { - - ret = tpci200->slots[i].irq->handler(tpci200->slots[i].irq->arg); - - /* Dummy reads */ - readw(tpci200->slots[i].dev->io_space.address + - 0xC0); - readw(tpci200->slots[i].dev->io_space.address + - 0xC2); - - unhandled_ints &= ~(((TPCI200_A_INT0 | TPCI200_A_INT1) << (2*i))); - } - } - } - /* Interrupt not handled are disabled */ - if (unhandled_ints) { - for (i = 0; i < TPCI200_NB_SLOT; i++) { - if (unhandled_ints & ((TPCI200_INT0_EN | TPCI200_INT1_EN) << (2*i))) { - dev_info(&tpci200->slots[i].dev->dev, - "No registered ISR for slot [%d:%d]!. IRQ will be disabled.\n", - tpci200->number, i); - reg_value = readw( - tpci200->info->interface_regs + - control_reg[i]); - reg_value &= - ~(TPCI200_INT0_EN | TPCI200_INT1_EN); - writew(reg_value, - (tpci200->info->interface_regs + - control_reg[i])); - } - } - } + rcu_assign_pointer(tpci200->slots[dev->slot].irq, slot_irq); + tpci200_enable_irq(tpci200, dev->slot); - return ret; +out_unlock: + mutex_unlock(&tpci200->mutex); + return res; } static int tpci200_register(struct tpci200_board *tpci200) @@ -398,18 +286,21 @@ static int tpci200_register(struct tpci200_board *tpci200) /* Map internal tpci200 driver user space */ tpci200->info->interface_regs = - ioremap(pci_resource_start(tpci200->info->pdev, + ioremap_nocache(pci_resource_start(tpci200->info->pdev, TPCI200_IP_INTERFACE_BAR), TPCI200_IFACE_SIZE); tpci200->info->ioidint_space = - ioremap(pci_resource_start(tpci200->info->pdev, + ioremap_nocache(pci_resource_start(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR), TPCI200_IOIDINT_SIZE); tpci200->info->mem8_space = - ioremap(pci_resource_start(tpci200->info->pdev, + ioremap_nocache(pci_resource_start(tpci200->info->pdev, TPCI200_MEM8_SPACE_BAR), TPCI200_MEM8_SIZE); + /* Initialize lock that protects interface_regs */ + spin_lock_init(&tpci200->regs_lock); + ioidint_base = pci_resource_start(tpci200->info->pdev, TPCI200_IO_ID_INT_SPACES_BAR); mem_base = pci_resource_start(tpci200->info->pdev, @@ -437,12 +328,16 @@ static int tpci200_register(struct tpci200_board *tpci200) TPCI200_ID_SPACE_OFF + TPCI200_ID_SPACE_GAP*i; tpci200->slots[i].id_phys.size = TPCI200_ID_SPACE_SIZE; + tpci200->slots[i].int_phys.address = + (void __iomem *)ioidint_base + + TPCI200_INT_SPACE_OFF + TPCI200_INT_SPACE_GAP * i; + tpci200->slots[i].int_phys.size = TPCI200_INT_SPACE_SIZE; + tpci200->slots[i].mem_phys.address = (void __iomem *)mem_base + TPCI200_MEM8_GAP*i; tpci200->slots[i].mem_phys.size = TPCI200_MEM8_SIZE; - writew(slot_ctrl, (tpci200->info->interface_regs + - control_reg[i])); + writew(slot_ctrl, &tpci200->info->interface_regs->control[i]); } res = request_irq(tpci200->info->pdev->irq, @@ -467,70 +362,6 @@ out_disable_pci: return res; } -static int __tpci200_request_irq(struct tpci200_board *tpci200, - struct ipack_device *dev) -{ - unsigned short slot_ctrl; - - /* Set the default parameters of the slot - * INT0 enabled, level sensitive - * INT1 enabled, level sensitive - * error interrupt disabled - * timeout interrupt disabled - * recover time disabled - * clock rate 8 MHz - */ - slot_ctrl = TPCI200_INT0_EN | TPCI200_INT1_EN; - writew(slot_ctrl, (tpci200->info->interface_regs + - control_reg[dev->slot])); - - return 0; -} - -static void __tpci200_free_irq(struct tpci200_board *tpci200, - struct ipack_device *dev) -{ - unsigned short slot_ctrl; - - /* Set the default parameters of the slot - * INT0 disabled, level sensitive - * INT1 disabled, level sensitive - * error interrupt disabled - * timeout interrupt disabled - * recover time disabled - * clock rate 8 MHz - */ - slot_ctrl = 0; - writew(slot_ctrl, (tpci200->info->interface_regs + - control_reg[dev->slot])); -} - -static int tpci200_free_irq(struct ipack_device *dev) -{ - struct slot_irq *slot_irq; - struct tpci200_board *tpci200; - - tpci200 = check_slot(dev); - if (tpci200 == NULL) - return -EINVAL; - - if (mutex_lock_interruptible(&tpci200->mutex)) - return -ERESTARTSYS; - - if (tpci200->slots[dev->slot].irq == NULL) { - mutex_unlock(&tpci200->mutex); - return -EINVAL; - } - - __tpci200_free_irq(tpci200, dev); - slot_irq = tpci200->slots[dev->slot].irq; - tpci200->slots[dev->slot].irq = NULL; - kfree(slot_irq); - - mutex_unlock(&tpci200->mutex); - return 0; -} - static int tpci200_slot_unmap_space(struct ipack_device *dev, int space) { struct ipack_addr_space *virt_addr_space; @@ -562,6 +393,15 @@ static int tpci200_slot_unmap_space(struct ipack_device *dev, int space) } virt_addr_space = &dev->id_space; break; + case IPACK_INT_SPACE: + if (dev->int_space.address == NULL) { + dev_info(&dev->dev, + "Slot [%d:%d] INT space not mapped !\n", + dev->bus_nr, dev->slot); + goto out_unlock; + } + virt_addr_space = &dev->int_space; + break; case IPACK_MEM_SPACE: if (dev->mem_space.address == NULL) { dev_info(&dev->dev, @@ -588,29 +428,6 @@ out_unlock: return 0; } -static int tpci200_slot_unregister(struct ipack_device *dev) -{ - struct tpci200_board *tpci200; - - if (dev == NULL) - return -ENODEV; - - tpci200 = check_slot(dev); - if (tpci200 == NULL) - return -EINVAL; - - tpci200_free_irq(dev); - - if (mutex_lock_interruptible(&tpci200->mutex)) - return -ERESTARTSYS; - - ipack_device_unregister(dev); - tpci200->slots[dev->slot].dev = NULL; - mutex_unlock(&tpci200->mutex); - - return 0; -} - static int tpci200_slot_map_space(struct ipack_device *dev, unsigned int memory_size, int space) { @@ -654,6 +471,19 @@ static int tpci200_slot_map_space(struct ipack_device *dev, phys_address = tpci200->slots[dev->slot].id_phys.address; size_to_map = tpci200->slots[dev->slot].id_phys.size; break; + case IPACK_INT_SPACE: + if (dev->int_space.address != NULL) { + dev_err(&dev->dev, + "Slot [%d:%d] INT space already mapped !\n", + tpci200->number, dev->slot); + res = -EINVAL; + goto out_unlock; + } + virt_addr_space = &dev->int_space; + + phys_address = tpci200->slots[dev->slot].int_phys.address; + size_to_map = tpci200->slots[dev->slot].int_phys.size; + break; case IPACK_MEM_SPACE: if (dev->mem_space.address != NULL) { dev_err(&dev->dev, @@ -685,85 +515,109 @@ static int tpci200_slot_map_space(struct ipack_device *dev, virt_addr_space->size = size_to_map; virt_addr_space->address = - ioremap((unsigned long)phys_address, size_to_map); + ioremap_nocache((unsigned long)phys_address, size_to_map); out_unlock: mutex_unlock(&tpci200->mutex); return res; } -static int tpci200_request_irq(struct ipack_device *dev, int vector, - int (*handler)(void *), void *arg) +static int tpci200_get_clockrate(struct ipack_device *dev) { - int res; - struct slot_irq *slot_irq; - struct tpci200_board *tpci200; + struct tpci200_board *tpci200 = check_slot(dev); + __le16 __iomem *addr; - tpci200 = check_slot(dev); - if (tpci200 == NULL) - return -EINVAL; + if (!tpci200) + return -ENODEV; - if (mutex_lock_interruptible(&tpci200->mutex)) - return -ERESTARTSYS; + addr = &tpci200->info->interface_regs->control[dev->slot]; + return (ioread16(addr) & TPCI200_CLK32) ? 32 : 8; +} - if (tpci200->slots[dev->slot].irq != NULL) { - dev_err(&dev->dev, - "Slot [%d:%d] IRQ already registered !\n", dev->bus_nr, - dev->slot); - res = -EINVAL; - goto out_unlock; - } +static int tpci200_set_clockrate(struct ipack_device *dev, int mherz) +{ + struct tpci200_board *tpci200 = check_slot(dev); + __le16 __iomem *addr; - slot_irq = kzalloc(sizeof(struct slot_irq), GFP_KERNEL); - if (slot_irq == NULL) { - dev_err(&dev->dev, - "Slot [%d:%d] unable to allocate memory for IRQ !\n", - dev->bus_nr, dev->slot); - res = -ENOMEM; - goto out_unlock; + if (!tpci200) + return -ENODEV; + + addr = &tpci200->info->interface_regs->control[dev->slot]; + + switch (mherz) { + case 8: + tpci200_clear_mask(tpci200, addr, TPCI200_CLK32); + break; + case 32: + tpci200_set_mask(tpci200, addr, TPCI200_CLK32); + break; + default: + return -EINVAL; } + return 0; +} - /* - * WARNING: Setup Interrupt Vector in the IndustryPack device - * before an IRQ request. - * Read the User Manual of your IndustryPack device to know - * where to write the vector in memory. - */ - slot_irq->vector = vector; - slot_irq->handler = handler; - slot_irq->arg = arg; +static int tpci200_get_error(struct ipack_device *dev) +{ + struct tpci200_board *tpci200 = check_slot(dev); + __le16 __iomem *addr; + u16 mask; - tpci200->slots[dev->slot].irq = slot_irq; - res = __tpci200_request_irq(tpci200, dev); + if (!tpci200) + return -ENODEV; -out_unlock: - mutex_unlock(&tpci200->mutex); - return res; + addr = &tpci200->info->interface_regs->status; + mask = tpci200_status_error[dev->slot]; + return (ioread16(addr) & mask) ? 1 : 0; } -static void tpci200_uninstall(struct tpci200_board *tpci200) +static int tpci200_get_timeout(struct ipack_device *dev) { - int i; + struct tpci200_board *tpci200 = check_slot(dev); + __le16 __iomem *addr; + u16 mask; - for (i = 0; i < TPCI200_NB_SLOT; i++) - tpci200_slot_unregister(tpci200->slots[i].dev); + if (!tpci200) + return -ENODEV; + + addr = &tpci200->info->interface_regs->status; + mask = tpci200_status_timeout[dev->slot]; + + return (ioread16(addr) & mask) ? 1 : 0; +} + +static int tpci200_reset_timeout(struct ipack_device *dev) +{ + struct tpci200_board *tpci200 = check_slot(dev); + __le16 __iomem *addr; + u16 mask; + + if (!tpci200) + return -ENODEV; + + addr = &tpci200->info->interface_regs->status; + mask = tpci200_status_timeout[dev->slot]; + iowrite16(mask, addr); + return 0; +} + +static void tpci200_uninstall(struct tpci200_board *tpci200) +{ tpci200_unregister(tpci200); kfree(tpci200->slots); } -static struct ipack_bus_ops tpci200_bus_ops = { +static const struct ipack_bus_ops tpci200_bus_ops = { .map_space = tpci200_slot_map_space, .unmap_space = tpci200_slot_unmap_space, .request_irq = tpci200_request_irq, .free_irq = tpci200_free_irq, - .read8 = tpci200_read8, - .read16 = tpci200_read16, - .read32 = tpci200_read32, - .write8 = tpci200_write8, - .write16 = tpci200_write16, - .write32 = tpci200_write32, - .remove_device = tpci200_slot_unregister, + .get_clockrate = tpci200_get_clockrate, + .set_clockrate = tpci200_set_clockrate, + .get_error = tpci200_get_error, + .get_timeout = tpci200_get_timeout, + .reset_timeout = tpci200_reset_timeout, }; static int tpci200_install(struct tpci200_board *tpci200) @@ -786,11 +640,12 @@ static int tpci200_install(struct tpci200_board *tpci200) return 0; } -static int tpci200_pciprobe(struct pci_dev *pdev, - const struct pci_device_id *id) +static int tpci200_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *id) { int ret, i; struct tpci200_board *tpci200; + u32 reg32; tpci200 = kzalloc(sizeof(struct tpci200_board), GFP_KERNEL); if (!tpci200) @@ -798,10 +653,40 @@ static int tpci200_pciprobe(struct pci_dev *pdev, tpci200->info = kzalloc(sizeof(struct tpci200_infos), GFP_KERNEL); if (!tpci200->info) { - kfree(tpci200); - return -ENOMEM; + ret = -ENOMEM; + goto out_err_info; } + pci_dev_get(pdev); + + /* Obtain a mapping of the carrier's PCI configuration registers */ + ret = pci_request_region(pdev, TPCI200_CFG_MEM_BAR, + KBUILD_MODNAME " Configuration Memory"); + if (ret) { + dev_err(&pdev->dev, "Failed to allocate PCI Configuration Memory"); + ret = -EBUSY; + goto out_err_pci_request; + } + tpci200->info->cfg_regs = ioremap_nocache( + pci_resource_start(pdev, TPCI200_CFG_MEM_BAR), + pci_resource_len(pdev, TPCI200_CFG_MEM_BAR)); + if (!tpci200->info->cfg_regs) { + dev_err(&pdev->dev, "Failed to map PCI Configuration Memory"); + ret = -EFAULT; + goto out_err_ioremap; + } + + /* Disable byte swapping for 16 bit IP module access. This will ensure + * that the Industrypack big endian byte order is preserved by the + * carrier. */ + reg32 = ioread32(tpci200->info->cfg_regs + LAS1_DESC); + reg32 |= 1 << LAS_BIT_BIGENDIAN; + iowrite32(reg32, tpci200->info->cfg_regs + LAS1_DESC); + + reg32 = ioread32(tpci200->info->cfg_regs + LAS2_DESC); + reg32 |= 1 << LAS_BIT_BIGENDIAN; + iowrite32(reg32, tpci200->info->cfg_regs + LAS2_DESC); + /* Save struct pci_dev pointer */ tpci200->info->pdev = pdev; tpci200->info->id_table = (struct pci_device_id *)id; @@ -809,10 +694,9 @@ static int tpci200_pciprobe(struct pci_dev *pdev, /* register the device and initialize it */ ret = tpci200_install(tpci200); if (ret) { - dev_err(&pdev->dev, "Error during tpci200 install !\n"); - kfree(tpci200->info); - kfree(tpci200); - return -ENODEV; + dev_err(&pdev->dev, "error during tpci200 install\n"); + ret = -ENODEV; + goto out_err_install; } /* Register the carrier in the industry pack bus driver */ @@ -822,48 +706,46 @@ static int tpci200_pciprobe(struct pci_dev *pdev, if (!tpci200->info->ipack_bus) { dev_err(&pdev->dev, "error registering the carrier on ipack driver\n"); - tpci200_uninstall(tpci200); - kfree(tpci200->info); - kfree(tpci200); - return -EFAULT; + ret = -EFAULT; + goto out_err_bus_register; } /* save the bus number given by ipack to logging purpose */ tpci200->number = tpci200->info->ipack_bus->bus_nr; dev_set_drvdata(&pdev->dev, tpci200); - /* add the registered device in an internal linked list */ - list_add_tail(&tpci200->list, &tpci200_list); - /* - * Give the same IRQ number as the slot number. - * The TPCI200 has assigned his own two IRQ by PCI bus driver - */ for (i = 0; i < TPCI200_NB_SLOT; i++) - tpci200->slots[i].dev = - ipack_device_register(tpci200->info->ipack_bus, i, i); + ipack_device_register(tpci200->info->ipack_bus, i); + return 0; + +out_err_bus_register: + tpci200_uninstall(tpci200); +out_err_install: + iounmap(tpci200->info->cfg_regs); +out_err_ioremap: + pci_release_region(pdev, TPCI200_CFG_MEM_BAR); +out_err_pci_request: + pci_dev_put(pdev); + kfree(tpci200->info); +out_err_info: + kfree(tpci200); return ret; } static void __tpci200_pci_remove(struct tpci200_board *tpci200) { - tpci200_uninstall(tpci200); - list_del(&tpci200->list); ipack_bus_unregister(tpci200->info->ipack_bus); + tpci200_uninstall(tpci200); + kfree(tpci200->info); kfree(tpci200); } static void __devexit tpci200_pci_remove(struct pci_dev *dev) { - struct tpci200_board *tpci200, *next; + struct tpci200_board *tpci200 = pci_get_drvdata(dev); - /* Search the registered device to uninstall it */ - list_for_each_entry_safe(tpci200, next, &tpci200_list, list) { - if (tpci200->info->pdev == dev) { - __tpci200_pci_remove(tpci200); - break; - } - } + __tpci200_pci_remove(tpci200); } static DEFINE_PCI_DEVICE_TABLE(tpci200_idtable) = { @@ -877,7 +759,7 @@ MODULE_DEVICE_TABLE(pci, tpci200_idtable); static struct pci_driver tpci200_pci_drv = { .name = "tpci200", .id_table = tpci200_idtable, - .probe = tpci200_pciprobe, + .probe = tpci200_pci_probe, .remove = __devexit_p(tpci200_pci_remove), }; @@ -888,11 +770,6 @@ static int __init tpci200_drvr_init_module(void) static void __exit tpci200_drvr_exit_module(void) { - struct tpci200_board *tpci200, *next; - - list_for_each_entry_safe(tpci200, next, &tpci200_list, list) - __tpci200_pci_remove(tpci200); - pci_unregister_driver(&tpci200_pci_drv); } diff --git a/drivers/staging/ipack/bridges/tpci200.h b/drivers/staging/ipack/bridges/tpci200.h index d04510a89be4..235d1fe4f48c 100644 --- a/drivers/staging/ipack/bridges/tpci200.h +++ b/drivers/staging/ipack/bridges/tpci200.h @@ -17,7 +17,6 @@ #include <linux/limits.h> #include <linux/pci.h> #include <linux/spinlock.h> -#include <linux/interrupt.h> #include <linux/swab.h> #include <linux/io.h> @@ -31,18 +30,21 @@ #define TPCI200_SUBVENDOR_ID 0x1498 #define TPCI200_SUBDEVICE_ID 0x300A +#define TPCI200_CFG_MEM_BAR 0 #define TPCI200_IP_INTERFACE_BAR 2 #define TPCI200_IO_ID_INT_SPACES_BAR 3 #define TPCI200_MEM16_SPACE_BAR 4 #define TPCI200_MEM8_SPACE_BAR 5 -#define TPCI200_REVISION_REG 0x00 -#define TPCI200_CONTROL_A_REG 0x02 -#define TPCI200_CONTROL_B_REG 0x04 -#define TPCI200_CONTROL_C_REG 0x06 -#define TPCI200_CONTROL_D_REG 0x08 -#define TPCI200_RESET_REG 0x0A -#define TPCI200_STATUS_REG 0x0C +struct tpci200_regs { + __le16 revision; + /* writes to control should occur with the mutex held to protect + * read-modify-write operations */ + __le16 control[4]; + __le16 reset; + __le16 status; + u8 reserved[242]; +} __packed; #define TPCI200_IFACE_SIZE 0x100 @@ -62,6 +64,7 @@ #define TPCI200_MEM16_GAP 0x00800000 #define TPCI200_MEM16_SIZE 0x00800000 +/* control field in tpci200_regs */ #define TPCI200_INT0_EN 0x0040 #define TPCI200_INT1_EN 0x0080 #define TPCI200_INT0_EDGE 0x0010 @@ -71,11 +74,13 @@ #define TPCI200_RECOVER_EN 0x0002 #define TPCI200_CLK32 0x0001 +/* reset field in tpci200_regs */ #define TPCI200_A_RESET 0x0001 #define TPCI200_B_RESET 0x0002 #define TPCI200_C_RESET 0x0004 #define TPCI200_D_RESET 0x0008 +/* status field in tpci200_regs */ #define TPCI200_A_TIMEOUT 0x1000 #define TPCI200_B_TIMEOUT 0x2000 #define TPCI200_C_TIMEOUT 0x4000 @@ -97,6 +102,13 @@ #define TPCI200_SLOT_INT_MASK 0x00FF +/* PCI Configuration registers. The PCI bridge is a PLX Technology PCI9030. */ +#define LAS1_DESC 0x2C +#define LAS2_DESC 0x30 + +/* Bits in the LAS?_DESC registers */ +#define LAS_BIT_BIGENDIAN 24 + #define VME_IOID_SPACE "IOID" #define VME_MEM_SPACE "MEM" @@ -108,8 +120,9 @@ * */ struct slot_irq { + struct ipack_device *holder; int vector; - int (*handler)(void *); + irqreturn_t (*handler)(void *); void *arg; }; @@ -119,14 +132,15 @@ struct slot_irq { * @irq Slot IRQ infos * @io_phys IO physical base address register of the slot * @id_phys ID physical base address register of the slot + * @int_phys INT physical base address register of the slot * @mem_phys MEM physical base address register of the slot * */ struct tpci200_slot { - struct ipack_device *dev; struct slot_irq *irq; struct ipack_addr_space io_phys; struct ipack_addr_space id_phys; + struct ipack_addr_space int_phys; struct ipack_addr_space mem_phys; }; @@ -141,15 +155,16 @@ struct tpci200_slot { struct tpci200_infos { struct pci_dev *pdev; struct pci_device_id *id_table; - void __iomem *interface_regs; + struct tpci200_regs __iomem *interface_regs; void __iomem *ioidint_space; void __iomem *mem8_space; + void __iomem *cfg_regs; struct ipack_bus_device *ipack_bus; }; struct tpci200_board { - struct list_head list; unsigned int number; struct mutex mutex; + spinlock_t regs_lock; struct tpci200_slot *slots; struct tpci200_infos *info; }; diff --git a/drivers/staging/ipack/devices/ipoctal.c b/drivers/staging/ipack/devices/ipoctal.c index fd0e30132ca2..2cdbf280cdab 100644 --- a/drivers/staging/ipack/devices/ipoctal.c +++ b/drivers/staging/ipack/devices/ipoctal.c @@ -20,127 +20,68 @@ #include <linux/tty_flip.h> #include <linux/slab.h> #include <linux/atomic.h> +#include <linux/io.h> #include "../ipack.h" #include "ipoctal.h" #include "scc2698.h" -#define IP_OCTAL_MANUFACTURER_ID 0xF0 -#define IP_OCTAL_232_ID 0x22 -#define IP_OCTAL_422_ID 0x2A -#define IP_OCTAL_485_ID 0x48 - #define IP_OCTAL_ID_SPACE_VECTOR 0x41 #define IP_OCTAL_NB_BLOCKS 4 -static struct ipack_driver driver; static const struct tty_operations ipoctal_fops; +struct ipoctal_channel { + struct ipoctal_stats stats; + unsigned int nb_bytes; + wait_queue_head_t queue; + spinlock_t lock; + unsigned int pointer_read; + unsigned int pointer_write; + atomic_t open; + struct tty_port tty_port; + union scc2698_channel __iomem *regs; + union scc2698_block __iomem *block_regs; + unsigned int board_id; + unsigned char *board_write; + u8 isr_rx_rdy_mask; + u8 isr_tx_rdy_mask; +}; + struct ipoctal { - struct list_head list; struct ipack_device *dev; unsigned int board_id; - struct scc2698_channel *chan_regs; - struct scc2698_block *block_regs; - struct ipoctal_stats chan_stats[NR_CHANNELS]; - unsigned int nb_bytes[NR_CHANNELS]; - unsigned int count_wr[NR_CHANNELS]; - wait_queue_head_t queue[NR_CHANNELS]; - spinlock_t lock[NR_CHANNELS]; - unsigned int pointer_read[NR_CHANNELS]; - unsigned int pointer_write[NR_CHANNELS]; - atomic_t open[NR_CHANNELS]; + struct ipoctal_channel channel[NR_CHANNELS]; unsigned char write; - struct tty_port tty_port[NR_CHANNELS]; struct tty_driver *tty_drv; }; -/* Linked list to save the registered devices */ -static LIST_HEAD(ipoctal_list); - -static inline void ipoctal_write_io_reg(struct ipoctal *ipoctal, - unsigned char *dest, - unsigned char value) -{ - unsigned long offset; - - offset = ((void __iomem *) dest) - ipoctal->dev->io_space.address; - ipoctal->dev->bus->ops->write8(ipoctal->dev, IPACK_IO_SPACE, offset, - value); -} - -static inline void ipoctal_write_cr_cmd(struct ipoctal *ipoctal, - unsigned char *dest, - unsigned char value) -{ - ipoctal_write_io_reg(ipoctal, dest, value); -} - -static inline unsigned char ipoctal_read_io_reg(struct ipoctal *ipoctal, - unsigned char *src) -{ - unsigned long offset; - unsigned char value; - - offset = ((void __iomem *) src) - ipoctal->dev->io_space.address; - ipoctal->dev->bus->ops->read8(ipoctal->dev, IPACK_IO_SPACE, offset, - &value); - return value; -} - -static struct ipoctal *ipoctal_find_board(struct tty_struct *tty) -{ - struct ipoctal *p; - - list_for_each_entry(p, &ipoctal_list, list) { - if (tty->driver->major == p->tty_drv->major) - return p; - } - - return NULL; -} - static int ipoctal_port_activate(struct tty_port *port, struct tty_struct *tty) { - struct ipoctal *ipoctal; - int channel = tty->index; + struct ipoctal_channel *channel; - ipoctal = ipoctal_find_board(tty); + channel = dev_get_drvdata(tty->dev); - if (ipoctal == NULL) { - dev_err(tty->dev, "Device not found. Major %d\n", - tty->driver->major); - return -ENODEV; - } - - ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_ENABLE_RX); + iowrite8(CR_ENABLE_RX, &channel->regs->w.cr); return 0; } static int ipoctal_open(struct tty_struct *tty, struct file *file) { - int channel = tty->index; int res; - struct ipoctal *ipoctal; + struct ipoctal_channel *channel; - ipoctal = ipoctal_find_board(tty); - - if (ipoctal == NULL) { - dev_err(tty->dev, "Device not found. Major %d\n", - tty->driver->major); - return -ENODEV; - } + channel = dev_get_drvdata(tty->dev); - if (atomic_read(&ipoctal->open[channel])) + if (atomic_read(&channel->open)) return -EBUSY; - tty->driver_data = ipoctal; + tty->driver_data = channel; - res = tty_port_open(&ipoctal->tty_port[channel], tty, file); + res = tty_port_open(&channel->tty_port, tty, file); if (res) return res; - atomic_inc(&ipoctal->open[channel]); + atomic_inc(&channel->open); return 0; } @@ -154,175 +95,166 @@ static void ipoctal_reset_stats(struct ipoctal_stats *stats) stats->parity_err = 0; } -static void ipoctal_free_channel(struct tty_struct *tty) +static void ipoctal_free_channel(struct ipoctal_channel *channel) { - int channel = tty->index; - struct ipoctal *ipoctal = tty->driver_data; - - if (ipoctal == NULL) - return; - - ipoctal_reset_stats(&ipoctal->chan_stats[channel]); - ipoctal->pointer_read[channel] = 0; - ipoctal->pointer_write[channel] = 0; - ipoctal->nb_bytes[channel] = 0; + ipoctal_reset_stats(&channel->stats); + channel->pointer_read = 0; + channel->pointer_write = 0; + channel->nb_bytes = 0; } static void ipoctal_close(struct tty_struct *tty, struct file *filp) { - int channel = tty->index; - struct ipoctal *ipoctal = tty->driver_data; + struct ipoctal_channel *channel = tty->driver_data; - tty_port_close(&ipoctal->tty_port[channel], tty, filp); + tty_port_close(&channel->tty_port, tty, filp); - if (atomic_dec_and_test(&ipoctal->open[channel])) - ipoctal_free_channel(tty); + if (atomic_dec_and_test(&channel->open)) + ipoctal_free_channel(channel); } static int ipoctal_get_icount(struct tty_struct *tty, struct serial_icounter_struct *icount) { - struct ipoctal *ipoctal = tty->driver_data; - int channel = tty->index; + struct ipoctal_channel *channel = tty->driver_data; icount->cts = 0; icount->dsr = 0; icount->rng = 0; icount->dcd = 0; - icount->rx = ipoctal->chan_stats[channel].rx; - icount->tx = ipoctal->chan_stats[channel].tx; - icount->frame = ipoctal->chan_stats[channel].framing_err; - icount->parity = ipoctal->chan_stats[channel].parity_err; - icount->brk = ipoctal->chan_stats[channel].rcv_break; + icount->rx = channel->stats.rx; + icount->tx = channel->stats.tx; + icount->frame = channel->stats.framing_err; + icount->parity = channel->stats.parity_err; + icount->brk = channel->stats.rcv_break; return 0; } -static int ipoctal_irq_handler(void *arg) +static void ipoctal_irq_rx(struct ipoctal_channel *channel, + struct tty_struct *tty, u8 sr) { - unsigned int channel; - unsigned int block; - unsigned char isr; - unsigned char sr; - unsigned char isr_tx_rdy, isr_rx_rdy; unsigned char value; - unsigned char flag; - struct tty_struct *tty; - struct ipoctal *ipoctal = (struct ipoctal *) arg; - - /* Check all channels */ - for (channel = 0; channel < NR_CHANNELS; channel++) { - /* If there is no client, skip the check */ - if (!atomic_read(&ipoctal->open[channel])) - continue; - - tty = tty_port_tty_get(&ipoctal->tty_port[channel]); - if (!tty) - continue; - - /* - * The HW is organized in pair of channels. - * See which register we need to read from - */ - block = channel / 2; - isr = ipoctal_read_io_reg(ipoctal, - &ipoctal->block_regs[block].u.r.isr); - sr = ipoctal_read_io_reg(ipoctal, - &ipoctal->chan_regs[channel].u.r.sr); - - if ((channel % 2) == 1) { - isr_tx_rdy = isr & ISR_TxRDY_B; - isr_rx_rdy = isr & ISR_RxRDY_FFULL_B; - } else { - isr_tx_rdy = isr & ISR_TxRDY_A; - isr_rx_rdy = isr & ISR_RxRDY_FFULL_A; + unsigned char flag = TTY_NORMAL; + u8 isr; + + do { + value = ioread8(&channel->regs->r.rhr); + /* Error: count statistics */ + if (sr & SR_ERROR) { + iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr); + + if (sr & SR_OVERRUN_ERROR) { + channel->stats.overrun_err++; + /* Overrun doesn't affect the current character*/ + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + } + if (sr & SR_PARITY_ERROR) { + channel->stats.parity_err++; + flag = TTY_PARITY; + } + if (sr & SR_FRAMING_ERROR) { + channel->stats.framing_err++; + flag = TTY_FRAME; + } + if (sr & SR_RECEIVED_BREAK) { + iowrite8(CR_CMD_RESET_BREAK_CHANGE, &channel->regs->w.cr); + channel->stats.rcv_break++; + flag = TTY_BREAK; + } } + tty_insert_flip_char(tty, value, flag); - /* In case of RS-485, change from TX to RX when finishing TX. - * Half-duplex. + /* Check if there are more characters in RX FIFO + * If there are more, the isr register for this channel + * has enabled the RxRDY|FFULL bit. */ - if ((ipoctal->board_id == IP_OCTAL_485_ID) && - (sr & SR_TX_EMPTY) && - (ipoctal->nb_bytes[channel] == 0)) { - ipoctal_write_io_reg(ipoctal, - &ipoctal->chan_regs[channel].u.w.cr, - CR_DISABLE_TX); - ipoctal_write_cr_cmd(ipoctal, - &ipoctal->chan_regs[channel].u.w.cr, - CR_CMD_NEGATE_RTSN); - ipoctal_write_io_reg(ipoctal, - &ipoctal->chan_regs[channel].u.w.cr, - CR_ENABLE_RX); - ipoctal->write = 1; - wake_up_interruptible(&ipoctal->queue[channel]); - } + isr = ioread8(&channel->block_regs->r.isr); + sr = ioread8(&channel->regs->r.sr); + } while (isr & channel->isr_rx_rdy_mask); - /* RX data */ - if (isr_rx_rdy && (sr & SR_RX_READY)) { - value = ipoctal_read_io_reg(ipoctal, - &ipoctal->chan_regs[channel].u.r.rhr); - flag = TTY_NORMAL; - - /* Error: count statistics */ - if (sr & SR_ERROR) { - ipoctal_write_cr_cmd(ipoctal, - &ipoctal->chan_regs[channel].u.w.cr, - CR_CMD_RESET_ERR_STATUS); - - if (sr & SR_OVERRUN_ERROR) { - ipoctal->chan_stats[channel].overrun_err++; - /* Overrun doesn't affect the current character*/ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } - if (sr & SR_PARITY_ERROR) { - ipoctal->chan_stats[channel].parity_err++; - flag = TTY_PARITY; - } - if (sr & SR_FRAMING_ERROR) { - ipoctal->chan_stats[channel].framing_err++; - flag = TTY_FRAME; - } - if (sr & SR_RECEIVED_BREAK) { - ipoctal->chan_stats[channel].rcv_break++; - flag = TTY_BREAK; - } - } + tty_flip_buffer_push(tty); +} - tty_insert_flip_char(tty, value, flag); - } +static void ipoctal_irq_tx(struct ipoctal_channel *channel) +{ + unsigned char value; + unsigned int *pointer_write = &channel->pointer_write; - /* TX of each character */ - if (isr_tx_rdy && (sr & SR_TX_READY)) { - unsigned int *pointer_write = - &ipoctal->pointer_write[channel]; + if (channel->nb_bytes <= 0) { + channel->nb_bytes = 0; + return; + } - if (ipoctal->nb_bytes[channel] <= 0) { - ipoctal->nb_bytes[channel] = 0; - continue; - } + value = channel->tty_port.xmit_buf[*pointer_write]; + iowrite8(value, &channel->regs->w.thr); + channel->stats.tx++; + (*pointer_write)++; + *pointer_write = *pointer_write % PAGE_SIZE; + channel->nb_bytes--; - value = ipoctal->tty_port[channel].xmit_buf[*pointer_write]; - ipoctal_write_io_reg(ipoctal, - &ipoctal->chan_regs[channel].u.w.thr, - value); - ipoctal->chan_stats[channel].tx++; - ipoctal->count_wr[channel]++; - (*pointer_write)++; - *pointer_write = *pointer_write % PAGE_SIZE; - ipoctal->nb_bytes[channel]--; - - if ((ipoctal->nb_bytes[channel] == 0) && - (waitqueue_active(&ipoctal->queue[channel]))) { - - if (ipoctal->board_id != IP_OCTAL_485_ID) { - ipoctal->write = 1; - wake_up_interruptible(&ipoctal->queue[channel]); - } - } + if ((channel->nb_bytes == 0) && + (waitqueue_active(&channel->queue))) { + + if (channel->board_id != IPACK1_DEVICE_ID_SBS_OCTAL_485) { + *channel->board_write = 1; + wake_up_interruptible(&channel->queue); } + } +} - tty_flip_buffer_push(tty); - tty_kref_put(tty); +static void ipoctal_irq_channel(struct ipoctal_channel *channel) +{ + u8 isr, sr; + struct tty_struct *tty; + + /* If there is no client, skip the check */ + if (!atomic_read(&channel->open)) + return; + + tty = tty_port_tty_get(&channel->tty_port); + if (!tty) + return; + /* The HW is organized in pair of channels. See which register we need + * to read from */ + isr = ioread8(&channel->block_regs->r.isr); + sr = ioread8(&channel->regs->r.sr); + + /* In case of RS-485, change from TX to RX when finishing TX. + * Half-duplex. */ + if ((channel->board_id == IPACK1_DEVICE_ID_SBS_OCTAL_485) && + (sr & SR_TX_EMPTY) && (channel->nb_bytes == 0)) { + iowrite8(CR_DISABLE_TX, &channel->regs->w.cr); + iowrite8(CR_CMD_NEGATE_RTSN, &channel->regs->w.cr); + iowrite8(CR_ENABLE_RX, &channel->regs->w.cr); + *channel->board_write = 1; + wake_up_interruptible(&channel->queue); } + + /* RX data */ + if ((isr & channel->isr_rx_rdy_mask) && (sr & SR_RX_READY)) + ipoctal_irq_rx(channel, tty, sr); + + /* TX of each character */ + if ((isr & channel->isr_tx_rdy_mask) && (sr & SR_TX_READY)) + ipoctal_irq_tx(channel); + + tty_flip_buffer_push(tty); + tty_kref_put(tty); +} + +static irqreturn_t ipoctal_irq_handler(void *arg) +{ + unsigned int i; + struct ipoctal *ipoctal = (struct ipoctal *) arg; + + /* Check all channels */ + for (i = 0; i < NR_CHANNELS; i++) + ipoctal_irq_channel(&ipoctal->channel[i]); + + /* Clear the IPack device interrupt */ + readw(ipoctal->dev->int_space.address + ACK_INT_REQ0); + readw(ipoctal->dev->int_space.address + ACK_INT_REQ1); + return IRQ_HANDLED; } @@ -331,18 +263,15 @@ static int ipoctal_check_model(struct ipack_device *dev, unsigned char *id) unsigned char manufacturerID; unsigned char board_id; - dev->bus->ops->read8(dev, IPACK_ID_SPACE, - IPACK_IDPROM_OFFSET_MANUFACTURER_ID, &manufacturerID); - if (manufacturerID != IP_OCTAL_MANUFACTURER_ID) - return -ENODEV; - - dev->bus->ops->read8(dev, IPACK_ID_SPACE, - IPACK_IDPROM_OFFSET_MODEL, (unsigned char *)&board_id); + manufacturerID = ioread8(dev->id_space.address + IPACK_IDPROM_OFFSET_MANUFACTURER_ID); + if (manufacturerID != IPACK1_VENDOR_ID_SBS) + return -ENODEV; + board_id = ioread8(dev->id_space.address + IPACK_IDPROM_OFFSET_MODEL); switch (board_id) { - case IP_OCTAL_232_ID: - case IP_OCTAL_422_ID: - case IP_OCTAL_485_ID: + case IPACK1_DEVICE_ID_SBS_OCTAL_232: + case IPACK1_DEVICE_ID_SBS_OCTAL_422: + case IPACK1_DEVICE_ID_SBS_OCTAL_485: *id = board_id; break; default: @@ -358,13 +287,16 @@ static const struct tty_port_operations ipoctal_tty_port_ops = { }; static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr, - unsigned int slot, unsigned int vector) + unsigned int slot) { int res = 0; int i; struct tty_driver *tty; char name[20]; unsigned char board_id; + struct ipoctal_channel *channel; + union scc2698_channel __iomem *chan_regs; + union scc2698_block __iomem *block_regs; res = ipoctal->dev->bus->ops->map_space(ipoctal->dev, 0, IPACK_ID_SPACE); @@ -392,54 +324,61 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr, goto out_unregister_id_space; } + res = ipoctal->dev->bus->ops->map_space(ipoctal->dev, 0, + IPACK_INT_SPACE); + if (res) { + dev_err(&ipoctal->dev->dev, + "Unable to map slot [%d:%d] INT space!\n", + bus_nr, slot); + goto out_unregister_io_space; + } + res = ipoctal->dev->bus->ops->map_space(ipoctal->dev, 0x8000, IPACK_MEM_SPACE); if (res) { dev_err(&ipoctal->dev->dev, "Unable to map slot [%d:%d] MEM space!\n", bus_nr, slot); - goto out_unregister_io_space; + goto out_unregister_int_space; } /* Save the virtual address to access the registers easily */ - ipoctal->chan_regs = - (struct scc2698_channel *) ipoctal->dev->io_space.address; - ipoctal->block_regs = - (struct scc2698_block *) ipoctal->dev->io_space.address; + chan_regs = + (union scc2698_channel __iomem *) ipoctal->dev->io_space.address; + block_regs = + (union scc2698_block __iomem *) ipoctal->dev->io_space.address; /* Disable RX and TX before touching anything */ for (i = 0; i < NR_CHANNELS ; i++) { - ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[i].u.w.cr, - CR_DISABLE_RX | CR_DISABLE_TX); - ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[i].u.w.cr, - CR_CMD_RESET_RX); - ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[i].u.w.cr, - CR_CMD_RESET_TX); - ipoctal_write_io_reg(ipoctal, - &ipoctal->chan_regs[i].u.w.mr, - MR1_CHRL_8_BITS | MR1_ERROR_CHAR | - MR1_RxINT_RxRDY); /* mr1 */ - ipoctal_write_io_reg(ipoctal, - &ipoctal->chan_regs[i].u.w.mr, - 0); /* mr2 */ - ipoctal_write_io_reg(ipoctal, - &ipoctal->chan_regs[i].u.w.csr, - TX_CLK_9600 | RX_CLK_9600); + struct ipoctal_channel *channel = &ipoctal->channel[i]; + channel->regs = chan_regs + i; + channel->block_regs = block_regs + (i >> 1); + channel->board_write = &ipoctal->write; + channel->board_id = ipoctal->board_id; + if (i & 1) { + channel->isr_tx_rdy_mask = ISR_TxRDY_B; + channel->isr_rx_rdy_mask = ISR_RxRDY_FFULL_B; + } else { + channel->isr_tx_rdy_mask = ISR_TxRDY_A; + channel->isr_rx_rdy_mask = ISR_RxRDY_FFULL_A; + } + + iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr); + iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr); + iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr); + iowrite8(MR1_CHRL_8_BITS | MR1_ERROR_CHAR | MR1_RxINT_RxRDY, + &channel->regs->w.mr); /* mr1 */ + iowrite8(0, &channel->regs->w.mr); /* mr2 */ + iowrite8(TX_CLK_9600 | RX_CLK_9600, &channel->regs->w.csr); } for (i = 0; i < IP_OCTAL_NB_BLOCKS; i++) { - ipoctal_write_io_reg(ipoctal, - &ipoctal->block_regs[i].u.w.acr, - ACR_BRG_SET2); - ipoctal_write_io_reg(ipoctal, - &ipoctal->block_regs[i].u.w.opcr, - OPCR_MPP_OUTPUT | OPCR_MPOa_RTSN | - OPCR_MPOb_RTSN); - ipoctal_write_io_reg(ipoctal, - &ipoctal->block_regs[i].u.w.imr, - IMR_TxRDY_A | IMR_RxRDY_FFULL_A | - IMR_DELTA_BREAK_A | IMR_TxRDY_B | - IMR_RxRDY_FFULL_B | IMR_DELTA_BREAK_B); + iowrite8(ACR_BRG_SET2, &block_regs[i].w.acr); + iowrite8(OPCR_MPP_OUTPUT | OPCR_MPOa_RTSN | OPCR_MPOb_RTSN, + &block_regs[i].w.opcr); + iowrite8(IMR_TxRDY_A | IMR_RxRDY_FFULL_A | IMR_DELTA_BREAK_A | + IMR_TxRDY_B | IMR_RxRDY_FFULL_B | IMR_DELTA_BREAK_B, + &block_regs[i].w.imr); } /* @@ -447,10 +386,10 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr, * Depending of the carrier these addresses are accesible or not. * More info in the datasheet. */ - ipoctal->dev->bus->ops->request_irq(ipoctal->dev, vector, + ipoctal->dev->bus->ops->request_irq(ipoctal->dev, ipoctal_irq_handler, ipoctal); - ipoctal->dev->bus->ops->write8(ipoctal->dev, IPACK_MEM_SPACE, 0, - vector); + /* Dummy write */ + iowrite8(1, ipoctal->dev->mem_space.address + 1); /* Register the TTY device */ @@ -464,8 +403,8 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr, /* Fill struct tty_driver with ipoctal data */ tty->owner = THIS_MODULE; - tty->driver_name = "ipoctal"; - sprintf(name, "ipoctal.%d.%d.", bus_nr, slot); + tty->driver_name = KBUILD_MODNAME; + sprintf(name, KBUILD_MODNAME ".%d.%d.", bus_nr, slot); tty->name = name; tty->major = 0; @@ -490,32 +429,40 @@ static int ipoctal_inst_slot(struct ipoctal *ipoctal, unsigned int bus_nr, ipoctal->tty_drv = tty; for (i = 0; i < NR_CHANNELS; i++) { - tty_port_init(&ipoctal->tty_port[i]); - tty_port_alloc_xmit_buf(&ipoctal->tty_port[i]); - ipoctal->tty_port[i].ops = &ipoctal_tty_port_ops; - - ipoctal_reset_stats(&ipoctal->chan_stats[i]); - ipoctal->nb_bytes[i] = 0; - init_waitqueue_head(&ipoctal->queue[i]); - - spin_lock_init(&ipoctal->lock[i]); - ipoctal->pointer_read[i] = 0; - ipoctal->pointer_write[i] = 0; - ipoctal->nb_bytes[i] = 0; - tty_register_device(tty, i, NULL); + struct device *tty_dev; + + channel = &ipoctal->channel[i]; + tty_port_init(&channel->tty_port); + tty_port_alloc_xmit_buf(&channel->tty_port); + channel->tty_port.ops = &ipoctal_tty_port_ops; + + ipoctal_reset_stats(&channel->stats); + channel->nb_bytes = 0; + init_waitqueue_head(&channel->queue); + + spin_lock_init(&channel->lock); + channel->pointer_read = 0; + channel->pointer_write = 0; + tty_dev = tty_register_device(tty, i, NULL); + if (IS_ERR(tty_dev)) { + dev_err(&ipoctal->dev->dev, "Failed to register tty device.\n"); + continue; + } + dev_set_drvdata(tty_dev, channel); /* * Enable again the RX. TX will be enabled when * there is something to send */ - ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[i].u.w.cr, - CR_ENABLE_RX); + iowrite8(CR_ENABLE_RX, &channel->regs->w.cr); } return 0; out_unregister_slot_unmap: ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_ID_SPACE); +out_unregister_int_space: + ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_INT_SPACE); out_unregister_io_space: ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_IO_SPACE); out_unregister_id_space: @@ -523,23 +470,22 @@ out_unregister_id_space: return res; } -static inline int ipoctal_copy_write_buffer(struct ipoctal *ipoctal, - unsigned int channel, +static inline int ipoctal_copy_write_buffer(struct ipoctal_channel *channel, const unsigned char *buf, int count) { unsigned long flags; int i; - unsigned int *pointer_read = &ipoctal->pointer_read[channel]; + unsigned int *pointer_read = &channel->pointer_read; /* Copy the bytes from the user buffer to the internal one */ for (i = 0; i < count; i++) { - if (i <= (PAGE_SIZE - ipoctal->nb_bytes[channel])) { - spin_lock_irqsave(&ipoctal->lock[channel], flags); - ipoctal->tty_port[channel].xmit_buf[*pointer_read] = buf[i]; + if (i <= (PAGE_SIZE - channel->nb_bytes)) { + spin_lock_irqsave(&channel->lock, flags); + channel->tty_port.xmit_buf[*pointer_read] = buf[i]; *pointer_read = (*pointer_read + 1) % PAGE_SIZE; - ipoctal->nb_bytes[channel]++; - spin_unlock_irqrestore(&ipoctal->lock[channel], flags); + channel->nb_bytes++; + spin_unlock_irqrestore(&channel->lock, flags); } else { break; } @@ -547,63 +493,44 @@ static inline int ipoctal_copy_write_buffer(struct ipoctal *ipoctal, return i; } -static int ipoctal_write(struct ipoctal *ipoctal, unsigned int channel, - const unsigned char *buf, int count) +static int ipoctal_write_tty(struct tty_struct *tty, + const unsigned char *buf, int count) { - ipoctal->nb_bytes[channel] = 0; - ipoctal->count_wr[channel] = 0; + struct ipoctal_channel *channel = tty->driver_data; + unsigned int char_copied; - ipoctal_copy_write_buffer(ipoctal, channel, buf, count); + char_copied = ipoctal_copy_write_buffer(channel, buf, count); /* As the IP-OCTAL 485 only supports half duplex, do it manually */ - if (ipoctal->board_id == IP_OCTAL_485_ID) { - ipoctal_write_io_reg(ipoctal, - &ipoctal->chan_regs[channel].u.w.cr, - CR_DISABLE_RX); - ipoctal_write_cr_cmd(ipoctal, - &ipoctal->chan_regs[channel].u.w.cr, - CR_CMD_ASSERT_RTSN); + if (channel->board_id == IPACK1_DEVICE_ID_SBS_OCTAL_485) { + iowrite8(CR_DISABLE_RX, &channel->regs->w.cr); + iowrite8(CR_CMD_ASSERT_RTSN, &channel->regs->w.cr); } /* * Send a packet and then disable TX to avoid failure after several send * operations */ - ipoctal_write_io_reg(ipoctal, - &ipoctal->chan_regs[channel].u.w.cr, - CR_ENABLE_TX); - wait_event_interruptible(ipoctal->queue[channel], ipoctal->write); - ipoctal_write_io_reg(ipoctal, - &ipoctal->chan_regs[channel].u.w.cr, - CR_DISABLE_TX); - - ipoctal->write = 0; - return ipoctal->count_wr[channel]; -} - -static int ipoctal_write_tty(struct tty_struct *tty, - const unsigned char *buf, int count) -{ - unsigned int channel = tty->index; - struct ipoctal *ipoctal = tty->driver_data; + iowrite8(CR_ENABLE_TX, &channel->regs->w.cr); + wait_event_interruptible(channel->queue, *channel->board_write); + iowrite8(CR_DISABLE_TX, &channel->regs->w.cr); - return ipoctal_write(ipoctal, channel, buf, count); + *channel->board_write = 0; + return char_copied; } static int ipoctal_write_room(struct tty_struct *tty) { - int channel = tty->index; - struct ipoctal *ipoctal = tty->driver_data; + struct ipoctal_channel *channel = tty->driver_data; - return PAGE_SIZE - ipoctal->nb_bytes[channel]; + return PAGE_SIZE - channel->nb_bytes; } static int ipoctal_chars_in_buffer(struct tty_struct *tty) { - int channel = tty->index; - struct ipoctal *ipoctal = tty->driver_data; + struct ipoctal_channel *channel = tty->driver_data; - return ipoctal->nb_bytes[channel]; + return channel->nb_bytes; } static void ipoctal_set_termios(struct tty_struct *tty, @@ -613,23 +540,17 @@ static void ipoctal_set_termios(struct tty_struct *tty, unsigned char mr1 = 0; unsigned char mr2 = 0; unsigned char csr = 0; - unsigned int channel = tty->index; - struct ipoctal *ipoctal = tty->driver_data; + struct ipoctal_channel *channel = tty->driver_data; speed_t baud; cflag = tty->termios->c_cflag; /* Disable and reset everything before change the setup */ - ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_DISABLE_RX | CR_DISABLE_TX); - ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_CMD_RESET_RX); - ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_CMD_RESET_TX); - ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_CMD_RESET_ERR_STATUS); - ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_CMD_RESET_MR); + iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr); + iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr); + iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr); + iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr); + iowrite8(CR_CMD_RESET_MR, &channel->regs->w.cr); /* Set Bits per chars */ switch (cflag & CSIZE) { @@ -666,8 +587,8 @@ static void ipoctal_set_termios(struct tty_struct *tty, mr2 |= MR2_STOP_BITS_LENGTH_1; /* Set the flow control */ - switch (ipoctal->board_id) { - case IP_OCTAL_232_ID: + switch (channel->board_id) { + case IPACK1_DEVICE_ID_SBS_OCTAL_232: if (cflag & CRTSCTS) { mr1 |= MR1_RxRTS_CONTROL_ON; mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_ON; @@ -676,11 +597,11 @@ static void ipoctal_set_termios(struct tty_struct *tty, mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_OFF; } break; - case IP_OCTAL_422_ID: + case IPACK1_DEVICE_ID_SBS_OCTAL_422: mr1 |= MR1_RxRTS_CONTROL_OFF; mr2 |= MR2_TxRTS_CONTROL_OFF | MR2_CTS_ENABLE_TX_OFF; break; - case IP_OCTAL_485_ID: + case IPACK1_DEVICE_ID_SBS_OCTAL_485: mr1 |= MR1_RxRTS_CONTROL_OFF; mr2 |= MR2_TxRTS_CONTROL_ON | MR2_CTS_ENABLE_TX_OFF; break; @@ -742,45 +663,38 @@ static void ipoctal_set_termios(struct tty_struct *tty, mr1 |= MR1_RxINT_RxRDY; /* Write the control registers */ - ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.mr, mr1); - ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.mr, mr2); - ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.csr, csr); + iowrite8(mr1, &channel->regs->w.mr); + iowrite8(mr2, &channel->regs->w.mr); + iowrite8(csr, &channel->regs->w.csr); /* Enable again the RX */ - ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_ENABLE_RX); + iowrite8(CR_ENABLE_RX, &channel->regs->w.cr); } static void ipoctal_hangup(struct tty_struct *tty) { unsigned long flags; - int channel = tty->index; - struct ipoctal *ipoctal = tty->driver_data; + struct ipoctal_channel *channel = tty->driver_data; - if (ipoctal == NULL) + if (channel == NULL) return; - spin_lock_irqsave(&ipoctal->lock[channel], flags); - ipoctal->nb_bytes[channel] = 0; - ipoctal->pointer_read[channel] = 0; - ipoctal->pointer_write[channel] = 0; - spin_unlock_irqrestore(&ipoctal->lock[channel], flags); - - tty_port_hangup(&ipoctal->tty_port[channel]); - - ipoctal_write_io_reg(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_DISABLE_RX | CR_DISABLE_TX); - ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_CMD_RESET_RX); - ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_CMD_RESET_TX); - ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_CMD_RESET_ERR_STATUS); - ipoctal_write_cr_cmd(ipoctal, &ipoctal->chan_regs[channel].u.w.cr, - CR_CMD_RESET_MR); - - clear_bit(ASYNCB_INITIALIZED, &ipoctal->tty_port[channel].flags); - wake_up_interruptible(&ipoctal->tty_port[channel].open_wait); + spin_lock_irqsave(&channel->lock, flags); + channel->nb_bytes = 0; + channel->pointer_read = 0; + channel->pointer_write = 0; + spin_unlock_irqrestore(&channel->lock, flags); + + tty_port_hangup(&channel->tty_port); + + iowrite8(CR_DISABLE_RX | CR_DISABLE_TX, &channel->regs->w.cr); + iowrite8(CR_CMD_RESET_RX, &channel->regs->w.cr); + iowrite8(CR_CMD_RESET_TX, &channel->regs->w.cr); + iowrite8(CR_CMD_RESET_ERR_STATUS, &channel->regs->w.cr); + iowrite8(CR_CMD_RESET_MR, &channel->regs->w.cr); + + clear_bit(ASYNCB_INITIALIZED, &channel->tty_port.flags); + wake_up_interruptible(&channel->tty_port.open_wait); } static const struct tty_operations ipoctal_fops = { @@ -795,27 +709,6 @@ static const struct tty_operations ipoctal_fops = { .hangup = ipoctal_hangup, }; -static int ipoctal_match(struct ipack_device *dev) -{ - int res; - unsigned char board_id; - - if ((!dev->bus->ops) || (!dev->bus->ops->map_space) || - (!dev->bus->ops->unmap_space)) - return 0; - - res = dev->bus->ops->map_space(dev, 0, IPACK_ID_SPACE); - if (res) - return 0; - - res = ipoctal_check_model(dev, &board_id); - dev->bus->ops->unmap_space(dev, IPACK_ID_SPACE); - if (!res) - return 1; - - return 0; -} - static int ipoctal_probe(struct ipack_device *dev) { int res; @@ -826,11 +719,11 @@ static int ipoctal_probe(struct ipack_device *dev) return -ENOMEM; ipoctal->dev = dev; - res = ipoctal_inst_slot(ipoctal, dev->bus_nr, dev->slot, dev->irq); + res = ipoctal_inst_slot(ipoctal, dev->bus_nr, dev->slot); if (res) goto out_uninst; - list_add_tail(&ipoctal->list, &ipoctal_list); + dev_set_drvdata(&dev->dev, ipoctal); return 0; out_uninst: @@ -842,46 +735,57 @@ static void __ipoctal_remove(struct ipoctal *ipoctal) { int i; + ipoctal->dev->bus->ops->free_irq(ipoctal->dev); + for (i = 0; i < NR_CHANNELS; i++) { + struct ipoctal_channel *channel = &ipoctal->channel[i]; tty_unregister_device(ipoctal->tty_drv, i); - tty_port_free_xmit_buf(&ipoctal->tty_port[i]); + tty_port_free_xmit_buf(&channel->tty_port); } tty_unregister_driver(ipoctal->tty_drv); put_tty_driver(ipoctal->tty_drv); - list_del(&ipoctal->list); + ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_MEM_SPACE); + ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_INT_SPACE); + ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_IO_SPACE); + ipoctal->dev->bus->ops->unmap_space(ipoctal->dev, IPACK_ID_SPACE); kfree(ipoctal); } -static void ipoctal_remove(struct ipack_device *device) +static void ipoctal_remove(struct ipack_device *idev) { - struct ipoctal *ipoctal, *next; - - list_for_each_entry_safe(ipoctal, next, &ipoctal_list, list) { - if (ipoctal->dev == device) - __ipoctal_remove(ipoctal); - } + __ipoctal_remove(dev_get_drvdata(&idev->dev)); } -static struct ipack_driver_ops ipoctal_drv_ops = { - .match = ipoctal_match, - .probe = ipoctal_probe, +static DEFINE_IPACK_DEVICE_TABLE(ipoctal_ids) = { + { IPACK_DEVICE(IPACK_ID_VERSION_1, IPACK1_VENDOR_ID_SBS, + IPACK1_DEVICE_ID_SBS_OCTAL_232) }, + { IPACK_DEVICE(IPACK_ID_VERSION_1, IPACK1_VENDOR_ID_SBS, + IPACK1_DEVICE_ID_SBS_OCTAL_422) }, + { IPACK_DEVICE(IPACK_ID_VERSION_1, IPACK1_VENDOR_ID_SBS, + IPACK1_DEVICE_ID_SBS_OCTAL_485) }, + { 0, }, +}; + +MODULE_DEVICE_TABLE(ipack, ipoctal_ids); + +static const struct ipack_driver_ops ipoctal_drv_ops = { + .probe = ipoctal_probe, .remove = ipoctal_remove, }; +static struct ipack_driver driver = { + .ops = &ipoctal_drv_ops, + .id_table = ipoctal_ids, +}; + static int __init ipoctal_init(void) { - driver.ops = &ipoctal_drv_ops; return ipack_driver_register(&driver, THIS_MODULE, KBUILD_MODNAME); } static void __exit ipoctal_exit(void) { - struct ipoctal *p, *next; - - list_for_each_entry_safe(p, next, &ipoctal_list, list) - p->dev->bus->ops->remove_device(p->dev); - ipack_driver_unregister(&driver); } diff --git a/drivers/staging/ipack/devices/scc2698.h b/drivers/staging/ipack/devices/scc2698.h index 47f6269985fd..96e8d8c30e14 100644 --- a/drivers/staging/ipack/devices/scc2698.h +++ b/drivers/staging/ipack/devices/scc2698.h @@ -15,78 +15,74 @@ #define SCC2698_H_ /* - * struct scc2698_channel - Channel access to scc2698 IO + * union scc2698_channel - Channel access to scc2698 IO * * dn value are only spacer. * */ -struct scc2698_channel { - union { - struct { - unsigned char d0, mr; /* Mode register 1/2*/ - unsigned char d1, sr; /* Status register */ - unsigned char d2, r1; /* reserved */ - unsigned char d3, rhr; /* Receive holding register (R) */ - unsigned char junk[8]; /* other crap for block control */ - } r; /* Read access */ - struct { - unsigned char d0, mr; /* Mode register 1/2 */ - unsigned char d1, csr; /* Clock select register */ - unsigned char d2, cr; /* Command register */ - unsigned char d3, thr; /* Transmit holding register */ - unsigned char junk[8]; /* other crap for block control */ - } w; /* Write access */ - } u; +union scc2698_channel { + struct { + u8 d0, mr; /* Mode register 1/2*/ + u8 d1, sr; /* Status register */ + u8 d2, r1; /* reserved */ + u8 d3, rhr; /* Receive holding register (R) */ + u8 junk[8]; /* other crap for block control */ + } __packed r; /* Read access */ + struct { + u8 d0, mr; /* Mode register 1/2 */ + u8 d1, csr; /* Clock select register */ + u8 d2, cr; /* Command register */ + u8 d3, thr; /* Transmit holding register */ + u8 junk[8]; /* other crap for block control */ + } __packed w; /* Write access */ }; /* - * struct scc2698_block - Block access to scc2698 IO + * union scc2698_block - Block access to scc2698 IO * * The scc2698 contain 4 block. * Each block containt two channel a and b. * dn value are only spacer. * */ -struct scc2698_block { - union { - struct { - unsigned char d0, mra; /* Mode register 1/2 (a) */ - unsigned char d1, sra; /* Status register (a) */ - unsigned char d2, r1; /* reserved */ - unsigned char d3, rhra; /* Receive holding register (a) */ - unsigned char d4, ipcr; /* Input port change register of block */ - unsigned char d5, isr; /* Interrupt status register of block */ - unsigned char d6, ctur; /* Counter timer upper register of block */ - unsigned char d7, ctlr; /* Counter timer lower register of block */ - unsigned char d8, mrb; /* Mode register 1/2 (b) */ - unsigned char d9, srb; /* Status register (b) */ - unsigned char da, r2; /* reserved */ - unsigned char db, rhrb; /* Receive holding register (b) */ - unsigned char dc, r3; /* reserved */ - unsigned char dd, ip; /* Input port register of block */ - unsigned char de, ctg; /* Start counter timer of block */ - unsigned char df, cts; /* Stop counter timer of block */ - } r; /* Read access */ - struct { - unsigned char d0, mra; /* Mode register 1/2 (a) */ - unsigned char d1, csra; /* Clock select register (a) */ - unsigned char d2, cra; /* Command register (a) */ - unsigned char d3, thra; /* Transmit holding register (a) */ - unsigned char d4, acr; /* Auxiliary control register of block */ - unsigned char d5, imr; /* Interrupt mask register of block */ - unsigned char d6, ctu; /* Counter timer upper register of block */ - unsigned char d7, ctl; /* Counter timer lower register of block */ - unsigned char d8, mrb; /* Mode register 1/2 (b) */ - unsigned char d9, csrb; /* Clock select register (a) */ - unsigned char da, crb; /* Command register (b) */ - unsigned char db, thrb; /* Transmit holding register (b) */ - unsigned char dc, r1; /* reserved */ - unsigned char dd, opcr; /* Output port configuration register of block */ - unsigned char de, r2; /* reserved */ - unsigned char df, r3; /* reserved */ - } w; /* Write access */ - } u; -} ; +union scc2698_block { + struct { + u8 d0, mra; /* Mode register 1/2 (a) */ + u8 d1, sra; /* Status register (a) */ + u8 d2, r1; /* reserved */ + u8 d3, rhra; /* Receive holding register (a) */ + u8 d4, ipcr; /* Input port change register of block */ + u8 d5, isr; /* Interrupt status register of block */ + u8 d6, ctur; /* Counter timer upper register of block */ + u8 d7, ctlr; /* Counter timer lower register of block */ + u8 d8, mrb; /* Mode register 1/2 (b) */ + u8 d9, srb; /* Status register (b) */ + u8 da, r2; /* reserved */ + u8 db, rhrb; /* Receive holding register (b) */ + u8 dc, r3; /* reserved */ + u8 dd, ip; /* Input port register of block */ + u8 de, ctg; /* Start counter timer of block */ + u8 df, cts; /* Stop counter timer of block */ + } __packed r; /* Read access */ + struct { + u8 d0, mra; /* Mode register 1/2 (a) */ + u8 d1, csra; /* Clock select register (a) */ + u8 d2, cra; /* Command register (a) */ + u8 d3, thra; /* Transmit holding register (a) */ + u8 d4, acr; /* Auxiliary control register of block */ + u8 d5, imr; /* Interrupt mask register of block */ + u8 d6, ctu; /* Counter timer upper register of block */ + u8 d7, ctl; /* Counter timer lower register of block */ + u8 d8, mrb; /* Mode register 1/2 (b) */ + u8 d9, csrb; /* Clock select register (a) */ + u8 da, crb; /* Command register (b) */ + u8 db, thrb; /* Transmit holding register (b) */ + u8 dc, r1; /* reserved */ + u8 dd, opcr; /* Output port configuration register of block */ + u8 de, r2; /* reserved */ + u8 df, r3; /* reserved */ + } __packed w; /* Write access */ +}; #define MR1_CHRL_5_BITS (0x0 << 0) #define MR1_CHRL_6_BITS (0x1 << 0) @@ -225,4 +221,7 @@ struct scc2698_block { #define ISR_DELTA_BREAK_B (0x1 << 6) #define ISR_INPUT_PORT_CHANGE (0x1 << 7) +#define ACK_INT_REQ0 0 +#define ACK_INT_REQ1 2 + #endif /* SCC2698_H_ */ diff --git a/drivers/staging/ipack/ipack.c b/drivers/staging/ipack/ipack.c index c1cd97a4d9ce..d1e0651592a2 100644 --- a/drivers/staging/ipack/ipack.c +++ b/drivers/staging/ipack/ipack.c @@ -12,6 +12,7 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/idr.h> +#include <asm/io.h> #include "ipack.h" #define to_ipack_dev(device) container_of(device, struct ipack_device, dev) @@ -22,55 +23,190 @@ static DEFINE_IDA(ipack_ida); static void ipack_device_release(struct device *dev) { struct ipack_device *device = to_ipack_dev(dev); + kfree(device->id); kfree(device); } -static int ipack_bus_match(struct device *device, struct device_driver *driver) +static inline const struct ipack_device_id * +ipack_match_one_device(const struct ipack_device_id *id, + const struct ipack_device *device) { - int ret; - struct ipack_device *dev = to_ipack_dev(device); - struct ipack_driver *drv = to_ipack_driver(driver); + if ((id->format == IPACK_ANY_FORMAT || + id->format == device->id_format) && + (id->vendor == IPACK_ANY_ID || id->vendor == device->id_vendor) && + (id->device == IPACK_ANY_ID || id->device == device->id_device)) + return id; + return NULL; +} - if ((!drv->ops) || (!drv->ops->match)) - return -EINVAL; +static const struct ipack_device_id * +ipack_match_id(const struct ipack_device_id *ids, struct ipack_device *idev) +{ + if (ids) { + while (ids->vendor || ids->device) { + if (ipack_match_one_device(ids, idev)) + return ids; + ids++; + } + } + return NULL; +} - ret = drv->ops->match(dev); - if (ret) - dev->driver = drv; +static int ipack_bus_match(struct device *dev, struct device_driver *drv) +{ + struct ipack_device *idev = to_ipack_dev(dev); + struct ipack_driver *idrv = to_ipack_driver(drv); + const struct ipack_device_id *found_id; - return ret; + found_id = ipack_match_id(idrv->id_table, idev); + return found_id ? 1 : 0; } static int ipack_bus_probe(struct device *device) { struct ipack_device *dev = to_ipack_dev(device); + struct ipack_driver *drv = to_ipack_driver(device->driver); - if (!dev->driver->ops->probe) + if (!drv->ops->probe) return -EINVAL; - return dev->driver->ops->probe(dev); + return drv->ops->probe(dev); } static int ipack_bus_remove(struct device *device) { struct ipack_device *dev = to_ipack_dev(device); + struct ipack_driver *drv = to_ipack_driver(device->driver); - if (!dev->driver->ops->remove) + if (!drv->ops->remove) return -EINVAL; - dev->driver->ops->remove(dev); + drv->ops->remove(dev); + return 0; +} + +#ifdef CONFIG_HOTPLUG + +static int ipack_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct ipack_device *idev; + + if (!dev) + return -ENODEV; + + idev = to_ipack_dev(dev); + + if (add_uevent_var(env, + "MODALIAS=ipack:f%02Xv%08Xd%08X", idev->id_format, + idev->id_vendor, idev->id_device)) + return -ENOMEM; + return 0; } +#else /* !CONFIG_HOTPLUG */ + +#define ipack_uevent NULL + +#endif /* !CONFIG_HOTPLUG */ + +#define ipack_device_attr(field, format_string) \ +static ssize_t \ +field##_show(struct device *dev, struct device_attribute *attr, \ + char *buf) \ +{ \ + struct ipack_device *idev = to_ipack_dev(dev); \ + return sprintf(buf, format_string, idev->field); \ +} + +static ssize_t id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + unsigned int i, c, l, s; + struct ipack_device *idev = to_ipack_dev(dev); + + + switch (idev->id_format) { + case IPACK_ID_VERSION_1: + l = 0x7; s = 1; break; + case IPACK_ID_VERSION_2: + l = 0xf; s = 2; break; + default: + return -EIO; + } + c = 0; + for (i = 0; i < idev->id_avail; i++) { + if (i > 0) { + if ((i & l) == 0) + buf[c++] = '\n'; + else if ((i & s) == 0) + buf[c++] = ' '; + } + sprintf(&buf[c], "%02x", idev->id[i]); + c += 2; + } + buf[c++] = '\n'; + return c; +} + +static ssize_t +id_vendor_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct ipack_device *idev = to_ipack_dev(dev); + switch (idev->id_format) { + case IPACK_ID_VERSION_1: + return sprintf(buf, "0x%02x\n", idev->id_vendor); + case IPACK_ID_VERSION_2: + return sprintf(buf, "0x%06x\n", idev->id_vendor); + default: + return -EIO; + } +} + +static ssize_t +id_device_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct ipack_device *idev = to_ipack_dev(dev); + switch (idev->id_format) { + case IPACK_ID_VERSION_1: + return sprintf(buf, "0x%02x\n", idev->id_device); + case IPACK_ID_VERSION_2: + return sprintf(buf, "0x%04x\n", idev->id_device); + default: + return -EIO; + } +} + +static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ipack_device *idev = to_ipack_dev(dev); + + return sprintf(buf, "ipac:f%02Xv%08Xd%08X", idev->id_format, + idev->id_vendor, idev->id_device); +} + +ipack_device_attr(id_format, "0x%hhu\n"); + +static struct device_attribute ipack_dev_attrs[] = { + __ATTR_RO(id), + __ATTR_RO(id_device), + __ATTR_RO(id_format), + __ATTR_RO(id_vendor), + __ATTR_RO(modalias), +}; + static struct bus_type ipack_bus_type = { - .name = "ipack", - .probe = ipack_bus_probe, - .match = ipack_bus_match, - .remove = ipack_bus_remove, + .name = "ipack", + .probe = ipack_bus_probe, + .match = ipack_bus_match, + .remove = ipack_bus_remove, + .dev_attrs = ipack_dev_attrs, + .uevent = ipack_uevent, }; struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots, - struct ipack_bus_ops *ops) + const struct ipack_bus_ops *ops) { int bus_nr; struct ipack_bus_device *bus; @@ -93,8 +229,20 @@ struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots, } EXPORT_SYMBOL_GPL(ipack_bus_register); +static int ipack_unregister_bus_member(struct device *dev, void *data) +{ + struct ipack_device *idev = to_ipack_dev(dev); + struct ipack_bus_device *bus = data; + + if (idev->bus_nr == bus->bus_nr) + ipack_device_unregister(idev); + + return 1; +} + int ipack_bus_unregister(struct ipack_bus_device *bus) { + bus_for_each_dev(&ipack_bus_type, NULL, bus, ipack_unregister_bus_member); ida_simple_remove(&ipack_ida, bus->bus_nr); kfree(bus); return 0; @@ -102,7 +250,7 @@ int ipack_bus_unregister(struct ipack_bus_device *bus) EXPORT_SYMBOL_GPL(ipack_bus_unregister); int ipack_driver_register(struct ipack_driver *edrv, struct module *owner, - char *name) + const char *name) { edrv->driver.owner = owner; edrv->driver.name = name; @@ -117,8 +265,169 @@ void ipack_driver_unregister(struct ipack_driver *edrv) } EXPORT_SYMBOL_GPL(ipack_driver_unregister); +static u16 ipack_crc_byte(u16 crc, u8 c) +{ + int i; + + crc ^= c << 8; + for (i = 0; i < 8; i++) + crc = (crc << 1) ^ ((crc & 0x8000) ? 0x1021 : 0); + return crc; +} + +/* + * The algorithm in lib/crc-ccitt.c does not seem to apply since it uses the + * opposite bit ordering. + */ +static u8 ipack_calc_crc1(struct ipack_device *dev) +{ + u8 c; + u16 crc; + unsigned int i; + + crc = 0xffff; + for (i = 0; i < dev->id_avail; i++) { + c = (i != 11) ? dev->id[i] : 0; + crc = ipack_crc_byte(crc, c); + } + crc = ~crc; + return crc & 0xff; +} + +static u16 ipack_calc_crc2(struct ipack_device *dev) +{ + u8 c; + u16 crc; + unsigned int i; + + crc = 0xffff; + for (i = 0; i < dev->id_avail; i++) { + c = ((i != 0x18) && (i != 0x19)) ? dev->id[i] : 0; + crc = ipack_crc_byte(crc, c); + } + crc = ~crc; + return crc; +} + +static void ipack_parse_id1(struct ipack_device *dev) +{ + u8 *id = dev->id; + u8 crc; + + dev->id_vendor = id[4]; + dev->id_device = id[5]; + dev->speed_8mhz = 1; + dev->speed_32mhz = (id[7] == 'H'); + crc = ipack_calc_crc1(dev); + dev->id_crc_correct = (crc == id[11]); + if (!dev->id_crc_correct) { + dev_warn(&dev->dev, "ID CRC invalid found 0x%x, expected 0x%x.\n", + id[11], crc); + } +} + +static void ipack_parse_id2(struct ipack_device *dev) +{ + __be16 *id = (__be16 *) dev->id; + u16 flags, crc; + + dev->id_vendor = ((be16_to_cpu(id[3]) & 0xff) << 16) + + be16_to_cpu(id[4]); + dev->id_device = be16_to_cpu(id[5]); + flags = be16_to_cpu(id[10]); + dev->speed_8mhz = !!(flags & 2); + dev->speed_32mhz = !!(flags & 4); + crc = ipack_calc_crc2(dev); + dev->id_crc_correct = (crc == be16_to_cpu(id[12])); + if (!dev->id_crc_correct) { + dev_warn(&dev->dev, "ID CRC invalid found 0x%x, expected 0x%x.\n", + id[11], crc); + } +} + +static int ipack_device_read_id(struct ipack_device *dev) +{ + u8 __iomem *idmem; + int i; + int ret = 0; + + ret = dev->bus->ops->map_space(dev, 0, IPACK_ID_SPACE); + if (ret) { + dev_err(&dev->dev, "error mapping memory\n"); + return ret; + } + idmem = dev->id_space.address; + + /* Determine ID PROM Data Format. If we find the ids "IPAC" or "IPAH" + * we are dealing with a IndustryPack format 1 device. If we detect + * "VITA4 " (16 bit big endian formatted) we are dealing with a + * IndustryPack format 2 device */ + if ((ioread8(idmem + 1) == 'I') && + (ioread8(idmem + 3) == 'P') && + (ioread8(idmem + 5) == 'A') && + ((ioread8(idmem + 7) == 'C') || + (ioread8(idmem + 7) == 'H'))) { + dev->id_format = IPACK_ID_VERSION_1; + dev->id_avail = ioread8(idmem + 0x15); + if ((dev->id_avail < 0x0c) || (dev->id_avail > 0x40)) { + dev_warn(&dev->dev, "invalid id size"); + dev->id_avail = 0x0c; + } + } else if ((ioread8(idmem + 0) == 'I') && + (ioread8(idmem + 1) == 'V') && + (ioread8(idmem + 2) == 'A') && + (ioread8(idmem + 3) == 'T') && + (ioread8(idmem + 4) == ' ') && + (ioread8(idmem + 5) == '4')) { + dev->id_format = IPACK_ID_VERSION_2; + dev->id_avail = ioread16be(idmem + 0x16); + if ((dev->id_avail < 0x1a) || (dev->id_avail > 0x40)) { + dev_warn(&dev->dev, "invalid id size"); + dev->id_avail = 0x1a; + } + } else { + dev->id_format = IPACK_ID_VERSION_INVALID; + dev->id_avail = 0; + } + + if (!dev->id_avail) { + ret = -ENODEV; + goto out; + } + + /* Obtain the amount of memory required to store a copy of the complete + * ID ROM contents */ + dev->id = kmalloc(dev->id_avail, GFP_KERNEL); + if (!dev->id) { + dev_err(&dev->dev, "dev->id alloc failed.\n"); + ret = -ENOMEM; + goto out; + } + for (i = 0; i < dev->id_avail; i++) { + if (dev->id_format == IPACK_ID_VERSION_1) + dev->id[i] = ioread8(idmem + (i << 1) + 1); + else + dev->id[i] = ioread8(idmem + i); + } + + /* now we can finally work with the copy */ + switch (dev->id_format) { + case IPACK_ID_VERSION_1: + ipack_parse_id1(dev); + break; + case IPACK_ID_VERSION_2: + ipack_parse_id2(dev); + break; + } + +out: + dev->bus->ops->unmap_space(dev, IPACK_ID_SPACE); + + return ret; +} + struct ipack_device *ipack_device_register(struct ipack_bus_device *bus, - int slot, int irqv) + int slot) { int ret; struct ipack_device *dev; @@ -132,13 +441,32 @@ struct ipack_device *ipack_device_register(struct ipack_bus_device *bus, dev->dev.parent = bus->parent; dev->slot = slot; dev->bus_nr = bus->bus_nr; - dev->irq = irqv; dev->bus = bus; dev_set_name(&dev->dev, "ipack-dev.%u.%u", dev->bus_nr, dev->slot); + if (bus->ops->set_clockrate(dev, 8)) + dev_warn(&dev->dev, "failed to switch to 8 MHz operation for reading of device ID.\n"); + if (bus->ops->reset_timeout(dev)) + dev_warn(&dev->dev, "failed to reset potential timeout."); + + ret = ipack_device_read_id(dev); + if (ret < 0) { + dev_err(&dev->dev, "error reading device id section.\n"); + kfree(dev); + return NULL; + } + + /* if the device supports 32 MHz operation, use it. */ + if (dev->speed_32mhz) { + ret = bus->ops->set_clockrate(dev, 32); + if (ret < 0) + dev_err(&dev->dev, "failed to switch to 32 MHz operation.\n"); + } + ret = device_register(&dev->dev); if (ret < 0) { + kfree(dev->id); kfree(dev); return NULL; } diff --git a/drivers/staging/ipack/ipack.h b/drivers/staging/ipack/ipack.h index 8bc001e3ca4e..d8e3bb6feac8 100644 --- a/drivers/staging/ipack/ipack.h +++ b/drivers/staging/ipack/ipack.h @@ -9,7 +9,11 @@ * Software Foundation; version 2 of the License. */ +#include <linux/mod_devicetable.h> #include <linux/device.h> +#include <linux/interrupt.h> + +#include "ipack_ids.h" #define IPACK_IDPROM_OFFSET_I 0x01 #define IPACK_IDPROM_OFFSET_P 0x03 @@ -31,6 +35,7 @@ enum ipack_space { IPACK_IO_SPACE = 0, IPACK_ID_SPACE = 1, IPACK_MEM_SPACE = 2, + IPACK_INT_SPACE, }; /** @@ -49,8 +54,6 @@ struct ipack_addr_space { * * @bus_nr: IP bus number where the device is plugged * @slot: Slot where the device is plugged in the carrier board - * @irq: IRQ vector - * @driver: Pointer to the ipack_driver that manages the device * @bus: ipack_bus_device where the device is plugged to. * @id_space: Virtual address to ID space. * @io_space: Virtual address to IO space. @@ -64,25 +67,30 @@ struct ipack_addr_space { struct ipack_device { unsigned int bus_nr; unsigned int slot; - unsigned int irq; - struct ipack_driver *driver; struct ipack_bus_device *bus; struct ipack_addr_space id_space; struct ipack_addr_space io_space; + struct ipack_addr_space int_space; struct ipack_addr_space mem_space; struct device dev; + u8 *id; + size_t id_avail; + u32 id_vendor; + u32 id_device; + u8 id_format; + unsigned int id_crc_correct:1; + unsigned int speed_8mhz:1; + unsigned int speed_32mhz:1; }; /** * struct ipack_driver_ops -- callbacks to mezzanine driver for installing/removing one device * - * @match: Match function * @probe: Probe function * @remove: tell the driver that the carrier board wants to remove one device */ struct ipack_driver_ops { - int (*match) (struct ipack_device *dev); int (*probe) (struct ipack_device *dev); void (*remove) (struct ipack_device *dev); }; @@ -95,7 +103,8 @@ struct ipack_driver_ops { */ struct ipack_driver { struct device_driver driver; - struct ipack_driver_ops *ops; + const struct ipack_device_id *id_table; + const struct ipack_driver_ops *ops; }; /** @@ -105,26 +114,27 @@ struct ipack_driver { * @unmap_space: unmap IP address space * @request_irq: request IRQ * @free_irq: free IRQ - * @read8: read unsigned char - * @read16: read unsigned short - * @read32: read unsigned int - * @write8: read unsigned char - * @write16: read unsigned short - * @write32: read unsigned int - * @remove_device: tell the bridge module that the device has been removed + * @get_clockrate: Returns the clockrate the carrier is currently + * communicating with the device at. + * @set_clockrate: Sets the clock-rate for carrier / module communication. + * Should return -EINVAL if the requested speed is not supported. + * @get_error: Returns the error state for the slot the device is attached + * to. + * @get_timeout: Returns 1 if the communication with the device has + * previously timed out. + * @reset_timeout: Resets the state returned by get_timeout. */ struct ipack_bus_ops { int (*map_space) (struct ipack_device *dev, unsigned int memory_size, int space); int (*unmap_space) (struct ipack_device *dev, int space); - int (*request_irq) (struct ipack_device *dev, int vector, int (*handler)(void *), void *arg); + int (*request_irq) (struct ipack_device *dev, + irqreturn_t (*handler)(void *), void *arg); int (*free_irq) (struct ipack_device *dev); - int (*read8) (struct ipack_device *dev, int space, unsigned long offset, unsigned char *value); - int (*read16) (struct ipack_device *dev, int space, unsigned long offset, unsigned short *value); - int (*read32) (struct ipack_device *dev, int space, unsigned long offset, unsigned int *value); - int (*write8) (struct ipack_device *dev, int space, unsigned long offset, unsigned char value); - int (*write16) (struct ipack_device *dev, int space, unsigned long offset, unsigned short value); - int (*write32) (struct ipack_device *dev, int space, unsigned long offset, unsigned int value); - int (*remove_device) (struct ipack_device *dev); + int (*get_clockrate) (struct ipack_device *dev); + int (*set_clockrate) (struct ipack_device *dev, int mherz); + int (*get_error) (struct ipack_device *dev); + int (*get_timeout) (struct ipack_device *dev); + int (*reset_timeout) (struct ipack_device *dev); }; /** @@ -139,7 +149,7 @@ struct ipack_bus_device { struct device *parent; int slots; int bus_nr; - struct ipack_bus_ops *ops; + const struct ipack_bus_ops *ops; }; /** @@ -153,7 +163,7 @@ struct ipack_bus_device { * available bus device in ipack. */ struct ipack_bus_device *ipack_bus_register(struct device *parent, int slots, - struct ipack_bus_ops *ops); + const struct ipack_bus_ops *ops); /** * ipack_bus_unregister -- unregister an ipack bus @@ -166,7 +176,8 @@ int ipack_bus_unregister(struct ipack_bus_device *bus); * Called by a ipack driver to register itself as a driver * that can manage ipack devices. */ -int ipack_driver_register(struct ipack_driver *edrv, struct module *owner, char *name); +int ipack_driver_register(struct ipack_driver *edrv, struct module *owner, + const char *name); void ipack_driver_unregister(struct ipack_driver *edrv); /** @@ -174,10 +185,33 @@ void ipack_driver_unregister(struct ipack_driver *edrv); * * @bus: ipack bus device it is plugged to. * @slot: slot position in the bus device. - * @irqv: IRQ vector for the mezzanine. * * Register a new ipack device (mezzanine device). The call is done by * the carrier device driver. */ -struct ipack_device *ipack_device_register(struct ipack_bus_device *bus, int slot, int irqv); +struct ipack_device *ipack_device_register(struct ipack_bus_device *bus, int slot); void ipack_device_unregister(struct ipack_device *dev); + +/** + * DEFINE_IPACK_DEVICE_TABLE - macro used to describe a IndustryPack table + * @_table: device table name + * + * This macro is used to create a struct ipack_device_id array (a device table) + * in a generic manner. + */ +#define DEFINE_IPACK_DEVICE_TABLE(_table) \ + const struct ipack_device_id _table[] __devinitconst + +/** + * IPACK_DEVICE - macro used to describe a specific IndustryPack device + * @_format: the format version (currently either 1 or 2, 8 bit value) + * @vend: the 8 or 24 bit IndustryPack Vendor ID + * @dev: the 8 or 16 bit IndustryPack Device ID + * + * This macro is used to create a struct ipack_device_id that matches a specific + * device. + */ +#define IPACK_DEVICE(_format, vend, dev) \ + .format = (_format), \ + .vendor = (vend), \ + .device = (dev) diff --git a/drivers/staging/ipack/ipack_ids.h b/drivers/staging/ipack/ipack_ids.h new file mode 100644 index 000000000000..8153fee3f2f7 --- /dev/null +++ b/drivers/staging/ipack/ipack_ids.h @@ -0,0 +1,32 @@ +/* + * IndustryPack Fromat, Vendor and Device IDs. + */ + +/* ID section format versions */ +#define IPACK_ID_VERSION_INVALID 0x00 +#define IPACK_ID_VERSION_1 0x01 +#define IPACK_ID_VERSION_2 0x02 + +/* Vendors and devices. Sort key: vendor first, device next. */ +#define IPACK1_VENDOR_ID_RESERVED1 0x00 +#define IPACK1_VENDOR_ID_RESERVED2 0xFF +#define IPACK1_VENDOR_ID_UNREGISTRED01 0x01 +#define IPACK1_VENDOR_ID_UNREGISTRED02 0x02 +#define IPACK1_VENDOR_ID_UNREGISTRED03 0x03 +#define IPACK1_VENDOR_ID_UNREGISTRED04 0x04 +#define IPACK1_VENDOR_ID_UNREGISTRED05 0x05 +#define IPACK1_VENDOR_ID_UNREGISTRED06 0x06 +#define IPACK1_VENDOR_ID_UNREGISTRED07 0x07 +#define IPACK1_VENDOR_ID_UNREGISTRED08 0x08 +#define IPACK1_VENDOR_ID_UNREGISTRED09 0x09 +#define IPACK1_VENDOR_ID_UNREGISTRED10 0x0A +#define IPACK1_VENDOR_ID_UNREGISTRED11 0x0B +#define IPACK1_VENDOR_ID_UNREGISTRED12 0x0C +#define IPACK1_VENDOR_ID_UNREGISTRED13 0x0D +#define IPACK1_VENDOR_ID_UNREGISTRED14 0x0E +#define IPACK1_VENDOR_ID_UNREGISTRED15 0x0F + +#define IPACK1_VENDOR_ID_SBS 0xF0 +#define IPACK1_DEVICE_ID_SBS_OCTAL_232 0x22 +#define IPACK1_DEVICE_ID_SBS_OCTAL_422 0x2A +#define IPACK1_DEVICE_ID_SBS_OCTAL_485 0x48 diff --git a/drivers/staging/keucr/smcommon.h b/drivers/staging/keucr/smcommon.h index 278bdb871129..4d57203b64d8 100644 --- a/drivers/staging/keucr/smcommon.h +++ b/drivers/staging/keucr/smcommon.h @@ -25,7 +25,5 @@ Define Difinetion #define ERR_NoSmartMedia 0x003A /* Medium Not Present */ /***************************************************************************/ -void StringCopy(char *, char *, int); -int StringCmp(char *, char *, int); #endif diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c index 5e319e3ce685..7fe44a6fd0ed 100644 --- a/drivers/staging/line6/pcm.c +++ b/drivers/staging/line6/pcm.c @@ -48,7 +48,13 @@ static ssize_t pcm_set_impulse_volume(struct device *dev, const char *buf, size_t count) { struct snd_line6_pcm *line6pcm = dev2pcm(dev); - int value = simple_strtoul(buf, NULL, 10); + int value; + int rv; + + rv = kstrtoint(buf, 10, &value); + if (rv < 0) + return rv; + line6pcm->impulse_volume = value; if (value > 0) diff --git a/drivers/staging/line6/variax.c b/drivers/staging/line6/variax.c index bb99ee4919e7..f97416b1de54 100644 --- a/drivers/staging/line6/variax.c +++ b/drivers/staging/line6/variax.c @@ -353,10 +353,10 @@ static ssize_t variax_set_model(struct device *dev, { struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev)); - unsigned long value; + u8 value; int ret; - ret = strict_strtoul(buf, 10, &value); + ret = kstrtou8(buf, 10, &value); if (ret) return ret; @@ -387,10 +387,10 @@ static ssize_t variax_set_active(struct device *dev, { struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev)); - unsigned long value; + u8 value; int ret; - ret = strict_strtoul(buf, 10, &value); + ret = kstrtou8(buf, 10, &value); if (ret) return ret; diff --git a/drivers/staging/nvec/Kconfig b/drivers/staging/nvec/Kconfig index 43048e9ba0d4..1235a7897d04 100644 --- a/drivers/staging/nvec/Kconfig +++ b/drivers/staging/nvec/Kconfig @@ -28,7 +28,7 @@ config NVEC_POWER config NVEC_PAZ00 bool "Support for OEM specific functions on Compal PAZ00 based devices" - depends on MFD_NVEC && LEDS_CLASS && MACH_PAZ00 + depends on MFD_NVEC && LEDS_CLASS help Say Y to enable control of the yellow side leds on Compal PAZ00 based devices, e.g. Toshbia AC100 and Dynabooks AZ netbooks. diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c index d0a7e408efe9..24d8eebc1d10 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c @@ -264,7 +264,7 @@ int nvec_write_async(struct nvec_chip *nvec, const unsigned char *data, list_add_tail(&msg->node, &nvec->tx_data); spin_unlock_irqrestore(&nvec->tx_lock, flags); - queue_work(nvec->wq, &nvec->tx_work); + queue_work(system_nrt_wq, &nvec->tx_work); return 0; } @@ -294,8 +294,10 @@ struct nvec_msg *nvec_write_sync(struct nvec_chip *nvec, nvec->sync_write_pending = (data[1] << 8) + data[0]; - if (nvec_write_async(nvec, data, size) < 0) + if (nvec_write_async(nvec, data, size) < 0) { + mutex_unlock(&nvec->sync_write_mutex); return NULL; + } dev_dbg(nvec->dev, "nvec_sync_write: 0x%04x\n", nvec->sync_write_pending); @@ -366,8 +368,7 @@ static void nvec_request_master(struct work_struct *work) static int parse_msg(struct nvec_chip *nvec, struct nvec_msg *msg) { if ((msg->data[0] & 1 << 7) == 0 && msg->data[3]) { - dev_err(nvec->dev, "ec responded %02x %02x %02x %02x\n", - msg->data[0], msg->data[1], msg->data[2], msg->data[3]); + dev_err(nvec->dev, "ec responded %*ph\n", 4, msg->data); return -EINVAL; } @@ -470,7 +471,7 @@ static void nvec_rx_completed(struct nvec_chip *nvec) if (!nvec_msg_is_event(nvec->rx)) complete(&nvec->ec_transfer); - queue_work(nvec->wq, &nvec->rx_work); + queue_work(system_nrt_wq, &nvec->rx_work); } /** @@ -737,12 +738,14 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev) nvec->gpio = pdata->gpio; nvec->i2c_addr = pdata->i2c_addr; } else if (nvec->dev->of_node) { - nvec->gpio = of_get_named_gpio(nvec->dev->of_node, "request-gpios", 0); + nvec->gpio = of_get_named_gpio(nvec->dev->of_node, + "request-gpios", 0); if (nvec->gpio < 0) { dev_err(&pdev->dev, "no gpio specified"); return -ENODEV; } - if (of_property_read_u32(nvec->dev->of_node, "slave-addr", &nvec->i2c_addr)) { + if (of_property_read_u32(nvec->dev->of_node, + "slave-addr", &nvec->i2c_addr)) { dev_err(&pdev->dev, "no i2c address specified"); return -ENODEV; } @@ -769,7 +772,7 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev) return -ENODEV; } - i2c_clk = clk_get_sys("tegra-i2c.2", NULL); + i2c_clk = clk_get_sys("tegra-i2c.2", "div-clk"); if (IS_ERR(i2c_clk)) { dev_err(nvec->dev, "failed to get controller clock\n"); return -ENODEV; @@ -791,13 +794,11 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev) INIT_LIST_HEAD(&nvec->tx_data); INIT_WORK(&nvec->rx_work, nvec_dispatch); INIT_WORK(&nvec->tx_work, nvec_request_master); - nvec->wq = alloc_workqueue("nvec", WQ_NON_REENTRANT, 2); err = devm_gpio_request_one(&pdev->dev, nvec->gpio, GPIOF_OUT_INIT_HIGH, "nvec gpio"); if (err < 0) { dev_err(nvec->dev, "couldn't request gpio\n"); - destroy_workqueue(nvec->wq); return -ENODEV; } @@ -805,7 +806,6 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev) "nvec", nvec); if (err) { dev_err(nvec->dev, "couldn't request irq\n"); - destroy_workqueue(nvec->wq); return -ENODEV; } disable_irq(nvec->irq); @@ -859,7 +859,8 @@ static int __devexit tegra_nvec_remove(struct platform_device *pdev) nvec_write_async(nvec, EC_DISABLE_EVENT_REPORTING, 3); mfd_remove_devices(nvec->dev); - destroy_workqueue(nvec->wq); + cancel_work_sync(&nvec->rx_work); + cancel_work_sync(&nvec->tx_work); return 0; } diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c index 2c4bd746715a..d49c32a95690 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon.c +++ b/drivers/staging/olpc_dcon/olpc_dcon.c @@ -11,6 +11,7 @@ * License as published by the Free Software Foundation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/kernel.h> #include <linux/fb.h> @@ -72,18 +73,16 @@ static int dcon_hw_init(struct dcon_priv *dcon, int is_init) ver = dcon_read(dcon, DCON_REG_ID); if ((ver >> 8) != 0xDC) { - printk(KERN_ERR "olpc-dcon: DCON ID not 0xDCxx: 0x%04x instead.\n", - ver); + pr_err("DCON ID not 0xDCxx: 0x%04x instead.\n", ver); rc = -ENXIO; goto err; } if (is_init) { - printk(KERN_INFO "olpc-dcon: Discovered DCON version %x\n", - ver & 0xFF); + pr_info("Discovered DCON version %x\n", ver & 0xFF); rc = pdata->init(dcon); if (rc != 0) { - printk(KERN_ERR "olpc-dcon: Unable to init.\n"); + pr_err("Unable to init.\n"); goto err; } } @@ -137,8 +136,7 @@ power_up: x = 1; x = olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0); if (x) { - printk(KERN_WARNING "olpc-dcon: unable to force dcon to power up: %d!\n", - x); + pr_warn("unable to force dcon to power up: %d!\n", x); return x; } msleep(10); /* we'll be conservative */ @@ -151,7 +149,7 @@ power_up: x = dcon_read(dcon, DCON_REG_ID); } if (x < 0) { - printk(KERN_ERR "olpc-dcon: unable to stabilize dcon's smbus, reasserting power and praying.\n"); + pr_err("unable to stabilize dcon's smbus, reasserting power and praying.\n"); BUG_ON(olpc_board_at_least(olpc_board(0xc2))); x = 0; olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0); @@ -222,8 +220,7 @@ static void dcon_sleep(struct dcon_priv *dcon, bool sleep) x = 0; x = olpc_ec_cmd(0x26, (unsigned char *)&x, 1, NULL, 0); if (x) - printk(KERN_WARNING "olpc-dcon: unable to force dcon to power down: %d!\n", - x); + pr_warn("unable to force dcon to power down: %d!\n", x); else dcon->asleep = sleep; } else { @@ -232,8 +229,7 @@ static void dcon_sleep(struct dcon_priv *dcon, bool sleep) dcon->disp_mode |= MODE_BL_ENABLE; x = dcon_bus_stabilize(dcon, 1); if (x) - printk(KERN_WARNING "olpc-dcon: unable to reinit dcon hardware: %d!\n", - x); + pr_warn("unable to reinit dcon hardware: %d!\n", x); else dcon->asleep = sleep; @@ -304,12 +300,11 @@ static void dcon_source_switch(struct work_struct *work) switch (source) { case DCON_SOURCE_CPU: - printk(KERN_INFO "dcon_source_switch to CPU\n"); + pr_info("dcon_source_switch to CPU\n"); /* Enable the scanline interrupt bit */ if (dcon_write(dcon, DCON_REG_MODE, dcon->disp_mode | MODE_SCAN_INT)) - printk(KERN_ERR - "olpc-dcon: couldn't enable scanline interrupt!\n"); + pr_err("couldn't enable scanline interrupt!\n"); else { /* Wait up to one second for the scanline interrupt */ wait_event_timeout(dcon_wait_queue, @@ -317,11 +312,11 @@ static void dcon_source_switch(struct work_struct *work) } if (!dcon->switched) - printk(KERN_ERR "olpc-dcon: Timeout entering CPU mode; expect a screen glitch.\n"); + pr_err("Timeout entering CPU mode; expect a screen glitch.\n"); /* Turn off the scanline interrupt */ if (dcon_write(dcon, DCON_REG_MODE, dcon->disp_mode)) - printk(KERN_ERR "olpc-dcon: couldn't disable scanline interrupt!\n"); + pr_err("couldn't disable scanline interrupt!\n"); /* * Ideally we'd like to disable interrupts here so that the @@ -332,7 +327,7 @@ static void dcon_source_switch(struct work_struct *work) * For now, we just hope.. */ if (!dcon_blank_fb(dcon, false)) { - printk(KERN_ERR "olpc-dcon: Failed to enter CPU mode\n"); + pr_err("Failed to enter CPU mode\n"); dcon->pending_src = DCON_SOURCE_DCON; return; } @@ -341,14 +336,14 @@ static void dcon_source_switch(struct work_struct *work) pdata->set_dconload(1); getnstimeofday(&dcon->load_time); - printk(KERN_INFO "olpc-dcon: The CPU has control\n"); + pr_info("The CPU has control\n"); break; case DCON_SOURCE_DCON: { int t; struct timespec delta_t; - printk(KERN_INFO "dcon_source_switch to DCON\n"); + pr_info("dcon_source_switch to DCON\n"); add_wait_queue(&dcon_wait_queue, &wait); set_current_state(TASK_UNINTERRUPTIBLE); @@ -362,7 +357,7 @@ static void dcon_source_switch(struct work_struct *work) set_current_state(TASK_RUNNING); if (!dcon->switched) { - printk(KERN_ERR "olpc-dcon: Timeout entering DCON mode; expect a screen glitch.\n"); + pr_err("Timeout entering DCON mode; expect a screen glitch.\n"); } else { /* sometimes the DCON doesn't follow its own rules, * and doesn't wait for two vsync pulses before @@ -378,7 +373,7 @@ static void dcon_source_switch(struct work_struct *work) delta_t = timespec_sub(dcon->irq_time, dcon->load_time); if (dcon->switched && delta_t.tv_sec == 0 && delta_t.tv_nsec < NSEC_PER_MSEC * 20) { - printk(KERN_ERR "olpc-dcon: missed loading, retrying\n"); + pr_err("missed loading, retrying\n"); pdata->set_dconload(1); mdelay(41); pdata->set_dconload(0); @@ -388,7 +383,7 @@ static void dcon_source_switch(struct work_struct *work) } dcon_blank_fb(dcon, true); - printk(KERN_INFO "olpc-dcon: The DCON has control\n"); + pr_info("The DCON has control\n"); break; } default: @@ -476,7 +471,7 @@ static ssize_t dcon_freeze_store(struct device *dev, if (ret) return ret; - printk(KERN_INFO "dcon_freeze_store: %lu\n", output); + pr_info("dcon_freeze_store: %lu\n", output); switch (output) { case 0: @@ -650,7 +645,7 @@ static int dcon_probe(struct i2c_client *client, const struct i2c_device_id *id) dcon_device = platform_device_alloc("dcon", -1); if (dcon_device == NULL) { - printk(KERN_ERR "dcon: Unable to create the DCON device\n"); + pr_err("Unable to create the DCON device\n"); rc = -ENOMEM; goto eirq; } @@ -658,7 +653,7 @@ static int dcon_probe(struct i2c_client *client, const struct i2c_device_id *id) platform_set_drvdata(dcon_device, dcon); if (rc) { - printk(KERN_ERR "dcon: Unable to add the DCON device\n"); + pr_err("Unable to add the DCON device\n"); goto edev; } @@ -762,7 +757,7 @@ irqreturn_t dcon_interrupt(int irq, void *id) switch (status & 3) { case 3: - printk(KERN_DEBUG "olpc-dcon: DCONLOAD_MISSED interrupt\n"); + pr_debug("DCONLOAD_MISSED interrupt\n"); break; case 2: /* switch to DCON mode */ @@ -784,9 +779,9 @@ irqreturn_t dcon_interrupt(int irq, void *id) dcon->switched = true; getnstimeofday(&dcon->irq_time); wake_up(&dcon_wait_queue); - printk(KERN_DEBUG "olpc-dcon: switching w/ status 0/0\n"); + pr_debug("switching w/ status 0/0\n"); } else { - printk(KERN_DEBUG "olpc-dcon: scanline interrupt w/CPU\n"); + pr_debug("scanline interrupt w/CPU\n"); } } diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c index c87fdfac4855..77e8eb5a5abd 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c +++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c @@ -10,6 +10,9 @@ * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/cs5535.h> #include <linux/gpio.h> #include <linux/delay.h> @@ -22,23 +25,23 @@ static int dcon_init_xo_1(struct dcon_priv *dcon) unsigned char lob; if (gpio_request(OLPC_GPIO_DCON_STAT0, "OLPC-DCON")) { - printk(KERN_ERR "olpc-dcon: failed to request STAT0 GPIO\n"); + pr_err("failed to request STAT0 GPIO\n"); return -EIO; } if (gpio_request(OLPC_GPIO_DCON_STAT1, "OLPC-DCON")) { - printk(KERN_ERR "olpc-dcon: failed to request STAT1 GPIO\n"); + pr_err("failed to request STAT1 GPIO\n"); goto err_gp_stat1; } if (gpio_request(OLPC_GPIO_DCON_IRQ, "OLPC-DCON")) { - printk(KERN_ERR "olpc-dcon: failed to request IRQ GPIO\n"); + pr_err("failed to request IRQ GPIO\n"); goto err_gp_irq; } if (gpio_request(OLPC_GPIO_DCON_LOAD, "OLPC-DCON")) { - printk(KERN_ERR "olpc-dcon: failed to request LOAD GPIO\n"); + pr_err("failed to request LOAD GPIO\n"); goto err_gp_load; } if (gpio_request(OLPC_GPIO_DCON_BLANK, "OLPC-DCON")) { - printk(KERN_ERR "olpc-dcon: failed to request BLANK GPIO\n"); + pr_err("failed to request BLANK GPIO\n"); goto err_gp_blank; } @@ -83,7 +86,7 @@ static int dcon_init_xo_1(struct dcon_priv *dcon) /* Register the interrupt handler */ if (request_irq(DCON_IRQ, &dcon_interrupt, 0, "DCON", dcon)) { - printk(KERN_ERR "olpc-dcon: failed to request DCON's irq\n"); + pr_err("failed to request DCON's irq\n"); goto err_req_irq; } diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c index 69415eec425c..352dd3db0132 100644 --- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c +++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1_5.c @@ -6,6 +6,8 @@ * License as published by the Free Software Foundation. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/acpi.h> #include <linux/delay.h> #include <linux/pci.h> @@ -66,7 +68,7 @@ static int dcon_init_xo_1_5(struct dcon_priv *dcon) pdev = pci_get_device(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855, NULL); if (!pdev) { - printk(KERN_ERR "cannot find VX855 PCI ID\n"); + pr_err("cannot find VX855 PCI ID\n"); return 1; } @@ -104,7 +106,7 @@ static int dcon_init_xo_1_5(struct dcon_priv *dcon) /* we're sharing the IRQ with ACPI */ irq = acpi_gbl_FADT.sci_interrupt; if (request_irq(irq, &dcon_interrupt, IRQF_SHARED, "DCON", dcon)) { - printk(KERN_ERR PREFIX "DCON (IRQ%d) allocation failed\n", irq); + pr_err("DCON (IRQ%d) allocation failed\n", irq); return 1; } diff --git a/drivers/staging/omap-thermal/omap-bandgap.c b/drivers/staging/omap-thermal/omap-bandgap.c index c556abb63a17..368a2e19b2d4 100644 --- a/drivers/staging/omap-thermal/omap-bandgap.c +++ b/drivers/staging/omap-thermal/omap-bandgap.c @@ -157,7 +157,7 @@ static int temp_to_adc_conversion(long temp, struct omap_bandgap *bg_ptr, int i, high = ts_data->adc_end_val - ts_data->adc_start_val; mid = (high + low) / 2; - if (temp < bg_ptr->conv_table[high] || temp > bg_ptr->conv_table[high]) + if (temp < bg_ptr->conv_table[low] || temp > bg_ptr->conv_table[high]) return -EINVAL; while (low < high) { @@ -953,12 +953,12 @@ int __devinit omap_bandgap_probe(struct platform_device *pdev) for (i = 0; i < bg_ptr->conf->sensor_count; i++) { char *domain; + if (bg_ptr->conf->sensors[i].register_cooling) + bg_ptr->conf->sensors[i].register_cooling(bg_ptr, i); + domain = bg_ptr->conf->sensors[i].domain; if (bg_ptr->conf->expose_sensor) bg_ptr->conf->expose_sensor(bg_ptr, i, domain); - - if (bg_ptr->conf->sensors[i].register_cooling) - bg_ptr->conf->sensors[i].register_cooling(bg_ptr, i); } /* @@ -1037,20 +1037,20 @@ static int omap_bandgap_save_ctxt(struct omap_bandgap *bg_ptr) if (OMAP_BANDGAP_HAS(bg_ptr, MODE_CONFIG)) rval->bg_mode_ctrl = omap_bandgap_readl(bg_ptr, - tsr->bgap_mode_ctrl); + tsr->bgap_mode_ctrl); if (OMAP_BANDGAP_HAS(bg_ptr, COUNTER)) rval->bg_counter = omap_bandgap_readl(bg_ptr, - tsr->bgap_counter); + tsr->bgap_counter); if (OMAP_BANDGAP_HAS(bg_ptr, TALERT)) { rval->bg_threshold = omap_bandgap_readl(bg_ptr, - tsr->bgap_threshold); + tsr->bgap_threshold); rval->bg_ctrl = omap_bandgap_readl(bg_ptr, - tsr->bgap_mask_ctrl); + tsr->bgap_mask_ctrl); } if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT_CONFIG)) rval->tshut_threshold = omap_bandgap_readl(bg_ptr, - tsr->tshut_threshold); + tsr->tshut_threshold); } return 0; @@ -1074,8 +1074,9 @@ static int omap_bandgap_restore_ctxt(struct omap_bandgap *bg_ptr) if (val == 0) { if (OMAP_BANDGAP_HAS(bg_ptr, TSHUT_CONFIG)) - omap_bandgap_writel(bg_ptr, rval->tshut_threshold, - tsr->tshut_threshold); + omap_bandgap_writel(bg_ptr, + rval->tshut_threshold, + tsr->tshut_threshold); /* Force immediate temperature measurement and update * of the DTEMP field */ diff --git a/drivers/staging/omap-thermal/omap-thermal-common.c b/drivers/staging/omap-thermal/omap-thermal-common.c index 0675a5e2f7c8..46ee0a9f49d9 100644 --- a/drivers/staging/omap-thermal/omap-thermal-common.c +++ b/drivers/staging/omap-thermal/omap-thermal-common.c @@ -77,10 +77,16 @@ static inline int omap_thermal_get_temp(struct thermal_zone_device *thermal, unsigned long *temp) { struct omap_thermal_data *data = thermal->devdata; - struct omap_bandgap *bg_ptr = data->bg_ptr; - struct omap_temp_sensor *s = &bg_ptr->conf->sensors[data->sensor_id]; + struct omap_bandgap *bg_ptr; + struct omap_temp_sensor *s; int ret, tmp, pcb_temp, slope, constant; + if (!data) + return 0; + + bg_ptr = data->bg_ptr; + s = &bg_ptr->conf->sensors[data->sensor_id]; + ret = omap_bandgap_read_temperature(bg_ptr, data->sensor_id, &tmp); if (ret) return ret; @@ -227,26 +233,44 @@ static struct thermal_zone_device_ops omap_thermal_ops = { .get_crit_temp = omap_thermal_get_crit_temp, }; -int omap_thermal_expose_sensor(struct omap_bandgap *bg_ptr, int id, - char *domain) +static struct omap_thermal_data +*omap_thermal_build_data(struct omap_bandgap *bg_ptr, int id) { struct omap_thermal_data *data; data = devm_kzalloc(bg_ptr->dev, sizeof(*data), GFP_KERNEL); if (!data) { dev_err(bg_ptr->dev, "kzalloc fail\n"); - return -ENOMEM; + return NULL; } data->sensor_id = id; data->bg_ptr = bg_ptr; data->mode = THERMAL_DEVICE_ENABLED; INIT_WORK(&data->thermal_wq, omap_thermal_work); + return data; +} + +int omap_thermal_expose_sensor(struct omap_bandgap *bg_ptr, int id, + char *domain) +{ + struct omap_thermal_pdata pdata; + + data = omap_bandgap_get_sensor_data(bg_ptr, id); + + if (!data) + data = omap_thermal_build_pdata(bg_ptr, id); + + if (!data) + return -EINVAL; + /* TODO: remove TC1 TC2 */ /* Create thermal zone */ data->omap_thermal = thermal_zone_device_register(domain, OMAP_TRIP_NUMBER, 0, data, &omap_thermal_ops, - 0, FAST_TEMP_MONITORING_RATE, 0, 0); + 1, 2, /*TODO: remove this when FW allows */ + FAST_TEMP_MONITORING_RATE, + FAST_TEMP_MONITORING_RATE); if (IS_ERR_OR_NULL(data->omap_thermal)) { dev_err(bg_ptr->dev, "thermal zone device is NULL\n"); return PTR_ERR(data->omap_thermal); @@ -333,6 +357,11 @@ int omap_thermal_register_cpu_cooling(struct omap_bandgap *bg_ptr, int id) int tab_size, ret; data = omap_bandgap_get_sensor_data(bg_ptr, id); + if (!data) + data = omap_thermal_build_pdata(bg_ptr, id); + + if (!data) + return -EINVAL; ret = omap_thermal_build_cpufreq_clip(bg_ptr, &tab_ptr, &tab_size); if (ret < 0) { @@ -349,6 +378,7 @@ int omap_thermal_register_cpu_cooling(struct omap_bandgap *bg_ptr, int id) return PTR_ERR(data->cool_dev); } bg_ptr->conf->sensors[id].cooling_data.freq_clip_count = tab_size; + omap_bandgap_set_sensor_data(bg_ptr, id, data); return 0; } diff --git a/drivers/staging/omap-thermal/omap4-thermal.c b/drivers/staging/omap-thermal/omap4-thermal.c index fa9dbcd71830..04c02b6c0077 100644 --- a/drivers/staging/omap-thermal/omap4-thermal.c +++ b/drivers/staging/omap-thermal/omap4-thermal.c @@ -77,15 +77,15 @@ const struct omap_bandgap_data omap4430_data = { .remove_sensor = omap_thermal_remove_sensor, .sensors = { { - .registers = &omap4430_mpu_temp_sensor_registers, - .ts_data = &omap4430_mpu_temp_sensor_data, - .domain = "cpu", - .slope = 0, - .constant = 20000, - .slope_pcb = 0, - .constant_pcb = 20000, - .register_cooling = omap_thermal_register_cpu_cooling, - .unregister_cooling = omap_thermal_unregister_cpu_cooling, + .registers = &omap4430_mpu_temp_sensor_registers, + .ts_data = &omap4430_mpu_temp_sensor_data, + .domain = "cpu", + .slope = 0, + .constant = 20000, + .slope_pcb = 0, + .constant_pcb = 20000, + .register_cooling = omap_thermal_register_cpu_cooling, + .unregister_cooling = omap_thermal_unregister_cpu_cooling, }, }, .sensor_count = 1, @@ -215,15 +215,15 @@ const struct omap_bandgap_data omap4460_data = { .remove_sensor = omap_thermal_remove_sensor, .sensors = { { - .registers = &omap4460_mpu_temp_sensor_registers, - .ts_data = &omap4460_mpu_temp_sensor_data, - .domain = "cpu", - .slope = OMAP_GRADIENT_SLOPE_4460, - .constant = OMAP_GRADIENT_CONST_4460, - .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4460, - .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4460, - .register_cooling = omap_thermal_register_cpu_cooling, - .unregister_cooling = omap_thermal_unregister_cpu_cooling, + .registers = &omap4460_mpu_temp_sensor_registers, + .ts_data = &omap4460_mpu_temp_sensor_data, + .domain = "cpu", + .slope = OMAP_GRADIENT_SLOPE_4460, + .constant = OMAP_GRADIENT_CONST_4460, + .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4460, + .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4460, + .register_cooling = omap_thermal_register_cpu_cooling, + .unregister_cooling = omap_thermal_unregister_cpu_cooling, }, }, .sensor_count = 1, @@ -244,15 +244,15 @@ const struct omap_bandgap_data omap4470_data = { .remove_sensor = omap_thermal_remove_sensor, .sensors = { { - .registers = &omap4460_mpu_temp_sensor_registers, - .ts_data = &omap4460_mpu_temp_sensor_data, - .domain = "cpu", - .slope = OMAP_GRADIENT_SLOPE_4470, - .constant = OMAP_GRADIENT_CONST_4470, - .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4470, - .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4470, - .register_cooling = omap_thermal_register_cpu_cooling, - .unregister_cooling = omap_thermal_unregister_cpu_cooling, + .registers = &omap4460_mpu_temp_sensor_registers, + .ts_data = &omap4460_mpu_temp_sensor_data, + .domain = "cpu", + .slope = OMAP_GRADIENT_SLOPE_4470, + .constant = OMAP_GRADIENT_CONST_4470, + .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_4470, + .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_4470, + .register_cooling = omap_thermal_register_cpu_cooling, + .unregister_cooling = omap_thermal_unregister_cpu_cooling, }, }, .sensor_count = 1, diff --git a/drivers/staging/omap-thermal/omap5-thermal.c b/drivers/staging/omap-thermal/omap5-thermal.c index 0658af24a5c7..2f3a498dacd1 100644 --- a/drivers/staging/omap-thermal/omap5-thermal.c +++ b/drivers/staging/omap-thermal/omap5-thermal.c @@ -268,29 +268,29 @@ const struct omap_bandgap_data omap5430_data = { .remove_sensor = omap_thermal_remove_sensor, .sensors = { { - .registers = &omap5430_mpu_temp_sensor_registers, - .ts_data = &omap5430_mpu_temp_sensor_data, - .domain = "cpu", - .register_cooling = omap_thermal_register_cpu_cooling, - .unregister_cooling = omap_thermal_unregister_cpu_cooling, - .slope = OMAP_GRADIENT_SLOPE_5430_CPU, - .constant = OMAP_GRADIENT_CONST_5430_CPU, - .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_CPU, - .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_CPU, + .registers = &omap5430_mpu_temp_sensor_registers, + .ts_data = &omap5430_mpu_temp_sensor_data, + .domain = "cpu", + .register_cooling = omap_thermal_register_cpu_cooling, + .unregister_cooling = omap_thermal_unregister_cpu_cooling, + .slope = OMAP_GRADIENT_SLOPE_5430_CPU, + .constant = OMAP_GRADIENT_CONST_5430_CPU, + .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_CPU, + .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_CPU, }, { - .registers = &omap5430_gpu_temp_sensor_registers, - .ts_data = &omap5430_gpu_temp_sensor_data, - .domain = "gpu", - .slope = OMAP_GRADIENT_SLOPE_5430_GPU, - .constant = OMAP_GRADIENT_CONST_5430_GPU, - .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_GPU, - .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_GPU, + .registers = &omap5430_gpu_temp_sensor_registers, + .ts_data = &omap5430_gpu_temp_sensor_data, + .domain = "gpu", + .slope = OMAP_GRADIENT_SLOPE_5430_GPU, + .constant = OMAP_GRADIENT_CONST_5430_GPU, + .slope_pcb = OMAP_GRADIENT_SLOPE_W_PCB_5430_GPU, + .constant_pcb = OMAP_GRADIENT_CONST_W_PCB_5430_GPU, }, { - .registers = &omap5430_core_temp_sensor_registers, - .ts_data = &omap5430_core_temp_sensor_data, - .domain = "core", + .registers = &omap5430_core_temp_sensor_registers, + .ts_data = &omap5430_core_temp_sensor_data, + .domain = "core", }, }, .sensor_count = 3, diff --git a/drivers/staging/omapdrm/omap_crtc.c b/drivers/staging/omapdrm/omap_crtc.c index 62e0022561bc..732f2ad34036 100644 --- a/drivers/staging/omapdrm/omap_crtc.c +++ b/drivers/staging/omapdrm/omap_crtc.c @@ -155,6 +155,7 @@ static void page_flip_cb(void *arg) struct drm_crtc *crtc = arg; struct omap_crtc *omap_crtc = to_omap_crtc(crtc); struct drm_framebuffer *old_fb = omap_crtc->old_fb; + struct drm_gem_object *bo; omap_crtc->old_fb = NULL; @@ -165,6 +166,9 @@ static void page_flip_cb(void *arg) * cycle.. for now go for correctness and later figure out speed.. */ omap_plane_on_endwin(omap_crtc->plane, vblank_cb, crtc); + + bo = omap_framebuffer_bo(crtc->fb, 0); + drm_gem_object_unreference_unlocked(bo); } static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, @@ -173,6 +177,7 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, { struct drm_device *dev = crtc->dev; struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + struct drm_gem_object *bo; DBG("%d -> %d", crtc->fb ? crtc->fb->base.id : -1, fb->base.id); @@ -185,16 +190,38 @@ static int omap_crtc_page_flip_locked(struct drm_crtc *crtc, omap_crtc->event = event; crtc->fb = fb; - omap_gem_op_async(omap_framebuffer_bo(fb, 0), OMAP_GEM_READ, - page_flip_cb, crtc); + /* + * Hold a reference temporarily until the crtc is updated + * and takes the reference to the bo. This avoids it + * getting freed from under us: + */ + bo = omap_framebuffer_bo(fb, 0); + drm_gem_object_reference(bo); + + omap_gem_op_async(bo, OMAP_GEM_READ, page_flip_cb, crtc); return 0; } +static int omap_crtc_set_property(struct drm_crtc *crtc, + struct drm_property *property, uint64_t val) +{ + struct omap_crtc *omap_crtc = to_omap_crtc(crtc); + struct omap_drm_private *priv = crtc->dev->dev_private; + + if (property == priv->rotation_prop) { + crtc->invert_dimensions = + !!(val & ((1LL << DRM_ROTATE_90) | (1LL << DRM_ROTATE_270))); + } + + return omap_plane_set_property(omap_crtc->plane, property, val); +} + static const struct drm_crtc_funcs omap_crtc_funcs = { .set_config = drm_crtc_helper_set_config, .destroy = omap_crtc_destroy, .page_flip = omap_crtc_page_flip_locked, + .set_property = omap_crtc_set_property, }; static const struct drm_crtc_helper_funcs omap_crtc_helper_funcs = { @@ -231,6 +258,8 @@ struct drm_crtc *omap_crtc_init(struct drm_device *dev, drm_crtc_init(dev, crtc, &omap_crtc_funcs); drm_crtc_helper_add(crtc, &omap_crtc_helper_funcs); + omap_plane_install_properties(omap_crtc->plane, &crtc->base); + return crtc; fail: diff --git a/drivers/staging/omapdrm/omap_dmm_tiler.c b/drivers/staging/omapdrm/omap_dmm_tiler.c index 86197831f63e..3ae39554df18 100644 --- a/drivers/staging/omapdrm/omap_dmm_tiler.c +++ b/drivers/staging/omapdrm/omap_dmm_tiler.c @@ -120,7 +120,7 @@ static int wait_status(struct refill_engine *engine, uint32_t wait_mask) return 0; } -irqreturn_t omap_dmm_irq_handler(int irq, void *arg) +static irqreturn_t omap_dmm_irq_handler(int irq, void *arg) { struct dmm *dmm = arg; uint32_t status = readl(dmm->base + DMM_PAT_IRQSTATUS); @@ -367,7 +367,7 @@ struct tiler_block *tiler_reserve_1d(size_t size) int num_pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; if (!block) - return 0; + return ERR_PTR(-ENOMEM); block->fmt = TILFMT_PAGE; @@ -404,8 +404,26 @@ int tiler_release(struct tiler_block *block) * Utils */ -/* calculate the tiler space address of a pixel in a view orientation */ -static u32 tiler_get_address(u32 orient, enum tiler_fmt fmt, u32 x, u32 y) +/* calculate the tiler space address of a pixel in a view orientation... + * below description copied from the display subsystem section of TRM: + * + * When the TILER is addressed, the bits: + * [28:27] = 0x0 for 8-bit tiled + * 0x1 for 16-bit tiled + * 0x2 for 32-bit tiled + * 0x3 for page mode + * [31:29] = 0x0 for 0-degree view + * 0x1 for 180-degree view + mirroring + * 0x2 for 0-degree view + mirroring + * 0x3 for 180-degree view + * 0x4 for 270-degree view + mirroring + * 0x5 for 270-degree view + * 0x6 for 90-degree view + * 0x7 for 90-degree view + mirroring + * Otherwise the bits indicated the corresponding bit address to access + * the SDRAM. + */ +static u32 tiler_get_address(enum tiler_fmt fmt, u32 orient, u32 x, u32 y) { u32 x_bits, y_bits, tmp, x_mask, y_mask, alignment; @@ -417,8 +435,11 @@ static u32 tiler_get_address(u32 orient, enum tiler_fmt fmt, u32 x, u32 y) x_mask = MASK(x_bits); y_mask = MASK(y_bits); - if (x < 0 || x > x_mask || y < 0 || y > y_mask) + if (x < 0 || x > x_mask || y < 0 || y > y_mask) { + DBG("invalid coords: %u < 0 || %u > %u || %u < 0 || %u > %u", + x, x, x_mask, y, y, y_mask); return 0; + } /* account for mirroring */ if (orient & MASK_X_INVERT) @@ -439,11 +460,22 @@ dma_addr_t tiler_ssptr(struct tiler_block *block) { BUG_ON(!validfmt(block->fmt)); - return TILVIEW_8BIT + tiler_get_address(0, block->fmt, + return TILVIEW_8BIT + tiler_get_address(block->fmt, 0, block->area.p0.x * geom[block->fmt].slot_w, block->area.p0.y * geom[block->fmt].slot_h); } +dma_addr_t tiler_tsptr(struct tiler_block *block, uint32_t orient, + uint32_t x, uint32_t y) +{ + struct tcm_pt *p = &block->area.p0; + BUG_ON(!validfmt(block->fmt)); + + return tiler_get_address(block->fmt, orient, + (p->x * geom[block->fmt].slot_w) + x, + (p->y * geom[block->fmt].slot_h) + y); +} + void tiler_align(enum tiler_fmt fmt, uint16_t *w, uint16_t *h) { BUG_ON(!validfmt(fmt)); @@ -451,11 +483,14 @@ void tiler_align(enum tiler_fmt fmt, uint16_t *w, uint16_t *h) *h = round_up(*h, geom[fmt].slot_h); } -uint32_t tiler_stride(enum tiler_fmt fmt) +uint32_t tiler_stride(enum tiler_fmt fmt, uint32_t orient) { BUG_ON(!validfmt(fmt)); - return 1 << (CONT_WIDTH_BITS + geom[fmt].y_shft); + if (orient & MASK_XY_FLIP) + return 1 << (CONT_HEIGHT_BITS + geom[fmt].x_shft); + else + return 1 << (CONT_WIDTH_BITS + geom[fmt].y_shft); } size_t tiler_size(enum tiler_fmt fmt, uint16_t w, uint16_t h) diff --git a/drivers/staging/omapdrm/omap_dmm_tiler.h b/drivers/staging/omapdrm/omap_dmm_tiler.h index 7b1052a329e4..740911df5fc3 100644 --- a/drivers/staging/omapdrm/omap_dmm_tiler.h +++ b/drivers/staging/omapdrm/omap_dmm_tiler.h @@ -54,7 +54,18 @@ struct tiler_block { #define TILER_WIDTH (1 << (CONT_WIDTH_BITS - SLOT_WIDTH_BITS)) #define TILER_HEIGHT (1 << (CONT_HEIGHT_BITS - SLOT_HEIGHT_BITS)) -/* tiler space addressing bitfields */ +/* +Table 15-11. Coding and Description of TILER Orientations +S Y X Description Alternate description +0 0 0 0-degree view Natural view +0 0 1 0-degree view with vertical mirror 180-degree view with horizontal mirror +0 1 0 0-degree view with horizontal mirror 180-degree view with vertical mirror +0 1 1 180-degree view +1 0 0 90-degree view with vertical mirror 270-degree view with horizontal mirror +1 0 1 270-degree view +1 1 0 90-degree view +1 1 1 90-degree view with horizontal mirror 270-degree view with vertical mirror + */ #define MASK_XY_FLIP (1 << 31) #define MASK_Y_INVERT (1 << 30) #define MASK_X_INVERT (1 << 29) @@ -90,7 +101,9 @@ int tiler_release(struct tiler_block *block); /* utilities */ dma_addr_t tiler_ssptr(struct tiler_block *block); -uint32_t tiler_stride(enum tiler_fmt fmt); +dma_addr_t tiler_tsptr(struct tiler_block *block, uint32_t orient, + uint32_t x, uint32_t y); +uint32_t tiler_stride(enum tiler_fmt fmt, uint32_t orient); size_t tiler_size(enum tiler_fmt fmt, uint16_t w, uint16_t h); size_t tiler_vsize(enum tiler_fmt fmt, uint16_t w, uint16_t h); void tiler_align(enum tiler_fmt fmt, uint16_t *w, uint16_t *h); diff --git a/drivers/staging/omapdrm/omap_drv.c b/drivers/staging/omapdrm/omap_drv.c index 4beab9447ceb..2ec5264dd002 100644 --- a/drivers/staging/omapdrm/omap_drv.c +++ b/drivers/staging/omapdrm/omap_drv.c @@ -571,8 +571,7 @@ static int dev_load(struct drm_device *dev, unsigned long flags) dev->dev_private = priv; - priv->wq = alloc_workqueue("omapdrm", - WQ_UNBOUND | WQ_NON_REENTRANT, 1); + priv->wq = alloc_ordered_workqueue("omapdrm", 0); INIT_LIST_HEAD(&priv->obj_list); @@ -649,6 +648,8 @@ static int dev_firstopen(struct drm_device *dev) */ static void dev_lastclose(struct drm_device *dev) { + int i; + /* we don't support vga-switcheroo.. so just make sure the fbdev * mode is active */ @@ -657,6 +658,21 @@ static void dev_lastclose(struct drm_device *dev) DBG("lastclose: dev=%p", dev); + /* need to restore default rotation state.. not sure if there is + * a cleaner way to restore properties to default state? Maybe + * a flag that properties should automatically be restored to + * default state on lastclose? + */ + for (i = 0; i < priv->num_crtcs; i++) { + drm_object_property_set_value(&priv->crtcs[i]->base, + priv->rotation_prop, 0); + } + + for (i = 0; i < priv->num_planes; i++) { + drm_object_property_set_value(&priv->planes[i]->base, + priv->rotation_prop, 0); + } + ret = drm_fb_helper_restore_fbdev_mode(priv->fbdev); if (ret) DBG("failed to restore crtc mode"); @@ -761,7 +777,6 @@ static struct drm_driver omap_drm_driver = { .irq_postinstall = dev_irq_postinstall, .irq_uninstall = dev_irq_uninstall, .irq_handler = dev_irq_handler, - .reclaim_buffers = drm_core_reclaim_buffers, #ifdef CONFIG_DEBUG_FS .debugfs_init = omap_debugfs_init, .debugfs_cleanup = omap_debugfs_cleanup, diff --git a/drivers/staging/omapdrm/omap_drv.h b/drivers/staging/omapdrm/omap_drv.h index 2092a9167d29..9dc72d143ff3 100644 --- a/drivers/staging/omapdrm/omap_drv.h +++ b/drivers/staging/omapdrm/omap_drv.h @@ -59,6 +59,27 @@ struct omap_drm_private { struct list_head obj_list; bool has_dmm; + + /* properties: */ + struct drm_property *rotation_prop; + struct drm_property *zorder_prop; +}; + +/* this should probably be in drm-core to standardize amongst drivers */ +#define DRM_ROTATE_0 0 +#define DRM_ROTATE_90 1 +#define DRM_ROTATE_180 2 +#define DRM_ROTATE_270 3 +#define DRM_REFLECT_X 4 +#define DRM_REFLECT_Y 5 + +/* parameters which describe (unrotated) coordinates of scanout within a fb: */ +struct omap_drm_window { + uint32_t rotation; + int32_t crtc_x, crtc_y; /* signed because can be offscreen */ + uint32_t crtc_w, crtc_h; + uint32_t src_x, src_y; + uint32_t src_w, src_h; }; #ifdef CONFIG_DEBUG_FS @@ -87,6 +108,10 @@ int omap_plane_mode_set(struct drm_plane *plane, uint32_t src_w, uint32_t src_h); void omap_plane_on_endwin(struct drm_plane *plane, void (*fxn)(void *), void *arg); +void omap_plane_install_properties(struct drm_plane *plane, + struct drm_mode_object *obj); +int omap_plane_set_property(struct drm_plane *plane, + struct drm_property *property, uint64_t val); struct drm_encoder *omap_encoder_init(struct drm_device *dev, struct omap_overlay_manager *mgr); @@ -114,8 +139,8 @@ struct drm_gem_object *omap_framebuffer_bo(struct drm_framebuffer *fb, int p); int omap_framebuffer_replace(struct drm_framebuffer *a, struct drm_framebuffer *b, void *arg, void (*unpin)(void *arg, struct drm_gem_object *bo)); -void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, int x, int y, - struct omap_overlay_info *info); +void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, + struct omap_drm_window *win, struct omap_overlay_info *info); struct drm_connector *omap_framebuffer_get_next_connector( struct drm_framebuffer *fb, struct drm_connector *from); void omap_framebuffer_flush(struct drm_framebuffer *fb, @@ -157,8 +182,12 @@ int omap_gem_get_pages(struct drm_gem_object *obj, struct page ***pages, bool remap); int omap_gem_put_pages(struct drm_gem_object *obj); uint32_t omap_gem_flags(struct drm_gem_object *obj); +int omap_gem_rotated_paddr(struct drm_gem_object *obj, uint32_t orient, + int x, int y, dma_addr_t *paddr); uint64_t omap_gem_mmap_offset(struct drm_gem_object *obj); size_t omap_gem_mmap_size(struct drm_gem_object *obj); +int omap_gem_tiled_size(struct drm_gem_object *obj, uint16_t *w, uint16_t *h); +int omap_gem_tiled_stride(struct drm_gem_object *obj, uint32_t orient); struct dma_buf * omap_gem_prime_export(struct drm_device *dev, struct drm_gem_object *obj, int flags); diff --git a/drivers/staging/omapdrm/omap_fb.c b/drivers/staging/omapdrm/omap_fb.c index 74260f043ab1..446801d63007 100644 --- a/drivers/staging/omapdrm/omap_fb.c +++ b/drivers/staging/omapdrm/omap_fb.c @@ -18,6 +18,7 @@ */ #include "omap_drv.h" +#include "omap_dmm_tiler.h" #include "drm_crtc.h" #include "drm_crtc_helper.h" @@ -137,30 +138,100 @@ static const struct drm_framebuffer_funcs omap_framebuffer_funcs = { .dirty = omap_framebuffer_dirty, }; +static uint32_t get_linear_addr(struct plane *plane, + const struct format *format, int n, int x, int y) +{ + uint32_t offset; + + offset = plane->offset + + (x * format->planes[n].stride_bpp) + + (y * plane->pitch / format->planes[n].sub_y); + + return plane->paddr + offset; +} + /* update ovl info for scanout, handles cases of multi-planar fb's, etc. */ -void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, int x, int y, - struct omap_overlay_info *info) +void omap_framebuffer_update_scanout(struct drm_framebuffer *fb, + struct omap_drm_window *win, struct omap_overlay_info *info) { struct omap_framebuffer *omap_fb = to_omap_framebuffer(fb); const struct format *format = omap_fb->format; struct plane *plane = &omap_fb->planes[0]; - unsigned int offset; + uint32_t x, y, orient = 0; + + info->color_mode = format->dss_format; + + info->pos_x = win->crtc_x; + info->pos_y = win->crtc_y; + info->out_width = win->crtc_w; + info->out_height = win->crtc_h; + info->width = win->src_w; + info->height = win->src_h; + + x = win->src_x; + y = win->src_y; + + if (omap_gem_flags(plane->bo) & OMAP_BO_TILED) { + uint32_t w = win->src_w; + uint32_t h = win->src_h; + + switch (win->rotation & 0xf) { + default: + dev_err(fb->dev->dev, "invalid rotation: %02x", + (uint32_t)win->rotation); + /* fallthru to default to no rotation */ + case 0: + case BIT(DRM_ROTATE_0): + orient = 0; + break; + case BIT(DRM_ROTATE_90): + orient = MASK_XY_FLIP | MASK_X_INVERT; + break; + case BIT(DRM_ROTATE_180): + orient = MASK_X_INVERT | MASK_Y_INVERT; + break; + case BIT(DRM_ROTATE_270): + orient = MASK_XY_FLIP | MASK_Y_INVERT; + break; + } - offset = plane->offset + - (x * format->planes[0].stride_bpp) + - (y * plane->pitch / format->planes[0].sub_y); + if (win->rotation & BIT(DRM_REFLECT_X)) + orient ^= MASK_X_INVERT; + + if (win->rotation & BIT(DRM_REFLECT_Y)) + orient ^= MASK_Y_INVERT; + + /* adjust x,y offset for flip/invert: */ + if (orient & MASK_XY_FLIP) + swap(w, h); + if (orient & MASK_Y_INVERT) + y += h - 1; + if (orient & MASK_X_INVERT) + x += w - 1; - info->color_mode = format->dss_format; - info->paddr = plane->paddr + offset; - info->screen_width = plane->pitch / format->planes[0].stride_bpp; + omap_gem_rotated_paddr(plane->bo, orient, x, y, &info->paddr); + info->rotation_type = OMAP_DSS_ROT_TILER; + info->screen_width = omap_gem_tiled_stride(plane->bo, orient); + } else { + info->paddr = get_linear_addr(plane, format, 0, x, y); + info->rotation_type = OMAP_DSS_ROT_DMA; + info->screen_width = plane->pitch; + } + + /* convert to pixels: */ + info->screen_width /= format->planes[0].stride_bpp; if (format->dss_format == OMAP_DSS_COLOR_NV12) { plane = &omap_fb->planes[1]; - offset = plane->offset + - (x * format->planes[1].stride_bpp) + - (y * plane->pitch / format->planes[1].sub_y); - info->p_uv_addr = plane->paddr + offset; + + if (info->rotation_type == OMAP_DSS_ROT_TILER) { + WARN_ON(!(omap_gem_flags(plane->bo) & OMAP_BO_TILED)); + omap_gem_rotated_paddr(plane->bo, orient, + x/2, y/2, &info->p_uv_addr); + } else { + info->p_uv_addr = get_linear_addr(plane, format, 1, x, y); + } } else { info->p_uv_addr = 0; } @@ -377,7 +448,7 @@ struct drm_framebuffer *omap_framebuffer_init(struct drm_device *dev, size = pitch * mode_cmd->height / format->planes[i].sub_y; - if (size > (bos[i]->size - mode_cmd->offsets[i])) { + if (size > (omap_gem_mmap_size(bos[i]) - mode_cmd->offsets[i])) { dev_err(dev->dev, "provided buffer object is too small! %d < %d\n", bos[i]->size - mode_cmd->offsets[i], size); ret = -EINVAL; diff --git a/drivers/staging/omapdrm/omap_gem.c b/drivers/staging/omapdrm/omap_gem.c index 3a0d035a9e03..c8287438e0dc 100644 --- a/drivers/staging/omapdrm/omap_gem.c +++ b/drivers/staging/omapdrm/omap_gem.c @@ -226,7 +226,8 @@ static int omap_gem_attach_pages(struct drm_gem_object *obj) struct drm_device *dev = obj->dev; struct omap_gem_object *omap_obj = to_omap_bo(obj); struct page **pages; - int i, npages = obj->size >> PAGE_SHIFT; + int npages = obj->size >> PAGE_SHIFT; + int i, ret; dma_addr_t *addrs; WARN_ON(omap_obj->pages); @@ -246,18 +247,32 @@ static int omap_gem_attach_pages(struct drm_gem_object *obj) */ if (omap_obj->flags & (OMAP_BO_WC|OMAP_BO_UNCACHED)) { addrs = kmalloc(npages * sizeof(addrs), GFP_KERNEL); + if (!addrs) { + ret = -ENOMEM; + goto free_pages; + } + for (i = 0; i < npages; i++) { addrs[i] = dma_map_page(dev->dev, pages[i], 0, PAGE_SIZE, DMA_BIDIRECTIONAL); } } else { addrs = kzalloc(npages * sizeof(addrs), GFP_KERNEL); + if (!addrs) { + ret = -ENOMEM; + goto free_pages; + } } omap_obj->addrs = addrs; omap_obj->pages = pages; return 0; + +free_pages: + _drm_gem_put_pages(obj, pages, true, false); + + return ret; } /** release backing pages */ @@ -339,6 +354,17 @@ size_t omap_gem_mmap_size(struct drm_gem_object *obj) return size; } +/* get tiled size, returns -EINVAL if not tiled buffer */ +int omap_gem_tiled_size(struct drm_gem_object *obj, uint16_t *w, uint16_t *h) +{ + struct omap_gem_object *omap_obj = to_omap_bo(obj); + if (omap_obj->flags & OMAP_BO_TILED) { + *w = omap_obj->width; + *h = omap_obj->height; + return 0; + } + return -EINVAL; +} /* Normal handling for the case of faulting in non-tiled buffers */ static int fault_1d(struct drm_gem_object *obj, @@ -832,6 +858,36 @@ fail: return ret; } +/* Get rotated scanout address (only valid if already pinned), at the + * specified orientation and x,y offset from top-left corner of buffer + * (only valid for tiled 2d buffers) + */ +int omap_gem_rotated_paddr(struct drm_gem_object *obj, uint32_t orient, + int x, int y, dma_addr_t *paddr) +{ + struct omap_gem_object *omap_obj = to_omap_bo(obj); + int ret = -EINVAL; + + mutex_lock(&obj->dev->struct_mutex); + if ((omap_obj->paddr_cnt > 0) && omap_obj->block && + (omap_obj->flags & OMAP_BO_TILED)) { + *paddr = tiler_tsptr(omap_obj->block, orient, x, y); + ret = 0; + } + mutex_unlock(&obj->dev->struct_mutex); + return ret; +} + +/* Get tiler stride for the buffer (only valid for 2d tiled buffers) */ +int omap_gem_tiled_stride(struct drm_gem_object *obj, uint32_t orient) +{ + struct omap_gem_object *omap_obj = to_omap_bo(obj); + int ret = -EINVAL; + if (omap_obj->flags & OMAP_BO_TILED) + ret = tiler_stride(gem2fmt(omap_obj->flags), orient); + return ret; +} + /* acquire pages when needed (for example, for DMA where physically * contiguous buffer is not required */ @@ -1402,7 +1458,7 @@ void omap_gem_init(struct drm_device *dev) */ usergart[i].height = h; usergart[i].height_shift = ilog2(h); - usergart[i].stride_pfn = tiler_stride(fmts[i]) >> PAGE_SHIFT; + usergart[i].stride_pfn = tiler_stride(fmts[i], 0) >> PAGE_SHIFT; usergart[i].slot_shift = ilog2((PAGE_SIZE / h) >> i); for (j = 0; j < NUM_USERGART_ENTRIES; j++) { struct usergart_entry *entry = &usergart[i].entry[j]; diff --git a/drivers/staging/omapdrm/omap_plane.c b/drivers/staging/omapdrm/omap_plane.c index 7997be74010d..4bde639dd02c 100644 --- a/drivers/staging/omapdrm/omap_plane.c +++ b/drivers/staging/omapdrm/omap_plane.c @@ -20,6 +20,7 @@ #include <linux/kfifo.h> #include "omap_drv.h" +#include "omap_dmm_tiler.h" /* some hackery because omapdss has an 'enum omap_plane' (which would be * better named omap_plane_id).. and compiler seems unhappy about having @@ -43,10 +44,9 @@ struct omap_plane { struct omap_overlay *ovl; struct omap_overlay_info info; - /* Source values, converted to integers because we don't support - * fractional positions: - */ - unsigned int src_x, src_y; + /* position/orientation of scanout within the fb: */ + struct omap_drm_window win; + /* last fb that we pinned: */ struct drm_framebuffer *pinned_fb; @@ -289,6 +289,7 @@ static void update_scanout(struct drm_plane *plane) { struct omap_plane *omap_plane = to_omap_plane(plane); struct omap_overlay_info *info = &omap_plane->info; + struct omap_drm_window *win = &omap_plane->win; int ret; ret = update_pin(plane, plane->fb); @@ -299,11 +300,10 @@ static void update_scanout(struct drm_plane *plane) return; } - omap_framebuffer_update_scanout(plane->fb, - omap_plane->src_x, omap_plane->src_y, info); + omap_framebuffer_update_scanout(plane->fb, win, info); DBG("%s: %d,%d: %08x %08x (%d)", omap_plane->ovl->name, - omap_plane->src_x, omap_plane->src_y, + win->src_x, win->src_y, (u32)info->paddr, (u32)info->p_uv_addr, info->screen_width); } @@ -316,21 +316,18 @@ int omap_plane_mode_set(struct drm_plane *plane, uint32_t src_w, uint32_t src_h) { struct omap_plane *omap_plane = to_omap_plane(plane); + struct omap_drm_window *win = &omap_plane->win; + + win->crtc_x = crtc_x; + win->crtc_y = crtc_y; + win->crtc_w = crtc_w; + win->crtc_h = crtc_h; /* src values are in Q16 fixed point, convert to integer: */ - src_x = src_x >> 16; - src_y = src_y >> 16; - src_w = src_w >> 16; - src_h = src_h >> 16; - - omap_plane->info.pos_x = crtc_x; - omap_plane->info.pos_y = crtc_y; - omap_plane->info.out_width = crtc_w; - omap_plane->info.out_height = crtc_h; - omap_plane->info.width = src_w; - omap_plane->info.height = src_h; - omap_plane->src_x = src_x; - omap_plane->src_y = src_y; + win->src_x = src_x >> 16; + win->src_y = src_y >> 16; + win->src_w = src_w >> 16; + win->src_h = src_h >> 16; /* note: this is done after this fxn returns.. but if we need * to do a commit/update_scanout, etc before this returns we @@ -359,6 +356,8 @@ static int omap_plane_update(struct drm_plane *plane, static int omap_plane_disable(struct drm_plane *plane) { + struct omap_plane *omap_plane = to_omap_plane(plane); + omap_plane->win.rotation = BIT(DRM_ROTATE_0); return omap_plane_dpms(plane, DRM_MODE_DPMS_OFF); } @@ -409,10 +408,79 @@ void omap_plane_on_endwin(struct drm_plane *plane, install_irq(plane); } +/* helper to install properties which are common to planes and crtcs */ +void omap_plane_install_properties(struct drm_plane *plane, + struct drm_mode_object *obj) +{ + struct drm_device *dev = plane->dev; + struct omap_drm_private *priv = dev->dev_private; + struct drm_property *prop; + + prop = priv->rotation_prop; + if (!prop) { + const struct drm_prop_enum_list props[] = { + { DRM_ROTATE_0, "rotate-0" }, + { DRM_ROTATE_90, "rotate-90" }, + { DRM_ROTATE_180, "rotate-180" }, + { DRM_ROTATE_270, "rotate-270" }, + { DRM_REFLECT_X, "reflect-x" }, + { DRM_REFLECT_Y, "reflect-y" }, + }; + prop = drm_property_create_bitmask(dev, 0, "rotation", + props, ARRAY_SIZE(props)); + if (prop == NULL) + return; + priv->rotation_prop = prop; + } + drm_object_attach_property(obj, prop, 0); + + prop = priv->zorder_prop; + if (!prop) { + prop = drm_property_create_range(dev, 0, "zorder", 0, 3); + if (prop == NULL) + return; + priv->zorder_prop = prop; + } + drm_object_attach_property(obj, prop, 0); +} + +int omap_plane_set_property(struct drm_plane *plane, + struct drm_property *property, uint64_t val) +{ + struct omap_plane *omap_plane = to_omap_plane(plane); + struct omap_drm_private *priv = plane->dev->dev_private; + int ret = -EINVAL; + + if (property == priv->rotation_prop) { + struct omap_overlay *ovl = omap_plane->ovl; + + DBG("%s: rotation: %02x", ovl->name, (uint32_t)val); + omap_plane->win.rotation = val; + + if (ovl->is_enabled(ovl)) + ret = omap_plane_dpms(plane, DRM_MODE_DPMS_ON); + else + ret = 0; + } else if (property == priv->zorder_prop) { + struct omap_overlay *ovl = omap_plane->ovl; + + DBG("%s: zorder: %d", ovl->name, (uint32_t)val); + omap_plane->info.zorder = val; + + if (ovl->is_enabled(ovl)) + ret = omap_plane_dpms(plane, DRM_MODE_DPMS_ON); + else + ret = 0; + } + + return ret; +} + static const struct drm_plane_funcs omap_plane_funcs = { .update_plane = omap_plane_update, .disable_plane = omap_plane_disable, .destroy = omap_plane_destroy, + .set_property = omap_plane_set_property, }; /* initialize plane */ @@ -455,6 +523,8 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, drm_plane_init(dev, plane, possible_crtcs, &omap_plane_funcs, omap_plane->formats, omap_plane->nformats, priv); + omap_plane_install_properties(plane, &plane->base); + /* get our starting configuration, set defaults for parameters * we don't currently use, etc: */ @@ -463,7 +533,6 @@ struct drm_plane *omap_plane_init(struct drm_device *dev, omap_plane->info.rotation = OMAP_DSS_ROT_0; omap_plane->info.global_alpha = 0xff; omap_plane->info.mirror = 0; - omap_plane->info.mirror = 0; /* Set defaults depending on whether we are a CRTC or overlay * layer. diff --git a/drivers/staging/ozwpan/ozcdev.c b/drivers/staging/ozwpan/ozcdev.c index 758ce0a8d82e..64913aeb0bac 100644 --- a/drivers/staging/ozwpan/ozcdev.c +++ b/drivers/staging/ozwpan/ozcdev.c @@ -104,10 +104,10 @@ ssize_t oz_cdev_read(struct file *filp, char __user *buf, size_t count, if (pd) oz_pd_get(pd); spin_unlock_bh(&g_cdev.lock); - if (pd == 0) + if (pd == NULL) return -1; ctx = oz_cdev_claim_ctx(pd); - if (ctx == 0) + if (ctx == NULL) goto out2; n = ctx->rd_in - ctx->rd_out; if (n < 0) @@ -157,11 +157,11 @@ ssize_t oz_cdev_write(struct file *filp, const char __user *buf, size_t count, if (pd) oz_pd_get(pd); spin_unlock_bh(&g_cdev.lock); - if (pd == 0) + if (pd == NULL) return -1; eb = &pd->elt_buff; ei = oz_elt_info_alloc(eb); - if (ei == 0) { + if (ei == NULL) { count = 0; goto out; } @@ -410,7 +410,7 @@ int oz_cdev_start(struct oz_pd *pd, int resume) return 0; } ctx = kzalloc(sizeof(struct oz_serial_ctx), GFP_ATOMIC); - if (ctx == 0) + if (ctx == NULL) return -ENOMEM; atomic_set(&ctx->ref_count, 1); ctx->tx_seq_num = 1; @@ -424,7 +424,7 @@ int oz_cdev_start(struct oz_pd *pd, int resume) spin_unlock_bh(&pd->app_lock[OZ_APPID_SERIAL-1]); } spin_lock(&g_cdev.lock); - if ((g_cdev.active_pd == 0) && + if ((g_cdev.active_pd == NULL) && (memcmp(pd->mac_addr, g_cdev.active_addr, ETH_ALEN) == 0)) { oz_pd_get(pd); g_cdev.active_pd = pd; @@ -477,7 +477,7 @@ void oz_cdev_rx(struct oz_pd *pd, struct oz_elt *elt) int ix; ctx = oz_cdev_claim_ctx(pd); - if (ctx == 0) { + if (ctx == NULL) { oz_trace("Cannot claim serial context.\n"); return; } diff --git a/drivers/staging/ozwpan/ozevent.c b/drivers/staging/ozwpan/ozevent.c index 7f66b4f19b01..a48498bd9b5f 100644 --- a/drivers/staging/ozwpan/ozevent.c +++ b/drivers/staging/ozwpan/ozevent.c @@ -14,7 +14,7 @@ #include "ozappif.h" /*------------------------------------------------------------------------------ * Although the event mask is logically part of the oz_evtdev structure, it is - * needed outside of this file so define it seperately to avoid the need to + * needed outside of this file so define it separately to avoid the need to * export definition of struct oz_evtdev. */ u32 g_evt_mask; @@ -39,8 +39,8 @@ static struct oz_evtdev g_evtdev; */ void oz_event_init(void) { - /* Because g_evtdev is static external all fields initally zero so no - * need to reinitialised those. + /* Because g_evtdev is static external all fields initially zero so no + * need to reinitialized those. */ oz_trace("Event tracing initialized\n"); spin_lock_init(&g_evtdev.lock); diff --git a/drivers/staging/ozwpan/ozhcd.c b/drivers/staging/ozwpan/ozhcd.c index 251f07c39a6b..2e087acf1578 100644 --- a/drivers/staging/ozwpan/ozhcd.c +++ b/drivers/staging/ozwpan/ozhcd.c @@ -417,6 +417,44 @@ static void oz_ep_free(struct oz_port *port, struct oz_endpoint *ep) /*------------------------------------------------------------------------------ * Context: softirq */ +void oz_complete_buffered_urb(struct oz_port *port, struct oz_endpoint *ep, + struct urb *urb) +{ + u8 data_len, available_space, copy_len; + + memcpy(&data_len, &ep->buffer[ep->out_ix], sizeof(u8)); + if (data_len <= urb->transfer_buffer_length) + available_space = data_len; + else + available_space = urb->transfer_buffer_length; + + if (++ep->out_ix == ep->buffer_size) + ep->out_ix = 0; + copy_len = ep->buffer_size - ep->out_ix; + if (copy_len >= available_space) + copy_len = available_space; + memcpy(urb->transfer_buffer, &ep->buffer[ep->out_ix], copy_len); + + if (copy_len < available_space) { + memcpy((urb->transfer_buffer + copy_len), ep->buffer, + (available_space - copy_len)); + ep->out_ix = available_space - copy_len; + } else { + ep->out_ix += copy_len; + } + urb->actual_length = available_space; + if (ep->out_ix == ep->buffer_size) + ep->out_ix = 0; + + ep->buffered_units--; + oz_trace("Trying to give back buffered frame of size=%d\n", + available_space); + oz_complete_urb(port->ozhcd->hcd, urb, 0, 0); +} + +/*------------------------------------------------------------------------------ + * Context: softirq + */ static int oz_enqueue_ep_urb(struct oz_port *port, u8 ep_addr, int in_dir, struct urb *urb, u8 req_id) { @@ -452,6 +490,18 @@ static int oz_enqueue_ep_urb(struct oz_port *port, u8 ep_addr, int in_dir, ep = port->in_ep[ep_addr]; else ep = port->out_ep[ep_addr]; + + /*For interrupt endpoint check for buffered data + * & complete urb + */ + if (((ep->attrib & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT) + && ep->buffered_units > 0) { + oz_free_urb_link(urbl); + spin_unlock_bh(&port->ozhcd->hcd_lock); + oz_complete_buffered_urb(port, ep, urb); + return 0; + } + if (ep && port->hpd) { list_add_tail(&urbl->link, &ep->urb_list); if (!in_dir && ep_addr && (ep->credit < 0)) { @@ -883,13 +933,14 @@ void oz_hcd_control_cnf(void *hport, u8 req_id, u8 rcode, u8 *data, } else { int copy_len; oz_trace("VENDOR-CLASS - cnf\n"); - if (data_len <= urb->transfer_buffer_length) - copy_len = data_len; - else - copy_len = urb->transfer_buffer_length; - if (copy_len) + if (data_len) { + if (data_len <= urb->transfer_buffer_length) + copy_len = data_len; + else + copy_len = urb->transfer_buffer_length; memcpy(urb->transfer_buffer, data, copy_len); - urb->actual_length = copy_len; + urb->actual_length = copy_len; + } oz_complete_urb(hcd, urb, 0, 0); } } @@ -961,6 +1012,9 @@ void oz_hcd_data_ind(void *hport, u8 endpoint, u8 *data, int data_len) urb->actual_length = copy_len; oz_complete_urb(port->ozhcd->hcd, urb, 0, 0); return; + } else { + oz_trace("buffering frame as URB is not available\n"); + oz_hcd_buffer_data(ep, data, data_len); } break; case USB_ENDPOINT_XFER_ISOC: @@ -1000,7 +1054,7 @@ int oz_hcd_heartbeat(void *hport) ep = ep_from_link(e); if (ep->credit < 0) continue; - ep->credit += (now - ep->last_jiffies); + ep->credit += jiffies_to_msecs(now - ep->last_jiffies); if (ep->credit > ep->credit_ceiling) ep->credit = ep->credit_ceiling; oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num, 0, 0, ep->credit); @@ -1009,13 +1063,12 @@ int oz_hcd_heartbeat(void *hport) urbl = list_first_entry(&ep->urb_list, struct oz_urb_link, link); urb = urbl->urb; - if (ep->credit < urb->number_of_packets) + if ((ep->credit + 1) < urb->number_of_packets) break; ep->credit -= urb->number_of_packets; oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num, 0, 0, ep->credit); - list_del(&urbl->link); - list_add_tail(&urbl->link, &xfr_list); + list_move_tail(&urbl->link, &xfr_list); } } spin_unlock_bh(&ozhcd->hcd_lock); @@ -1052,7 +1105,7 @@ int oz_hcd_heartbeat(void *hport) } continue; } - ep->credit += (now - ep->last_jiffies); + ep->credit += jiffies_to_msecs(now - ep->last_jiffies); oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num | USB_DIR_IN, 0, 0, ep->credit); ep->last_jiffies = now; @@ -1064,7 +1117,7 @@ int oz_hcd_heartbeat(void *hport) int len = 0; int copy_len; int i; - if (ep->credit < urb->number_of_packets) + if ((ep->credit + 1) < urb->number_of_packets) break; if (ep->buffered_units < urb->number_of_packets) break; @@ -1096,8 +1149,7 @@ int oz_hcd_heartbeat(void *hport) urb->error_count = 0; urb->start_frame = ep->start_frame; ep->start_frame += urb->number_of_packets; - list_del(&urbl->link); - list_add_tail(&urbl->link, &xfr_list); + list_move_tail(&urbl->link, &xfr_list); ep->credit -= urb->number_of_packets; oz_event_log(OZ_EVT_EP_CREDIT, ep->ep_num | USB_DIR_IN, 0, 0, ep->credit); @@ -1129,8 +1181,7 @@ int oz_hcd_heartbeat(void *hport) oz_trace("%ld: Request 0x%p timeout\n", now, urbl->urb); urbl->submit_jiffies = now; - list_del(e); - list_add_tail(e, &xfr_list); + list_move_tail(e, &xfr_list); } } if (!list_empty(&ep->urb_list)) @@ -1167,10 +1218,16 @@ static int oz_build_endpoints_for_interface(struct usb_hcd *hcd, int buffer_size = 0; oz_trace("%d bEndpointAddress = %x\n", i, ep_addr); - if ((ep_addr & USB_ENDPOINT_DIR_MASK) && - ((hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) - == USB_ENDPOINT_XFER_ISOC)) { - buffer_size = 24*1024; + if (ep_addr & USB_ENDPOINT_DIR_MASK) { + switch (hep->desc.bmAttributes & + USB_ENDPOINT_XFERTYPE_MASK) { + case USB_ENDPOINT_XFER_ISOC: + buffer_size = 24*1024; + break; + case USB_ENDPOINT_XFER_INT: + buffer_size = 128; + break; + } } ep = oz_ep_alloc(mem_flags, buffer_size); @@ -1247,16 +1304,14 @@ static void oz_clean_endpoints_for_interface(struct usb_hcd *hcd, port->out_ep[i] = 0; /* Remove from isoc list if present. */ - list_del(e); - list_add_tail(e, &ep_list); + list_move_tail(e, &ep_list); } /* Gather IN endpoints. */ if ((mask & (1<<(i+OZ_NB_ENDPOINTS))) && port->in_ep[i]) { e = &port->in_ep[i]->link; port->in_ep[i] = 0; - list_del(e); - list_add_tail(e, &ep_list); + list_move_tail(e, &ep_list); } } spin_unlock_bh(&ozhcd->hcd_lock); @@ -1458,6 +1513,7 @@ static void oz_process_ep0_urb(struct oz_hcd *ozhcd, struct urb *urb, int data_len = 0; if ((setup->bRequestType & USB_DIR_IN) == 0) data_len = wlength; + urb->actual_length = data_len; if (oz_usb_control_req(port->hpd, req_id, setup, urb->transfer_buffer, data_len)) { rc = -ENOMEM; diff --git a/drivers/staging/ozwpan/ozmain.c b/drivers/staging/ozwpan/ozmain.c index c1ed6b2522ec..ef6c5ab753ee 100644 --- a/drivers/staging/ozwpan/ozmain.c +++ b/drivers/staging/ozwpan/ozmain.c @@ -59,6 +59,6 @@ module_exit(ozwpan_exit); MODULE_AUTHOR("Chris Kelly"); MODULE_DESCRIPTION("Ozmo Devices USB over WiFi hcd driver"); -MODULE_VERSION("1.0.10"); +MODULE_VERSION("1.0.13"); MODULE_LICENSE("GPL"); diff --git a/drivers/staging/ozwpan/ozpd.c b/drivers/staging/ozwpan/ozpd.c index 6c287ac6eaea..0b3648ce9687 100644 --- a/drivers/staging/ozwpan/ozpd.c +++ b/drivers/staging/ozwpan/ozpd.c @@ -24,12 +24,6 @@ /*------------------------------------------------------------------------------ */ #define OZ_MAX_TX_POOL_SIZE 6 -/* Maximum number of uncompleted isoc frames that can be pending in network. - */ -#define OZ_MAX_SUBMITTED_ISOC 16 -/* Maximum number of uncompleted isoc frames that can be pending in Tx Queue. - */ -#define OZ_MAX_TX_QUEUE_ISOC 32 /*------------------------------------------------------------------------------ */ static struct oz_tx_frame *oz_tx_frame_alloc(struct oz_pd *pd); @@ -752,8 +746,7 @@ int oz_isoc_stream_create(struct oz_pd *pd, u8 ep_num) */ static void oz_isoc_stream_free(struct oz_isoc_stream *st) { - if (st->skb) - kfree_skb(st->skb); + kfree_skb(st->skb); kfree(st); } /*------------------------------------------------------------------------------ @@ -854,7 +847,7 @@ int oz_send_isoc_unit(struct oz_pd *pd, u8 ep_num, u8 *data, int len) if (!(pd->mode & OZ_F_ISOC_ANYTIME)) { struct oz_tx_frame *isoc_unit = NULL; int nb = pd->nb_queued_isoc_frames; - if (nb >= OZ_MAX_TX_QUEUE_ISOC) { + if (nb >= pd->isoc_latency) { oz_trace2(OZ_TRACE_TX_FRAMES, "Dropping ISOC Unit nb= %d\n", nb); diff --git a/drivers/staging/ozwpan/ozpd.h b/drivers/staging/ozwpan/ozpd.h index ddf1341b4e67..d35b0ea44f67 100644 --- a/drivers/staging/ozwpan/ozpd.h +++ b/drivers/staging/ozwpan/ozpd.h @@ -82,6 +82,7 @@ struct oz_pd { u8 heartbeat_requested; u8 mode; u8 ms_per_isoc; + unsigned isoc_latency; unsigned max_stream_buffering; int nb_queued_frames; int nb_queued_isoc_frames; diff --git a/drivers/staging/ozwpan/ozproto.c b/drivers/staging/ozwpan/ozproto.c index a50ab18a5987..cfb5160d1ebe 100644 --- a/drivers/staging/ozwpan/ozproto.c +++ b/drivers/staging/ozwpan/ozproto.c @@ -220,6 +220,19 @@ static struct oz_pd *oz_connect_req(struct oz_pd *cur_pd, struct oz_elt *elt, pd->ms_per_isoc = body->ms_per_isoc; if (!pd->ms_per_isoc) pd->ms_per_isoc = 4; + + switch (body->ms_isoc_latency & OZ_LATENCY_MASK) { + case OZ_ONE_MS_LATENCY: + pd->isoc_latency = (body->ms_isoc_latency & + ~OZ_LATENCY_MASK) / pd->ms_per_isoc; + break; + case OZ_TEN_MS_LATENCY: + pd->isoc_latency = ((body->ms_isoc_latency & + ~OZ_LATENCY_MASK) * 10) / pd->ms_per_isoc; + break; + default: + pd->isoc_latency = OZ_MAX_TX_QUEUE_ISOC; + } } if (body->max_len_div16) pd->max_tx_size = ((u16)body->max_len_div16)<<4; diff --git a/drivers/staging/ozwpan/ozproto.h b/drivers/staging/ozwpan/ozproto.h index 89aea28bd8d5..755a08d0e1ca 100644 --- a/drivers/staging/ozwpan/ozproto.h +++ b/drivers/staging/ozwpan/ozproto.h @@ -14,7 +14,7 @@ /* Converts millisecs to jiffies. */ -#define oz_ms_to_jiffies(__x) (((__x)*1000)/HZ) +#define oz_ms_to_jiffies(__x) msecs_to_jiffies(__x) /* Quantum milliseconds. */ @@ -30,6 +30,12 @@ /* Maximun sizes of tx frames. */ #define OZ_MAX_TX_SIZE 1514 +/* Maximum number of uncompleted isoc frames that can be pending in network. */ +#define OZ_MAX_SUBMITTED_ISOC 16 + +/* Maximum number of uncompleted isoc frames that can be pending in Tx Queue. */ +#define OZ_MAX_TX_QUEUE_ISOC 32 + /* Application handler functions. */ typedef int (*oz_app_init_fn_t)(void); diff --git a/drivers/staging/ozwpan/ozprotocol.h b/drivers/staging/ozwpan/ozprotocol.h index 1e4edbeb61cd..17b09b9a5b08 100644 --- a/drivers/staging/ozwpan/ozprotocol.h +++ b/drivers/staging/ozwpan/ozprotocol.h @@ -65,6 +65,10 @@ struct oz_hdr { #define OZ_LAST_PN_HALF_CYCLE 127 +#define OZ_LATENCY_MASK 0xc0 +#define OZ_ONE_MS_LATENCY 0x40 +#define OZ_TEN_MS_LATENCY 0x80 + /* Connect request data structure. */ struct oz_elt_connect_req { @@ -73,7 +77,7 @@ struct oz_elt_connect_req { u8 pd_info; u8 session_id; u8 presleep; - u8 resv2; + u8 ms_isoc_latency; u8 host_vendor; u8 keep_alive; u16 apps; diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c index 39f9982c2708..6e9f7090c451 100644 --- a/drivers/staging/panel/panel.c +++ b/drivers/staging/panel/panel.c @@ -137,8 +137,8 @@ #define r_ctr(x) (parport_read_control((x)->port)) #define r_dtr(x) (parport_read_data((x)->port)) #define r_str(x) (parport_read_status((x)->port)) -#define w_ctr(x, y) do { parport_write_control((x)->port, (y)); } while (0) -#define w_dtr(x, y) do { parport_write_data((x)->port, (y)); } while (0) +#define w_ctr(x, y) (parport_write_control((x)->port, (y))) +#define w_dtr(x, y) (parport_write_data((x)->port, (y))) /* this defines which bits are to be used and which ones to be ignored */ /* logical or of the output bits involved in the scan matrix */ @@ -757,38 +757,38 @@ static void lcd_backlight(int on) return; /* The backlight is activated by setting the AUTOFEED line to +5V */ - spin_lock(&pprt_lock); + spin_lock_irq(&pprt_lock); bits.bl = on; panel_set_bits(); - spin_unlock(&pprt_lock); + spin_unlock_irq(&pprt_lock); } /* send a command to the LCD panel in serial mode */ static void lcd_write_cmd_s(int cmd) { - spin_lock(&pprt_lock); + spin_lock_irq(&pprt_lock); lcd_send_serial(0x1F); /* R/W=W, RS=0 */ lcd_send_serial(cmd & 0x0F); lcd_send_serial((cmd >> 4) & 0x0F); udelay(40); /* the shortest command takes at least 40 us */ - spin_unlock(&pprt_lock); + spin_unlock_irq(&pprt_lock); } /* send data to the LCD panel in serial mode */ static void lcd_write_data_s(int data) { - spin_lock(&pprt_lock); + spin_lock_irq(&pprt_lock); lcd_send_serial(0x5F); /* R/W=W, RS=1 */ lcd_send_serial(data & 0x0F); lcd_send_serial((data >> 4) & 0x0F); udelay(40); /* the shortest data takes at least 40 us */ - spin_unlock(&pprt_lock); + spin_unlock_irq(&pprt_lock); } /* send a command to the LCD panel in 8 bits parallel mode */ static void lcd_write_cmd_p8(int cmd) { - spin_lock(&pprt_lock); + spin_lock_irq(&pprt_lock); /* present the data to the data port */ w_dtr(pprt, cmd); udelay(20); /* maintain the data during 20 us before the strobe */ @@ -804,13 +804,13 @@ static void lcd_write_cmd_p8(int cmd) set_ctrl_bits(); udelay(120); /* the shortest command takes at least 120 us */ - spin_unlock(&pprt_lock); + spin_unlock_irq(&pprt_lock); } /* send data to the LCD panel in 8 bits parallel mode */ static void lcd_write_data_p8(int data) { - spin_lock(&pprt_lock); + spin_lock_irq(&pprt_lock); /* present the data to the data port */ w_dtr(pprt, data); udelay(20); /* maintain the data during 20 us before the strobe */ @@ -826,27 +826,27 @@ static void lcd_write_data_p8(int data) set_ctrl_bits(); udelay(45); /* the shortest data takes at least 45 us */ - spin_unlock(&pprt_lock); + spin_unlock_irq(&pprt_lock); } /* send a command to the TI LCD panel */ static void lcd_write_cmd_tilcd(int cmd) { - spin_lock(&pprt_lock); + spin_lock_irq(&pprt_lock); /* present the data to the control port */ w_ctr(pprt, cmd); udelay(60); - spin_unlock(&pprt_lock); + spin_unlock_irq(&pprt_lock); } /* send data to the TI LCD panel */ static void lcd_write_data_tilcd(int data) { - spin_lock(&pprt_lock); + spin_lock_irq(&pprt_lock); /* present the data to the data port */ w_dtr(pprt, data); udelay(60); - spin_unlock(&pprt_lock); + spin_unlock_irq(&pprt_lock); } static void lcd_gotoxy(void) @@ -879,14 +879,14 @@ static void lcd_clear_fast_s(void) lcd_addr_x = lcd_addr_y = 0; lcd_gotoxy(); - spin_lock(&pprt_lock); + spin_lock_irq(&pprt_lock); for (pos = 0; pos < lcd_height * lcd_hwidth; pos++) { lcd_send_serial(0x5F); /* R/W=W, RS=1 */ lcd_send_serial(' ' & 0x0F); lcd_send_serial((' ' >> 4) & 0x0F); udelay(40); /* the shortest data takes at least 40 us */ } - spin_unlock(&pprt_lock); + spin_unlock_irq(&pprt_lock); lcd_addr_x = lcd_addr_y = 0; lcd_gotoxy(); @@ -899,7 +899,7 @@ static void lcd_clear_fast_p8(void) lcd_addr_x = lcd_addr_y = 0; lcd_gotoxy(); - spin_lock(&pprt_lock); + spin_lock_irq(&pprt_lock); for (pos = 0; pos < lcd_height * lcd_hwidth; pos++) { /* present the data to the data port */ w_dtr(pprt, ' '); @@ -921,7 +921,7 @@ static void lcd_clear_fast_p8(void) /* the shortest data takes at least 45 us */ udelay(45); } - spin_unlock(&pprt_lock); + spin_unlock_irq(&pprt_lock); lcd_addr_x = lcd_addr_y = 0; lcd_gotoxy(); @@ -934,14 +934,14 @@ static void lcd_clear_fast_tilcd(void) lcd_addr_x = lcd_addr_y = 0; lcd_gotoxy(); - spin_lock(&pprt_lock); + spin_lock_irq(&pprt_lock); for (pos = 0; pos < lcd_height * lcd_hwidth; pos++) { /* present the data to the data port */ w_dtr(pprt, ' '); udelay(60); } - spin_unlock(&pprt_lock); + spin_unlock_irq(&pprt_lock); lcd_addr_x = lcd_addr_y = 0; lcd_gotoxy(); @@ -1197,7 +1197,7 @@ static inline int handle_lcd_special_code(void) break; } - /* Check wether one flag was changed */ + /* Check whether one flag was changed */ if (oldflags != lcd_flags) { /* check whether one of B,C,D flags were changed */ if ((oldflags ^ lcd_flags) & @@ -1212,7 +1212,7 @@ static inline int handle_lcd_special_code(void) lcd_write_cmd(0x30 | ((lcd_flags & LCD_FLAG_F) ? 4 : 0) | ((lcd_flags & LCD_FLAG_N) ? 8 : 0)); - /* check wether L flag was changed */ + /* check whether L flag was changed */ else if ((oldflags ^ lcd_flags) & (LCD_FLAG_L)) { if (lcd_flags & (LCD_FLAG_L)) lcd_backlight(1); @@ -1886,11 +1886,11 @@ static void panel_process_inputs(void) static void panel_scan_timer(void) { if (keypad_enabled && keypad_initialized) { - if (spin_trylock(&pprt_lock)) { + if (spin_trylock_irq(&pprt_lock)) { phys_scan_contacts(); /* no need for the parport anymore */ - spin_unlock(&pprt_lock); + spin_unlock_irq(&pprt_lock); } if (!inputs_stable || phys_curr != phys_prev) diff --git a/drivers/staging/ramster/Kconfig b/drivers/staging/ramster/Kconfig index 8349887827dc..843c54101438 100644 --- a/drivers/staging/ramster/Kconfig +++ b/drivers/staging/ramster/Kconfig @@ -1,13 +1,30 @@ +config ZCACHE2 + bool "Dynamic compression of swap pages and clean pagecache pages" + depends on CRYPTO=y && SWAP=y && CLEANCACHE && FRONTSWAP && !ZCACHE + select CRYPTO_LZO + default n + help + Zcache2 doubles RAM efficiency while providing a significant + performance boosts on many workloads. Zcache2 uses + compression and an in-kernel implementation of transcendent + memory to store clean page cache pages and swap in RAM, + providing a noticeable reduction in disk I/O. Zcache2 + is a complete rewrite of the older zcache; it was intended to + be a merge but that has been blocked due to political and + technical disagreements. It is intended that they will merge + again in the future. Until then, zcache2 is a single-node + version of ramster. + config RAMSTER bool "Cross-machine RAM capacity sharing, aka peer-to-peer tmem" - depends on (CLEANCACHE || FRONTSWAP) && CONFIGFS_FS=y && !ZCACHE && !XVMALLOC && !HIGHMEM && NET - select LZO_COMPRESS - select LZO_DECOMPRESS + depends on CONFIGFS_FS=y && SYSFS=y && !HIGHMEM && ZCACHE2=y + # must ensure struct page is 8-byte aligned + select HAVE_ALIGNED_STRUCT_PAGE if !64_BIT default n help RAMster allows RAM on other machines in a cluster to be utilized dynamically and symmetrically instead of swapping to a local swap disk, thus improving performance on memory-constrained workloads while minimizing total RAM across the cluster. RAMster, like - zcache, compresses swap pages into local RAM, but then remotifies + zcache2, compresses swap pages into local RAM, but then remotifies the compressed pages to another node in the RAMster cluster. diff --git a/drivers/staging/ramster/Makefile b/drivers/staging/ramster/Makefile index bcc13c87f996..2d8b9d0a6a8b 100644 --- a/drivers/staging/ramster/Makefile +++ b/drivers/staging/ramster/Makefile @@ -1 +1,6 @@ -obj-$(CONFIG_RAMSTER) += zcache-main.o tmem.o r2net.o xvmalloc.o cluster/ +zcache-y := zcache-main.o tmem.o zbud.o +zcache-$(CONFIG_RAMSTER) += ramster/ramster.o ramster/r2net.o +zcache-$(CONFIG_RAMSTER) += ramster/nodemanager.o ramster/tcp.o +zcache-$(CONFIG_RAMSTER) += ramster/heartbeat.o ramster/masklog.o + +obj-$(CONFIG_ZCACHE2) += zcache.o diff --git a/drivers/staging/ramster/TODO b/drivers/staging/ramster/TODO deleted file mode 100644 index 46fcf0c58acf..000000000000 --- a/drivers/staging/ramster/TODO +++ /dev/null @@ -1,13 +0,0 @@ -For this staging driver, RAMster duplicates code from drivers/staging/zcache -then incorporates changes to the local copy of the code. For V5, it also -directly incorporates the soon-to-be-removed drivers/staging/zram/xvmalloc.[ch] -as all testing has been done with xvmalloc rather than the new zsmalloc. -Before RAMster can be promoted from staging, the zcache and RAMster drivers -should be either merged or reorganized to separate out common code. - -Until V4, RAMster duplicated code from fs/ocfs2/cluster, but this made -RAMster incompatible with ocfs2 running in the same kernel and included -lots of code that could be removed. As of V5, the ocfs2 code has been -mined and made RAMster-specific, made to communicate with a userland -ramster-tools package rather than ocfs2-tools, and can co-exist with ocfs2 -both in the same kernel and in userland on the same machine. diff --git a/drivers/staging/ramster/cluster/Makefile b/drivers/staging/ramster/cluster/Makefile deleted file mode 100644 index 9c6943652c01..000000000000 --- a/drivers/staging/ramster/cluster/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_RAMSTER) += ramster_nodemanager.o - -ramster_nodemanager-objs := heartbeat.o masklog.o nodemanager.o tcp.o diff --git a/drivers/staging/ramster/ramster.h b/drivers/staging/ramster/ramster.h index 0c9455e8dcd8..1b71aea2ff62 100644 --- a/drivers/staging/ramster/ramster.h +++ b/drivers/staging/ramster/ramster.h @@ -1,118 +1,59 @@ + /* - * ramster.h + * zcache/ramster.h * - * Peer-to-peer transcendent memory + * Placeholder to resolve ramster references when !CONFIG_RAMSTER + * Real ramster.h lives in ramster subdirectory. * * Copyright (c) 2009-2012, Dan Magenheimer, Oracle Corp. */ -#ifndef _RAMSTER_H_ -#define _RAMSTER_H_ - -/* - * format of remote pampd: - * bit 0 == intransit - * bit 1 == is_remote... if this bit is set, then - * bit 2-9 == remotenode - * bit 10-22 == size - * bit 23-30 == cksum - */ -#define FAKE_PAMPD_INTRANSIT_BITS 1 -#define FAKE_PAMPD_ISREMOTE_BITS 1 -#define FAKE_PAMPD_REMOTENODE_BITS 8 -#define FAKE_PAMPD_REMOTESIZE_BITS 13 -#define FAKE_PAMPD_CHECKSUM_BITS 8 - -#define FAKE_PAMPD_INTRANSIT_SHIFT 0 -#define FAKE_PAMPD_ISREMOTE_SHIFT (FAKE_PAMPD_INTRANSIT_SHIFT + \ - FAKE_PAMPD_INTRANSIT_BITS) -#define FAKE_PAMPD_REMOTENODE_SHIFT (FAKE_PAMPD_ISREMOTE_SHIFT + \ - FAKE_PAMPD_ISREMOTE_BITS) -#define FAKE_PAMPD_REMOTESIZE_SHIFT (FAKE_PAMPD_REMOTENODE_SHIFT + \ - FAKE_PAMPD_REMOTENODE_BITS) -#define FAKE_PAMPD_CHECKSUM_SHIFT (FAKE_PAMPD_REMOTESIZE_SHIFT + \ - FAKE_PAMPD_REMOTESIZE_BITS) +#ifndef _ZCACHE_RAMSTER_H_ +#define _ZCACHE_RAMSTER_H_ -#define FAKE_PAMPD_MASK(x) ((1UL << (x)) - 1) - -static inline void *pampd_make_remote(int remotenode, size_t size, - unsigned char cksum) +#ifdef CONFIG_RAMSTER +#include "ramster/ramster.h" +#else +static inline void ramster_init(bool x, bool y, bool z) { - unsigned long fake_pampd = 0; - fake_pampd |= 1UL << FAKE_PAMPD_ISREMOTE_SHIFT; - fake_pampd |= ((unsigned long)remotenode & - FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTENODE_BITS)) << - FAKE_PAMPD_REMOTENODE_SHIFT; - fake_pampd |= ((unsigned long)size & - FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTESIZE_BITS)) << - FAKE_PAMPD_REMOTESIZE_SHIFT; - fake_pampd |= ((unsigned long)cksum & - FAKE_PAMPD_MASK(FAKE_PAMPD_CHECKSUM_BITS)) << - FAKE_PAMPD_CHECKSUM_SHIFT; - return (void *)fake_pampd; } -static inline unsigned int pampd_remote_node(void *pampd) +static inline void ramster_register_pamops(struct tmem_pamops *p) { - unsigned long fake_pampd = (unsigned long)pampd; - return (fake_pampd >> FAKE_PAMPD_REMOTENODE_SHIFT) & - FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTENODE_BITS); } -static inline unsigned int pampd_remote_size(void *pampd) +static inline int ramster_remotify_pageframe(bool b) { - unsigned long fake_pampd = (unsigned long)pampd; - return (fake_pampd >> FAKE_PAMPD_REMOTESIZE_SHIFT) & - FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTESIZE_BITS); + return 0; } -static inline unsigned char pampd_remote_cksum(void *pampd) +static inline void *ramster_pampd_free(void *v, struct tmem_pool *p, + struct tmem_oid *o, uint32_t u, bool b) { - unsigned long fake_pampd = (unsigned long)pampd; - return (fake_pampd >> FAKE_PAMPD_CHECKSUM_SHIFT) & - FAKE_PAMPD_MASK(FAKE_PAMPD_CHECKSUM_BITS); + return NULL; } -static inline bool pampd_is_remote(void *pampd) +static inline int ramster_do_preload_flnode(struct tmem_pool *p) { - unsigned long fake_pampd = (unsigned long)pampd; - return (fake_pampd >> FAKE_PAMPD_ISREMOTE_SHIFT) & - FAKE_PAMPD_MASK(FAKE_PAMPD_ISREMOTE_BITS); + return -1; } -static inline bool pampd_is_intransit(void *pampd) +static inline bool pampd_is_remote(void *v) { - unsigned long fake_pampd = (unsigned long)pampd; - return (fake_pampd >> FAKE_PAMPD_INTRANSIT_SHIFT) & - FAKE_PAMPD_MASK(FAKE_PAMPD_INTRANSIT_BITS); + return false; } -/* note that it is a BUG for intransit to be set without isremote also set */ -static inline void *pampd_mark_intransit(void *pampd) +static inline void ramster_count_foreign_pages(bool b, int i) { - unsigned long fake_pampd = (unsigned long)pampd; - - fake_pampd |= 1UL << FAKE_PAMPD_ISREMOTE_SHIFT; - fake_pampd |= 1UL << FAKE_PAMPD_INTRANSIT_SHIFT; - return (void *)fake_pampd; } -static inline void *pampd_mask_intransit_and_remote(void *marked_pampd) +static inline void ramster_cpu_up(int cpu) { - unsigned long pampd = (unsigned long)marked_pampd; - - pampd &= ~(1UL << FAKE_PAMPD_INTRANSIT_SHIFT); - pampd &= ~(1UL << FAKE_PAMPD_ISREMOTE_SHIFT); - return (void *)pampd; } -extern int ramster_remote_async_get(struct tmem_xhandle *, - bool, int, size_t, uint8_t, void *extra); -extern int ramster_remote_put(struct tmem_xhandle *, char *, size_t, - bool, int *); -extern int ramster_remote_flush(struct tmem_xhandle *, int); -extern int ramster_remote_flush_object(struct tmem_xhandle *, int); -extern int r2net_register_handlers(void); -extern int r2net_remote_target_node_set(int); +static inline void ramster_cpu_down(int cpu) +{ +} +#endif -#endif /* _TMEM_H */ +#endif /* _ZCACHE_RAMSTER_H */ diff --git a/drivers/staging/ramster/cluster/heartbeat.c b/drivers/staging/ramster/ramster/heartbeat.c index 00209490756e..75d3fe80b055 100644 --- a/drivers/staging/ramster/cluster/heartbeat.c +++ b/drivers/staging/ramster/ramster/heartbeat.c @@ -172,8 +172,7 @@ static void r2hb_hb_group_drop_item(struct config_group *group, struct config_item *item) { if (r2hb_global_heartbeat_active()) { - printk(KERN_NOTICE "ramster: Heartbeat %s " - "on region %s (%s)\n", + pr_notice("ramster: Heartbeat %s on region %s (%s)\n", "stopped/aborted", config_item_name(item), "no region"); } @@ -265,8 +264,7 @@ ssize_t r2hb_hb_group_mode_store(struct r2hb_hb_group *group, ret = r2hb_global_hearbeat_mode_set(i); if (!ret) - printk(KERN_NOTICE "ramster: Heartbeat mode " - "set to %s\n", + pr_notice("ramster: Heartbeat mode set to %s\n", r2hb_heartbeat_mode_desc[i]); return count; } diff --git a/drivers/staging/ramster/cluster/heartbeat.h b/drivers/staging/ramster/ramster/heartbeat.h index 6cbc775bd63b..6cbc775bd63b 100644 --- a/drivers/staging/ramster/cluster/heartbeat.h +++ b/drivers/staging/ramster/ramster/heartbeat.h diff --git a/drivers/staging/ramster/cluster/masklog.c b/drivers/staging/ramster/ramster/masklog.c index 1261d8579aae..1261d8579aae 100644 --- a/drivers/staging/ramster/cluster/masklog.c +++ b/drivers/staging/ramster/ramster/masklog.c diff --git a/drivers/staging/ramster/cluster/masklog.h b/drivers/staging/ramster/ramster/masklog.h index 918ae110b699..918ae110b699 100644 --- a/drivers/staging/ramster/cluster/masklog.h +++ b/drivers/staging/ramster/ramster/masklog.h diff --git a/drivers/staging/ramster/cluster/nodemanager.c b/drivers/staging/ramster/ramster/nodemanager.c index de0e5c8da6ea..c0f48158735d 100644 --- a/drivers/staging/ramster/cluster/nodemanager.c +++ b/drivers/staging/ramster/ramster/nodemanager.c @@ -528,7 +528,8 @@ static ssize_t r2nm_cluster_attr_idle_timeout_ms_write( r2net_num_connected_peers()); ret = -EINVAL; } else if (val <= cluster->cl_keepalive_delay_ms) { - mlog(ML_NOTICE, "r2net: idle timeout must be larger " + mlog(ML_NOTICE, + "r2net: idle timeout must be larger " "than keepalive delay\n"); ret = -EINVAL; } else { @@ -563,7 +564,8 @@ static ssize_t r2nm_cluster_attr_keepalive_delay_ms_write( r2net_num_connected_peers()); ret = -EINVAL; } else if (val >= cluster->cl_idle_timeout_ms) { - mlog(ML_NOTICE, "r2net: keepalive delay must be " + mlog(ML_NOTICE, + "r2net: keepalive delay must be " "smaller than idle timeout\n"); ret = -EINVAL; } else { @@ -612,7 +614,7 @@ static ssize_t r2nm_cluster_attr_fence_method_write( if (strncasecmp(page, r2nm_fence_method_desc[i], count - 1)) continue; if (cluster->cl_fence_method != i) { - printk(KERN_INFO "ramster: Changing fence method to %s\n", + pr_info("ramster: Changing fence method to %s\n", r2nm_fence_method_desc[i]); cluster->cl_fence_method = i; } @@ -967,7 +969,7 @@ static int __init init_r2nm(void) mutex_init(&r2nm_cluster_group.cs_subsys.su_mutex); ret = configfs_register_subsystem(&r2nm_cluster_group.cs_subsys); if (ret) { - printk(KERN_ERR "nodemanager: Registration returned %d\n", ret); + pr_err("nodemanager: Registration returned %d\n", ret); goto out_callbacks; } @@ -988,5 +990,6 @@ out: MODULE_AUTHOR("Oracle"); MODULE_LICENSE("GPL"); -module_init(init_r2nm) -module_exit(exit_r2nm) +/* module_init(init_r2nm) */ +late_initcall(init_r2nm); +/* module_exit(exit_r2nm) */ diff --git a/drivers/staging/ramster/cluster/nodemanager.h b/drivers/staging/ramster/ramster/nodemanager.h index 41a04df5842c..41a04df5842c 100644 --- a/drivers/staging/ramster/cluster/nodemanager.h +++ b/drivers/staging/ramster/ramster/nodemanager.h diff --git a/drivers/staging/ramster/r2net.c b/drivers/staging/ramster/ramster/r2net.c index fc830c3ac74b..34818dc65612 100644 --- a/drivers/staging/ramster/r2net.c +++ b/drivers/staging/ramster/ramster/r2net.c @@ -1,7 +1,7 @@ /* * r2net.c * - * Copyright (c) 2011, Dan Magenheimer, Oracle Corp. + * Copyright (c) 2011-2012, Dan Magenheimer, Oracle Corp. * * Ramster_r2net provides an interface between zcache and r2net. * @@ -9,10 +9,10 @@ */ #include <linux/list.h> -#include "cluster/tcp.h" -#include "cluster/nodemanager.h" -#include "tmem.h" -#include "zcache.h" +#include "tcp.h" +#include "nodemanager.h" +#include "../tmem.h" +#include "../zcache.h" #include "ramster.h" #define RAMSTER_TESTING @@ -33,7 +33,7 @@ enum { #define RMSTR_R2NET_MAX_LEN \ (R2NET_MAX_PAYLOAD_BYTES - sizeof(struct tmem_xhandle)) -#include "cluster/tcp_internal.h" +#include "tcp_internal.h" static struct r2nm_node *r2net_target_node; static int r2net_target_nodenum; @@ -72,8 +72,8 @@ static int ramster_remote_async_get_request_handler(struct r2net_msg *msg, *(struct tmem_xhandle *)pdata = xh; pdata += sizeof(struct tmem_xhandle); local_irq_save(flags); - found = zcache_get(xh.client_id, xh.pool_id, &xh.oid, xh.index, - pdata, &size, 1, get_and_free ? 1 : -1); + found = zcache_get_page(xh.client_id, xh.pool_id, &xh.oid, xh.index, + pdata, &size, true, get_and_free ? 1 : -1); local_irq_restore(flags); if (found < 0) { /* a zero size indicates the get failed */ @@ -98,7 +98,7 @@ static int ramster_remote_async_get_reply_handler(struct r2net_msg *msg, in += sizeof(struct tmem_xhandle); datalen -= sizeof(struct tmem_xhandle); BUG_ON(datalen < 0 || datalen > PAGE_SIZE); - ret = zcache_localify(xh->pool_id, &xh->oid, xh->index, + ret = ramster_localify(xh->pool_id, &xh->oid, xh->index, in, datalen, xh->extra); #ifdef RAMSTER_TESTING if (ret == -EEXIST) @@ -123,8 +123,8 @@ int ramster_remote_put_handler(struct r2net_msg *msg, p += sizeof(struct tmem_xhandle); zcache_autocreate_pool(xh->client_id, xh->pool_id, ephemeral); local_irq_save(flags); - ret = zcache_put(xh->client_id, xh->pool_id, &xh->oid, xh->index, - p, datalen, 1, ephemeral ? 1 : -1); + ret = zcache_put_page(xh->client_id, xh->pool_id, &xh->oid, xh->index, + p, datalen, true, ephemeral); local_irq_restore(flags); return ret; } @@ -137,7 +137,8 @@ int ramster_remote_flush_handler(struct r2net_msg *msg, xh = (struct tmem_xhandle *)p; p += sizeof(struct tmem_xhandle); - (void)zcache_flush(xh->client_id, xh->pool_id, &xh->oid, xh->index); + (void)zcache_flush_page(xh->client_id, xh->pool_id, + &xh->oid, xh->index); return 0; } @@ -153,15 +154,16 @@ int ramster_remote_flobj_handler(struct r2net_msg *msg, return 0; } -int ramster_remote_async_get(struct tmem_xhandle *xh, bool free, int remotenode, +int r2net_remote_async_get(struct tmem_xhandle *xh, bool free, int remotenode, size_t expect_size, uint8_t expect_cksum, void *extra) { - int ret = -1, status; + int nodenum, ret = -1, status; struct r2nm_node *node = NULL; struct kvec vec[1]; size_t veclen = 1; u32 msg_type; + struct r2net_node *nn; node = r2nm_get_node_by_num(remotenode); if (node == NULL) @@ -172,6 +174,21 @@ int ramster_remote_async_get(struct tmem_xhandle *xh, bool free, int remotenode, xh->extra = extra; vec[0].iov_len = sizeof(*xh); vec[0].iov_base = xh; + + node = r2net_target_node; + if (!node) + goto out; + + nodenum = r2net_target_nodenum; + + r2nm_node_get(node); + nn = r2net_nn_from_num(nodenum); + if (nn->nn_persistent_error || !nn->nn_sc_valid) { + ret = -ENOTCONN; + r2nm_node_put(node); + goto out; + } + if (free) msg_type = RMSTR_TMEM_ASYNC_GET_AND_FREE_REQUEST; else @@ -180,8 +197,13 @@ int ramster_remote_async_get(struct tmem_xhandle *xh, bool free, int remotenode, vec, veclen, remotenode, &status); r2nm_node_put(node); if (ret < 0) { + if (ret == -ENOTCONN || ret == -EHOSTDOWN) + goto out; + if (ret == -EAGAIN) + goto out; /* FIXME handle bad message possibilities here? */ - pr_err("UNTESTED ret<0 in ramster_remote_async_get\n"); + pr_err("UNTESTED ret<0 in ramster_remote_async_get: ret=%d\n", + ret); } ret = status; out: @@ -219,7 +241,7 @@ static void ramster_check_irq_counts(void) } #endif -int ramster_remote_put(struct tmem_xhandle *xh, char *data, size_t size, +int r2net_remote_put(struct tmem_xhandle *xh, char *data, size_t size, bool ephemeral, int *remotenode) { int nodenum, ret = -1, status; @@ -227,9 +249,7 @@ int ramster_remote_put(struct tmem_xhandle *xh, char *data, size_t size, struct kvec vec[2]; size_t veclen = 2; u32 msg_type; -#ifdef RAMSTER_TESTING struct r2net_node *nn; -#endif BUG_ON(size > RMSTR_R2NET_MAX_LEN); xh->client_id = r2nm_this_node(); /* which node is putting */ @@ -237,6 +257,7 @@ int ramster_remote_put(struct tmem_xhandle *xh, char *data, size_t size, vec[0].iov_base = xh; vec[1].iov_len = size; vec[1].iov_base = data; + node = r2net_target_node; if (!node) goto out; @@ -245,10 +266,12 @@ int ramster_remote_put(struct tmem_xhandle *xh, char *data, size_t size, r2nm_node_get(node); -#ifdef RAMSTER_TESTING nn = r2net_nn_from_num(nodenum); - WARN_ON_ONCE(nn->nn_persistent_error || !nn->nn_sc_valid); -#endif + if (nn->nn_persistent_error || !nn->nn_sc_valid) { + ret = -ENOTCONN; + r2nm_node_put(node); + goto out; + } if (ephemeral) msg_type = RMSTR_TMEM_PUT_EPH; @@ -261,16 +284,6 @@ int ramster_remote_put(struct tmem_xhandle *xh, char *data, size_t size, ret = r2net_send_message_vec(msg_type, RMSTR_KEY, vec, veclen, nodenum, &status); -#ifdef RAMSTER_TESTING - if (ret != 0) { - static unsigned long cnt; - cnt++; - if (!(cnt&(cnt-1))) - pr_err("ramster_remote_put: message failed, ret=%d, cnt=%lu\n", - ret, cnt); - ret = -1; - } -#endif if (ret < 0) ret = -1; else { @@ -283,7 +296,7 @@ out: return ret; } -int ramster_remote_flush(struct tmem_xhandle *xh, int remotenode) +int r2net_remote_flush(struct tmem_xhandle *xh, int remotenode) { int ret = -1, status; struct r2nm_node *node = NULL; @@ -303,7 +316,7 @@ int ramster_remote_flush(struct tmem_xhandle *xh, int remotenode) return ret; } -int ramster_remote_flush_object(struct tmem_xhandle *xh, int remotenode) +int r2net_remote_flush_object(struct tmem_xhandle *xh, int remotenode) { int ret = -1, status; struct r2nm_node *node = NULL; diff --git a/drivers/staging/ramster/ramster/ramster.c b/drivers/staging/ramster/ramster/ramster.c new file mode 100644 index 000000000000..c06709f39682 --- /dev/null +++ b/drivers/staging/ramster/ramster/ramster.c @@ -0,0 +1,985 @@ +/* + * ramster.c + * + * Copyright (c) 2010-2012, Dan Magenheimer, Oracle Corp. + * + * RAMster implements peer-to-peer transcendent memory, allowing a "cluster" of + * kernels to dynamically pool their RAM so that a RAM-hungry workload on one + * machine can temporarily and transparently utilize RAM on another machine + * which is presumably idle or running a non-RAM-hungry workload. + * + * RAMster combines a clustering and messaging foundation based on the ocfs2 + * cluster layer with the in-kernel compression implementation of zcache, and + * adds code to glue them together. When a page is "put" to RAMster, it is + * compressed and stored locally. Periodically, a thread will "remotify" these + * pages by sending them via messages to a remote machine. When the page is + * later needed as indicated by a page fault, a "get" is issued. If the data + * is local, it is uncompressed and the fault is resolved. If the data is + * remote, a message is sent to fetch the data and the faulting thread sleeps; + * when the data arrives, the thread awakens, the data is decompressed and + * the fault is resolved. + + * As of V5, clusters up to eight nodes are supported; each node can remotify + * pages to one specified node, so clusters can be configured as clients to + * a "memory server". Some simple policy is in place that will need to be + * refined over time. Larger clusters and fault-resistant protocols can also + * be added over time. + */ + +#include <linux/module.h> +#include <linux/cpu.h> +#include <linux/highmem.h> +#include <linux/list.h> +#include <linux/lzo.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/types.h> +#include <linux/atomic.h> +#include <linux/frontswap.h> +#include "../tmem.h" +#include "../zcache.h" +#include "../zbud.h" +#include "ramster.h" +#include "ramster_nodemanager.h" +#include "tcp.h" + +#define RAMSTER_TESTING + +#ifndef CONFIG_SYSFS +#error "ramster needs sysfs to define cluster nodes to use" +#endif + +static bool use_cleancache __read_mostly; +static bool use_frontswap __read_mostly; +static bool use_frontswap_exclusive_gets __read_mostly; + +/* These must be sysfs not debugfs as they are checked/used by userland!! */ +static unsigned long ramster_interface_revision __read_mostly = + R2NM_API_VERSION; /* interface revision must match userspace! */ +static unsigned long ramster_pers_remotify_enable __read_mostly; +static unsigned long ramster_eph_remotify_enable __read_mostly; +static atomic_t ramster_remote_pers_pages = ATOMIC_INIT(0); +#define MANUAL_NODES 8 +static bool ramster_nodes_manual_up[MANUAL_NODES] __read_mostly; +static int ramster_remote_target_nodenum __read_mostly = -1; + +/* these counters are made available via debugfs */ +static long ramster_flnodes; +static atomic_t ramster_flnodes_atomic = ATOMIC_INIT(0); +static unsigned long ramster_flnodes_max; +static long ramster_foreign_eph_pages; +static atomic_t ramster_foreign_eph_pages_atomic = ATOMIC_INIT(0); +static unsigned long ramster_foreign_eph_pages_max; +static long ramster_foreign_pers_pages; +static atomic_t ramster_foreign_pers_pages_atomic = ATOMIC_INIT(0); +static unsigned long ramster_foreign_pers_pages_max; +static unsigned long ramster_eph_pages_remoted; +static unsigned long ramster_pers_pages_remoted; +static unsigned long ramster_eph_pages_remote_failed; +static unsigned long ramster_pers_pages_remote_failed; +static unsigned long ramster_remote_eph_pages_succ_get; +static unsigned long ramster_remote_pers_pages_succ_get; +static unsigned long ramster_remote_eph_pages_unsucc_get; +static unsigned long ramster_remote_pers_pages_unsucc_get; +static unsigned long ramster_pers_pages_remote_nomem; +static unsigned long ramster_remote_objects_flushed; +static unsigned long ramster_remote_object_flushes_failed; +static unsigned long ramster_remote_pages_flushed; +static unsigned long ramster_remote_page_flushes_failed; +/* FIXME frontswap selfshrinking knobs in debugfs? */ + +#ifdef CONFIG_DEBUG_FS +#include <linux/debugfs.h> +#define zdfs debugfs_create_size_t +#define zdfs64 debugfs_create_u64 +static int __init ramster_debugfs_init(void) +{ + struct dentry *root = debugfs_create_dir("ramster", NULL); + if (root == NULL) + return -ENXIO; + + zdfs("eph_pages_remoted", S_IRUGO, root, &ramster_eph_pages_remoted); + zdfs("pers_pages_remoted", S_IRUGO, root, &ramster_pers_pages_remoted); + zdfs("eph_pages_remote_failed", S_IRUGO, root, + &ramster_eph_pages_remote_failed); + zdfs("pers_pages_remote_failed", S_IRUGO, root, + &ramster_pers_pages_remote_failed); + zdfs("remote_eph_pages_succ_get", S_IRUGO, root, + &ramster_remote_eph_pages_succ_get); + zdfs("remote_pers_pages_succ_get", S_IRUGO, root, + &ramster_remote_pers_pages_succ_get); + zdfs("remote_eph_pages_unsucc_get", S_IRUGO, root, + &ramster_remote_eph_pages_unsucc_get); + zdfs("remote_pers_pages_unsucc_get", S_IRUGO, root, + &ramster_remote_pers_pages_unsucc_get); + zdfs("pers_pages_remote_nomem", S_IRUGO, root, + &ramster_pers_pages_remote_nomem); + zdfs("remote_objects_flushed", S_IRUGO, root, + &ramster_remote_objects_flushed); + zdfs("remote_pages_flushed", S_IRUGO, root, + &ramster_remote_pages_flushed); + zdfs("remote_object_flushes_failed", S_IRUGO, root, + &ramster_remote_object_flushes_failed); + zdfs("remote_page_flushes_failed", S_IRUGO, root, + &ramster_remote_page_flushes_failed); + zdfs("foreign_eph_pages", S_IRUGO, root, + &ramster_foreign_eph_pages); + zdfs("foreign_eph_pages_max", S_IRUGO, root, + &ramster_foreign_eph_pages_max); + zdfs("foreign_pers_pages", S_IRUGO, root, + &ramster_foreign_pers_pages); + zdfs("foreign_pers_pages_max", S_IRUGO, root, + &ramster_foreign_pers_pages_max); + return 0; +} +#undef zdebugfs +#undef zdfs64 +#endif + +static LIST_HEAD(ramster_rem_op_list); +static DEFINE_SPINLOCK(ramster_rem_op_list_lock); +static DEFINE_PER_CPU(struct ramster_preload, ramster_preloads); + +static DEFINE_PER_CPU(unsigned char *, ramster_remoteputmem1); +static DEFINE_PER_CPU(unsigned char *, ramster_remoteputmem2); + +static struct kmem_cache *ramster_flnode_cache __read_mostly; + +static struct flushlist_node *ramster_flnode_alloc(struct tmem_pool *pool) +{ + struct flushlist_node *flnode = NULL; + struct ramster_preload *kp; + + kp = &__get_cpu_var(ramster_preloads); + flnode = kp->flnode; + BUG_ON(flnode == NULL); + kp->flnode = NULL; + ramster_flnodes = atomic_inc_return(&ramster_flnodes_atomic); + if (ramster_flnodes > ramster_flnodes_max) + ramster_flnodes_max = ramster_flnodes; + return flnode; +} + +/* the "flush list" asynchronously collects pages to remotely flush */ +#define FLUSH_ENTIRE_OBJECT ((uint32_t)-1) +static void ramster_flnode_free(struct flushlist_node *flnode, + struct tmem_pool *pool) +{ + int flnodes; + + flnodes = atomic_dec_return(&ramster_flnodes_atomic); + BUG_ON(flnodes < 0); + kmem_cache_free(ramster_flnode_cache, flnode); +} + +int ramster_do_preload_flnode(struct tmem_pool *pool) +{ + struct ramster_preload *kp; + struct flushlist_node *flnode; + int ret = -ENOMEM; + + BUG_ON(!irqs_disabled()); + if (unlikely(ramster_flnode_cache == NULL)) + BUG(); + kp = &__get_cpu_var(ramster_preloads); + flnode = kmem_cache_alloc(ramster_flnode_cache, GFP_ATOMIC); + if (unlikely(flnode == NULL) && kp->flnode == NULL) + BUG(); /* FIXME handle more gracefully, but how??? */ + else if (kp->flnode == NULL) + kp->flnode = flnode; + else + kmem_cache_free(ramster_flnode_cache, flnode); + return ret; +} + +/* + * Called by the message handler after a (still compressed) page has been + * fetched from the remote machine in response to an "is_remote" tmem_get + * or persistent tmem_localify. For a tmem_get, "extra" is the address of + * the page that is to be filled to successfully resolve the tmem_get; for + * a (persistent) tmem_localify, "extra" is NULL (as the data is placed only + * in the local zcache). "data" points to "size" bytes of (compressed) data + * passed in the message. In the case of a persistent remote get, if + * pre-allocation was successful (see ramster_repatriate_preload), the page + * is placed into both local zcache and at "extra". + */ +int ramster_localify(int pool_id, struct tmem_oid *oidp, uint32_t index, + char *data, unsigned int size, void *extra) +{ + int ret = -ENOENT; + unsigned long flags; + struct tmem_pool *pool; + bool eph, delete = false; + void *pampd, *saved_hb; + struct tmem_obj *obj; + + pool = zcache_get_pool_by_id(LOCAL_CLIENT, pool_id); + if (unlikely(pool == NULL)) + /* pool doesn't exist anymore */ + goto out; + eph = is_ephemeral(pool); + local_irq_save(flags); /* FIXME: maybe only disable softirqs? */ + pampd = tmem_localify_get_pampd(pool, oidp, index, &obj, &saved_hb); + if (pampd == NULL) { + /* hmmm... must have been a flush while waiting */ +#ifdef RAMSTER_TESTING + pr_err("UNTESTED pampd==NULL in ramster_localify\n"); +#endif + if (eph) + ramster_remote_eph_pages_unsucc_get++; + else + ramster_remote_pers_pages_unsucc_get++; + obj = NULL; + goto finish; + } else if (unlikely(!pampd_is_remote(pampd))) { + /* hmmm... must have been a dup put while waiting */ +#ifdef RAMSTER_TESTING + pr_err("UNTESTED dup while waiting in ramster_localify\n"); +#endif + if (eph) + ramster_remote_eph_pages_unsucc_get++; + else + ramster_remote_pers_pages_unsucc_get++; + obj = NULL; + pampd = NULL; + ret = -EEXIST; + goto finish; + } else if (size == 0) { + /* no remote data, delete the local is_remote pampd */ + pampd = NULL; + if (eph) + ramster_remote_eph_pages_unsucc_get++; + else + BUG(); + delete = true; + goto finish; + } + if (pampd_is_intransit(pampd)) { + /* + * a pampd is marked intransit if it is remote and space has + * been allocated for it locally (note, only happens for + * persistent pages, in which case the remote copy is freed) + */ + BUG_ON(eph); + pampd = pampd_mask_intransit_and_remote(pampd); + zbud_copy_to_zbud(pampd, data, size); + } else { + /* + * setting pampd to NULL tells tmem_localify_finish to leave + * pampd alone... meaning it is left pointing to the + * remote copy + */ + pampd = NULL; + obj = NULL; + } + /* + * but in all cases, we decompress direct-to-memory to complete + * the remotify and return success + */ + BUG_ON(extra == NULL); + zcache_decompress_to_page(data, size, (struct page *)extra); + if (eph) + ramster_remote_eph_pages_succ_get++; + else + ramster_remote_pers_pages_succ_get++; + ret = 0; +finish: + tmem_localify_finish(obj, index, pampd, saved_hb, delete); + zcache_put_pool(pool); + local_irq_restore(flags); +out: + return ret; +} + +void ramster_pampd_new_obj(struct tmem_obj *obj) +{ + obj->extra = NULL; +} + +void ramster_pampd_free_obj(struct tmem_pool *pool, struct tmem_obj *obj, + bool pool_destroy) +{ + struct flushlist_node *flnode; + + BUG_ON(preemptible()); + if (obj->extra == NULL) + return; + if (pool_destroy && is_ephemeral(pool)) + /* FIXME don't bother with remote eph data for now */ + return; + BUG_ON(!pampd_is_remote(obj->extra)); + flnode = ramster_flnode_alloc(pool); + flnode->xh.client_id = pampd_remote_node(obj->extra); + flnode->xh.pool_id = pool->pool_id; + flnode->xh.oid = obj->oid; + flnode->xh.index = FLUSH_ENTIRE_OBJECT; + flnode->rem_op.op = RAMSTER_REMOTIFY_FLUSH_OBJ; + spin_lock(&ramster_rem_op_list_lock); + list_add(&flnode->rem_op.list, &ramster_rem_op_list); + spin_unlock(&ramster_rem_op_list_lock); +} + +/* + * Called on a remote persistent tmem_get to attempt to preallocate + * local storage for the data contained in the remote persistent page. + * If successfully preallocated, returns the pampd, marked as remote and + * in_transit. Else returns NULL. Note that the appropriate tmem data + * structure must be locked. + */ +void *ramster_pampd_repatriate_preload(void *pampd, struct tmem_pool *pool, + struct tmem_oid *oidp, uint32_t index, + bool *intransit) +{ + int clen = pampd_remote_size(pampd), c; + void *ret_pampd = NULL; + unsigned long flags; + struct tmem_handle th; + + BUG_ON(!pampd_is_remote(pampd)); + BUG_ON(is_ephemeral(pool)); + if (use_frontswap_exclusive_gets) + /* don't need local storage */ + goto out; + if (pampd_is_intransit(pampd)) { + /* + * to avoid multiple allocations (and maybe a memory leak) + * don't preallocate if already in the process of being + * repatriated + */ + *intransit = true; + goto out; + } + *intransit = false; + local_irq_save(flags); + th.client_id = pampd_remote_node(pampd); + th.pool_id = pool->pool_id; + th.oid = *oidp; + th.index = index; + ret_pampd = zcache_pampd_create(NULL, clen, true, false, &th); + if (ret_pampd != NULL) { + /* + * a pampd is marked intransit if it is remote and space has + * been allocated for it locally (note, only happens for + * persistent pages, in which case the remote copy is freed) + */ + ret_pampd = pampd_mark_intransit(ret_pampd); + c = atomic_dec_return(&ramster_remote_pers_pages); + WARN_ON_ONCE(c < 0); + } else { + ramster_pers_pages_remote_nomem++; + } + local_irq_restore(flags); +out: + return ret_pampd; +} + +/* + * Called on a remote tmem_get to invoke a message to fetch the page. + * Might sleep so no tmem locks can be held. "extra" is passed + * all the way through the round-trip messaging to ramster_localify. + */ +int ramster_pampd_repatriate(void *fake_pampd, void *real_pampd, + struct tmem_pool *pool, + struct tmem_oid *oid, uint32_t index, + bool free, void *extra) +{ + struct tmem_xhandle xh; + int ret; + + if (pampd_is_intransit(real_pampd)) + /* have local space pre-reserved, so free remote copy */ + free = true; + xh = tmem_xhandle_fill(LOCAL_CLIENT, pool, oid, index); + /* unreliable request/response for now */ + ret = r2net_remote_async_get(&xh, free, + pampd_remote_node(fake_pampd), + pampd_remote_size(fake_pampd), + pampd_remote_cksum(fake_pampd), + extra); + return ret; +} + +bool ramster_pampd_is_remote(void *pampd) +{ + return pampd_is_remote(pampd); +} + +int ramster_pampd_replace_in_obj(void *new_pampd, struct tmem_obj *obj) +{ + int ret = -1; + + if (new_pampd != NULL) { + if (obj->extra == NULL) + obj->extra = new_pampd; + /* enforce that all remote pages in an object reside + * in the same node! */ + else if (pampd_remote_node(new_pampd) != + pampd_remote_node((void *)(obj->extra))) + BUG(); + ret = 0; + } + return ret; +} + +void *ramster_pampd_free(void *pampd, struct tmem_pool *pool, + struct tmem_oid *oid, uint32_t index, bool acct) +{ + bool eph = is_ephemeral(pool); + void *local_pampd = NULL; + int c; + + BUG_ON(preemptible()); + BUG_ON(!pampd_is_remote(pampd)); + WARN_ON(acct == false); + if (oid == NULL) { + /* + * a NULL oid means to ignore this pampd free + * as the remote freeing will be handled elsewhere + */ + } else if (eph) { + /* FIXME remote flush optional but probably good idea */ + } else if (pampd_is_intransit(pampd)) { + /* did a pers remote get_and_free, so just free local */ + local_pampd = pampd_mask_intransit_and_remote(pampd); + } else { + struct flushlist_node *flnode = + ramster_flnode_alloc(pool); + + flnode->xh.client_id = pampd_remote_node(pampd); + flnode->xh.pool_id = pool->pool_id; + flnode->xh.oid = *oid; + flnode->xh.index = index; + flnode->rem_op.op = RAMSTER_REMOTIFY_FLUSH_PAGE; + spin_lock(&ramster_rem_op_list_lock); + list_add(&flnode->rem_op.list, &ramster_rem_op_list); + spin_unlock(&ramster_rem_op_list_lock); + c = atomic_dec_return(&ramster_remote_pers_pages); + WARN_ON_ONCE(c < 0); + } + return local_pampd; +} + +void ramster_count_foreign_pages(bool eph, int count) +{ + int c; + + BUG_ON(count != 1 && count != -1); + if (eph) { + if (count > 0) { + c = atomic_inc_return( + &ramster_foreign_eph_pages_atomic); + if (c > ramster_foreign_eph_pages_max) + ramster_foreign_eph_pages_max = c; + } else { + c = atomic_dec_return(&ramster_foreign_eph_pages_atomic); + WARN_ON_ONCE(c < 0); + } + ramster_foreign_eph_pages = c; + } else { + if (count > 0) { + c = atomic_inc_return( + &ramster_foreign_pers_pages_atomic); + if (c > ramster_foreign_pers_pages_max) + ramster_foreign_pers_pages_max = c; + } else { + c = atomic_dec_return( + &ramster_foreign_pers_pages_atomic); + WARN_ON_ONCE(c < 0); + } + ramster_foreign_pers_pages = c; + } +} + +/* + * For now, just push over a few pages every few seconds to + * ensure that it basically works + */ +static struct workqueue_struct *ramster_remotify_workqueue; +static void ramster_remotify_process(struct work_struct *work); +static DECLARE_DELAYED_WORK(ramster_remotify_worker, + ramster_remotify_process); + +static void ramster_remotify_queue_delayed_work(unsigned long delay) +{ + if (!queue_delayed_work(ramster_remotify_workqueue, + &ramster_remotify_worker, delay)) + pr_err("ramster_remotify: bad workqueue\n"); +} + +static void ramster_remote_flush_page(struct flushlist_node *flnode) +{ + struct tmem_xhandle *xh; + int remotenode, ret; + + preempt_disable(); + xh = &flnode->xh; + remotenode = flnode->xh.client_id; + ret = r2net_remote_flush(xh, remotenode); + if (ret >= 0) + ramster_remote_pages_flushed++; + else + ramster_remote_page_flushes_failed++; + preempt_enable_no_resched(); + ramster_flnode_free(flnode, NULL); +} + +static void ramster_remote_flush_object(struct flushlist_node *flnode) +{ + struct tmem_xhandle *xh; + int remotenode, ret; + + preempt_disable(); + xh = &flnode->xh; + remotenode = flnode->xh.client_id; + ret = r2net_remote_flush_object(xh, remotenode); + if (ret >= 0) + ramster_remote_objects_flushed++; + else + ramster_remote_object_flushes_failed++; + preempt_enable_no_resched(); + ramster_flnode_free(flnode, NULL); +} + +int ramster_remotify_pageframe(bool eph) +{ + struct tmem_xhandle xh; + unsigned int size; + int remotenode, ret, zbuds; + struct tmem_pool *pool; + unsigned long flags; + unsigned char cksum; + char *p; + int i, j; + unsigned char *tmpmem[2]; + struct tmem_handle th[2]; + unsigned int zsize[2]; + + tmpmem[0] = __get_cpu_var(ramster_remoteputmem1); + tmpmem[1] = __get_cpu_var(ramster_remoteputmem2); + local_bh_disable(); + zbuds = zbud_make_zombie_lru(&th[0], &tmpmem[0], &zsize[0], eph); + /* now OK to release lock set in caller */ + local_bh_enable(); + if (zbuds == 0) + goto out; + BUG_ON(zbuds > 2); + for (i = 0; i < zbuds; i++) { + xh.client_id = th[i].client_id; + xh.pool_id = th[i].pool_id; + xh.oid = th[i].oid; + xh.index = th[i].index; + size = zsize[i]; + BUG_ON(size == 0 || size > zbud_max_buddy_size()); + for (p = tmpmem[i], cksum = 0, j = 0; j < size; j++) + cksum += *p++; + ret = r2net_remote_put(&xh, tmpmem[i], size, eph, &remotenode); + if (ret != 0) { + /* + * This is some form of a memory leak... if the remote put + * fails, there will never be another attempt to remotify + * this page. But since we've dropped the zv pointer, + * the page may have been freed or the data replaced + * so we can't just "put it back" in the remote op list. + * Even if we could, not sure where to put it in the list + * because there may be flushes that must be strictly + * ordered vs the put. So leave this as a FIXME for now. + * But count them so we know if it becomes a problem. + */ + if (eph) + ramster_eph_pages_remote_failed++; + else + ramster_pers_pages_remote_failed++; + break; + } else { + if (!eph) + atomic_inc(&ramster_remote_pers_pages); + } + if (eph) + ramster_eph_pages_remoted++; + else + ramster_pers_pages_remoted++; + /* + * data was successfully remoted so change the local version to + * point to the remote node where it landed + */ + local_bh_disable(); + pool = zcache_get_pool_by_id(LOCAL_CLIENT, xh.pool_id); + local_irq_save(flags); + (void)tmem_replace(pool, &xh.oid, xh.index, + pampd_make_remote(remotenode, size, cksum)); + local_irq_restore(flags); + zcache_put_pool(pool); + local_bh_enable(); + } +out: + return zbuds; +} + +static void zcache_do_remotify_flushes(void) +{ + struct ramster_remotify_hdr *rem_op; + union remotify_list_node *u; + + while (1) { + spin_lock(&ramster_rem_op_list_lock); + if (list_empty(&ramster_rem_op_list)) { + spin_unlock(&ramster_rem_op_list_lock); + goto out; + } + rem_op = list_first_entry(&ramster_rem_op_list, + struct ramster_remotify_hdr, list); + list_del_init(&rem_op->list); + spin_unlock(&ramster_rem_op_list_lock); + u = (union remotify_list_node *)rem_op; + switch (rem_op->op) { + case RAMSTER_REMOTIFY_FLUSH_PAGE: + ramster_remote_flush_page((struct flushlist_node *)u); + break; + case RAMSTER_REMOTIFY_FLUSH_OBJ: + ramster_remote_flush_object((struct flushlist_node *)u); + break; + default: + BUG(); + } + } +out: + return; +} + +static void ramster_remotify_process(struct work_struct *work) +{ + static bool remotify_in_progress; + int i; + + BUG_ON(irqs_disabled()); + if (remotify_in_progress) + goto requeue; + if (ramster_remote_target_nodenum == -1) + goto requeue; + remotify_in_progress = true; + if (use_cleancache && ramster_eph_remotify_enable) { + for (i = 0; i < 100; i++) { + zcache_do_remotify_flushes(); + (void)ramster_remotify_pageframe(true); + } + } + if (use_frontswap && ramster_pers_remotify_enable) { + for (i = 0; i < 100; i++) { + zcache_do_remotify_flushes(); + (void)ramster_remotify_pageframe(false); + } + } + remotify_in_progress = false; +requeue: + ramster_remotify_queue_delayed_work(HZ); +} + +void __init ramster_remotify_init(void) +{ + unsigned long n = 60UL; + ramster_remotify_workqueue = + create_singlethread_workqueue("ramster_remotify"); + ramster_remotify_queue_delayed_work(n * HZ); +} + +static ssize_t ramster_manual_node_up_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + int i; + char *p = buf; + for (i = 0; i < MANUAL_NODES; i++) + if (ramster_nodes_manual_up[i]) + p += sprintf(p, "%d ", i); + p += sprintf(p, "\n"); + return p - buf; +} + +static ssize_t ramster_manual_node_up_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int err; + unsigned long node_num; + + err = kstrtoul(buf, 10, &node_num); + if (err) { + pr_err("ramster: bad strtoul?\n"); + return -EINVAL; + } + if (node_num >= MANUAL_NODES) { + pr_err("ramster: bad node_num=%lu?\n", node_num); + return -EINVAL; + } + if (ramster_nodes_manual_up[node_num]) { + pr_err("ramster: node %d already up, ignoring\n", + (int)node_num); + } else { + ramster_nodes_manual_up[node_num] = true; + r2net_hb_node_up_manual((int)node_num); + } + return count; +} + +static struct kobj_attribute ramster_manual_node_up_attr = { + .attr = { .name = "manual_node_up", .mode = 0644 }, + .show = ramster_manual_node_up_show, + .store = ramster_manual_node_up_store, +}; + +static ssize_t ramster_remote_target_nodenum_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + if (ramster_remote_target_nodenum == -1UL) + return sprintf(buf, "unset\n"); + else + return sprintf(buf, "%d\n", ramster_remote_target_nodenum); +} + +static ssize_t ramster_remote_target_nodenum_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t count) +{ + int err; + unsigned long node_num; + + err = kstrtoul(buf, 10, &node_num); + if (err) { + pr_err("ramster: bad strtoul?\n"); + return -EINVAL; + } else if (node_num == -1UL) { + pr_err("ramster: disabling all remotification, " + "data may still reside on remote nodes however\n"); + return -EINVAL; + } else if (node_num >= MANUAL_NODES) { + pr_err("ramster: bad node_num=%lu?\n", node_num); + return -EINVAL; + } else if (!ramster_nodes_manual_up[node_num]) { + pr_err("ramster: node %d not up, ignoring setting " + "of remotification target\n", (int)node_num); + } else if (r2net_remote_target_node_set((int)node_num) >= 0) { + pr_info("ramster: node %d set as remotification target\n", + (int)node_num); + ramster_remote_target_nodenum = (int)node_num; + } else { + pr_err("ramster: bad num to node node_num=%d?\n", + (int)node_num); + return -EINVAL; + } + return count; +} + +static struct kobj_attribute ramster_remote_target_nodenum_attr = { + .attr = { .name = "remote_target_nodenum", .mode = 0644 }, + .show = ramster_remote_target_nodenum_show, + .store = ramster_remote_target_nodenum_store, +}; + +#define RAMSTER_SYSFS_RO(_name) \ + static ssize_t ramster_##_name##_show(struct kobject *kobj, \ + struct kobj_attribute *attr, char *buf) \ + { \ + return sprintf(buf, "%lu\n", ramster_##_name); \ + } \ + static struct kobj_attribute ramster_##_name##_attr = { \ + .attr = { .name = __stringify(_name), .mode = 0444 }, \ + .show = ramster_##_name##_show, \ + } + +#define RAMSTER_SYSFS_RW(_name) \ + static ssize_t ramster_##_name##_show(struct kobject *kobj, \ + struct kobj_attribute *attr, char *buf) \ + { \ + return sprintf(buf, "%lu\n", ramster_##_name); \ + } \ + static ssize_t ramster_##_name##_store(struct kobject *kobj, \ + struct kobj_attribute *attr, const char *buf, size_t count) \ + { \ + int err; \ + unsigned long enable; \ + err = kstrtoul(buf, 10, &enable); \ + if (err) \ + return -EINVAL; \ + ramster_##_name = enable; \ + return count; \ + } \ + static struct kobj_attribute ramster_##_name##_attr = { \ + .attr = { .name = __stringify(_name), .mode = 0644 }, \ + .show = ramster_##_name##_show, \ + .store = ramster_##_name##_store, \ + } + +#define RAMSTER_SYSFS_RO_ATOMIC(_name) \ + static ssize_t ramster_##_name##_show(struct kobject *kobj, \ + struct kobj_attribute *attr, char *buf) \ + { \ + return sprintf(buf, "%d\n", atomic_read(&ramster_##_name)); \ + } \ + static struct kobj_attribute ramster_##_name##_attr = { \ + .attr = { .name = __stringify(_name), .mode = 0444 }, \ + .show = ramster_##_name##_show, \ + } + +RAMSTER_SYSFS_RO(interface_revision); +RAMSTER_SYSFS_RO_ATOMIC(remote_pers_pages); +RAMSTER_SYSFS_RW(pers_remotify_enable); +RAMSTER_SYSFS_RW(eph_remotify_enable); + +static struct attribute *ramster_attrs[] = { + &ramster_interface_revision_attr.attr, + &ramster_remote_pers_pages_attr.attr, + &ramster_manual_node_up_attr.attr, + &ramster_remote_target_nodenum_attr.attr, + &ramster_pers_remotify_enable_attr.attr, + &ramster_eph_remotify_enable_attr.attr, + NULL, +}; + +static struct attribute_group ramster_attr_group = { + .attrs = ramster_attrs, + .name = "ramster", +}; + +/* + * frontswap selfshrinking + */ + +/* In HZ, controls frequency of worker invocation. */ +static unsigned int selfshrink_interval __read_mostly = 5; +/* Enable/disable with sysfs. */ +static bool frontswap_selfshrinking __read_mostly; + +static void selfshrink_process(struct work_struct *work); +static DECLARE_DELAYED_WORK(selfshrink_worker, selfshrink_process); + +/* Enable/disable with kernel boot option. */ +static bool use_frontswap_selfshrink __initdata = true; + +/* + * The default values for the following parameters were deemed reasonable + * by experimentation, may be workload-dependent, and can all be + * adjusted via sysfs. + */ + +/* Control rate for frontswap shrinking. Higher hysteresis is slower. */ +static unsigned int frontswap_hysteresis __read_mostly = 20; + +/* + * Number of selfshrink worker invocations to wait before observing that + * frontswap selfshrinking should commence. Note that selfshrinking does + * not use a separate worker thread. + */ +static unsigned int frontswap_inertia __read_mostly = 3; + +/* Countdown to next invocation of frontswap_shrink() */ +static unsigned long frontswap_inertia_counter; + +/* + * Invoked by the selfshrink worker thread, uses current number of pages + * in frontswap (frontswap_curr_pages()), previous status, and control + * values (hysteresis and inertia) to determine if frontswap should be + * shrunk and what the new frontswap size should be. Note that + * frontswap_shrink is essentially a partial swapoff that immediately + * transfers pages from the "swap device" (frontswap) back into kernel + * RAM; despite the name, frontswap "shrinking" is very different from + * the "shrinker" interface used by the kernel MM subsystem to reclaim + * memory. + */ +static void frontswap_selfshrink(void) +{ + static unsigned long cur_frontswap_pages; + static unsigned long last_frontswap_pages; + static unsigned long tgt_frontswap_pages; + + last_frontswap_pages = cur_frontswap_pages; + cur_frontswap_pages = frontswap_curr_pages(); + if (!cur_frontswap_pages || + (cur_frontswap_pages > last_frontswap_pages)) { + frontswap_inertia_counter = frontswap_inertia; + return; + } + if (frontswap_inertia_counter && --frontswap_inertia_counter) + return; + if (cur_frontswap_pages <= frontswap_hysteresis) + tgt_frontswap_pages = 0; + else + tgt_frontswap_pages = cur_frontswap_pages - + (cur_frontswap_pages / frontswap_hysteresis); + frontswap_shrink(tgt_frontswap_pages); +} + +static int __init ramster_nofrontswap_selfshrink_setup(char *s) +{ + use_frontswap_selfshrink = false; + return 1; +} + +__setup("noselfshrink", ramster_nofrontswap_selfshrink_setup); + +static void selfshrink_process(struct work_struct *work) +{ + if (frontswap_selfshrinking && frontswap_enabled) { + frontswap_selfshrink(); + schedule_delayed_work(&selfshrink_worker, + selfshrink_interval * HZ); + } +} + +void ramster_cpu_up(int cpu) +{ + unsigned char *p1 = kzalloc(PAGE_SIZE, GFP_KERNEL | __GFP_REPEAT); + unsigned char *p2 = kzalloc(PAGE_SIZE, GFP_KERNEL | __GFP_REPEAT); + BUG_ON(!p1 || !p2); + per_cpu(ramster_remoteputmem1, cpu) = p1; + per_cpu(ramster_remoteputmem2, cpu) = p2; +} + +void ramster_cpu_down(int cpu) +{ + struct ramster_preload *kp; + + kfree(per_cpu(ramster_remoteputmem1, cpu)); + per_cpu(ramster_remoteputmem1, cpu) = NULL; + kfree(per_cpu(ramster_remoteputmem2, cpu)); + per_cpu(ramster_remoteputmem2, cpu) = NULL; + kp = &per_cpu(ramster_preloads, cpu); + if (kp->flnode) { + kmem_cache_free(ramster_flnode_cache, kp->flnode); + kp->flnode = NULL; + } +} + +void ramster_register_pamops(struct tmem_pamops *pamops) +{ + pamops->free_obj = ramster_pampd_free_obj; + pamops->new_obj = ramster_pampd_new_obj; + pamops->replace_in_obj = ramster_pampd_replace_in_obj; + pamops->is_remote = ramster_pampd_is_remote; + pamops->repatriate = ramster_pampd_repatriate; + pamops->repatriate_preload = ramster_pampd_repatriate_preload; +} + +void __init ramster_init(bool cleancache, bool frontswap, + bool frontswap_exclusive_gets) +{ + int ret = 0; + + if (cleancache) + use_cleancache = true; + if (frontswap) + use_frontswap = true; + if (frontswap_exclusive_gets) + use_frontswap_exclusive_gets = true; + ramster_debugfs_init(); + ret = sysfs_create_group(mm_kobj, &ramster_attr_group); + if (ret) + pr_err("ramster: can't create sysfs for ramster\n"); + (void)r2net_register_handlers(); + INIT_LIST_HEAD(&ramster_rem_op_list); + ramster_flnode_cache = kmem_cache_create("ramster_flnode", + sizeof(struct flushlist_node), 0, 0, NULL); + frontswap_selfshrinking = use_frontswap_selfshrink; + if (frontswap_selfshrinking) { + pr_info("ramster: Initializing frontswap selfshrink driver.\n"); + schedule_delayed_work(&selfshrink_worker, + selfshrink_interval * HZ); + } + ramster_remotify_init(); +} diff --git a/drivers/staging/ramster/ramster/ramster.h b/drivers/staging/ramster/ramster/ramster.h new file mode 100644 index 000000000000..12ae56f09ca4 --- /dev/null +++ b/drivers/staging/ramster/ramster/ramster.h @@ -0,0 +1,161 @@ +/* + * ramster.h + * + * Peer-to-peer transcendent memory + * + * Copyright (c) 2009-2012, Dan Magenheimer, Oracle Corp. + */ + +#ifndef _RAMSTER_RAMSTER_H_ +#define _RAMSTER_RAMSTER_H_ + +#include "../tmem.h" + +enum ramster_remotify_op { + RAMSTER_REMOTIFY_FLUSH_PAGE, + RAMSTER_REMOTIFY_FLUSH_OBJ, +}; + +struct ramster_remotify_hdr { + enum ramster_remotify_op op; + struct list_head list; +}; + +struct flushlist_node { + struct ramster_remotify_hdr rem_op; + struct tmem_xhandle xh; +}; + +struct ramster_preload { + struct flushlist_node *flnode; +}; + +union remotify_list_node { + struct ramster_remotify_hdr rem_op; + struct { + struct ramster_remotify_hdr rem_op; + struct tmem_handle th; + } zbud_hdr; + struct flushlist_node flist; +}; + +/* + * format of remote pampd: + * bit 0 is reserved for zbud (in-page buddy selection) + * bit 1 == intransit + * bit 2 == is_remote... if this bit is set, then + * bit 3-10 == remotenode + * bit 11-23 == size + * bit 24-31 == cksum + */ +#define FAKE_PAMPD_INTRANSIT_BITS 1 +#define FAKE_PAMPD_ISREMOTE_BITS 1 +#define FAKE_PAMPD_REMOTENODE_BITS 8 +#define FAKE_PAMPD_REMOTESIZE_BITS 13 +#define FAKE_PAMPD_CHECKSUM_BITS 8 + +#define FAKE_PAMPD_INTRANSIT_SHIFT 1 +#define FAKE_PAMPD_ISREMOTE_SHIFT (FAKE_PAMPD_INTRANSIT_SHIFT + \ + FAKE_PAMPD_INTRANSIT_BITS) +#define FAKE_PAMPD_REMOTENODE_SHIFT (FAKE_PAMPD_ISREMOTE_SHIFT + \ + FAKE_PAMPD_ISREMOTE_BITS) +#define FAKE_PAMPD_REMOTESIZE_SHIFT (FAKE_PAMPD_REMOTENODE_SHIFT + \ + FAKE_PAMPD_REMOTENODE_BITS) +#define FAKE_PAMPD_CHECKSUM_SHIFT (FAKE_PAMPD_REMOTESIZE_SHIFT + \ + FAKE_PAMPD_REMOTESIZE_BITS) + +#define FAKE_PAMPD_MASK(x) ((1UL << (x)) - 1) + +static inline void *pampd_make_remote(int remotenode, size_t size, + unsigned char cksum) +{ + unsigned long fake_pampd = 0; + fake_pampd |= 1UL << FAKE_PAMPD_ISREMOTE_SHIFT; + fake_pampd |= ((unsigned long)remotenode & + FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTENODE_BITS)) << + FAKE_PAMPD_REMOTENODE_SHIFT; + fake_pampd |= ((unsigned long)size & + FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTESIZE_BITS)) << + FAKE_PAMPD_REMOTESIZE_SHIFT; + fake_pampd |= ((unsigned long)cksum & + FAKE_PAMPD_MASK(FAKE_PAMPD_CHECKSUM_BITS)) << + FAKE_PAMPD_CHECKSUM_SHIFT; + return (void *)fake_pampd; +} + +static inline unsigned int pampd_remote_node(void *pampd) +{ + unsigned long fake_pampd = (unsigned long)pampd; + return (fake_pampd >> FAKE_PAMPD_REMOTENODE_SHIFT) & + FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTENODE_BITS); +} + +static inline unsigned int pampd_remote_size(void *pampd) +{ + unsigned long fake_pampd = (unsigned long)pampd; + return (fake_pampd >> FAKE_PAMPD_REMOTESIZE_SHIFT) & + FAKE_PAMPD_MASK(FAKE_PAMPD_REMOTESIZE_BITS); +} + +static inline unsigned char pampd_remote_cksum(void *pampd) +{ + unsigned long fake_pampd = (unsigned long)pampd; + return (fake_pampd >> FAKE_PAMPD_CHECKSUM_SHIFT) & + FAKE_PAMPD_MASK(FAKE_PAMPD_CHECKSUM_BITS); +} + +static inline bool pampd_is_remote(void *pampd) +{ + unsigned long fake_pampd = (unsigned long)pampd; + return (fake_pampd >> FAKE_PAMPD_ISREMOTE_SHIFT) & + FAKE_PAMPD_MASK(FAKE_PAMPD_ISREMOTE_BITS); +} + +static inline bool pampd_is_intransit(void *pampd) +{ + unsigned long fake_pampd = (unsigned long)pampd; + return (fake_pampd >> FAKE_PAMPD_INTRANSIT_SHIFT) & + FAKE_PAMPD_MASK(FAKE_PAMPD_INTRANSIT_BITS); +} + +/* note that it is a BUG for intransit to be set without isremote also set */ +static inline void *pampd_mark_intransit(void *pampd) +{ + unsigned long fake_pampd = (unsigned long)pampd; + + fake_pampd |= 1UL << FAKE_PAMPD_ISREMOTE_SHIFT; + fake_pampd |= 1UL << FAKE_PAMPD_INTRANSIT_SHIFT; + return (void *)fake_pampd; +} + +static inline void *pampd_mask_intransit_and_remote(void *marked_pampd) +{ + unsigned long pampd = (unsigned long)marked_pampd; + + pampd &= ~(1UL << FAKE_PAMPD_INTRANSIT_SHIFT); + pampd &= ~(1UL << FAKE_PAMPD_ISREMOTE_SHIFT); + return (void *)pampd; +} + +extern int r2net_remote_async_get(struct tmem_xhandle *, + bool, int, size_t, uint8_t, void *extra); +extern int r2net_remote_put(struct tmem_xhandle *, char *, size_t, + bool, int *); +extern int r2net_remote_flush(struct tmem_xhandle *, int); +extern int r2net_remote_flush_object(struct tmem_xhandle *, int); +extern int r2net_register_handlers(void); +extern int r2net_remote_target_node_set(int); + +extern int ramster_remotify_pageframe(bool); +extern void ramster_init(bool, bool, bool); +extern void ramster_register_pamops(struct tmem_pamops *); +extern int ramster_localify(int, struct tmem_oid *oidp, uint32_t, char *, + unsigned int, void *); +extern void *ramster_pampd_free(void *, struct tmem_pool *, struct tmem_oid *, + uint32_t, bool); +extern void ramster_count_foreign_pages(bool, int); +extern int ramster_do_preload_flnode(struct tmem_pool *); +extern void ramster_cpu_up(int); +extern void ramster_cpu_down(int); + +#endif /* _RAMSTER_RAMSTER_H */ diff --git a/drivers/staging/ramster/cluster/ramster_nodemanager.h b/drivers/staging/ramster/ramster/ramster_nodemanager.h index 49f879d943ab..49f879d943ab 100644 --- a/drivers/staging/ramster/cluster/ramster_nodemanager.h +++ b/drivers/staging/ramster/ramster/ramster_nodemanager.h diff --git a/drivers/staging/ramster/cluster/tcp.c b/drivers/staging/ramster/ramster/tcp.c index d0a07d722b61..aa2a1a763aa4 100644 --- a/drivers/staging/ramster/cluster/tcp.c +++ b/drivers/staging/ramster/ramster/tcp.c @@ -541,8 +541,7 @@ static void r2net_set_nn_state(struct r2net_node *nn, } if (was_valid && !valid) { - printk(KERN_NOTICE "ramster: No longer connected to " - SC_NODEF_FMT "\n", + pr_notice("ramster: No longer connected to " SC_NODEF_FMT "\n", old_sc->sc_node->nd_name, old_sc->sc_node->nd_num, &old_sc->sc_node->nd_ipv4_address, ntohs(old_sc->sc_node->nd_ipv4_port)); @@ -551,7 +550,7 @@ static void r2net_set_nn_state(struct r2net_node *nn, if (!was_valid && valid) { cancel_delayed_work(&nn->nn_connect_expired); - printk(KERN_NOTICE "ramster: %s " SC_NODEF_FMT "\n", + pr_notice("ramster: %s " SC_NODEF_FMT "\n", r2nm_this_node() > sc->sc_node->nd_num ? "Connected to" : "Accepted connection from", sc->sc_node->nd_name, sc->sc_node->nd_num, @@ -644,7 +643,7 @@ static void r2net_state_change(struct sock *sk) r2net_sc_queue_work(sc, &sc->sc_connect_work); break; default: - printk(KERN_INFO "ramster: Connection to " + pr_info("ramster: Connection to " SC_NODEF_FMT " shutdown, state %d\n", sc->sc_node->nd_name, sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address, @@ -1160,7 +1159,8 @@ int r2net_send_message_vec(u32 msg_type, u32 key, struct kvec *caller_vec, /* wait on other node's handler */ r2net_set_nst_status_time(&nst); - wait_event(nsw.ns_wq, r2net_nsw_completed(nn, &nsw)); + wait_event(nsw.ns_wq, r2net_nsw_completed(nn, &nsw) || + nn->nn_persistent_error || !nn->nn_sc_valid); r2net_update_send_stats(&nst, sc); @@ -1325,8 +1325,10 @@ static int r2net_process_message(struct r2net_sock_container *sc, if (be16_to_cpu(hdr->data_len) > nmh->nh_max_len) syserr = R2NET_ERR_OVERFLOW; - if (syserr != R2NET_ERR_NONE) + if (syserr != R2NET_ERR_NONE) { + pr_err("ramster_r2net, message length problem\n"); goto out_respond; + } r2net_set_func_start_time(sc); sc->sc_msg_key = be32_to_cpu(hdr->key); @@ -1393,7 +1395,7 @@ static int r2net_check_handshake(struct r2net_sock_container *sc) struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num); if (hand->protocol_version != cpu_to_be64(R2NET_PROTOCOL_VERSION)) { - printk(KERN_NOTICE "ramster: " SC_NODEF_FMT " Advertised net " + pr_notice("ramster: " SC_NODEF_FMT " Advertised net " "protocol version %llu but %llu is required. " "Disconnecting.\n", sc->sc_node->nd_name, sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address, @@ -1413,7 +1415,7 @@ static int r2net_check_handshake(struct r2net_sock_container *sc) */ if (be32_to_cpu(hand->r2net_idle_timeout_ms) != r2net_idle_timeout()) { - printk(KERN_NOTICE "ramster: " SC_NODEF_FMT " uses a network " + pr_notice("ramster: " SC_NODEF_FMT " uses a network " "idle timeout of %u ms, but we use %u ms locally. " "Disconnecting.\n", sc->sc_node->nd_name, sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address, @@ -1426,7 +1428,7 @@ static int r2net_check_handshake(struct r2net_sock_container *sc) if (be32_to_cpu(hand->r2net_keepalive_delay_ms) != r2net_keepalive_delay()) { - printk(KERN_NOTICE "ramster: " SC_NODEF_FMT " uses a keepalive " + pr_notice("ramster: " SC_NODEF_FMT " uses a keepalive " "delay of %u ms, but we use %u ms locally. " "Disconnecting.\n", sc->sc_node->nd_name, sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address, @@ -1439,7 +1441,7 @@ static int r2net_check_handshake(struct r2net_sock_container *sc) if (be32_to_cpu(hand->r2hb_heartbeat_timeout_ms) != R2HB_MAX_WRITE_TIMEOUT_MS) { - printk(KERN_NOTICE "ramster: " SC_NODEF_FMT " uses a heartbeat " + pr_notice("ramster: " SC_NODEF_FMT " uses a heartbeat " "timeout of %u ms, but we use %u ms locally. " "Disconnecting.\n", sc->sc_node->nd_name, sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address, @@ -1516,6 +1518,7 @@ static int r2net_advance_rx(struct r2net_sock_container *sc) if (be16_to_cpu(hdr->data_len) > R2NET_MAX_PAYLOAD_BYTES) ret = -EOVERFLOW; + WARN_ON_ONCE(ret == -EOVERFLOW); } } if (ret <= 0) @@ -1583,7 +1586,6 @@ static void r2net_rx_until_empty(struct work_struct *work) /* not permanent so read failed handshake can retry */ r2net_ensure_shutdown(nn, sc, 0); } - sc_put(sc); } @@ -1659,6 +1661,7 @@ static void r2net_sc_send_keep_req(struct work_struct *work) static void r2net_idle_timer(unsigned long data) { struct r2net_sock_container *sc = (struct r2net_sock_container *)data; + struct r2net_node *nn = r2net_nn_from_num(sc->sc_node->nd_num); #ifdef CONFIG_DEBUG_FS unsigned long msecs = ktime_to_ms(ktime_get()) - ktime_to_ms(sc->sc_tv_timer); @@ -1666,7 +1669,7 @@ static void r2net_idle_timer(unsigned long data) unsigned long msecs = r2net_idle_timeout(); #endif - printk(KERN_NOTICE "ramster: Connection to " SC_NODEF_FMT " has been " + pr_notice("ramster: Connection to " SC_NODEF_FMT " has been " "idle for %lu.%lu secs, shutting it down.\n", sc->sc_node->nd_name, sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address, ntohs(sc->sc_node->nd_ipv4_port), @@ -1676,13 +1679,8 @@ static void r2net_idle_timer(unsigned long data) * Initialize the nn_timeout so that the next connection attempt * will continue in r2net_start_connect. */ - /* Avoid spurious shutdowns... not sure if this is still necessary */ - pr_err("ramster_idle_timer, skipping shutdown work\n"); -#if 0 - /* old code used to do these two lines */ atomic_set(&nn->nn_timeout, 1); r2net_sc_queue_work(sc, &sc->sc_shutdown_work); -#endif } static void r2net_sc_reset_idle_timer(struct r2net_sock_container *sc) @@ -1807,7 +1805,7 @@ static void r2net_start_connect(struct work_struct *work) out: if (ret) { - printk(KERN_NOTICE "ramster: Connect attempt to " SC_NODEF_FMT + pr_notice("ramster: Connect attempt to " SC_NODEF_FMT " failed with errno %d\n", sc->sc_node->nd_name, sc->sc_node->nd_num, &sc->sc_node->nd_ipv4_address, ntohs(sc->sc_node->nd_ipv4_port), ret); @@ -1833,7 +1831,7 @@ static void r2net_connect_expired(struct work_struct *work) spin_lock(&nn->nn_lock); if (!nn->nn_sc_valid) { - printk(KERN_NOTICE "ramster: No connection established with " + pr_notice("ramster: No connection established with " "node %u after %u.%u seconds, giving up.\n", r2net_num_from_nn(nn), r2net_idle_timeout() / 1000, @@ -1969,7 +1967,7 @@ static int r2net_accept_one(struct socket *sock) node = r2nm_get_node_by_ip(sin.sin_addr.s_addr); if (node == NULL) { - printk(KERN_NOTICE "ramster: Attempt to connect from unknown " + pr_notice("ramster: Attempt to connect from unknown " "node at %pI4:%d\n", &sin.sin_addr.s_addr, ntohs(sin.sin_port)); ret = -EINVAL; @@ -1978,7 +1976,7 @@ static int r2net_accept_one(struct socket *sock) if (r2nm_this_node() >= node->nd_num) { local_node = r2nm_get_node_by_num(r2nm_this_node()); - printk(KERN_NOTICE "ramster: Unexpected connect attempt seen " + pr_notice("ramster: Unexpected connect attempt seen " "at node '%s' (%u, %pI4:%d) from node '%s' (%u, " "%pI4:%d)\n", local_node->nd_name, local_node->nd_num, &(local_node->nd_ipv4_address), @@ -2008,7 +2006,7 @@ static int r2net_accept_one(struct socket *sock) ret = 0; spin_unlock(&nn->nn_lock); if (ret) { - printk(KERN_NOTICE "ramster: Attempt to connect from node '%s' " + pr_notice("ramster: Attempt to connect from node '%s' " "at %pI4:%d but it already has an open connection\n", node->nd_name, &sin.sin_addr.s_addr, ntohs(sin.sin_port)); @@ -2091,8 +2089,7 @@ static int r2net_open_listening_sock(__be32 addr, __be16 port) ret = sock_create(PF_INET, SOCK_STREAM, IPPROTO_TCP, &sock); if (ret < 0) { - printk(KERN_ERR "ramster: Error %d while creating socket\n", - ret); + pr_err("ramster: Error %d while creating socket\n", ret); goto out; } @@ -2106,17 +2103,17 @@ static int r2net_open_listening_sock(__be32 addr, __be16 port) r2net_listen_sock = sock; INIT_WORK(&r2net_listen_work, r2net_accept_many); - sock->sk->sk_reuse = SK_CAN_REUSE; + sock->sk->sk_reuse = /* SK_CAN_REUSE FIXME FOR 3.4 */ 1; ret = sock->ops->bind(sock, (struct sockaddr *)&sin, sizeof(sin)); if (ret < 0) { - printk(KERN_ERR "ramster: Error %d while binding socket at " - "%pI4:%u\n", ret, &addr, ntohs(port)); + pr_err("ramster: Error %d while binding socket at %pI4:%u\n", + ret, &addr, ntohs(port)); goto out; } ret = sock->ops->listen(sock, 64); if (ret < 0) - printk(KERN_ERR "ramster: Error %d while listening on %pI4:%u\n", + pr_err("ramster: Error %d while listening on %pI4:%u\n", ret, &addr, ntohs(port)); out: diff --git a/drivers/staging/ramster/cluster/tcp.h b/drivers/staging/ramster/ramster/tcp.h index 9d05833452b5..9d05833452b5 100644 --- a/drivers/staging/ramster/cluster/tcp.h +++ b/drivers/staging/ramster/ramster/tcp.h diff --git a/drivers/staging/ramster/cluster/tcp_internal.h b/drivers/staging/ramster/ramster/tcp_internal.h index 4d8cc9f96fd2..4d8cc9f96fd2 100644 --- a/drivers/staging/ramster/cluster/tcp_internal.h +++ b/drivers/staging/ramster/ramster/tcp_internal.h diff --git a/drivers/staging/ramster/tmem.c b/drivers/staging/ramster/tmem.c index 8f2f6892d8d3..a2b7e03b6062 100644 --- a/drivers/staging/ramster/tmem.c +++ b/drivers/staging/ramster/tmem.c @@ -1,33 +1,43 @@ /* * In-kernel transcendent memory (generic implementation) * - * Copyright (c) 2009-2011, Dan Magenheimer, Oracle Corp. + * Copyright (c) 2009-2012, Dan Magenheimer, Oracle Corp. * * The primary purpose of Transcedent Memory ("tmem") is to map object-oriented * "handles" (triples containing a pool id, and object id, and an index), to * pages in a page-accessible memory (PAM). Tmem references the PAM pages via * an abstract "pampd" (PAM page-descriptor), which can be operated on by a * set of functions (pamops). Each pampd contains some representation of - * PAGE_SIZE bytes worth of data. Tmem must support potentially millions of - * pages and must be able to insert, find, and delete these pages at a - * potential frequency of thousands per second concurrently across many CPUs, - * (and, if used with KVM, across many vcpus across many guests). - * Tmem is tracked with a hierarchy of data structures, organized by - * the elements in a handle-tuple: pool_id, object_id, and page index. - * One or more "clients" (e.g. guests) each provide one or more tmem_pools. - * Each pool, contains a hash table of rb_trees of tmem_objs. Each - * tmem_obj contains a radix-tree-like tree of pointers, with intermediate - * nodes called tmem_objnodes. Each leaf pointer in this tree points to - * a pampd, which is accessible only through a small set of callbacks - * registered by the PAM implementation (see tmem_register_pamops). Tmem - * does all memory allocation via a set of callbacks registered by the tmem - * host implementation (e.g. see tmem_register_hostops). + * PAGE_SIZE bytes worth of data. For those familiar with key-value stores, + * the tmem handle is a three-level hierarchical key, and the value is always + * reconstituted (but not necessarily stored) as PAGE_SIZE bytes and is + * referenced in the datastore by the pampd. The hierarchy is required + * to ensure that certain invalidation functions can be performed efficiently + * (i.e. flush all indexes associated with this object_id, or + * flush all objects associated with this pool). + * + * Tmem must support potentially millions of pages and must be able to insert, + * find, and delete these pages at a potential frequency of thousands per + * second concurrently across many CPUs, (and, if used with KVM, across many + * vcpus across many guests). Tmem is tracked with a hierarchy of data + * structures, organized by the elements in the handle-tuple: pool_id, + * object_id, and page index. One or more "clients" (e.g. guests) each + * provide one or more tmem_pools. Each pool, contains a hash table of + * rb_trees of tmem_objs. Each tmem_obj contains a radix-tree-like tree + * of pointers, with intermediate nodes called tmem_objnodes. Each leaf + * pointer in this tree points to a pampd, which is accessible only through + * a small set of callbacks registered by the PAM implementation (see + * tmem_register_pamops). Tmem only needs to memory allocation for objs + * and objnodes and this is done via a set of callbacks that must be + * registered by the tmem host implementation (e.g. see tmem_register_hostops). */ #include <linux/list.h> #include <linux/spinlock.h> #include <linux/atomic.h> +#ifdef CONFIG_RAMSTER #include <linux/delay.h> +#endif #include "tmem.h" @@ -52,7 +62,7 @@ void tmem_register_hostops(struct tmem_hostops *m) /* * A tmem host implementation must use this function to register - * callbacks for a page-accessible memory (PAM) implementation + * callbacks for a page-accessible memory (PAM) implementation. */ static struct tmem_pamops tmem_pamops; @@ -67,42 +77,62 @@ void tmem_register_pamops(struct tmem_pamops *m) * So an rb_tree is an ideal data structure to manage tmem_objs. But because * of the potentially huge number of tmem_objs, each pool manages a hashtable * of rb_trees to reduce search, insert, delete, and rebalancing time. - * Each hashbucket also has a lock to manage concurrent access. + * Each hashbucket also has a lock to manage concurrent access and no + * searches, inserts, or deletions can be performed unless the lock is held. + * As a result, care must be taken to ensure tmem routines are not called + * recursively; the vast majority of the time, a recursive call may work + * but a deadlock will occur a small fraction of the time due to the + * hashbucket lock. * - * The following routines manage tmem_objs. When any tmem_obj is accessed, - * the hashbucket lock must be held. + * The following routines manage tmem_objs. In all of these routines, + * the hashbucket lock is already held. */ -/* searches for object==oid in pool, returns locked object if found */ -static struct tmem_obj *tmem_obj_find(struct tmem_hashbucket *hb, - struct tmem_oid *oidp) +/* Search for object==oid in pool, returns object if found. */ +static struct tmem_obj *__tmem_obj_find(struct tmem_hashbucket *hb, + struct tmem_oid *oidp, + struct rb_node **parent, + struct rb_node ***link) { - struct rb_node *rbnode; - struct tmem_obj *obj; + struct rb_node *_parent = NULL, **rbnode; + struct tmem_obj *obj = NULL; - rbnode = hb->obj_rb_root.rb_node; - while (rbnode) { - BUG_ON(RB_EMPTY_NODE(rbnode)); - obj = rb_entry(rbnode, struct tmem_obj, rb_tree_node); + rbnode = &hb->obj_rb_root.rb_node; + while (*rbnode) { + BUG_ON(RB_EMPTY_NODE(*rbnode)); + _parent = *rbnode; + obj = rb_entry(*rbnode, struct tmem_obj, + rb_tree_node); switch (tmem_oid_compare(oidp, &obj->oid)) { case 0: /* equal */ goto out; case -1: - rbnode = rbnode->rb_left; + rbnode = &(*rbnode)->rb_left; break; case 1: - rbnode = rbnode->rb_right; + rbnode = &(*rbnode)->rb_right; break; } } + + if (parent) + *parent = _parent; + if (link) + *link = rbnode; obj = NULL; out: return obj; } -static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *); +static struct tmem_obj *tmem_obj_find(struct tmem_hashbucket *hb, + struct tmem_oid *oidp) +{ + return __tmem_obj_find(hb, oidp, NULL, NULL); +} -/* free an object that has no more pampds in it */ +static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *, bool); + +/* Free an object that has no more pampds in it. */ static void tmem_obj_free(struct tmem_obj *obj, struct tmem_hashbucket *hb) { struct tmem_pool *pool; @@ -113,7 +143,7 @@ static void tmem_obj_free(struct tmem_obj *obj, struct tmem_hashbucket *hb) pool = obj->pool; BUG_ON(pool == NULL); if (obj->objnode_tree_root != NULL) /* may be "stump" with no leaves */ - tmem_pampd_destroy_all_in_obj(obj); + tmem_pampd_destroy_all_in_obj(obj, false); BUG_ON(obj->objnode_tree_root != NULL); BUG_ON((long)obj->objnode_count != 0); atomic_dec(&pool->obj_count); @@ -125,15 +155,14 @@ static void tmem_obj_free(struct tmem_obj *obj, struct tmem_hashbucket *hb) } /* - * initialize, and insert an tmem_object_root (called only if find failed) + * Initialize, and insert an tmem_object_root (called only if find failed). */ static void tmem_obj_init(struct tmem_obj *obj, struct tmem_hashbucket *hb, struct tmem_pool *pool, struct tmem_oid *oidp) { struct rb_root *root = &hb->obj_rb_root; - struct rb_node **new = &(root->rb_node), *parent = NULL; - struct tmem_obj *this; + struct rb_node **new = NULL, *parent = NULL; BUG_ON(pool == NULL); atomic_inc(&pool->obj_count); @@ -143,24 +172,15 @@ static void tmem_obj_init(struct tmem_obj *obj, struct tmem_hashbucket *hb, obj->oid = *oidp; obj->objnode_count = 0; obj->pampd_count = 0; - (*tmem_pamops.new_obj)(obj); +#ifdef CONFIG_RAMSTER + if (tmem_pamops.new_obj != NULL) + (*tmem_pamops.new_obj)(obj); +#endif SET_SENTINEL(obj, OBJ); - while (*new) { - BUG_ON(RB_EMPTY_NODE(*new)); - this = rb_entry(*new, struct tmem_obj, rb_tree_node); - parent = *new; - switch (tmem_oid_compare(oidp, &this->oid)) { - case 0: - BUG(); /* already present; should never happen! */ - break; - case -1: - new = &(*new)->rb_left; - break; - case 1: - new = &(*new)->rb_right; - break; - } - } + + if (__tmem_obj_find(hb, oidp, &parent, &new)) + BUG(); + rb_link_node(&obj->rb_tree_node, parent, new); rb_insert_color(&obj->rb_tree_node, root); } @@ -170,7 +190,7 @@ static void tmem_obj_init(struct tmem_obj *obj, struct tmem_hashbucket *hb, * "ephemeral" vs "persistent". These attributes apply to all tmem_objs * and all pampds that belong to a tmem_pool. A tmem_pool is created * or deleted relatively rarely (for example, when a filesystem is - * mounted or unmounted. + * mounted or unmounted). */ /* flush all data from a pool and, optionally, free it */ @@ -188,7 +208,7 @@ static void tmem_pool_flush(struct tmem_pool *pool, bool destroy) while (rbnode != NULL) { obj = rb_entry(rbnode, struct tmem_obj, rb_tree_node); rbnode = rb_next(rbnode); - tmem_pampd_destroy_all_in_obj(obj); + tmem_pampd_destroy_all_in_obj(obj, true); tmem_obj_free(obj, hb); (*tmem_hostops.obj_free)(obj, pool); } @@ -274,7 +294,7 @@ static void tmem_objnode_free(struct tmem_objnode *objnode) } /* - * lookup index in object and return associated pampd (or NULL if not found) + * Lookup index in object and return associated pampd (or NULL if not found). */ static void **__tmem_pampd_lookup_in_obj(struct tmem_obj *obj, uint32_t index) { @@ -316,6 +336,7 @@ static void *tmem_pampd_lookup_in_obj(struct tmem_obj *obj, uint32_t index) return slot != NULL ? *slot : NULL; } +#ifdef CONFIG_RAMSTER static void *tmem_pampd_replace_in_obj(struct tmem_obj *obj, uint32_t index, void *new_pampd, bool no_free) { @@ -333,6 +354,7 @@ static void *tmem_pampd_replace_in_obj(struct tmem_obj *obj, uint32_t index, } return ret; } +#endif static int tmem_pampd_add_to_obj(struct tmem_obj *obj, uint32_t index, void *pampd) @@ -470,7 +492,7 @@ out: return slot; } -/* recursively walk the objnode_tree destroying pampds and objnodes */ +/* Recursively walk the objnode_tree destroying pampds and objnodes. */ static void tmem_objnode_node_destroy(struct tmem_obj *obj, struct tmem_objnode *objnode, unsigned int ht) @@ -495,7 +517,8 @@ static void tmem_objnode_node_destroy(struct tmem_obj *obj, } } -static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *obj) +static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *obj, + bool pool_destroy) { if (obj->objnode_tree_root == NULL) return; @@ -510,7 +533,10 @@ static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *obj) obj->objnode_tree_height = 0; } obj->objnode_tree_root = NULL; - (*tmem_pamops.free_obj)(obj->pool, obj); +#ifdef CONFIG_RAMSTER + if (tmem_pamops.free_obj != NULL) + (*tmem_pamops.free_obj)(obj->pool, obj, pool_destroy); +#endif } /* @@ -523,17 +549,16 @@ static void tmem_pampd_destroy_all_in_obj(struct tmem_obj *obj) */ /* - * "Put" a page, e.g. copy a page from the kernel into newly allocated - * PAM space (if such space is available). Tmem_put is complicated by - * a corner case: What if a page with matching handle already exists in - * tmem? To guarantee coherency, one of two actions is necessary: Either - * the data for the page must be overwritten, or the page must be - * "flushed" so that the data is not accessible to a subsequent "get". - * Since these "duplicate puts" are relatively rare, this implementation - * always flushes for simplicity. + * "Put" a page, e.g. associate the passed pampd with the passed handle. + * Tmem_put is complicated by a corner case: What if a page with matching + * handle already exists in tmem? To guarantee coherency, one of two + * actions is necessary: Either the data for the page must be overwritten, + * or the page must be "flushed" so that the data is not accessible to a + * subsequent "get". Since these "duplicate puts" are relatively rare, + * this implementation always flushes for simplicity. */ int tmem_put(struct tmem_pool *pool, struct tmem_oid *oidp, uint32_t index, - char *data, size_t size, bool raw, int ephemeral) + bool raw, void *pampd_to_use) { struct tmem_obj *obj = NULL, *objfound = NULL, *objnew = NULL; void *pampd = NULL, *pampd_del = NULL; @@ -566,19 +591,17 @@ int tmem_put(struct tmem_pool *pool, struct tmem_oid *oidp, uint32_t index, } BUG_ON(obj == NULL); BUG_ON(((objnew != obj) && (objfound != obj)) || (objnew == objfound)); - pampd = (*tmem_pamops.create)(data, size, raw, ephemeral, - obj->pool, &obj->oid, index); - if (unlikely(pampd == NULL)) - goto free; + pampd = pampd_to_use; + BUG_ON(pampd_to_use == NULL); ret = tmem_pampd_add_to_obj(obj, index, pampd); if (unlikely(ret == -ENOMEM)) /* may have partially built objnode tree ("stump") */ goto delete_and_free; + (*tmem_pamops.create_finish)(pampd, is_ephemeral(pool)); goto out; delete_and_free: (void)tmem_pampd_delete_from_obj(obj, index); -free: if (pampd) (*tmem_pamops.free)(pampd, pool, NULL, 0, true); if (objnew) { @@ -590,6 +613,16 @@ out: return ret; } +#ifdef CONFIG_RAMSTER +/* + * For ramster only: The following routines provide a two-step sequence + * to allow the caller to replace a pampd in the tmem data structures with + * another pampd. Here, we lookup the passed handle and, if found, return the + * associated pampd and object, leaving the hashbucket locked and returning + * a reference to it. The caller is expected to immediately call the + * matching tmem_localify_finish routine which will handles the replacement + * and unlocks the hashbucket. + */ void *tmem_localify_get_pampd(struct tmem_pool *pool, struct tmem_oid *oidp, uint32_t index, struct tmem_obj **ret_obj, void **saved_hb) @@ -618,6 +651,7 @@ void tmem_localify_finish(struct tmem_obj *obj, uint32_t index, if (pampd != NULL) { BUG_ON(obj == NULL); (void)tmem_pampd_replace_in_obj(obj, index, pampd, 1); + (*tmem_pamops.create_finish)(pampd, is_ephemeral(obj->pool)); } else if (delete) { BUG_ON(obj == NULL); (void)tmem_pampd_delete_from_obj(obj, index); @@ -625,6 +659,9 @@ void tmem_localify_finish(struct tmem_obj *obj, uint32_t index, spin_unlock(&hb->lock); } +/* + * For ramster only. Helper function to support asynchronous tmem_get. + */ static int tmem_repatriate(void **ppampd, struct tmem_hashbucket *hb, struct tmem_pool *pool, struct tmem_oid *oidp, uint32_t index, bool free, char *data) @@ -633,7 +670,6 @@ static int tmem_repatriate(void **ppampd, struct tmem_hashbucket *hb, bool intransit = false; int ret = 0; - if (!is_ephemeral(pool)) new_pampd = (*tmem_pamops.repatriate_preload)( old_pampd, pool, oidp, index, &intransit); @@ -646,60 +682,91 @@ static int tmem_repatriate(void **ppampd, struct tmem_hashbucket *hb, if (!intransit) ret = (*tmem_pamops.repatriate)(old_pampd, new_pampd, pool, oidp, index, free, data); + if (ret == -EAGAIN) { + /* rare I think, but should cond_resched()??? */ + usleep_range(10, 1000); + } else if (ret == -ENOTCONN || ret == -EHOSTDOWN) { + ret = -1; + } else if (ret != 0 && ret != -ENOENT) { + ret = -1; + } + /* note hb->lock has now been unlocked */ + return ret; +} + +/* + * For ramster only. If a page in tmem matches the handle, replace the + * page so that any subsequent "get" gets the new page. Returns 0 if + * there was a page to replace, else returns -1. + */ +int tmem_replace(struct tmem_pool *pool, struct tmem_oid *oidp, + uint32_t index, void *new_pampd) +{ + struct tmem_obj *obj; + int ret = -1; + struct tmem_hashbucket *hb; + + hb = &pool->hashbucket[tmem_oid_hash(oidp)]; + spin_lock(&hb->lock); + obj = tmem_obj_find(hb, oidp); + if (obj == NULL) + goto out; + new_pampd = tmem_pampd_replace_in_obj(obj, index, new_pampd, 0); + /* if we bug here, pamops wasn't properly set up for ramster */ + BUG_ON(tmem_pamops.replace_in_obj == NULL); + ret = (*tmem_pamops.replace_in_obj)(new_pampd, obj); +out: + spin_unlock(&hb->lock); return ret; } +#endif /* - * "Get" a page, e.g. if one can be found, copy the tmem page with the - * matching handle from PAM space to the kernel. By tmem definition, - * when a "get" is successful on an ephemeral page, the page is "flushed", - * and when a "get" is successful on a persistent page, the page is retained - * in tmem. Note that to preserve + * "Get" a page, e.g. if a pampd can be found matching the passed handle, + * use a pamops callback to recreated the page from the pampd with the + * matching handle. By tmem definition, when a "get" is successful on + * an ephemeral page, the page is "flushed", and when a "get" is successful + * on a persistent page, the page is retained in tmem. Note that to preserve * coherency, "get" can never be skipped if tmem contains the data. * That is, if a get is done with a certain handle and fails, any * subsequent "get" must also fail (unless of course there is a * "put" done with the same handle). - */ int tmem_get(struct tmem_pool *pool, struct tmem_oid *oidp, uint32_t index, - char *data, size_t *size, bool raw, int get_and_free) + char *data, size_t *sizep, bool raw, int get_and_free) { struct tmem_obj *obj; - void *pampd; + void *pampd = NULL; bool ephemeral = is_ephemeral(pool); int ret = -1; struct tmem_hashbucket *hb; bool free = (get_and_free == 1) || ((get_and_free == 0) && ephemeral); - bool lock_held = 0; + bool lock_held = false; void **ppampd; -again: - hb = &pool->hashbucket[tmem_oid_hash(oidp)]; - spin_lock(&hb->lock); - lock_held = 1; - obj = tmem_obj_find(hb, oidp); - if (obj == NULL) - goto out; - ppampd = __tmem_pampd_lookup_in_obj(obj, index); - if (ppampd == NULL) - goto out; - if (tmem_pamops.is_remote(*ppampd)) { - ret = tmem_repatriate(ppampd, hb, pool, oidp, - index, free, data); - lock_held = 0; /* note hb->lock has been unlocked */ - if (ret == -EAGAIN) { - /* rare I think, but should cond_resched()??? */ - usleep_range(10, 1000); - goto again; - } else if (ret != 0) { - if (ret != -ENOENT) - pr_err("UNTESTED case in tmem_get, ret=%d\n", - ret); - ret = -1; + do { + hb = &pool->hashbucket[tmem_oid_hash(oidp)]; + spin_lock(&hb->lock); + lock_held = true; + obj = tmem_obj_find(hb, oidp); + if (obj == NULL) + goto out; + ppampd = __tmem_pampd_lookup_in_obj(obj, index); + if (ppampd == NULL) goto out; +#ifdef CONFIG_RAMSTER + if ((tmem_pamops.is_remote != NULL) && + tmem_pamops.is_remote(*ppampd)) { + ret = tmem_repatriate(ppampd, hb, pool, oidp, + index, free, data); + /* tmem_repatriate releases hb->lock */ + lock_held = false; + *sizep = PAGE_SIZE; + if (ret != -EAGAIN) + goto out; } - goto out; - } +#endif + } while (ret == -EAGAIN); if (free) pampd = tmem_pampd_delete_from_obj(obj, index); else @@ -715,10 +782,10 @@ again: } if (free) ret = (*tmem_pamops.get_data_and_free)( - data, size, raw, pampd, pool, oidp, index); + data, sizep, raw, pampd, pool, oidp, index); else ret = (*tmem_pamops.get_data)( - data, size, raw, pampd, pool, oidp, index); + data, sizep, raw, pampd, pool, oidp, index); if (ret < 0) goto out; ret = 0; @@ -762,30 +829,6 @@ out: } /* - * If a page in tmem matches the handle, replace the page so that any - * subsequent "get" gets the new page. Returns the new page if - * there was a page to replace, else returns NULL. - */ -int tmem_replace(struct tmem_pool *pool, struct tmem_oid *oidp, - uint32_t index, void *new_pampd) -{ - struct tmem_obj *obj; - int ret = -1; - struct tmem_hashbucket *hb; - - hb = &pool->hashbucket[tmem_oid_hash(oidp)]; - spin_lock(&hb->lock); - obj = tmem_obj_find(hb, oidp); - if (obj == NULL) - goto out; - new_pampd = tmem_pampd_replace_in_obj(obj, index, new_pampd, 0); - ret = (*tmem_pamops.replace_in_obj)(new_pampd, obj); -out: - spin_unlock(&hb->lock); - return ret; -} - -/* * "Flush" all pages in tmem matching this oid. */ int tmem_flush_object(struct tmem_pool *pool, struct tmem_oid *oidp) @@ -799,7 +842,7 @@ int tmem_flush_object(struct tmem_pool *pool, struct tmem_oid *oidp) obj = tmem_obj_find(hb, oidp); if (obj == NULL) goto out; - tmem_pampd_destroy_all_in_obj(obj); + tmem_pampd_destroy_all_in_obj(obj, false); tmem_obj_free(obj, hb); (*tmem_hostops.obj_free)(obj, pool); ret = 0; diff --git a/drivers/staging/ramster/tmem.h b/drivers/staging/ramster/tmem.h index 47f1918c8314..adbe5a8f28aa 100644 --- a/drivers/staging/ramster/tmem.h +++ b/drivers/staging/ramster/tmem.h @@ -3,23 +3,20 @@ * * Transcendent memory * - * Copyright (c) 2009-2011, Dan Magenheimer, Oracle Corp. + * Copyright (c) 2009-2012, Dan Magenheimer, Oracle Corp. */ #ifndef _TMEM_H_ #define _TMEM_H_ +#include <linux/types.h> #include <linux/highmem.h> #include <linux/hash.h> #include <linux/atomic.h> /* - * These are pre-defined by the Xen<->Linux ABI + * These are defined by the Xen<->Linux ABI so should remain consistent */ -#define TMEM_PUT_PAGE 4 -#define TMEM_GET_PAGE 5 -#define TMEM_FLUSH_PAGE 6 -#define TMEM_FLUSH_OBJECT 7 #define TMEM_POOL_PERSIST 1 #define TMEM_POOL_SHARED 2 #define TMEM_POOL_PRECOMPRESSED 4 @@ -31,7 +28,7 @@ * sentinels have proven very useful for debugging but can be removed * or disabled before final merge. */ -#define SENTINELS +#undef SENTINELS #ifdef SENTINELS #define DECL_SENTINEL uint32_t sentinel; #define SET_SENTINEL(_x, _y) (_x->sentinel = _y##_SENTINEL) @@ -46,7 +43,7 @@ #define ASSERT_INVERTED_SENTINEL(_x, _y) do { } while (0) #endif -#define ASSERT_SPINLOCK(_l) WARN_ON(!spin_is_locked(_l)) +#define ASSERT_SPINLOCK(_l) lockdep_assert_held(_l) /* * A pool is the highest-level data structure managed by tmem and @@ -88,31 +85,6 @@ struct tmem_oid { uint64_t oid[3]; }; -struct tmem_xhandle { - uint8_t client_id; - uint8_t xh_data_cksum; - uint16_t xh_data_size; - uint16_t pool_id; - struct tmem_oid oid; - uint32_t index; - void *extra; -}; - -static inline struct tmem_xhandle tmem_xhandle_fill(uint16_t client_id, - struct tmem_pool *pool, - struct tmem_oid *oidp, - uint32_t index) -{ - struct tmem_xhandle xh; - xh.client_id = client_id; - xh.xh_data_cksum = (uint8_t)-1; - xh.xh_data_size = (uint16_t)-1; - xh.pool_id = pool->pool_id; - xh.oid = *oidp; - xh.index = index; - return xh; -} - static inline void tmem_oid_set_invalid(struct tmem_oid *oidp) { oidp->oid[0] = oidp->oid[1] = oidp->oid[2] = -1UL; @@ -154,6 +126,34 @@ static inline unsigned tmem_oid_hash(struct tmem_oid *oidp) TMEM_HASH_BUCKET_BITS); } +#ifdef CONFIG_RAMSTER +struct tmem_xhandle { + uint8_t client_id; + uint8_t xh_data_cksum; + uint16_t xh_data_size; + uint16_t pool_id; + struct tmem_oid oid; + uint32_t index; + void *extra; +}; + +static inline struct tmem_xhandle tmem_xhandle_fill(uint16_t client_id, + struct tmem_pool *pool, + struct tmem_oid *oidp, + uint32_t index) +{ + struct tmem_xhandle xh; + xh.client_id = client_id; + xh.xh_data_cksum = (uint8_t)-1; + xh.xh_data_size = (uint16_t)-1; + xh.pool_id = pool->pool_id; + xh.oid = *oidp; + xh.index = index; + return xh; +} +#endif + + /* * A tmem_obj contains an identifier (oid), pointers to the parent * pool and the rb_tree to which it belongs, counters, and an ordered @@ -171,11 +171,15 @@ struct tmem_obj { unsigned int objnode_tree_height; unsigned long objnode_count; long pampd_count; - /* for current design of ramster, all pages belonging to +#ifdef CONFIG_RAMSTER + /* + * for current design of ramster, all pages belonging to * an object reside on the same remotenode and extra is * used to record the number of the remotenode so a - * flush-object operation can specify it */ - void *extra; /* for use by pampd implementation */ + * flush-object operation can specify it + */ + void *extra; /* for private use by pampd implementation */ +#endif DECL_SENTINEL }; @@ -193,10 +197,17 @@ struct tmem_objnode { unsigned int slots_in_use; }; +struct tmem_handle { + struct tmem_oid oid; /* 24 bytes */ + uint32_t index; + uint16_t pool_id; + uint16_t client_id; +}; + + /* pampd abstract datatype methods provided by the PAM implementation */ struct tmem_pamops { - void *(*create)(char *, size_t, bool, int, - struct tmem_pool *, struct tmem_oid *, uint32_t); + void (*create_finish)(void *, bool); int (*get_data)(char *, size_t *, bool, void *, struct tmem_pool *, struct tmem_oid *, uint32_t); int (*get_data_and_free)(char *, size_t *, bool, void *, @@ -204,14 +215,16 @@ struct tmem_pamops { uint32_t); void (*free)(void *, struct tmem_pool *, struct tmem_oid *, uint32_t, bool); - void (*free_obj)(struct tmem_pool *, struct tmem_obj *); - bool (*is_remote)(void *); +#ifdef CONFIG_RAMSTER + void (*new_obj)(struct tmem_obj *); + void (*free_obj)(struct tmem_pool *, struct tmem_obj *, bool); void *(*repatriate_preload)(void *, struct tmem_pool *, struct tmem_oid *, uint32_t, bool *); int (*repatriate)(void *, void *, struct tmem_pool *, struct tmem_oid *, uint32_t, bool, void *); - void (*new_obj)(struct tmem_obj *); + bool (*is_remote)(void *); int (*replace_in_obj)(void *, struct tmem_obj *); +#endif }; extern void tmem_register_pamops(struct tmem_pamops *m); @@ -226,9 +239,15 @@ extern void tmem_register_hostops(struct tmem_hostops *m); /* core tmem accessor functions */ extern int tmem_put(struct tmem_pool *, struct tmem_oid *, uint32_t index, - char *, size_t, bool, int); + bool, void *); extern int tmem_get(struct tmem_pool *, struct tmem_oid *, uint32_t index, char *, size_t *, bool, int); +extern int tmem_flush_page(struct tmem_pool *, struct tmem_oid *, + uint32_t index); +extern int tmem_flush_object(struct tmem_pool *, struct tmem_oid *); +extern int tmem_destroy_pool(struct tmem_pool *); +extern void tmem_new_pool(struct tmem_pool *, uint32_t); +#ifdef CONFIG_RAMSTER extern int tmem_replace(struct tmem_pool *, struct tmem_oid *, uint32_t index, void *); extern void *tmem_localify_get_pampd(struct tmem_pool *, struct tmem_oid *, @@ -236,9 +255,5 @@ extern void *tmem_localify_get_pampd(struct tmem_pool *, struct tmem_oid *, void **); extern void tmem_localify_finish(struct tmem_obj *, uint32_t index, void *, void *, bool); -extern int tmem_flush_page(struct tmem_pool *, struct tmem_oid *, - uint32_t index); -extern int tmem_flush_object(struct tmem_pool *, struct tmem_oid *); -extern int tmem_destroy_pool(struct tmem_pool *); -extern void tmem_new_pool(struct tmem_pool *, uint32_t); +#endif #endif /* _TMEM_H */ diff --git a/drivers/staging/ramster/xvmalloc.c b/drivers/staging/ramster/xvmalloc.c deleted file mode 100644 index 44ceb0b823a9..000000000000 --- a/drivers/staging/ramster/xvmalloc.c +++ /dev/null @@ -1,509 +0,0 @@ -/* - * xvmalloc memory allocator - * - * Copyright (C) 2008, 2009, 2010 Nitin Gupta - * - * This code is released using a dual license strategy: BSD/GPL - * You can choose the licence that better fits your requirements. - * - * Released under the terms of 3-clause BSD License - * Released under the terms of GNU General Public License Version 2.0 - */ - -#ifdef CONFIG_ZRAM_DEBUG -#define DEBUG -#endif - -#include <linux/module.h> -#include <linux/kernel.h> -#include <linux/bitops.h> -#include <linux/errno.h> -#include <linux/highmem.h> -#include <linux/init.h> -#include <linux/string.h> -#include <linux/slab.h> - -#include "xvmalloc.h" -#include "xvmalloc_int.h" - -static void stat_inc(u64 *value) -{ - *value = *value + 1; -} - -static void stat_dec(u64 *value) -{ - *value = *value - 1; -} - -static int test_flag(struct block_header *block, enum blockflags flag) -{ - return block->prev & BIT(flag); -} - -static void set_flag(struct block_header *block, enum blockflags flag) -{ - block->prev |= BIT(flag); -} - -static void clear_flag(struct block_header *block, enum blockflags flag) -{ - block->prev &= ~BIT(flag); -} - -/* - * Given <page, offset> pair, provide a dereferencable pointer. - * This is called from xv_malloc/xv_free path, so it - * needs to be fast. - */ -static void *get_ptr_atomic(struct page *page, u16 offset) -{ - unsigned char *base; - - base = kmap_atomic(page); - return base + offset; -} - -static void put_ptr_atomic(void *ptr) -{ - kunmap_atomic(ptr); -} - -static u32 get_blockprev(struct block_header *block) -{ - return block->prev & PREV_MASK; -} - -static void set_blockprev(struct block_header *block, u16 new_offset) -{ - block->prev = new_offset | (block->prev & FLAGS_MASK); -} - -static struct block_header *BLOCK_NEXT(struct block_header *block) -{ - return (struct block_header *) - ((char *)block + block->size + XV_ALIGN); -} - -/* - * Get index of free list containing blocks of maximum size - * which is less than or equal to given size. - */ -static u32 get_index_for_insert(u32 size) -{ - if (unlikely(size > XV_MAX_ALLOC_SIZE)) - size = XV_MAX_ALLOC_SIZE; - size &= ~FL_DELTA_MASK; - return (size - XV_MIN_ALLOC_SIZE) >> FL_DELTA_SHIFT; -} - -/* - * Get index of free list having blocks of size greater than - * or equal to requested size. - */ -static u32 get_index(u32 size) -{ - if (unlikely(size < XV_MIN_ALLOC_SIZE)) - size = XV_MIN_ALLOC_SIZE; - size = ALIGN(size, FL_DELTA); - return (size - XV_MIN_ALLOC_SIZE) >> FL_DELTA_SHIFT; -} - -/** - * find_block - find block of at least given size - * @pool: memory pool to search from - * @size: size of block required - * @page: page containing required block - * @offset: offset within the page where block is located. - * - * Searches two level bitmap to locate block of at least - * the given size. If such a block is found, it provides - * <page, offset> to identify this block and returns index - * in freelist where we found this block. - * Otherwise, returns 0 and <page, offset> params are not touched. - */ -static u32 find_block(struct xv_pool *pool, u32 size, - struct page **page, u32 *offset) -{ - ulong flbitmap, slbitmap; - u32 flindex, slindex, slbitstart; - - /* There are no free blocks in this pool */ - if (!pool->flbitmap) - return 0; - - /* Get freelist index corresponding to this size */ - slindex = get_index(size); - slbitmap = pool->slbitmap[slindex / BITS_PER_LONG]; - slbitstart = slindex % BITS_PER_LONG; - - /* - * If freelist is not empty at this index, we found the - * block - head of this list. This is approximate best-fit match. - */ - if (test_bit(slbitstart, &slbitmap)) { - *page = pool->freelist[slindex].page; - *offset = pool->freelist[slindex].offset; - return slindex; - } - - /* - * No best-fit found. Search a bit further in bitmap for a free block. - * Second level bitmap consists of series of 32-bit chunks. Search - * further in the chunk where we expected a best-fit, starting from - * index location found above. - */ - slbitstart++; - slbitmap >>= slbitstart; - - /* Skip this search if we were already at end of this bitmap chunk */ - if ((slbitstart != BITS_PER_LONG) && slbitmap) { - slindex += __ffs(slbitmap) + 1; - *page = pool->freelist[slindex].page; - *offset = pool->freelist[slindex].offset; - return slindex; - } - - /* Now do a full two-level bitmap search to find next nearest fit */ - flindex = slindex / BITS_PER_LONG; - - flbitmap = (pool->flbitmap) >> (flindex + 1); - if (!flbitmap) - return 0; - - flindex += __ffs(flbitmap) + 1; - slbitmap = pool->slbitmap[flindex]; - slindex = (flindex * BITS_PER_LONG) + __ffs(slbitmap); - *page = pool->freelist[slindex].page; - *offset = pool->freelist[slindex].offset; - - return slindex; -} - -/* - * Insert block at <page, offset> in freelist of given pool. - * freelist used depends on block size. - */ -static void insert_block(struct xv_pool *pool, struct page *page, u32 offset, - struct block_header *block) -{ - u32 flindex, slindex; - struct block_header *nextblock; - - slindex = get_index_for_insert(block->size); - flindex = slindex / BITS_PER_LONG; - - block->link.prev_page = NULL; - block->link.prev_offset = 0; - block->link.next_page = pool->freelist[slindex].page; - block->link.next_offset = pool->freelist[slindex].offset; - pool->freelist[slindex].page = page; - pool->freelist[slindex].offset = offset; - - if (block->link.next_page) { - nextblock = get_ptr_atomic(block->link.next_page, - block->link.next_offset); - nextblock->link.prev_page = page; - nextblock->link.prev_offset = offset; - put_ptr_atomic(nextblock); - /* If there was a next page then the free bits are set. */ - return; - } - - __set_bit(slindex % BITS_PER_LONG, &pool->slbitmap[flindex]); - __set_bit(flindex, &pool->flbitmap); -} - -/* - * Remove block from freelist. Index 'slindex' identifies the freelist. - */ -static void remove_block(struct xv_pool *pool, struct page *page, u32 offset, - struct block_header *block, u32 slindex) -{ - u32 flindex = slindex / BITS_PER_LONG; - struct block_header *tmpblock; - - if (block->link.prev_page) { - tmpblock = get_ptr_atomic(block->link.prev_page, - block->link.prev_offset); - tmpblock->link.next_page = block->link.next_page; - tmpblock->link.next_offset = block->link.next_offset; - put_ptr_atomic(tmpblock); - } - - if (block->link.next_page) { - tmpblock = get_ptr_atomic(block->link.next_page, - block->link.next_offset); - tmpblock->link.prev_page = block->link.prev_page; - tmpblock->link.prev_offset = block->link.prev_offset; - put_ptr_atomic(tmpblock); - } - - /* Is this block is at the head of the freelist? */ - if (pool->freelist[slindex].page == page - && pool->freelist[slindex].offset == offset) { - - pool->freelist[slindex].page = block->link.next_page; - pool->freelist[slindex].offset = block->link.next_offset; - - if (pool->freelist[slindex].page) { - struct block_header *tmpblock; - tmpblock = get_ptr_atomic(pool->freelist[slindex].page, - pool->freelist[slindex].offset); - tmpblock->link.prev_page = NULL; - tmpblock->link.prev_offset = 0; - put_ptr_atomic(tmpblock); - } else { - /* This freelist bucket is empty */ - __clear_bit(slindex % BITS_PER_LONG, - &pool->slbitmap[flindex]); - if (!pool->slbitmap[flindex]) - __clear_bit(flindex, &pool->flbitmap); - } - } - - block->link.prev_page = NULL; - block->link.prev_offset = 0; - block->link.next_page = NULL; - block->link.next_offset = 0; -} - -/* - * Allocate a page and add it to freelist of given pool. - */ -static int grow_pool(struct xv_pool *pool, gfp_t flags) -{ - struct page *page; - struct block_header *block; - - page = alloc_page(flags); - if (unlikely(!page)) - return -ENOMEM; - - stat_inc(&pool->total_pages); - - spin_lock(&pool->lock); - block = get_ptr_atomic(page, 0); - - block->size = PAGE_SIZE - XV_ALIGN; - set_flag(block, BLOCK_FREE); - clear_flag(block, PREV_FREE); - set_blockprev(block, 0); - - insert_block(pool, page, 0, block); - - put_ptr_atomic(block); - spin_unlock(&pool->lock); - - return 0; -} - -/* - * Create a memory pool. Allocates freelist, bitmaps and other - * per-pool metadata. - */ -struct xv_pool *xv_create_pool(void) -{ - u32 ovhd_size; - struct xv_pool *pool; - - ovhd_size = roundup(sizeof(*pool), PAGE_SIZE); - pool = kzalloc(ovhd_size, GFP_KERNEL); - if (!pool) - return NULL; - - spin_lock_init(&pool->lock); - - return pool; -} -EXPORT_SYMBOL_GPL(xv_create_pool); - -void xv_destroy_pool(struct xv_pool *pool) -{ - kfree(pool); -} -EXPORT_SYMBOL_GPL(xv_destroy_pool); - -/** - * xv_malloc - Allocate block of given size from pool. - * @pool: pool to allocate from - * @size: size of block to allocate - * @page: page no. that holds the object - * @offset: location of object within page - * - * On success, <page, offset> identifies block allocated - * and 0 is returned. On failure, <page, offset> is set to - * 0 and -ENOMEM is returned. - * - * Allocation requests with size > XV_MAX_ALLOC_SIZE will fail. - */ -int xv_malloc(struct xv_pool *pool, u32 size, struct page **page, - u32 *offset, gfp_t flags) -{ - int error; - u32 index, tmpsize, origsize, tmpoffset; - struct block_header *block, *tmpblock; - - *page = NULL; - *offset = 0; - origsize = size; - - if (unlikely(!size || size > XV_MAX_ALLOC_SIZE)) - return -ENOMEM; - - size = ALIGN(size, XV_ALIGN); - - spin_lock(&pool->lock); - - index = find_block(pool, size, page, offset); - - if (!*page) { - spin_unlock(&pool->lock); - if (flags & GFP_NOWAIT) - return -ENOMEM; - error = grow_pool(pool, flags); - if (unlikely(error)) - return error; - - spin_lock(&pool->lock); - index = find_block(pool, size, page, offset); - } - - if (!*page) { - spin_unlock(&pool->lock); - return -ENOMEM; - } - - block = get_ptr_atomic(*page, *offset); - - remove_block(pool, *page, *offset, block, index); - - /* Split the block if required */ - tmpoffset = *offset + size + XV_ALIGN; - tmpsize = block->size - size; - tmpblock = (struct block_header *)((char *)block + size + XV_ALIGN); - if (tmpsize) { - tmpblock->size = tmpsize - XV_ALIGN; - set_flag(tmpblock, BLOCK_FREE); - clear_flag(tmpblock, PREV_FREE); - - set_blockprev(tmpblock, *offset); - if (tmpblock->size >= XV_MIN_ALLOC_SIZE) - insert_block(pool, *page, tmpoffset, tmpblock); - - if (tmpoffset + XV_ALIGN + tmpblock->size != PAGE_SIZE) { - tmpblock = BLOCK_NEXT(tmpblock); - set_blockprev(tmpblock, tmpoffset); - } - } else { - /* This block is exact fit */ - if (tmpoffset != PAGE_SIZE) - clear_flag(tmpblock, PREV_FREE); - } - - block->size = origsize; - clear_flag(block, BLOCK_FREE); - - put_ptr_atomic(block); - spin_unlock(&pool->lock); - - *offset += XV_ALIGN; - - return 0; -} -EXPORT_SYMBOL_GPL(xv_malloc); - -/* - * Free block identified with <page, offset> - */ -void xv_free(struct xv_pool *pool, struct page *page, u32 offset) -{ - void *page_start; - struct block_header *block, *tmpblock; - - offset -= XV_ALIGN; - - spin_lock(&pool->lock); - - page_start = get_ptr_atomic(page, 0); - block = (struct block_header *)((char *)page_start + offset); - - /* Catch double free bugs */ - BUG_ON(test_flag(block, BLOCK_FREE)); - - block->size = ALIGN(block->size, XV_ALIGN); - - tmpblock = BLOCK_NEXT(block); - if (offset + block->size + XV_ALIGN == PAGE_SIZE) - tmpblock = NULL; - - /* Merge next block if its free */ - if (tmpblock && test_flag(tmpblock, BLOCK_FREE)) { - /* - * Blocks smaller than XV_MIN_ALLOC_SIZE - * are not inserted in any free list. - */ - if (tmpblock->size >= XV_MIN_ALLOC_SIZE) { - remove_block(pool, page, - offset + block->size + XV_ALIGN, tmpblock, - get_index_for_insert(tmpblock->size)); - } - block->size += tmpblock->size + XV_ALIGN; - } - - /* Merge previous block if its free */ - if (test_flag(block, PREV_FREE)) { - tmpblock = (struct block_header *)((char *)(page_start) + - get_blockprev(block)); - offset = offset - tmpblock->size - XV_ALIGN; - - if (tmpblock->size >= XV_MIN_ALLOC_SIZE) - remove_block(pool, page, offset, tmpblock, - get_index_for_insert(tmpblock->size)); - - tmpblock->size += block->size + XV_ALIGN; - block = tmpblock; - } - - /* No used objects in this page. Free it. */ - if (block->size == PAGE_SIZE - XV_ALIGN) { - put_ptr_atomic(page_start); - spin_unlock(&pool->lock); - - __free_page(page); - stat_dec(&pool->total_pages); - return; - } - - set_flag(block, BLOCK_FREE); - if (block->size >= XV_MIN_ALLOC_SIZE) - insert_block(pool, page, offset, block); - - if (offset + block->size + XV_ALIGN != PAGE_SIZE) { - tmpblock = BLOCK_NEXT(block); - set_flag(tmpblock, PREV_FREE); - set_blockprev(tmpblock, offset); - } - - put_ptr_atomic(page_start); - spin_unlock(&pool->lock); -} -EXPORT_SYMBOL_GPL(xv_free); - -u32 xv_get_object_size(void *obj) -{ - struct block_header *blk; - - blk = (struct block_header *)((char *)(obj) - XV_ALIGN); - return blk->size; -} -EXPORT_SYMBOL_GPL(xv_get_object_size); - -/* - * Returns total memory used by allocator (userdata + metadata) - */ -u64 xv_get_total_size_bytes(struct xv_pool *pool) -{ - return pool->total_pages << PAGE_SHIFT; -} -EXPORT_SYMBOL_GPL(xv_get_total_size_bytes); diff --git a/drivers/staging/ramster/xvmalloc.h b/drivers/staging/ramster/xvmalloc.h deleted file mode 100644 index 5b1a81aa5faf..000000000000 --- a/drivers/staging/ramster/xvmalloc.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * xvmalloc memory allocator - * - * Copyright (C) 2008, 2009, 2010 Nitin Gupta - * - * This code is released using a dual license strategy: BSD/GPL - * You can choose the licence that better fits your requirements. - * - * Released under the terms of 3-clause BSD License - * Released under the terms of GNU General Public License Version 2.0 - */ - -#ifndef _XV_MALLOC_H_ -#define _XV_MALLOC_H_ - -#include <linux/types.h> - -struct xv_pool; - -struct xv_pool *xv_create_pool(void); -void xv_destroy_pool(struct xv_pool *pool); - -int xv_malloc(struct xv_pool *pool, u32 size, struct page **page, - u32 *offset, gfp_t flags); -void xv_free(struct xv_pool *pool, struct page *page, u32 offset); - -u32 xv_get_object_size(void *obj); -u64 xv_get_total_size_bytes(struct xv_pool *pool); - -#endif diff --git a/drivers/staging/ramster/xvmalloc_int.h b/drivers/staging/ramster/xvmalloc_int.h deleted file mode 100644 index b5f1f7febcf6..000000000000 --- a/drivers/staging/ramster/xvmalloc_int.h +++ /dev/null @@ -1,95 +0,0 @@ -/* - * xvmalloc memory allocator - * - * Copyright (C) 2008, 2009, 2010 Nitin Gupta - * - * This code is released using a dual license strategy: BSD/GPL - * You can choose the licence that better fits your requirements. - * - * Released under the terms of 3-clause BSD License - * Released under the terms of GNU General Public License Version 2.0 - */ - -#ifndef _XV_MALLOC_INT_H_ -#define _XV_MALLOC_INT_H_ - -#include <linux/kernel.h> -#include <linux/types.h> - -/* User configurable params */ - -/* Must be power of two */ -#ifdef CONFIG_64BIT -#define XV_ALIGN_SHIFT 3 -#else -#define XV_ALIGN_SHIFT 2 -#endif -#define XV_ALIGN (1 << XV_ALIGN_SHIFT) -#define XV_ALIGN_MASK (XV_ALIGN - 1) - -/* This must be greater than sizeof(link_free) */ -#define XV_MIN_ALLOC_SIZE 32 -#define XV_MAX_ALLOC_SIZE (PAGE_SIZE - XV_ALIGN) - -/* - * Free lists are separated by FL_DELTA bytes - * This value is 3 for 4k pages and 4 for 64k pages, for any - * other page size, a conservative (PAGE_SHIFT - 9) is used. - */ -#if PAGE_SHIFT == 16 -#define FL_DELTA_SHIFT 4 -#else -#define FL_DELTA_SHIFT (PAGE_SHIFT - 9) -#endif -#define FL_DELTA (1 << FL_DELTA_SHIFT) -#define FL_DELTA_MASK (FL_DELTA - 1) -#define NUM_FREE_LISTS ((XV_MAX_ALLOC_SIZE - XV_MIN_ALLOC_SIZE) \ - / FL_DELTA + 1) - -#define MAX_FLI DIV_ROUND_UP(NUM_FREE_LISTS, BITS_PER_LONG) - -/* End of user params */ - -enum blockflags { - BLOCK_FREE, - PREV_FREE, - __NR_BLOCKFLAGS, -}; - -#define FLAGS_MASK XV_ALIGN_MASK -#define PREV_MASK (~FLAGS_MASK) - -struct freelist_entry { - struct page *page; - u16 offset; - u16 pad; -}; - -struct link_free { - struct page *prev_page; - struct page *next_page; - u16 prev_offset; - u16 next_offset; -}; - -struct block_header { - union { - /* This common header must be XV_ALIGN bytes */ - u8 common[XV_ALIGN]; - struct { - u16 size; - u16 prev; - }; - }; - struct link_free link; -}; - -struct xv_pool { - ulong flbitmap; - ulong slbitmap[MAX_FLI]; - u64 total_pages; /* stats */ - struct freelist_entry freelist[NUM_FREE_LISTS]; - spinlock_t lock; -}; - -#endif diff --git a/drivers/staging/ramster/zbud.c b/drivers/staging/ramster/zbud.c new file mode 100644 index 000000000000..a7c436127aa1 --- /dev/null +++ b/drivers/staging/ramster/zbud.c @@ -0,0 +1,1060 @@ +/* + * zbud.c - Compression buddies allocator + * + * Copyright (c) 2010-2012, Dan Magenheimer, Oracle Corp. + * + * Compression buddies ("zbud") provides for efficiently packing two + * (or, possibly in the future, more) compressed pages ("zpages") into + * a single "raw" pageframe and for tracking both zpages and pageframes + * so that whole pageframes can be easily reclaimed in LRU-like order. + * It is designed to be used in conjunction with transcendent memory + * ("tmem"); for example separate LRU lists are maintained for persistent + * vs. ephemeral pages. + * + * A zbudpage is an overlay for a struct page and thus each zbudpage + * refers to a physical pageframe of RAM. When the caller passes a + * struct page from the kernel's page allocator, zbud "transforms" it + * to a zbudpage which sets/uses a different set of fields than the + * struct-page and thus must "untransform" it back by reinitializing + * certain fields before the struct-page can be freed. The fields + * of a zbudpage include a page lock for controlling access to the + * corresponding pageframe, and there is a size field for each zpage. + * Each zbudpage also lives on two linked lists: a "budlist" which is + * used to support efficient buddying of zpages; and an "lru" which + * is used for reclaiming pageframes in approximately least-recently-used + * order. + * + * A zbudpageframe is a pageframe divided up into aligned 64-byte "chunks" + * which contain the compressed data for zero, one, or two zbuds. Contained + * with the compressed data is a tmem_handle which is a key to allow + * the same data to be found via the tmem interface so the zpage can + * be invalidated (for ephemeral pages) or repatriated to the swap cache + * (for persistent pages). The contents of a zbudpageframe must never + * be accessed without holding the page lock for the corresponding + * zbudpage and, to accomodate highmem machines, the contents may + * only be examined or changes when kmapped. Thus, when in use, a + * kmapped zbudpageframe is referred to in the zbud code as "void *zbpg". + * + * Note that the term "zbud" refers to the combination of a zpage and + * a tmem_handle that is stored as one of possibly two "buddied" zpages; + * it also generically refers to this allocator... sorry for any confusion. + * + * A zbudref is a pointer to a struct zbudpage (which can be cast to a + * struct page), with the LSB either cleared or set to indicate, respectively, + * the first or second zpage in the zbudpageframe. Since a zbudref can be + * cast to a pointer, it is used as the tmem "pampd" pointer and uniquely + * references a stored tmem page and so is the only zbud data structure + * externally visible to zbud.c/zbud.h. + * + * Since we wish to reclaim entire pageframes but zpages may be randomly + * added and deleted to any given pageframe, we approximate LRU by + * promoting a pageframe to MRU when a zpage is added to it, but + * leaving it at the current place in the list when a zpage is deleted + * from it. As a side effect, zpages that are difficult to buddy (e.g. + * very large paages) will be reclaimed faster than average, which seems + * reasonable. + * + * In the current implementation, no more than two zpages may be stored in + * any pageframe and no zpage ever crosses a pageframe boundary. While + * other zpage allocation mechanisms may allow greater density, this two + * zpage-per-pageframe limit both ensures simple reclaim of pageframes + * (including garbage collection of references to the contents of those + * pageframes from tmem data structures) AND avoids the need for compaction. + * With additional complexity, zbud could be modified to support storing + * up to three zpages per pageframe or, to handle larger average zpages, + * up to three zpages per pair of pageframes, but it is not clear if the + * additional complexity would be worth it. So consider it an exercise + * for future developers. + * + * Note also that zbud does no page allocation or freeing. This is so + * that the caller has complete control over and, for accounting, visibility + * into if/when pages are allocated and freed. + * + * Finally, note that zbud limits the size of zpages it can store; the + * caller must check the zpage size with zbud_max_buddy_size before + * storing it, else BUGs will result. User beware. + */ + +#include <linux/module.h> +#include <linux/highmem.h> +#include <linux/list.h> +#include <linux/spinlock.h> +#include <linux/pagemap.h> +#include <linux/atomic.h> +#include <linux/bug.h> +#include "tmem.h" +#include "zcache.h" +#include "zbud.h" + +/* + * We need to ensure that a struct zbudpage is never larger than a + * struct page. This is checked with a BUG_ON in zbud_init. + * + * The unevictable field indicates that a zbud is being added to the + * zbudpage. Since this is a two-phase process (due to tmem locking), + * this field locks the zbudpage against eviction when a zbud match + * or creation is in process. Since this addition process may occur + * in parallel for two zbuds in one zbudpage, the field is a counter + * that must not exceed two. + */ +struct zbudpage { + union { + struct page page; + struct { + unsigned long space_for_flags; + struct { + unsigned zbud0_size:12; + unsigned zbud1_size:12; + unsigned unevictable:2; + }; + struct list_head budlist; + struct list_head lru; + }; + }; +}; + +struct zbudref { + union { + struct zbudpage *zbudpage; + unsigned long zbudref; + }; +}; + +#define CHUNK_SHIFT 6 +#define CHUNK_SIZE (1 << CHUNK_SHIFT) +#define CHUNK_MASK (~(CHUNK_SIZE-1)) +#define NCHUNKS (PAGE_SIZE >> CHUNK_SHIFT) +#define MAX_CHUNK (NCHUNKS-1) + +/* + * The following functions deal with the difference between struct + * page and struct zbudpage. Note the hack of using the pageflags + * from struct page; this is to avoid duplicating all the complex + * pageflag macros. + */ +static inline void zbudpage_spin_lock(struct zbudpage *zbudpage) +{ + struct page *page = (struct page *)zbudpage; + + while (unlikely(test_and_set_bit_lock(PG_locked, &page->flags))) { + do { + cpu_relax(); + } while (test_bit(PG_locked, &page->flags)); + } +} + +static inline void zbudpage_spin_unlock(struct zbudpage *zbudpage) +{ + struct page *page = (struct page *)zbudpage; + + clear_bit(PG_locked, &page->flags); +} + +static inline int zbudpage_spin_trylock(struct zbudpage *zbudpage) +{ + return trylock_page((struct page *)zbudpage); +} + +static inline int zbudpage_is_locked(struct zbudpage *zbudpage) +{ + return PageLocked((struct page *)zbudpage); +} + +static inline void *kmap_zbudpage_atomic(struct zbudpage *zbudpage) +{ + return kmap_atomic((struct page *)zbudpage); +} + +/* + * A dying zbudpage is an ephemeral page in the process of being evicted. + * Any data contained in the zbudpage is invalid and we are just waiting for + * the tmem pampds to be invalidated before freeing the page + */ +static inline int zbudpage_is_dying(struct zbudpage *zbudpage) +{ + struct page *page = (struct page *)zbudpage; + + return test_bit(PG_reclaim, &page->flags); +} + +static inline void zbudpage_set_dying(struct zbudpage *zbudpage) +{ + struct page *page = (struct page *)zbudpage; + + set_bit(PG_reclaim, &page->flags); +} + +static inline void zbudpage_clear_dying(struct zbudpage *zbudpage) +{ + struct page *page = (struct page *)zbudpage; + + clear_bit(PG_reclaim, &page->flags); +} + +/* + * A zombie zbudpage is a persistent page in the process of being evicted. + * The data contained in the zbudpage is valid and we are just waiting for + * the tmem pampds to be invalidated before freeing the page + */ +static inline int zbudpage_is_zombie(struct zbudpage *zbudpage) +{ + struct page *page = (struct page *)zbudpage; + + return test_bit(PG_dirty, &page->flags); +} + +static inline void zbudpage_set_zombie(struct zbudpage *zbudpage) +{ + struct page *page = (struct page *)zbudpage; + + set_bit(PG_dirty, &page->flags); +} + +static inline void zbudpage_clear_zombie(struct zbudpage *zbudpage) +{ + struct page *page = (struct page *)zbudpage; + + clear_bit(PG_dirty, &page->flags); +} + +static inline void kunmap_zbudpage_atomic(void *zbpg) +{ + kunmap_atomic(zbpg); +} + +/* + * zbud "translation" and helper functions + */ + +static inline struct zbudpage *zbudref_to_zbudpage(struct zbudref *zref) +{ + unsigned long zbud = (unsigned long)zref; + zbud &= ~1UL; + return (struct zbudpage *)zbud; +} + +static inline struct zbudref *zbudpage_to_zbudref(struct zbudpage *zbudpage, + unsigned budnum) +{ + unsigned long zbud = (unsigned long)zbudpage; + BUG_ON(budnum > 1); + zbud |= budnum; + return (struct zbudref *)zbud; +} + +static inline int zbudref_budnum(struct zbudref *zbudref) +{ + unsigned long zbud = (unsigned long)zbudref; + return zbud & 1UL; +} + +static inline unsigned zbud_max_size(void) +{ + return MAX_CHUNK << CHUNK_SHIFT; +} + +static inline unsigned zbud_size_to_chunks(unsigned size) +{ + BUG_ON(size == 0 || size > zbud_max_size()); + return (size + CHUNK_SIZE - 1) >> CHUNK_SHIFT; +} + +/* can only be used between kmap_zbudpage_atomic/kunmap_zbudpage_atomic! */ +static inline char *zbud_data(void *zbpg, + unsigned budnum, unsigned size) +{ + char *p; + + BUG_ON(size == 0 || size > zbud_max_size()); + p = (char *)zbpg; + if (budnum == 1) + p += PAGE_SIZE - ((size + CHUNK_SIZE - 1) & CHUNK_MASK); + return p; +} + +/* + * These are all informative and exposed through debugfs... except for + * the arrays... anyone know how to do that? To avoid confusion for + * debugfs viewers, some of these should also be atomic_long_t, but + * I don't know how to expose atomics via debugfs either... + */ +static unsigned long zbud_eph_pageframes; +static unsigned long zbud_pers_pageframes; +static unsigned long zbud_eph_zpages; +static unsigned long zbud_pers_zpages; +static u64 zbud_eph_zbytes; +static u64 zbud_pers_zbytes; +static unsigned long zbud_eph_evicted_pageframes; +static unsigned long zbud_pers_evicted_pageframes; +static unsigned long zbud_eph_cumul_zpages; +static unsigned long zbud_pers_cumul_zpages; +static u64 zbud_eph_cumul_zbytes; +static u64 zbud_pers_cumul_zbytes; +static unsigned long zbud_eph_cumul_chunk_counts[NCHUNKS]; +static unsigned long zbud_pers_cumul_chunk_counts[NCHUNKS]; +static unsigned long zbud_eph_buddied_count; +static unsigned long zbud_pers_buddied_count; +static unsigned long zbud_eph_unbuddied_count; +static unsigned long zbud_pers_unbuddied_count; +static unsigned long zbud_eph_zombie_count; +static unsigned long zbud_pers_zombie_count; +static atomic_t zbud_eph_zombie_atomic; +static atomic_t zbud_pers_zombie_atomic; + +#ifdef CONFIG_DEBUG_FS +#include <linux/debugfs.h> +#define zdfs debugfs_create_size_t +#define zdfs64 debugfs_create_u64 +static int zbud_debugfs_init(void) +{ + struct dentry *root = debugfs_create_dir("zbud", NULL); + if (root == NULL) + return -ENXIO; + + /* + * would be nice to dump the sizes of the unbuddied + * arrays, like was done with sysfs, but it doesn't + * look like debugfs is flexible enough to do that + */ + zdfs64("eph_zbytes", S_IRUGO, root, &zbud_eph_zbytes); + zdfs64("eph_cumul_zbytes", S_IRUGO, root, &zbud_eph_cumul_zbytes); + zdfs64("pers_zbytes", S_IRUGO, root, &zbud_pers_zbytes); + zdfs64("pers_cumul_zbytes", S_IRUGO, root, &zbud_pers_cumul_zbytes); + zdfs("eph_cumul_zpages", S_IRUGO, root, &zbud_eph_cumul_zpages); + zdfs("eph_evicted_pageframes", S_IRUGO, root, + &zbud_eph_evicted_pageframes); + zdfs("eph_zpages", S_IRUGO, root, &zbud_eph_zpages); + zdfs("eph_pageframes", S_IRUGO, root, &zbud_eph_pageframes); + zdfs("eph_buddied_count", S_IRUGO, root, &zbud_eph_buddied_count); + zdfs("eph_unbuddied_count", S_IRUGO, root, &zbud_eph_unbuddied_count); + zdfs("pers_cumul_zpages", S_IRUGO, root, &zbud_pers_cumul_zpages); + zdfs("pers_evicted_pageframes", S_IRUGO, root, + &zbud_pers_evicted_pageframes); + zdfs("pers_zpages", S_IRUGO, root, &zbud_pers_zpages); + zdfs("pers_pageframes", S_IRUGO, root, &zbud_pers_pageframes); + zdfs("pers_buddied_count", S_IRUGO, root, &zbud_pers_buddied_count); + zdfs("pers_unbuddied_count", S_IRUGO, root, &zbud_pers_unbuddied_count); + zdfs("pers_zombie_count", S_IRUGO, root, &zbud_pers_zombie_count); + return 0; +} +#undef zdfs +#undef zdfs64 +#endif + +/* protects the buddied list and all unbuddied lists */ +static DEFINE_SPINLOCK(zbud_eph_lists_lock); +static DEFINE_SPINLOCK(zbud_pers_lists_lock); + +struct zbud_unbuddied { + struct list_head list; + unsigned count; +}; + +/* list N contains pages with N chunks USED and NCHUNKS-N unused */ +/* element 0 is never used but optimizing that isn't worth it */ +static struct zbud_unbuddied zbud_eph_unbuddied[NCHUNKS]; +static struct zbud_unbuddied zbud_pers_unbuddied[NCHUNKS]; +static LIST_HEAD(zbud_eph_lru_list); +static LIST_HEAD(zbud_pers_lru_list); +static LIST_HEAD(zbud_eph_buddied_list); +static LIST_HEAD(zbud_pers_buddied_list); +static LIST_HEAD(zbud_eph_zombie_list); +static LIST_HEAD(zbud_pers_zombie_list); + +/* + * Given a struct page, transform it to a zbudpage so that it can be + * used by zbud and initialize fields as necessary. + */ +static inline struct zbudpage *zbud_init_zbudpage(struct page *page, bool eph) +{ + struct zbudpage *zbudpage = (struct zbudpage *)page; + + BUG_ON(page == NULL); + INIT_LIST_HEAD(&zbudpage->budlist); + INIT_LIST_HEAD(&zbudpage->lru); + zbudpage->zbud0_size = 0; + zbudpage->zbud1_size = 0; + zbudpage->unevictable = 0; + if (eph) + zbud_eph_pageframes++; + else + zbud_pers_pageframes++; + return zbudpage; +} + +/* "Transform" a zbudpage back to a struct page suitable to free. */ +static inline struct page *zbud_unuse_zbudpage(struct zbudpage *zbudpage, + bool eph) +{ + struct page *page = (struct page *)zbudpage; + + BUG_ON(!list_empty(&zbudpage->budlist)); + BUG_ON(!list_empty(&zbudpage->lru)); + BUG_ON(zbudpage->zbud0_size != 0); + BUG_ON(zbudpage->zbud1_size != 0); + BUG_ON(!PageLocked(page)); + BUG_ON(zbudpage->unevictable != 0); + BUG_ON(zbudpage_is_dying(zbudpage)); + BUG_ON(zbudpage_is_zombie(zbudpage)); + if (eph) + zbud_eph_pageframes--; + else + zbud_pers_pageframes--; + zbudpage_spin_unlock(zbudpage); + reset_page_mapcount(page); + init_page_count(page); + page->index = 0; + return page; +} + +/* Mark a zbud as unused and do accounting */ +static inline void zbud_unuse_zbud(struct zbudpage *zbudpage, + int budnum, bool eph) +{ + unsigned size; + + BUG_ON(!zbudpage_is_locked(zbudpage)); + if (budnum == 0) { + size = zbudpage->zbud0_size; + zbudpage->zbud0_size = 0; + } else { + size = zbudpage->zbud1_size; + zbudpage->zbud1_size = 0; + } + if (eph) { + zbud_eph_zbytes -= size; + zbud_eph_zpages--; + } else { + zbud_pers_zbytes -= size; + zbud_pers_zpages--; + } +} + +/* + * Given a zbudpage/budnum/size, a tmem handle, and a kmapped pointer + * to some data, set up the zbud appropriately including data copying + * and accounting. Note that if cdata is NULL, the data copying is + * skipped. (This is useful for lazy writes such as for RAMster.) + */ +static void zbud_init_zbud(struct zbudpage *zbudpage, struct tmem_handle *th, + bool eph, void *cdata, + unsigned budnum, unsigned size) +{ + char *to; + void *zbpg; + struct tmem_handle *to_th; + unsigned nchunks = zbud_size_to_chunks(size); + + BUG_ON(!zbudpage_is_locked(zbudpage)); + zbpg = kmap_zbudpage_atomic(zbudpage); + to = zbud_data(zbpg, budnum, size); + to_th = (struct tmem_handle *)to; + to_th->index = th->index; + to_th->oid = th->oid; + to_th->pool_id = th->pool_id; + to_th->client_id = th->client_id; + to += sizeof(struct tmem_handle); + if (cdata != NULL) + memcpy(to, cdata, size - sizeof(struct tmem_handle)); + kunmap_zbudpage_atomic(zbpg); + if (budnum == 0) + zbudpage->zbud0_size = size; + else + zbudpage->zbud1_size = size; + if (eph) { + zbud_eph_cumul_chunk_counts[nchunks]++; + zbud_eph_zpages++; + zbud_eph_cumul_zpages++; + zbud_eph_zbytes += size; + zbud_eph_cumul_zbytes += size; + } else { + zbud_pers_cumul_chunk_counts[nchunks]++; + zbud_pers_zpages++; + zbud_pers_cumul_zpages++; + zbud_pers_zbytes += size; + zbud_pers_cumul_zbytes += size; + } +} + +/* + * Given a locked dying zbudpage, read out the tmem handles from the data, + * unlock the page, then use the handles to tell tmem to flush out its + * references + */ +static void zbud_evict_tmem(struct zbudpage *zbudpage) +{ + int i, j; + uint32_t pool_id[2], client_id[2]; + uint32_t index[2]; + struct tmem_oid oid[2]; + struct tmem_pool *pool; + void *zbpg; + struct tmem_handle *th; + unsigned size; + + /* read out the tmem handles from the data and set aside */ + zbpg = kmap_zbudpage_atomic(zbudpage); + for (i = 0, j = 0; i < 2; i++) { + size = (i == 0) ? zbudpage->zbud0_size : zbudpage->zbud1_size; + if (size) { + th = (struct tmem_handle *)zbud_data(zbpg, i, size); + client_id[j] = th->client_id; + pool_id[j] = th->pool_id; + oid[j] = th->oid; + index[j] = th->index; + j++; + zbud_unuse_zbud(zbudpage, i, true); + } + } + kunmap_zbudpage_atomic(zbpg); + zbudpage_spin_unlock(zbudpage); + /* zbudpage is now an unlocked dying... tell tmem to flush pointers */ + for (i = 0; i < j; i++) { + pool = zcache_get_pool_by_id(client_id[i], pool_id[i]); + if (pool != NULL) { + tmem_flush_page(pool, &oid[i], index[i]); + zcache_put_pool(pool); + } + } +} + +/* + * Externally callable zbud handling routines. + */ + +/* + * Return the maximum size compressed page that can be stored (secretly + * setting aside space for the tmem handle. + */ +unsigned int zbud_max_buddy_size(void) +{ + return zbud_max_size() - sizeof(struct tmem_handle); +} + +/* + * Given a zbud reference, free the corresponding zbud from all lists, + * mark it as unused, do accounting, and if the freeing of the zbud + * frees up an entire pageframe, return it to the caller (else NULL). + */ +struct page *zbud_free_and_delist(struct zbudref *zref, bool eph, + unsigned int *zsize, unsigned int *zpages) +{ + unsigned long budnum = zbudref_budnum(zref); + struct zbudpage *zbudpage = zbudref_to_zbudpage(zref); + struct page *page = NULL; + unsigned chunks, bud_size, other_bud_size; + spinlock_t *lists_lock = + eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock; + struct zbud_unbuddied *unbud = + eph ? zbud_eph_unbuddied : zbud_pers_unbuddied; + + + spin_lock(lists_lock); + zbudpage_spin_lock(zbudpage); + if (zbudpage_is_dying(zbudpage)) { + /* ignore dying zbudpage... see zbud_evict_pageframe_lru() */ + zbudpage_spin_unlock(zbudpage); + spin_unlock(lists_lock); + *zpages = 0; + *zsize = 0; + goto out; + } + if (budnum == 0) { + bud_size = zbudpage->zbud0_size; + other_bud_size = zbudpage->zbud1_size; + } else { + bud_size = zbudpage->zbud1_size; + other_bud_size = zbudpage->zbud0_size; + } + *zsize = bud_size - sizeof(struct tmem_handle); + *zpages = 1; + zbud_unuse_zbud(zbudpage, budnum, eph); + if (other_bud_size == 0) { /* was unbuddied: unlist and free */ + chunks = zbud_size_to_chunks(bud_size) ; + if (zbudpage_is_zombie(zbudpage)) { + if (eph) + zbud_pers_zombie_count = + atomic_dec_return(&zbud_eph_zombie_atomic); + else + zbud_pers_zombie_count = + atomic_dec_return(&zbud_pers_zombie_atomic); + zbudpage_clear_zombie(zbudpage); + } else { + BUG_ON(list_empty(&unbud[chunks].list)); + list_del_init(&zbudpage->budlist); + unbud[chunks].count--; + } + list_del_init(&zbudpage->lru); + spin_unlock(lists_lock); + if (eph) + zbud_eph_unbuddied_count--; + else + zbud_pers_unbuddied_count--; + page = zbud_unuse_zbudpage(zbudpage, eph); + } else { /* was buddied: move remaining buddy to unbuddied list */ + chunks = zbud_size_to_chunks(other_bud_size) ; + if (!zbudpage_is_zombie(zbudpage)) { + list_del_init(&zbudpage->budlist); + list_add_tail(&zbudpage->budlist, &unbud[chunks].list); + unbud[chunks].count++; + } + if (eph) { + zbud_eph_buddied_count--; + zbud_eph_unbuddied_count++; + } else { + zbud_pers_unbuddied_count++; + zbud_pers_buddied_count--; + } + /* don't mess with lru, no need to move it */ + zbudpage_spin_unlock(zbudpage); + spin_unlock(lists_lock); + } +out: + return page; +} + +/* + * Given a tmem handle, and a kmapped pointer to compressed data of + * the given size, try to find an unbuddied zbudpage in which to + * create a zbud. If found, put it there, mark the zbudpage unevictable, + * and return a zbudref to it. Else return NULL. + */ +struct zbudref *zbud_match_prep(struct tmem_handle *th, bool eph, + void *cdata, unsigned size) +{ + struct zbudpage *zbudpage = NULL, *zbudpage2; + unsigned long budnum = 0UL; + unsigned nchunks; + int i, found_good_buddy = 0; + spinlock_t *lists_lock = + eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock; + struct zbud_unbuddied *unbud = + eph ? zbud_eph_unbuddied : zbud_pers_unbuddied; + + size += sizeof(struct tmem_handle); + nchunks = zbud_size_to_chunks(size); + for (i = MAX_CHUNK - nchunks + 1; i > 0; i--) { + spin_lock(lists_lock); + if (!list_empty(&unbud[i].list)) { + list_for_each_entry_safe(zbudpage, zbudpage2, + &unbud[i].list, budlist) { + if (zbudpage_spin_trylock(zbudpage)) { + found_good_buddy = i; + goto found_unbuddied; + } + } + } + spin_unlock(lists_lock); + } + zbudpage = NULL; + goto out; + +found_unbuddied: + BUG_ON(!zbudpage_is_locked(zbudpage)); + BUG_ON(!((zbudpage->zbud0_size == 0) ^ (zbudpage->zbud1_size == 0))); + if (zbudpage->zbud0_size == 0) + budnum = 0UL; + else if (zbudpage->zbud1_size == 0) + budnum = 1UL; + list_del_init(&zbudpage->budlist); + if (eph) { + list_add_tail(&zbudpage->budlist, &zbud_eph_buddied_list); + unbud[found_good_buddy].count--; + zbud_eph_unbuddied_count--; + zbud_eph_buddied_count++; + /* "promote" raw zbudpage to most-recently-used */ + list_del_init(&zbudpage->lru); + list_add_tail(&zbudpage->lru, &zbud_eph_lru_list); + } else { + list_add_tail(&zbudpage->budlist, &zbud_pers_buddied_list); + unbud[found_good_buddy].count--; + zbud_pers_unbuddied_count--; + zbud_pers_buddied_count++; + /* "promote" raw zbudpage to most-recently-used */ + list_del_init(&zbudpage->lru); + list_add_tail(&zbudpage->lru, &zbud_pers_lru_list); + } + zbud_init_zbud(zbudpage, th, eph, cdata, budnum, size); + zbudpage->unevictable++; + BUG_ON(zbudpage->unevictable == 3); + zbudpage_spin_unlock(zbudpage); + spin_unlock(lists_lock); +out: + return zbudpage_to_zbudref(zbudpage, budnum); + +} + +/* + * Given a tmem handle, and a kmapped pointer to compressed data of + * the given size, and a newly allocated struct page, create an unevictable + * zbud in that new page and return a zbudref to it. + */ +struct zbudref *zbud_create_prep(struct tmem_handle *th, bool eph, + void *cdata, unsigned size, + struct page *newpage) +{ + struct zbudpage *zbudpage; + unsigned long budnum = 0; + unsigned nchunks; + spinlock_t *lists_lock = + eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock; + struct zbud_unbuddied *unbud = + eph ? zbud_eph_unbuddied : zbud_pers_unbuddied; + +#if 0 + /* this may be worth it later to support decompress-in-place? */ + static unsigned long counter; + budnum = counter++ & 1; /* alternate using zbud0 and zbud1 */ +#endif + + if (size > zbud_max_buddy_size()) + return NULL; + if (newpage == NULL) + return NULL; + + size += sizeof(struct tmem_handle); + nchunks = zbud_size_to_chunks(size) ; + spin_lock(lists_lock); + zbudpage = zbud_init_zbudpage(newpage, eph); + zbudpage_spin_lock(zbudpage); + list_add_tail(&zbudpage->budlist, &unbud[nchunks].list); + if (eph) { + list_add_tail(&zbudpage->lru, &zbud_eph_lru_list); + zbud_eph_unbuddied_count++; + } else { + list_add_tail(&zbudpage->lru, &zbud_pers_lru_list); + zbud_pers_unbuddied_count++; + } + unbud[nchunks].count++; + zbud_init_zbud(zbudpage, th, eph, cdata, budnum, size); + zbudpage->unevictable++; + BUG_ON(zbudpage->unevictable == 3); + zbudpage_spin_unlock(zbudpage); + spin_unlock(lists_lock); + return zbudpage_to_zbudref(zbudpage, budnum); +} + +/* + * Finish creation of a zbud by, assuming another zbud isn't being created + * in parallel, marking it evictable. + */ +void zbud_create_finish(struct zbudref *zref, bool eph) +{ + struct zbudpage *zbudpage = zbudref_to_zbudpage(zref); + spinlock_t *lists_lock = + eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock; + + spin_lock(lists_lock); + zbudpage_spin_lock(zbudpage); + BUG_ON(zbudpage_is_dying(zbudpage)); + zbudpage->unevictable--; + BUG_ON((int)zbudpage->unevictable < 0); + zbudpage_spin_unlock(zbudpage); + spin_unlock(lists_lock); +} + +/* + * Given a zbudref and a struct page, decompress the data from + * the zbud into the physical page represented by the struct page + * by upcalling to zcache_decompress + */ +int zbud_decompress(struct page *data_page, struct zbudref *zref, bool eph, + void (*decompress)(char *, unsigned int, char *)) +{ + struct zbudpage *zbudpage = zbudref_to_zbudpage(zref); + unsigned long budnum = zbudref_budnum(zref); + void *zbpg; + char *to_va, *from_va; + unsigned size; + int ret = -1; + spinlock_t *lists_lock = + eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock; + + spin_lock(lists_lock); + zbudpage_spin_lock(zbudpage); + if (zbudpage_is_dying(zbudpage)) { + /* ignore dying zbudpage... see zbud_evict_pageframe_lru() */ + goto out; + } + zbpg = kmap_zbudpage_atomic(zbudpage); + to_va = kmap_atomic(data_page); + if (budnum == 0) + size = zbudpage->zbud0_size; + else + size = zbudpage->zbud1_size; + BUG_ON(size == 0 || size > zbud_max_size()); + from_va = zbud_data(zbpg, budnum, size); + from_va += sizeof(struct tmem_handle); + size -= sizeof(struct tmem_handle); + decompress(from_va, size, to_va); + kunmap_atomic(to_va); + kunmap_zbudpage_atomic(zbpg); + ret = 0; +out: + zbudpage_spin_unlock(zbudpage); + spin_unlock(lists_lock); + return ret; +} + +/* + * Given a zbudref and a kernel pointer, copy the data from + * the zbud to the kernel pointer. + */ +int zbud_copy_from_zbud(char *to_va, struct zbudref *zref, + size_t *sizep, bool eph) +{ + struct zbudpage *zbudpage = zbudref_to_zbudpage(zref); + unsigned long budnum = zbudref_budnum(zref); + void *zbpg; + char *from_va; + unsigned size; + int ret = -1; + spinlock_t *lists_lock = + eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock; + + spin_lock(lists_lock); + zbudpage_spin_lock(zbudpage); + if (zbudpage_is_dying(zbudpage)) { + /* ignore dying zbudpage... see zbud_evict_pageframe_lru() */ + goto out; + } + zbpg = kmap_zbudpage_atomic(zbudpage); + if (budnum == 0) + size = zbudpage->zbud0_size; + else + size = zbudpage->zbud1_size; + BUG_ON(size == 0 || size > zbud_max_size()); + from_va = zbud_data(zbpg, budnum, size); + from_va += sizeof(struct tmem_handle); + size -= sizeof(struct tmem_handle); + *sizep = size; + memcpy(to_va, from_va, size); + + kunmap_zbudpage_atomic(zbpg); + ret = 0; +out: + zbudpage_spin_unlock(zbudpage); + spin_unlock(lists_lock); + return ret; +} + +/* + * Given a zbudref and a kernel pointer, copy the data from + * the kernel pointer to the zbud. + */ +int zbud_copy_to_zbud(struct zbudref *zref, char *from_va, bool eph) +{ + struct zbudpage *zbudpage = zbudref_to_zbudpage(zref); + unsigned long budnum = zbudref_budnum(zref); + void *zbpg; + char *to_va; + unsigned size; + int ret = -1; + spinlock_t *lists_lock = + eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock; + + spin_lock(lists_lock); + zbudpage_spin_lock(zbudpage); + if (zbudpage_is_dying(zbudpage)) { + /* ignore dying zbudpage... see zbud_evict_pageframe_lru() */ + goto out; + } + zbpg = kmap_zbudpage_atomic(zbudpage); + if (budnum == 0) + size = zbudpage->zbud0_size; + else + size = zbudpage->zbud1_size; + BUG_ON(size == 0 || size > zbud_max_size()); + to_va = zbud_data(zbpg, budnum, size); + to_va += sizeof(struct tmem_handle); + size -= sizeof(struct tmem_handle); + memcpy(to_va, from_va, size); + + kunmap_zbudpage_atomic(zbpg); + ret = 0; +out: + zbudpage_spin_unlock(zbudpage); + spin_unlock(lists_lock); + return ret; +} + +/* + * Choose an ephemeral LRU zbudpage that is evictable (not locked), ensure + * there are no references to it remaining, and return the now unused + * (and re-init'ed) struct page and the total amount of compressed + * data that was evicted. + */ +struct page *zbud_evict_pageframe_lru(unsigned int *zsize, unsigned int *zpages) +{ + struct zbudpage *zbudpage = NULL, *zbudpage2; + struct zbud_unbuddied *unbud = zbud_eph_unbuddied; + struct page *page = NULL; + bool irqs_disabled = irqs_disabled(); + + /* + * Since this can be called indirectly from cleancache_put, which + * has interrupts disabled, as well as frontswap_put, which does not, + * we need to be able to handle both cases, even though it is ugly. + */ + if (irqs_disabled) + spin_lock(&zbud_eph_lists_lock); + else + spin_lock_bh(&zbud_eph_lists_lock); + *zsize = 0; + if (list_empty(&zbud_eph_lru_list)) + goto unlock_out; + list_for_each_entry_safe(zbudpage, zbudpage2, &zbud_eph_lru_list, lru) { + /* skip a locked zbudpage */ + if (unlikely(!zbudpage_spin_trylock(zbudpage))) + continue; + /* skip an unevictable zbudpage */ + if (unlikely(zbudpage->unevictable != 0)) { + zbudpage_spin_unlock(zbudpage); + continue; + } + /* got a locked evictable page */ + goto evict_page; + + } +unlock_out: + /* no unlocked evictable pages, give up */ + if (irqs_disabled) + spin_unlock(&zbud_eph_lists_lock); + else + spin_unlock_bh(&zbud_eph_lists_lock); + goto out; + +evict_page: + list_del_init(&zbudpage->budlist); + list_del_init(&zbudpage->lru); + zbudpage_set_dying(zbudpage); + /* + * the zbudpage is now "dying" and attempts to read, write, + * or delete data from it will be ignored + */ + if (zbudpage->zbud0_size != 0 && zbudpage->zbud1_size != 0) { + *zsize = zbudpage->zbud0_size + zbudpage->zbud1_size - + (2 * sizeof(struct tmem_handle)); + *zpages = 2; + } else if (zbudpage->zbud0_size != 0) { + unbud[zbud_size_to_chunks(zbudpage->zbud0_size)].count--; + *zsize = zbudpage->zbud0_size - sizeof(struct tmem_handle); + *zpages = 1; + } else if (zbudpage->zbud1_size != 0) { + unbud[zbud_size_to_chunks(zbudpage->zbud1_size)].count--; + *zsize = zbudpage->zbud1_size - sizeof(struct tmem_handle); + *zpages = 1; + } else { + BUG(); + } + spin_unlock(&zbud_eph_lists_lock); + zbud_eph_evicted_pageframes++; + if (*zpages == 1) + zbud_eph_unbuddied_count--; + else + zbud_eph_buddied_count--; + zbud_evict_tmem(zbudpage); + zbudpage_spin_lock(zbudpage); + zbudpage_clear_dying(zbudpage); + page = zbud_unuse_zbudpage(zbudpage, true); + if (!irqs_disabled) + local_bh_enable(); +out: + return page; +} + +/* + * Choose a persistent LRU zbudpage that is evictable (not locked), zombify it, + * read the tmem_handle(s) out of it into the passed array, and return the + * number of zbuds. Caller must perform necessary tmem functions and, + * indirectly, zbud functions to fetch any valid data and cause the + * now-zombified zbudpage to eventually be freed. We track the zombified + * zbudpage count so it is possible to observe if there is a leak. + FIXME: describe (ramster) case where data pointers are passed in for memcpy + */ +unsigned int zbud_make_zombie_lru(struct tmem_handle *th, unsigned char **data, + unsigned int *zsize, bool eph) +{ + struct zbudpage *zbudpage = NULL, *zbudpag2; + struct tmem_handle *thfrom; + char *from_va; + void *zbpg; + unsigned size; + int ret = 0, i; + spinlock_t *lists_lock = + eph ? &zbud_eph_lists_lock : &zbud_pers_lists_lock; + struct list_head *lru_list = + eph ? &zbud_eph_lru_list : &zbud_pers_lru_list; + + spin_lock_bh(lists_lock); + if (list_empty(lru_list)) + goto out; + list_for_each_entry_safe(zbudpage, zbudpag2, lru_list, lru) { + /* skip a locked zbudpage */ + if (unlikely(!zbudpage_spin_trylock(zbudpage))) + continue; + /* skip an unevictable zbudpage */ + if (unlikely(zbudpage->unevictable != 0)) { + zbudpage_spin_unlock(zbudpage); + continue; + } + /* got a locked evictable page */ + goto zombify_page; + } + /* no unlocked evictable pages, give up */ + goto out; + +zombify_page: + /* got an unlocked evictable page, zombify it */ + list_del_init(&zbudpage->budlist); + zbudpage_set_zombie(zbudpage); + /* FIXME what accounting do I need to do here? */ + list_del_init(&zbudpage->lru); + if (eph) { + list_add_tail(&zbudpage->lru, &zbud_eph_zombie_list); + zbud_eph_zombie_count = + atomic_inc_return(&zbud_eph_zombie_atomic); + } else { + list_add_tail(&zbudpage->lru, &zbud_pers_zombie_list); + zbud_pers_zombie_count = + atomic_inc_return(&zbud_pers_zombie_atomic); + } + /* FIXME what accounting do I need to do here? */ + zbpg = kmap_zbudpage_atomic(zbudpage); + for (i = 0; i < 2; i++) { + size = (i == 0) ? zbudpage->zbud0_size : zbudpage->zbud1_size; + if (size) { + from_va = zbud_data(zbpg, i, size); + thfrom = (struct tmem_handle *)from_va; + from_va += sizeof(struct tmem_handle); + size -= sizeof(struct tmem_handle); + if (th != NULL) + th[ret] = *thfrom; + if (data != NULL) + memcpy(data[ret], from_va, size); + if (zsize != NULL) + *zsize++ = size; + ret++; + } + } + kunmap_zbudpage_atomic(zbpg); + zbudpage_spin_unlock(zbudpage); +out: + spin_unlock_bh(lists_lock); + return ret; +} + +void __init zbud_init(void) +{ + int i; + +#ifdef CONFIG_DEBUG_FS + zbud_debugfs_init(); +#endif + BUG_ON((sizeof(struct tmem_handle) * 2 > CHUNK_SIZE)); + BUG_ON(sizeof(struct zbudpage) > sizeof(struct page)); + for (i = 0; i < NCHUNKS; i++) { + INIT_LIST_HEAD(&zbud_eph_unbuddied[i].list); + INIT_LIST_HEAD(&zbud_pers_unbuddied[i].list); + } +} diff --git a/drivers/staging/ramster/zbud.h b/drivers/staging/ramster/zbud.h new file mode 100644 index 000000000000..891e8a7d5aa5 --- /dev/null +++ b/drivers/staging/ramster/zbud.h @@ -0,0 +1,33 @@ +/* + * zbud.h + * + * Copyright (c) 2010-2012, Dan Magenheimer, Oracle Corp. + * + */ + +#ifndef _ZBUD_H_ +#define _ZBUD_H_ + +#include "tmem.h" + +struct zbudref; + +extern unsigned int zbud_max_buddy_size(void); +extern struct zbudref *zbud_match_prep(struct tmem_handle *th, bool eph, + void *cdata, unsigned size); +extern struct zbudref *zbud_create_prep(struct tmem_handle *th, bool eph, + void *cdata, unsigned size, + struct page *newpage); +extern void zbud_create_finish(struct zbudref *, bool); +extern int zbud_decompress(struct page *, struct zbudref *, bool, + void (*func)(char *, unsigned int, char *)); +extern int zbud_copy_from_zbud(char *, struct zbudref *, size_t *, bool); +extern int zbud_copy_to_zbud(struct zbudref *, char *, bool); +extern struct page *zbud_free_and_delist(struct zbudref *, bool eph, + unsigned int *, unsigned int *); +extern struct page *zbud_evict_pageframe_lru(unsigned int *, unsigned int *); +extern unsigned int zbud_make_zombie_lru(struct tmem_handle *, unsigned char **, + unsigned int *, bool); +extern void zbud_init(void); + +#endif /* _ZBUD_H_ */ diff --git a/drivers/staging/ramster/zcache-main.c b/drivers/staging/ramster/zcache-main.c index d46764b5aaba..a09dd5cc1cea 100644 --- a/drivers/staging/ramster/zcache-main.c +++ b/drivers/staging/ramster/zcache-main.c @@ -5,1392 +5,322 @@ * Copyright (c) 2010,2011, Nitin Gupta * * Zcache provides an in-kernel "host implementation" for transcendent memory - * and, thus indirectly, for cleancache and frontswap. Zcache includes two - * page-accessible memory [1] interfaces, both utilizing lzo1x compression: - * 1) "compression buddies" ("zbud") is used for ephemeral pages - * 2) xvmalloc is used for persistent pages. - * Xvmalloc (based on the TLSF allocator) has very low fragmentation - * so maximizes space efficiency, while zbud allows pairs (and potentially, - * in the future, more than a pair of) compressed pages to be closely linked - * so that reclaiming can be done via the kernel's physical-page-oriented - * "shrinker" interface. - * - * [1] For a definition of page-accessible memory (aka PAM), see: - * http://marc.info/?l=linux-mm&m=127811271605009 - * RAMSTER TODO: - * - handle remotifying of buddied pages (see zbud_remotify_zbpg) - * - kernel boot params: nocleancache/nofrontswap don't always work?!? + * ("tmem") and, thus indirectly, for cleancache and frontswap. Zcache uses + * lzo1x compression to improve density and an embedded allocator called + * "zbud" which "buddies" two compressed pages semi-optimally in each physical + * pageframe. Zbud is integrally tied into tmem to allow pageframes to + * be "reclaimed" efficiently. */ #include <linux/module.h> #include <linux/cpu.h> #include <linux/highmem.h> #include <linux/list.h> -#include <linux/lzo.h> #include <linux/slab.h> #include <linux/spinlock.h> #include <linux/types.h> #include <linux/atomic.h> #include <linux/math64.h> -#include "tmem.h" -#include "zcache.h" -#include "ramster.h" -#include "cluster/tcp.h" +#include <linux/crypto.h> -#include "xvmalloc.h" /* temporary until change to zsmalloc */ - -#define RAMSTER_TESTING - -#if (!defined(CONFIG_CLEANCACHE) && !defined(CONFIG_FRONTSWAP)) -#error "ramster is useless without CONFIG_CLEANCACHE or CONFIG_FRONTSWAP" -#endif -#ifdef CONFIG_CLEANCACHE #include <linux/cleancache.h> -#endif -#ifdef CONFIG_FRONTSWAP #include <linux/frontswap.h> -#endif - -enum ramster_remotify_op { - RAMSTER_REMOTIFY_EPH_PUT, - RAMSTER_REMOTIFY_PERS_PUT, - RAMSTER_REMOTIFY_FLUSH_PAGE, - RAMSTER_REMOTIFY_FLUSH_OBJ, - RAMSTER_INTRANSIT_PERS -}; - -struct ramster_remotify_hdr { - enum ramster_remotify_op op; - struct list_head list; -}; - -#define ZBH_SENTINEL 0x43214321 -#define ZBPG_SENTINEL 0xdeadbeef - -#define ZBUD_MAX_BUDS 2 - -struct zbud_hdr { - struct ramster_remotify_hdr rem_op; - uint16_t client_id; - uint16_t pool_id; - struct tmem_oid oid; - uint32_t index; - uint16_t size; /* compressed size in bytes, zero means unused */ - DECL_SENTINEL -}; - -#define ZVH_SENTINEL 0x43214321 -static const int zv_max_page_size = (PAGE_SIZE / 8) * 7; - -struct zv_hdr { - struct ramster_remotify_hdr rem_op; - uint16_t client_id; - uint16_t pool_id; - struct tmem_oid oid; - uint32_t index; - DECL_SENTINEL -}; - -struct flushlist_node { - struct ramster_remotify_hdr rem_op; - struct tmem_xhandle xh; -}; - -union { - struct ramster_remotify_hdr rem_op; - struct zv_hdr zv; - struct zbud_hdr zbud; - struct flushlist_node flist; -} remotify_list_node; - -static LIST_HEAD(zcache_rem_op_list); -static DEFINE_SPINLOCK(zcache_rem_op_list_lock); - -#if 0 -/* this is more aggressive but may cause other problems? */ -#define ZCACHE_GFP_MASK (GFP_ATOMIC | __GFP_NORETRY | __GFP_NOWARN) +#include "tmem.h" +#include "zcache.h" +#include "zbud.h" +#include "ramster.h" +#ifdef CONFIG_RAMSTER +static int ramster_enabled; #else -#define ZCACHE_GFP_MASK \ - (__GFP_FS | __GFP_NORETRY | __GFP_NOWARN | __GFP_NOMEMALLOC) +#define ramster_enabled 0 #endif -#define MAX_POOLS_PER_CLIENT 16 - -#define MAX_CLIENTS 16 -#define LOCAL_CLIENT ((uint16_t)-1) - -MODULE_LICENSE("GPL"); - -struct zcache_client { - struct tmem_pool *tmem_pools[MAX_POOLS_PER_CLIENT]; - struct xv_pool *xvpool; - bool allocated; - atomic_t refcount; -}; - -static struct zcache_client zcache_host; -static struct zcache_client zcache_clients[MAX_CLIENTS]; - -static inline uint16_t get_client_id_from_client(struct zcache_client *cli) +#ifndef __PG_WAS_ACTIVE +static inline bool PageWasActive(struct page *page) { - BUG_ON(cli == NULL); - if (cli == &zcache_host) - return LOCAL_CLIENT; - return cli - &zcache_clients[0]; + return true; } -static inline bool is_local_client(struct zcache_client *cli) +static inline void SetPageWasActive(struct page *page) { - return cli == &zcache_host; -} - -/********** - * Compression buddies ("zbud") provides for packing two (or, possibly - * in the future, more) compressed ephemeral pages into a single "raw" - * (physical) page and tracking them with data structures so that - * the raw pages can be easily reclaimed. - * - * A zbud page ("zbpg") is an aligned page containing a list_head, - * a lock, and two "zbud headers". The remainder of the physical - * page is divided up into aligned 64-byte "chunks" which contain - * the compressed data for zero, one, or two zbuds. Each zbpg - * resides on: (1) an "unused list" if it has no zbuds; (2) a - * "buddied" list if it is fully populated with two zbuds; or - * (3) one of PAGE_SIZE/64 "unbuddied" lists indexed by how many chunks - * the one unbuddied zbud uses. The data inside a zbpg cannot be - * read or written unless the zbpg's lock is held. - */ - -struct zbud_page { - struct list_head bud_list; - spinlock_t lock; - struct zbud_hdr buddy[ZBUD_MAX_BUDS]; - DECL_SENTINEL - /* followed by NUM_CHUNK aligned CHUNK_SIZE-byte chunks */ -}; - -#define CHUNK_SHIFT 6 -#define CHUNK_SIZE (1 << CHUNK_SHIFT) -#define CHUNK_MASK (~(CHUNK_SIZE-1)) -#define NCHUNKS (((PAGE_SIZE - sizeof(struct zbud_page)) & \ - CHUNK_MASK) >> CHUNK_SHIFT) -#define MAX_CHUNK (NCHUNKS-1) - -static struct { - struct list_head list; - unsigned count; -} zbud_unbuddied[NCHUNKS]; -/* list N contains pages with N chunks USED and NCHUNKS-N unused */ -/* element 0 is never used but optimizing that isn't worth it */ -static unsigned long zbud_cumul_chunk_counts[NCHUNKS]; - -struct list_head zbud_buddied_list; -static unsigned long zcache_zbud_buddied_count; - -/* protects the buddied list and all unbuddied lists */ -static DEFINE_SPINLOCK(zbud_budlists_spinlock); - -static atomic_t zcache_zbud_curr_raw_pages; -static atomic_t zcache_zbud_curr_zpages; -static unsigned long zcache_zbud_curr_zbytes; -static unsigned long zcache_zbud_cumul_zpages; -static unsigned long zcache_zbud_cumul_zbytes; -static unsigned long zcache_compress_poor; -static unsigned long zcache_policy_percent_exceeded; -static unsigned long zcache_mean_compress_poor; - -/* - * RAMster counters - * - Remote pages are pages with a local pampd but the data is remote - * - Foreign pages are pages stored locally but belonging to another node - */ -static atomic_t ramster_remote_pers_pages = ATOMIC_INIT(0); -static unsigned long ramster_pers_remotify_enable; -static unsigned long ramster_eph_remotify_enable; -static unsigned long ramster_eph_pages_remoted; -static unsigned long ramster_eph_pages_remote_failed; -static unsigned long ramster_pers_pages_remoted; -static unsigned long ramster_pers_pages_remote_failed; -static unsigned long ramster_pers_pages_remote_nomem; -static unsigned long ramster_remote_objects_flushed; -static unsigned long ramster_remote_object_flushes_failed; -static unsigned long ramster_remote_pages_flushed; -static unsigned long ramster_remote_page_flushes_failed; -static unsigned long ramster_remote_eph_pages_succ_get; -static unsigned long ramster_remote_pers_pages_succ_get; -static unsigned long ramster_remote_eph_pages_unsucc_get; -static unsigned long ramster_remote_pers_pages_unsucc_get; -static atomic_t ramster_curr_flnode_count = ATOMIC_INIT(0); -static unsigned long ramster_curr_flnode_count_max; -static atomic_t ramster_foreign_eph_pampd_count = ATOMIC_INIT(0); -static unsigned long ramster_foreign_eph_pampd_count_max; -static atomic_t ramster_foreign_pers_pampd_count = ATOMIC_INIT(0); -static unsigned long ramster_foreign_pers_pampd_count_max; - -/* forward references */ -static void *zcache_get_free_page(void); -static void zcache_free_page(void *p); - -/* - * zbud helper functions - */ - -static inline unsigned zbud_max_buddy_size(void) -{ - return MAX_CHUNK << CHUNK_SHIFT; } +#endif -static inline unsigned zbud_size_to_chunks(unsigned size) +#ifdef FRONTSWAP_HAS_EXCLUSIVE_GETS +static bool frontswap_has_exclusive_gets __read_mostly = true; +#else +static bool frontswap_has_exclusive_gets __read_mostly; +static inline void frontswap_tmem_exclusive_gets(bool b) { - BUG_ON(size == 0 || size > zbud_max_buddy_size()); - return (size + CHUNK_SIZE - 1) >> CHUNK_SHIFT; -} - -static inline int zbud_budnum(struct zbud_hdr *zh) -{ - unsigned offset = (unsigned long)zh & (PAGE_SIZE - 1); - struct zbud_page *zbpg = NULL; - unsigned budnum = -1U; - int i; - - for (i = 0; i < ZBUD_MAX_BUDS; i++) - if (offset == offsetof(typeof(*zbpg), buddy[i])) { - budnum = i; - break; - } - BUG_ON(budnum == -1U); - return budnum; -} - -static char *zbud_data(struct zbud_hdr *zh, unsigned size) -{ - struct zbud_page *zbpg; - char *p; - unsigned budnum; - - ASSERT_SENTINEL(zh, ZBH); - budnum = zbud_budnum(zh); - BUG_ON(size == 0 || size > zbud_max_buddy_size()); - zbpg = container_of(zh, struct zbud_page, buddy[budnum]); - ASSERT_SPINLOCK(&zbpg->lock); - p = (char *)zbpg; - if (budnum == 0) - p += ((sizeof(struct zbud_page) + CHUNK_SIZE - 1) & - CHUNK_MASK); - else if (budnum == 1) - p += PAGE_SIZE - ((size + CHUNK_SIZE - 1) & CHUNK_MASK); - return p; -} - -static void zbud_copy_from_pampd(char *data, size_t *size, struct zbud_hdr *zh) -{ - struct zbud_page *zbpg; - char *p; - unsigned budnum; - - ASSERT_SENTINEL(zh, ZBH); - budnum = zbud_budnum(zh); - zbpg = container_of(zh, struct zbud_page, buddy[budnum]); - spin_lock(&zbpg->lock); - BUG_ON(zh->size > *size); - p = (char *)zbpg; - if (budnum == 0) - p += ((sizeof(struct zbud_page) + CHUNK_SIZE - 1) & - CHUNK_MASK); - else if (budnum == 1) - p += PAGE_SIZE - ((zh->size + CHUNK_SIZE - 1) & CHUNK_MASK); - /* client should be filled in by caller */ - memcpy(data, p, zh->size); - *size = zh->size; - spin_unlock(&zbpg->lock); -} - -/* - * zbud raw page management - */ - -static struct zbud_page *zbud_alloc_raw_page(void) -{ - struct zbud_page *zbpg = NULL; - struct zbud_hdr *zh0, *zh1; - zbpg = zcache_get_free_page(); - if (likely(zbpg != NULL)) { - INIT_LIST_HEAD(&zbpg->bud_list); - zh0 = &zbpg->buddy[0]; zh1 = &zbpg->buddy[1]; - spin_lock_init(&zbpg->lock); - atomic_inc(&zcache_zbud_curr_raw_pages); - INIT_LIST_HEAD(&zbpg->bud_list); - SET_SENTINEL(zbpg, ZBPG); - zh0->size = 0; zh1->size = 0; - tmem_oid_set_invalid(&zh0->oid); - tmem_oid_set_invalid(&zh1->oid); - } - return zbpg; } +#endif -static void zbud_free_raw_page(struct zbud_page *zbpg) -{ - struct zbud_hdr *zh0 = &zbpg->buddy[0], *zh1 = &zbpg->buddy[1]; +static int zcache_enabled __read_mostly; +static int disable_cleancache __read_mostly; +static int disable_frontswap __read_mostly; +static int disable_frontswap_ignore_nonactive __read_mostly; +static int disable_cleancache_ignore_nonactive __read_mostly; +static char *namestr __read_mostly = "zcache"; - ASSERT_SENTINEL(zbpg, ZBPG); - BUG_ON(!list_empty(&zbpg->bud_list)); - ASSERT_SPINLOCK(&zbpg->lock); - BUG_ON(zh0->size != 0 || tmem_oid_valid(&zh0->oid)); - BUG_ON(zh1->size != 0 || tmem_oid_valid(&zh1->oid)); - INVERT_SENTINEL(zbpg, ZBPG); - spin_unlock(&zbpg->lock); - atomic_dec(&zcache_zbud_curr_raw_pages); - zcache_free_page(zbpg); -} +#define ZCACHE_GFP_MASK \ + (__GFP_FS | __GFP_NORETRY | __GFP_NOWARN | __GFP_NOMEMALLOC) -/* - * core zbud handling routines - */ +MODULE_LICENSE("GPL"); -static unsigned zbud_free(struct zbud_hdr *zh) -{ - unsigned size; - - ASSERT_SENTINEL(zh, ZBH); - BUG_ON(!tmem_oid_valid(&zh->oid)); - size = zh->size; - BUG_ON(zh->size == 0 || zh->size > zbud_max_buddy_size()); - zh->size = 0; - tmem_oid_set_invalid(&zh->oid); - INVERT_SENTINEL(zh, ZBH); - zcache_zbud_curr_zbytes -= size; - atomic_dec(&zcache_zbud_curr_zpages); - return size; -} - -static void zbud_free_and_delist(struct zbud_hdr *zh) -{ - unsigned chunks; - struct zbud_hdr *zh_other; - unsigned budnum = zbud_budnum(zh), size; - struct zbud_page *zbpg = - container_of(zh, struct zbud_page, buddy[budnum]); - - /* FIXME, should be BUG_ON, pool destruction path doesn't disable - * interrupts tmem_destroy_pool()->tmem_pampd_destroy_all_in_obj()-> - * tmem_objnode_node_destroy()-> zcache_pampd_free() */ - WARN_ON(!irqs_disabled()); - spin_lock(&zbpg->lock); - if (list_empty(&zbpg->bud_list)) { - /* ignore zombie page... see zbud_evict_pages() */ - spin_unlock(&zbpg->lock); - return; - } - size = zbud_free(zh); - ASSERT_SPINLOCK(&zbpg->lock); - zh_other = &zbpg->buddy[(budnum == 0) ? 1 : 0]; - if (zh_other->size == 0) { /* was unbuddied: unlist and free */ - chunks = zbud_size_to_chunks(size) ; - spin_lock(&zbud_budlists_spinlock); - BUG_ON(list_empty(&zbud_unbuddied[chunks].list)); - list_del_init(&zbpg->bud_list); - zbud_unbuddied[chunks].count--; - spin_unlock(&zbud_budlists_spinlock); - zbud_free_raw_page(zbpg); - } else { /* was buddied: move remaining buddy to unbuddied list */ - chunks = zbud_size_to_chunks(zh_other->size) ; - spin_lock(&zbud_budlists_spinlock); - list_del_init(&zbpg->bud_list); - zcache_zbud_buddied_count--; - list_add_tail(&zbpg->bud_list, &zbud_unbuddied[chunks].list); - zbud_unbuddied[chunks].count++; - spin_unlock(&zbud_budlists_spinlock); - spin_unlock(&zbpg->lock); - } -} +/* crypto API for zcache */ +#define ZCACHE_COMP_NAME_SZ CRYPTO_MAX_ALG_NAME +static char zcache_comp_name[ZCACHE_COMP_NAME_SZ] __read_mostly; +static struct crypto_comp * __percpu *zcache_comp_pcpu_tfms __read_mostly; -static struct zbud_hdr *zbud_create(uint16_t client_id, uint16_t pool_id, - struct tmem_oid *oid, - uint32_t index, struct page *page, - void *cdata, unsigned size) -{ - struct zbud_hdr *zh0, *zh1, *zh = NULL; - struct zbud_page *zbpg = NULL, *ztmp; - unsigned nchunks; - char *to; - int i, found_good_buddy = 0; - - nchunks = zbud_size_to_chunks(size) ; - for (i = MAX_CHUNK - nchunks + 1; i > 0; i--) { - spin_lock(&zbud_budlists_spinlock); - if (!list_empty(&zbud_unbuddied[i].list)) { - list_for_each_entry_safe(zbpg, ztmp, - &zbud_unbuddied[i].list, bud_list) { - if (spin_trylock(&zbpg->lock)) { - found_good_buddy = i; - goto found_unbuddied; - } - } - } - spin_unlock(&zbud_budlists_spinlock); - } - /* didn't find a good buddy, try allocating a new page */ - zbpg = zbud_alloc_raw_page(); - if (unlikely(zbpg == NULL)) - goto out; - /* ok, have a page, now compress the data before taking locks */ - spin_lock(&zbud_budlists_spinlock); - spin_lock(&zbpg->lock); - list_add_tail(&zbpg->bud_list, &zbud_unbuddied[nchunks].list); - zbud_unbuddied[nchunks].count++; - zh = &zbpg->buddy[0]; - goto init_zh; - -found_unbuddied: - ASSERT_SPINLOCK(&zbpg->lock); - zh0 = &zbpg->buddy[0]; zh1 = &zbpg->buddy[1]; - BUG_ON(!((zh0->size == 0) ^ (zh1->size == 0))); - if (zh0->size != 0) { /* buddy0 in use, buddy1 is vacant */ - ASSERT_SENTINEL(zh0, ZBH); - zh = zh1; - } else if (zh1->size != 0) { /* buddy1 in use, buddy0 is vacant */ - ASSERT_SENTINEL(zh1, ZBH); - zh = zh0; - } else - BUG(); - list_del_init(&zbpg->bud_list); - zbud_unbuddied[found_good_buddy].count--; - list_add_tail(&zbpg->bud_list, &zbud_buddied_list); - zcache_zbud_buddied_count++; - -init_zh: - SET_SENTINEL(zh, ZBH); - zh->size = size; - zh->index = index; - zh->oid = *oid; - zh->pool_id = pool_id; - zh->client_id = client_id; - to = zbud_data(zh, size); - memcpy(to, cdata, size); - spin_unlock(&zbpg->lock); - spin_unlock(&zbud_budlists_spinlock); - zbud_cumul_chunk_counts[nchunks]++; - atomic_inc(&zcache_zbud_curr_zpages); - zcache_zbud_cumul_zpages++; - zcache_zbud_curr_zbytes += size; - zcache_zbud_cumul_zbytes += size; -out: - return zh; -} +enum comp_op { + ZCACHE_COMPOP_COMPRESS, + ZCACHE_COMPOP_DECOMPRESS +}; -static int zbud_decompress(struct page *page, struct zbud_hdr *zh) +static inline int zcache_comp_op(enum comp_op op, + const u8 *src, unsigned int slen, + u8 *dst, unsigned int *dlen) { - struct zbud_page *zbpg; - unsigned budnum = zbud_budnum(zh); - size_t out_len = PAGE_SIZE; - char *to_va, *from_va; - unsigned size; - int ret = 0; + struct crypto_comp *tfm; + int ret = -1; - zbpg = container_of(zh, struct zbud_page, buddy[budnum]); - spin_lock(&zbpg->lock); - if (list_empty(&zbpg->bud_list)) { - /* ignore zombie page... see zbud_evict_pages() */ + BUG_ON(!zcache_comp_pcpu_tfms); + tfm = *per_cpu_ptr(zcache_comp_pcpu_tfms, get_cpu()); + BUG_ON(!tfm); + switch (op) { + case ZCACHE_COMPOP_COMPRESS: + ret = crypto_comp_compress(tfm, src, slen, dst, dlen); + break; + case ZCACHE_COMPOP_DECOMPRESS: + ret = crypto_comp_decompress(tfm, src, slen, dst, dlen); + break; + default: ret = -EINVAL; - goto out; } - ASSERT_SENTINEL(zh, ZBH); - BUG_ON(zh->size == 0 || zh->size > zbud_max_buddy_size()); - to_va = kmap_atomic(page); - size = zh->size; - from_va = zbud_data(zh, size); - ret = lzo1x_decompress_safe(from_va, size, to_va, &out_len); - BUG_ON(ret != LZO_E_OK); - BUG_ON(out_len != PAGE_SIZE); - kunmap_atomic(to_va); -out: - spin_unlock(&zbpg->lock); + put_cpu(); return ret; } /* - * The following routines handle shrinking of ephemeral pages by evicting - * pages "least valuable" first. - */ - -static unsigned long zcache_evicted_raw_pages; -static unsigned long zcache_evicted_buddied_pages; -static unsigned long zcache_evicted_unbuddied_pages; - -static struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id, - uint16_t poolid); -static void zcache_put_pool(struct tmem_pool *pool); - -/* - * Flush and free all zbuds in a zbpg, then free the pageframe - */ -static void zbud_evict_zbpg(struct zbud_page *zbpg) -{ - struct zbud_hdr *zh; - int i, j; - uint32_t pool_id[ZBUD_MAX_BUDS], client_id[ZBUD_MAX_BUDS]; - uint32_t index[ZBUD_MAX_BUDS]; - struct tmem_oid oid[ZBUD_MAX_BUDS]; - struct tmem_pool *pool; - unsigned long flags; - - ASSERT_SPINLOCK(&zbpg->lock); - for (i = 0, j = 0; i < ZBUD_MAX_BUDS; i++) { - zh = &zbpg->buddy[i]; - if (zh->size) { - client_id[j] = zh->client_id; - pool_id[j] = zh->pool_id; - oid[j] = zh->oid; - index[j] = zh->index; - j++; - } - } - spin_unlock(&zbpg->lock); - for (i = 0; i < j; i++) { - pool = zcache_get_pool_by_id(client_id[i], pool_id[i]); - BUG_ON(pool == NULL); - local_irq_save(flags); - /* these flushes should dispose of any local storage */ - tmem_flush_page(pool, &oid[i], index[i]); - local_irq_restore(flags); - zcache_put_pool(pool); - } -} - -/* - * Free nr pages. This code is funky because we want to hold the locks - * protecting various lists for as short a time as possible, and in some - * circumstances the list may change asynchronously when the list lock is - * not held. In some cases we also trylock not only to avoid waiting on a - * page in use by another cpu, but also to avoid potential deadlock due to - * lock inversion. - */ -static void zbud_evict_pages(int nr) -{ - struct zbud_page *zbpg; - int i, newly_unused_pages = 0; - - - /* now try freeing unbuddied pages, starting with least space avail */ - for (i = 0; i < MAX_CHUNK; i++) { -retry_unbud_list_i: - spin_lock_bh(&zbud_budlists_spinlock); - if (list_empty(&zbud_unbuddied[i].list)) { - spin_unlock_bh(&zbud_budlists_spinlock); - continue; - } - list_for_each_entry(zbpg, &zbud_unbuddied[i].list, bud_list) { - if (unlikely(!spin_trylock(&zbpg->lock))) - continue; - zbud_unbuddied[i].count--; - spin_unlock(&zbud_budlists_spinlock); - zcache_evicted_unbuddied_pages++; - /* want budlists unlocked when doing zbpg eviction */ - zbud_evict_zbpg(zbpg); - newly_unused_pages++; - local_bh_enable(); - if (--nr <= 0) - goto evict_unused; - goto retry_unbud_list_i; - } - spin_unlock_bh(&zbud_budlists_spinlock); - } - - /* as a last resort, free buddied pages */ -retry_bud_list: - spin_lock_bh(&zbud_budlists_spinlock); - if (list_empty(&zbud_buddied_list)) { - spin_unlock_bh(&zbud_budlists_spinlock); - goto evict_unused; - } - list_for_each_entry(zbpg, &zbud_buddied_list, bud_list) { - if (unlikely(!spin_trylock(&zbpg->lock))) - continue; - zcache_zbud_buddied_count--; - spin_unlock(&zbud_budlists_spinlock); - zcache_evicted_buddied_pages++; - /* want budlists unlocked when doing zbpg eviction */ - zbud_evict_zbpg(zbpg); - newly_unused_pages++; - local_bh_enable(); - if (--nr <= 0) - goto evict_unused; - goto retry_bud_list; - } - spin_unlock_bh(&zbud_budlists_spinlock); - -evict_unused: - return; -} - -static DEFINE_PER_CPU(unsigned char *, zcache_remoteputmem); - -static int zbud_remotify_zbud(struct tmem_xhandle *xh, char *data, - size_t size) -{ - struct tmem_pool *pool; - int i, remotenode, ret = -1; - unsigned char cksum, *p; - unsigned long flags; - - for (p = data, cksum = 0, i = 0; i < size; i++) - cksum += *p; - ret = ramster_remote_put(xh, data, size, true, &remotenode); - if (ret == 0) { - /* data was successfully remoted so change the local version - * to point to the remote node where it landed */ - pool = zcache_get_pool_by_id(LOCAL_CLIENT, xh->pool_id); - BUG_ON(pool == NULL); - local_irq_save(flags); - /* tmem_replace will also free up any local space */ - (void)tmem_replace(pool, &xh->oid, xh->index, - pampd_make_remote(remotenode, size, cksum)); - local_irq_restore(flags); - zcache_put_pool(pool); - ramster_eph_pages_remoted++; - ret = 0; - } else - ramster_eph_pages_remote_failed++; - return ret; -} - -static int zbud_remotify_zbpg(struct zbud_page *zbpg) -{ - struct zbud_hdr *zh1, *zh2 = NULL; - struct tmem_xhandle xh1, xh2 = { 0 }; - char *data1 = NULL, *data2 = NULL; - size_t size1 = 0, size2 = 0; - int ret = 0; - unsigned char *tmpmem = __get_cpu_var(zcache_remoteputmem); - - ASSERT_SPINLOCK(&zbpg->lock); - if (zbpg->buddy[0].size == 0) - zh1 = &zbpg->buddy[1]; - else if (zbpg->buddy[1].size == 0) - zh1 = &zbpg->buddy[0]; - else { - zh1 = &zbpg->buddy[0]; - zh2 = &zbpg->buddy[1]; - } - /* don't remotify pages that are already remotified */ - if (zh1->client_id != LOCAL_CLIENT) - zh1 = NULL; - if ((zh2 != NULL) && (zh2->client_id != LOCAL_CLIENT)) - zh2 = NULL; - - /* copy the data and metadata so can release lock */ - if (zh1 != NULL) { - xh1.client_id = zh1->client_id; - xh1.pool_id = zh1->pool_id; - xh1.oid = zh1->oid; - xh1.index = zh1->index; - size1 = zh1->size; - data1 = zbud_data(zh1, size1); - memcpy(tmpmem, zbud_data(zh1, size1), size1); - data1 = tmpmem; - tmpmem += size1; - } - if (zh2 != NULL) { - xh2.client_id = zh2->client_id; - xh2.pool_id = zh2->pool_id; - xh2.oid = zh2->oid; - xh2.index = zh2->index; - size2 = zh2->size; - memcpy(tmpmem, zbud_data(zh2, size2), size2); - data2 = tmpmem; - } - spin_unlock(&zbpg->lock); - preempt_enable(); - - /* OK, no locks held anymore, remotify one or both zbuds */ - if (zh1 != NULL) - ret = zbud_remotify_zbud(&xh1, data1, size1); - if (zh2 != NULL) - ret |= zbud_remotify_zbud(&xh2, data2, size2); - return ret; -} - -void zbud_remotify_pages(int nr) -{ - struct zbud_page *zbpg; - int i, ret; - - /* - * for now just try remotifying unbuddied pages, starting with - * least space avail - */ - for (i = 0; i < MAX_CHUNK; i++) { -retry_unbud_list_i: - preempt_disable(); /* enable in zbud_remotify_zbpg */ - spin_lock_bh(&zbud_budlists_spinlock); - if (list_empty(&zbud_unbuddied[i].list)) { - spin_unlock_bh(&zbud_budlists_spinlock); - preempt_enable(); - continue; /* next i in for loop */ - } - list_for_each_entry(zbpg, &zbud_unbuddied[i].list, bud_list) { - if (unlikely(!spin_trylock(&zbpg->lock))) - continue; /* next list_for_each_entry */ - zbud_unbuddied[i].count--; - /* want budlists unlocked when doing zbpg remotify */ - spin_unlock_bh(&zbud_budlists_spinlock); - ret = zbud_remotify_zbpg(zbpg); - /* preemption is re-enabled in zbud_remotify_zbpg */ - if (ret == 0) { - if (--nr <= 0) - goto out; - goto retry_unbud_list_i; - } - /* if fail to remotify any page, quit */ - pr_err("TESTING zbud_remotify_pages failed on page," - " trying to re-add\n"); - spin_lock_bh(&zbud_budlists_spinlock); - spin_lock(&zbpg->lock); - list_add_tail(&zbpg->bud_list, &zbud_unbuddied[i].list); - zbud_unbuddied[i].count++; - spin_unlock(&zbpg->lock); - spin_unlock_bh(&zbud_budlists_spinlock); - pr_err("TESTING zbud_remotify_pages failed on page," - " finished re-add\n"); - goto out; - } - spin_unlock_bh(&zbud_budlists_spinlock); - preempt_enable(); - } - -next_buddied_zbpg: - preempt_disable(); /* enable in zbud_remotify_zbpg */ - spin_lock_bh(&zbud_budlists_spinlock); - if (list_empty(&zbud_buddied_list)) - goto unlock_out; - list_for_each_entry(zbpg, &zbud_buddied_list, bud_list) { - if (unlikely(!spin_trylock(&zbpg->lock))) - continue; /* next list_for_each_entry */ - zcache_zbud_buddied_count--; - /* want budlists unlocked when doing zbpg remotify */ - spin_unlock_bh(&zbud_budlists_spinlock); - ret = zbud_remotify_zbpg(zbpg); - /* preemption is re-enabled in zbud_remotify_zbpg */ - if (ret == 0) { - if (--nr <= 0) - goto out; - goto next_buddied_zbpg; - } - /* if fail to remotify any page, quit */ - pr_err("TESTING zbud_remotify_pages failed on BUDDIED page," - " trying to re-add\n"); - spin_lock_bh(&zbud_budlists_spinlock); - spin_lock(&zbpg->lock); - list_add_tail(&zbpg->bud_list, &zbud_buddied_list); - zcache_zbud_buddied_count++; - spin_unlock(&zbpg->lock); - spin_unlock_bh(&zbud_budlists_spinlock); - pr_err("TESTING zbud_remotify_pages failed on BUDDIED page," - " finished re-add\n"); - goto out; - } -unlock_out: - spin_unlock_bh(&zbud_budlists_spinlock); - preempt_enable(); -out: - return; -} - -/* the "flush list" asynchronously collects pages to remotely flush */ -#define FLUSH_ENTIRE_OBJECT ((uint32_t)-1) -static void ramster_flnode_free(struct flushlist_node *, - struct tmem_pool *); - -static void zcache_remote_flush_page(struct flushlist_node *flnode) -{ - struct tmem_xhandle *xh; - int remotenode, ret; - - preempt_disable(); - xh = &flnode->xh; - remotenode = flnode->xh.client_id; - ret = ramster_remote_flush(xh, remotenode); - if (ret >= 0) - ramster_remote_pages_flushed++; - else - ramster_remote_page_flushes_failed++; - preempt_enable_no_resched(); - ramster_flnode_free(flnode, NULL); -} - -static void zcache_remote_flush_object(struct flushlist_node *flnode) -{ - struct tmem_xhandle *xh; - int remotenode, ret; - - preempt_disable(); - xh = &flnode->xh; - remotenode = flnode->xh.client_id; - ret = ramster_remote_flush_object(xh, remotenode); - if (ret >= 0) - ramster_remote_objects_flushed++; - else - ramster_remote_object_flushes_failed++; - preempt_enable_no_resched(); - ramster_flnode_free(flnode, NULL); -} - -static void zcache_remote_eph_put(struct zbud_hdr *zbud) -{ - /* FIXME */ -} - -static void zcache_remote_pers_put(struct zv_hdr *zv) -{ - struct tmem_xhandle xh; - uint16_t size; - bool ephemeral; - int remotenode, ret = -1; - char *data; - struct tmem_pool *pool; - unsigned long flags; - unsigned char cksum; - char *p; - int i; - unsigned char *tmpmem = __get_cpu_var(zcache_remoteputmem); - - ASSERT_SENTINEL(zv, ZVH); - BUG_ON(zv->client_id != LOCAL_CLIENT); - local_bh_disable(); - xh.client_id = zv->client_id; - xh.pool_id = zv->pool_id; - xh.oid = zv->oid; - xh.index = zv->index; - size = xv_get_object_size(zv) - sizeof(*zv); - BUG_ON(size == 0 || size > zv_max_page_size); - data = (char *)zv + sizeof(*zv); - for (p = data, cksum = 0, i = 0; i < size; i++) - cksum += *p; - memcpy(tmpmem, data, size); - data = tmpmem; - pool = zcache_get_pool_by_id(zv->client_id, zv->pool_id); - ephemeral = is_ephemeral(pool); - zcache_put_pool(pool); - /* now OK to release lock set in caller */ - spin_unlock(&zcache_rem_op_list_lock); - local_bh_enable(); - preempt_disable(); - ret = ramster_remote_put(&xh, data, size, ephemeral, &remotenode); - preempt_enable_no_resched(); - if (ret != 0) { - /* - * This is some form of a memory leak... if the remote put - * fails, there will never be another attempt to remotify - * this page. But since we've dropped the zv pointer, - * the page may have been freed or the data replaced - * so we can't just "put it back" in the remote op list. - * Even if we could, not sure where to put it in the list - * because there may be flushes that must be strictly - * ordered vs the put. So leave this as a FIXME for now. - * But count them so we know if it becomes a problem. - */ - ramster_pers_pages_remote_failed++; - goto out; - } else - atomic_inc(&ramster_remote_pers_pages); - ramster_pers_pages_remoted++; - /* - * data was successfully remoted so change the local version to - * point to the remote node where it landed - */ - local_bh_disable(); - pool = zcache_get_pool_by_id(LOCAL_CLIENT, xh.pool_id); - local_irq_save(flags); - (void)tmem_replace(pool, &xh.oid, xh.index, - pampd_make_remote(remotenode, size, cksum)); - local_irq_restore(flags); - zcache_put_pool(pool); - local_bh_enable(); -out: - return; -} - -static void zcache_do_remotify_ops(int nr) -{ - struct ramster_remotify_hdr *rem_op; - union remotify_list_node *u; - - while (1) { - if (!nr) - goto out; - spin_lock(&zcache_rem_op_list_lock); - if (list_empty(&zcache_rem_op_list)) { - spin_unlock(&zcache_rem_op_list_lock); - goto out; - } - rem_op = list_first_entry(&zcache_rem_op_list, - struct ramster_remotify_hdr, list); - list_del_init(&rem_op->list); - if (rem_op->op != RAMSTER_REMOTIFY_PERS_PUT) - spin_unlock(&zcache_rem_op_list_lock); - u = (union remotify_list_node *)rem_op; - switch (rem_op->op) { - case RAMSTER_REMOTIFY_EPH_PUT: -BUG(); - zcache_remote_eph_put((struct zbud_hdr *)rem_op); - break; - case RAMSTER_REMOTIFY_PERS_PUT: - zcache_remote_pers_put((struct zv_hdr *)rem_op); - break; - case RAMSTER_REMOTIFY_FLUSH_PAGE: - zcache_remote_flush_page((struct flushlist_node *)u); - break; - case RAMSTER_REMOTIFY_FLUSH_OBJ: - zcache_remote_flush_object((struct flushlist_node *)u); - break; - default: - BUG(); - } - } -out: - return; -} - -/* - * Communicate interface revision with userspace - */ -#include "cluster/ramster_nodemanager.h" -static unsigned long ramster_interface_revision = R2NM_API_VERSION; - -/* - * For now, just push over a few pages every few seconds to - * ensure that it basically works - */ -static struct workqueue_struct *ramster_remotify_workqueue; -static void ramster_remotify_process(struct work_struct *work); -static DECLARE_DELAYED_WORK(ramster_remotify_worker, - ramster_remotify_process); - -static void ramster_remotify_queue_delayed_work(unsigned long delay) -{ - if (!queue_delayed_work(ramster_remotify_workqueue, - &ramster_remotify_worker, delay)) - pr_err("ramster_remotify: bad workqueue\n"); -} - - -static int use_frontswap; -static int use_cleancache; -static int ramster_remote_target_nodenum = -1; -static void ramster_remotify_process(struct work_struct *work) -{ - static bool remotify_in_progress; - - BUG_ON(irqs_disabled()); - if (remotify_in_progress) - ramster_remotify_queue_delayed_work(HZ); - else if (ramster_remote_target_nodenum != -1) { - remotify_in_progress = true; -#ifdef CONFIG_CLEANCACHE - if (use_cleancache && ramster_eph_remotify_enable) - zbud_remotify_pages(5000); /* FIXME is this a good number? */ -#endif -#ifdef CONFIG_FRONTSWAP - if (use_frontswap && ramster_pers_remotify_enable) - zcache_do_remotify_ops(500); /* FIXME is this a good number? */ -#endif - remotify_in_progress = false; - ramster_remotify_queue_delayed_work(HZ); - } -} - -static void ramster_remotify_init(void) -{ - unsigned long n = 60UL; - ramster_remotify_workqueue = - create_singlethread_workqueue("ramster_remotify"); - ramster_remotify_queue_delayed_work(n * HZ); -} - - -static void zbud_init(void) -{ - int i; - - INIT_LIST_HEAD(&zbud_buddied_list); - zcache_zbud_buddied_count = 0; - for (i = 0; i < NCHUNKS; i++) { - INIT_LIST_HEAD(&zbud_unbuddied[i].list); - zbud_unbuddied[i].count = 0; - } -} - -#ifdef CONFIG_SYSFS -/* - * These sysfs routines show a nice distribution of how many zbpg's are - * currently (and have ever been placed) in each unbuddied list. It's fun - * to watch but can probably go away before final merge. + * policy parameters */ -static int zbud_show_unbuddied_list_counts(char *buf) -{ - int i; - char *p = buf; - - for (i = 0; i < NCHUNKS; i++) - p += sprintf(p, "%u ", zbud_unbuddied[i].count); - return p - buf; -} - -static int zbud_show_cumul_chunk_counts(char *buf) -{ - unsigned long i, chunks = 0, total_chunks = 0, sum_total_chunks = 0; - unsigned long total_chunks_lte_21 = 0, total_chunks_lte_32 = 0; - unsigned long total_chunks_lte_42 = 0; - char *p = buf; - - for (i = 0; i < NCHUNKS; i++) { - p += sprintf(p, "%lu ", zbud_cumul_chunk_counts[i]); - chunks += zbud_cumul_chunk_counts[i]; - total_chunks += zbud_cumul_chunk_counts[i]; - sum_total_chunks += i * zbud_cumul_chunk_counts[i]; - if (i == 21) - total_chunks_lte_21 = total_chunks; - if (i == 32) - total_chunks_lte_32 = total_chunks; - if (i == 42) - total_chunks_lte_42 = total_chunks; - } - p += sprintf(p, "<=21:%lu <=32:%lu <=42:%lu, mean:%lu\n", - total_chunks_lte_21, total_chunks_lte_32, total_chunks_lte_42, - chunks == 0 ? 0 : sum_total_chunks / chunks); - return p - buf; -} -#endif -/********** - * This "zv" PAM implementation combines the TLSF-based xvMalloc - * with lzo1x compression to maximize the amount of data that can - * be packed into a physical page. - * - * Zv represents a PAM page with the index and object (plus a "size" value - * necessary for decompression) immediately preceding the compressed data. - */ - -/* rudimentary policy limits */ -/* total number of persistent pages may not exceed this percentage */ -static unsigned int zv_page_count_policy_percent = 75; /* * byte count defining poor compression; pages with greater zsize will be * rejected */ -static unsigned int zv_max_zsize = (PAGE_SIZE / 8) * 7; +static unsigned int zbud_max_zsize __read_mostly = (PAGE_SIZE / 8) * 7; /* * byte count defining poor *mean* compression; pages with greater zsize * will be rejected until sufficient better-compressed pages are accepted * driving the mean below this threshold */ -static unsigned int zv_max_mean_zsize = (PAGE_SIZE / 8) * 5; - -static atomic_t zv_curr_dist_counts[NCHUNKS]; -static atomic_t zv_cumul_dist_counts[NCHUNKS]; +static unsigned int zbud_max_mean_zsize __read_mostly = (PAGE_SIZE / 8) * 5; - -static struct zv_hdr *zv_create(struct zcache_client *cli, uint32_t pool_id, - struct tmem_oid *oid, uint32_t index, - void *cdata, unsigned clen) -{ - struct page *page; - struct zv_hdr *zv = NULL; - uint32_t offset; - int alloc_size = clen + sizeof(struct zv_hdr); - int chunks = (alloc_size + (CHUNK_SIZE - 1)) >> CHUNK_SHIFT; - int ret; - - BUG_ON(!irqs_disabled()); - BUG_ON(chunks >= NCHUNKS); - ret = xv_malloc(cli->xvpool, clen + sizeof(struct zv_hdr), - &page, &offset, ZCACHE_GFP_MASK); - if (unlikely(ret)) - goto out; - atomic_inc(&zv_curr_dist_counts[chunks]); - atomic_inc(&zv_cumul_dist_counts[chunks]); - zv = kmap_atomic(page) + offset; - zv->index = index; - zv->oid = *oid; - zv->pool_id = pool_id; - SET_SENTINEL(zv, ZVH); - INIT_LIST_HEAD(&zv->rem_op.list); - zv->client_id = get_client_id_from_client(cli); - zv->rem_op.op = RAMSTER_REMOTIFY_PERS_PUT; - if (zv->client_id == LOCAL_CLIENT) { - spin_lock(&zcache_rem_op_list_lock); - list_add_tail(&zv->rem_op.list, &zcache_rem_op_list); - spin_unlock(&zcache_rem_op_list_lock); - } - memcpy((char *)zv + sizeof(struct zv_hdr), cdata, clen); - kunmap_atomic(zv); -out: - return zv; -} - -/* similar to zv_create, but just reserve space, no data yet */ -static struct zv_hdr *zv_alloc(struct tmem_pool *pool, - struct tmem_oid *oid, uint32_t index, - unsigned clen) -{ - struct zcache_client *cli = pool->client; - struct page *page; - struct zv_hdr *zv = NULL; - uint32_t offset; - int ret; - - BUG_ON(!irqs_disabled()); - BUG_ON(!is_local_client(pool->client)); - ret = xv_malloc(cli->xvpool, clen + sizeof(struct zv_hdr), - &page, &offset, ZCACHE_GFP_MASK); - if (unlikely(ret)) - goto out; - zv = kmap_atomic(page) + offset; - SET_SENTINEL(zv, ZVH); - INIT_LIST_HEAD(&zv->rem_op.list); - zv->client_id = LOCAL_CLIENT; - zv->rem_op.op = RAMSTER_INTRANSIT_PERS; - zv->index = index; - zv->oid = *oid; - zv->pool_id = pool->pool_id; - kunmap_atomic(zv); -out: - return zv; -} - -static void zv_free(struct xv_pool *xvpool, struct zv_hdr *zv) -{ - unsigned long flags; - struct page *page; - uint32_t offset; - uint16_t size = xv_get_object_size(zv); - int chunks = (size + (CHUNK_SIZE - 1)) >> CHUNK_SHIFT; - - ASSERT_SENTINEL(zv, ZVH); - BUG_ON(chunks >= NCHUNKS); - atomic_dec(&zv_curr_dist_counts[chunks]); - size -= sizeof(*zv); - spin_lock(&zcache_rem_op_list_lock); - size = xv_get_object_size(zv) - sizeof(*zv); - BUG_ON(size == 0); - INVERT_SENTINEL(zv, ZVH); - if (!list_empty(&zv->rem_op.list)) - list_del_init(&zv->rem_op.list); - spin_unlock(&zcache_rem_op_list_lock); - page = virt_to_page(zv); - offset = (unsigned long)zv & ~PAGE_MASK; - local_irq_save(flags); - xv_free(xvpool, page, offset); - local_irq_restore(flags); -} - -static void zv_decompress(struct page *page, struct zv_hdr *zv) -{ - size_t clen = PAGE_SIZE; - char *to_va; - unsigned size; - int ret; - - ASSERT_SENTINEL(zv, ZVH); - size = xv_get_object_size(zv) - sizeof(*zv); - BUG_ON(size == 0); - to_va = kmap_atomic(page); - ret = lzo1x_decompress_safe((char *)zv + sizeof(*zv), - size, to_va, &clen); - kunmap_atomic(to_va); - BUG_ON(ret != LZO_E_OK); - BUG_ON(clen != PAGE_SIZE); -} - -static void zv_copy_from_pampd(char *data, size_t *bufsize, struct zv_hdr *zv) -{ - unsigned size; - - ASSERT_SENTINEL(zv, ZVH); - size = xv_get_object_size(zv) - sizeof(*zv); - BUG_ON(size == 0 || size > zv_max_page_size); - BUG_ON(size > *bufsize); - memcpy(data, (char *)zv + sizeof(*zv), size); - *bufsize = size; -} - -static void zv_copy_to_pampd(struct zv_hdr *zv, char *data, size_t size) -{ - unsigned zv_size; - - ASSERT_SENTINEL(zv, ZVH); - zv_size = xv_get_object_size(zv) - sizeof(*zv); - BUG_ON(zv_size != size); - BUG_ON(zv_size == 0 || zv_size > zv_max_page_size); - memcpy((char *)zv + sizeof(*zv), data, size); -} - -#ifdef CONFIG_SYSFS /* - * show a distribution of compression stats for zv pages. + * for now, used named slabs so can easily track usage; later can + * either just use kmalloc, or perhaps add a slab-like allocator + * to more carefully manage total memory utilization */ +static struct kmem_cache *zcache_objnode_cache; +static struct kmem_cache *zcache_obj_cache; -static int zv_curr_dist_counts_show(char *buf) -{ - unsigned long i, n, chunks = 0, sum_total_chunks = 0; - char *p = buf; - - for (i = 0; i < NCHUNKS; i++) { - n = atomic_read(&zv_curr_dist_counts[i]); - p += sprintf(p, "%lu ", n); - chunks += n; - sum_total_chunks += i * n; - } - p += sprintf(p, "mean:%lu\n", - chunks == 0 ? 0 : sum_total_chunks / chunks); - return p - buf; -} - -static int zv_cumul_dist_counts_show(char *buf) -{ - unsigned long i, n, chunks = 0, sum_total_chunks = 0; - char *p = buf; - - for (i = 0; i < NCHUNKS; i++) { - n = atomic_read(&zv_cumul_dist_counts[i]); - p += sprintf(p, "%lu ", n); - chunks += n; - sum_total_chunks += i * n; - } - p += sprintf(p, "mean:%lu\n", - chunks == 0 ? 0 : sum_total_chunks / chunks); - return p - buf; -} +static DEFINE_PER_CPU(struct zcache_preload, zcache_preloads) = { 0, }; -/* - * setting zv_max_zsize via sysfs causes all persistent (e.g. swap) - * pages that don't compress to less than this value (including metadata - * overhead) to be rejected. We don't allow the value to get too close - * to PAGE_SIZE. - */ -static ssize_t zv_max_zsize_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - return sprintf(buf, "%u\n", zv_max_zsize); +/* we try to keep these statistics SMP-consistent */ +static long zcache_obj_count; +static atomic_t zcache_obj_atomic = ATOMIC_INIT(0); +static long zcache_obj_count_max; +static long zcache_objnode_count; +static atomic_t zcache_objnode_atomic = ATOMIC_INIT(0); +static long zcache_objnode_count_max; +static u64 zcache_eph_zbytes; +static atomic_long_t zcache_eph_zbytes_atomic = ATOMIC_INIT(0); +static u64 zcache_eph_zbytes_max; +static u64 zcache_pers_zbytes; +static atomic_long_t zcache_pers_zbytes_atomic = ATOMIC_INIT(0); +static u64 zcache_pers_zbytes_max; +static long zcache_eph_pageframes; +static atomic_t zcache_eph_pageframes_atomic = ATOMIC_INIT(0); +static long zcache_eph_pageframes_max; +static long zcache_pers_pageframes; +static atomic_t zcache_pers_pageframes_atomic = ATOMIC_INIT(0); +static long zcache_pers_pageframes_max; +static long zcache_pageframes_alloced; +static atomic_t zcache_pageframes_alloced_atomic = ATOMIC_INIT(0); +static long zcache_pageframes_freed; +static atomic_t zcache_pageframes_freed_atomic = ATOMIC_INIT(0); +static long zcache_eph_zpages; +static atomic_t zcache_eph_zpages_atomic = ATOMIC_INIT(0); +static long zcache_eph_zpages_max; +static long zcache_pers_zpages; +static atomic_t zcache_pers_zpages_atomic = ATOMIC_INIT(0); +static long zcache_pers_zpages_max; + +/* but for the rest of these, counting races are ok */ +static unsigned long zcache_flush_total; +static unsigned long zcache_flush_found; +static unsigned long zcache_flobj_total; +static unsigned long zcache_flobj_found; +static unsigned long zcache_failed_eph_puts; +static unsigned long zcache_failed_pers_puts; +static unsigned long zcache_failed_getfreepages; +static unsigned long zcache_failed_alloc; +static unsigned long zcache_put_to_flush; +static unsigned long zcache_compress_poor; +static unsigned long zcache_mean_compress_poor; +static unsigned long zcache_eph_ate_tail; +static unsigned long zcache_eph_ate_tail_failed; +static unsigned long zcache_pers_ate_eph; +static unsigned long zcache_pers_ate_eph_failed; +static unsigned long zcache_evicted_eph_zpages; +static unsigned long zcache_evicted_eph_pageframes; +static unsigned long zcache_last_active_file_pageframes; +static unsigned long zcache_last_inactive_file_pageframes; +static unsigned long zcache_last_active_anon_pageframes; +static unsigned long zcache_last_inactive_anon_pageframes; +static unsigned long zcache_eph_nonactive_puts_ignored; +static unsigned long zcache_pers_nonactive_puts_ignored; + +#ifdef CONFIG_DEBUG_FS +#include <linux/debugfs.h> +#define zdfs debugfs_create_size_t +#define zdfs64 debugfs_create_u64 +static int zcache_debugfs_init(void) +{ + struct dentry *root = debugfs_create_dir("zcache", NULL); + if (root == NULL) + return -ENXIO; + + zdfs("obj_count", S_IRUGO, root, &zcache_obj_count); + zdfs("obj_count_max", S_IRUGO, root, &zcache_obj_count_max); + zdfs("objnode_count", S_IRUGO, root, &zcache_objnode_count); + zdfs("objnode_count_max", S_IRUGO, root, &zcache_objnode_count_max); + zdfs("flush_total", S_IRUGO, root, &zcache_flush_total); + zdfs("flush_found", S_IRUGO, root, &zcache_flush_found); + zdfs("flobj_total", S_IRUGO, root, &zcache_flobj_total); + zdfs("flobj_found", S_IRUGO, root, &zcache_flobj_found); + zdfs("failed_eph_puts", S_IRUGO, root, &zcache_failed_eph_puts); + zdfs("failed_pers_puts", S_IRUGO, root, &zcache_failed_pers_puts); + zdfs("failed_get_free_pages", S_IRUGO, root, + &zcache_failed_getfreepages); + zdfs("failed_alloc", S_IRUGO, root, &zcache_failed_alloc); + zdfs("put_to_flush", S_IRUGO, root, &zcache_put_to_flush); + zdfs("compress_poor", S_IRUGO, root, &zcache_compress_poor); + zdfs("mean_compress_poor", S_IRUGO, root, &zcache_mean_compress_poor); + zdfs("eph_ate_tail", S_IRUGO, root, &zcache_eph_ate_tail); + zdfs("eph_ate_tail_failed", S_IRUGO, root, &zcache_eph_ate_tail_failed); + zdfs("pers_ate_eph", S_IRUGO, root, &zcache_pers_ate_eph); + zdfs("pers_ate_eph_failed", S_IRUGO, root, &zcache_pers_ate_eph_failed); + zdfs("evicted_eph_zpages", S_IRUGO, root, &zcache_evicted_eph_zpages); + zdfs("evicted_eph_pageframes", S_IRUGO, root, + &zcache_evicted_eph_pageframes); + zdfs("eph_pageframes", S_IRUGO, root, &zcache_eph_pageframes); + zdfs("eph_pageframes_max", S_IRUGO, root, &zcache_eph_pageframes_max); + zdfs("pers_pageframes", S_IRUGO, root, &zcache_pers_pageframes); + zdfs("pers_pageframes_max", S_IRUGO, root, &zcache_pers_pageframes_max); + zdfs("eph_zpages", S_IRUGO, root, &zcache_eph_zpages); + zdfs("eph_zpages_max", S_IRUGO, root, &zcache_eph_zpages_max); + zdfs("pers_zpages", S_IRUGO, root, &zcache_pers_zpages); + zdfs("pers_zpages_max", S_IRUGO, root, &zcache_pers_zpages_max); + zdfs("last_active_file_pageframes", S_IRUGO, root, + &zcache_last_active_file_pageframes); + zdfs("last_inactive_file_pageframes", S_IRUGO, root, + &zcache_last_inactive_file_pageframes); + zdfs("last_active_anon_pageframes", S_IRUGO, root, + &zcache_last_active_anon_pageframes); + zdfs("last_inactive_anon_pageframes", S_IRUGO, root, + &zcache_last_inactive_anon_pageframes); + zdfs("eph_nonactive_puts_ignored", S_IRUGO, root, + &zcache_eph_nonactive_puts_ignored); + zdfs("pers_nonactive_puts_ignored", S_IRUGO, root, + &zcache_pers_nonactive_puts_ignored); + zdfs64("eph_zbytes", S_IRUGO, root, &zcache_eph_zbytes); + zdfs64("eph_zbytes_max", S_IRUGO, root, &zcache_eph_zbytes_max); + zdfs64("pers_zbytes", S_IRUGO, root, &zcache_pers_zbytes); + zdfs64("pers_zbytes_max", S_IRUGO, root, &zcache_pers_zbytes_max); + return 0; } +#undef zdebugfs +#undef zdfs64 +#endif -static ssize_t zv_max_zsize_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) -{ - unsigned long val; - int err; - - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - err = kstrtoul(buf, 10, &val); - if (err || (val == 0) || (val > (PAGE_SIZE / 8) * 7)) - return -EINVAL; - zv_max_zsize = val; - return count; +#define ZCACHE_DEBUG +#ifdef ZCACHE_DEBUG +/* developers can call this in case of ooms, e.g. to find memory leaks */ +void zcache_dump(void) +{ + pr_info("zcache: obj_count=%lu\n", zcache_obj_count); + pr_info("zcache: obj_count_max=%lu\n", zcache_obj_count_max); + pr_info("zcache: objnode_count=%lu\n", zcache_objnode_count); + pr_info("zcache: objnode_count_max=%lu\n", zcache_objnode_count_max); + pr_info("zcache: flush_total=%lu\n", zcache_flush_total); + pr_info("zcache: flush_found=%lu\n", zcache_flush_found); + pr_info("zcache: flobj_total=%lu\n", zcache_flobj_total); + pr_info("zcache: flobj_found=%lu\n", zcache_flobj_found); + pr_info("zcache: failed_eph_puts=%lu\n", zcache_failed_eph_puts); + pr_info("zcache: failed_pers_puts=%lu\n", zcache_failed_pers_puts); + pr_info("zcache: failed_get_free_pages=%lu\n", + zcache_failed_getfreepages); + pr_info("zcache: failed_alloc=%lu\n", zcache_failed_alloc); + pr_info("zcache: put_to_flush=%lu\n", zcache_put_to_flush); + pr_info("zcache: compress_poor=%lu\n", zcache_compress_poor); + pr_info("zcache: mean_compress_poor=%lu\n", + zcache_mean_compress_poor); + pr_info("zcache: eph_ate_tail=%lu\n", zcache_eph_ate_tail); + pr_info("zcache: eph_ate_tail_failed=%lu\n", + zcache_eph_ate_tail_failed); + pr_info("zcache: pers_ate_eph=%lu\n", zcache_pers_ate_eph); + pr_info("zcache: pers_ate_eph_failed=%lu\n", + zcache_pers_ate_eph_failed); + pr_info("zcache: evicted_eph_zpages=%lu\n", zcache_evicted_eph_zpages); + pr_info("zcache: evicted_eph_pageframes=%lu\n", + zcache_evicted_eph_pageframes); + pr_info("zcache: eph_pageframes=%lu\n", zcache_eph_pageframes); + pr_info("zcache: eph_pageframes_max=%lu\n", zcache_eph_pageframes_max); + pr_info("zcache: pers_pageframes=%lu\n", zcache_pers_pageframes); + pr_info("zcache: pers_pageframes_max=%lu\n", + zcache_pers_pageframes_max); + pr_info("zcache: eph_zpages=%lu\n", zcache_eph_zpages); + pr_info("zcache: eph_zpages_max=%lu\n", zcache_eph_zpages_max); + pr_info("zcache: pers_zpages=%lu\n", zcache_pers_zpages); + pr_info("zcache: pers_zpages_max=%lu\n", zcache_pers_zpages_max); + pr_info("zcache: eph_zbytes=%llu\n", + (unsigned long long)zcache_eph_zbytes); + pr_info("zcache: eph_zbytes_max=%llu\n", + (unsigned long long)zcache_eph_zbytes_max); + pr_info("zcache: pers_zbytes=%llu\n", + (unsigned long long)zcache_pers_zbytes); + pr_info("zcache: pers_zbytes_max=%llu\n", + (unsigned long long)zcache_pers_zbytes_max); } +#endif /* - * setting zv_max_mean_zsize via sysfs causes all persistent (e.g. swap) - * pages that don't compress to less than this value (including metadata - * overhead) to be rejected UNLESS the mean compression is also smaller - * than this value. In other words, we are load-balancing-by-zsize the - * accepted pages. Again, we don't allow the value to get too close - * to PAGE_SIZE. + * zcache core code starts here */ -static ssize_t zv_max_mean_zsize_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) -{ - return sprintf(buf, "%u\n", zv_max_mean_zsize); -} - -static ssize_t zv_max_mean_zsize_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) -{ - unsigned long val; - int err; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - err = kstrtoul(buf, 10, &val); - if (err || (val == 0) || (val > (PAGE_SIZE / 8) * 7)) - return -EINVAL; - zv_max_mean_zsize = val; - return count; -} +static struct zcache_client zcache_host; +static struct zcache_client zcache_clients[MAX_CLIENTS]; -/* - * setting zv_page_count_policy_percent via sysfs sets an upper bound of - * persistent (e.g. swap) pages that will be retained according to: - * (zv_page_count_policy_percent * totalram_pages) / 100) - * when that limit is reached, further puts will be rejected (until - * some pages have been flushed). Note that, due to compression, - * this number may exceed 100; it defaults to 75 and we set an - * arbitrary limit of 150. A poor choice will almost certainly result - * in OOM's, so this value should only be changed prudently. - */ -static ssize_t zv_page_count_policy_percent_show(struct kobject *kobj, - struct kobj_attribute *attr, - char *buf) +static inline bool is_local_client(struct zcache_client *cli) { - return sprintf(buf, "%u\n", zv_page_count_policy_percent); + return cli == &zcache_host; } -static ssize_t zv_page_count_policy_percent_store(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count) +static struct zcache_client *zcache_get_client_by_id(uint16_t cli_id) { - unsigned long val; - int err; + struct zcache_client *cli = &zcache_host; - if (!capable(CAP_SYS_ADMIN)) - return -EPERM; - - err = kstrtoul(buf, 10, &val); - if (err || (val == 0) || (val > 150)) - return -EINVAL; - zv_page_count_policy_percent = val; - return count; + if (cli_id != LOCAL_CLIENT) { + if (cli_id >= MAX_CLIENTS) + goto out; + cli = &zcache_clients[cli_id]; + } +out: + return cli; } -static struct kobj_attribute zcache_zv_max_zsize_attr = { - .attr = { .name = "zv_max_zsize", .mode = 0644 }, - .show = zv_max_zsize_show, - .store = zv_max_zsize_store, -}; - -static struct kobj_attribute zcache_zv_max_mean_zsize_attr = { - .attr = { .name = "zv_max_mean_zsize", .mode = 0644 }, - .show = zv_max_mean_zsize_show, - .store = zv_max_mean_zsize_store, -}; - -static struct kobj_attribute zcache_zv_page_count_policy_percent_attr = { - .attr = { .name = "zv_page_count_policy_percent", - .mode = 0644 }, - .show = zv_page_count_policy_percent_show, - .store = zv_page_count_policy_percent_store, -}; -#endif - -/* - * zcache core code starts here - */ - -/* useful stats not collected by cleancache or frontswap */ -static unsigned long zcache_flush_total; -static unsigned long zcache_flush_found; -static unsigned long zcache_flobj_total; -static unsigned long zcache_flobj_found; -static unsigned long zcache_failed_eph_puts; -static unsigned long zcache_nonactive_puts; -static unsigned long zcache_failed_pers_puts; - /* * Tmem operations assume the poolid implies the invoking client. * Zcache only has one client (the kernel itself): LOCAL_CLIENT. @@ -1398,21 +328,16 @@ static unsigned long zcache_failed_pers_puts; * of zcache would have one client per guest and each client might * have a poolid==N. */ -static struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id, uint16_t poolid) +struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id, uint16_t poolid) { struct tmem_pool *pool = NULL; struct zcache_client *cli = NULL; - if (cli_id == LOCAL_CLIENT) - cli = &zcache_host; - else { - if (cli_id >= MAX_CLIENTS) - goto out; - cli = &zcache_clients[cli_id]; - if (cli == NULL) - goto out; + cli = zcache_get_client_by_id(cli_id); + if (cli == NULL) + goto out; + if (!is_local_client(cli)) atomic_inc(&cli->refcount); - } if (poolid < MAX_POOLS_PER_CLIENT) { pool = cli->tmem_pools[poolid]; if (pool != NULL) @@ -1422,7 +347,7 @@ out: return pool; } -static void zcache_put_pool(struct tmem_pool *pool) +void zcache_put_pool(struct tmem_pool *pool) { struct zcache_client *cli = NULL; @@ -1430,173 +355,26 @@ static void zcache_put_pool(struct tmem_pool *pool) BUG(); cli = pool->client; atomic_dec(&pool->refcount); - atomic_dec(&cli->refcount); + if (!is_local_client(cli)) + atomic_dec(&cli->refcount); } int zcache_new_client(uint16_t cli_id) { - struct zcache_client *cli = NULL; + struct zcache_client *cli; int ret = -1; - if (cli_id == LOCAL_CLIENT) - cli = &zcache_host; - else if ((unsigned int)cli_id < MAX_CLIENTS) - cli = &zcache_clients[cli_id]; + cli = zcache_get_client_by_id(cli_id); if (cli == NULL) goto out; if (cli->allocated) goto out; cli->allocated = 1; -#ifdef CONFIG_FRONTSWAP - cli->xvpool = xv_create_pool(); - if (cli->xvpool == NULL) - goto out; -#endif - ret = 0; -out: - return ret; -} - -/* counters for debugging */ -static unsigned long zcache_failed_get_free_pages; -static unsigned long zcache_failed_alloc; -static unsigned long zcache_put_to_flush; - -/* - * for now, used named slabs so can easily track usage; later can - * either just use kmalloc, or perhaps add a slab-like allocator - * to more carefully manage total memory utilization - */ -static struct kmem_cache *zcache_objnode_cache; -static struct kmem_cache *zcache_obj_cache; -static struct kmem_cache *ramster_flnode_cache; -static atomic_t zcache_curr_obj_count = ATOMIC_INIT(0); -static unsigned long zcache_curr_obj_count_max; -static atomic_t zcache_curr_objnode_count = ATOMIC_INIT(0); -static unsigned long zcache_curr_objnode_count_max; - -/* - * to avoid memory allocation recursion (e.g. due to direct reclaim), we - * preload all necessary data structures so the hostops callbacks never - * actually do a malloc - */ -struct zcache_preload { - void *page; - struct tmem_obj *obj; - int nr; - struct tmem_objnode *objnodes[OBJNODE_TREE_MAX_PATH]; - struct flushlist_node *flnode; -}; -static DEFINE_PER_CPU(struct zcache_preload, zcache_preloads) = { 0, }; - -static int zcache_do_preload(struct tmem_pool *pool) -{ - struct zcache_preload *kp; - struct tmem_objnode *objnode; - struct tmem_obj *obj; - struct flushlist_node *flnode; - void *page; - int ret = -ENOMEM; - - if (unlikely(zcache_objnode_cache == NULL)) - goto out; - if (unlikely(zcache_obj_cache == NULL)) - goto out; - preempt_disable(); - kp = &__get_cpu_var(zcache_preloads); - while (kp->nr < ARRAY_SIZE(kp->objnodes)) { - preempt_enable_no_resched(); - objnode = kmem_cache_alloc(zcache_objnode_cache, - ZCACHE_GFP_MASK); - if (unlikely(objnode == NULL)) { - zcache_failed_alloc++; - goto out; - } - preempt_disable(); - kp = &__get_cpu_var(zcache_preloads); - if (kp->nr < ARRAY_SIZE(kp->objnodes)) - kp->objnodes[kp->nr++] = objnode; - else - kmem_cache_free(zcache_objnode_cache, objnode); - } - preempt_enable_no_resched(); - obj = kmem_cache_alloc(zcache_obj_cache, ZCACHE_GFP_MASK); - if (unlikely(obj == NULL)) { - zcache_failed_alloc++; - goto out; - } - flnode = kmem_cache_alloc(ramster_flnode_cache, ZCACHE_GFP_MASK); - if (unlikely(flnode == NULL)) { - zcache_failed_alloc++; - goto out; - } - if (is_ephemeral(pool)) { - page = (void *)__get_free_page(ZCACHE_GFP_MASK); - if (unlikely(page == NULL)) { - zcache_failed_get_free_pages++; - kmem_cache_free(zcache_obj_cache, obj); - kmem_cache_free(ramster_flnode_cache, flnode); - goto out; - } - } - preempt_disable(); - kp = &__get_cpu_var(zcache_preloads); - if (kp->obj == NULL) - kp->obj = obj; - else - kmem_cache_free(zcache_obj_cache, obj); - if (kp->flnode == NULL) - kp->flnode = flnode; - else - kmem_cache_free(ramster_flnode_cache, flnode); - if (is_ephemeral(pool)) { - if (kp->page == NULL) - kp->page = page; - else - free_page((unsigned long)page); - } ret = 0; out: return ret; } -static int ramster_do_preload_flnode_only(struct tmem_pool *pool) -{ - struct zcache_preload *kp; - struct flushlist_node *flnode; - int ret = -ENOMEM; - - BUG_ON(!irqs_disabled()); - if (unlikely(ramster_flnode_cache == NULL)) - BUG(); - kp = &__get_cpu_var(zcache_preloads); - flnode = kmem_cache_alloc(ramster_flnode_cache, GFP_ATOMIC); - if (unlikely(flnode == NULL) && kp->flnode == NULL) - BUG(); /* FIXME handle more gracefully, but how??? */ - else if (kp->flnode == NULL) - kp->flnode = flnode; - else - kmem_cache_free(ramster_flnode_cache, flnode); - return ret; -} - -static void *zcache_get_free_page(void) -{ - struct zcache_preload *kp; - void *page; - - kp = &__get_cpu_var(zcache_preloads); - page = kp->page; - BUG_ON(page == NULL); - kp->page = NULL; - return page; -} - -static void zcache_free_page(void *p) -{ - free_page((unsigned long)p); -} - /* * zcache implementation for tmem host ops */ @@ -1604,78 +382,56 @@ static void zcache_free_page(void *p) static struct tmem_objnode *zcache_objnode_alloc(struct tmem_pool *pool) { struct tmem_objnode *objnode = NULL; - unsigned long count; struct zcache_preload *kp; + int i; kp = &__get_cpu_var(zcache_preloads); - if (kp->nr <= 0) - goto out; - objnode = kp->objnodes[kp->nr - 1]; + for (i = 0; i < ARRAY_SIZE(kp->objnodes); i++) { + objnode = kp->objnodes[i]; + if (objnode != NULL) { + kp->objnodes[i] = NULL; + break; + } + } BUG_ON(objnode == NULL); - kp->objnodes[kp->nr - 1] = NULL; - kp->nr--; - count = atomic_inc_return(&zcache_curr_objnode_count); - if (count > zcache_curr_objnode_count_max) - zcache_curr_objnode_count_max = count; -out: + zcache_objnode_count = atomic_inc_return(&zcache_objnode_atomic); + if (zcache_objnode_count > zcache_objnode_count_max) + zcache_objnode_count_max = zcache_objnode_count; return objnode; } static void zcache_objnode_free(struct tmem_objnode *objnode, struct tmem_pool *pool) { - atomic_dec(&zcache_curr_objnode_count); - BUG_ON(atomic_read(&zcache_curr_objnode_count) < 0); + zcache_objnode_count = + atomic_dec_return(&zcache_objnode_atomic); + BUG_ON(zcache_objnode_count < 0); kmem_cache_free(zcache_objnode_cache, objnode); } static struct tmem_obj *zcache_obj_alloc(struct tmem_pool *pool) { struct tmem_obj *obj = NULL; - unsigned long count; struct zcache_preload *kp; kp = &__get_cpu_var(zcache_preloads); obj = kp->obj; BUG_ON(obj == NULL); kp->obj = NULL; - count = atomic_inc_return(&zcache_curr_obj_count); - if (count > zcache_curr_obj_count_max) - zcache_curr_obj_count_max = count; + zcache_obj_count = atomic_inc_return(&zcache_obj_atomic); + if (zcache_obj_count > zcache_obj_count_max) + zcache_obj_count_max = zcache_obj_count; return obj; } static void zcache_obj_free(struct tmem_obj *obj, struct tmem_pool *pool) { - atomic_dec(&zcache_curr_obj_count); - BUG_ON(atomic_read(&zcache_curr_obj_count) < 0); + zcache_obj_count = + atomic_dec_return(&zcache_obj_atomic); + BUG_ON(zcache_obj_count < 0); kmem_cache_free(zcache_obj_cache, obj); } -static struct flushlist_node *ramster_flnode_alloc(struct tmem_pool *pool) -{ - struct flushlist_node *flnode = NULL; - struct zcache_preload *kp; - int count; - - kp = &__get_cpu_var(zcache_preloads); - flnode = kp->flnode; - BUG_ON(flnode == NULL); - kp->flnode = NULL; - count = atomic_inc_return(&ramster_curr_flnode_count); - if (count > ramster_curr_flnode_count_max) - ramster_curr_flnode_count_max = count; - return flnode; -} - -static void ramster_flnode_free(struct flushlist_node *flnode, - struct tmem_pool *pool) -{ - atomic_dec(&ramster_curr_flnode_count); - BUG_ON(atomic_read(&ramster_curr_flnode_count) < 0); - kmem_cache_free(ramster_flnode_cache, flnode); -} - static struct tmem_hostops zcache_hostops = { .obj_alloc = zcache_obj_alloc, .obj_free = zcache_obj_free, @@ -1683,220 +439,363 @@ static struct tmem_hostops zcache_hostops = { .objnode_free = zcache_objnode_free, }; -/* - * zcache implementations for PAM page descriptor ops - */ +static struct page *zcache_alloc_page(void) +{ + struct page *page = alloc_page(ZCACHE_GFP_MASK); + if (page != NULL) + zcache_pageframes_alloced = + atomic_inc_return(&zcache_pageframes_alloced_atomic); + return page; +} -static inline void dec_and_check(atomic_t *pvar) +#ifdef FRONTSWAP_HAS_UNUSE +static void zcache_unacct_page(void) { - atomic_dec(pvar); - /* later when all accounting is fixed, make this a BUG */ - WARN_ON_ONCE(atomic_read(pvar) < 0); + zcache_pageframes_freed = + atomic_inc_return(&zcache_pageframes_freed_atomic); } +#endif + +static void zcache_free_page(struct page *page) +{ + long curr_pageframes; + static long max_pageframes, min_pageframes; -static atomic_t zcache_curr_eph_pampd_count = ATOMIC_INIT(0); -static unsigned long zcache_curr_eph_pampd_count_max; -static atomic_t zcache_curr_pers_pampd_count = ATOMIC_INIT(0); -static unsigned long zcache_curr_pers_pampd_count_max; + if (page == NULL) + BUG(); + __free_page(page); + zcache_pageframes_freed = + atomic_inc_return(&zcache_pageframes_freed_atomic); + curr_pageframes = zcache_pageframes_alloced - + atomic_read(&zcache_pageframes_freed_atomic) - + atomic_read(&zcache_eph_pageframes_atomic) - + atomic_read(&zcache_pers_pageframes_atomic); + if (curr_pageframes > max_pageframes) + max_pageframes = curr_pageframes; + if (curr_pageframes < min_pageframes) + min_pageframes = curr_pageframes; +#ifdef ZCACHE_DEBUG + if (curr_pageframes > 2L || curr_pageframes < -2L) { + /* pr_info here */ + } +#endif +} + +/* + * zcache implementations for PAM page descriptor ops + */ /* forward reference */ -static int zcache_compress(struct page *from, void **out_va, size_t *out_len); +static void zcache_compress(struct page *from, + void **out_va, unsigned *out_len); -static int zcache_pampd_eph_create(char *data, size_t size, bool raw, - struct tmem_pool *pool, struct tmem_oid *oid, - uint32_t index, void **pampd) +static struct page *zcache_evict_eph_pageframe(void); + +static void *zcache_pampd_eph_create(char *data, size_t size, bool raw, + struct tmem_handle *th) { - int ret = -1; - void *cdata = data; - size_t clen = size; - struct zcache_client *cli = pool->client; - uint16_t client_id = get_client_id_from_client(cli); - struct page *page = NULL; - unsigned long count; + void *pampd = NULL, *cdata = data; + unsigned clen = size; + struct page *page = (struct page *)(data), *newpage; if (!raw) { - page = virt_to_page(data); - ret = zcache_compress(page, &cdata, &clen); - if (ret == 0) - goto out; - if (clen == 0 || clen > zbud_max_buddy_size()) { + zcache_compress(page, &cdata, &clen); + if (clen > zbud_max_buddy_size()) { zcache_compress_poor++; goto out; } + } else { + BUG_ON(clen > zbud_max_buddy_size()); } - *pampd = (void *)zbud_create(client_id, pool->pool_id, oid, - index, page, cdata, clen); - if (*pampd == NULL) { - ret = -ENOMEM; + + /* look for space via an existing match first */ + pampd = (void *)zbud_match_prep(th, true, cdata, clen); + if (pampd != NULL) + goto got_pampd; + + /* no match, now we need to find (or free up) a full page */ + newpage = zcache_alloc_page(); + if (newpage != NULL) + goto create_in_new_page; + + zcache_failed_getfreepages++; + /* can't allocate a page, evict an ephemeral page via LRU */ + newpage = zcache_evict_eph_pageframe(); + if (newpage == NULL) { + zcache_eph_ate_tail_failed++; goto out; } - ret = 0; - count = atomic_inc_return(&zcache_curr_eph_pampd_count); - if (count > zcache_curr_eph_pampd_count_max) - zcache_curr_eph_pampd_count_max = count; - if (client_id != LOCAL_CLIENT) { - count = atomic_inc_return(&ramster_foreign_eph_pampd_count); - if (count > ramster_foreign_eph_pampd_count_max) - ramster_foreign_eph_pampd_count_max = count; - } + zcache_eph_ate_tail++; + +create_in_new_page: + pampd = (void *)zbud_create_prep(th, true, cdata, clen, newpage); + BUG_ON(pampd == NULL); + zcache_eph_pageframes = + atomic_inc_return(&zcache_eph_pageframes_atomic); + if (zcache_eph_pageframes > zcache_eph_pageframes_max) + zcache_eph_pageframes_max = zcache_eph_pageframes; + +got_pampd: + zcache_eph_zbytes = + atomic_long_add_return(clen, &zcache_eph_zbytes_atomic); + if (zcache_eph_zbytes > zcache_eph_zbytes_max) + zcache_eph_zbytes_max = zcache_eph_zbytes; + zcache_eph_zpages = atomic_inc_return(&zcache_eph_zpages_atomic); + if (zcache_eph_zpages > zcache_eph_zpages_max) + zcache_eph_zpages_max = zcache_eph_zpages; + if (ramster_enabled && raw) + ramster_count_foreign_pages(true, 1); out: - return ret; + return pampd; } -static int zcache_pampd_pers_create(char *data, size_t size, bool raw, - struct tmem_pool *pool, struct tmem_oid *oid, - uint32_t index, void **pampd) +static void *zcache_pampd_pers_create(char *data, size_t size, bool raw, + struct tmem_handle *th) { - int ret = -1; - void *cdata = data; - size_t clen = size; - struct zcache_client *cli = pool->client; - struct page *page; - unsigned long count; - unsigned long zv_mean_zsize; - struct zv_hdr *zv; - long curr_pers_pampd_count; - u64 total_zsize; -#ifdef RAMSTER_TESTING - static bool pampd_neg_warned; -#endif + void *pampd = NULL, *cdata = data; + unsigned clen = size; + struct page *page = (struct page *)(data), *newpage; + unsigned long zbud_mean_zsize; + unsigned long curr_pers_zpages, total_zsize; - curr_pers_pampd_count = atomic_read(&zcache_curr_pers_pampd_count) - - atomic_read(&ramster_remote_pers_pages); -#ifdef RAMSTER_TESTING - /* should always be positive, but warn if accounting is off */ - if (!pampd_neg_warned) { - pr_warn("ramster: bad accounting for curr_pers_pampd_count\n"); - pampd_neg_warned = true; + if (data == NULL) { + BUG_ON(!ramster_enabled); + goto create_pampd; } -#endif - if (curr_pers_pampd_count > - (zv_page_count_policy_percent * totalram_pages) / 100) { - zcache_policy_percent_exceeded++; - goto out; - } - if (raw) - goto ok_to_create; - page = virt_to_page(data); - if (zcache_compress(page, &cdata, &clen) == 0) - goto out; + curr_pers_zpages = zcache_pers_zpages; +/* FIXME CONFIG_RAMSTER... subtract atomic remote_pers_pages here? */ + if (!raw) + zcache_compress(page, &cdata, &clen); /* reject if compression is too poor */ - if (clen > zv_max_zsize) { + if (clen > zbud_max_zsize) { zcache_compress_poor++; goto out; } /* reject if mean compression is too poor */ - if ((clen > zv_max_mean_zsize) && (curr_pers_pampd_count > 0)) { - total_zsize = xv_get_total_size_bytes(cli->xvpool); - zv_mean_zsize = div_u64(total_zsize, curr_pers_pampd_count); - if (zv_mean_zsize > zv_max_mean_zsize) { + if ((clen > zbud_max_mean_zsize) && (curr_pers_zpages > 0)) { + total_zsize = zcache_pers_zbytes; + if ((long)total_zsize < 0) + total_zsize = 0; + zbud_mean_zsize = div_u64(total_zsize, + curr_pers_zpages); + if (zbud_mean_zsize > zbud_max_mean_zsize) { zcache_mean_compress_poor++; goto out; } } -ok_to_create: - *pampd = (void *)zv_create(cli, pool->pool_id, oid, index, cdata, clen); - if (*pampd == NULL) { - ret = -ENOMEM; + +create_pampd: + /* look for space via an existing match first */ + pampd = (void *)zbud_match_prep(th, false, cdata, clen); + if (pampd != NULL) + goto got_pampd; + + /* no match, now we need to find (or free up) a full page */ + newpage = zcache_alloc_page(); + if (newpage != NULL) + goto create_in_new_page; + /* + * FIXME do the following only if eph is oversized? + * if (zcache_eph_pageframes > + * (global_page_state(NR_LRU_BASE + LRU_ACTIVE_FILE) + + * global_page_state(NR_LRU_BASE + LRU_INACTIVE_FILE))) + */ + zcache_failed_getfreepages++; + /* can't allocate a page, evict an ephemeral page via LRU */ + newpage = zcache_evict_eph_pageframe(); + if (newpage == NULL) { + zcache_pers_ate_eph_failed++; goto out; } - ret = 0; - count = atomic_inc_return(&zcache_curr_pers_pampd_count); - if (count > zcache_curr_pers_pampd_count_max) - zcache_curr_pers_pampd_count_max = count; - if (is_local_client(cli)) - goto out; - zv = *(struct zv_hdr **)pampd; - count = atomic_inc_return(&ramster_foreign_pers_pampd_count); - if (count > ramster_foreign_pers_pampd_count_max) - ramster_foreign_pers_pampd_count_max = count; + zcache_pers_ate_eph++; + +create_in_new_page: + pampd = (void *)zbud_create_prep(th, false, cdata, clen, newpage); + BUG_ON(pampd == NULL); + zcache_pers_pageframes = + atomic_inc_return(&zcache_pers_pageframes_atomic); + if (zcache_pers_pageframes > zcache_pers_pageframes_max) + zcache_pers_pageframes_max = zcache_pers_pageframes; + +got_pampd: + zcache_pers_zpages = atomic_inc_return(&zcache_pers_zpages_atomic); + if (zcache_pers_zpages > zcache_pers_zpages_max) + zcache_pers_zpages_max = zcache_pers_zpages; + zcache_pers_zbytes = + atomic_long_add_return(clen, &zcache_pers_zbytes_atomic); + if (zcache_pers_zbytes > zcache_pers_zbytes_max) + zcache_pers_zbytes_max = zcache_pers_zbytes; + if (ramster_enabled && raw) + ramster_count_foreign_pages(false, 1); out: - return ret; + return pampd; } -static void *zcache_pampd_create(char *data, size_t size, bool raw, int eph, - struct tmem_pool *pool, struct tmem_oid *oid, - uint32_t index) +/* + * This is called directly from zcache_put_page to pre-allocate space + * to store a zpage. + */ +void *zcache_pampd_create(char *data, unsigned int size, bool raw, + int eph, struct tmem_handle *th) { void *pampd = NULL; - int ret; - bool ephemeral; + struct zcache_preload *kp; + struct tmem_objnode *objnode; + struct tmem_obj *obj; + int i; - BUG_ON(preemptible()); - ephemeral = (eph == 1) || ((eph == 0) && is_ephemeral(pool)); - if (ephemeral) - ret = zcache_pampd_eph_create(data, size, raw, pool, - oid, index, &pampd); + BUG_ON(!irqs_disabled()); + /* pre-allocate per-cpu metadata */ + BUG_ON(zcache_objnode_cache == NULL); + BUG_ON(zcache_obj_cache == NULL); + kp = &__get_cpu_var(zcache_preloads); + for (i = 0; i < ARRAY_SIZE(kp->objnodes); i++) { + objnode = kp->objnodes[i]; + if (objnode == NULL) { + objnode = kmem_cache_alloc(zcache_objnode_cache, + ZCACHE_GFP_MASK); + if (unlikely(objnode == NULL)) { + zcache_failed_alloc++; + goto out; + } + kp->objnodes[i] = objnode; + } + } + if (kp->obj == NULL) { + obj = kmem_cache_alloc(zcache_obj_cache, ZCACHE_GFP_MASK); + kp->obj = obj; + } + if (unlikely(kp->obj == NULL)) { + zcache_failed_alloc++; + goto out; + } + /* + * ok, have all the metadata pre-allocated, now do the data + * but since how we allocate the data is dependent on ephemeral + * or persistent, we split the call here to different sub-functions + */ + if (eph) + pampd = zcache_pampd_eph_create(data, size, raw, th); else - ret = zcache_pampd_pers_create(data, size, raw, pool, - oid, index, &pampd); - /* FIXME add some counters here for failed creates? */ + pampd = zcache_pampd_pers_create(data, size, raw, th); +out: return pampd; } /* + * This is a pamops called via tmem_put and is necessary to "finish" + * a pampd creation. + */ +void zcache_pampd_create_finish(void *pampd, bool eph) +{ + zbud_create_finish((struct zbudref *)pampd, eph); +} + +/* + * This is passed as a function parameter to zbud_decompress so that + * zbud need not be familiar with the details of crypto. It assumes that + * the bytes from_va and to_va through from_va+size-1 and to_va+size-1 are + * kmapped. It must be successful, else there is a logic bug somewhere. + */ +static void zcache_decompress(char *from_va, unsigned int size, char *to_va) +{ + int ret; + unsigned int outlen = PAGE_SIZE; + + ret = zcache_comp_op(ZCACHE_COMPOP_DECOMPRESS, from_va, size, + to_va, &outlen); + BUG_ON(ret); + BUG_ON(outlen != PAGE_SIZE); +} + +/* + * Decompress from the kernel va to a pageframe + */ +void zcache_decompress_to_page(char *from_va, unsigned int size, + struct page *to_page) +{ + char *to_va = kmap_atomic(to_page); + zcache_decompress(from_va, size, to_va); + kunmap_atomic(to_va); +} + +/* * fill the pageframe corresponding to the struct page with the data * from the passed pampd */ -static int zcache_pampd_get_data(char *data, size_t *bufsize, bool raw, +static int zcache_pampd_get_data(char *data, size_t *sizep, bool raw, void *pampd, struct tmem_pool *pool, struct tmem_oid *oid, uint32_t index) { - int ret = 0; + int ret; + bool eph = !is_persistent(pool); BUG_ON(preemptible()); - BUG_ON(is_ephemeral(pool)); /* Fix later for shared pools? */ + BUG_ON(eph); /* fix later if shared pools get implemented */ BUG_ON(pampd_is_remote(pampd)); if (raw) - zv_copy_from_pampd(data, bufsize, pampd); - else - zv_decompress(virt_to_page(data), pampd); + ret = zbud_copy_from_zbud(data, (struct zbudref *)pampd, + sizep, eph); + else { + ret = zbud_decompress((struct page *)(data), + (struct zbudref *)pampd, false, + zcache_decompress); + *sizep = PAGE_SIZE; + } return ret; } -static int zcache_pampd_get_data_and_free(char *data, size_t *bufsize, bool raw, +/* + * fill the pageframe corresponding to the struct page with the data + * from the passed pampd + */ +static int zcache_pampd_get_data_and_free(char *data, size_t *sizep, bool raw, void *pampd, struct tmem_pool *pool, struct tmem_oid *oid, uint32_t index) { - int ret = 0; - unsigned long flags; - struct zcache_client *cli = pool->client; + int ret; + bool eph = !is_persistent(pool); + struct page *page = NULL; + unsigned int zsize, zpages; BUG_ON(preemptible()); BUG_ON(pampd_is_remote(pampd)); - if (is_ephemeral(pool)) { - local_irq_save(flags); - if (raw) - zbud_copy_from_pampd(data, bufsize, pampd); - else - ret = zbud_decompress(virt_to_page(data), pampd); - zbud_free_and_delist((struct zbud_hdr *)pampd); - local_irq_restore(flags); - if (!is_local_client(cli)) - dec_and_check(&ramster_foreign_eph_pampd_count); - dec_and_check(&zcache_curr_eph_pampd_count); + if (raw) + ret = zbud_copy_from_zbud(data, (struct zbudref *)pampd, + sizep, eph); + else { + ret = zbud_decompress((struct page *)(data), + (struct zbudref *)pampd, eph, + zcache_decompress); + *sizep = PAGE_SIZE; + } + page = zbud_free_and_delist((struct zbudref *)pampd, eph, + &zsize, &zpages); + if (eph) { + if (page) + zcache_eph_pageframes = + atomic_dec_return(&zcache_eph_pageframes_atomic); + zcache_eph_zpages = + atomic_sub_return(zpages, &zcache_eph_zpages_atomic); + zcache_eph_zbytes = + atomic_long_sub_return(zsize, &zcache_eph_zbytes_atomic); } else { - if (is_local_client(cli)) - BUG(); - if (raw) - zv_copy_from_pampd(data, bufsize, pampd); - else - zv_decompress(virt_to_page(data), pampd); - zv_free(cli->xvpool, pampd); - if (!is_local_client(cli)) - dec_and_check(&ramster_foreign_pers_pampd_count); - dec_and_check(&zcache_curr_pers_pampd_count); - ret = 0; - } + if (page) + zcache_pers_pageframes = + atomic_dec_return(&zcache_pers_pageframes_atomic); + zcache_pers_zpages = + atomic_sub_return(zpages, &zcache_pers_zpages_atomic); + zcache_pers_zbytes = + atomic_long_sub_return(zsize, &zcache_pers_zbytes_atomic); + } + if (!is_local_client(pool->client)) + ramster_count_foreign_pages(eph, -1); + if (page) + zcache_free_page(page); return ret; } -static bool zcache_pampd_is_remote(void *pampd) -{ - return pampd_is_remote(pampd); -} - /* * free the pampd and remove it from any zcache lists * pampd must no longer be pointed to from any tmem data structures! @@ -1904,362 +803,134 @@ static bool zcache_pampd_is_remote(void *pampd) static void zcache_pampd_free(void *pampd, struct tmem_pool *pool, struct tmem_oid *oid, uint32_t index, bool acct) { - struct zcache_client *cli = pool->client; - bool eph = is_ephemeral(pool); - struct zv_hdr *zv; + struct page *page = NULL; + unsigned int zsize, zpages; BUG_ON(preemptible()); if (pampd_is_remote(pampd)) { - WARN_ON(acct == false); - if (oid == NULL) { - /* - * a NULL oid means to ignore this pampd free - * as the remote freeing will be handled elsewhere - */ - } else if (eph) { - /* FIXME remote flush optional but probably good idea */ - /* FIXME get these working properly again */ - dec_and_check(&zcache_curr_eph_pampd_count); - } else if (pampd_is_intransit(pampd)) { - /* did a pers remote get_and_free, so just free local */ - pampd = pampd_mask_intransit_and_remote(pampd); - goto local_pers; - } else { - struct flushlist_node *flnode = - ramster_flnode_alloc(pool); - - flnode->xh.client_id = pampd_remote_node(pampd); - flnode->xh.pool_id = pool->pool_id; - flnode->xh.oid = *oid; - flnode->xh.index = index; - flnode->rem_op.op = RAMSTER_REMOTIFY_FLUSH_PAGE; - spin_lock(&zcache_rem_op_list_lock); - list_add(&flnode->rem_op.list, &zcache_rem_op_list); - spin_unlock(&zcache_rem_op_list_lock); - dec_and_check(&zcache_curr_pers_pampd_count); - dec_and_check(&ramster_remote_pers_pages); - } - } else if (eph) { - zbud_free_and_delist((struct zbud_hdr *)pampd); - if (!is_local_client(pool->client)) - dec_and_check(&ramster_foreign_eph_pampd_count); - if (acct) - /* FIXME get these working properly again */ - dec_and_check(&zcache_curr_eph_pampd_count); - } else { -local_pers: - zv = (struct zv_hdr *)pampd; - if (!is_local_client(pool->client)) - dec_and_check(&ramster_foreign_pers_pampd_count); - zv_free(cli->xvpool, zv); - if (acct) - /* FIXME get these working properly again */ - dec_and_check(&zcache_curr_pers_pampd_count); + BUG_ON(!ramster_enabled); + pampd = ramster_pampd_free(pampd, pool, oid, index, acct); + if (pampd == NULL) + return; } -} - -static void zcache_pampd_free_obj(struct tmem_pool *pool, - struct tmem_obj *obj) -{ - struct flushlist_node *flnode; - - BUG_ON(preemptible()); - if (obj->extra == NULL) - return; - BUG_ON(!pampd_is_remote(obj->extra)); - flnode = ramster_flnode_alloc(pool); - flnode->xh.client_id = pampd_remote_node(obj->extra); - flnode->xh.pool_id = pool->pool_id; - flnode->xh.oid = obj->oid; - flnode->xh.index = FLUSH_ENTIRE_OBJECT; - flnode->rem_op.op = RAMSTER_REMOTIFY_FLUSH_OBJ; - spin_lock(&zcache_rem_op_list_lock); - list_add(&flnode->rem_op.list, &zcache_rem_op_list); - spin_unlock(&zcache_rem_op_list_lock); -} - -void zcache_pampd_new_obj(struct tmem_obj *obj) -{ - obj->extra = NULL; -} - -int zcache_pampd_replace_in_obj(void *new_pampd, struct tmem_obj *obj) -{ - int ret = -1; - - if (new_pampd != NULL) { - if (obj->extra == NULL) - obj->extra = new_pampd; - /* enforce that all remote pages in an object reside - * in the same node! */ - else if (pampd_remote_node(new_pampd) != - pampd_remote_node((void *)(obj->extra))) - BUG(); - ret = 0; - } - return ret; -} - -/* - * Called by the message handler after a (still compressed) page has been - * fetched from the remote machine in response to an "is_remote" tmem_get - * or persistent tmem_localify. For a tmem_get, "extra" is the address of - * the page that is to be filled to successfully resolve the tmem_get; for - * a (persistent) tmem_localify, "extra" is NULL (as the data is placed only - * in the local zcache). "data" points to "size" bytes of (compressed) data - * passed in the message. In the case of a persistent remote get, if - * pre-allocation was successful (see zcache_repatriate_preload), the page - * is placed into both local zcache and at "extra". - */ -int zcache_localify(int pool_id, struct tmem_oid *oidp, - uint32_t index, char *data, size_t size, - void *extra) -{ - int ret = -ENOENT; - unsigned long flags; - struct tmem_pool *pool; - bool ephemeral, delete = false; - size_t clen = PAGE_SIZE; - void *pampd, *saved_hb; - struct tmem_obj *obj; - - pool = zcache_get_pool_by_id(LOCAL_CLIENT, pool_id); - if (unlikely(pool == NULL)) - /* pool doesn't exist anymore */ - goto out; - ephemeral = is_ephemeral(pool); - local_irq_save(flags); /* FIXME: maybe only disable softirqs? */ - pampd = tmem_localify_get_pampd(pool, oidp, index, &obj, &saved_hb); - if (pampd == NULL) { - /* hmmm... must have been a flush while waiting */ -#ifdef RAMSTER_TESTING - pr_err("UNTESTED pampd==NULL in zcache_localify\n"); -#endif - if (ephemeral) - ramster_remote_eph_pages_unsucc_get++; - else - ramster_remote_pers_pages_unsucc_get++; - obj = NULL; - goto finish; - } else if (unlikely(!pampd_is_remote(pampd))) { - /* hmmm... must have been a dup put while waiting */ -#ifdef RAMSTER_TESTING - pr_err("UNTESTED dup while waiting in zcache_localify\n"); -#endif - if (ephemeral) - ramster_remote_eph_pages_unsucc_get++; - else - ramster_remote_pers_pages_unsucc_get++; - obj = NULL; - pampd = NULL; - ret = -EEXIST; - goto finish; - } else if (size == 0) { - /* no remote data, delete the local is_remote pampd */ - pampd = NULL; - if (ephemeral) - ramster_remote_eph_pages_unsucc_get++; - else - BUG(); - delete = true; - goto finish; - } - if (!ephemeral && pampd_is_intransit(pampd)) { - /* localify to zcache */ - pampd = pampd_mask_intransit_and_remote(pampd); - zv_copy_to_pampd(pampd, data, size); + if (is_ephemeral(pool)) { + page = zbud_free_and_delist((struct zbudref *)pampd, + true, &zsize, &zpages); + if (page) + zcache_eph_pageframes = + atomic_dec_return(&zcache_eph_pageframes_atomic); + zcache_eph_zpages = + atomic_sub_return(zpages, &zcache_eph_zpages_atomic); + zcache_eph_zbytes = + atomic_long_sub_return(zsize, &zcache_eph_zbytes_atomic); + /* FIXME CONFIG_RAMSTER... check acct parameter? */ } else { - pampd = NULL; - obj = NULL; - } - if (extra != NULL) { - /* decompress direct-to-memory to complete remotify */ - ret = lzo1x_decompress_safe((char *)data, size, - (char *)extra, &clen); - BUG_ON(ret != LZO_E_OK); - BUG_ON(clen != PAGE_SIZE); - } - if (ephemeral) - ramster_remote_eph_pages_succ_get++; - else - ramster_remote_pers_pages_succ_get++; - ret = 0; -finish: - tmem_localify_finish(obj, index, pampd, saved_hb, delete); - zcache_put_pool(pool); - local_irq_restore(flags); -out: - return ret; -} - -/* - * Called on a remote persistent tmem_get to attempt to preallocate - * local storage for the data contained in the remote persistent page. - * If successfully preallocated, returns the pampd, marked as remote and - * in_transit. Else returns NULL. Note that the appropriate tmem data - * structure must be locked. - */ -static void *zcache_pampd_repatriate_preload(void *pampd, - struct tmem_pool *pool, - struct tmem_oid *oid, - uint32_t index, - bool *intransit) -{ - int clen = pampd_remote_size(pampd); - void *ret_pampd = NULL; - unsigned long flags; - - if (!pampd_is_remote(pampd)) - BUG(); - if (is_ephemeral(pool)) - BUG(); - if (pampd_is_intransit(pampd)) { - /* - * to avoid multiple allocations (and maybe a memory leak) - * don't preallocate if already in the process of being - * repatriated - */ - *intransit = true; - goto out; - } - *intransit = false; - local_irq_save(flags); - ret_pampd = (void *)zv_alloc(pool, oid, index, clen); - if (ret_pampd != NULL) { - /* - * a pampd is marked intransit if it is remote and space has - * been allocated for it locally (note, only happens for - * persistent pages, in which case the remote copy is freed) - */ - ret_pampd = pampd_mark_intransit(ret_pampd); - dec_and_check(&ramster_remote_pers_pages); - } else - ramster_pers_pages_remote_nomem++; - local_irq_restore(flags); -out: - return ret_pampd; -} - -/* - * Called on a remote tmem_get to invoke a message to fetch the page. - * Might sleep so no tmem locks can be held. "extra" is passed - * all the way through the round-trip messaging to zcache_localify. - */ -static int zcache_pampd_repatriate(void *fake_pampd, void *real_pampd, - struct tmem_pool *pool, - struct tmem_oid *oid, uint32_t index, - bool free, void *extra) -{ - struct tmem_xhandle xh; - int ret; - - if (pampd_is_intransit(real_pampd)) - /* have local space pre-reserved, so free remote copy */ - free = true; - xh = tmem_xhandle_fill(LOCAL_CLIENT, pool, oid, index); - /* unreliable request/response for now */ - ret = ramster_remote_async_get(&xh, free, - pampd_remote_node(fake_pampd), - pampd_remote_size(fake_pampd), - pampd_remote_cksum(fake_pampd), - extra); -#ifdef RAMSTER_TESTING - if (ret != 0 && ret != -ENOENT) - pr_err("TESTING zcache_pampd_repatriate returns, ret=%d\n", - ret); -#endif - return ret; + page = zbud_free_and_delist((struct zbudref *)pampd, + false, &zsize, &zpages); + if (page) + zcache_pers_pageframes = + atomic_dec_return(&zcache_pers_pageframes_atomic); + zcache_pers_zpages = + atomic_sub_return(zpages, &zcache_pers_zpages_atomic); + zcache_pers_zbytes = + atomic_long_sub_return(zsize, &zcache_pers_zbytes_atomic); + } + if (!is_local_client(pool->client)) + ramster_count_foreign_pages(is_ephemeral(pool), -1); + if (page) + zcache_free_page(page); } static struct tmem_pamops zcache_pamops = { - .create = zcache_pampd_create, + .create_finish = zcache_pampd_create_finish, .get_data = zcache_pampd_get_data, - .free = zcache_pampd_free, .get_data_and_free = zcache_pampd_get_data_and_free, - .free_obj = zcache_pampd_free_obj, - .is_remote = zcache_pampd_is_remote, - .repatriate_preload = zcache_pampd_repatriate_preload, - .repatriate = zcache_pampd_repatriate, - .new_obj = zcache_pampd_new_obj, - .replace_in_obj = zcache_pampd_replace_in_obj, + .free = zcache_pampd_free, }; /* * zcache compression/decompression and related per-cpu stuff */ -#define LZO_WORKMEM_BYTES LZO1X_1_MEM_COMPRESS -#define LZO_DSTMEM_PAGE_ORDER 1 -static DEFINE_PER_CPU(unsigned char *, zcache_workmem); static DEFINE_PER_CPU(unsigned char *, zcache_dstmem); +#define ZCACHE_DSTMEM_ORDER 1 -static int zcache_compress(struct page *from, void **out_va, size_t *out_len) +static void zcache_compress(struct page *from, void **out_va, unsigned *out_len) { - int ret = 0; + int ret; unsigned char *dmem = __get_cpu_var(zcache_dstmem); - unsigned char *wmem = __get_cpu_var(zcache_workmem); char *from_va; BUG_ON(!irqs_disabled()); - if (unlikely(dmem == NULL || wmem == NULL)) - goto out; /* no buffer, so can't compress */ + /* no buffer or no compressor so can't compress */ + BUG_ON(dmem == NULL); + *out_len = PAGE_SIZE << ZCACHE_DSTMEM_ORDER; from_va = kmap_atomic(from); mb(); - ret = lzo1x_1_compress(from_va, PAGE_SIZE, dmem, out_len, wmem); - BUG_ON(ret != LZO_E_OK); + ret = zcache_comp_op(ZCACHE_COMPOP_COMPRESS, from_va, PAGE_SIZE, dmem, + out_len); + BUG_ON(ret); *out_va = dmem; kunmap_atomic(from_va); - ret = 1; -out: - return ret; } +static int zcache_comp_cpu_up(int cpu) +{ + struct crypto_comp *tfm; + + tfm = crypto_alloc_comp(zcache_comp_name, 0, 0); + if (IS_ERR(tfm)) + return NOTIFY_BAD; + *per_cpu_ptr(zcache_comp_pcpu_tfms, cpu) = tfm; + return NOTIFY_OK; +} + +static void zcache_comp_cpu_down(int cpu) +{ + struct crypto_comp *tfm; + + tfm = *per_cpu_ptr(zcache_comp_pcpu_tfms, cpu); + crypto_free_comp(tfm); + *per_cpu_ptr(zcache_comp_pcpu_tfms, cpu) = NULL; +} static int zcache_cpu_notifier(struct notifier_block *nb, unsigned long action, void *pcpu) { - int cpu = (long)pcpu; + int ret, i, cpu = (long)pcpu; struct zcache_preload *kp; switch (action) { case CPU_UP_PREPARE: + ret = zcache_comp_cpu_up(cpu); + if (ret != NOTIFY_OK) { + pr_err("%s: can't allocate compressor xform\n", + namestr); + return ret; + } per_cpu(zcache_dstmem, cpu) = (void *)__get_free_pages( - GFP_KERNEL | __GFP_REPEAT, - LZO_DSTMEM_PAGE_ORDER), - per_cpu(zcache_workmem, cpu) = - kzalloc(LZO1X_MEM_COMPRESS, - GFP_KERNEL | __GFP_REPEAT); - per_cpu(zcache_remoteputmem, cpu) = - kzalloc(PAGE_SIZE, GFP_KERNEL | __GFP_REPEAT); + GFP_KERNEL | __GFP_REPEAT, ZCACHE_DSTMEM_ORDER); + if (ramster_enabled) + ramster_cpu_up(cpu); break; case CPU_DEAD: case CPU_UP_CANCELED: - kfree(per_cpu(zcache_remoteputmem, cpu)); - per_cpu(zcache_remoteputmem, cpu) = NULL; + zcache_comp_cpu_down(cpu); free_pages((unsigned long)per_cpu(zcache_dstmem, cpu), - LZO_DSTMEM_PAGE_ORDER); + ZCACHE_DSTMEM_ORDER); per_cpu(zcache_dstmem, cpu) = NULL; - kfree(per_cpu(zcache_workmem, cpu)); - per_cpu(zcache_workmem, cpu) = NULL; kp = &per_cpu(zcache_preloads, cpu); - while (kp->nr) { - kmem_cache_free(zcache_objnode_cache, - kp->objnodes[kp->nr - 1]); - kp->objnodes[kp->nr - 1] = NULL; - kp->nr--; + for (i = 0; i < ARRAY_SIZE(kp->objnodes); i++) { + if (kp->objnodes[i]) + kmem_cache_free(zcache_objnode_cache, + kp->objnodes[i]); } if (kp->obj) { kmem_cache_free(zcache_obj_cache, kp->obj); kp->obj = NULL; } - if (kp->flnode) { - kmem_cache_free(ramster_flnode_cache, kp->flnode); - kp->flnode = NULL; - } - if (kp->page) { - free_page((unsigned long)kp->page); - kp->page = NULL; - } + if (ramster_enabled) + ramster_cpu_down(cpu); break; default: break; @@ -2271,314 +942,104 @@ static struct notifier_block zcache_cpu_notifier_block = { .notifier_call = zcache_cpu_notifier }; -#ifdef CONFIG_SYSFS -#define ZCACHE_SYSFS_RO(_name) \ - static ssize_t zcache_##_name##_show(struct kobject *kobj, \ - struct kobj_attribute *attr, char *buf) \ - { \ - return sprintf(buf, "%lu\n", zcache_##_name); \ - } \ - static struct kobj_attribute zcache_##_name##_attr = { \ - .attr = { .name = __stringify(_name), .mode = 0444 }, \ - .show = zcache_##_name##_show, \ - } - -#define ZCACHE_SYSFS_RO_ATOMIC(_name) \ - static ssize_t zcache_##_name##_show(struct kobject *kobj, \ - struct kobj_attribute *attr, char *buf) \ - { \ - return sprintf(buf, "%d\n", atomic_read(&zcache_##_name)); \ - } \ - static struct kobj_attribute zcache_##_name##_attr = { \ - .attr = { .name = __stringify(_name), .mode = 0444 }, \ - .show = zcache_##_name##_show, \ - } - -#define ZCACHE_SYSFS_RO_CUSTOM(_name, _func) \ - static ssize_t zcache_##_name##_show(struct kobject *kobj, \ - struct kobj_attribute *attr, char *buf) \ - { \ - return _func(buf); \ - } \ - static struct kobj_attribute zcache_##_name##_attr = { \ - .attr = { .name = __stringify(_name), .mode = 0444 }, \ - .show = zcache_##_name##_show, \ - } - -ZCACHE_SYSFS_RO(curr_obj_count_max); -ZCACHE_SYSFS_RO(curr_objnode_count_max); -ZCACHE_SYSFS_RO(flush_total); -ZCACHE_SYSFS_RO(flush_found); -ZCACHE_SYSFS_RO(flobj_total); -ZCACHE_SYSFS_RO(flobj_found); -ZCACHE_SYSFS_RO(failed_eph_puts); -ZCACHE_SYSFS_RO(nonactive_puts); -ZCACHE_SYSFS_RO(failed_pers_puts); -ZCACHE_SYSFS_RO(zbud_curr_zbytes); -ZCACHE_SYSFS_RO(zbud_cumul_zpages); -ZCACHE_SYSFS_RO(zbud_cumul_zbytes); -ZCACHE_SYSFS_RO(zbud_buddied_count); -ZCACHE_SYSFS_RO(evicted_raw_pages); -ZCACHE_SYSFS_RO(evicted_unbuddied_pages); -ZCACHE_SYSFS_RO(evicted_buddied_pages); -ZCACHE_SYSFS_RO(failed_get_free_pages); -ZCACHE_SYSFS_RO(failed_alloc); -ZCACHE_SYSFS_RO(put_to_flush); -ZCACHE_SYSFS_RO(compress_poor); -ZCACHE_SYSFS_RO(mean_compress_poor); -ZCACHE_SYSFS_RO(policy_percent_exceeded); -ZCACHE_SYSFS_RO_ATOMIC(zbud_curr_raw_pages); -ZCACHE_SYSFS_RO_ATOMIC(zbud_curr_zpages); -ZCACHE_SYSFS_RO_ATOMIC(curr_obj_count); -ZCACHE_SYSFS_RO_ATOMIC(curr_objnode_count); -ZCACHE_SYSFS_RO_CUSTOM(zbud_unbuddied_list_counts, - zbud_show_unbuddied_list_counts); -ZCACHE_SYSFS_RO_CUSTOM(zbud_cumul_chunk_counts, - zbud_show_cumul_chunk_counts); -ZCACHE_SYSFS_RO_CUSTOM(zv_curr_dist_counts, - zv_curr_dist_counts_show); -ZCACHE_SYSFS_RO_CUSTOM(zv_cumul_dist_counts, - zv_cumul_dist_counts_show); - -static struct attribute *zcache_attrs[] = { - &zcache_curr_obj_count_attr.attr, - &zcache_curr_obj_count_max_attr.attr, - &zcache_curr_objnode_count_attr.attr, - &zcache_curr_objnode_count_max_attr.attr, - &zcache_flush_total_attr.attr, - &zcache_flobj_total_attr.attr, - &zcache_flush_found_attr.attr, - &zcache_flobj_found_attr.attr, - &zcache_failed_eph_puts_attr.attr, - &zcache_nonactive_puts_attr.attr, - &zcache_failed_pers_puts_attr.attr, - &zcache_policy_percent_exceeded_attr.attr, - &zcache_compress_poor_attr.attr, - &zcache_mean_compress_poor_attr.attr, - &zcache_zbud_curr_raw_pages_attr.attr, - &zcache_zbud_curr_zpages_attr.attr, - &zcache_zbud_curr_zbytes_attr.attr, - &zcache_zbud_cumul_zpages_attr.attr, - &zcache_zbud_cumul_zbytes_attr.attr, - &zcache_zbud_buddied_count_attr.attr, - &zcache_evicted_raw_pages_attr.attr, - &zcache_evicted_unbuddied_pages_attr.attr, - &zcache_evicted_buddied_pages_attr.attr, - &zcache_failed_get_free_pages_attr.attr, - &zcache_failed_alloc_attr.attr, - &zcache_put_to_flush_attr.attr, - &zcache_zbud_unbuddied_list_counts_attr.attr, - &zcache_zbud_cumul_chunk_counts_attr.attr, - &zcache_zv_curr_dist_counts_attr.attr, - &zcache_zv_cumul_dist_counts_attr.attr, - &zcache_zv_max_zsize_attr.attr, - &zcache_zv_max_mean_zsize_attr.attr, - &zcache_zv_page_count_policy_percent_attr.attr, - NULL, -}; - -static struct attribute_group zcache_attr_group = { - .attrs = zcache_attrs, - .name = "zcache", -}; - -#define RAMSTER_SYSFS_RO(_name) \ - static ssize_t ramster_##_name##_show(struct kobject *kobj, \ - struct kobj_attribute *attr, char *buf) \ - { \ - return sprintf(buf, "%lu\n", ramster_##_name); \ - } \ - static struct kobj_attribute ramster_##_name##_attr = { \ - .attr = { .name = __stringify(_name), .mode = 0444 }, \ - .show = ramster_##_name##_show, \ - } - -#define RAMSTER_SYSFS_RW(_name) \ - static ssize_t ramster_##_name##_show(struct kobject *kobj, \ - struct kobj_attribute *attr, char *buf) \ - { \ - return sprintf(buf, "%lu\n", ramster_##_name); \ - } \ - static ssize_t ramster_##_name##_store(struct kobject *kobj, \ - struct kobj_attribute *attr, const char *buf, size_t count) \ - { \ - int err; \ - unsigned long enable; \ - err = kstrtoul(buf, 10, &enable); \ - if (err) \ - return -EINVAL; \ - ramster_##_name = enable; \ - return count; \ - } \ - static struct kobj_attribute ramster_##_name##_attr = { \ - .attr = { .name = __stringify(_name), .mode = 0644 }, \ - .show = ramster_##_name##_show, \ - .store = ramster_##_name##_store, \ - } - -#define RAMSTER_SYSFS_RO_ATOMIC(_name) \ - static ssize_t ramster_##_name##_show(struct kobject *kobj, \ - struct kobj_attribute *attr, char *buf) \ - { \ - return sprintf(buf, "%d\n", atomic_read(&ramster_##_name)); \ - } \ - static struct kobj_attribute ramster_##_name##_attr = { \ - .attr = { .name = __stringify(_name), .mode = 0444 }, \ - .show = ramster_##_name##_show, \ - } - -RAMSTER_SYSFS_RO(interface_revision); -RAMSTER_SYSFS_RO_ATOMIC(remote_pers_pages); -RAMSTER_SYSFS_RW(pers_remotify_enable); -RAMSTER_SYSFS_RW(eph_remotify_enable); -RAMSTER_SYSFS_RO(eph_pages_remoted); -RAMSTER_SYSFS_RO(eph_pages_remote_failed); -RAMSTER_SYSFS_RO(pers_pages_remoted); -RAMSTER_SYSFS_RO(pers_pages_remote_failed); -RAMSTER_SYSFS_RO(pers_pages_remote_nomem); -RAMSTER_SYSFS_RO(remote_pages_flushed); -RAMSTER_SYSFS_RO(remote_page_flushes_failed); -RAMSTER_SYSFS_RO(remote_objects_flushed); -RAMSTER_SYSFS_RO(remote_object_flushes_failed); -RAMSTER_SYSFS_RO(remote_eph_pages_succ_get); -RAMSTER_SYSFS_RO(remote_eph_pages_unsucc_get); -RAMSTER_SYSFS_RO(remote_pers_pages_succ_get); -RAMSTER_SYSFS_RO(remote_pers_pages_unsucc_get); -RAMSTER_SYSFS_RO_ATOMIC(foreign_eph_pampd_count); -RAMSTER_SYSFS_RO(foreign_eph_pampd_count_max); -RAMSTER_SYSFS_RO_ATOMIC(foreign_pers_pampd_count); -RAMSTER_SYSFS_RO(foreign_pers_pampd_count_max); -RAMSTER_SYSFS_RO_ATOMIC(curr_flnode_count); -RAMSTER_SYSFS_RO(curr_flnode_count_max); - -#define MANUAL_NODES 8 -static bool ramster_nodes_manual_up[MANUAL_NODES]; -static ssize_t ramster_manual_node_up_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) -{ - int i; - char *p = buf; - for (i = 0; i < MANUAL_NODES; i++) - if (ramster_nodes_manual_up[i]) - p += sprintf(p, "%d ", i); - p += sprintf(p, "\n"); - return p - buf; -} +/* + * The following code interacts with the zbud eviction and zbud + * zombify code to access LRU pages + */ -static ssize_t ramster_manual_node_up_store(struct kobject *kobj, - struct kobj_attribute *attr, const char *buf, size_t count) +static struct page *zcache_evict_eph_pageframe(void) { - int err; - unsigned long node_num; + struct page *page; + unsigned int zsize = 0, zpages = 0; - err = kstrtoul(buf, 10, &node_num); - if (err) { - pr_err("ramster: bad strtoul?\n"); - return -EINVAL; - } - if (node_num >= MANUAL_NODES) { - pr_err("ramster: bad node_num=%lu?\n", node_num); - return -EINVAL; - } - if (ramster_nodes_manual_up[node_num]) { - pr_err("ramster: node %d already up, ignoring\n", - (int)node_num); - } else { - ramster_nodes_manual_up[node_num] = true; - r2net_hb_node_up_manual((int)node_num); - } - return count; + page = zbud_evict_pageframe_lru(&zsize, &zpages); + if (page == NULL) + goto out; + zcache_eph_zbytes = atomic_long_sub_return(zsize, + &zcache_eph_zbytes_atomic); + zcache_eph_zpages = atomic_sub_return(zpages, + &zcache_eph_zpages_atomic); + zcache_evicted_eph_zpages++; + zcache_eph_pageframes = + atomic_dec_return(&zcache_eph_pageframes_atomic); + zcache_evicted_eph_pageframes++; +out: + return page; } -static struct kobj_attribute ramster_manual_node_up_attr = { - .attr = { .name = "manual_node_up", .mode = 0644 }, - .show = ramster_manual_node_up_show, - .store = ramster_manual_node_up_store, -}; +#ifdef FRONTSWAP_HAS_UNUSE +static void unswiz(struct tmem_oid oid, u32 index, + unsigned *type, pgoff_t *offset); -static ssize_t ramster_remote_target_nodenum_show(struct kobject *kobj, - struct kobj_attribute *attr, char *buf) +/* + * Choose an LRU persistent pageframe and attempt to "unuse" it by + * calling frontswap_unuse on both zpages. + * + * This is work-in-progress. + */ + +static int zcache_frontswap_unuse(void) { - if (ramster_remote_target_nodenum == -1UL) - return sprintf(buf, "unset\n"); - else - return sprintf(buf, "%d\n", ramster_remote_target_nodenum); -} - -static ssize_t ramster_remote_target_nodenum_store(struct kobject *kobj, - struct kobj_attribute *attr, const char *buf, size_t count) -{ - int err; - unsigned long node_num; - - err = kstrtoul(buf, 10, &node_num); - if (err) { - pr_err("ramster: bad strtoul?\n"); - return -EINVAL; - } else if (node_num == -1UL) { - pr_err("ramster: disabling all remotification, " - "data may still reside on remote nodes however\n"); - return -EINVAL; - } else if (node_num >= MANUAL_NODES) { - pr_err("ramster: bad node_num=%lu?\n", node_num); - return -EINVAL; - } else if (!ramster_nodes_manual_up[node_num]) { - pr_err("ramster: node %d not up, ignoring setting " - "of remotification target\n", (int)node_num); - } else if (r2net_remote_target_node_set((int)node_num) >= 0) { - pr_info("ramster: node %d set as remotification target\n", - (int)node_num); - ramster_remote_target_nodenum = (int)node_num; - } else { - pr_err("ramster: bad num to node node_num=%d?\n", - (int)node_num); - return -EINVAL; + struct tmem_handle th[2]; + int ret = -ENOMEM; + int nzbuds, unuse_ret; + unsigned type; + struct page *newpage1 = NULL, *newpage2 = NULL; + struct page *evictpage1 = NULL, *evictpage2 = NULL; + pgoff_t offset; + + newpage1 = alloc_page(ZCACHE_GFP_MASK); + newpage2 = alloc_page(ZCACHE_GFP_MASK); + if (newpage1 == NULL) + evictpage1 = zcache_evict_eph_pageframe(); + if (newpage2 == NULL) + evictpage2 = zcache_evict_eph_pageframe(); + if (evictpage1 == NULL || evictpage2 == NULL) + goto free_and_out; + /* ok, we have two pages pre-allocated */ + nzbuds = zbud_make_zombie_lru(&th[0], NULL, NULL, false); + if (nzbuds == 0) { + ret = -ENOENT; + goto free_and_out; + } + unswiz(th[0].oid, th[0].index, &type, &offset); + unuse_ret = frontswap_unuse(type, offset, + newpage1 != NULL ? newpage1 : evictpage1, + ZCACHE_GFP_MASK); + if (unuse_ret != 0) + goto free_and_out; + else if (evictpage1 != NULL) + zcache_unacct_page(); + newpage1 = NULL; + evictpage1 = NULL; + if (nzbuds == 2) { + unswiz(th[1].oid, th[1].index, &type, &offset); + unuse_ret = frontswap_unuse(type, offset, + newpage2 != NULL ? newpage2 : evictpage2, + ZCACHE_GFP_MASK); + if (unuse_ret != 0) { + goto free_and_out; + } else if (evictpage2 != NULL) { + zcache_unacct_page(); + } } - return count; + ret = 0; + goto out; + +free_and_out: + if (newpage1 != NULL) + __free_page(newpage1); + if (newpage2 != NULL) + __free_page(newpage2); + if (evictpage1 != NULL) + zcache_free_page(evictpage1); + if (evictpage2 != NULL) + zcache_free_page(evictpage2); +out: + return ret; } +#endif -static struct kobj_attribute ramster_remote_target_nodenum_attr = { - .attr = { .name = "remote_target_nodenum", .mode = 0644 }, - .show = ramster_remote_target_nodenum_show, - .store = ramster_remote_target_nodenum_store, -}; - - -static struct attribute *ramster_attrs[] = { - &ramster_interface_revision_attr.attr, - &ramster_pers_remotify_enable_attr.attr, - &ramster_eph_remotify_enable_attr.attr, - &ramster_remote_pers_pages_attr.attr, - &ramster_eph_pages_remoted_attr.attr, - &ramster_eph_pages_remote_failed_attr.attr, - &ramster_pers_pages_remoted_attr.attr, - &ramster_pers_pages_remote_failed_attr.attr, - &ramster_pers_pages_remote_nomem_attr.attr, - &ramster_remote_pages_flushed_attr.attr, - &ramster_remote_page_flushes_failed_attr.attr, - &ramster_remote_objects_flushed_attr.attr, - &ramster_remote_object_flushes_failed_attr.attr, - &ramster_remote_eph_pages_succ_get_attr.attr, - &ramster_remote_eph_pages_unsucc_get_attr.attr, - &ramster_remote_pers_pages_succ_get_attr.attr, - &ramster_remote_pers_pages_unsucc_get_attr.attr, - &ramster_foreign_eph_pampd_count_attr.attr, - &ramster_foreign_eph_pampd_count_max_attr.attr, - &ramster_foreign_pers_pampd_count_attr.attr, - &ramster_foreign_pers_pampd_count_max_attr.attr, - &ramster_curr_flnode_count_attr.attr, - &ramster_curr_flnode_count_max_attr.attr, - &ramster_manual_node_up_attr.attr, - &ramster_remote_target_nodenum_attr.attr, - NULL, -}; - -static struct attribute_group ramster_attr_group = { - .attrs = ramster_attrs, - .name = "ramster", -}; - -#endif /* CONFIG_SYSFS */ /* * When zcache is disabled ("frozen"), pools can be created and destroyed, * but all puts (and thus all other operations that require memory allocation) @@ -2589,23 +1050,74 @@ static struct attribute_group ramster_attr_group = { static bool zcache_freeze; /* - * zcache shrinker interface (only useful for ephemeral pages, so zbud only) + * This zcache shrinker interface reduces the number of ephemeral pageframes + * used by zcache to approximately the same as the total number of LRU_FILE + * pageframes in use. */ static int shrink_zcache_memory(struct shrinker *shrink, struct shrink_control *sc) { + static bool in_progress; int ret = -1; int nr = sc->nr_to_scan; - gfp_t gfp_mask = sc->gfp_mask; + int nr_evict = 0; + int nr_unuse = 0; + struct page *page; +#ifdef FRONTSWAP_HAS_UNUSE + int unuse_ret; +#endif - if (nr >= 0) { - if (!(gfp_mask & __GFP_FS)) - /* does this case really need to be skipped? */ - goto out; - zbud_evict_pages(nr); + if (nr <= 0) + goto skip_evict; + + /* don't allow more than one eviction thread at a time */ + if (in_progress) + goto skip_evict; + + in_progress = true; + + /* we are going to ignore nr, and target a different value */ + zcache_last_active_file_pageframes = + global_page_state(NR_LRU_BASE + LRU_ACTIVE_FILE); + zcache_last_inactive_file_pageframes = + global_page_state(NR_LRU_BASE + LRU_INACTIVE_FILE); + nr_evict = zcache_eph_pageframes - zcache_last_active_file_pageframes + + zcache_last_inactive_file_pageframes; + while (nr_evict-- > 0) { + page = zcache_evict_eph_pageframe(); + if (page == NULL) + break; + zcache_free_page(page); + } + + zcache_last_active_anon_pageframes = + global_page_state(NR_LRU_BASE + LRU_ACTIVE_ANON); + zcache_last_inactive_anon_pageframes = + global_page_state(NR_LRU_BASE + LRU_INACTIVE_ANON); + nr_unuse = zcache_pers_pageframes - zcache_last_active_anon_pageframes + + zcache_last_inactive_anon_pageframes; +#ifdef FRONTSWAP_HAS_UNUSE + /* rate limit for testing */ + if (nr_unuse > 32) + nr_unuse = 32; + while (nr_unuse-- > 0) { + unuse_ret = zcache_frontswap_unuse(); + if (unuse_ret == -ENOMEM) + break; } - ret = (int)atomic_read(&zcache_zbud_curr_raw_pages); -out: +#endif + in_progress = false; + +skip_evict: + /* resample: has changed, but maybe not all the way yet */ + zcache_last_active_file_pageframes = + global_page_state(NR_LRU_BASE + LRU_ACTIVE_FILE); + zcache_last_inactive_file_pageframes = + global_page_state(NR_LRU_BASE + LRU_INACTIVE_FILE); + ret = zcache_eph_pageframes - zcache_last_active_file_pageframes + + zcache_last_inactive_file_pageframes; + if (ret < 0) + ret = 0; return ret; } @@ -2618,30 +1130,46 @@ static struct shrinker zcache_shrinker = { * zcache shims between cleancache/frontswap ops and tmem */ -int zcache_put(int cli_id, int pool_id, struct tmem_oid *oidp, - uint32_t index, char *data, size_t size, - bool raw, int ephemeral) +/* FIXME rename these core routines to zcache_tmemput etc? */ +int zcache_put_page(int cli_id, int pool_id, struct tmem_oid *oidp, + uint32_t index, void *page, + unsigned int size, bool raw, int ephemeral) { struct tmem_pool *pool; + struct tmem_handle th; int ret = -1; + void *pampd = NULL; BUG_ON(!irqs_disabled()); pool = zcache_get_pool_by_id(cli_id, pool_id); if (unlikely(pool == NULL)) goto out; - if (!zcache_freeze && zcache_do_preload(pool) == 0) { - /* preload does preempt_disable on success */ - ret = tmem_put(pool, oidp, index, data, size, raw, ephemeral); - if (ret < 0) { - if (is_ephemeral(pool)) + if (!zcache_freeze) { + ret = 0; + th.client_id = cli_id; + th.pool_id = pool_id; + th.oid = *oidp; + th.index = index; + pampd = zcache_pampd_create((char *)page, size, raw, + ephemeral, &th); + if (pampd == NULL) { + ret = -ENOMEM; + if (ephemeral) zcache_failed_eph_puts++; else zcache_failed_pers_puts++; + } else { + if (ramster_enabled) + ramster_do_preload_flnode(pool); + ret = tmem_put(pool, oidp, index, 0, pampd); + if (ret < 0) + BUG(); } zcache_put_pool(pool); - preempt_enable_no_resched(); } else { zcache_put_to_flush++; + if (ramster_enabled) + ramster_do_preload_flnode(pool); if (atomic_read(&pool->obj_count) > 0) /* the put fails whether the flush succeeds or not */ (void)tmem_flush_page(pool, oidp, index); @@ -2651,9 +1179,9 @@ out: return ret; } -int zcache_get(int cli_id, int pool_id, struct tmem_oid *oidp, - uint32_t index, char *data, size_t *sizep, - bool raw, int get_and_free) +int zcache_get_page(int cli_id, int pool_id, struct tmem_oid *oidp, + uint32_t index, void *page, + size_t *sizep, bool raw, int get_and_free) { struct tmem_pool *pool; int ret = -1; @@ -2667,22 +1195,21 @@ int zcache_get(int cli_id, int pool_id, struct tmem_oid *oidp, eph = is_ephemeral(pool); if (likely(pool != NULL)) { if (atomic_read(&pool->obj_count) > 0) - ret = tmem_get(pool, oidp, index, data, sizep, - raw, get_and_free); + ret = tmem_get(pool, oidp, index, (char *)(page), + sizep, raw, get_and_free); zcache_put_pool(pool); } - WARN_ONCE((!eph && (ret != 0)), "zcache_get fails on persistent pool, " - "bad things are very likely to happen soon\n"); + WARN_ONCE((!is_ephemeral(pool) && (ret != 0)), + "zcache_get fails on persistent pool, " + "bad things are very likely to happen soon\n"); #ifdef RAMSTER_TESTING if (ret != 0 && ret != -1 && !(ret == -EINVAL && is_ephemeral(pool))) pr_err("TESTING zcache_get tmem_get returns ret=%d\n", ret); #endif - if (ret == -EAGAIN) - BUG(); /* FIXME... don't need this anymore??? let's ensure */ return ret; } -int zcache_flush(int cli_id, int pool_id, +int zcache_flush_page(int cli_id, int pool_id, struct tmem_oid *oidp, uint32_t index) { struct tmem_pool *pool; @@ -2692,7 +1219,8 @@ int zcache_flush(int cli_id, int pool_id, local_irq_save(flags); zcache_flush_total++; pool = zcache_get_pool_by_id(cli_id, pool_id); - ramster_do_preload_flnode_only(pool); + if (ramster_enabled) + ramster_do_preload_flnode(pool); if (likely(pool != NULL)) { if (atomic_read(&pool->obj_count) > 0) ret = tmem_flush_page(pool, oidp, index); @@ -2704,7 +1232,8 @@ int zcache_flush(int cli_id, int pool_id, return ret; } -int zcache_flush_object(int cli_id, int pool_id, struct tmem_oid *oidp) +int zcache_flush_object(int cli_id, int pool_id, + struct tmem_oid *oidp) { struct tmem_pool *pool; int ret = -1; @@ -2713,7 +1242,8 @@ int zcache_flush_object(int cli_id, int pool_id, struct tmem_oid *oidp) local_irq_save(flags); zcache_flobj_total++; pool = zcache_get_pool_by_id(cli_id, pool_id); - ramster_do_preload_flnode_only(pool); + if (ramster_enabled) + ramster_do_preload_flnode(pool); if (likely(pool != NULL)) { if (atomic_read(&pool->obj_count) > 0) ret = tmem_flush_object(pool, oidp); @@ -2725,7 +1255,7 @@ int zcache_flush_object(int cli_id, int pool_id, struct tmem_oid *oidp) return ret; } -int zcache_client_destroy_pool(int cli_id, int pool_id) +static int zcache_client_destroy_pool(int cli_id, int pool_id) { struct tmem_pool *pool = NULL; struct zcache_client *cli = NULL; @@ -2752,16 +1282,15 @@ int zcache_client_destroy_pool(int cli_id, int pool_id) ret = tmem_destroy_pool(pool); local_bh_enable(); kfree(pool); - pr_info("ramster: destroyed pool id=%d cli_id=%d\n", pool_id, cli_id); + if (cli_id == LOCAL_CLIENT) + pr_info("%s: destroyed local pool id=%d\n", namestr, pool_id); + else + pr_info("%s: destroyed pool id=%d, client=%d\n", + namestr, pool_id, cli_id); out: return ret; } -static int zcache_destroy_pool(int pool_id) -{ - return zcache_client_destroy_pool(LOCAL_CLIENT, pool_id); -} - int zcache_new_pool(uint16_t cli_id, uint32_t flags) { int poolid = -1; @@ -2777,7 +1306,7 @@ int zcache_new_pool(uint16_t cli_id, uint32_t flags) atomic_inc(&cli->refcount); pool = kmalloc(sizeof(struct tmem_pool), GFP_ATOMIC); if (pool == NULL) { - pr_info("ramster: pool creation failed: out of memory\n"); + pr_info("%s: pool creation failed: out of memory\n", namestr); goto out; } @@ -2785,7 +1314,7 @@ int zcache_new_pool(uint16_t cli_id, uint32_t flags) if (cli->tmem_pools[poolid] == NULL) break; if (poolid >= MAX_POOLS_PER_CLIENT) { - pr_info("ramster: pool creation failed: max exceeded\n"); + pr_info("%s: pool creation failed: max exceeded\n", namestr); kfree(pool); poolid = -1; goto out; @@ -2796,11 +1325,11 @@ int zcache_new_pool(uint16_t cli_id, uint32_t flags) tmem_new_pool(pool, flags); cli->tmem_pools[poolid] = pool; if (cli_id == LOCAL_CLIENT) - pr_info("ramster: created %s tmem pool, id=%d, local client\n", + pr_info("%s: created %s local tmem pool, id=%d\n", namestr, flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral", poolid); else - pr_info("ramster: created %s tmem pool, id=%d, client=%d\n", + pr_info("%s: created %s tmem pool, id=%d, client=%d\n", namestr, flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral", poolid, cli_id); out: @@ -2814,30 +1343,37 @@ static int zcache_local_new_pool(uint32_t flags) return zcache_new_pool(LOCAL_CLIENT, flags); } -int zcache_autocreate_pool(int cli_id, int pool_id, bool ephemeral) +int zcache_autocreate_pool(unsigned int cli_id, unsigned int pool_id, bool eph) { struct tmem_pool *pool; - struct zcache_client *cli = NULL; - uint32_t flags = ephemeral ? 0 : TMEM_POOL_PERSIST; + struct zcache_client *cli; + uint32_t flags = eph ? 0 : TMEM_POOL_PERSIST; int ret = -1; + BUG_ON(!ramster_enabled); if (cli_id == LOCAL_CLIENT) goto out; if (pool_id >= MAX_POOLS_PER_CLIENT) goto out; - else if ((unsigned int)cli_id < MAX_CLIENTS) - cli = &zcache_clients[cli_id]; - if ((ephemeral && !use_cleancache) || (!ephemeral && !use_frontswap)) - BUG(); /* FIXME, handle more gracefully later */ + if (cli_id >= MAX_CLIENTS) + goto out; + + cli = &zcache_clients[cli_id]; + if ((eph && disable_cleancache) || (!eph && disable_frontswap)) { + pr_err("zcache_autocreate_pool: pool type disabled\n"); + goto out; + } if (!cli->allocated) { - if (zcache_new_client(cli_id)) - BUG(); /* FIXME, handle more gracefully later */ + if (zcache_new_client(cli_id)) { + pr_err("zcache_autocreate_pool: can't create client\n"); + goto out; + } cli = &zcache_clients[cli_id]; } atomic_inc(&cli->refcount); pool = cli->tmem_pools[pool_id]; if (pool != NULL) { - if (pool->persistent && ephemeral) { + if (pool->persistent && eph) { pr_err("zcache_autocreate_pool: type mismatch\n"); goto out; } @@ -2846,7 +1382,7 @@ int zcache_autocreate_pool(int cli_id, int pool_id, bool ephemeral) } pool = kmalloc(sizeof(struct tmem_pool), GFP_KERNEL); if (pool == NULL) { - pr_info("ramster: pool creation failed: out of memory\n"); + pr_info("%s: pool creation failed: out of memory\n", namestr); goto out; } atomic_set(&pool->refcount, 0); @@ -2854,14 +1390,11 @@ int zcache_autocreate_pool(int cli_id, int pool_id, bool ephemeral) pool->pool_id = pool_id; tmem_new_pool(pool, flags); cli->tmem_pools[pool_id] = pool; - pr_info("ramster: AUTOcreated %s tmem poolid=%d, for remote client=%d\n", - flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral", + pr_info("%s: AUTOcreated %s tmem poolid=%d, for remote client=%d\n", + namestr, flags & TMEM_POOL_PERSIST ? "persistent" : "ephemeral", pool_id, cli_id); ret = 0; out: - if (cli == NULL) - BUG(); /* FIXME, handle more gracefully later */ - /* pr_err("zcache_autocreate_pool: failed\n"); */ if (cli != NULL) atomic_dec(&cli->refcount); return ret; @@ -2875,7 +1408,6 @@ out: * to translate in-kernel semantics to zcache semantics. */ -#ifdef CONFIG_CLEANCACHE static void zcache_cleancache_put_page(int pool_id, struct cleancache_filekey key, pgoff_t index, struct page *page) @@ -2883,18 +1415,13 @@ static void zcache_cleancache_put_page(int pool_id, u32 ind = (u32) index; struct tmem_oid oid = *(struct tmem_oid *)&key; -#ifdef __PG_WAS_ACTIVE - if (!PageWasActive(page)) { - zcache_nonactive_puts++; + if (!disable_cleancache_ignore_nonactive && !PageWasActive(page)) { + zcache_eph_nonactive_puts_ignored++; return; } -#endif - if (likely(ind == index)) { - char *kva = page_address(page); - - (void)zcache_put(LOCAL_CLIENT, pool_id, &oid, index, - kva, PAGE_SIZE, 0, 1); - } + if (likely(ind == index)) + (void)zcache_put_page(LOCAL_CLIENT, pool_id, &oid, index, + page, PAGE_SIZE, false, 1); } static int zcache_cleancache_get_page(int pool_id, @@ -2903,21 +1430,16 @@ static int zcache_cleancache_get_page(int pool_id, { u32 ind = (u32) index; struct tmem_oid oid = *(struct tmem_oid *)&key; + size_t size; int ret = -1; - preempt_disable(); if (likely(ind == index)) { - char *kva = page_address(page); - size_t size = PAGE_SIZE; - - ret = zcache_get(LOCAL_CLIENT, pool_id, &oid, index, - kva, &size, 0, 0); -#ifdef __PG_WAS_ACTIVE + ret = zcache_get_page(LOCAL_CLIENT, pool_id, &oid, index, + page, &size, false, 0); + BUG_ON(ret >= 0 && size != PAGE_SIZE); if (ret == 0) SetPageWasActive(page); -#endif } - preempt_enable(); return ret; } @@ -2929,7 +1451,7 @@ static void zcache_cleancache_flush_page(int pool_id, struct tmem_oid oid = *(struct tmem_oid *)&key; if (likely(ind == index)) - (void)zcache_flush(LOCAL_CLIENT, pool_id, &oid, ind); + (void)zcache_flush_page(LOCAL_CLIENT, pool_id, &oid, ind); } static void zcache_cleancache_flush_inode(int pool_id, @@ -2943,7 +1465,7 @@ static void zcache_cleancache_flush_inode(int pool_id, static void zcache_cleancache_flush_fs(int pool_id) { if (pool_id >= 0) - (void)zcache_destroy_pool(pool_id); + (void)zcache_client_destroy_pool(LOCAL_CLIENT, pool_id); } static int zcache_cleancache_init_fs(size_t pagesize) @@ -2980,15 +1502,15 @@ struct cleancache_ops zcache_cleancache_register_ops(void) return old_ops; } -#endif -#ifdef CONFIG_FRONTSWAP /* a single tmem poolid is used for all frontswap "types" (swapfiles) */ -static int zcache_frontswap_poolid = -1; +static int zcache_frontswap_poolid __read_mostly = -1; /* * Swizzling increases objects per swaptype, increasing tmem concurrency * for heavy swaploads. Later, larger nr_cpus -> larger SWIZ_BITS + * Setting SWIZ_BITS to 27 basically reconstructs the swap entry from + * frontswap_get_page(), but has side-effects. Hence using 8. */ #define SWIZ_BITS 8 #define SWIZ_MASK ((1 << SWIZ_BITS) - 1) @@ -3002,47 +1524,64 @@ static inline struct tmem_oid oswiz(unsigned type, u32 ind) return oid; } -static int zcache_frontswap_store(unsigned type, pgoff_t offset, - struct page *page) +#ifdef FRONTSWAP_HAS_UNUSE +static void unswiz(struct tmem_oid oid, u32 index, + unsigned *type, pgoff_t *offset) +{ + *type = (unsigned)(oid.oid[0] >> SWIZ_BITS); + *offset = (pgoff_t)((index << SWIZ_BITS) | + (oid.oid[0] & SWIZ_MASK)); +} +#endif + +static int zcache_frontswap_put_page(unsigned type, pgoff_t offset, + struct page *page) { u64 ind64 = (u64)offset; u32 ind = (u32)offset; struct tmem_oid oid = oswiz(type, ind); int ret = -1; unsigned long flags; - char *kva; BUG_ON(!PageLocked(page)); + if (!disable_frontswap_ignore_nonactive && !PageWasActive(page)) { + zcache_pers_nonactive_puts_ignored++; + ret = -ERANGE; + goto out; + } if (likely(ind64 == ind)) { local_irq_save(flags); - kva = page_address(page); - ret = zcache_put(LOCAL_CLIENT, zcache_frontswap_poolid, - &oid, iswiz(ind), kva, PAGE_SIZE, 0, 0); + ret = zcache_put_page(LOCAL_CLIENT, zcache_frontswap_poolid, + &oid, iswiz(ind), + page, PAGE_SIZE, false, 0); local_irq_restore(flags); } +out: return ret; } /* returns 0 if the page was successfully gotten from frontswap, -1 if * was not present (should never happen!) */ -static int zcache_frontswap_load(unsigned type, pgoff_t offset, - struct page *page) +static int zcache_frontswap_get_page(unsigned type, pgoff_t offset, + struct page *page) { u64 ind64 = (u64)offset; u32 ind = (u32)offset; struct tmem_oid oid = oswiz(type, ind); - int ret = -1; + size_t size; + int ret = -1, get_and_free; - preempt_disable(); /* FIXME, remove this? */ + if (frontswap_has_exclusive_gets) + get_and_free = 1; + else + get_and_free = -1; BUG_ON(!PageLocked(page)); if (likely(ind64 == ind)) { - char *kva = page_address(page); - size_t size = PAGE_SIZE; - - ret = zcache_get(LOCAL_CLIENT, zcache_frontswap_poolid, - &oid, iswiz(ind), kva, &size, 0, -1); + ret = zcache_get_page(LOCAL_CLIENT, zcache_frontswap_poolid, + &oid, iswiz(ind), + page, &size, false, get_and_free); + BUG_ON(ret >= 0 && size != PAGE_SIZE); } - preempt_enable(); /* FIXME, remove this? */ return ret; } @@ -3054,7 +1593,7 @@ static void zcache_frontswap_flush_page(unsigned type, pgoff_t offset) struct tmem_oid oid = oswiz(type, ind); if (likely(ind64 == ind)) - (void)zcache_flush(LOCAL_CLIENT, zcache_frontswap_poolid, + (void)zcache_flush_page(LOCAL_CLIENT, zcache_frontswap_poolid, &oid, iswiz(ind)); } @@ -3076,12 +1615,12 @@ static void zcache_frontswap_init(unsigned ignored) /* a single tmem poolid is used for all frontswap "types" (swapfiles) */ if (zcache_frontswap_poolid < 0) zcache_frontswap_poolid = - zcache_local_new_pool(TMEM_POOL_PERSIST); + zcache_local_new_pool(TMEM_POOL_PERSIST); } static struct frontswap_ops zcache_frontswap_ops = { - .store = zcache_frontswap_store, - .load = zcache_frontswap_load, + .store = zcache_frontswap_put_page, + .load = zcache_frontswap_get_page, .invalidate_page = zcache_frontswap_flush_page, .invalidate_area = zcache_frontswap_flush_area, .init = zcache_frontswap_init @@ -3094,179 +1633,135 @@ struct frontswap_ops zcache_frontswap_register_ops(void) return old_ops; } -#endif /* - * frontswap selfshrinking - */ - -#ifdef CONFIG_FRONTSWAP -/* In HZ, controls frequency of worker invocation. */ -static unsigned int selfshrink_interval __read_mostly = 5; - -static void selfshrink_process(struct work_struct *work); -static DECLARE_DELAYED_WORK(selfshrink_worker, selfshrink_process); - -/* Enable/disable with sysfs. */ -static bool frontswap_selfshrinking __read_mostly; - -/* Enable/disable with kernel boot option. */ -static bool use_frontswap_selfshrink __initdata = true; - -/* - * The default values for the following parameters were deemed reasonable - * by experimentation, may be workload-dependent, and can all be - * adjusted via sysfs. - */ - -/* Control rate for frontswap shrinking. Higher hysteresis is slower. */ -static unsigned int frontswap_hysteresis __read_mostly = 20; - -/* - * Number of selfshrink worker invocations to wait before observing that - * frontswap selfshrinking should commence. Note that selfshrinking does - * not use a separate worker thread. + * zcache initialization + * NOTE FOR NOW zcache or ramster MUST BE PROVIDED AS A KERNEL BOOT PARAMETER + * OR NOTHING HAPPENS! */ -static unsigned int frontswap_inertia __read_mostly = 3; -/* Countdown to next invocation of frontswap_shrink() */ -static unsigned long frontswap_inertia_counter; - -/* - * Invoked by the selfshrink worker thread, uses current number of pages - * in frontswap (frontswap_curr_pages()), previous status, and control - * values (hysteresis and inertia) to determine if frontswap should be - * shrunk and what the new frontswap size should be. Note that - * frontswap_shrink is essentially a partial swapoff that immediately - * transfers pages from the "swap device" (frontswap) back into kernel - * RAM; despite the name, frontswap "shrinking" is very different from - * the "shrinker" interface used by the kernel MM subsystem to reclaim - * memory. - */ -static void frontswap_selfshrink(void) +static int __init enable_zcache(char *s) { - static unsigned long cur_frontswap_pages; - static unsigned long last_frontswap_pages; - static unsigned long tgt_frontswap_pages; - - last_frontswap_pages = cur_frontswap_pages; - cur_frontswap_pages = frontswap_curr_pages(); - if (!cur_frontswap_pages || - (cur_frontswap_pages > last_frontswap_pages)) { - frontswap_inertia_counter = frontswap_inertia; - return; - } - if (frontswap_inertia_counter && --frontswap_inertia_counter) - return; - if (cur_frontswap_pages <= frontswap_hysteresis) - tgt_frontswap_pages = 0; - else - tgt_frontswap_pages = cur_frontswap_pages - - (cur_frontswap_pages / frontswap_hysteresis); - frontswap_shrink(tgt_frontswap_pages); + zcache_enabled = 1; + return 1; } +__setup("zcache", enable_zcache); -static int __init ramster_nofrontswap_selfshrink_setup(char *s) +static int __init enable_ramster(char *s) { - use_frontswap_selfshrink = false; + zcache_enabled = 1; +#ifdef CONFIG_RAMSTER + ramster_enabled = 1; +#endif return 1; } +__setup("ramster", enable_ramster); -__setup("noselfshrink", ramster_nofrontswap_selfshrink_setup); +/* allow independent dynamic disabling of cleancache and frontswap */ -static void selfshrink_process(struct work_struct *work) +static int __init no_cleancache(char *s) { - if (frontswap_selfshrinking && frontswap_enabled) { - frontswap_selfshrink(); - schedule_delayed_work(&selfshrink_worker, - selfshrink_interval * HZ); - } + disable_cleancache = 1; + return 1; } -static int ramster_enabled; +__setup("nocleancache", no_cleancache); -static int __init ramster_selfshrink_init(void) +static int __init no_frontswap(char *s) { - frontswap_selfshrinking = ramster_enabled && use_frontswap_selfshrink; - if (frontswap_selfshrinking) - pr_info("ramster: Initializing frontswap " - "selfshrinking driver.\n"); - else - return -ENODEV; - - schedule_delayed_work(&selfshrink_worker, selfshrink_interval * HZ); - - return 0; + disable_frontswap = 1; + return 1; } -subsys_initcall(ramster_selfshrink_init); -#endif +__setup("nofrontswap", no_frontswap); -/* - * zcache initialization - * NOTE FOR NOW ramster MUST BE PROVIDED AS A KERNEL BOOT PARAMETER OR - * NOTHING HAPPENS! - */ +static int __init no_frontswap_exclusive_gets(char *s) +{ + frontswap_has_exclusive_gets = false; + return 1; +} -static int ramster_enabled; +__setup("nofrontswapexclusivegets", no_frontswap_exclusive_gets); -static int __init enable_ramster(char *s) +static int __init no_frontswap_ignore_nonactive(char *s) { - ramster_enabled = 1; + disable_frontswap_ignore_nonactive = 1; return 1; } -__setup("ramster", enable_ramster); -/* allow independent dynamic disabling of cleancache and frontswap */ +__setup("nofrontswapignorenonactive", no_frontswap_ignore_nonactive); -static int use_cleancache = 1; - -static int __init no_cleancache(char *s) +static int __init no_cleancache_ignore_nonactive(char *s) { - pr_info("INIT no_cleancache called\n"); - use_cleancache = 0; + disable_cleancache_ignore_nonactive = 1; return 1; } -/* - * FIXME: need to guarantee this gets checked before zcache_init is called - * What is the correct way to achieve this? - */ -early_param("nocleancache", no_cleancache); - -static int use_frontswap = 1; +__setup("nocleancacheignorenonactive", no_cleancache_ignore_nonactive); -static int __init no_frontswap(char *s) +static int __init enable_zcache_compressor(char *s) { - pr_info("INIT no_frontswap called\n"); - use_frontswap = 0; + strncpy(zcache_comp_name, s, ZCACHE_COMP_NAME_SZ); + zcache_enabled = 1; return 1; } +__setup("zcache=", enable_zcache_compressor); -__setup("nofrontswap", no_frontswap); -static int __init zcache_init(void) +static int __init zcache_comp_init(void) { int ret = 0; -#ifdef CONFIG_SYSFS - ret = sysfs_create_group(mm_kobj, &zcache_attr_group); - ret = sysfs_create_group(mm_kobj, &ramster_attr_group); - if (ret) { - pr_err("ramster: can't create sysfs\n"); + /* check crypto algorithm */ + if (*zcache_comp_name != '\0') { + ret = crypto_has_comp(zcache_comp_name, 0, 0); + if (!ret) + pr_info("zcache: %s not supported\n", + zcache_comp_name); + } + if (!ret) + strcpy(zcache_comp_name, "lzo"); + ret = crypto_has_comp(zcache_comp_name, 0, 0); + if (!ret) { + ret = 1; goto out; } -#endif /* CONFIG_SYSFS */ -#if defined(CONFIG_CLEANCACHE) || defined(CONFIG_FRONTSWAP) + pr_info("zcache: using %s compressor\n", zcache_comp_name); + + /* alloc percpu transforms */ + ret = 0; + zcache_comp_pcpu_tfms = alloc_percpu(struct crypto_comp *); + if (!zcache_comp_pcpu_tfms) + ret = 1; +out: + return ret; +} + +static int __init zcache_init(void) +{ + int ret = 0; + if (ramster_enabled) { + namestr = "ramster"; + ramster_register_pamops(&zcache_pamops); + } +#ifdef CONFIG_DEBUG_FS + zcache_debugfs_init(); +#endif + if (zcache_enabled) { unsigned int cpu; - (void)r2net_register_handlers(); tmem_register_hostops(&zcache_hostops); tmem_register_pamops(&zcache_pamops); ret = register_cpu_notifier(&zcache_cpu_notifier_block); if (ret) { - pr_err("ramster: can't register cpu notifier\n"); + pr_err("%s: can't register cpu notifier\n", namestr); + goto out; + } + ret = zcache_comp_init(); + if (ret) { + pr_err("%s: compressor initialization failed\n", + namestr); goto out; } for_each_online_cpu(cpu) { @@ -3279,42 +1774,47 @@ static int __init zcache_init(void) sizeof(struct tmem_objnode), 0, 0, NULL); zcache_obj_cache = kmem_cache_create("zcache_obj", sizeof(struct tmem_obj), 0, 0, NULL); - ramster_flnode_cache = kmem_cache_create("ramster_flnode", - sizeof(struct flushlist_node), 0, 0, NULL); -#endif -#ifdef CONFIG_CLEANCACHE - pr_info("INIT ramster_enabled=%d use_cleancache=%d\n", - ramster_enabled, use_cleancache); - if (ramster_enabled && use_cleancache) { + ret = zcache_new_client(LOCAL_CLIENT); + if (ret) { + pr_err("%s: can't create client\n", namestr); + goto out; + } + zbud_init(); + if (zcache_enabled && !disable_cleancache) { struct cleancache_ops old_ops; - zbud_init(); register_shrinker(&zcache_shrinker); old_ops = zcache_cleancache_register_ops(); - pr_info("ramster: cleancache enabled using kernel " - "transcendent memory and compression buddies\n"); + pr_info("%s: cleancache enabled using kernel transcendent " + "memory and compression buddies\n", namestr); +#ifdef ZCACHE_DEBUG + pr_info("%s: cleancache: ignorenonactive = %d\n", + namestr, !disable_cleancache_ignore_nonactive); +#endif if (old_ops.init_fs != NULL) - pr_warning("ramster: cleancache_ops overridden"); + pr_warn("%s: cleancache_ops overridden\n", namestr); } -#endif -#ifdef CONFIG_FRONTSWAP - pr_info("INIT ramster_enabled=%d use_frontswap=%d\n", - ramster_enabled, use_frontswap); - if (ramster_enabled && use_frontswap) { + if (zcache_enabled && !disable_frontswap) { struct frontswap_ops old_ops; - zcache_new_client(LOCAL_CLIENT); old_ops = zcache_frontswap_register_ops(); - pr_info("ramster: frontswap enabled using kernel " - "transcendent memory and xvmalloc\n"); + if (frontswap_has_exclusive_gets) + frontswap_tmem_exclusive_gets(true); + pr_info("%s: frontswap enabled using kernel transcendent " + "memory and compression buddies\n", namestr); +#ifdef ZCACHE_DEBUG + pr_info("%s: frontswap: excl gets = %d active only = %d\n", + namestr, frontswap_has_exclusive_gets, + !disable_frontswap_ignore_nonactive); +#endif if (old_ops.init != NULL) - pr_warning("ramster: frontswap_ops overridden"); + pr_warn("%s: frontswap_ops overridden\n", namestr); } - if (ramster_enabled && (use_frontswap || use_cleancache)) - ramster_remotify_init(); -#endif + if (ramster_enabled) + ramster_init(!disable_cleancache, !disable_frontswap, + frontswap_has_exclusive_gets); out: return ret; } -module_init(zcache_init) +late_initcall(zcache_init); diff --git a/drivers/staging/ramster/zcache.h b/drivers/staging/ramster/zcache.h index 250b121c22e5..81722b33b087 100644 --- a/drivers/staging/ramster/zcache.h +++ b/drivers/staging/ramster/zcache.h @@ -1,22 +1,53 @@ + /* * zcache.h * - * External zcache functions - * - * Copyright (c) 2009-2012, Dan Magenheimer, Oracle Corp. + * Copyright (c) 2012, Dan Magenheimer, Oracle Corp. */ #ifndef _ZCACHE_H_ #define _ZCACHE_H_ -extern int zcache_put(int, int, struct tmem_oid *, uint32_t, - char *, size_t, bool, int); -extern int zcache_autocreate_pool(int, int, bool); -extern int zcache_get(int, int, struct tmem_oid *, uint32_t, - char *, size_t *, bool, int); -extern int zcache_flush(int, int, struct tmem_oid *, uint32_t); +struct zcache_preload { + struct tmem_obj *obj; + struct tmem_objnode *objnodes[OBJNODE_TREE_MAX_PATH]; +}; + +struct tmem_pool; + +#define MAX_POOLS_PER_CLIENT 16 + +#define MAX_CLIENTS 16 +#define LOCAL_CLIENT ((uint16_t)-1) + +struct zcache_client { + struct tmem_pool *tmem_pools[MAX_POOLS_PER_CLIENT]; + bool allocated; + atomic_t refcount; +}; + +extern struct tmem_pool *zcache_get_pool_by_id(uint16_t cli_id, + uint16_t poolid); +extern void zcache_put_pool(struct tmem_pool *pool); + +extern int zcache_put_page(int, int, struct tmem_oid *, + uint32_t, void *, + unsigned int, bool, int); +extern int zcache_get_page(int, int, struct tmem_oid *, uint32_t, + void *, size_t *, bool, int); +extern int zcache_flush_page(int, int, struct tmem_oid *, uint32_t); extern int zcache_flush_object(int, int, struct tmem_oid *); -extern int zcache_localify(int, struct tmem_oid *, uint32_t, - char *, size_t, void *); +extern void zcache_decompress_to_page(char *, unsigned int, struct page *); + +#ifdef CONFIG_RAMSTER +extern void *zcache_pampd_create(char *, unsigned int, bool, int, + struct tmem_handle *); +int zcache_autocreate_pool(unsigned int cli_id, unsigned int pool_id, bool eph); +#endif + +#define MAX_POOLS_PER_CLIENT 16 + +#define MAX_CLIENTS 16 +#define LOCAL_CLIENT ((uint16_t)-1) -#endif /* _ZCACHE_H */ +#endif /* _ZCACHE_H_ */ diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211.h b/drivers/staging/rtl8187se/ieee80211/ieee80211.h index b94c48b29302..5f5a30223d56 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211.h +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211.h @@ -1094,7 +1094,7 @@ struct ieee80211_device { int (*reset_port)(struct net_device *dev); - /* Softmac-generated frames (mamagement) are TXed via this + /* Softmac-generated frames (management) are TXed via this * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is * not set. As some cards may have different HW queues that * one might want to use for data and management frames diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c index 8173240dcf7a..00f9af06aca5 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c @@ -21,6 +21,7 @@ #include <linux/slab.h> #include <linux/interrupt.h> #include <asm/uaccess.h> +#include <linux/etherdevice.h> #include "dot11d.h" u8 rsn_authen_cipher_suite[16][4] = { @@ -2110,13 +2111,7 @@ void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee) inline void ieee80211_randomize_cell(struct ieee80211_device *ieee) { - get_random_bytes(ieee->current_network.bssid, ETH_ALEN); - - /* an IBSS cell address must have the two less significant - * bits of the first byte = 2 - */ - ieee->current_network.bssid[0] &= ~0x01; - ieee->current_network.bssid[0] |= 0x02; + random_ether_addr(ieee->current_network.bssid); } /* called in user context only */ @@ -2808,9 +2803,7 @@ static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee, param->u.crypt.key_len); return -EINVAL; } - if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && - param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && - param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { + if (is_broadcast_ether_addr(param->sta_addr)) { if (param->u.crypt.idx >= WEP_KEYS) return -EINVAL; crypt = &ieee->crypt[param->u.crypt.idx]; diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c index 5d204906baf7..1ef8fd612732 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac_wx.c @@ -14,6 +14,8 @@ */ +#include <linux/etherdevice.h> + #include "ieee80211.h" /* FIXME: add A freqs */ @@ -131,7 +133,6 @@ int ieee80211_wx_set_wap(struct ieee80211_device *ieee, { int ret = 0; - u8 zero[] = {0,0,0,0,0,0}; unsigned long flags; short ifup = ieee->proto_started;//dev->flags & IFF_UP; @@ -161,7 +162,7 @@ int ieee80211_wx_set_wap(struct ieee80211_device *ieee, spin_lock_irqsave(&ieee->lock, flags); memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN); - ieee->wap_set = memcmp(temp->sa_data, zero,ETH_ALEN)!=0; + ieee->wap_set = !is_zero_ether_addr(temp->sa_data); //printk(" %x:%x:%x:%x:%x:%x\n", ieee->current_network.bssid[0],ieee->current_network.bssid[1],ieee->current_network.bssid[2],ieee->current_network.bssid[3],ieee->current_network.bssid[4],ieee->current_network.bssid[5]); spin_unlock_irqrestore(&ieee->lock, flags); diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c index fd22b75aea4f..20e5fb58f52f 100644 --- a/drivers/staging/rtl8187se/r8180_core.c +++ b/drivers/staging/rtl8187se/r8180_core.c @@ -2377,7 +2377,7 @@ void rtl8180_wmm_param_update(struct work_struct *work) u8 u1bAIFS; u32 u4bAcParam; pAcParam = (PAC_PARAM)(&AcParam); - /* Retrieve paramters to update. */ + /* Retrieve parameters to update. */ u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime; u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit))<<AC_PARAM_TXOP_LIMIT_OFFSET)| (((u32)(pAcParam->f.Ecw.f.ECWmax))<<AC_PARAM_ECW_MAX_OFFSET)| @@ -2413,7 +2413,7 @@ void rtl8180_wmm_param_update(struct work_struct *work) u8 u1bAIFS; u32 u4bAcParam; - /* Retrieve paramters to update. */ + /* Retrieve parameters to update. */ eACI = pAcParam->f.AciAifsn.f.ACI; /* Mode G/A: slotTimeTimer = 9; Mode B: 20 */ u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * (((mode&IEEE_G) == IEEE_G) ? 9 : 20) + aSifsTime; diff --git a/drivers/staging/rtl8187se/r8180_hw.h b/drivers/staging/rtl8187se/r8180_hw.h index 3fca144a56a4..533938123a97 100644 --- a/drivers/staging/rtl8187se/r8180_hw.h +++ b/drivers/staging/rtl8187se/r8180_hw.h @@ -554,11 +554,16 @@ /* by amy for power save */ /* by amy for antenna */ #define EEPROM_SW_REVD_OFFSET 0x3f -/* BIT[8-9] is for SW Antenna Diversity. Only the value EEPROM_SW_AD_ENABLE means enable, other values are diable. */ + +/* BIT[8-9] is for SW Antenna Diversity. + * Only the value EEPROM_SW_AD_ENABLE means enable, other values are disable. + */ #define EEPROM_SW_AD_MASK 0x0300 #define EEPROM_SW_AD_ENABLE 0x0100 -/* BIT[10-11] determine if Antenna 1 is the Default Antenna. Only the value EEPROM_DEF_ANT_1 means TRUE, other values are FALSE. */ +/* BIT[10-11] determine if Antenna 1 is the Default Antenna. + * Only the value EEPROM_DEF_ANT_1 means TRUE, other values are FALSE. + */ #define EEPROM_DEF_ANT_MASK 0x0C00 #define EEPROM_DEF_ANT_1 0x0400 /*by amy for antenna */ diff --git a/drivers/staging/rtl8187se/r8185b_init.c b/drivers/staging/rtl8187se/r8185b_init.c index 914495783c06..bf343199bd21 100644 --- a/drivers/staging/rtl8187se/r8185b_init.c +++ b/drivers/staging/rtl8187se/r8185b_init.c @@ -1008,7 +1008,7 @@ void ActUpdateChannelAccessSetting(struct net_device *dev, u8 u1bAIFS; u32 u4bAcParam; - /* Retrieve paramters to update. */ + /* Retrieve parameters to update. */ eACI = pAcParam->f.AciAifsn.f.ACI; u1bAIFS = pAcParam->f.AciAifsn.f.AIFSN * ChnlAccessSetting->SlotTimeTimer + aSifsTime; u4bAcParam = ((((u32)(pAcParam->f.TXOPLimit)) << AC_PARAM_TXOP_LIMIT_OFFSET) | diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c index b526fa428679..dd2a96bfcc0c 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.c @@ -265,10 +265,11 @@ bool init_firmware(struct net_device *dev) case FW_SOURCE_IMG_FILE: { if (pfirmware->firmware_buf_size[init_step] == 0) { - const char *fw_name[3] = { "RTL8192E/boot.img", - "RTL8192E/main.img", - "RTL8192E/data.img" - }; + const char *fw_name[3] = { + RTL8192E_BOOT_IMG_FW, + RTL8192E_MAIN_IMG_FW, + RTL8192E_DATA_IMG_FW + }; const struct firmware *fw_entry; int rc; rc = request_firmware(&fw_entry, diff --git a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h index caa878833106..06d6abc8345c 100644 --- a/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h +++ b/drivers/staging/rtl8192e/rtl8192e/r8192E_firmware.h @@ -23,6 +23,10 @@ #define GET_COMMAND_PACKET_FRAG_THRESHOLD(v) (4*(v/4) - 8) +#define RTL8192E_BOOT_IMG_FW "RTL8192E/boot.img" +#define RTL8192E_MAIN_IMG_FW "RTL8192E/main.img" +#define RTL8192E_DATA_IMG_FW "RTL8192E/data.img" + enum firmware_init_step { FW_INIT_STEP0_BOOT = 0, FW_INIT_STEP1_MAIN = 1, diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c index 4f602b227b50..81134d312ee3 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_core.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_core.c @@ -734,8 +734,7 @@ static void rtl8192_prepare_beacon(struct r8192_priv *priv) ring = &priv->tx_ring[BEACON_QUEUE]; pskb = __skb_dequeue(&ring->queue); - if (pskb) - kfree_skb(pskb); + kfree_skb(pskb); pnewskb = rtllib_get_beacon(priv->rtllib); if (!pnewskb) @@ -3125,6 +3124,9 @@ MODULE_DESCRIPTION("Linux driver for Realtek RTL819x WiFi cards"); MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_VERSION(DRV_VERSION); MODULE_LICENSE("GPL"); +MODULE_FIRMWARE(RTL8192E_BOOT_IMG_FW); +MODULE_FIRMWARE(RTL8192E_MAIN_IMG_FW); +MODULE_FIRMWARE(RTL8192E_DATA_IMG_FW); module_param(ifname, charp, S_IRUGO|S_IWUSR); module_param(hwwep, int, S_IRUGO|S_IWUSR); diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c index 481b1e4d4913..1853665764a0 100644 --- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c +++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c @@ -202,7 +202,7 @@ static void dm_check_ac_dc_power(struct net_device *dev) if (priv->ResetProgress == RESET_TYPE_SILENT) { RT_TRACE((COMP_INIT | COMP_POWER | COMP_RF), - "GPIOChangeRFWorkItemCallBack(): Silent Reseting!!!!!!!\n"); + "GPIOChangeRFWorkItemCallBack(): Silent Reset!!!!!!!\n"); return; } diff --git a/drivers/staging/rtl8192e/rtllib.h b/drivers/staging/rtl8192e/rtllib.h index d7460ae3a765..9ac8d8ea4ae8 100644 --- a/drivers/staging/rtl8192e/rtllib.h +++ b/drivers/staging/rtl8192e/rtllib.h @@ -2397,12 +2397,12 @@ struct rtllib_device { struct rtllib_network *network, u16 type); int (*is_qos_active)(struct net_device *dev, struct sk_buff *skb); - /* Softmac-generated frames (mamagement) are TXed via this + /* Softmac-generated frames (management) are TXed via this * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is * not set. As some cards may have different HW queues that * one might want to use for data and management frames * the option to have two callbacks might be useful. - * This fucntion can't sleep. + * This function can't sleep. */ int (*softmac_hard_start_xmit)(struct sk_buff *skb, struct net_device *dev); @@ -2441,9 +2441,9 @@ struct rtllib_device { * it is called in a work_queue when switching to ad-hoc mode * or in behalf of iwlist scan when the card is associated * and root user ask for a scan. - * the fucntion stop_scan should stop both the syncro and + * the function stop_scan should stop both the syncro and * background scanning and can sleep. - * The fucntion start_scan should initiate the background + * The function start_scan should initiate the background * scanning and can't sleep. */ void (*scan_syncro)(struct net_device *dev); diff --git a/drivers/staging/rtl8192e/rtllib_softmac.c b/drivers/staging/rtl8192e/rtllib_softmac.c index a21b4d91a596..4feecec8609c 100644 --- a/drivers/staging/rtl8192e/rtllib_softmac.c +++ b/drivers/staging/rtl8192e/rtllib_softmac.c @@ -19,6 +19,7 @@ #include <linux/random.h> #include <linux/delay.h> #include <linux/uaccess.h> +#include <linux/etherdevice.h> #include "dot11d.h" short rtllib_is_54g(struct rtllib_network *net) @@ -266,7 +267,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct rtllib_device *ieee) else ieee->seq_ctrl[0]++; - /* check wether the managed packet queued greater than 5 */ + /* check whether the managed packet queued greater than 5 */ if (!ieee->check_nic_enough_desc(ieee->dev, tcb_desc->queue_index) || (skb_queue_len(&ieee->skb_waitQ[tcb_desc->queue_index]) != 0) || (ieee->queue_stop)) { @@ -1687,7 +1688,7 @@ inline void rtllib_softmac_new_net(struct rtllib_device *ieee, * if the network does broadcast and the user did set essid * check if essid match * if the ap is not set, check that the user set the bssid - * and the network does bradcast and that those two bssid match + * and the network does broadcast and that those two bssid match */ if ((apset && apmatch && ((ssidset && ssidbroad && ssidmatch) || @@ -1843,7 +1844,7 @@ static short probe_rq_parse(struct rtllib_device *ieee, struct sk_buff *skb, bssid_match = (memcmp(header->addr3, ieee->current_network.bssid, ETH_ALEN) != 0) && - (memcmp(header->addr3, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0); + (!is_broadcast_ether_addr(header->addr3)); if (bssid_match) return -1; @@ -2442,7 +2443,7 @@ inline int rtllib_rx_frame_softmac(struct rtllib_device *ieee, return 0; } -/* following are for a simplier TX queue management. +/* following are for a simpler TX queue management. * Instead of using netif_[stop/wake]_queue the driver * will use these two functions (plus a reset one), that * will internally use the kernel netif_* and takes @@ -2619,13 +2620,7 @@ void rtllib_wake_all_queues(struct rtllib_device *ieee) inline void rtllib_randomize_cell(struct rtllib_device *ieee) { - get_random_bytes(ieee->current_network.bssid, ETH_ALEN); - - /* an IBSS cell address must have the two less significant - * bits of the first byte = 2 - */ - ieee->current_network.bssid[0] &= ~0x01; - ieee->current_network.bssid[0] |= 0x02; + random_ether_addr(ieee->current_network.bssid); } /* called in user context only */ @@ -3361,9 +3356,7 @@ static int rtllib_wpa_set_encryption(struct rtllib_device *ieee, param->u.crypt.key_len); return -EINVAL; } - if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && - param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && - param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { + if (is_broadcast_ether_addr(param->sta_addr)) { if (param->u.crypt.idx >= NUM_WEP_KEYS) return -EINVAL; crypt = &ieee->crypt_info.crypt[param->u.crypt.idx]; @@ -3411,8 +3404,7 @@ static int rtllib_wpa_set_encryption(struct rtllib_device *ieee, lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); - new_crypt = (struct lib80211_crypt_data *) - kmalloc(sizeof(*new_crypt), GFP_KERNEL); + new_crypt = kmalloc(sizeof(*new_crypt), GFP_KERNEL); if (new_crypt == NULL) { ret = -ENOMEM; goto done; diff --git a/drivers/staging/rtl8192e/rtllib_softmac_wx.c b/drivers/staging/rtl8192e/rtllib_softmac_wx.c index 1bb6b52e0f24..740cf85e9d5b 100644 --- a/drivers/staging/rtl8192e/rtllib_softmac_wx.c +++ b/drivers/staging/rtl8192e/rtllib_softmac_wx.c @@ -14,6 +14,8 @@ */ +#include <linux/etherdevice.h> + #include "rtllib.h" #include "dot11d.h" /* FIXME: add A freqs */ @@ -137,7 +139,6 @@ int rtllib_wx_set_wap(struct rtllib_device *ieee, { int ret = 0; - u8 zero[] = {0, 0, 0, 0, 0, 0}; unsigned long flags; short ifup = ieee->proto_started; @@ -157,7 +158,7 @@ int rtllib_wx_set_wap(struct rtllib_device *ieee, goto out; } - if (memcmp(temp->sa_data, zero, ETH_ALEN) == 0) { + if (is_zero_ether_addr(temp->sa_data)) { spin_lock_irqsave(&ieee->lock, flags); memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN); ieee->wap_set = 0; @@ -177,7 +178,7 @@ int rtllib_wx_set_wap(struct rtllib_device *ieee, ieee->cannot_notify = false; memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN); - ieee->wap_set = (memcmp(temp->sa_data, zero, ETH_ALEN) != 0); + ieee->wap_set = !is_zero_ether_addr(temp->sa_data); spin_unlock_irqrestore(&ieee->lock, flags); diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211.h b/drivers/staging/rtl8192u/ieee80211/ieee80211.h index 1c0a1db6420f..13f45c3125ce 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211.h +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211.h @@ -2114,7 +2114,7 @@ struct ieee80211_device { struct ieee80211_network * network, u16 type); int (*is_qos_active) (struct net_device *dev, struct sk_buff *skb); - /* Softmac-generated frames (mamagement) are TXed via this + /* Softmac-generated frames (management) are TXed via this * callback if the flag IEEE_SOFTMAC_SINGLE_QUEUE is * not set. As some cards may have different HW queues that * one might want to use for data and management frames @@ -2192,7 +2192,7 @@ struct ieee80211_device { int (*handle_assoc_response) (struct net_device * dev, struct ieee80211_assoc_response_frame * resp, struct ieee80211_network * network); - /* check whether Tx hw resouce available */ + /* check whether Tx hw resource available */ short (*check_nic_enough_desc)(struct net_device *dev, int queue_index); //added by wb for HT related // void (*SwChnlByTimerHandler)(struct net_device *dev, int channel); diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c index f6ff8cff313a..7a0707810fd0 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac.c @@ -20,6 +20,8 @@ #include <linux/delay.h> #include <linux/slab.h> #include <asm/uaccess.h> +#include <linux/etherdevice.h> + #include "dot11d.h" u8 rsn_authen_cipher_suite[16][4] = { @@ -269,7 +271,7 @@ inline void softmac_mgmt_xmit(struct sk_buff *skb, struct ieee80211_device *ieee else ieee->seq_ctrl[0]++; - /* check wether the managed packet queued greater than 5 */ + /* check whether the managed packet queued greater than 5 */ if(!ieee->check_nic_enough_desc(ieee->dev,tcb_desc->queue_index)||\ (skb_queue_len(&ieee->skb_waitQ[tcb_desc->queue_index]) != 0)||\ (ieee->queue_stop) ) { @@ -1448,7 +1450,7 @@ inline void ieee80211_softmac_new_net(struct ieee80211_device *ieee, struct ieee ( apset && apmatch && ((ssidset && ssidbroad && ssidmatch) || (ssidbroad && !ssidset) || (!ssidbroad && ssidset)) ) || /* if the ap is not set, check that the user set the bssid - * and the network does bradcast and that those two bssid matches + * and the network does broadcast and that those two bssid matches */ (!apset && ssidset && ssidbroad && ssidmatch) ){ @@ -2286,13 +2288,7 @@ void ieee80211_stop_queue(struct ieee80211_device *ieee) inline void ieee80211_randomize_cell(struct ieee80211_device *ieee) { - get_random_bytes(ieee->current_network.bssid, ETH_ALEN); - - /* an IBSS cell address must have the two less significant - * bits of the first byte = 2 - */ - ieee->current_network.bssid[0] &= ~0x01; - ieee->current_network.bssid[0] |= 0x02; + random_ether_addr(ieee->current_network.bssid); } /* called in user context only */ @@ -2520,7 +2516,7 @@ void ieee80211_associate_retry_wq(struct work_struct *work) /* until we do not set the state to IEEE80211_NOLINK * there are no possibility to have someone else trying - * to start an association procdure (we get here with + * to start an association procedure (we get here with * ieee->state = IEEE80211_ASSOCIATING). * When we set the state to IEEE80211_NOLINK it is possible * that the RX path run an attempt to associate, but @@ -2969,9 +2965,7 @@ static int ieee80211_wpa_set_encryption(struct ieee80211_device *ieee, param->u.crypt.key_len); return -EINVAL; } - if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && - param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && - param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { + if (is_broadcast_ether_addr(param->sta_addr)) { if (param->u.crypt.idx >= WEP_KEYS) return -EINVAL; crypt = &ieee->crypt[param->u.crypt.idx]; diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c index cb5a3c32974e..421da8a07697 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_softmac_wx.c @@ -14,6 +14,8 @@ */ +#include <linux/etherdevice.h> + #include "ieee80211.h" #include "dot11d.h" /* FIXME: add A freqs */ @@ -136,7 +138,6 @@ int ieee80211_wx_set_wap(struct ieee80211_device *ieee, { int ret = 0; - u8 zero[] = {0,0,0,0,0,0}; unsigned long flags; short ifup = ieee->proto_started;//dev->flags & IFF_UP; @@ -165,7 +166,7 @@ int ieee80211_wx_set_wap(struct ieee80211_device *ieee, spin_lock_irqsave(&ieee->lock, flags); memcpy(ieee->current_network.bssid, temp->sa_data, ETH_ALEN); - ieee->wap_set = memcmp(temp->sa_data, zero,ETH_ALEN)!=0; + ieee->wap_set = !is_zero_ether_addr(temp->sa_data); spin_unlock_irqrestore(&ieee->lock, flags); diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c index 27d083a70eb2..1ebea3daea2d 100644 --- a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c +++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c @@ -1,6 +1,6 @@ /******************************************************************************************************************************** * This file is created to process BA Action Frame. According to 802.11 spec, there are 3 BA action types at all. And as BA is - * related to TS, this part need some struture defined in QOS side code. Also TX RX is going to be resturctured, so how to send + * related to TS, this part need some structure defined in QOS side code. Also TX RX is going to be resturctured, so how to send * ADDBAREQ ADDBARSP and DELBA packet is still on consideration. Temporarily use MANAGE QUEUE instead of Normal Queue. * WB 2008-05-27 * *****************************************************************************************************************************/ diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h b/drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h index 0b1a1fc09391..a60b39cdb472 100644 --- a/drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h +++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_HT.h @@ -15,7 +15,7 @@ #define HT_OPMODE_MIXED 3 // -// MIMO Power Save Setings +// MIMO Power Save Settings // #define MIMO_PS_STATIC 0 #define MIMO_PS_DYNAMIC 1 @@ -242,7 +242,7 @@ typedef struct _RT_HIGH_THROUGHPUT{ u8 bEnableHT; u8 bCurrentHTSupport; - u8 bRegBW40MHz; // Tx 40MHz channel capablity + u8 bRegBW40MHz; // Tx 40MHz channel capability u8 bCurBW40MHz; // Tx 40MHz channel capability u8 bRegShortGI40MHz; // Tx Short GI for 40Mhz diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c index e88a839b2a91..ebb523904edc 100644 --- a/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c +++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_HTProc.c @@ -912,7 +912,7 @@ u8 HTFilterMCSRate( struct ieee80211_device* ieee, u8* pSupportMCS, u8* pOperate u8 i=0; - // filter out operational rate set not supported by AP, the lenth of it is 16 + // filter out operational rate set not supported by AP, the length of it is 16 for(i=0;i<=15;i++){ pOperateMCS[i] = ieee->Regdot11HTOperationalRateSet[i]&pSupportMCS[i]; } diff --git a/drivers/staging/rtl8192u/r8192U_core.c b/drivers/staging/rtl8192u/r8192U_core.c index 5981d6658320..5a2fab9fa772 100644 --- a/drivers/staging/rtl8192u/r8192U_core.c +++ b/drivers/staging/rtl8192u/r8192U_core.c @@ -2232,24 +2232,15 @@ short rtl8192_usb_initendpoints(struct net_device *dev) memset(priv->rx_urb, 0, sizeof(struct urb*) * MAX_RX_URB); priv->pp_rxskb = kcalloc(MAX_RX_URB, sizeof(struct sk_buff *), GFP_KERNEL); - if (priv->pp_rxskb == NULL) - goto destroy; - - goto _middle; - - -destroy: - kfree(priv->pp_rxskb); - kfree(priv->rx_urb); - - priv->pp_rxskb = NULL; - priv->rx_urb = NULL; - - DMESGE("Endpoint Alloc Failure"); - return -ENOMEM; + if (!priv->pp_rxskb) { + kfree(priv->rx_urb); + priv->pp_rxskb = NULL; + priv->rx_urb = NULL; -_middle: + DMESGE("Endpoint Alloc Failure"); + return -ENOMEM; + } printk("End of initendpoints\n"); return 0; @@ -2808,9 +2799,7 @@ static void rtl8192_init_priv_variable(struct net_device* dev) (priv->EarlyRxThreshold == 7 ? RCR_ONLYERLPKT:0); priv->AcmControl = 0; - priv->pFirmware = kmalloc(sizeof(rt_firmware), GFP_KERNEL); - if (priv->pFirmware) - memset(priv->pFirmware, 0, sizeof(rt_firmware)); + priv->pFirmware = kzalloc(sizeof(rt_firmware), GFP_KERNEL); /* rx related queue */ skb_queue_head_init(&priv->rx_queue); diff --git a/drivers/staging/rtl8192u/r819xU_HTType.h b/drivers/staging/rtl8192u/r819xU_HTType.h index e07f8b17a0d6..6c1d05e1e820 100644 --- a/drivers/staging/rtl8192u/r819xU_HTType.h +++ b/drivers/staging/rtl8192u/r819xU_HTType.h @@ -16,7 +16,7 @@ #define HT_OPMODE_MIXED 3 // -// MIMO Power Save Setings +// MIMO Power Save Settings // #define MIMO_PS_STATIC 0 #define MIMO_PS_DYNAMIC 1 diff --git a/drivers/staging/rtl8192u/r819xU_phyreg.h b/drivers/staging/rtl8192u/r819xU_phyreg.h index 50f24dce8b16..cca34c05f6a5 100644 --- a/drivers/staging/rtl8192u/r819xU_phyreg.h +++ b/drivers/staging/rtl8192u/r819xU_phyreg.h @@ -443,7 +443,7 @@ #define bCCKRxIG 0x7f00 #define bCCKLNAPolarity 0x800000 #define bCCKRx1stGain 0x7f0000 -#define bCCKRFExtend 0x20000000 //CCK Rx inital gain polarity +#define bCCKRFExtend 0x20000000 //CCK Rx initial gain polarity #define bCCKRxAGCSatLevel 0x1f000000 #define bCCKRxAGCSatCount 0xe0 #define bCCKRxRFSettle 0x1f //AGCsamp_dly diff --git a/drivers/staging/rtl8712/drv_types.h b/drivers/staging/rtl8712/drv_types.h index 62b55663c63a..a074fe810169 100644 --- a/drivers/staging/rtl8712/drv_types.h +++ b/drivers/staging/rtl8712/drv_types.h @@ -70,9 +70,7 @@ struct qos_priv { #include "rtl871x_event.h" #include "rtl871x_led.h" -#define SPEC_DEV_ID_NONE BIT(0) #define SPEC_DEV_ID_DISABLE_HT BIT(1) -#define SPEC_DEV_ID_ENABLE_PS BIT(2) struct specific_device_id { u32 flags; @@ -127,13 +125,6 @@ struct registry_priv { u8 wifi_test; }; -/* For registry parameters */ -#define RGTRY_OFT(field) ((addr_t)FIELD_OFFSET(struct registry_priv, field)) -#define RGTRY_SZ(field) sizeof(((struct registry_priv *)0)->field) -#define BSSID_OFT(field) ((addr_t)FIELD_OFFSET(struct ndis_wlan_bssid_ex, \ - field)) -#define BSSID_SZ(field) sizeof(((struct ndis_wlan_bssid_ex *)0)->field) - struct dvobj_priv { struct _adapter *padapter; u32 nr_endpoint; diff --git a/drivers/staging/rtl8712/ethernet.h b/drivers/staging/rtl8712/ethernet.h index 882d61b2e959..90954203776d 100644 --- a/drivers/staging/rtl8712/ethernet.h +++ b/drivers/staging/rtl8712/ethernet.h @@ -35,14 +35,6 @@ /*!< Is Multicast Address? */ #define RT_ETH_IS_MULTICAST(_pAddr) ((((u8 *)(_pAddr))[0]&0x01) != 0) -/*!< Is Broadcast Address? */ -#define RT_ETH_IS_BROADCAST(_pAddr) ( \ - ((u8 *)(_pAddr))[0] == 0xff && \ - ((u8 *)(_pAddr))[1] == 0xff && \ - ((u8 *)(_pAddr))[2] == 0xff && \ - ((u8 *)(_pAddr))[3] == 0xff && \ - ((u8 *)(_pAddr))[4] == 0xff && \ - ((u8 *)(_pAddr))[5] == 0xff) #endif /* #ifndef __INC_ETHERNET_H */ diff --git a/drivers/staging/rtl8712/os_intfs.c b/drivers/staging/rtl8712/os_intfs.c index 448f00dd68fe..e00f7918d261 100644 --- a/drivers/staging/rtl8712/os_intfs.c +++ b/drivers/staging/rtl8712/os_intfs.c @@ -96,7 +96,7 @@ static char *initmac; /* if wifi_test = 1, driver will disable the turbo mode and pass it to * firmware private. */ -static int wifi_test = 0; +static int wifi_test; module_param_string(ifname, ifname, sizeof(ifname), S_IRUGO|S_IWUSR); module_param(wifi_test, int, 0644); diff --git a/drivers/staging/rtl8712/rtl8712_recv.c b/drivers/staging/rtl8712/rtl8712_recv.c index 8e82ce2fee38..c76732cdb183 100644 --- a/drivers/staging/rtl8712/rtl8712_recv.c +++ b/drivers/staging/rtl8712/rtl8712_recv.c @@ -374,6 +374,8 @@ static int amsdu_to_msdu(struct _adapter *padapter, union recv_frame *prframe) a_len -= ETH_HLEN; /* Allocate new skb for releasing to upper layer */ sub_skb = dev_alloc_skb(nSubframe_Length + 12); + if (!sub_skb) + break; skb_reserve(sub_skb, 12); data_ptr = (u8 *)skb_put(sub_skb, nSubframe_Length); memcpy(data_ptr, pdata, nSubframe_Length); @@ -1094,6 +1096,8 @@ static int recvbuf2recvframe(struct _adapter *padapter, struct sk_buff *pskb) precvframe->u.hdr.rx_end = pkt_copy->data + alloc_sz; } else { precvframe->u.hdr.pkt = skb_clone(pskb, GFP_ATOMIC); + if (!precvframe->u.hdr.pkt) + return _FAIL; precvframe->u.hdr.rx_head = pbuf; precvframe->u.hdr.rx_data = pbuf; precvframe->u.hdr.rx_tail = pbuf; @@ -1127,6 +1131,9 @@ static void recv_tasklet(void *priv) recvbuf2recvframe(padapter, pskb); skb_reset_tail_pointer(pskb); pskb->len = 0; - skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb); + if (!skb_cloned(pskb)) + skb_queue_tail(&precvpriv->free_recv_skb_queue, pskb); + else + consume_skb(pskb); } } diff --git a/drivers/staging/rtl8712/rtl8712_recv.h b/drivers/staging/rtl8712/rtl8712_recv.h index 8efbd1fa035f..fd9e3fc4c226 100644 --- a/drivers/staging/rtl8712/rtl8712_recv.h +++ b/drivers/staging/rtl8712/rtl8712_recv.h @@ -41,7 +41,7 @@ #define RECV_BLK_SZ 512 #define RECV_BLK_CNT 16 #define RECV_BLK_TH RECV_BLK_CNT -#define MAX_RECVBUF_SZ (30720) /* 30K */ +#define MAX_RECVBUF_SZ 9100 #define RECVBUFF_ALIGN_SZ 512 #define RSVD_ROOM_SZ (0) /*These definition is used for Rx packet reordering.*/ diff --git a/drivers/staging/rtl8712/rtl8712_xmit.c b/drivers/staging/rtl8712/rtl8712_xmit.c index 3d23514c0222..4e3f09420c1e 100644 --- a/drivers/staging/rtl8712/rtl8712_xmit.c +++ b/drivers/staging/rtl8712/rtl8712_xmit.c @@ -376,7 +376,7 @@ u8 r8712_dump_aggr_xframe(struct xmit_buf *pxmitbuf, { struct _adapter *padapter = pxmitframe->padapter; struct dvobj_priv *pdvobj = (struct dvobj_priv *) &padapter->dvobjpriv; - struct tx_desc * ptxdesc = (struct tx_desc *)pxmitbuf->pbuf; + struct tx_desc *ptxdesc = (struct tx_desc *)pxmitbuf->pbuf; struct cmd_hdr *pcmd_hdr = (struct cmd_hdr *) (pxmitbuf->pbuf + TXDESC_SIZE); u16 total_length = (u16) (ptxdesc->txdw0 & 0xffff); diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c index 35e781fca4a0..c9a6a7fbb89c 100644 --- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c +++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c @@ -407,9 +407,7 @@ static int wpa_set_encryption(struct net_device *dev, struct ieee_param *param, if (param_len != (u32)((u8 *) param->u.crypt.key - (u8 *)param) + param->u.crypt.key_len) return -EINVAL; - if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && - param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && - param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { + if (is_broadcast_ether_addr(param->sta_addr)) { if (param->u.crypt.idx >= WEP_KEYS) { /* for large key indices, set the default (0) */ param->u.crypt.idx = 0; diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_set.c b/drivers/staging/rtl8712/rtl871x_ioctl_set.c index f352b32355a0..d3ab24e34e3d 100644 --- a/drivers/staging/rtl8712/rtl871x_ioctl_set.c +++ b/drivers/staging/rtl8712/rtl871x_ioctl_set.c @@ -131,10 +131,7 @@ u8 r8712_set_802_11_bssid(struct _adapter *padapter, u8 *bssid) u8 status = true; struct mlme_priv *pmlmepriv = &padapter->mlmepriv; - if ((bssid[0] == 0x00 && bssid[1] == 0x00 && bssid[2] == 0x00 && - bssid[3] == 0x00 && bssid[4] == 0x00 && bssid[5] == 0x00) || - (bssid[0] == 0xFF && bssid[1] == 0xFF && bssid[2] == 0xFF && - bssid[3] == 0xFF && bssid[4] == 0xFF && bssid[5] == 0xFF)) { + if (is_zero_ether_addr(bssid) || is_broadcast_ether_addr(bssid)) { status = false; return status; } diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c index dc7adc132d12..c51ad9ed4b52 100644 --- a/drivers/staging/rtl8712/rtl871x_mlme.c +++ b/drivers/staging/rtl8712/rtl871x_mlme.c @@ -28,6 +28,8 @@ #define _RTL871X_MLME_C_ +#include <linux/etherdevice.h> + #include "osdep_service.h" #include "drv_types.h" #include "recv_osdep.h" @@ -146,9 +148,8 @@ static struct wlan_network *_r8712_find_network(struct __queue *scanned_queue, unsigned long irqL; struct list_head *phead, *plist; struct wlan_network *pnetwork = NULL; - u8 zero_addr[ETH_ALEN] = {0, 0, 0, 0, 0, 0}; - if (!memcmp(zero_addr, addr, ETH_ALEN)) + if (is_zero_ether_addr(addr)) return NULL; spin_lock_irqsave(&scanned_queue->lock, irqL); phead = get_list_head(scanned_queue); diff --git a/drivers/staging/rtl8712/rtl871x_pwrctrl.h b/drivers/staging/rtl8712/rtl871x_pwrctrl.h index 6024c4f63d5b..70ff924fba04 100644 --- a/drivers/staging/rtl8712/rtl871x_pwrctrl.h +++ b/drivers/staging/rtl8712/rtl871x_pwrctrl.h @@ -30,26 +30,7 @@ #include "drv_types.h" -#define FW_PWR0 0 -#define FW_PWR1 1 -#define FW_PWR2 2 -#define FW_PWR3 3 - - -#define HW_PWR0 7 -#define HW_PWR1 6 -#define HW_PWR2 2 -#define HW_PWR3 0 -#define HW_PWR4 8 - -#define FW_PWRMSK 0x7 - - -#define XMIT_ALIVE BIT(0) -#define RECV_ALIVE BIT(1) #define CMD_ALIVE BIT(2) -#define EVT_ALIVE BIT(3) - enum Power_Mgnt { PS_MODE_ACTIVE = 0 , @@ -66,7 +47,6 @@ enum Power_Mgnt { PS_MODE_NUM }; - /* BIT[2:0] = HW state BIT[3] = Protocol PS state, 0: register active state, diff --git a/drivers/staging/rtl8712/rtl871x_recv.c b/drivers/staging/rtl8712/rtl871x_recv.c index c9d1743e5c5d..23ec684b60e1 100644 --- a/drivers/staging/rtl8712/rtl871x_recv.c +++ b/drivers/staging/rtl8712/rtl871x_recv.c @@ -32,6 +32,7 @@ #include <linux/slab.h> #include <linux/if_ether.h> #include <linux/kmemleak.h> +#include <linux/etherdevice.h> #include "osdep_service.h" #include "drv_types.h" @@ -331,8 +332,8 @@ static sint sta2sta_data_frame(struct _adapter *adapter, return _FAIL; if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) return _FAIL; - if (!memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || - !memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || + if (is_zero_ether_addr(pattrib->bssid) || + is_zero_ether_addr(mybssid) || (memcmp(pattrib->bssid, mybssid, ETH_ALEN))) return _FAIL; sta_addr = pattrib->src; @@ -409,8 +410,8 @@ static sint ap2sta_data_frame(struct _adapter *adapter, if ((memcmp(myhwaddr, pattrib->dst, ETH_ALEN)) && (!bmcast)) return _FAIL; /* check BSSID */ - if (!memcmp(pattrib->bssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || - !memcmp(mybssid, "\x0\x0\x0\x0\x0\x0", ETH_ALEN) || + if (is_zero_ether_addr(pattrib->bssid) || + is_zero_ether_addr(mybssid) || (memcmp(pattrib->bssid, mybssid, ETH_ALEN))) return _FAIL; if (bmcast) diff --git a/drivers/staging/rtl8712/rtl871x_security.c b/drivers/staging/rtl8712/rtl871x_security.c index 7b92927a04dc..e33fd6db246d 100644 --- a/drivers/staging/rtl8712/rtl871x_security.c +++ b/drivers/staging/rtl8712/rtl871x_security.c @@ -58,7 +58,7 @@ struct arc4context { u8 state[256]; }; -static void arcfour_init(struct arc4context *parc4ctx, u8 * key, u32 key_len) +static void arcfour_init(struct arc4context *parc4ctx, u8 *key, u32 key_len) { u32 t, u; u32 keyindex; @@ -288,7 +288,7 @@ static void secmicclear(struct mic_data *pmicdata) pmicdata->M = 0; } -void r8712_secmicsetkey(struct mic_data *pmicdata, u8 * key) +void r8712_secmicsetkey(struct mic_data *pmicdata, u8 *key) { /* Set the key */ pmicdata->K0 = secmicgetuint32(key); @@ -320,7 +320,7 @@ static void secmicappendbyte(struct mic_data *pmicdata, u8 b) } } -void r8712_secmicappend(struct mic_data *pmicdata, u8 * src, u32 nbytes) +void r8712_secmicappend(struct mic_data *pmicdata, u8 *src, u32 nbytes) { /* This is simple */ while (nbytes > 0) { @@ -1368,7 +1368,7 @@ u32 r8712_aes_decrypt(struct _adapter *padapter, u8 *precvframe) precvframe)->u.hdr.attrib; struct security_priv *psecuritypriv = &padapter->securitypriv; - pframe = (unsigned char *)((union recv_frame*)precvframe)-> + pframe = (unsigned char *)((union recv_frame *)precvframe)-> u.hdr.rx_data; /* 4 start to encrypt each fragment */ if ((prxattrib->encrypt == _AES_)) { diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c index c758c40e0c85..6b73843e580a 100644 --- a/drivers/staging/rtl8712/usb_intf.c +++ b/drivers/staging/rtl8712/usb_intf.c @@ -37,7 +37,6 @@ #include "recv_osdep.h" #include "xmit_osdep.h" #include "rtl8712_efuse.h" -#include "usb_vendor_req.h" #include "usb_ops.h" #include "usb_osintf.h" diff --git a/drivers/staging/rtl8712/usb_osintf.h b/drivers/staging/rtl8712/usb_osintf.h index d95797aac37a..609f9210cc46 100644 --- a/drivers/staging/rtl8712/usb_osintf.h +++ b/drivers/staging/rtl8712/usb_osintf.h @@ -28,9 +28,6 @@ #include "osdep_service.h" #include "drv_types.h" -#include "usb_vendor_req.h" - -#define USBD_HALTED(Status) ((u32)(Status) >> 30 == 3) extern char *r8712_initmac; diff --git a/drivers/staging/rtl8712/usb_vendor_req.h b/drivers/staging/rtl8712/usb_vendor_req.h deleted file mode 100644 index 82335a83d0d2..000000000000 --- a/drivers/staging/rtl8712/usb_vendor_req.h +++ /dev/null @@ -1,58 +0,0 @@ -/****************************************************************************** - * - * Copyright(c) 2007 - 2010 Realtek Corporation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of version 2 of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA - * - * Modifications for inclusion into the Linux staging tree are - * Copyright(c) 2010 Larry Finger. All rights reserved. - * - * Contact information: - * WLAN FAE <wlanfae@realtek.com> - * Larry Finger <Larry.Finger@lwfinger.net> - * - ******************************************************************************/ -#ifndef _USB_VENDOR_REQUEST_H_ -#define _USB_VENDOR_REQUEST_H_ - -/*4 Set/Get Register related wIndex/Data */ -#define RT_USB_RESET_MASK_OFF 0 -#define RT_USB_RESET_MASK_ON 1 -#define RT_USB_SLEEP_MASK_OFF 0 -#define RT_USB_SLEEP_MASK_ON 1 -#define RT_USB_LDO_ON 1 -#define RT_USB_LDO_OFF 0 - -/*4 Set/Get SYSCLK related wValue or Data */ -#define RT_USB_SYSCLK_32KHZ 0 -#define RT_USB_SYSCLK_40MHZ 1 -#define RT_USB_SYSCLK_60MHZ 2 - -enum RT_USB_BREQUEST { - RT_USB_SET_REGISTER = 1, - RT_USB_SET_SYSCLK = 2, - RT_USB_GET_SYSCLK = 3, - RT_USB_GET_REGISTER = 4 -}; - -enum RT_USB_WVALUE { - RT_USB_RESET_MASK = 1, - RT_USB_SLEEP_MASK = 2, - RT_USB_USB_HRCPWM = 3, - RT_USB_LDO = 4, - RT_USB_BOOT_TYPE = 5 -}; - -#endif - diff --git a/drivers/staging/rts5139/rts51x_fop.c b/drivers/staging/rts5139/rts51x_fop.c index e1200fe89579..bf1a9e64e874 100644 --- a/drivers/staging/rts5139/rts51x_fop.c +++ b/drivers/staging/rts5139/rts51x_fop.c @@ -79,7 +79,7 @@ static int rts51x_sd_direct_cmnd(struct rts51x_chip *chip, case 1: /* Read from card */ - buf = kmalloc(cmnd->buf_len, GFP_KERNEL); + buf = kzalloc(cmnd->buf_len, GFP_KERNEL); if (!buf) TRACE_RET(chip, STATUS_NOMEM); diff --git a/drivers/staging/rts5139/trace.h b/drivers/staging/rts5139/trace.h index 0584b8ab43ca..c9dfb1ea4115 100644 --- a/drivers/staging/rts5139/trace.h +++ b/drivers/staging/rts5139/trace.h @@ -93,35 +93,9 @@ do { \ #endif #ifdef CONFIG_RTS5139_DEBUG -static inline void rts51x_dump(u8 *buf, int buf_len) -{ - int i; - u8 tmp[16] = { 0 }; - u8 *_ptr = buf; - - for (i = 0; i < ((buf_len) / 16); i++) { - RTS51X_DEBUGP("%02x %02x %02x %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x %02x %02x %02x\n", - _ptr[0], _ptr[1], _ptr[2], _ptr[3], _ptr[4], - _ptr[5], _ptr[6], _ptr[7], _ptr[8], _ptr[9], - _ptr[10], _ptr[11], _ptr[12], _ptr[13], _ptr[14], - _ptr[15]); - _ptr += 16; - } - if ((buf_len) % 16) { - memcpy(tmp, _ptr, (buf_len) % 16); - _ptr = tmp; - RTS51X_DEBUGP("%02x %02x %02x %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x %02x %02x %02x\n", - _ptr[0], _ptr[1], _ptr[2], _ptr[3], _ptr[4], - _ptr[5], _ptr[6], _ptr[7], _ptr[8], _ptr[9], - _ptr[10], _ptr[11], _ptr[12], _ptr[13], _ptr[14], - _ptr[15]); - } -} - -#define RTS51X_DUMP(buf, buf_len) \ - rts51x_dump((u8 *)(buf), (buf_len)) +#define RTS51X_DUMP(buf, buf_len) \ + print_hex_dump(KERN_DEBUG, RTS51X_TIP, DUMP_PREFIX_NONE, \ + 16, 1, (buf), (buf_len), false) #define CATCH_TRIGGER(chip) \ do { \ diff --git a/drivers/staging/rts_pstor/ms.c b/drivers/staging/rts_pstor/ms.c index 7cc2b53f20d0..16a5c16fb6ab 100644 --- a/drivers/staging/rts_pstor/ms.c +++ b/drivers/staging/rts_pstor/ms.c @@ -109,9 +109,8 @@ static int ms_transfer_data(struct rtsx_chip *chip, u8 trans_mode, u8 tpc, u16 s u8 val, err_code = 0; enum dma_data_direction dir; - if (!buf || !buf_len) { + if (!buf || !buf_len) TRACE_RET(chip, STATUS_FAIL); - } if (trans_mode == MS_TM_AUTO_READ) { dir = DMA_FROM_DEVICE; @@ -151,18 +150,17 @@ static int ms_transfer_data(struct rtsx_chip *chip, u8 trans_mode, u8 tpc, u16 s use_sg, dir, chip->mspro_timeout); if (retval < 0) { ms_set_err_code(chip, err_code); - if (retval == -ETIMEDOUT) { + if (retval == -ETIMEDOUT) retval = STATUS_TIMEDOUT; - } else { + else retval = STATUS_FAIL; - } + TRACE_RET(chip, retval); } RTSX_READ_REG(chip, MS_TRANS_CFG, &val); - if (val & (MS_INT_CMDNK | MS_INT_ERR | MS_CRC16_ERR | MS_RDY_TIMEOUT)) { + if (val & (MS_INT_CMDNK | MS_INT_ERR | MS_CRC16_ERR | MS_RDY_TIMEOUT)) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -173,9 +171,8 @@ static int ms_write_bytes(struct rtsx_chip *chip, struct ms_info *ms_card = &(chip->ms_card); int retval, i; - if (!data || (data_len < cnt)) { + if (!data || (data_len < cnt)) TRACE_RET(chip, STATUS_ERROR); - } rtsx_init_cmd(chip); @@ -183,9 +180,8 @@ static int ms_write_bytes(struct rtsx_chip *chip, rtsx_add_cmd(chip, WRITE_REG_CMD, PPBUF_BASE2 + i, 0xFF, data[i]); } - if (cnt % 2) { + if (cnt % 2) rtsx_add_cmd(chip, WRITE_REG_CMD, PPBUF_BASE2 + i, 0xFF, 0xFF); - } rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TPC, 0xFF, tpc); rtsx_add_cmd(chip, WRITE_REG_CMD, MS_BYTE_CNT, 0xFF, cnt); @@ -238,9 +234,8 @@ static int ms_read_bytes(struct rtsx_chip *chip, u8 tpc, u8 cnt, u8 cfg, u8 *dat int retval, i; u8 *ptr; - if (!data) { + if (!data) TRACE_RET(chip, STATUS_ERROR); - } rtsx_init_cmd(chip); @@ -252,14 +247,13 @@ static int ms_read_bytes(struct rtsx_chip *chip, u8 tpc, u8 cnt, u8 cfg, u8 *dat rtsx_add_cmd(chip, WRITE_REG_CMD, MS_TRANSFER, 0xFF, MS_TRANSFER_START | MS_TM_READ_BYTES); rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANSFER, MS_TRANSFER_END, MS_TRANSFER_END); - for (i = 0; i < data_len - 1; i++) { + for (i = 0; i < data_len - 1; i++) rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + i, 0, 0); - } - if (data_len % 2) { + + if (data_len % 2) rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + data_len, 0, 0); - } else { + else rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + data_len - 1, 0, 0); - } retval = rtsx_send_cmd(chip, MS_CARD, 5000); if (retval < 0) { @@ -293,9 +287,8 @@ static int ms_read_bytes(struct rtsx_chip *chip, u8 tpc, u8 cnt, u8 cfg, u8 *dat ptr = rtsx_get_cmd_data(chip) + 1; - for (i = 0; i < data_len; i++) { + for (i = 0; i < data_len; i++) data[i] = ptr[i]; - } if ((tpc == PRO_READ_SHORT_DATA) && (data_len == 8)) { RTSX_DEBUGP("Read format progress:\n"); @@ -343,34 +336,31 @@ static int ms_set_init_para(struct rtsx_chip *chip) int retval; if (CHK_HG8BIT(ms_card)) { - if (chip->asic_code) { + if (chip->asic_code) ms_card->ms_clock = chip->asic_ms_hg_clk; - } else { + else ms_card->ms_clock = chip->fpga_ms_hg_clk; - } + } else if (CHK_MSPRO(ms_card) || CHK_MS4BIT(ms_card)) { - if (chip->asic_code) { + if (chip->asic_code) ms_card->ms_clock = chip->asic_ms_4bit_clk; - } else { + else ms_card->ms_clock = chip->fpga_ms_4bit_clk; - } + } else { - if (chip->asic_code) { + if (chip->asic_code) ms_card->ms_clock = chip->asic_ms_1bit_clk; - } else { + else ms_card->ms_clock = chip->fpga_ms_1bit_clk; - } } retval = switch_clock(chip, ms_card->ms_clock); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = select_card(chip, MS_CARD); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -381,14 +371,12 @@ static int ms_switch_clock(struct rtsx_chip *chip) int retval; retval = select_card(chip, MS_CARD); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = switch_clock(chip, ms_card->ms_clock); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -461,9 +449,8 @@ static int ms_pull_ctl_enable(struct rtsx_chip *chip) } retval = rtsx_send_cmd(chip, MS_CARD, 100); - if (retval < 0) { + if (retval < 0) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -482,40 +469,37 @@ static int ms_prepare_reset(struct rtsx_chip *chip) ms_card->pro_under_formatting = 0; retval = ms_power_off_card3v3(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (!chip->ft2_fast_mode) wait_timeout(250); retval = enable_card_clock(chip, MS_CARD); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (chip->asic_code) { retval = ms_pull_ctl_enable(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } else { RTSX_WRITE_REG(chip, FPGA_PULL_CTL, FPGA_MS_PULL_CTL_BIT | 0x20, 0); } if (!chip->ft2_fast_mode) { retval = card_power_on(chip, MS_CARD); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + wait_timeout(150); #ifdef SUPPORT_OCP - if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) { + if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) oc_mask = MS_OC_NOW | MS_OC_EVER; - } else { + else oc_mask = SD_OC_NOW | SD_OC_EVER; - } + if (chip->ocp_stat & oc_mask) { RTSX_DEBUGP("Over current, OCPSTAT is 0x%x\n", chip->ocp_stat); @@ -539,9 +523,8 @@ static int ms_prepare_reset(struct rtsx_chip *chip) RTSX_WRITE_REG(chip, CARD_STOP, MS_STOP | MS_CLR_ERR, MS_STOP | MS_CLR_ERR); retval = ms_set_init_para(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -553,26 +536,23 @@ static int ms_identify_media_type(struct rtsx_chip *chip, int switch_8bit_bus) u8 val; retval = ms_set_rw_reg_addr(chip, Pro_StatusReg, 6, SystemParm, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { retval = ms_transfer_tpc(chip, MS_TM_READ_BYTES, READ_REG, 6, NO_WAIT_INT); - if (retval == STATUS_SUCCESS) { + if (retval == STATUS_SUCCESS) break; - } } - if (i == MS_MAX_RETRY_COUNT) { + if (i == MS_MAX_RETRY_COUNT) TRACE_RET(chip, STATUS_FAIL); - } RTSX_READ_REG(chip, PPBUF_BASE2 + 2, &val); RTSX_DEBUGP("Type register: 0x%x\n", val); if (val != 0x01) { - if (val != 0x02) { + if (val != 0x02) ms_card->check_ms_flow = 1; - } + TRACE_RET(chip, STATUS_FAIL); } @@ -587,11 +567,11 @@ static int ms_identify_media_type(struct rtsx_chip *chip, int switch_8bit_bus) RTSX_DEBUGP("Class register: 0x%x\n", val); if (val == 0) { RTSX_READ_REG(chip, PPBUF_BASE2, &val); - if (val & WRT_PRTCT) { + if (val & WRT_PRTCT) chip->card_wp |= MS_CARD; - } else { + else chip->card_wp &= ~MS_CARD; - } + } else if ((val == 0x01) || (val == 0x02) || (val == 0x03)) { chip->card_wp |= MS_CARD; } else { @@ -606,11 +586,11 @@ static int ms_identify_media_type(struct rtsx_chip *chip, int switch_8bit_bus) if (val == 0) { ms_card->ms_type &= 0x0F; } else if (val == 7) { - if (switch_8bit_bus) { + if (switch_8bit_bus) ms_card->ms_type |= MS_HG; - } else { + else ms_card->ms_type &= 0x0F; - } + } else { TRACE_RET(chip, STATUS_FAIL); } @@ -633,17 +613,15 @@ static int ms_confirm_cpu_startup(struct rtsx_chip *chip) for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval == STATUS_SUCCESS) { + if (retval == STATUS_SUCCESS) break; - } } - if (i == MS_MAX_RETRY_COUNT) { + if (i == MS_MAX_RETRY_COUNT) TRACE_RET(chip, STATUS_FAIL); - } - if (k > 100) { + if (k > 100) TRACE_RET(chip, STATUS_FAIL); - } + k++; wait_timeout(100); } while (!(val & INT_REG_CED)); @@ -653,16 +631,14 @@ static int ms_confirm_cpu_startup(struct rtsx_chip *chip) if (retval == STATUS_SUCCESS) break; } - if (i == MS_MAX_RETRY_COUNT) { + if (i == MS_MAX_RETRY_COUNT) TRACE_RET(chip, STATUS_FAIL); - } if (val & INT_REG_ERR) { - if (val & INT_REG_CMDNK) { + if (val & INT_REG_CMDNK) chip->card_wp |= (MS_CARD); - } else { + else TRACE_RET(chip, STATUS_FAIL); - } } /* -- end confirm CPU startup */ @@ -681,9 +657,8 @@ static int ms_switch_parallel_bus(struct rtsx_chip *chip) if (retval == STATUS_SUCCESS) break; } - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -698,26 +673,22 @@ static int ms_switch_8bit_bus(struct rtsx_chip *chip) data[1] = 0; for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { retval = ms_write_bytes(chip, WRITE_REG, 1, NO_WAIT_INT, data, 2); - if (retval == STATUS_SUCCESS) { + if (retval == STATUS_SUCCESS) break; - } } - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } RTSX_WRITE_REG(chip, MS_CFG, 0x98, MS_BUS_WIDTH_8 | SAMPLE_TIME_FALLING); ms_card->ms_type |= MS_8BIT; retval = ms_set_init_para(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { retval = ms_transfer_tpc(chip, MS_TM_READ_BYTES, GET_INT, 1, NO_WAIT_INT); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } return STATUS_SUCCESS; @@ -730,19 +701,16 @@ static int ms_pro_reset_flow(struct rtsx_chip *chip, int switch_8bit_bus) for (i = 0; i < 3; i++) { retval = ms_prepare_reset(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = ms_identify_media_type(chip, switch_8bit_bus); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = ms_confirm_cpu_startup(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = ms_switch_parallel_bus(chip); if (retval != STATUS_SUCCESS) { @@ -756,18 +724,16 @@ static int ms_pro_reset_flow(struct rtsx_chip *chip, int switch_8bit_bus) } } - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } /* Switch MS-PRO into Parallel mode */ RTSX_WRITE_REG(chip, MS_CFG, 0x18, MS_BUS_WIDTH_4); RTSX_WRITE_REG(chip, MS_CFG, PUSH_TIME_ODD, PUSH_TIME_ODD); retval = ms_set_init_para(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } /* If MSPro HG Card, We shall try to switch to 8-bit bus */ if (CHK_MSHG(ms_card) && chip->support_ms_8bit && switch_8bit_bus) { @@ -790,9 +756,8 @@ static int msxc_change_power(struct rtsx_chip *chip, u8 mode) ms_cleanup_work(chip); retval = ms_set_rw_reg_addr(chip, 0, 0, Pro_DataCount1, 6); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } buf[0] = 0; buf[1] = mode; @@ -802,19 +767,16 @@ static int msxc_change_power(struct rtsx_chip *chip, u8 mode) buf[5] = 0; retval = ms_write_bytes(chip, PRO_WRITE_REG , 6, NO_WAIT_INT, buf, 6); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = ms_send_cmd(chip, XC_CHG_POWER, WAIT_INT); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } RTSX_READ_REG(chip, MS_TRANS_CFG, buf); - if (buf[0] & (MS_INT_CMDNK | MS_INT_ERR)) { + if (buf[0] & (MS_INT_CMDNK | MS_INT_ERR)) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -836,15 +798,14 @@ static int ms_read_attribute_info(struct rtsx_chip *chip) #endif retval = ms_set_rw_reg_addr(chip, Pro_IntReg, 2, Pro_SystemParm, 7); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } - if (CHK_MS8BIT(ms_card)) { + if (CHK_MS8BIT(ms_card)) data[0] = PARALLEL_8BIT_IF; - } else { + else data[0] = PARALLEL_4BIT_IF; - } + data[1] = 0; data[2] = 0x40; @@ -856,24 +817,21 @@ static int ms_read_attribute_info(struct rtsx_chip *chip) for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { retval = ms_write_bytes(chip, PRO_WRITE_REG, 7, NO_WAIT_INT, data, 8); - if (retval == STATUS_SUCCESS) { + if (retval == STATUS_SUCCESS) break; - } } - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } buf = kmalloc(64 * 512, GFP_KERNEL); - if (buf == NULL) { + if (buf == NULL) TRACE_RET(chip, STATUS_ERROR); - } for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { retval = ms_send_cmd(chip, PRO_READ_ATRB, WAIT_INT); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) continue; - } + retval = rtsx_read_register(chip, MS_TRANS_CFG, &val); if (retval != STATUS_SUCCESS) { kfree(buf); @@ -885,11 +843,10 @@ static int ms_read_attribute_info(struct rtsx_chip *chip) } retval = ms_transfer_data(chip, MS_TM_AUTO_READ, PRO_READ_LONG_DATA, 0x40, WAIT_INT, 0, 0, buf, 64 * 512); - if (retval == STATUS_SUCCESS) { + if (retval == STATUS_SUCCESS) break; - } else { + else rtsx_clear_ms_error(chip); - } } if (retval != STATUS_SUCCESS) { kfree(buf); @@ -963,9 +920,8 @@ static int ms_read_attribute_info(struct rtsx_chip *chip) } #ifdef SUPPORT_MSXC - if (buf[cur_addr_off + 8] == 0x13) { + if (buf[cur_addr_off + 8] == 0x13) ms_card->ms_type |= MS_XC; - } #endif #ifdef SUPPORT_PCGL_1P18 found_sys_info = 1; @@ -1046,18 +1002,15 @@ static int ms_read_attribute_info(struct rtsx_chip *chip) #ifdef SUPPORT_MSXC if (CHK_MSXC(ms_card)) { - if (class_code != 0x03) { + if (class_code != 0x03) TRACE_RET(chip, STATUS_FAIL); - } } else { - if (class_code != 0x02) { + if (class_code != 0x02) TRACE_RET(chip, STATUS_FAIL); - } } #else - if (class_code != 0x02) { + if (class_code != 0x02) TRACE_RET(chip, STATUS_FAIL); - } #endif if (device_type != 0x00) { @@ -1069,9 +1022,8 @@ static int ms_read_attribute_info(struct rtsx_chip *chip) } } - if (sub_class & 0xC0) { + if (sub_class & 0xC0) TRACE_RET(chip, STATUS_FAIL); - } RTSX_DEBUGP("class_code: 0x%x, device_type: 0x%x, sub_class: 0x%x\n", class_code, device_type, sub_class); @@ -1117,23 +1069,20 @@ Retry: if (retval != STATUS_SUCCESS) { if (ms_card->switch_8bit_fail) { retval = ms_pro_reset_flow(chip, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } else { TRACE_RET(chip, STATUS_FAIL); } } retval = ms_read_attribute_info(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } #ifdef XC_POWERCLASS - if (CHK_HG8BIT(ms_card)) { + if (CHK_HG8BIT(ms_card)) change_power_class = 0; - } if (change_power_class && CHK_MSXC(ms_card)) { u8 power_class_en = chip->ms_power_class_en; @@ -1141,11 +1090,10 @@ Retry: RTSX_DEBUGP("power_class_en = 0x%x\n", power_class_en); RTSX_DEBUGP("change_power_class = %d\n", change_power_class); - if (change_power_class) { + if (change_power_class) power_class_en &= (1 << (change_power_class - 1)); - } else { + else power_class_en = 0; - } if (power_class_en) { u8 power_class_mode = (ms_card->raw_sys_info[46] & 0x18) >> 3; @@ -1165,16 +1113,14 @@ Retry: #ifdef SUPPORT_MAGIC_GATE retval = mg_set_tpc_para_sub(chip, 0, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } #endif - if (CHK_HG8BIT(ms_card)) { + if (CHK_HG8BIT(ms_card)) chip->card_bus_width[chip->card2lun[MS_CARD]] = 8; - } else { + else chip->card_bus_width[chip->card2lun[MS_CARD]] = 4; - } return STATUS_SUCCESS; } @@ -1185,14 +1131,12 @@ static int ms_read_status_reg(struct rtsx_chip *chip) u8 val[2]; retval = ms_set_rw_reg_addr(chip, StatusReg0, 2, 0, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = ms_read_bytes(chip, READ_REG, 2, NO_WAIT_INT, val, 2); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (val[1] & (STS_UCDT | STS_UCEX | STS_UCFG)) { ms_set_err_code(chip, MS_FLASH_READ_ERROR); @@ -1211,9 +1155,8 @@ static int ms_read_extra_data(struct rtsx_chip *chip, u8 val, data[10]; retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, SystemParm, 6); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (CHK_MS4BIT(ms_card)) { /* Parallel interface */ @@ -1233,9 +1176,8 @@ static int ms_read_extra_data(struct rtsx_chip *chip, if (retval == STATUS_SUCCESS) break; } - if (i == MS_MAX_RETRY_COUNT) { + if (i == MS_MAX_RETRY_COUNT) TRACE_RET(chip, STATUS_FAIL); - } ms_set_err_code(chip, MS_NO_ERROR); @@ -1244,15 +1186,14 @@ static int ms_read_extra_data(struct rtsx_chip *chip, if (retval == STATUS_SUCCESS) break; } - if (i == MS_MAX_RETRY_COUNT) { + if (i == MS_MAX_RETRY_COUNT) TRACE_RET(chip, STATUS_FAIL); - } ms_set_err_code(chip, MS_NO_ERROR); retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + if (val & INT_REG_CMDNK) { ms_set_err_code(chip, MS_CMD_NK); TRACE_RET(chip, STATUS_FAIL); @@ -1260,20 +1201,18 @@ static int ms_read_extra_data(struct rtsx_chip *chip, if (val & INT_REG_CED) { if (val & INT_REG_ERR) { retval = ms_read_status_reg(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, SystemParm, 6); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } } retval = ms_read_bytes(chip, READ_REG, MS_EXTRA_SIZE, NO_WAIT_INT, data, MS_EXTRA_SIZE); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (buf && buf_len) { if (buf_len > MS_EXTRA_SIZE) @@ -1291,45 +1230,40 @@ static int ms_write_extra_data(struct rtsx_chip *chip, int retval, i; u8 val, data[16]; - if (!buf || (buf_len < MS_EXTRA_SIZE)) { + if (!buf || (buf_len < MS_EXTRA_SIZE)) TRACE_RET(chip, STATUS_FAIL); - } retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, SystemParm, 6 + MS_EXTRA_SIZE); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } - if (CHK_MS4BIT(ms_card)) { + if (CHK_MS4BIT(ms_card)) data[0] = 0x88; - } else { + else data[0] = 0x80; - } + data[1] = 0; data[2] = (u8)(block_addr >> 8); data[3] = (u8)block_addr; data[4] = 0x40; data[5] = page_num; - for (i = 6; i < MS_EXTRA_SIZE + 6; i++) { + for (i = 6; i < MS_EXTRA_SIZE + 6; i++) data[i] = buf[i - 6]; - } retval = ms_write_bytes(chip, WRITE_REG , (6+MS_EXTRA_SIZE), NO_WAIT_INT, data, 16); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } ms_set_err_code(chip, MS_NO_ERROR); retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + if (val & INT_REG_CMDNK) { ms_set_err_code(chip, MS_CMD_NK); TRACE_RET(chip, STATUS_FAIL); @@ -1352,15 +1286,14 @@ static int ms_read_page(struct rtsx_chip *chip, u16 block_addr, u8 page_num) u8 val, data[6]; retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, SystemParm, 6); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } - if (CHK_MS4BIT(ms_card)) { + if (CHK_MS4BIT(ms_card)) data[0] = 0x88; - } else { + else data[0] = 0x80; - } + data[1] = 0; data[2] = (u8)(block_addr >> 8); data[3] = (u8)block_addr; @@ -1368,20 +1301,18 @@ static int ms_read_page(struct rtsx_chip *chip, u16 block_addr, u8 page_num) data[5] = page_num; retval = ms_write_bytes(chip, WRITE_REG , 6, NO_WAIT_INT, data, 6); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } ms_set_err_code(chip, MS_NO_ERROR); retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + if (val & INT_REG_CMDNK) { ms_set_err_code(chip, MS_CMD_NK); TRACE_RET(chip, STATUS_FAIL); @@ -1394,9 +1325,9 @@ static int ms_read_page(struct rtsx_chip *chip, u16 block_addr, u8 page_num) TRACE_RET(chip, STATUS_FAIL); } retval = ms_read_status_reg(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) ms_set_err_code(chip, MS_FLASH_WRITE_ERROR); - } + } else { if (!(val & INT_REG_BREQ)) { ms_set_err_code(chip, MS_BREQ_ERROR); @@ -1406,13 +1337,11 @@ static int ms_read_page(struct rtsx_chip *chip, u16 block_addr, u8 page_num) } retval = ms_transfer_tpc(chip, MS_TM_NORMAL_READ, READ_PAGE_DATA, 0, NO_WAIT_INT); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } - if (ms_check_err_code(chip, MS_FLASH_WRITE_ERROR)) { + if (ms_check_err_code(chip, MS_FLASH_WRITE_ERROR)) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -1425,22 +1354,20 @@ static int ms_set_bad_block(struct rtsx_chip *chip, u16 phy_blk) u8 val, data[8], extra[MS_EXTRA_SIZE]; retval = ms_read_extra_data(chip, phy_blk, 0, extra, MS_EXTRA_SIZE); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, SystemParm, 7); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } ms_set_err_code(chip, MS_NO_ERROR); - if (CHK_MS4BIT(ms_card)) { + if (CHK_MS4BIT(ms_card)) data[0] = 0x88; - } else { + else data[0] = 0x80; - } + data[1] = 0; data[2] = (u8)(phy_blk >> 8); data[3] = (u8)phy_blk; @@ -1450,20 +1377,17 @@ static int ms_set_bad_block(struct rtsx_chip *chip, u16 phy_blk) data[7] = 0xFF; retval = ms_write_bytes(chip, WRITE_REG , 7, NO_WAIT_INT, data, 7); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } ms_set_err_code(chip, MS_NO_ERROR); retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (val & INT_REG_CMDNK) { ms_set_err_code(chip, MS_CMD_NK); @@ -1488,17 +1412,16 @@ static int ms_erase_block(struct rtsx_chip *chip, u16 phy_blk) u8 val, data[6]; retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, SystemParm, 6); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } ms_set_err_code(chip, MS_NO_ERROR); - if (CHK_MS4BIT(ms_card)) { + if (CHK_MS4BIT(ms_card)) data[0] = 0x88; - } else { + else data[0] = 0x80; - } + data[1] = 0; data[2] = (u8)(phy_blk >> 8); data[3] = (u8)phy_blk; @@ -1506,21 +1429,18 @@ static int ms_erase_block(struct rtsx_chip *chip, u16 phy_blk) data[5] = 0; retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT, data, 6); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } ERASE_RTY: retval = ms_send_cmd(chip, BLOCK_ERASE, WAIT_INT); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } ms_set_err_code(chip, MS_NO_ERROR); retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (val & INT_REG_CMDNK) { if (i < 3) { @@ -1546,9 +1466,8 @@ ERASE_RTY: static void ms_set_page_status(u16 log_blk, u8 type, u8 *extra, int extra_len) { - if (!extra || (extra_len < MS_EXTRA_SIZE)) { + if (!extra || (extra_len < MS_EXTRA_SIZE)) return; - } memset(extra, 0xFF, MS_EXTRA_SIZE); @@ -1583,9 +1502,8 @@ static int ms_init_page(struct rtsx_chip *chip, u16 phy_blk, u16 log_blk, u8 sta } retval = ms_write_extra_data(chip, phy_blk, i, extra, MS_EXTRA_SIZE); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } return STATUS_SUCCESS; @@ -1603,27 +1521,23 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk, RTSX_DEBUGP("start_page = %d, end_page = %d\n", start_page, end_page); retval = ms_read_extra_data(chip, new_blk, 0, extra, MS_EXTRA_SIZE); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = ms_read_status_reg(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } RTSX_READ_REG(chip, PPBUF_BASE2, &val); if (val & BUF_FULL) { retval = ms_send_cmd(chip, CLEAR_BUF, WAIT_INT); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (!(val & INT_REG_CED)) { ms_set_err_code(chip, MS_FLASH_WRITE_ERROR); @@ -1640,17 +1554,16 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk, ms_read_extra_data(chip, old_blk, i, extra, MS_EXTRA_SIZE); retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, SystemParm, 6); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } ms_set_err_code(chip, MS_NO_ERROR); - if (CHK_MS4BIT(ms_card)) { + if (CHK_MS4BIT(ms_card)) data[0] = 0x88; - } else { + else data[0] = 0x80; - } + data[1] = 0; data[2] = (u8)(old_blk >> 8); data[3] = (u8)old_blk; @@ -1658,20 +1571,17 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk, data[5] = i; retval = ms_write_bytes(chip, WRITE_REG , 6, NO_WAIT_INT, data, 6); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } ms_set_err_code(chip, MS_NO_ERROR); retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (val & INT_REG_CMDNK) { ms_set_err_code(chip, MS_CMD_NK); @@ -1689,15 +1599,14 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk, } retval = ms_transfer_tpc(chip, MS_TM_NORMAL_READ, READ_PAGE_DATA, 0, NO_WAIT_INT); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (uncorrect_flag) { ms_set_page_status(log_blk, setPS_NG, extra, MS_EXTRA_SIZE); - if (i == 0) { + if (i == 0) extra[0] &= 0xEF; - } + ms_write_extra_data(chip, old_blk, i, extra, MS_EXTRA_SIZE); RTSX_DEBUGP("page %d : extra[0] = 0x%x\n", i, extra[0]); MS_SET_BAD_BLOCK_FLG(ms_card); @@ -1710,13 +1619,11 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk, for (rty_cnt = 0; rty_cnt < MS_MAX_RETRY_COUNT; rty_cnt++) { retval = ms_transfer_tpc(chip, MS_TM_NORMAL_WRITE, WRITE_PAGE_DATA, 0, NO_WAIT_INT); - if (retval == STATUS_SUCCESS) { + if (retval == STATUS_SUCCESS) break; - } } - if (rty_cnt == MS_MAX_RETRY_COUNT) { + if (rty_cnt == MS_MAX_RETRY_COUNT) TRACE_RET(chip, STATUS_FAIL); - } } if (!(val & INT_REG_BREQ)) { @@ -1730,45 +1637,41 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk, ms_set_err_code(chip, MS_NO_ERROR); - if (CHK_MS4BIT(ms_card)) { + if (CHK_MS4BIT(ms_card)) data[0] = 0x88; - } else { + else data[0] = 0x80; - } + data[1] = 0; data[2] = (u8)(new_blk >> 8); data[3] = (u8)new_blk; data[4] = 0x20; data[5] = i; - if ((extra[0] & 0x60) != 0x60) { + if ((extra[0] & 0x60) != 0x60) data[6] = extra[0]; - } else { + else data[6] = 0xF8; - } + data[6 + 1] = 0xFF; data[6 + 2] = (u8)(log_blk >> 8); data[6 + 3] = (u8)log_blk; - for (j = 4; j <= MS_EXTRA_SIZE; j++) { + for (j = 4; j <= MS_EXTRA_SIZE; j++) data[6 + j] = 0xFF; - } retval = ms_write_bytes(chip, WRITE_REG, (6 + MS_EXTRA_SIZE), NO_WAIT_INT, data, 16); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } ms_set_err_code(chip, MS_NO_ERROR); retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (val & INT_REG_CMDNK) { ms_set_err_code(chip, MS_CMD_NK); @@ -1784,17 +1687,16 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk, if (i == 0) { retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, SystemParm, 7); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } ms_set_err_code(chip, MS_NO_ERROR); - if (CHK_MS4BIT(ms_card)) { + if (CHK_MS4BIT(ms_card)) data[0] = 0x88; - } else { + else data[0] = 0x80; - } + data[1] = 0; data[2] = (u8)(old_blk >> 8); data[3] = (u8)old_blk; @@ -1804,20 +1706,17 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk, data[7] = 0xFF; retval = ms_write_bytes(chip, WRITE_REG, 7, NO_WAIT_INT, data, 8); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } ms_set_err_code(chip, MS_NO_ERROR); retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (val & INT_REG_CMDNK) { ms_set_err_code(chip, MS_CMD_NK); @@ -1848,28 +1747,24 @@ static int reset_ms(struct rtsx_chip *chip) #endif retval = ms_prepare_reset(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } ms_card->ms_type |= TYPE_MS; retval = ms_send_cmd(chip, MS_RESET, NO_WAIT_INT); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = ms_read_status_reg(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } RTSX_READ_REG(chip, PPBUF_BASE2, &val); - if (val & WRT_PRTCT) { + if (val & WRT_PRTCT) chip->card_wp |= MS_CARD; - } else { + else chip->card_wp &= ~MS_CARD; - } i = 0; @@ -1913,21 +1808,18 @@ RE_SEARCH: } retval = ms_read_page(chip, ms_card->boot_block, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } /* Read MS system information as sys_info */ rtsx_init_cmd(chip); - for (i = 0; i < 96; i++) { + for (i = 0; i < 96; i++) rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + 0x1A0 + i, 0, 0); - } retval = rtsx_send_cmd(chip, MS_CARD, 100); - if (retval < 0) { + if (retval < 0) TRACE_RET(chip, STATUS_FAIL); - } ptr = rtsx_get_cmd_data(chip); memcpy(ms_card->raw_sys_info, ptr, 96); @@ -1938,21 +1830,18 @@ RE_SEARCH: rtsx_add_cmd(chip, READ_REG_CMD, HEADER_ID0, 0, 0); rtsx_add_cmd(chip, READ_REG_CMD, HEADER_ID1, 0, 0); - for (reg_addr = DISABLED_BLOCK0; reg_addr <= DISABLED_BLOCK3; reg_addr++) { + for (reg_addr = DISABLED_BLOCK0; reg_addr <= DISABLED_BLOCK3; reg_addr++) rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0); - } - for (reg_addr = BLOCK_SIZE_0; reg_addr <= PAGE_SIZE_1; reg_addr++) { + for (reg_addr = BLOCK_SIZE_0; reg_addr <= PAGE_SIZE_1; reg_addr++) rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0); - } rtsx_add_cmd(chip, READ_REG_CMD, MS_Device_Type, 0, 0); rtsx_add_cmd(chip, READ_REG_CMD, MS_4bit_Support, 0, 0); retval = rtsx_send_cmd(chip, MS_CARD, 100); - if (retval < 0) { + if (retval < 0) TRACE_RET(chip, STATUS_FAIL); - } ptr = rtsx_get_cmd_data(chip); @@ -1975,9 +1864,8 @@ RE_SEARCH: goto RE_SEARCH; } - if ((ptr[14] == 1) || (ptr[14] == 3)) { + if ((ptr[14] == 1) || (ptr[14] == 3)) chip->card_wp |= MS_CARD; - } /* BLOCK_SIZE_0, BLOCK_SIZE_1 */ block_size = ((u16)ptr[6] << 8) | ptr[7]; @@ -2026,17 +1914,15 @@ RE_SEARCH: /* Switch I/F Mode */ if (ptr[15]) { retval = ms_set_rw_reg_addr(chip, 0, 0, SystemParm, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } RTSX_WRITE_REG(chip, PPBUF_BASE2, 0xFF, 0x88); RTSX_WRITE_REG(chip, PPBUF_BASE2 + 1, 0xFF, 0); retval = ms_transfer_tpc(chip, MS_TM_WRITE_BYTES, WRITE_REG , 1, NO_WAIT_INT); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } RTSX_WRITE_REG(chip, MS_CFG, 0x58 | MS_NO_CHECK_INT, MS_BUS_WIDTH_4 | PUSH_TIME_ODD | MS_NO_CHECK_INT); @@ -2044,11 +1930,10 @@ RE_SEARCH: ms_card->ms_type |= MS_4BIT; } - if (CHK_MS4BIT(ms_card)) { + if (CHK_MS4BIT(ms_card)) chip->card_bus_width[chip->card2lun[MS_CARD]] = 4; - } else { + else chip->card_bus_width[chip->card2lun[MS_CARD]] = 1; - } return STATUS_SUCCESS; } @@ -2065,30 +1950,27 @@ static int ms_init_l2p_tbl(struct rtsx_chip *chip) size = ms_card->segment_cnt * sizeof(struct zone_entry); ms_card->segment = vzalloc(size); - if (ms_card->segment == NULL) { + if (ms_card->segment == NULL) TRACE_RET(chip, STATUS_FAIL); - } retval = ms_read_page(chip, ms_card->boot_block, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, INIT_FAIL); - } reg_addr = PPBUF_BASE2; for (i = 0; i < (((ms_card->total_block >> 9) * 10) + 1); i++) { retval = rtsx_read_register(chip, reg_addr++, &val1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, INIT_FAIL); - } + retval = rtsx_read_register(chip, reg_addr++, &val2); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, INIT_FAIL); - } defect_block = ((u16)val1 << 8) | val2; - if (defect_block == 0xFFFF) { + if (defect_block == 0xFFFF) break; - } + seg_no = defect_block / 512; ms_card->segment[seg_no].defect_list[ms_card->segment[seg_no].disable_count++] = defect_block; } @@ -2141,9 +2023,8 @@ static void ms_set_l2p_tbl(struct rtsx_chip *chip, int seg_no, u16 log_off, u16 return; segment = &(ms_card->segment[seg_no]); - if (segment->l2p_table) { + if (segment->l2p_table) segment->l2p_table[log_off] = phy_blk; - } } static void ms_set_unused_block(struct rtsx_chip *chip, u16 phy_blk) @@ -2156,9 +2037,9 @@ static void ms_set_unused_block(struct rtsx_chip *chip, u16 phy_blk) segment = &(ms_card->segment[seg_no]); segment->free_table[segment->set_index++] = phy_blk; - if (segment->set_index >= MS_FREE_TABLE_CNT) { + if (segment->set_index >= MS_FREE_TABLE_CNT) segment->set_index = 0; - } + segment->unused_blk_cnt++; } @@ -2175,9 +2056,9 @@ static u16 ms_get_unused_block(struct rtsx_chip *chip, int seg_no) phy_blk = segment->free_table[segment->get_index]; segment->free_table[segment->get_index++] = 0xFFFF; - if (segment->get_index >= MS_FREE_TABLE_CNT) { + if (segment->get_index >= MS_FREE_TABLE_CNT) segment->get_index = 0; - } + segment->unused_blk_cnt--; return phy_blk; @@ -2199,27 +2080,27 @@ static int ms_arbitrate_l2p(struct rtsx_chip *chip, u16 phy_blk, u16 log_off, u8 if (us1 != us2) { if (us1 == 0) { - if (!(chip->card_wp & MS_CARD)) { + if (!(chip->card_wp & MS_CARD)) ms_erase_block(chip, tmp_blk); - } + ms_set_unused_block(chip, tmp_blk); segment->l2p_table[log_off] = phy_blk; } else { - if (!(chip->card_wp & MS_CARD)) { + if (!(chip->card_wp & MS_CARD)) ms_erase_block(chip, phy_blk); - } + ms_set_unused_block(chip, phy_blk); } } else { if (phy_blk < tmp_blk) { - if (!(chip->card_wp & MS_CARD)) { + if (!(chip->card_wp & MS_CARD)) ms_erase_block(chip, phy_blk); - } + ms_set_unused_block(chip, phy_blk); } else { - if (!(chip->card_wp & MS_CARD)) { + if (!(chip->card_wp & MS_CARD)) ms_erase_block(chip, tmp_blk); - } + ms_set_unused_block(chip, tmp_blk); segment->l2p_table[log_off] = phy_blk; } @@ -2240,9 +2121,8 @@ static int ms_build_l2p_tbl(struct rtsx_chip *chip, int seg_no) if (ms_card->segment == NULL) { retval = ms_init_l2p_tbl(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, retval); - } } if (ms_card->segment[seg_no].build_flag) { @@ -2250,27 +2130,24 @@ static int ms_build_l2p_tbl(struct rtsx_chip *chip, int seg_no) return STATUS_SUCCESS; } - if (seg_no == 0) { + if (seg_no == 0) table_size = 494; - } else { + else table_size = 496; - } segment = &(ms_card->segment[seg_no]); if (segment->l2p_table == NULL) { segment->l2p_table = (u16 *)vmalloc(table_size * 2); - if (segment->l2p_table == NULL) { + if (segment->l2p_table == NULL) TRACE_GOTO(chip, BUILD_FAIL); - } } memset((u8 *)(segment->l2p_table), 0xff, table_size * 2); if (segment->free_table == NULL) { segment->free_table = (u16 *)vmalloc(MS_FREE_TABLE_CNT * 2); - if (segment->free_table == NULL) { + if (segment->free_table == NULL) TRACE_GOTO(chip, BUILD_FAIL); - } } memset((u8 *)(segment->free_table), 0xff, MS_FREE_TABLE_CNT * 2); @@ -2368,13 +2245,11 @@ static int ms_build_l2p_tbl(struct rtsx_chip *chip, int seg_no) /* Logical Address Confirmation Process */ if (seg_no == ms_card->segment_cnt - 1) { - if (segment->unused_blk_cnt < 2) { + if (segment->unused_blk_cnt < 2) chip->card_wp |= MS_CARD; - } } else { - if (segment->unused_blk_cnt < 1) { + if (segment->unused_blk_cnt < 1) chip->card_wp |= MS_CARD; - } } if (chip->card_wp & MS_CARD) @@ -2388,9 +2263,9 @@ static int ms_build_l2p_tbl(struct rtsx_chip *chip, int seg_no) return STATUS_SUCCESS; } retval = ms_init_page(chip, phy_blk, log_blk, 0, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, BUILD_FAIL); - } + segment->l2p_table[log_blk-ms_start_idx[seg_no]] = phy_blk; if (seg_no == ms_card->segment_cnt - 1) { if (segment->unused_blk_cnt < 2) { @@ -2419,16 +2294,14 @@ static int ms_build_l2p_tbl(struct rtsx_chip *chip, int seg_no) phy_blk = ms_get_unused_block(chip, 0); retval = ms_copy_page(chip, tmp_blk, phy_blk, log_blk, 0, ms_card->page_off + 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } segment->l2p_table[log_blk] = phy_blk; retval = ms_set_bad_block(chip, tmp_blk); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } } } @@ -2458,14 +2331,12 @@ int reset_ms_card(struct rtsx_chip *chip) memset(ms_card, 0, sizeof(struct ms_info)); retval = enable_card_clock(chip, MS_CARD); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = select_card(chip, MS_CARD); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } ms_card->ms_type = 0; @@ -2473,27 +2344,24 @@ int reset_ms_card(struct rtsx_chip *chip) if (retval != STATUS_SUCCESS) { if (ms_card->check_ms_flow) { retval = reset_ms(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } else { TRACE_RET(chip, STATUS_FAIL); } } retval = ms_set_init_para(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (!CHK_MSPRO(ms_card)) { /* Build table for the last segment, * to check if L2P table block exists, erasing it */ retval = ms_build_l2p_tbl(chip, ms_card->total_block / 512 - 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } RTSX_DEBUGP("ms_card->ms_type = 0x%x\n", ms_card->ms_type); @@ -2520,9 +2388,8 @@ static int mspro_set_rw_cmd(struct rtsx_chip *chip, u32 start_sec, u16 sec_cnt, if (retval == STATUS_SUCCESS) break; } - if (i == MS_MAX_RETRY_COUNT) { + if (i == MS_MAX_RETRY_COUNT) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -2556,21 +2423,18 @@ static inline int ms_auto_tune_clock(struct rtsx_chip *chip) RTSX_DEBUGP("--%s--\n", __func__); if (chip->asic_code) { - if (ms_card->ms_clock > 30) { + if (ms_card->ms_clock > 30) ms_card->ms_clock -= 20; - } } else { - if (ms_card->ms_clock == CLK_80) { + if (ms_card->ms_clock == CLK_80) ms_card->ms_clock = CLK_60; - } else if (ms_card->ms_clock == CLK_60) { + else if (ms_card->ms_clock == CLK_60) ms_card->ms_clock = CLK_40; - } } retval = ms_switch_clock(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -2616,15 +2480,13 @@ static int mspro_rw_multi_sector(struct scsi_cmnd *srb, struct rtsx_chip *chip, } retval = ms_switch_clock(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } - if (srb->sc_data_direction == DMA_FROM_DEVICE) { + if (srb->sc_data_direction == DMA_FROM_DEVICE) trans_mode = MS_TM_AUTO_READ; - } else { + else trans_mode = MS_TM_AUTO_WRITE; - } RTSX_READ_REG(chip, MS_TRANS_CFG, &val); @@ -2639,9 +2501,8 @@ static int mspro_rw_multi_sector(struct scsi_cmnd *srb, struct rtsx_chip *chip, ms_card->total_sec_cnt = 0; if (val & MS_INT_BREQ) { retval = ms_send_cmd(chip, PRO_STOP, WAIT_INT); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } rtsx_write_register(chip, RBCTL, RB_FLUSH, RB_FLUSH); } @@ -2651,17 +2512,16 @@ static int mspro_rw_multi_sector(struct scsi_cmnd *srb, struct rtsx_chip *chip, if (!ms_card->seq_mode) { ms_card->total_sec_cnt = 0; if (sector_cnt >= SEQ_START_CRITERIA) { - if ((ms_card->capacity - start_sector) > 0xFE00) { + if ((ms_card->capacity - start_sector) > 0xFE00) count = 0xFE00; - } else { + else count = (u16)(ms_card->capacity - start_sector); - } + if (count > sector_cnt) { - if (mode_2k) { + if (mode_2k) ms_card->seq_mode |= MODE_2K_SEQ; - } else { + else ms_card->seq_mode |= MODE_512_SEQ; - } } } else { count = sector_cnt; @@ -2686,9 +2546,9 @@ static int mspro_rw_multi_sector(struct scsi_cmnd *srb, struct rtsx_chip *chip, TRACE_RET(chip, STATUS_FAIL); } - if (val & MS_INT_BREQ) { + if (val & MS_INT_BREQ) ms_send_cmd(chip, PRO_STOP, WAIT_INT); - } + if (val & (MS_CRC16_ERR | MS_RDY_TIMEOUT)) { RTSX_DEBUGP("MSPro CRC error, tune clock!\n"); chip->rw_need_retry = 1; @@ -2739,11 +2599,10 @@ static int mspro_read_format_progress(struct rtsx_chip *chip, const int short_da TRACE_RET(chip, STATUS_FAIL); } - if (short_data_len >= 256) { + if (short_data_len >= 256) cnt = 0; - } else { + else cnt = (u8)short_data_len; - } retval = rtsx_write_register(chip, MS_CFG, MS_NO_CHECK_INT, MS_NO_CHECK_INT); if (retval != STATUS_SUCCESS) { @@ -2778,9 +2637,8 @@ static int mspro_read_format_progress(struct rtsx_chip *chip, const int short_da ms_card->format_status = FORMAT_FAIL; TRACE_RET(chip, STATUS_FAIL); } - if (tmp & (MS_INT_CED | MS_INT_CMDNK | MS_INT_BREQ | MS_INT_ERR)) { + if (tmp & (MS_INT_CED | MS_INT_CMDNK | MS_INT_BREQ | MS_INT_ERR)) break; - } wait_timeout(1); } @@ -2843,14 +2701,12 @@ int mspro_format(struct scsi_cmnd *srb, struct rtsx_chip *chip, int short_data_l RTSX_DEBUGP("--%s--\n", __func__); retval = ms_switch_clock(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = ms_set_rw_reg_addr(chip, 0x00, 0x00, Pro_TPCParm, 0x01); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } memset(buf, 0, 2); switch (short_data_len) { @@ -2874,25 +2730,22 @@ int mspro_format(struct scsi_cmnd *srb, struct rtsx_chip *chip, int short_data_l if (retval == STATUS_SUCCESS) break; } - if (i == MS_MAX_RETRY_COUNT) { + if (i == MS_MAX_RETRY_COUNT) TRACE_RET(chip, STATUS_FAIL); - } - if (quick_format) { + if (quick_format) para = 0x0000; - } else { + else para = 0x0001; - } + retval = mspro_set_rw_cmd(chip, 0, para, PRO_FORMAT); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } RTSX_READ_REG(chip, MS_TRANS_CFG, &tmp); - if (tmp & (MS_INT_CMDNK | MS_INT_ERR)) { + if (tmp & (MS_INT_CMDNK | MS_INT_ERR)) TRACE_RET(chip, STATUS_FAIL); - } if ((tmp & (MS_INT_BREQ | MS_INT_CED)) == MS_INT_BREQ) { ms_card->pro_under_formatting = 1; @@ -2930,15 +2783,14 @@ static int ms_read_multiple_pages(struct rtsx_chip *chip, u16 phy_blk, u16 log_b } retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, SystemParm, 6); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } - if (CHK_MS4BIT(ms_card)) { + if (CHK_MS4BIT(ms_card)) data[0] = 0x88; - } else { + else data[0] = 0x80; - } + data[1] = 0; data[2] = (u8)(phy_blk >> 8); data[3] = (u8)phy_blk; @@ -2950,16 +2802,14 @@ static int ms_read_multiple_pages(struct rtsx_chip *chip, u16 phy_blk, u16 log_b if (retval == STATUS_SUCCESS) break; } - if (i == MS_MAX_RETRY_COUNT) { + if (i == MS_MAX_RETRY_COUNT) TRACE_RET(chip, STATUS_FAIL); - } ms_set_err_code(chip, MS_NO_ERROR); retval = ms_send_cmd(chip, BLOCK_READ, WAIT_INT); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } ptr = buf; @@ -2972,9 +2822,9 @@ static int ms_read_multiple_pages(struct rtsx_chip *chip, u16 phy_blk, u16 log_b } retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + if (val & INT_REG_CMDNK) { ms_set_err_code(chip, MS_CMD_NK); TRACE_RET(chip, STATUS_FAIL); @@ -3006,15 +2856,14 @@ static int ms_read_multiple_pages(struct rtsx_chip *chip, u16 phy_blk, u16 log_b if (page_addr == (end_page - 1)) { if (!(val & INT_REG_CED)) { retval = ms_send_cmd(chip, BLOCK_END, WAIT_INT); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + if (!(val & INT_REG_CED)) { ms_set_err_code(chip, MS_FLASH_READ_ERROR); TRACE_RET(chip, STATUS_FAIL); @@ -3079,15 +2928,14 @@ static int ms_write_multiple_pages(struct rtsx_chip *chip, u16 old_blk, u16 new_ if (!start_page) { retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, SystemParm, 7); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } - if (CHK_MS4BIT(ms_card)) { + if (CHK_MS4BIT(ms_card)) data[0] = 0x88; - } else { + else data[0] = 0x80; - } + data[1] = 0; data[2] = (u8)(old_blk >> 8); data[3] = (u8)old_blk; @@ -3097,74 +2945,66 @@ static int ms_write_multiple_pages(struct rtsx_chip *chip, u16 old_blk, u16 new_ data[7] = 0xFF; retval = ms_write_bytes(chip, WRITE_REG, 7, NO_WAIT_INT, data, 8); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } ms_set_err_code(chip, MS_NO_ERROR); retval = ms_transfer_tpc(chip, MS_TM_READ_BYTES, GET_INT, 1, NO_WAIT_INT); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } retval = ms_set_rw_reg_addr(chip, OverwriteFlag, MS_EXTRA_SIZE, SystemParm, (6 + MS_EXTRA_SIZE)); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } ms_set_err_code(chip, MS_NO_ERROR); - if (CHK_MS4BIT(ms_card)) { + if (CHK_MS4BIT(ms_card)) data[0] = 0x88; - } else { + else data[0] = 0x80; - } + data[1] = 0; data[2] = (u8)(new_blk >> 8); data[3] = (u8)new_blk; - if ((end_page - start_page) == 1) { + if ((end_page - start_page) == 1) data[4] = 0x20; - } else { + else data[4] = 0; - } + data[5] = start_page; data[6] = 0xF8; data[7] = 0xFF; data[8] = (u8)(log_blk >> 8); data[9] = (u8)log_blk; - for (i = 0x0A; i < 0x10; i++) { + for (i = 0x0A; i < 0x10; i++) data[i] = 0xFF; - } for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { retval = ms_write_bytes(chip, WRITE_REG, 6 + MS_EXTRA_SIZE, NO_WAIT_INT, data, 16); if (retval == STATUS_SUCCESS) break; } - if (i == MS_MAX_RETRY_COUNT) { + if (i == MS_MAX_RETRY_COUNT) TRACE_RET(chip, STATUS_FAIL); - } for (i = 0; i < MS_MAX_RETRY_COUNT; i++) { retval = ms_send_cmd(chip, BLOCK_WRITE, WAIT_INT); if (retval == STATUS_SUCCESS) break; } - if (i == MS_MAX_RETRY_COUNT) { + if (i == MS_MAX_RETRY_COUNT) TRACE_RET(chip, STATUS_FAIL); - } retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } ptr = buf; for (page_addr = start_page; page_addr < end_page; page_addr++) { @@ -3210,17 +3050,15 @@ static int ms_write_multiple_pages(struct rtsx_chip *chip, u16 old_blk, u16 new_ ms_set_err_code(chip, MS_TO_ERROR); rtsx_clear_ms_error(chip); - if (retval == -ETIMEDOUT) { + if (retval == -ETIMEDOUT) TRACE_RET(chip, STATUS_TIMEDOUT); - } else { + else TRACE_RET(chip, STATUS_FAIL); - } } retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if ((end_page - start_page) == 1) { if (!(val & INT_REG_CED)) { @@ -3231,15 +3069,13 @@ static int ms_write_multiple_pages(struct rtsx_chip *chip, u16 old_blk, u16 new_ if (page_addr == (end_page - 1)) { if (!(val & INT_REG_CED)) { retval = ms_send_cmd(chip, BLOCK_END, WAIT_INT); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } retval = ms_read_bytes(chip, GET_INT, 1, NO_WAIT_INT, &val, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } if ((page_addr == (end_page - 1)) || (page_addr == ms_card->page_off)) { @@ -3266,9 +3102,8 @@ static int ms_finish_write(struct rtsx_chip *chip, u16 old_blk, u16 new_blk, retval = ms_copy_page(chip, old_blk, new_blk, log_blk, page_off, ms_card->page_off + 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } seg_no = old_blk >> 9; @@ -3277,9 +3112,8 @@ static int ms_finish_write(struct rtsx_chip *chip, u16 old_blk, u16 new_blk, ms_set_bad_block(chip, old_blk); } else { retval = ms_erase_block(chip, old_blk); - if (retval == STATUS_SUCCESS) { + if (retval == STATUS_SUCCESS) ms_set_unused_block(chip, old_blk); - } } ms_set_l2p_tbl(chip, seg_no, log_blk - ms_start_idx[seg_no], new_blk); @@ -3294,9 +3128,8 @@ static int ms_prepare_write(struct rtsx_chip *chip, u16 old_blk, u16 new_blk, if (start_page) { retval = ms_copy_page(chip, old_blk, new_blk, log_blk, 0, start_page); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } return STATUS_SUCCESS; @@ -3311,17 +3144,15 @@ int ms_delay_write(struct rtsx_chip *chip) if (delay_write->delay_write_flag) { retval = ms_set_init_para(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } delay_write->delay_write_flag = 0; retval = ms_finish_write(chip, delay_write->old_phyblock, delay_write->new_phyblock, delay_write->logblock, delay_write->pageoff); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } return STATUS_SUCCESS; @@ -3330,11 +3161,10 @@ int ms_delay_write(struct rtsx_chip *chip) static inline void ms_rw_fail(struct scsi_cmnd *srb, struct rtsx_chip *chip) { - if (srb->sc_data_direction == DMA_FROM_DEVICE) { + if (srb->sc_data_direction == DMA_FROM_DEVICE) set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - } else { + else set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_WRITE_ERR); - } } static int ms_rw_multi_sector(struct scsi_cmnd *srb, struct rtsx_chip *chip, u32 start_sector, u16 sector_cnt) @@ -3449,11 +3279,11 @@ static int ms_rw_multi_sector(struct scsi_cmnd *srb, struct rtsx_chip *chip, u32 RTSX_DEBUGP("seg_no = %d, old_blk = 0x%x, new_blk = 0x%x\n", seg_no, old_blk, new_blk); while (total_sec_cnt) { - if ((start_page + total_sec_cnt) > (ms_card->page_off + 1)) { + if ((start_page + total_sec_cnt) > (ms_card->page_off + 1)) end_page = ms_card->page_off + 1; - } else { + else end_page = start_page + (u8)total_sec_cnt; - } + page_cnt = end_page - start_page; RTSX_DEBUGP("start_page = %d, end_page = %d, page_cnt = %d\n", @@ -3482,9 +3312,9 @@ static int ms_rw_multi_sector(struct scsi_cmnd *srb, struct rtsx_chip *chip, u32 if (srb->sc_data_direction == DMA_TO_DEVICE) { if (end_page == (ms_card->page_off + 1)) { retval = ms_erase_block(chip, old_blk); - if (retval == STATUS_SUCCESS) { + if (retval == STATUS_SUCCESS) ms_set_unused_block(chip, old_blk); - } + ms_set_l2p_tbl(chip, seg_no, log_blk - ms_start_idx[seg_no], new_blk); } } @@ -3565,11 +3395,10 @@ int ms_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip, u32 start_sector, u16 s struct ms_info *ms_card = &(chip->ms_card); int retval; - if (CHK_MSPRO(ms_card)) { + if (CHK_MSPRO(ms_card)) retval = mspro_rw_multi_sector(srb, chip, start_sector, sector_cnt); - } else { + else retval = ms_rw_multi_sector(srb, chip, start_sector, sector_cnt); - } return retval; } @@ -3609,14 +3438,12 @@ static int ms_poll_int(struct rtsx_chip *chip) rtsx_add_cmd(chip, CHECK_REG_CMD, MS_TRANS_CFG, MS_INT_CED, MS_INT_CED); retval = rtsx_send_cmd(chip, MS_CARD, 5000); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } val = *rtsx_get_cmd_data(chip); - if (val & MS_INT_ERR) { + if (val & MS_INT_ERR) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -3678,9 +3505,8 @@ static int mg_send_ex_cmd(struct rtsx_chip *chip, u8 cmd, u8 entry_num) if (retval == STATUS_SUCCESS) break; } - if (i == MS_MAX_RETRY_COUNT) { + if (i == MS_MAX_RETRY_COUNT) TRACE_RET(chip, STATUS_FAIL); - } if (check_ms_err(chip)) { rtsx_clear_ms_error(chip); @@ -3697,14 +3523,13 @@ static int mg_set_tpc_para_sub(struct rtsx_chip *chip, int type, u8 mg_entry_num RTSX_DEBUGP("--%s--\n", __func__); - if (type == 0) { + if (type == 0) retval = ms_set_rw_reg_addr(chip, 0, 0, Pro_TPCParm, 1); - } else { + else retval = ms_set_rw_reg_addr(chip, 0, 0, Pro_DataCount1, 6); - } - if (retval != STATUS_SUCCESS) { + + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } buf[0] = 0; buf[1] = 0; @@ -3715,9 +3540,8 @@ static int mg_set_tpc_para_sub(struct rtsx_chip *chip, int type, u8 mg_entry_num buf[5] = mg_entry_num; } retval = ms_write_bytes(chip, PRO_WRITE_REG, (type == 0) ? 1 : 6, NO_WAIT_INT, buf, 6); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -3739,9 +3563,8 @@ int mg_set_leaf_id(struct scsi_cmnd *srb, struct rtsx_chip *chip) ms_cleanup_work(chip); retval = ms_switch_clock(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = mg_send_ex_cmd(chip, MG_SET_LID, 0); if (retval != STATUS_SUCCESS) { @@ -3751,9 +3574,9 @@ int mg_set_leaf_id(struct scsi_cmnd *srb, struct rtsx_chip *chip) memset(buf1, 0, 32); rtsx_stor_get_xfer_buf(buf2, min(12, (int)scsi_bufflen(srb)), srb); - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) buf1[8+i] = buf2[4+i]; - } + retval = ms_write_bytes(chip, PRO_WRITE_SHORT_DATA, 32, WAIT_INT, buf1, 32); if (retval != STATUS_SUCCESS) { set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB); @@ -3780,14 +3603,12 @@ int mg_get_local_EKB(struct scsi_cmnd *srb, struct rtsx_chip *chip) ms_cleanup_work(chip); retval = ms_switch_clock(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } buf = kmalloc(1540, GFP_KERNEL); - if (!buf) { + if (!buf) TRACE_RET(chip, STATUS_ERROR); - } buf[0] = 0x04; buf[1] = 0x1A; @@ -3835,9 +3656,8 @@ int mg_chg(struct scsi_cmnd *srb, struct rtsx_chip *chip) ms_cleanup_work(chip); retval = ms_switch_clock(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = mg_send_ex_cmd(chip, MG_GET_ID, 0); if (retval != STATUS_SUCCESS) { @@ -3875,12 +3695,12 @@ int mg_chg(struct scsi_cmnd *srb, struct rtsx_chip *chip) bufflen = min(12, (int)scsi_bufflen(srb)); rtsx_stor_get_xfer_buf(buf, bufflen, srb); - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) buf[i] = buf[4+i]; - } - for (i = 0; i < 24; i++) { + + for (i = 0; i < 24; i++) buf[8+i] = 0; - } + retval = ms_write_bytes(chip, PRO_WRITE_SHORT_DATA, 32, WAIT_INT, buf, 32); if (retval != STATUS_SUCCESS) { @@ -3911,9 +3731,8 @@ int mg_get_rsp_chg(struct scsi_cmnd *srb, struct rtsx_chip *chip) ms_cleanup_work(chip); retval = ms_switch_clock(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = mg_send_ex_cmd(chip, MG_MAKE_RMS, 0); if (retval != STATUS_SUCCESS) { @@ -3968,9 +3787,8 @@ int mg_rsp(struct scsi_cmnd *srb, struct rtsx_chip *chip) ms_cleanup_work(chip); retval = ms_switch_clock(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = mg_send_ex_cmd(chip, MG_MAKE_KSE, 0); if (retval != STATUS_SUCCESS) { @@ -3981,12 +3799,12 @@ int mg_rsp(struct scsi_cmnd *srb, struct rtsx_chip *chip) bufflen = min(12, (int)scsi_bufflen(srb)); rtsx_stor_get_xfer_buf(buf, bufflen, srb); - for (i = 0; i < 8; i++) { + for (i = 0; i < 8; i++) buf[i] = buf[4+i]; - } - for (i = 0; i < 24; i++) { + + for (i = 0; i < 24; i++) buf[8+i] = 0; - } + retval = ms_write_bytes(chip, PRO_WRITE_SHORT_DATA, 32, WAIT_INT, buf, 32); if (retval != STATUS_SUCCESS) { set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_AUTHEN); @@ -4016,14 +3834,12 @@ int mg_get_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip) ms_cleanup_work(chip); retval = ms_switch_clock(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } buf = kmalloc(1028, GFP_KERNEL); - if (!buf) { + if (!buf) TRACE_RET(chip, STATUS_ERROR); - } buf[0] = 0x04; buf[1] = 0x02; @@ -4073,14 +3889,12 @@ int mg_set_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip) ms_cleanup_work(chip); retval = ms_switch_clock(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } buf = kmalloc(1028, GFP_KERNEL); - if (!buf) { + if (!buf) TRACE_RET(chip, STATUS_ERROR); - } bufflen = min(1028, (int)scsi_bufflen(srb)); rtsx_stor_get_xfer_buf(buf, bufflen, srb); @@ -4088,11 +3902,10 @@ int mg_set_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip) retval = mg_send_ex_cmd(chip, MG_SET_IBD, ms_card->mg_entry_num); if (retval != STATUS_SUCCESS) { if (ms_card->mg_auth == 0) { - if ((buf[5] & 0xC0) != 0) { + if ((buf[5] & 0xC0) != 0) set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB); - } else { + else set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR); - } } else { set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR); } @@ -4121,11 +3934,10 @@ int mg_set_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip) if ((retval < 0) || check_ms_err(chip)) { rtsx_clear_ms_error(chip); if (ms_card->mg_auth == 0) { - if ((buf[5] & 0xC0) != 0) { + if ((buf[5] & 0xC0) != 0) set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB); - } else { + else set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR); - } } else { set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR); } @@ -4139,11 +3951,10 @@ int mg_set_ICV(struct scsi_cmnd *srb, struct rtsx_chip *chip) if ((retval != STATUS_SUCCESS) || check_ms_err(chip)) { rtsx_clear_ms_error(chip); if (ms_card->mg_auth == 0) { - if ((buf[5] & 0xC0) != 0) { + if ((buf[5] & 0xC0) != 0) set_sense_type(chip, lun, SENSE_TYPE_MG_KEY_FAIL_NOT_ESTAB); - } else { + else set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR); - } } else { set_sense_type(chip, lun, SENSE_TYPE_MG_WRITE_ERR); } @@ -4187,14 +3998,13 @@ int ms_power_off_card3v3(struct rtsx_chip *chip) int retval; retval = disable_card_clock(chip, MS_CARD); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + if (chip->asic_code) { retval = ms_pull_ctl_disable(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } else { RTSX_WRITE_REG(chip, FPGA_PULL_CTL, FPGA_MS_PULL_CTL_BIT | 0x20, FPGA_MS_PULL_CTL_BIT); @@ -4202,9 +4012,8 @@ int ms_power_off_card3v3(struct rtsx_chip *chip) RTSX_WRITE_REG(chip, CARD_OE, MS_OUTPUT_EN, 0); if (!chip->ft2_fast_mode) { retval = card_power_off(chip, MS_CARD); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } return STATUS_SUCCESS; @@ -4234,9 +4043,8 @@ int release_ms_card(struct rtsx_chip *chip) #endif retval = ms_power_off_card3v3(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } diff --git a/drivers/staging/rts_pstor/rtsx.c b/drivers/staging/rts_pstor/rtsx.c index 5fb05a2edebb..afe9c2e763d7 100644 --- a/drivers/staging/rts_pstor/rtsx.c +++ b/drivers/staging/rts_pstor/rtsx.c @@ -20,6 +20,8 @@ * No. 450, Shenhu Road, Suzhou Industry Park, Suzhou, China */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/blkdev.h> #include <linux/kthread.h> #include <linux/sched.h> @@ -170,14 +172,14 @@ static int queuecommand_lck(struct scsi_cmnd *srb, /* check for state-transition errors */ if (chip->srb != NULL) { - printk(KERN_ERR "Error in %s: chip->srb = %p\n", + dev_err(&dev->pci->dev, "Error in %s: chip->srb = %p\n", __func__, chip->srb); return SCSI_MLQUEUE_HOST_BUSY; } /* fail the command if we are disconnecting */ if (rtsx_chk_stat(chip, RTSX_STAT_DISCONNECT)) { - printk(KERN_INFO "Fail command during disconnect\n"); + dev_info(&dev->pci->dev, "Fail command during disconnect\n"); srb->result = DID_NO_CONNECT << 16; done(srb); return 0; @@ -204,14 +206,14 @@ static int command_abort(struct scsi_cmnd *srb) struct rtsx_dev *dev = host_to_rtsx(host); struct rtsx_chip *chip = dev->chip; - printk(KERN_INFO "%s called\n", __func__); + dev_info(&dev->pci->dev, "%s called\n", __func__); scsi_lock(host); /* Is this command still active? */ if (chip->srb != srb) { scsi_unlock(host); - printk(KERN_INFO "-- nothing to abort\n"); + dev_info(&dev->pci->dev, "-- nothing to abort\n"); return FAILED; } @@ -230,8 +232,9 @@ static int command_abort(struct scsi_cmnd *srb) static int device_reset(struct scsi_cmnd *srb) { int result = 0; + struct rtsx_dev *dev = host_to_rtsx(srb->device->host); - printk(KERN_INFO "%s called\n", __func__); + dev_info(&dev->pci->dev, "%s called\n", __func__); return result < 0 ? FAILED : SUCCESS; } @@ -240,8 +243,9 @@ static int device_reset(struct scsi_cmnd *srb) static int bus_reset(struct scsi_cmnd *srb) { int result = 0; + struct rtsx_dev *dev = host_to_rtsx(srb->device->host); - printk(KERN_INFO "%s called\n", __func__); + dev_info(&dev->pci->dev, "%s called\n", __func__); return result < 0 ? FAILED : SUCCESS; } @@ -303,14 +307,15 @@ static int rtsx_acquire_irq(struct rtsx_dev *dev) { struct rtsx_chip *chip = dev->chip; - printk(KERN_INFO "%s: chip->msi_en = %d, pci->irq = %d\n", - __func__, chip->msi_en, dev->pci->irq); + dev_info(&dev->pci->dev, "%s: chip->msi_en = %d, pci->irq = %d\n", + __func__, chip->msi_en, dev->pci->irq); if (request_irq(dev->pci->irq, rtsx_interrupt, chip->msi_en ? 0 : IRQF_SHARED, CR_DRIVER_NAME, dev)) { - printk(KERN_ERR "rtsx: unable to grab IRQ %d, " - "disabling device\n", dev->pci->irq); + dev_err(&dev->pci->dev, + "rtsx: unable to grab IRQ %d, disabling device\n", + dev->pci->irq); return -1; } @@ -347,12 +352,8 @@ static int rtsx_suspend(struct pci_dev *pci, pm_message_t state) struct rtsx_dev *dev = (struct rtsx_dev *)pci_get_drvdata(pci); struct rtsx_chip *chip; - printk(KERN_INFO "Ready to suspend\n"); - - if (!dev) { - printk(KERN_ERR "Invalid memory\n"); + if (!dev) return 0; - } /* lock the device pointers */ mutex_lock(&(dev->dev_mutex)); @@ -386,12 +387,8 @@ static int rtsx_resume(struct pci_dev *pci) struct rtsx_dev *dev = (struct rtsx_dev *)pci_get_drvdata(pci); struct rtsx_chip *chip; - printk(KERN_INFO "Ready to resume\n"); - - if (!dev) { - printk(KERN_ERR "Invalid memory\n"); + if (!dev) return 0; - } chip = dev->chip; @@ -401,8 +398,9 @@ static int rtsx_resume(struct pci_dev *pci) pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { - printk(KERN_ERR "%s: pci_enable_device failed, " - "disabling device\n", CR_DRIVER_NAME); + dev_err(&dev->pci->dev, + "%s: pci_enable_device failed, disabling device\n", + CR_DRIVER_NAME); /* unlock the device pointers */ mutex_unlock(&dev->dev_mutex); return -EIO; @@ -435,12 +433,8 @@ static void rtsx_shutdown(struct pci_dev *pci) struct rtsx_dev *dev = (struct rtsx_dev *)pci_get_drvdata(pci); struct rtsx_chip *chip; - printk(KERN_INFO "Ready to shutdown\n"); - - if (!dev) { - printk(KERN_ERR "Invalid memory\n"); + if (!dev) return; - } chip = dev->chip; @@ -475,7 +469,7 @@ static int rtsx_control_thread(void *__dev) /* if the device has disconnected, we are free to exit */ if (rtsx_chk_stat(chip, RTSX_STAT_DISCONNECT)) { - printk(KERN_INFO "-- rtsx-control exiting\n"); + dev_info(&dev->pci->dev, "-- rtsx-control exiting\n"); mutex_unlock(&dev->dev_mutex); break; } @@ -495,7 +489,7 @@ static int rtsx_control_thread(void *__dev) * is UNKNOWN */ if (chip->srb->sc_data_direction == DMA_BIDIRECTIONAL) { - printk(KERN_ERR "UNKNOWN data direction\n"); + dev_err(&dev->pci->dev, "UNKNOWN data direction\n"); chip->srb->result = DID_ERROR << 16; } @@ -503,14 +497,14 @@ static int rtsx_control_thread(void *__dev) * the maximum known LUN */ else if (chip->srb->device->id) { - printk(KERN_ERR "Bad target number (%d:%d)\n", + dev_err(&dev->pci->dev, "Bad target number (%d:%d)\n", chip->srb->device->id, chip->srb->device->lun); chip->srb->result = DID_BAD_TARGET << 16; } else if (chip->srb->device->lun > chip->max_lun) { - printk(KERN_ERR "Bad LUN (%d:%d)\n", + dev_err(&dev->pci->dev, "Bad LUN (%d:%d)\n", chip->srb->device->id, chip->srb->device->lun); chip->srb->result = DID_BAD_TARGET << 16; @@ -534,7 +528,7 @@ static int rtsx_control_thread(void *__dev) chip->srb->scsi_done(chip->srb); } else { SkipForAbort: - printk(KERN_ERR "scsi command aborted\n"); + dev_err(&dev->pci->dev, "scsi command aborted\n"); } if (rtsx_chk_stat(chip, RTSX_STAT_ABORT)) { @@ -594,7 +588,7 @@ static int rtsx_polling_thread(void *__dev) /* if the device has disconnected, we are free to exit */ if (rtsx_chk_stat(chip, RTSX_STAT_DISCONNECT)) { - printk(KERN_INFO "-- rtsx-polling exiting\n"); + dev_info(&dev->pci->dev, "-- rtsx-polling exiting\n"); mutex_unlock(&dev->dev_mutex); break; } @@ -683,13 +677,13 @@ Exit: /* Release all our dynamic resources */ static void rtsx_release_resources(struct rtsx_dev *dev) { - printk(KERN_INFO "-- %s\n", __func__); + dev_info(&dev->pci->dev, "-- %s\n", __func__); /* Tell the control thread to exit. The SCSI host must * already have been removed so it won't try to queue * any more commands. */ - printk(KERN_INFO "-- sending exit command to thread\n"); + dev_info(&dev->pci->dev, "-- sending exit command to thread\n"); complete(&dev->cmnd_ready); if (dev->ctl_thread) wait_for_completion(&dev->control_exit); @@ -774,8 +768,9 @@ static int rtsx_scan_thread(void *__dev) /* Wait for the timeout to expire or for a disconnect */ if (delay_use > 0) { - printk(KERN_INFO "%s: waiting for device " - "to settle before scanning\n", CR_DRIVER_NAME); + dev_info(&dev->pci->dev, + "%s: waiting for device to settle before scanning\n", + CR_DRIVER_NAME); wait_event_interruptible_timeout(dev->delay_wait, rtsx_chk_stat(chip, RTSX_STAT_DISCONNECT), delay_use * HZ); @@ -784,7 +779,8 @@ static int rtsx_scan_thread(void *__dev) /* If the device is still connected, perform the scanning */ if (!rtsx_chk_stat(chip, RTSX_STAT_DISCONNECT)) { scsi_scan_host(rtsx_to_host(dev)); - printk(KERN_INFO "%s: device scan complete\n", CR_DRIVER_NAME); + dev_info(&dev->pci->dev, "%s: device scan complete\n", + CR_DRIVER_NAME); /* Should we unbind if no devices were detected? */ } @@ -906,14 +902,14 @@ static int __devinit rtsx_probe(struct pci_dev *pci, err = pci_enable_device(pci); if (err < 0) { - printk(KERN_ERR "PCI enable device failed!\n"); + dev_err(&pci->dev, "PCI enable device failed!\n"); return err; } err = pci_request_regions(pci, CR_DRIVER_NAME); if (err < 0) { - printk(KERN_ERR "PCI request regions for %s failed!\n", - CR_DRIVER_NAME); + dev_err(&pci->dev, "PCI request regions for %s failed!\n", + CR_DRIVER_NAME); pci_disable_device(pci); return err; } @@ -924,7 +920,7 @@ static int __devinit rtsx_probe(struct pci_dev *pci, */ host = scsi_host_alloc(&rtsx_host_template, sizeof(*dev)); if (!host) { - printk(KERN_ERR "Unable to allocate the scsi host\n"); + dev_err(&pci->dev, "Unable to allocate the scsi host\n"); pci_release_regions(pci); pci_disable_device(pci); return -ENOMEM; @@ -949,12 +945,12 @@ static int __devinit rtsx_probe(struct pci_dev *pci, dev->pci = pci; dev->irq = -1; - printk(KERN_INFO "Resource length: 0x%x\n", - (unsigned int)pci_resource_len(pci, 0)); + dev_info(&pci->dev, "Resource length: 0x%x\n", + (unsigned int)pci_resource_len(pci, 0)); dev->addr = pci_resource_start(pci, 0); dev->remap_addr = ioremap_nocache(dev->addr, pci_resource_len(pci, 0)); if (dev->remap_addr == NULL) { - printk(KERN_ERR "ioremap error\n"); + dev_err(&pci->dev, "ioremap error\n"); err = -ENXIO; goto errout; } @@ -963,13 +959,13 @@ static int __devinit rtsx_probe(struct pci_dev *pci, * Using "unsigned long" cast here to eliminate gcc warning in * 64-bit system */ - printk(KERN_INFO "Original address: 0x%lx, remapped address: 0x%lx\n", - (unsigned long)(dev->addr), (unsigned long)(dev->remap_addr)); + dev_info(&pci->dev, "Original address: 0x%lx, remapped address: 0x%lx\n", + (unsigned long)(dev->addr), (unsigned long)(dev->remap_addr)); dev->rtsx_resv_buf = dma_alloc_coherent(&(pci->dev), RTSX_RESV_BUF_LEN, &(dev->rtsx_resv_buf_addr), GFP_KERNEL); if (dev->rtsx_resv_buf == NULL) { - printk(KERN_ERR "alloc dma buffer fail\n"); + dev_err(&pci->dev, "alloc dma buffer fail\n"); err = -ENXIO; goto errout; } @@ -983,7 +979,7 @@ static int __devinit rtsx_probe(struct pci_dev *pci, rtsx_init_options(dev->chip); - printk(KERN_INFO "pci->irq = %d\n", pci->irq); + dev_info(&pci->dev, "pci->irq = %d\n", pci->irq); if (dev->chip->msi_en) { if (pci_enable_msi(pci) < 0) @@ -1008,7 +1004,7 @@ static int __devinit rtsx_probe(struct pci_dev *pci, /* Start up our control thread */ th = kthread_run(rtsx_control_thread, dev, CR_DRIVER_NAME); if (IS_ERR(th)) { - printk(KERN_ERR "Unable to start control thread\n"); + dev_err(&pci->dev, "Unable to start control thread\n"); err = PTR_ERR(th); goto errout; } @@ -1016,14 +1012,14 @@ static int __devinit rtsx_probe(struct pci_dev *pci, err = scsi_add_host(host, &pci->dev); if (err) { - printk(KERN_ERR "Unable to add the scsi host\n"); + dev_err(&pci->dev, "Unable to add the scsi host\n"); goto errout; } /* Start up the thread for delayed SCSI-device scanning */ th = kthread_run(rtsx_scan_thread, dev, "rtsx-scan"); if (IS_ERR(th)) { - printk(KERN_ERR "Unable to start the device-scanning thread\n"); + dev_err(&pci->dev, "Unable to start the device-scanning thread\n"); complete(&dev->scanning_done); quiesce_and_remove_host(dev); err = PTR_ERR(th); @@ -1033,7 +1029,7 @@ static int __devinit rtsx_probe(struct pci_dev *pci, /* Start up the thread for polling thread */ th = kthread_run(rtsx_polling_thread, dev, "rtsx-polling"); if (IS_ERR(th)) { - printk(KERN_ERR "Unable to start the device-polling thread\n"); + dev_err(&pci->dev, "Unable to start the device-polling thread\n"); quiesce_and_remove_host(dev); err = PTR_ERR(th); goto errout; @@ -1046,7 +1042,7 @@ static int __devinit rtsx_probe(struct pci_dev *pci, /* We come here if there are any problems */ errout: - printk(KERN_ERR "rtsx_probe() failed\n"); + dev_err(&pci->dev, "rtsx_probe() failed\n"); release_everything(dev); return err; @@ -1057,7 +1053,7 @@ static void __devexit rtsx_remove(struct pci_dev *pci) { struct rtsx_dev *dev = (struct rtsx_dev *)pci_get_drvdata(pci); - printk(KERN_INFO "rtsx_remove() called\n"); + dev_info(&pci->dev, "rtsx_remove() called\n"); quiesce_and_remove_host(dev); release_everything(dev); @@ -1090,18 +1086,18 @@ static struct pci_driver driver = { static int __init rtsx_init(void) { - printk(KERN_INFO "Initializing Realtek PCIE storage driver...\n"); + pr_info("Initializing Realtek PCIE storage driver...\n"); return pci_register_driver(&driver); } static void __exit rtsx_exit(void) { - printk(KERN_INFO "rtsx_exit() called\n"); + pr_info("rtsx_exit() called\n"); pci_unregister_driver(&driver); - printk(KERN_INFO "%s module exit\n", CR_DRIVER_NAME); + pr_info("%s module exit\n", CR_DRIVER_NAME); } module_init(rtsx_init) diff --git a/drivers/staging/rts_pstor/rtsx_card.c b/drivers/staging/rts_pstor/rtsx_card.c index 4f971f2e930a..539aa6a27788 100644 --- a/drivers/staging/rts_pstor/rtsx_card.c +++ b/drivers/staging/rts_pstor/rtsx_card.c @@ -309,11 +309,10 @@ static void release_sdio(struct rtsx_chip *chip) if (chip->chip_insert_with_sdio) { chip->chip_insert_with_sdio = 0; - if (CHECK_PID(chip, 0x5288)) { + if (CHECK_PID(chip, 0x5288)) rtsx_write_register(chip, 0xFE5A, 0x08, 0x00); - } else { + else rtsx_write_register(chip, 0xFE70, 0x80, 0x00); - } } rtsx_write_register(chip, SDIO_CTRL, SDIO_CD_CTRL, 0); @@ -379,11 +378,10 @@ void rtsx_reset_cards(struct rtsx_chip *chip) if (chip->need_reset & XD_CARD) { chip->card_exist |= XD_CARD; - if (chip->xd_show_cnt >= MAX_SHOW_CNT) { + if (chip->xd_show_cnt >= MAX_SHOW_CNT) do_reset_xd_card(chip); - } else { + else chip->xd_show_cnt++; - } } if (CHECK_PID(chip, 0x5288) && CHECK_BARO_PKG(chip, QFN)) { if (chip->card_exist & XD_CARD) { @@ -404,11 +402,10 @@ void rtsx_reset_cards(struct rtsx_chip *chip) if (chip->need_reset & MS_CARD) { chip->card_exist |= MS_CARD; - if (chip->ms_show_cnt >= MAX_SHOW_CNT) { + if (chip->ms_show_cnt >= MAX_SHOW_CNT) do_reset_ms_card(chip); - } else { + else chip->ms_show_cnt++; - } } } @@ -473,13 +470,12 @@ void card_cd_debounce(struct rtsx_chip *chip, unsigned long *need_reset, unsigne release_map |= MS_CARD; } } else { - if (chip->int_reg & XD_EXIST) { + if (chip->int_reg & XD_EXIST) reset_map |= XD_CARD; - } else if (chip->int_reg & SD_EXIST) { + else if (chip->int_reg & SD_EXIST) reset_map |= SD_CARD; - } else if (chip->int_reg & MS_EXIST) { + else if (chip->int_reg & MS_EXIST) reset_map |= MS_CARD; - } } if (reset_map) { @@ -489,21 +485,21 @@ void card_cd_debounce(struct rtsx_chip *chip, unsigned long *need_reset, unsigne for (i = 0; i < (DEBOUNCE_CNT); i++) { chip->int_reg = rtsx_readl(chip, RTSX_BIPR); - if (chip->int_reg & XD_EXIST) { + if (chip->int_reg & XD_EXIST) xd_cnt++; - } else { + else xd_cnt = 0; - } - if (chip->int_reg & SD_EXIST) { + + if (chip->int_reg & SD_EXIST) sd_cnt++; - } else { + else sd_cnt = 0; - } - if (chip->int_reg & MS_EXIST) { + + if (chip->int_reg & MS_EXIST) ms_cnt++; - } else { + else ms_cnt = 0; - } + wait_timeout(30); } @@ -677,9 +673,8 @@ int switch_ssc_clock(struct rtsx_chip *chip, int clk) RTSX_DEBUGP("Switch SSC clock to %dMHz (cur_clk = %d)\n", clk, chip->cur_clk); - if ((clk <= 2) || (N > max_N)) { + if ((clk <= 2) || (N > max_N)) TRACE_RET(chip, STATUS_FAIL); - } mcu_cnt = (u8)(125/clk + 3); if (CHECK_PID(chip, 0x5209)) { @@ -700,32 +695,29 @@ int switch_ssc_clock(struct rtsx_chip *chip, int clk) if (chip->ssc_en) { if (CHECK_PID(chip, 0x5209)) { if (chip->cur_card == SD_CARD) { - if (CHK_SD_SDR104(sd_card)) { + if (CHK_SD_SDR104(sd_card)) ssc_depth = chip->ssc_depth_sd_sdr104; - } else if (CHK_SD_SDR50(sd_card)) { + else if (CHK_SD_SDR50(sd_card)) ssc_depth = chip->ssc_depth_sd_sdr50; - } else if (CHK_SD_DDR50(sd_card)) { + else if (CHK_SD_DDR50(sd_card)) ssc_depth = double_depth(chip->ssc_depth_sd_ddr50); - } else if (CHK_SD_HS(sd_card)) { + else if (CHK_SD_HS(sd_card)) ssc_depth = double_depth(chip->ssc_depth_sd_hs); - } else if (CHK_MMC_52M(sd_card) || CHK_MMC_DDR52(sd_card)) { + else if (CHK_MMC_52M(sd_card) || CHK_MMC_DDR52(sd_card)) ssc_depth = double_depth(chip->ssc_depth_mmc_52m); - } else { + else ssc_depth = double_depth(chip->ssc_depth_low_speed); - } } else if (chip->cur_card == MS_CARD) { if (CHK_MSPRO(ms_card)) { - if (CHK_HG8BIT(ms_card)) { + if (CHK_HG8BIT(ms_card)) ssc_depth = double_depth(chip->ssc_depth_ms_hg); - } else { + else ssc_depth = double_depth(chip->ssc_depth_ms_4bit); - } } else { - if (CHK_MS4BIT(ms_card)) { + if (CHK_MS4BIT(ms_card)) ssc_depth = double_depth(chip->ssc_depth_ms_4bit); - } else { + else ssc_depth = double_depth(chip->ssc_depth_low_speed); - } } } else { ssc_depth = double_depth(chip->ssc_depth_low_speed); @@ -733,23 +725,23 @@ int switch_ssc_clock(struct rtsx_chip *chip, int clk) if (ssc_depth) { if (div == CLK_DIV_2) { - if (ssc_depth > 1) { + if (ssc_depth > 1) ssc_depth -= 1; - } else { + else ssc_depth = SSC_DEPTH_4M; - } + } else if (div == CLK_DIV_4) { - if (ssc_depth > 2) { + if (ssc_depth > 2) ssc_depth -= 2; - } else { + else ssc_depth = SSC_DEPTH_4M; - } + } else if (div == CLK_DIV_8) { - if (ssc_depth > 3) { + if (ssc_depth > 3) ssc_depth -= 3; - } else { + else ssc_depth = SSC_DEPTH_4M; - } + } } } else { @@ -760,11 +752,10 @@ int switch_ssc_clock(struct rtsx_chip *chip, int clk) ssc_depth = 0; } - if (CHECK_PID(chip, 0x5209)) { + if (CHECK_PID(chip, 0x5209)) ssc_depth_mask = SSC_DEPTH_MASK; - } else { + else ssc_depth_mask = 0x03; - } RTSX_DEBUGP("ssc_depth = %d\n", ssc_depth); @@ -781,9 +772,8 @@ int switch_ssc_clock(struct rtsx_chip *chip, int clk) } retval = rtsx_send_cmd(chip, 0, WAIT_TIME); - if (retval < 0) { + if (retval < 0) TRACE_RET(chip, STATUS_ERROR); - } udelay(10); RTSX_WRITE_REG(chip, CLK_CTL, CLK_LOW_FREQ, 0); @@ -976,25 +966,23 @@ int card_power_on(struct rtsx_chip *chip, u8 card) rtsx_init_cmd(chip); rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL, mask, val1); - if (CHECK_PID(chip, 0x5209) && (card == SD_CARD)) { + if (CHECK_PID(chip, 0x5209) && (card == SD_CARD)) rtsx_add_cmd(chip, WRITE_REG_CMD, PWR_GATE_CTRL, LDO3318_PWR_MASK, LDO_SUSPEND); - } + retval = rtsx_send_cmd(chip, 0, 100); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } udelay(chip->pmos_pwr_on_interval); rtsx_init_cmd(chip); rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_PWR_CTL, mask, val2); - if (CHECK_PID(chip, 0x5209) && (card == SD_CARD)) { + if (CHECK_PID(chip, 0x5209) && (card == SD_CARD)) rtsx_add_cmd(chip, WRITE_REG_CMD, PWR_GATE_CTRL, LDO3318_PWR_MASK, LDO_ON); - } + retval = rtsx_send_cmd(chip, 0, 100); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -1016,9 +1004,8 @@ int card_power_off(struct rtsx_chip *chip, u8 card) } RTSX_WRITE_REG(chip, CARD_PWR_CTL, mask, val); - if (CHECK_PID(chip, 0x5209) && (card == SD_CARD)) { + if (CHECK_PID(chip, 0x5209) && (card == SD_CARD)) RTSX_WRITE_REG(chip, PWR_GATE_CTRL, LDO3318_PWR_MASK, LDO_OFF); - } return STATUS_SUCCESS; } @@ -1029,9 +1016,8 @@ int card_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip, u32 sec_addr, u16 sec unsigned int lun = SCSI_LUN(srb); int i; - if (chip->rw_card[lun] == NULL) { + if (chip->rw_card[lun] == NULL) TRACE_RET(chip, STATUS_FAIL); - } for (i = 0; i < 3; i++) { chip->rw_need_retry = 0; @@ -1042,9 +1028,9 @@ int card_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip, u32 sec_addr, u16 sec rtsx_release_chip(chip); TRACE_RET(chip, STATUS_FAIL); } - if (detect_card_cd(chip, chip->cur_card) != STATUS_SUCCESS) { + if (detect_card_cd(chip, chip->cur_card) != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + if (!chip->rw_need_retry) { RTSX_DEBUGP("RW fail, but no need to retry\n"); break; @@ -1066,26 +1052,26 @@ int card_share_mode(struct rtsx_chip *chip, int card) if (CHECK_PID(chip, 0x5209) || CHECK_PID(chip, 0x5208)) { mask = CARD_SHARE_MASK; - if (card == SD_CARD) { + if (card == SD_CARD) value = CARD_SHARE_48_SD; - } else if (card == MS_CARD) { + else if (card == MS_CARD) value = CARD_SHARE_48_MS; - } else if (card == XD_CARD) { + else if (card == XD_CARD) value = CARD_SHARE_48_XD; - } else { + else TRACE_RET(chip, STATUS_FAIL); - } + } else if (CHECK_PID(chip, 0x5288)) { mask = 0x03; - if (card == SD_CARD) { + if (card == SD_CARD) value = CARD_SHARE_BAROSSA_SD; - } else if (card == MS_CARD) { + else if (card == MS_CARD) value = CARD_SHARE_BAROSSA_MS; - } else if (card == XD_CARD) { + else if (card == XD_CARD) value = CARD_SHARE_BAROSSA_XD; - } else { + else TRACE_RET(chip, STATUS_FAIL); - } + } else { TRACE_RET(chip, STATUS_FAIL); } @@ -1103,24 +1089,23 @@ int select_card(struct rtsx_chip *chip, int card) if (chip->cur_card != card) { u8 mod; - if (card == SD_CARD) { + if (card == SD_CARD) mod = SD_MOD_SEL; - } else if (card == MS_CARD) { + else if (card == MS_CARD) mod = MS_MOD_SEL; - } else if (card == XD_CARD) { + else if (card == XD_CARD) mod = XD_MOD_SEL; - } else if (card == SPI_CARD) { + else if (card == SPI_CARD) mod = SPI_MOD_SEL; - } else { + else TRACE_RET(chip, STATUS_FAIL); - } + RTSX_WRITE_REG(chip, CARD_SELECT, 0x07, mod); chip->cur_card = card; retval = card_share_mode(chip, card); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } return STATUS_SUCCESS; @@ -1137,20 +1122,18 @@ void toggle_gpio(struct rtsx_chip *chip, u8 gpio) void turn_on_led(struct rtsx_chip *chip, u8 gpio) { - if (CHECK_PID(chip, 0x5288)) { + if (CHECK_PID(chip, 0x5288)) rtsx_write_register(chip, CARD_GPIO, (u8)(1 << gpio), (u8)(1 << gpio)); - } else { + else rtsx_write_register(chip, CARD_GPIO, (u8)(1 << gpio), 0); - } } void turn_off_led(struct rtsx_chip *chip, u8 gpio) { - if (CHECK_PID(chip, 0x5288)) { + if (CHECK_PID(chip, 0x5288)) rtsx_write_register(chip, CARD_GPIO, (u8)(1 << gpio), 0); - } else { + else rtsx_write_register(chip, CARD_GPIO, (u8)(1 << gpio), (u8)(1 << gpio)); - } } int detect_card_cd(struct rtsx_chip *chip, int card) @@ -1169,67 +1152,60 @@ int detect_card_cd(struct rtsx_chip *chip, int card) } status = rtsx_readl(chip, RTSX_BIPR); - if (!(status & card_cd)) { + if (!(status & card_cd)) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } int check_card_exist(struct rtsx_chip *chip, unsigned int lun) { - if (chip->card_exist & chip->lun2card[lun]) { + if (chip->card_exist & chip->lun2card[lun]) return 1; - } return 0; } int check_card_ready(struct rtsx_chip *chip, unsigned int lun) { - if (chip->card_ready & chip->lun2card[lun]) { + if (chip->card_ready & chip->lun2card[lun]) return 1; - } return 0; } int check_card_wp(struct rtsx_chip *chip, unsigned int lun) { - if (chip->card_wp & chip->lun2card[lun]) { + if (chip->card_wp & chip->lun2card[lun]) return 1; - } return 0; } int check_card_fail(struct rtsx_chip *chip, unsigned int lun) { - if (chip->card_fail & chip->lun2card[lun]) { + if (chip->card_fail & chip->lun2card[lun]) return 1; - } return 0; } int check_card_ejected(struct rtsx_chip *chip, unsigned int lun) { - if (chip->card_ejected & chip->lun2card[lun]) { + if (chip->card_ejected & chip->lun2card[lun]) return 1; - } return 0; } u8 get_lun_card(struct rtsx_chip *chip, unsigned int lun) { - if ((chip->card_ready & chip->lun2card[lun]) == XD_CARD) { + if ((chip->card_ready & chip->lun2card[lun]) == XD_CARD) return (u8)XD_CARD; - } else if ((chip->card_ready & chip->lun2card[lun]) == SD_CARD) { + else if ((chip->card_ready & chip->lun2card[lun]) == SD_CARD) return (u8)SD_CARD; - } else if ((chip->card_ready & chip->lun2card[lun]) == MS_CARD) { + else if ((chip->card_ready & chip->lun2card[lun]) == MS_CARD) return (u8)MS_CARD; - } return 0; } diff --git a/drivers/staging/rts_pstor/rtsx_chip.c b/drivers/staging/rts_pstor/rtsx_chip.c index 5452069fbe08..d8e691b99028 100644 --- a/drivers/staging/rts_pstor/rtsx_chip.c +++ b/drivers/staging/rts_pstor/rtsx_chip.c @@ -105,11 +105,10 @@ void rtsx_enable_bus_int(struct rtsx_chip *chip) reg |= DELINK_INT_EN; #ifdef SUPPORT_OCP if (CHECK_PID(chip, 0x5209)) { - if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) { + if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) reg |= MS_OC_INT_EN | SD_OC_INT_EN; - } else { + else reg |= SD_OC_INT_EN; - } } else { reg |= OC_INT_EN; } @@ -186,20 +185,20 @@ static int rtsx_pre_handle_sdio_new(struct rtsx_chip *chip) u8 cd_toggle_mask = 0; RTSX_READ_REG(chip, TLPTISTAT, &tmp); - if (CHECK_PID(chip, 0x5209)) { + if (CHECK_PID(chip, 0x5209)) cd_toggle_mask = 0x10; - } else { + else cd_toggle_mask = 0x08; - } + if (tmp & cd_toggle_mask) { /* Disable sdio_bus_auto_switch */ - if (CHECK_PID(chip, 0x5288)) { + if (CHECK_PID(chip, 0x5288)) RTSX_WRITE_REG(chip, 0xFE5A, 0x08, 0x00); - } else if (CHECK_PID(chip, 0x5208)) { + else if (CHECK_PID(chip, 0x5208)) RTSX_WRITE_REG(chip, 0xFE70, 0x80, 0x00); - } else { + else RTSX_WRITE_REG(chip, SDIO_CFG, SDIO_BUS_AUTO_SWITCH, 0); - } + RTSX_WRITE_REG(chip, TLPTISTAT, 0xFF, tmp); chip->need_reset |= SD_CARD; @@ -208,16 +207,14 @@ static int rtsx_pre_handle_sdio_new(struct rtsx_chip *chip) if (chip->asic_code) { retval = sd_pull_ctl_enable(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } else { RTSX_WRITE_REG(chip, FPGA_PULL_CTL, FPGA_SD_PULL_CTL_BIT | 0x20, 0); } retval = card_share_mode(chip, SD_CARD); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } /* Enable sdio_bus_auto_switch */ if (CHECK_PID(chip, 0x5288)) { @@ -232,11 +229,11 @@ static int rtsx_pre_handle_sdio_new(struct rtsx_chip *chip) chip->sd_io = 1; } } else { - if (CHECK_PID(chip, 0x5209)) { + if (CHECK_PID(chip, 0x5209)) RTSX_WRITE_REG(chip, TLPTISTAT, 0x10, 0x10); - } else { + else RTSX_WRITE_REG(chip, TLPTISTAT, 0x08, 0x08); - } + chip->need_reset |= SD_CARD; } @@ -257,48 +254,47 @@ int rtsx_reset_chip(struct rtsx_chip *chip) /* optimize PHY */ retval = rtsx_write_phy_register(chip, 0x00, 0xB966); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + retval = rtsx_write_phy_register(chip, 0x01, 0x713F); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + retval = rtsx_write_phy_register(chip, 0x03, 0xA549); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + retval = rtsx_write_phy_register(chip, 0x06, 0xB235); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + retval = rtsx_write_phy_register(chip, 0x07, 0xEF40); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + retval = rtsx_write_phy_register(chip, 0x1E, 0xF8EB); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + retval = rtsx_write_phy_register(chip, 0x19, 0xFE6C); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + wait_timeout(1); retval = rtsx_write_phy_register(chip, 0x0A, 0x05C0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + retval = rtsx_write_cfg_dw(chip, 1, 0x110, 0xFFFF, 0xFFFF); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = rtsx_read_phy_register(chip, 0x08, &val); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + RTSX_DEBUGP("Read from phy 0x08: 0x%04x\n", val); if (chip->phy_voltage) { @@ -308,9 +304,9 @@ int rtsx_reset_chip(struct rtsx_chip *chip) val |= chip->phy_voltage; RTSX_DEBUGP("Write to phy 0x08: 0x%04x\n", val); retval = rtsx_write_phy_register(chip, 0x08, val); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + } else { chip->phy_voltage = (u8)(val & 0x3F); RTSX_DEBUGP("Default, chip->phy_voltage = 0x%x\n", chip->phy_voltage); @@ -324,11 +320,11 @@ int rtsx_reset_chip(struct rtsx_chip *chip) #ifdef SUPPORT_OCP /* SSC power on, OCD power on */ - if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) { + if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) RTSX_WRITE_REG(chip, FPDCTL, OC_POWER_DOWN, 0); - } else { + else RTSX_WRITE_REG(chip, FPDCTL, OC_POWER_DOWN, MS_OC_POWER_DOWN); - } + if (CHECK_PID(chip, 0x5209)) { RTSX_WRITE_REG(chip, OCPPARA1, SD_OCP_TIME_MASK | MS_OCP_TIME_MASK, SD_OCP_TIME_800 | MS_OCP_TIME_800); @@ -352,9 +348,8 @@ int rtsx_reset_chip(struct rtsx_chip *chip) RTSX_WRITE_REG(chip, FPDCTL, OC_POWER_DOWN, OC_POWER_DOWN); #endif - if (!CHECK_PID(chip, 0x5288)) { + if (!CHECK_PID(chip, 0x5288)) RTSX_WRITE_REG(chip, CARD_GPIO_DIR, 0xFF, 0x03); - } /* Turn off LED */ RTSX_WRITE_REG(chip, CARD_GPIO, 0xFF, 0x03); @@ -364,9 +359,8 @@ int rtsx_reset_chip(struct rtsx_chip *chip) /* Card driving select */ RTSX_WRITE_REG(chip, CARD_DRIVE_SEL, 0xFF, chip->card_drive_sel); - if (CHECK_PID(chip, 0x5209)) { + if (CHECK_PID(chip, 0x5209)) RTSX_WRITE_REG(chip, SD30_DRIVE_SEL, 0x07, chip->sd30_drive_sel_3v3); - } #ifdef LED_AUTO_BLINK RTSX_WRITE_REG(chip, CARD_AUTO_BLINK, 0xFF, @@ -394,36 +388,34 @@ int rtsx_reset_chip(struct rtsx_chip *chip) if (CHK_SDIO_EXIST(chip)) { if (CHECK_PID(chip, 0x5209)) { retval = rtsx_write_cfg_dw(chip, 1, 0xC0, 0xFF, chip->aspm_l0s_l1_en); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + } else if (CHECK_PID(chip, 0x5288)) { retval = rtsx_write_cfg_dw(chip, 2, 0xC0, 0xFF, chip->aspm_l0s_l1_en); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } } } else { - if (CHECK_PID(chip, 0x5208)) { + if (CHECK_PID(chip, 0x5208)) RTSX_WRITE_REG(chip, ASPM_FORCE_CTL, 0xFF, 0x3F); - } retval = rtsx_write_config_byte(chip, LCTLR, chip->aspm_l0s_l1_en); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + chip->aspm_level[0] = chip->aspm_l0s_l1_en; if (CHK_SDIO_EXIST(chip)) { chip->aspm_level[1] = chip->aspm_l0s_l1_en; - if (CHECK_PID(chip, 0x5288)) { + if (CHECK_PID(chip, 0x5288)) retval = rtsx_write_cfg_dw(chip, 2, 0xC0, 0xFF, chip->aspm_l0s_l1_en); - } else { + else retval = rtsx_write_cfg_dw(chip, 1, 0xC0, 0xFF, chip->aspm_l0s_l1_en); - } - if (retval != STATUS_SUCCESS) { + + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + } chip->aspm_enabled = 1; @@ -431,49 +423,45 @@ int rtsx_reset_chip(struct rtsx_chip *chip) } else { if (chip->asic_code && CHECK_PID(chip, 0x5208)) { retval = rtsx_write_phy_register(chip, 0x07, 0x0129); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } retval = rtsx_write_config_byte(chip, LCTLR, chip->aspm_l0s_l1_en); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } retval = rtsx_write_config_byte(chip, 0x81, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (CHK_SDIO_EXIST(chip)) { - if (CHECK_PID(chip, 0x5288)) { + if (CHECK_PID(chip, 0x5288)) retval = rtsx_write_cfg_dw(chip, 2, 0xC0, 0xFF00, 0x0100); - } else { + else retval = rtsx_write_cfg_dw(chip, 1, 0xC0, 0xFF00, 0x0100); - } - if (retval != STATUS_SUCCESS) { + + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + } if (CHECK_PID(chip, 0x5209)) { retval = rtsx_write_cfg_dw(chip, 0, 0x70C, 0xFF000000, 0x5B); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } if (CHECK_PID(chip, 0x5288)) { if (!CHK_SDIO_EXIST(chip)) { retval = rtsx_write_cfg_dw(chip, 2, 0xC0, 0xFFFF, 0x0103); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + retval = rtsx_write_cfg_dw(chip, 2, 0x84, 0xFF, 0x03); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + } } @@ -499,29 +487,29 @@ int rtsx_reset_chip(struct rtsx_chip *chip) if (chip->ic_version >= IC_VER_D) { u16 reg; retval = rtsx_read_phy_register(chip, 0x00, ®); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + reg &= 0xFE7F; reg |= 0x80; retval = rtsx_write_phy_register(chip, 0x00, reg); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + retval = rtsx_read_phy_register(chip, 0x1C, ®); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + reg &= 0xFFF7; retval = rtsx_write_phy_register(chip, 0x1C, reg); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + } - if (chip->driver_first_load && (chip->ic_version < IC_VER_C)) { + if (chip->driver_first_load && (chip->ic_version < IC_VER_C)) rtsx_calibration(chip); - } + } else { rtsx_enable_bus_int(chip); } @@ -550,18 +538,18 @@ int rtsx_reset_chip(struct rtsx_chip *chip) RTSX_DEBUGP("In rtsx_reset_chip, chip->int_reg = 0x%x\n", chip->int_reg); if (chip->int_reg & SD_EXIST) { #ifdef HW_AUTO_SWITCH_SD_BUS - if (CHECK_PID(chip, 0x5208) && (chip->ic_version < IC_VER_C)) { + if (CHECK_PID(chip, 0x5208) && (chip->ic_version < IC_VER_C)) retval = rtsx_pre_handle_sdio_old(chip); - } else { + else retval = rtsx_pre_handle_sdio_new(chip); - } + RTSX_DEBUGP("chip->need_reset = 0x%x (rtsx_reset_chip)\n", (unsigned int)(chip->need_reset)); #else /* HW_AUTO_SWITCH_SD_BUS */ retval = rtsx_pre_handle_sdio_old(chip); #endif /* HW_AUTO_SWITCH_SD_BUS */ - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + } else { chip->sd_io = 0; RTSX_WRITE_REG(chip, SDIO_CTRL, SDIO_BUS_CTRL | SDIO_CD_CTRL, 0); @@ -572,9 +560,8 @@ NextCard: chip->need_reset |= XD_CARD; if (chip->int_reg & MS_EXIST) chip->need_reset |= MS_CARD; - if (chip->int_reg & CARD_EXIST) { + if (chip->int_reg & CARD_EXIST) RTSX_WRITE_REG(chip, SSC_CTL1, SSC_RSTB, SSC_RSTB); - } RTSX_DEBUGP("In rtsx_init_chip, chip->need_reset = 0x%x\n", (unsigned int)(chip->need_reset)); @@ -587,9 +574,8 @@ NextCard: if (chip->remote_wakeup_en && !chip->auto_delink_en) { RTSX_WRITE_REG(chip, WAKE_SEL_CTL, 0x07, 0x07); - if (chip->aux_pwr_exist) { + if (chip->aux_pwr_exist) RTSX_WRITE_REG(chip, PME_FORCE_CTL, 0xFF, 0x33); - } } else { RTSX_WRITE_REG(chip, WAKE_SEL_CTL, 0x07, 0x04); RTSX_WRITE_REG(chip, PME_FORCE_CTL, 0xFF, 0x30); @@ -598,18 +584,16 @@ NextCard: if (CHECK_PID(chip, 0x5208) && (chip->ic_version >= IC_VER_D)) { RTSX_WRITE_REG(chip, PETXCFG, 0x1C, 0x14); } else if (CHECK_PID(chip, 0x5209)) { - if (chip->force_clkreq_0) { + if (chip->force_clkreq_0) RTSX_WRITE_REG(chip, PETXCFG, 0x08, 0x08); - } else { + else RTSX_WRITE_REG(chip, PETXCFG, 0x08, 0x00); - } } if (chip->asic_code && CHECK_PID(chip, 0x5208)) { retval = rtsx_clr_phy_reg_bit(chip, 0x1C, 2); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } if (chip->ft2_fast_mode) { @@ -665,11 +649,10 @@ static int rts5209_init(struct rtsx_chip *chip) u8 val = 0; val = rtsx_readb(chip, 0x1C); - if ((val & 0x10) == 0) { + if ((val & 0x10) == 0) chip->asic_code = 1; - } else { + else chip->asic_code = 0; - } chip->ic_version = val & 0x0F; chip->phy_debug_mode = 0; @@ -679,9 +662,9 @@ static int rts5209_init(struct rtsx_chip *chip) chip->ms_power_class_en = 0x03; retval = rtsx_read_cfg_dw(chip, 0, 0x724, &lval); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + RTSX_DEBUGP("dw in 0x724: 0x%x\n", lval); val = (u8)lval; if (!(val & 0x80)) { @@ -690,17 +673,16 @@ static int rts5209_init(struct rtsx_chip *chip) else chip->lun_mode = SD_MS_2LUN; - if (val & 0x04) { + if (val & 0x04) SET_SDIO_EXIST(chip); - } else { + else CLR_SDIO_EXIST(chip); - } - if (val & 0x02) { + if (val & 0x02) chip->hw_bypass_sd = 0; - } else { + else chip->hw_bypass_sd = 1; - } + } else { SET_SDIO_EXIST(chip); chip->hw_bypass_sd = 0; @@ -714,24 +696,21 @@ static int rts5209_init(struct rtsx_chip *chip) val = (u8)(lval >> 8); clk = (val >> 5) & 0x07; - if (clk != 0x07) { + if (clk != 0x07) chip->asic_sd_sdr50_clk = 98 - clk * 2; - } - if (val & 0x10) { + if (val & 0x10) chip->auto_delink_en = 1; - } else { + else chip->auto_delink_en = 0; - } if (chip->ss_en == 2) { chip->ss_en = 0; } else { - if (val & 0x08) { + if (val & 0x08) chip->ss_en = 1; - } else { + else chip->ss_en = 0; - } } clk = val & 0x07; @@ -750,21 +729,21 @@ static int rts5209_init(struct rtsx_chip *chip) if (clk != 0x03) chip->asic_sd_ddr50_clk = (48 - clk * 2) * 2; - if (val & 0x01) { + if (val & 0x01) chip->sdr104_en = 1; - } else { + else chip->sdr104_en = 0; - } - if (val & 0x02) { + + if (val & 0x02) chip->ddr50_en = 1; - } else { + else chip->ddr50_en = 0; - } - if (val & 0x04) { + + if (val & 0x04) chip->sdr50_en = 1; - } else { + else chip->sdr50_en = 0; - } + val = (u8)(lval >> 24); @@ -772,11 +751,10 @@ static int rts5209_init(struct rtsx_chip *chip) if (clk != 0x07) chip->asic_sd_sdr104_clk = 206 - clk * 3; - if (val & 0x10) { + if (val & 0x10) chip->power_down_in_ss = 1; - } else { + else chip->power_down_in_ss = 0; - } chip->ms_power_class_en = val & 0x03; } @@ -786,20 +764,19 @@ static int rts5209_init(struct rtsx_chip *chip) retval = rtsx_read_pci_cfg_byte(0x00, 0x1C, 0x02, 0x58, ®58); - if (retval < 0) { + if (retval < 0) return STATUS_SUCCESS; - } + retval = rtsx_read_pci_cfg_byte(0x00, 0x1C, 0x02, 0x5B, ®5b); - if (retval < 0) { + if (retval < 0) return STATUS_SUCCESS; - } RTSX_DEBUGP("reg58 = 0x%x, reg5b = 0x%x\n", reg58, reg5b); - if ((reg58 == 0x00) && (reg5b == 0x01)) { + if ((reg58 == 0x00) && (reg5b == 0x01)) chip->auto_delink_en = 0; - } + } return STATUS_SUCCESS; @@ -813,24 +790,23 @@ static int rts5208_init(struct rtsx_chip *chip) RTSX_WRITE_REG(chip, CLK_SEL, 0x03, 0x03); RTSX_READ_REG(chip, CLK_SEL, &val); - if (val == 0) { + if (val == 0) chip->asic_code = 1; - } else { + else chip->asic_code = 0; - } if (chip->asic_code) { retval = rtsx_read_phy_register(chip, 0x1C, ®); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + RTSX_DEBUGP("Value of phy register 0x1C is 0x%x\n", reg); chip->ic_version = (reg >> 4) & 0x07; - if (reg & PHY_DEBUG_MODE) { + if (reg & PHY_DEBUG_MODE) chip->phy_debug_mode = 1; - } else { + else chip->phy_debug_mode = 0; - } + } else { RTSX_READ_REG(chip, 0xFE80, &val); chip->ic_version = val; @@ -839,33 +815,29 @@ static int rts5208_init(struct rtsx_chip *chip) RTSX_READ_REG(chip, PDINFO, &val); RTSX_DEBUGP("PDINFO: 0x%x\n", val); - if (val & AUX_PWR_DETECTED) { + if (val & AUX_PWR_DETECTED) chip->aux_pwr_exist = 1; - } else { + else chip->aux_pwr_exist = 0; - } RTSX_READ_REG(chip, 0xFE50, &val); - if (val & 0x01) { + if (val & 0x01) chip->hw_bypass_sd = 1; - } else { + else chip->hw_bypass_sd = 0; - } rtsx_read_config_byte(chip, 0x0E, &val); - if (val & 0x80) { + if (val & 0x80) SET_SDIO_EXIST(chip); - } else { + else CLR_SDIO_EXIST(chip); - } if (chip->use_hw_setting) { RTSX_READ_REG(chip, CHANGE_LINK_STATE, &val); - if (val & 0x80) { + if (val & 0x80) chip->auto_delink_en = 1; - } else { + else chip->auto_delink_en = 0; - } } return STATUS_SUCCESS; @@ -879,63 +851,57 @@ static int rts5288_init(struct rtsx_chip *chip) RTSX_WRITE_REG(chip, CLK_SEL, 0x03, 0x03); RTSX_READ_REG(chip, CLK_SEL, &val); - if (val == 0) { + if (val == 0) chip->asic_code = 1; - } else { + else chip->asic_code = 0; - } chip->ic_version = 0; chip->phy_debug_mode = 0; RTSX_READ_REG(chip, PDINFO, &val); RTSX_DEBUGP("PDINFO: 0x%x\n", val); - if (val & AUX_PWR_DETECTED) { + if (val & AUX_PWR_DETECTED) chip->aux_pwr_exist = 1; - } else { + else chip->aux_pwr_exist = 0; - } RTSX_READ_REG(chip, CARD_SHARE_MODE, &val); RTSX_DEBUGP("CARD_SHARE_MODE: 0x%x\n", val); - if (val & 0x04) { + if (val & 0x04) chip->baro_pkg = QFN; - } else { + else chip->baro_pkg = LQFP; - } RTSX_READ_REG(chip, 0xFE5A, &val); - if (val & 0x10) { + if (val & 0x10) chip->hw_bypass_sd = 1; - } else { + else chip->hw_bypass_sd = 0; - } retval = rtsx_read_cfg_dw(chip, 0, 0x718, &lval); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + max_func = (u8)((lval >> 29) & 0x07); RTSX_DEBUGP("Max function number: %d\n", max_func); - if (max_func == 0x02) { + if (max_func == 0x02) SET_SDIO_EXIST(chip); - } else { + else CLR_SDIO_EXIST(chip); - } if (chip->use_hw_setting) { RTSX_READ_REG(chip, CHANGE_LINK_STATE, &val); - if (val & 0x80) { + if (val & 0x80) chip->auto_delink_en = 1; - } else { + else chip->auto_delink_en = 0; - } - if (CHECK_BARO_PKG(chip, LQFP)) { + if (CHECK_BARO_PKG(chip, LQFP)) chip->lun_mode = SD_MS_1LUN; - } else { + else chip->lun_mode = DEFAULT_SINGLE; - } + } return STATUS_SUCCESS; @@ -990,22 +956,21 @@ int rtsx_init_chip(struct rtsx_chip *chip) chip->rw_fail_cnt[i] = 0; } - if (!check_sd_speed_prior(chip->sd_speed_prior)) { + if (!check_sd_speed_prior(chip->sd_speed_prior)) chip->sd_speed_prior = 0x01040203; - } + RTSX_DEBUGP("sd_speed_prior = 0x%08x\n", chip->sd_speed_prior); - if (!check_sd_current_prior(chip->sd_current_prior)) { + if (!check_sd_current_prior(chip->sd_current_prior)) chip->sd_current_prior = 0x00010203; - } + RTSX_DEBUGP("sd_current_prior = 0x%08x\n", chip->sd_current_prior); - if ((chip->sd_ddr_tx_phase > 31) || (chip->sd_ddr_tx_phase < 0)) { + if ((chip->sd_ddr_tx_phase > 31) || (chip->sd_ddr_tx_phase < 0)) chip->sd_ddr_tx_phase = 0; - } - if ((chip->mmc_ddr_tx_phase > 31) || (chip->mmc_ddr_tx_phase < 0)) { + + if ((chip->mmc_ddr_tx_phase > 31) || (chip->mmc_ddr_tx_phase < 0)) chip->mmc_ddr_tx_phase = 0; - } RTSX_WRITE_REG(chip, FPDCTL, SSC_POWER_DOWN, 0); wait_timeout(200); @@ -1014,24 +979,23 @@ int rtsx_init_chip(struct rtsx_chip *chip) if (CHECK_PID(chip, 0x5209)) { retval = rts5209_init(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + } else if (CHECK_PID(chip, 0x5208)) { retval = rts5208_init(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + } else if (CHECK_PID(chip, 0x5288)) { retval = rts5288_init(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + } - if (chip->ss_en == 2) { + if (chip->ss_en == 2) chip->ss_en = 0; - } RTSX_DEBUGP("chip->asic_code = %d\n", chip->asic_code); RTSX_DEBUGP("chip->ic_version = 0x%x\n", chip->ic_version); @@ -1068,9 +1032,8 @@ int rtsx_init_chip(struct rtsx_chip *chip) } retval = rtsx_reset_chip(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -1118,19 +1081,19 @@ static void rtsx_monitor_aspm_config(struct rtsx_chip *chip) chip->aspm_level[1] = reg1; } - if ((reg0 & 0x03) && (reg1 & 0x03)) { + if ((reg0 & 0x03) && (reg1 & 0x03)) maybe_support_aspm = 1; - } + } else { - if (reg0 & 0x03) { + if (reg0 & 0x03) maybe_support_aspm = 1; - } + } if (reg_changed) { - if (maybe_support_aspm) { + if (maybe_support_aspm) chip->aspm_l0s_l1_en = 0x03; - } + RTSX_DEBUGP("aspm_level[0] = 0x%02x, aspm_level[1] = 0x%02x\n", chip->aspm_level[0], chip->aspm_level[1]); @@ -1177,13 +1140,13 @@ void rtsx_polling_func(struct rtsx_chip *chip) if (chip->ocp_int & MS_OC_INT) ms_power_off_card3v3(chip); } else { - if (chip->card_exist & SD_CARD) { + if (chip->card_exist & SD_CARD) sd_power_off_card3v3(chip); - } else if (chip->card_exist & MS_CARD) { + else if (chip->card_exist & MS_CARD) ms_power_off_card3v3(chip); - } else if (chip->card_exist & XD_CARD) { + else if (chip->card_exist & XD_CARD) xd_power_off_card3v3(chip); - } + } chip->ocp_int = 0; @@ -1226,9 +1189,9 @@ void rtsx_polling_func(struct rtsx_chip *chip) if (CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip)) { u32 val; rtsx_read_cfg_dw(chip, 1, 0x04, &val); - if (val & 0x07) { + if (val & 0x07) ss_allowed = 0; - } + } } } else { @@ -1284,9 +1247,9 @@ void rtsx_polling_func(struct rtsx_chip *chip) turn_off_led(chip, LED_GPIO); - if (chip->auto_power_down && !chip->card_ready && !chip->sd_io) { + if (chip->auto_power_down && !chip->card_ready && !chip->sd_io) rtsx_force_power_down(chip, SSC_PDCTL | OC_PDCTL); - } + } } @@ -1299,9 +1262,9 @@ void rtsx_polling_func(struct rtsx_chip *chip) break; case RTSX_STAT_IDLE: - if (chip->sd_io && !chip->sd_int) { + if (chip->sd_io && !chip->sd_int) try_to_switch_sdio_ctrl(chip); - } + rtsx_enable_aspm(chip); break; @@ -1313,9 +1276,8 @@ void rtsx_polling_func(struct rtsx_chip *chip) #ifdef SUPPORT_OCP if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) { #ifdef CONFIG_RTS_PSTOR_DEBUG - if (chip->ocp_stat & (SD_OC_NOW | SD_OC_EVER | MS_OC_NOW | MS_OC_EVER)) { + if (chip->ocp_stat & (SD_OC_NOW | SD_OC_EVER | MS_OC_NOW | MS_OC_EVER)) RTSX_DEBUGP("Over current, OCPSTAT is 0x%x\n", chip->ocp_stat); - } #endif if (chip->ocp_stat & (SD_OC_NOW | SD_OC_EVER)) { @@ -1362,28 +1324,27 @@ Delink_Stage: if (chip->auto_delink_cnt == delink_stage1_cnt) { rtsx_set_stat(chip, RTSX_STAT_DELINK); - if (chip->asic_code && CHECK_PID(chip, 0x5208)) { + if (chip->asic_code && CHECK_PID(chip, 0x5208)) rtsx_set_phy_reg_bit(chip, 0x1C, 2); - } + if (chip->card_exist) { RTSX_DEBUGP("False card inserted, do force delink\n"); - if (enter_L1) { + if (enter_L1) rtsx_write_register(chip, HOST_SLEEP_STATE, 0x03, 1); - } + rtsx_write_register(chip, CHANGE_LINK_STATE, 0x0A, 0x0A); - if (enter_L1) { + if (enter_L1) rtsx_enter_L1(chip); - } chip->auto_delink_cnt = delink_stage3_cnt + 1; } else { RTSX_DEBUGP("No card inserted, do delink\n"); - if (enter_L1) { + if (enter_L1) rtsx_write_register(chip, HOST_SLEEP_STATE, 0x03, 1); - } + #ifdef HW_INT_WRITE_CLR if (CHECK_PID(chip, 0x5209)) { rtsx_writel(chip, RTSX_BIPR, 0xFFFFFFFF); @@ -1392,22 +1353,21 @@ Delink_Stage: #endif rtsx_write_register(chip, CHANGE_LINK_STATE, 0x02, 0x02); - if (enter_L1) { + if (enter_L1) rtsx_enter_L1(chip); - } + } } if (chip->auto_delink_cnt == delink_stage2_cnt) { RTSX_DEBUGP("Try to do force delink\n"); - if (enter_L1) { + if (enter_L1) rtsx_exit_L1(chip); - } - if (chip->asic_code && CHECK_PID(chip, 0x5208)) { + if (chip->asic_code && CHECK_PID(chip, 0x5208)) rtsx_set_phy_reg_bit(chip, 0x1C, 2); - } + rtsx_write_register(chip, CHANGE_LINK_STATE, 0x0A, 0x0A); } @@ -1472,9 +1432,9 @@ int rtsx_write_register(struct rtsx_chip *chip, u16 addr, u8 mask, u8 data) for (i = 0; i < MAX_RW_REG_CNT; i++) { val = rtsx_readl(chip, RTSX_HAIMR); if ((val & (1 << 31)) == 0) { - if (data != (u8)val) { + if (data != (u8)val) TRACE_RET(chip, STATUS_FAIL); - } + return STATUS_SUCCESS; } } @@ -1487,9 +1447,8 @@ int rtsx_read_register(struct rtsx_chip *chip, u16 addr, u8 *data) u32 val = 2 << 30; int i; - if (data) { + if (data) *data = 0; - } val |= (u32)(addr & 0x3FFF) << 16; @@ -1497,18 +1456,15 @@ int rtsx_read_register(struct rtsx_chip *chip, u16 addr, u8 *data) for (i = 0; i < MAX_RW_REG_CNT; i++) { val = rtsx_readl(chip, RTSX_HAIMR); - if ((val & (1 << 31)) == 0) { + if ((val & (1 << 31)) == 0) break; - } } - if (i >= MAX_RW_REG_CNT) { + if (i >= MAX_RW_REG_CNT) TRACE_RET(chip, STATUS_TIMEDOUT); - } - if (data) { + if (data) *data = (u8)(val & 0xFF); - } return STATUS_SUCCESS; } @@ -1537,9 +1493,8 @@ int rtsx_write_cfg_dw(struct rtsx_chip *chip, u8 func_no, u16 addr, u32 mask, u3 for (i = 0; i < MAX_RW_REG_CNT; i++) { RTSX_READ_REG(chip, CFGRWCTL, &tmp); - if ((tmp & 0x80) == 0) { + if ((tmp & 0x80) == 0) break; - } } } @@ -1558,9 +1513,8 @@ int rtsx_read_cfg_dw(struct rtsx_chip *chip, u8 func_no, u16 addr, u32 *val) for (i = 0; i < MAX_RW_REG_CNT; i++) { RTSX_READ_REG(chip, CFGRWCTL, &tmp); - if ((tmp & 0x80) == 0) { + if ((tmp & 0x80) == 0) break; - } } for (i = 0; i < 4; i++) { @@ -1568,9 +1522,8 @@ int rtsx_read_cfg_dw(struct rtsx_chip *chip, u8 func_no, u16 addr, u32 *val) data |= (u32)tmp << (i * 8); } - if (val) { + if (val) *val = data; - } return STATUS_SUCCESS; } @@ -1585,21 +1538,19 @@ int rtsx_write_cfg_seq(struct rtsx_chip *chip, u8 func, u16 addr, u8 *buf, int l RTSX_DEBUGP("%s\n", __func__); - if (!buf) { + if (!buf) TRACE_RET(chip, STATUS_NOMEM); - } - if ((len + offset) % 4) { + if ((len + offset) % 4) dw_len = (len + offset) / 4 + 1; - } else { + else dw_len = (len + offset) / 4; - } + RTSX_DEBUGP("dw_len = %d\n", dw_len); data = vzalloc(dw_len * 4); - if (!data) { + if (!data) TRACE_RET(chip, STATUS_NOMEM); - } mask = vzalloc(dw_len * 4); if (!mask) { @@ -1645,17 +1596,16 @@ int rtsx_read_cfg_seq(struct rtsx_chip *chip, u8 func, u16 addr, u8 *buf, int le RTSX_DEBUGP("%s\n", __func__); - if ((len + offset) % 4) { + if ((len + offset) % 4) dw_len = (len + offset) / 4 + 1; - } else { + else dw_len = (len + offset) / 4; - } + RTSX_DEBUGP("dw_len = %d\n", dw_len); data = (u32 *)vmalloc(dw_len * 4); - if (!data) { + if (!data) TRACE_RET(chip, STATUS_NOMEM); - } for (i = 0; i < dw_len; i++) { retval = rtsx_read_cfg_dw(chip, func, aligned_addr + i * 4, data + i); @@ -1700,9 +1650,8 @@ int rtsx_write_phy_register(struct rtsx_chip *chip, u8 addr, u16 val) } } - if (!finished) { + if (!finished) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -1724,9 +1673,8 @@ int rtsx_read_phy_register(struct rtsx_chip *chip, u8 addr, u16 *val) } } - if (!finished) { + if (!finished) TRACE_RET(chip, STATUS_FAIL); - } RTSX_READ_REG(chip, PHYDATA0, &tmp); data = tmp; @@ -1753,9 +1701,8 @@ int rtsx_read_efuse(struct rtsx_chip *chip, u8 addr, u8 *val) udelay(1); } - if (data & 0x80) { + if (data & 0x80) TRACE_RET(chip, STATUS_TIMEDOUT); - } RTSX_READ_REG(chip, EFUSE_DATA, &data); if (val) @@ -1786,9 +1733,8 @@ int rtsx_write_efuse(struct rtsx_chip *chip, u8 addr, u8 val) wait_timeout(3); } - if (data & 0x80) { + if (data & 0x80) TRACE_RET(chip, STATUS_TIMEDOUT); - } wait_timeout(5); } @@ -1802,15 +1748,14 @@ int rtsx_clr_phy_reg_bit(struct rtsx_chip *chip, u8 reg, u8 bit) u16 value; retval = rtsx_read_phy_register(chip, reg, &value); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + if (value & (1 << bit)) { value &= ~(1 << bit); retval = rtsx_write_phy_register(chip, reg, value); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } return STATUS_SUCCESS; @@ -1822,15 +1767,14 @@ int rtsx_set_phy_reg_bit(struct rtsx_chip *chip, u8 reg, u8 bit) u16 value; retval = rtsx_read_phy_register(chip, reg, &value); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + if (0 == (value & (1 << bit))) { value |= (1 << bit); retval = rtsx_write_phy_register(chip, reg, value); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } return STATUS_SUCCESS; @@ -1861,11 +1805,11 @@ static void rtsx_handle_pm_dstate(struct rtsx_chip *chip, u8 dstate) if (CHK_SDIO_EXIST(chip)) { u8 func_no; - if (CHECK_PID(chip, 0x5288)) { + if (CHECK_PID(chip, 0x5288)) func_no = 2; - } else { + else func_no = 1; - } + rtsx_read_cfg_dw(chip, func_no, 0x84, &ultmp); RTSX_DEBUGP("pm_dstate of function %d: 0x%x\n", (int)func_no, ultmp); rtsx_write_cfg_dw(chip, func_no, 0x84, 0xFF, dstate); @@ -1898,11 +1842,10 @@ void rtsx_enter_ss(struct rtsx_chip *chip) } if (CHK_SDIO_EXIST(chip)) { - if (CHECK_PID(chip, 0x5288)) { + if (CHECK_PID(chip, 0x5288)) rtsx_write_cfg_dw(chip, 2, 0xC0, 0xFF00, 0x0100); - } else { + else rtsx_write_cfg_dw(chip, 1, 0xC0, 0xFF00, 0x0100); - } } if (chip->auto_delink_en) { @@ -1953,11 +1896,11 @@ int rtsx_pre_handle_interrupt(struct rtsx_chip *chip) u32 ocp_int = 0; if (CHECK_PID(chip, 0x5209)) { - if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) { + if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) ocp_int = MS_OC_INT | SD_OC_INT; - } else { + else ocp_int = SD_OC_INT; - } + } else { ocp_int = OC_INT; } @@ -1976,9 +1919,8 @@ int rtsx_pre_handle_interrupt(struct rtsx_chip *chip) chip->int_reg = rtsx_readl(chip, RTSX_BIPR); #ifdef HW_INT_WRITE_CLR - if (CHECK_PID(chip, 0x5209)) { + if (CHECK_PID(chip, 0x5209)) rtsx_writel(chip, RTSX_BIPR, chip->int_reg); - } #endif if (((chip->int_reg & int_enable) == 0) || (chip->int_reg == 0xFFFFFFFF)) @@ -1988,9 +1930,8 @@ int rtsx_pre_handle_interrupt(struct rtsx_chip *chip) if (CHECK_PID(chip, 0x5209)) { u8 val; rtsx_read_config_byte(chip, 0x05, &val); - if (val & 0x04) { + if (val & 0x04) return STATUS_FAIL; - } } } @@ -2107,16 +2048,15 @@ void rtsx_do_before_power_down(struct rtsx_chip *chip, int pm_stat) RTSX_DEBUGP("Host enter S1\n"); rtsx_write_register(chip, HOST_SLEEP_STATE, 0x03, HOST_ENTER_S1); } else if (pm_stat == PM_S3) { - if (chip->s3_pwr_off_delay > 0) { + if (chip->s3_pwr_off_delay > 0) wait_timeout(chip->s3_pwr_off_delay); - } + RTSX_DEBUGP("Host enter S3\n"); rtsx_write_register(chip, HOST_SLEEP_STATE, 0x03, HOST_ENTER_S3); } - if (chip->do_delink_before_power_down && chip->auto_delink_en) { + if (chip->do_delink_before_power_down && chip->auto_delink_en) rtsx_write_register(chip, CHANGE_LINK_STATE, 0x02, 2); - } rtsx_force_power_down(chip, SSC_PDCTL | OC_PDCTL); @@ -2143,11 +2083,10 @@ void rtsx_enable_aspm(struct rtsx_chip *chip) if (CHK_SDIO_EXIST(chip)) { u16 val = chip->aspm_l0s_l1_en | 0x0100; - if (CHECK_PID(chip, 0x5288)) { + if (CHECK_PID(chip, 0x5288)) rtsx_write_cfg_dw(chip, 2, 0xC0, 0xFFFF, val); - } else { + else rtsx_write_cfg_dw(chip, 1, 0xC0, 0xFFFF, val); - } } } } @@ -2167,11 +2106,11 @@ void rtsx_disable_aspm(struct rtsx_chip *chip) if (chip->asic_code && CHECK_PID(chip, 0x5208)) rtsx_write_phy_register(chip, 0x07, 0x0129); - if (CHECK_PID(chip, 0x5208)) { + if (CHECK_PID(chip, 0x5208)) rtsx_write_register(chip, ASPM_FORCE_CTL, 0xF3, 0x30); - } else { + else rtsx_write_config_byte(chip, LCTLR, 0x00); - } + wait_timeout(1); } } @@ -2186,9 +2125,8 @@ int rtsx_read_ppbuf(struct rtsx_chip *chip, u8 *buf, int buf_len) u16 reg_addr; u8 *ptr; - if (!buf) { + if (!buf) TRACE_RET(chip, STATUS_ERROR); - } ptr = buf; reg_addr = PPBUF_BASE2; @@ -2199,9 +2137,8 @@ int rtsx_read_ppbuf(struct rtsx_chip *chip, u8 *buf, int buf_len) rtsx_add_cmd(chip, READ_REG_CMD, reg_addr++, 0, 0); retval = rtsx_send_cmd(chip, 0, 250); - if (retval < 0) { + if (retval < 0) TRACE_RET(chip, STATUS_FAIL); - } memcpy(ptr, rtsx_get_cmd_data(chip), 256); ptr += 256; @@ -2214,9 +2151,8 @@ int rtsx_read_ppbuf(struct rtsx_chip *chip, u8 *buf, int buf_len) rtsx_add_cmd(chip, READ_REG_CMD, reg_addr++, 0, 0); retval = rtsx_send_cmd(chip, 0, 250); - if (retval < 0) { + if (retval < 0) TRACE_RET(chip, STATUS_FAIL); - } } memcpy(ptr, rtsx_get_cmd_data(chip), buf_len%256); @@ -2231,9 +2167,8 @@ int rtsx_write_ppbuf(struct rtsx_chip *chip, u8 *buf, int buf_len) u16 reg_addr; u8 *ptr; - if (!buf) { + if (!buf) TRACE_RET(chip, STATUS_ERROR); - } ptr = buf; reg_addr = PPBUF_BASE2; @@ -2246,9 +2181,8 @@ int rtsx_write_ppbuf(struct rtsx_chip *chip, u8 *buf, int buf_len) } retval = rtsx_send_cmd(chip, 0, 250); - if (retval < 0) { + if (retval < 0) TRACE_RET(chip, STATUS_FAIL); - } } if (buf_len%256) { @@ -2260,9 +2194,8 @@ int rtsx_write_ppbuf(struct rtsx_chip *chip, u8 *buf, int buf_len) } retval = rtsx_send_cmd(chip, 0, 250); - if (retval < 0) { + if (retval < 0) TRACE_RET(chip, STATUS_FAIL); - } } return STATUS_SUCCESS; @@ -2270,9 +2203,8 @@ int rtsx_write_ppbuf(struct rtsx_chip *chip, u8 *buf, int buf_len) int rtsx_check_chip_exist(struct rtsx_chip *chip) { - if (rtsx_readl(chip, 0) == 0xFFFFFFFF) { + if (rtsx_readl(chip, 0) == 0xFFFFFFFF) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -2288,17 +2220,15 @@ int rtsx_force_power_on(struct rtsx_chip *chip, u8 ctl) #ifdef SUPPORT_OCP if (ctl & OC_PDCTL) { mask |= SD_OC_POWER_DOWN; - if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) { + if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) mask |= MS_OC_POWER_DOWN; - } } #endif if (mask) { retval = rtsx_write_register(chip, FPDCTL, mask, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (CHECK_PID(chip, 0x5288)) wait_timeout(200); @@ -2326,9 +2256,8 @@ int rtsx_force_power_down(struct rtsx_chip *chip, u8 ctl) if (mask) { val = mask; retval = rtsx_write_register(chip, FPDCTL, mask, val); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } return STATUS_SUCCESS; diff --git a/drivers/staging/rts_pstor/rtsx_scsi.c b/drivers/staging/rts_pstor/rtsx_scsi.c index f2e5842d4c90..86c41b3a42a3 100644 --- a/drivers/staging/rts_pstor/rtsx_scsi.c +++ b/drivers/staging/rts_pstor/rtsx_scsi.c @@ -135,9 +135,9 @@ void scsi_show_command(struct scsi_cmnd *srb) default: what = "(unknown command)"; unknown_cmd = 1; break; } - if (srb->cmnd[0] != TEST_UNIT_READY) { + if (srb->cmnd[0] != TEST_UNIT_READY) RTSX_DEBUGP("Command %s (%d bytes)\n", what, srb->cmd_len); - } + if (unknown_cmd) { RTSX_DEBUGP(""); for (i = 0; i < srb->cmd_len && i < 16; i++) @@ -317,11 +317,11 @@ static int inquiry(struct scsi_cmnd *srb, struct rtsx_chip *chip) }; if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) { - if (chip->lun2card[lun] == SD_CARD) { + if (chip->lun2card[lun] == SD_CARD) inquiry_string = inquiry_sd; - } else { + else inquiry_string = inquiry_ms; - } + } else if (CHECK_LUN_MODE(chip, SD_MS_1LUN)) { inquiry_string = inquiry_sdms; } else { @@ -329,9 +329,8 @@ static int inquiry(struct scsi_cmnd *srb, struct rtsx_chip *chip) } buf = vmalloc(scsi_bufflen(srb)); - if (buf == NULL) { + if (buf == NULL) TRACE_RET(chip, TRANSPORT_ERROR); - } #ifdef SUPPORT_MAGIC_GATE if ((chip->mspro_formatter_enable) && @@ -340,23 +339,21 @@ static int inquiry(struct scsi_cmnd *srb, struct rtsx_chip *chip) if (chip->mspro_formatter_enable) #endif { - if (!card || (card == MS_CARD)) { + if (!card || (card == MS_CARD)) pro_formatter_flag = 1; - } } if (pro_formatter_flag) { - if (scsi_bufflen(srb) < 56) { + if (scsi_bufflen(srb) < 56) sendbytes = (unsigned char)(scsi_bufflen(srb)); - } else { + else sendbytes = 56; - } + } else { - if (scsi_bufflen(srb) < 36) { + if (scsi_bufflen(srb) < 36) sendbytes = (unsigned char)(scsi_bufflen(srb)); - } else { + else sendbytes = 36; - } } if (sendbytes > 8) { @@ -371,9 +368,8 @@ static int inquiry(struct scsi_cmnd *srb, struct rtsx_chip *chip) } if (pro_formatter_flag) { - if (sendbytes > 36) { + if (sendbytes > 36) memcpy(buf + 36, formatter_inquiry_str, sendbytes - 36); - } } scsi_set_resid(srb, 0); @@ -467,9 +463,8 @@ static int request_sense(struct scsi_cmnd *srb, struct rtsx_chip *chip) } buf = vmalloc(scsi_bufflen(srb)); - if (buf == NULL) { + if (buf == NULL) TRACE_RET(chip, TRANSPORT_ERROR); - } tmp = (unsigned char *)sense; memcpy(buf, tmp, scsi_bufflen(srb)); @@ -494,15 +489,15 @@ static void ms_mode_sense(struct rtsx_chip *chip, u8 cmd, if (cmd == MODE_SENSE) { sys_info_offset = 8; - if (data_size > 0x68) { + if (data_size > 0x68) data_size = 0x68; - } + buf[i++] = 0x67; /* Mode Data Length */ } else { sys_info_offset = 12; - if (data_size > 0x6C) { + if (data_size > 0x6C) data_size = 0x6C; - } + buf[i++] = 0x00; /* Mode Data Length (MSB) */ buf[i++] = 0x6A; /* Mode Data Length (LSB) */ } @@ -520,11 +515,11 @@ static void ms_mode_sense(struct rtsx_chip *chip, u8 cmd, } /* WP */ - if (check_card_wp(chip, lun)) { + if (check_card_wp(chip, lun)) buf[i++] = 0x80; - } else { + else buf[i++] = 0x00; - } + } else { buf[i++] = 0x00; /* MediaType */ buf[i++] = 0x00; /* WP */ @@ -545,11 +540,10 @@ static void ms_mode_sense(struct rtsx_chip *chip, u8 cmd, if (data_size >= 11) buf[i++] = 0x00; /* No Access Control */ if (data_size >= 12) { - if (support_format) { + if (support_format) buf[i++] = 0xC0; /* SF, SGM */ - } else { + else buf[i++] = 0x00; - } } } else { /* The Following Data is the content of "Page 0x20" */ @@ -560,11 +554,10 @@ static void ms_mode_sense(struct rtsx_chip *chip, u8 cmd, if (data_size >= 7) buf[i++] = 0x00; /* No Access Control */ if (data_size >= 8) { - if (support_format) { + if (support_format) buf[i++] = 0xC0; /* SF, SGM */ - } else { + else buf[i++] = 0x00; - } } } @@ -600,9 +593,8 @@ static int mode_sense(struct scsi_cmnd *srb, struct rtsx_chip *chip) if ((chip->lun2card[lun] & MS_CARD)) { if (!card || (card == MS_CARD)) { dataSize = 108; - if (chip->mspro_formatter_enable) { + if (chip->mspro_formatter_enable) pro_formatter_flag = 1; - } } } #else @@ -615,9 +607,8 @@ static int mode_sense(struct scsi_cmnd *srb, struct rtsx_chip *chip) #endif buf = kmalloc(dataSize, GFP_KERNEL); - if (buf == NULL) { + if (buf == NULL) TRACE_RET(chip, TRANSPORT_ERROR); - } pageCode = srb->cmnd[2] & 0x3f; @@ -632,11 +623,11 @@ static int mode_sense(struct scsi_cmnd *srb, struct rtsx_chip *chip) dataSize = 4; buf[0] = 0x03; buf[1] = 0x00; - if (check_card_wp(chip, lun)) { + if (check_card_wp(chip, lun)) buf[2] = 0x80; - } else { + else buf[2] = 0x00; - } + buf[3] = 0x00; } } else { @@ -648,11 +639,10 @@ static int mode_sense(struct scsi_cmnd *srb, struct rtsx_chip *chip) buf[0] = 0x00; buf[1] = 0x06; buf[2] = 0x00; - if (check_card_wp(chip, lun)) { + if (check_card_wp(chip, lun)) buf[3] = 0x80; - } else { + else buf[3] = 0x00; - } buf[4] = 0x00; buf[5] = 0x00; buf[6] = 0x00; @@ -759,11 +749,11 @@ static int read_write(struct scsi_cmnd *srb, struct rtsx_chip *chip) if (chip->rw_fail_cnt[lun] == 3) { RTSX_DEBUGP("read/write fail three times in succession\n"); - if (srb->sc_data_direction == DMA_FROM_DEVICE) { + if (srb->sc_data_direction == DMA_FROM_DEVICE) set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - } else { + else set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR); - } + TRACE_RET(chip, TRANSPORT_FAILED); } @@ -776,9 +766,8 @@ static int read_write(struct scsi_cmnd *srb, struct rtsx_chip *chip) if (CHECK_PID(chip, 0x5209) && chip->max_payload) { u8 val = 0x10 | (chip->max_payload << 5); retval = rtsx_write_cfg_dw(chip, 0, 0x78, 0xFF, val); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_ERROR); - } } } @@ -789,11 +778,10 @@ static int read_write(struct scsi_cmnd *srb, struct rtsx_chip *chip) set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); } else { chip->rw_fail_cnt[lun]++; - if (srb->sc_data_direction == DMA_FROM_DEVICE) { + if (srb->sc_data_direction == DMA_FROM_DEVICE) set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - } else { + else set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR); - } } retval = TRANSPORT_FAILED; TRACE_GOTO(chip, Exit); @@ -808,9 +796,8 @@ Exit: if (srb->sc_data_direction == DMA_TO_DEVICE) { if (CHECK_PID(chip, 0x5209) && chip->max_payload) { retval = rtsx_write_cfg_dw(chip, 0, 0x78, 0xFF, 0x10); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_ERROR); - } } } @@ -837,9 +824,8 @@ static int read_format_capacity(struct scsi_cmnd *srb, struct rtsx_chip *chip) buf_len = (scsi_bufflen(srb) > 12) ? 0x14 : 12; buf = kmalloc(buf_len, GFP_KERNEL); - if (buf == NULL) { + if (buf == NULL) TRACE_RET(chip, TRANSPORT_ERROR); - } buf[i++] = 0; buf[i++] = 0; @@ -864,22 +850,20 @@ static int read_format_capacity(struct scsi_cmnd *srb, struct rtsx_chip *chip) buf[i++] = (unsigned char)(card_size >> 8); buf[i++] = (unsigned char)card_size; - if (desc_cnt == 2) { + if (desc_cnt == 2) buf[i++] = 2; - } else { + else buf[i++] = 0; - } } else { buf[i++] = 0xFF; buf[i++] = 0xFF; buf[i++] = 0xFF; buf[i++] = 0xFF; - if (desc_cnt == 2) { + if (desc_cnt == 2) buf[i++] = 3; - } else { + else buf[i++] = 0; - } } buf[i++] = 0x00; @@ -916,9 +900,8 @@ static int read_capacity(struct scsi_cmnd *srb, struct rtsx_chip *chip) } buf = kmalloc(8, GFP_KERNEL); - if (buf == NULL) { + if (buf == NULL) TRACE_RET(chip, TRANSPORT_ERROR); - } card_size = get_card_size(chip, lun); buf[0] = (unsigned char)((card_size - 1) >> 24); @@ -956,9 +939,8 @@ static int read_eeprom(struct scsi_cmnd *srb, struct rtsx_chip *chip) len = ((u16)srb->cmnd[4] << 8) | srb->cmnd[5]; buf = (u8 *)vmalloc(len); - if (!buf) { + if (!buf) TRACE_RET(chip, TRANSPORT_ERROR); - } retval = rtsx_force_power_on(chip, SSC_PDCTL); if (retval != STATUS_SUCCESS) { @@ -1016,9 +998,8 @@ static int write_eeprom(struct scsi_cmnd *srb, struct rtsx_chip *chip) } else { len = (unsigned short)min(scsi_bufflen(srb), (unsigned int)len); buf = (u8 *)vmalloc(len); - if (buf == NULL) { + if (buf == NULL) TRACE_RET(chip, TRANSPORT_ERROR); - } rtsx_stor_get_xfer_buf(buf, len, srb); scsi_set_resid(srb, scsi_bufflen(srb) - len); @@ -1061,9 +1042,8 @@ static int read_mem(struct scsi_cmnd *srb, struct rtsx_chip *chip) } buf = (u8 *)vmalloc(len); - if (!buf) { + if (!buf) TRACE_RET(chip, TRANSPORT_ERROR); - } retval = rtsx_force_power_on(chip, SSC_PDCTL); if (retval != STATUS_SUCCESS) { @@ -1114,9 +1094,8 @@ static int write_mem(struct scsi_cmnd *srb, struct rtsx_chip *chip) len = (unsigned short)min(scsi_bufflen(srb), (unsigned int)len); buf = (u8 *)vmalloc(len); - if (buf == NULL) { + if (buf == NULL) TRACE_RET(chip, TRANSPORT_ERROR); - } rtsx_stor_get_xfer_buf(buf, len, srb); scsi_set_resid(srb, scsi_bufflen(srb) - len); @@ -1200,16 +1179,15 @@ static int trace_msg_cmd(struct scsi_cmnd *srb, struct rtsx_chip *chip) clear = srb->cmnd[2]; buf = (unsigned char *)vmalloc(scsi_bufflen(srb)); - if (buf == NULL) { + if (buf == NULL) TRACE_RET(chip, TRANSPORT_ERROR); - } ptr = buf; - if (chip->trace_msg[chip->msg_idx].valid) { + if (chip->trace_msg[chip->msg_idx].valid) msg_cnt = TRACE_ITEM_CNT; - } else { + else msg_cnt = chip->msg_idx; - } + *(ptr++) = (u8)(msg_cnt >> 24); *(ptr++) = (u8)(msg_cnt >> 16); *(ptr++) = (u8)(msg_cnt >> 8); @@ -1225,15 +1203,14 @@ static int trace_msg_cmd(struct scsi_cmnd *srb, struct rtsx_chip *chip) *(ptr++) = (u8)(chip->trace_msg[idx].line >> 8); *(ptr++) = (u8)(chip->trace_msg[idx].line); - for (j = 0; j < MSG_FUNC_LEN; j++) { + for (j = 0; j < MSG_FUNC_LEN; j++) *(ptr++) = chip->trace_msg[idx].func[j]; - } - for (j = 0; j < MSG_FILE_LEN; j++) { + + for (j = 0; j < MSG_FILE_LEN; j++) *(ptr++) = chip->trace_msg[idx].file[j]; - } - for (j = 0; j < TIME_VAL_LEN; j++) { + + for (j = 0; j < TIME_VAL_LEN; j++) *(ptr++) = chip->trace_msg[idx].timeval_buf[j]; - } } rtsx_stor_set_xfer_buf(buf, scsi_bufflen(srb), srb); @@ -1424,20 +1401,19 @@ static int dma_access_ring_buffer(struct scsi_cmnd *srb, struct rtsx_chip *chip) len = ((u16)(srb->cmnd[4]) << 8) | srb->cmnd[5]; len = min(len, (u16)scsi_bufflen(srb)); - if (srb->sc_data_direction == DMA_FROM_DEVICE) { + if (srb->sc_data_direction == DMA_FROM_DEVICE) RTSX_DEBUGP("Read from device\n"); - } else { + else RTSX_DEBUGP("Write to device\n"); - } retval = rtsx_transfer_data(chip, 0, scsi_sglist(srb), len, scsi_sg_count(srb), srb->sc_data_direction, 1000); if (retval < 0) { - if (srb->sc_data_direction == DMA_FROM_DEVICE) { + if (srb->sc_data_direction == DMA_FROM_DEVICE) set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - } else { + else set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR); - } + TRACE_RET(chip, TRANSPORT_FAILED); } scsi_set_resid(srb, 0); @@ -1462,22 +1438,20 @@ static int get_dev_status(struct scsi_cmnd *srb, struct rtsx_chip *chip) status[0] = (u8)(chip->product_id); status[1] = chip->ic_version; - if (chip->auto_delink_en) { + if (chip->auto_delink_en) status[2] = 0x10; - } else { + else status[2] = 0x00; - } status[3] = 20; status[4] = 10; status[5] = 05; status[6] = 21; - if (chip->card_wp) { + if (chip->card_wp) status[7] = 0x20; - } else { + else status[7] = 0x00; - } #ifdef SUPPORT_OCP status[8] = 0; @@ -1489,67 +1463,60 @@ static int get_dev_status(struct scsi_cmnd *srb, struct rtsx_chip *chip) oc_ever_mask = SD_OC_EVER; } - if (chip->ocp_stat & oc_now_mask) { + if (chip->ocp_stat & oc_now_mask) status[8] |= 0x02; - } - if (chip->ocp_stat & oc_ever_mask) { + + if (chip->ocp_stat & oc_ever_mask) status[8] |= 0x01; - } #endif if (card == SD_CARD) { if (CHK_SD(sd_card)) { if (CHK_SD_HCXC(sd_card)) { - if (sd_card->capacity > 0x4000000) { + if (sd_card->capacity > 0x4000000) status[0x0E] = 0x02; - } else { + else status[0x0E] = 0x01; - } } else { status[0x0E] = 0x00; } - if (CHK_SD_SDR104(sd_card)) { + if (CHK_SD_SDR104(sd_card)) status[0x0F] = 0x03; - } else if (CHK_SD_DDR50(sd_card)) { + else if (CHK_SD_DDR50(sd_card)) status[0x0F] = 0x04; - } else if (CHK_SD_SDR50(sd_card)) { + else if (CHK_SD_SDR50(sd_card)) status[0x0F] = 0x02; - } else if (CHK_SD_HS(sd_card)) { + else if (CHK_SD_HS(sd_card)) status[0x0F] = 0x01; - } else { + else status[0x0F] = 0x00; - } } else { - if (CHK_MMC_SECTOR_MODE(sd_card)) { + if (CHK_MMC_SECTOR_MODE(sd_card)) status[0x0E] = 0x01; - } else { + else status[0x0E] = 0x00; - } - if (CHK_MMC_DDR52(sd_card)) { + if (CHK_MMC_DDR52(sd_card)) status[0x0F] = 0x03; - } else if (CHK_MMC_52M(sd_card)) { + else if (CHK_MMC_52M(sd_card)) status[0x0F] = 0x02; - } else if (CHK_MMC_26M(sd_card)) { + else if (CHK_MMC_26M(sd_card)) status[0x0F] = 0x01; - } else { + else status[0x0F] = 0x00; - } } } else if (card == MS_CARD) { if (CHK_MSPRO(ms_card)) { - if (CHK_MSXC(ms_card)) { + if (CHK_MSXC(ms_card)) status[0x0E] = 0x01; - } else { + else status[0x0E] = 0x00; - } - if (CHK_HG8BIT(ms_card)) { + if (CHK_HG8BIT(ms_card)) status[0x0F] = 0x01; - } else { + else status[0x0F] = 0x00; - } } } @@ -1600,37 +1567,35 @@ static int set_chip_mode(struct scsi_cmnd *srb, struct rtsx_chip *chip) if (phy_debug_mode) { chip->phy_debug_mode = 1; retval = rtsx_write_register(chip, CDRESUMECTL, 0x77, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } + rtsx_disable_bus_int(chip); retval = rtsx_read_phy_register(chip, 0x1C, ®); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } + reg |= 0x0001; retval = rtsx_write_phy_register(chip, 0x1C, reg); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } } else { chip->phy_debug_mode = 0; retval = rtsx_write_register(chip, CDRESUMECTL, 0x77, 0x77); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } + rtsx_enable_bus_int(chip); retval = rtsx_read_phy_register(chip, 0x1C, ®); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } + reg &= 0xFFFE; retval = rtsx_write_phy_register(chip, 0x1C, reg); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } } return TRANSPORT_GOOD; @@ -1737,9 +1702,8 @@ static int read_phy_register(struct scsi_cmnd *srb, struct rtsx_chip *chip) if (len) { buf = (u8 *)vmalloc(len); - if (!buf) { + if (!buf) TRACE_RET(chip, TRANSPORT_ERROR); - } retval = rtsx_force_power_on(chip, SSC_PDCTL); if (retval != STATUS_SUCCESS) { @@ -1795,9 +1759,8 @@ static int write_phy_register(struct scsi_cmnd *srb, struct rtsx_chip *chip) len = (unsigned short)min(scsi_bufflen(srb), (unsigned int)len); buf = (u8 *)vmalloc(len); - if (buf == NULL) { + if (buf == NULL) TRACE_RET(chip, TRANSPORT_ERROR); - } rtsx_stor_get_xfer_buf(buf, len, srb); scsi_set_resid(srb, scsi_bufflen(srb) - len); @@ -1886,9 +1849,8 @@ static int read_eeprom2(struct scsi_cmnd *srb, struct rtsx_chip *chip) len = ((u16)srb->cmnd[6] << 8) | srb->cmnd[7]; buf = (u8 *)vmalloc(len); - if (!buf) { + if (!buf) TRACE_RET(chip, TRANSPORT_ERROR); - } retval = rtsx_force_power_on(chip, SSC_PDCTL); if (retval != STATUS_SUCCESS) { @@ -1934,9 +1896,8 @@ static int write_eeprom2(struct scsi_cmnd *srb, struct rtsx_chip *chip) len = (unsigned short)min(scsi_bufflen(srb), (unsigned int)len); buf = (u8 *)vmalloc(len); - if (buf == NULL) { + if (buf == NULL) TRACE_RET(chip, TRANSPORT_ERROR); - } rtsx_stor_get_xfer_buf(buf, len, srb); scsi_set_resid(srb, scsi_bufflen(srb) - len); @@ -1980,9 +1941,8 @@ static int read_efuse(struct scsi_cmnd *srb, struct rtsx_chip *chip) len = srb->cmnd[5]; buf = (u8 *)vmalloc(len); - if (!buf) { + if (!buf) TRACE_RET(chip, TRANSPORT_ERROR); - } retval = rtsx_force_power_on(chip, SSC_PDCTL); if (retval != STATUS_SUCCESS) { @@ -2029,9 +1989,8 @@ static int write_efuse(struct scsi_cmnd *srb, struct rtsx_chip *chip) len = (u8)min(scsi_bufflen(srb), (unsigned int)len); buf = (u8 *)vmalloc(len); - if (buf == NULL) { + if (buf == NULL) TRACE_RET(chip, TRANSPORT_ERROR); - } rtsx_stor_get_xfer_buf(buf, len, srb); scsi_set_resid(srb, scsi_bufflen(srb) - len); @@ -2093,27 +2052,23 @@ Exit: vfree(buf); retval = card_power_off(chip, SPI_CARD); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_ERROR); - } if (chip->asic_code) { retval = rtsx_write_register(chip, PWR_GATE_CTRL, LDO3318_PWR_MASK, LDO_OFF); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_ERROR); - } wait_timeout(600); retval = rtsx_write_phy_register(chip, 0x08, val); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_ERROR); - } retval = rtsx_write_register(chip, PWR_GATE_CTRL, LDO3318_PWR_MASK, LDO_ON); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_ERROR); - } } return result; @@ -2140,11 +2095,10 @@ static int read_cfg_byte(struct scsi_cmnd *srb, struct rtsx_chip *chip) RTSX_DEBUGP("%s: func = %d, addr = 0x%x, len = %d\n", __func__, func, addr, len); - if (CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip)) { + if (CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip)) func_max = 1; - } else { + else func_max = 0; - } if (func > func_max) { set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); @@ -2152,9 +2106,8 @@ static int read_cfg_byte(struct scsi_cmnd *srb, struct rtsx_chip *chip) } buf = (u8 *)vmalloc(len); - if (!buf) { + if (!buf) TRACE_RET(chip, TRANSPORT_ERROR); - } retval = rtsx_read_cfg_seq(chip, func, addr, buf, len); if (retval != STATUS_SUCCESS) { @@ -2193,11 +2146,10 @@ static int write_cfg_byte(struct scsi_cmnd *srb, struct rtsx_chip *chip) RTSX_DEBUGP("%s: func = %d, addr = 0x%x\n", __func__, func, addr); - if (CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip)) { + if (CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip)) func_max = 1; - } else { + else func_max = 0; - } if (func > func_max) { set_sense_type(chip, SCSI_LUN(srb), SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); @@ -2206,9 +2158,8 @@ static int write_cfg_byte(struct scsi_cmnd *srb, struct rtsx_chip *chip) len = (unsigned short)min(scsi_bufflen(srb), (unsigned int)len); buf = (u8 *)vmalloc(len); - if (!buf) { + if (!buf) TRACE_RET(chip, TRANSPORT_ERROR); - } rtsx_stor_get_xfer_buf(buf, len, srb); scsi_set_resid(srb, scsi_bufflen(srb) - len); @@ -2328,63 +2279,56 @@ static int read_status(struct scsi_cmnd *srb, struct rtsx_chip *chip) rtsx_status[4] = (u8)lun; if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) { - if (chip->lun2card[lun] == SD_CARD) { + if (chip->lun2card[lun] == SD_CARD) rtsx_status[5] = 2; - } else { + else rtsx_status[5] = 3; - } } else { if (chip->card_exist) { - if (chip->card_exist & XD_CARD) { + if (chip->card_exist & XD_CARD) rtsx_status[5] = 4; - } else if (chip->card_exist & SD_CARD) { + else if (chip->card_exist & SD_CARD) rtsx_status[5] = 2; - } else if (chip->card_exist & MS_CARD) { + else if (chip->card_exist & MS_CARD) rtsx_status[5] = 3; - } else { + else rtsx_status[5] = 7; - } } else { rtsx_status[5] = 7; } } - if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) { + if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) rtsx_status[6] = 2; - } else { + else rtsx_status[6] = 1; - } rtsx_status[7] = (u8)(chip->product_id); rtsx_status[8] = chip->ic_version; - if (check_card_exist(chip, lun)) { + if (check_card_exist(chip, lun)) rtsx_status[9] = 1; - } else { + else rtsx_status[9] = 0; - } - if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) { + if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) rtsx_status[10] = 0; - } else { + else rtsx_status[10] = 1; - } if (CHECK_LUN_MODE(chip, SD_MS_2LUN)) { - if (chip->lun2card[lun] == SD_CARD) { + if (chip->lun2card[lun] == SD_CARD) rtsx_status[11] = SD_CARD; - } else { + else rtsx_status[11] = MS_CARD; - } } else { rtsx_status[11] = XD_CARD | SD_CARD | MS_CARD; } - if (check_card_ready(chip, lun)) { + if (check_card_ready(chip, lun)) rtsx_status[12] = 1; - } else { + else rtsx_status[12] = 0; - } if (get_lun_card(chip, lun) == XD_CARD) { rtsx_status[13] = 0x40; @@ -2421,29 +2365,26 @@ static int read_status(struct scsi_cmnd *srb, struct rtsx_chip *chip) } else { if (CHECK_LUN_MODE(chip, DEFAULT_SINGLE)) { #ifdef SUPPORT_SDIO - if (chip->sd_io && chip->sd_int) { + if (chip->sd_io && chip->sd_int) rtsx_status[13] = 0x60; - } else { + else rtsx_status[13] = 0x70; - } #else rtsx_status[13] = 0x70; #endif } else { - if (chip->lun2card[lun] == SD_CARD) { + if (chip->lun2card[lun] == SD_CARD) rtsx_status[13] = 0x20; - } else { + else rtsx_status[13] = 0x30; - } } } rtsx_status[14] = 0x78; - if (CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip)) { + if (CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip)) rtsx_status[15] = 0x83; - } else { + else rtsx_status[15] = 0x82; - } buf_len = min(scsi_bufflen(srb), (unsigned int)sizeof(rtsx_status)); rtsx_stor_set_xfer_buf(rtsx_status, buf_len, srb); @@ -2482,7 +2423,7 @@ static int spi_vendor_cmd(struct scsi_cmnd *srb, struct rtsx_chip *chip) unsigned int lun = SCSI_LUN(srb); u8 gpio_dir; - if (CHECK_PID(chip, 0x5208) && CHECK_PID(chip, 0x5288)) { + if (CHECK_PID(chip, 0x5208) || CHECK_PID(chip, 0x5288)) { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); TRACE_RET(chip, TRANSPORT_FAILED); } @@ -2538,9 +2479,8 @@ static int spi_vendor_cmd(struct scsi_cmnd *srb, struct rtsx_chip *chip) rtsx_write_register(chip, CARD_GPIO_DIR, 0x07, gpio_dir); - if (result != STATUS_SUCCESS) { + if (result != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } return TRANSPORT_GOOD; } @@ -2610,13 +2550,12 @@ void led_shine(struct scsi_cmnd *srb, struct rtsx_chip *chip) unsigned int lun = SCSI_LUN(srb); u16 sec_cnt; - if ((srb->cmnd[0] == READ_10) || (srb->cmnd[0] == WRITE_10)) { + if ((srb->cmnd[0] == READ_10) || (srb->cmnd[0] == WRITE_10)) sec_cnt = ((u16)(srb->cmnd[7]) << 8) | srb->cmnd[8]; - } else if ((srb->cmnd[0] == READ_6) || (srb->cmnd[0] == WRITE_6)) { + else if ((srb->cmnd[0] == READ_6) || (srb->cmnd[0] == WRITE_6)) sec_cnt = srb->cmnd[4]; - } else { + else return; - } if (chip->rw_cap[lun] >= GPIO_TOGGLE_THRESHOLD) { toggle_gpio(chip, LED_GPIO); @@ -2659,11 +2598,10 @@ static int ms_format_cmnd(struct scsi_cmnd *srb, struct rtsx_chip *chip) } rtsx_set_stat(chip, RTSX_STAT_RUN); - if (srb->cmnd[8] & 0x01) { + if (srb->cmnd[8] & 0x01) quick_format = 0; - } else { + else quick_format = 1; - } if (!(chip->card_ready & MS_CARD)) { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); @@ -2724,27 +2662,25 @@ static int get_ms_information(struct scsi_cmnd *srb, struct rtsx_chip *chip) TRACE_RET(chip, TRANSPORT_FAILED); } - if (dev_info_id == 0x15) { + if (dev_info_id == 0x15) buf_len = data_len = 0x3A; - } else { + else buf_len = data_len = 0x6A; - } buf = kmalloc(buf_len, GFP_KERNEL); - if (!buf) { + if (!buf) TRACE_RET(chip, TRANSPORT_ERROR); - } i = 0; /* GET Memory Stick Media Information Response Header */ buf[i++] = 0x00; /* Data length MSB */ buf[i++] = data_len; /* Data length LSB */ /* Device Information Type Code */ - if (CHK_MSXC(ms_card)) { + if (CHK_MSXC(ms_card)) buf[i++] = 0x03; - } else { + else buf[i++] = 0x02; - } + /* SGM bit */ buf[i++] = 0x01; /* Reserved */ @@ -2759,11 +2695,11 @@ static int get_ms_information(struct scsi_cmnd *srb, struct rtsx_chip *chip) /* Device Information ID Number */ buf[i++] = dev_info_id; /* Device Information Length */ - if (dev_info_id == 0x15) { + if (dev_info_id == 0x15) data_len = 0x31; - } else { + else data_len = 0x61; - } + buf[i++] = 0x00; /* Data length MSB */ buf[i++] = data_len; /* Data length LSB */ /* Valid Bit */ @@ -2778,11 +2714,10 @@ static int get_ms_information(struct scsi_cmnd *srb, struct rtsx_chip *chip) rtsx_stor_set_xfer_buf(buf, buf_len, srb); - if (dev_info_id == 0x15) { + if (dev_info_id == 0x15) scsi_set_resid(srb, scsi_bufflen(srb)-0x3C); - } else { + else scsi_set_resid(srb, scsi_bufflen(srb)-0x6C); - } kfree(buf); return STATUS_SUCCESS; @@ -2793,13 +2728,11 @@ static int ms_sp_cmnd(struct scsi_cmnd *srb, struct rtsx_chip *chip) { int retval = TRANSPORT_ERROR; - if (srb->cmnd[2] == MS_FORMAT) { + if (srb->cmnd[2] == MS_FORMAT) retval = ms_format_cmnd(srb, chip); - } #ifdef SUPPORT_PCGL_1P18 - else if (srb->cmnd[2] == GET_MS_INFORMATION) { + else if (srb->cmnd[2] == GET_MS_INFORMATION) retval = get_ms_information(srb, chip); - } #endif return retval; @@ -2912,9 +2845,9 @@ static int mg_report_key(struct scsi_cmnd *srb, struct rtsx_chip *chip) (srb->cmnd[8] == 0x04) && (srb->cmnd[9] == 0x1C)) { retval = mg_get_local_EKB(srb, chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } + } else { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); TRACE_RET(chip, TRANSPORT_FAILED); @@ -2926,9 +2859,9 @@ static int mg_report_key(struct scsi_cmnd *srb, struct rtsx_chip *chip) (srb->cmnd[8] == 0x00) && (srb->cmnd[9] == 0x24)) { retval = mg_get_rsp_chg(srb, chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } + } else { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); TRACE_RET(chip, TRANSPORT_FAILED); @@ -2945,9 +2878,9 @@ static int mg_report_key(struct scsi_cmnd *srb, struct rtsx_chip *chip) (srb->cmnd[4] == 0x00) && (srb->cmnd[5] < 32)) { retval = mg_get_ICV(srb, chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } + } else { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); TRACE_RET(chip, TRANSPORT_FAILED); @@ -3014,9 +2947,9 @@ static int mg_send_key(struct scsi_cmnd *srb, struct rtsx_chip *chip) (srb->cmnd[8] == 0x00) && (srb->cmnd[9] == 0x0C)) { retval = mg_set_leaf_id(srb, chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } + } else { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); TRACE_RET(chip, TRANSPORT_FAILED); @@ -3028,9 +2961,9 @@ static int mg_send_key(struct scsi_cmnd *srb, struct rtsx_chip *chip) (srb->cmnd[8] == 0x00) && (srb->cmnd[9] == 0x0C)) { retval = mg_chg(srb, chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } + } else { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); TRACE_RET(chip, TRANSPORT_FAILED); @@ -3042,9 +2975,9 @@ static int mg_send_key(struct scsi_cmnd *srb, struct rtsx_chip *chip) (srb->cmnd[8] == 0x00) && (srb->cmnd[9] == 0x0C)) { retval = mg_rsp(srb, chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } + } else { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); TRACE_RET(chip, TRANSPORT_FAILED); @@ -3061,9 +2994,9 @@ static int mg_send_key(struct scsi_cmnd *srb, struct rtsx_chip *chip) (srb->cmnd[4] == 0x00) && (srb->cmnd[5] < 32)) { retval = mg_set_ICV(srb, chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } + } else { set_sense_type(chip, lun, SENSE_TYPE_MEDIA_INVALID_CMD_FIELD); TRACE_RET(chip, TRANSPORT_FAILED); diff --git a/drivers/staging/rts_pstor/rtsx_transport.c b/drivers/staging/rts_pstor/rtsx_transport.c index 54a474235f26..1f9a42480443 100644 --- a/drivers/staging/rts_pstor/rtsx_transport.c +++ b/drivers/staging/rts_pstor/rtsx_transport.c @@ -218,9 +218,9 @@ void rtsx_add_cmd(struct rtsx_chip *chip, val |= (u32)data; spin_lock_irq(&chip->rtsx->reg_lock); - if (chip->ci < (HOST_CMDS_BUF_LEN / 4)) { + if (chip->ci < (HOST_CMDS_BUF_LEN / 4)) cb[(chip->ci)++] = cpu_to_le32(val); - } + spin_unlock_irq(&chip->rtsx->reg_lock); } @@ -244,15 +244,14 @@ int rtsx_send_cmd(struct rtsx_chip *chip, u8 card, int timeout) long timeleft; int err = 0; - if (card == SD_CARD) { + if (card == SD_CARD) rtsx->check_card_cd = SD_EXIST; - } else if (card == MS_CARD) { + else if (card == MS_CARD) rtsx->check_card_cd = MS_EXIST; - } else if (card == XD_CARD) { + else if (card == XD_CARD) rtsx->check_card_cd = XD_EXIST; - } else { + else rtsx->check_card_cd = 0; - } spin_lock_irq(&rtsx->reg_lock); @@ -281,11 +280,11 @@ int rtsx_send_cmd(struct rtsx_chip *chip, u8 card, int timeout) } spin_lock_irq(&rtsx->reg_lock); - if (rtsx->trans_result == TRANS_RESULT_FAIL) { + if (rtsx->trans_result == TRANS_RESULT_FAIL) err = -EIO; - } else if (rtsx->trans_result == TRANS_RESULT_OK) { + else if (rtsx->trans_result == TRANS_RESULT_OK) err = 0; - } + spin_unlock_irq(&rtsx->reg_lock); finish_send_cmd: @@ -341,23 +340,21 @@ static int rtsx_transfer_sglist_adma_partial(struct rtsx_chip *chip, u8 card, if ((sg == NULL) || (num_sg <= 0) || !offset || !index) return -EIO; - if (dma_dir == DMA_TO_DEVICE) { + if (dma_dir == DMA_TO_DEVICE) dir = HOST_TO_DEVICE; - } else if (dma_dir == DMA_FROM_DEVICE) { + else if (dma_dir == DMA_FROM_DEVICE) dir = DEVICE_TO_HOST; - } else { + else return -ENXIO; - } - if (card == SD_CARD) { + if (card == SD_CARD) rtsx->check_card_cd = SD_EXIST; - } else if (card == MS_CARD) { + else if (card == MS_CARD) rtsx->check_card_cd = MS_EXIST; - } else if (card == XD_CARD) { + else if (card == XD_CARD) rtsx->check_card_cd = XD_EXIST; - } else { + else rtsx->check_card_cd = 0; - } spin_lock_irq(&rtsx->reg_lock); @@ -405,11 +402,10 @@ static int rtsx_transfer_sglist_adma_partial(struct rtsx_chip *chip, u8 card, *offset = 0; *index = *index + 1; } - if ((i == (sg_cnt - 1)) || !resid) { + if ((i == (sg_cnt - 1)) || !resid) option = SG_VALID | SG_END | SG_TRANS_DATA; - } else { + else option = SG_VALID | SG_TRANS_DATA; - } rtsx_add_sg_tbl(chip, (u32)addr, (u32)len, option); @@ -468,11 +464,11 @@ static int rtsx_transfer_sglist_adma_partial(struct rtsx_chip *chip, u8 card, } spin_lock_irq(&rtsx->reg_lock); - if (rtsx->trans_result == TRANS_RESULT_FAIL) { + if (rtsx->trans_result == TRANS_RESULT_FAIL) err = -EIO; - } else if (rtsx->trans_result == TRANS_RESULT_OK) { + else if (rtsx->trans_result == TRANS_RESULT_OK) err = 0; - } + spin_unlock_irq(&rtsx->reg_lock); out: @@ -501,23 +497,21 @@ static int rtsx_transfer_sglist_adma(struct rtsx_chip *chip, u8 card, if ((sg == NULL) || (num_sg <= 0)) return -EIO; - if (dma_dir == DMA_TO_DEVICE) { + if (dma_dir == DMA_TO_DEVICE) dir = HOST_TO_DEVICE; - } else if (dma_dir == DMA_FROM_DEVICE) { + else if (dma_dir == DMA_FROM_DEVICE) dir = DEVICE_TO_HOST; - } else { + else return -ENXIO; - } - if (card == SD_CARD) { + if (card == SD_CARD) rtsx->check_card_cd = SD_EXIST; - } else if (card == MS_CARD) { + else if (card == MS_CARD) rtsx->check_card_cd = MS_EXIST; - } else if (card == XD_CARD) { + else if (card == XD_CARD) rtsx->check_card_cd = XD_EXIST; - } else { + else rtsx->check_card_cd = 0; - } spin_lock_irq(&rtsx->reg_lock); @@ -537,11 +531,10 @@ static int rtsx_transfer_sglist_adma(struct rtsx_chip *chip, u8 card, u32 val = TRIG_DMA; int sg_cnt, j; - if (i == buf_cnt / (HOST_SG_TBL_BUF_LEN / 8)) { + if (i == buf_cnt / (HOST_SG_TBL_BUF_LEN / 8)) sg_cnt = buf_cnt % (HOST_SG_TBL_BUF_LEN / 8); - } else { + else sg_cnt = (HOST_SG_TBL_BUF_LEN / 8); - } chip->sgi = 0; for (j = 0; j < sg_cnt; j++) { @@ -552,11 +545,10 @@ static int rtsx_transfer_sglist_adma(struct rtsx_chip *chip, u8 card, RTSX_DEBUGP("DMA addr: 0x%x, Len: 0x%x\n", (unsigned int)addr, len); - if (j == (sg_cnt - 1)) { + if (j == (sg_cnt - 1)) option = SG_VALID | SG_END | SG_TRANS_DATA; - } else { + else option = SG_VALID | SG_TRANS_DATA; - } rtsx_add_sg_tbl(chip, (u32)addr, (u32)len, option); @@ -615,11 +607,11 @@ static int rtsx_transfer_sglist_adma(struct rtsx_chip *chip, u8 card, } spin_lock_irq(&rtsx->reg_lock); - if (rtsx->trans_result == TRANS_RESULT_FAIL) { + if (rtsx->trans_result == TRANS_RESULT_FAIL) err = -EIO; - } else if (rtsx->trans_result == TRANS_RESULT_OK) { + else if (rtsx->trans_result == TRANS_RESULT_OK) err = 0; - } + spin_unlock_irq(&rtsx->reg_lock); out: @@ -647,27 +639,25 @@ static int rtsx_transfer_buf(struct rtsx_chip *chip, u8 card, void *buf, size_t if ((buf == NULL) || (len <= 0)) return -EIO; - if (dma_dir == DMA_TO_DEVICE) { + if (dma_dir == DMA_TO_DEVICE) dir = HOST_TO_DEVICE; - } else if (dma_dir == DMA_FROM_DEVICE) { + else if (dma_dir == DMA_FROM_DEVICE) dir = DEVICE_TO_HOST; - } else { + else return -ENXIO; - } addr = dma_map_single(&(rtsx->pci->dev), buf, len, dma_dir); if (!addr) return -ENOMEM; - if (card == SD_CARD) { + if (card == SD_CARD) rtsx->check_card_cd = SD_EXIST; - } else if (card == MS_CARD) { + else if (card == MS_CARD) rtsx->check_card_cd = MS_EXIST; - } else if (card == XD_CARD) { + else if (card == XD_CARD) rtsx->check_card_cd = XD_EXIST; - } else { + else rtsx->check_card_cd = 0; - } val |= (u32)(dir & 0x01) << 29; val |= (u32)(len & 0x00FFFFFF); @@ -698,11 +688,11 @@ static int rtsx_transfer_buf(struct rtsx_chip *chip, u8 card, void *buf, size_t } spin_lock_irq(&rtsx->reg_lock); - if (rtsx->trans_result == TRANS_RESULT_FAIL) { + if (rtsx->trans_result == TRANS_RESULT_FAIL) err = -EIO; - } else if (rtsx->trans_result == TRANS_RESULT_OK) { + else if (rtsx->trans_result == TRANS_RESULT_OK) err = 0; - } + spin_unlock_irq(&rtsx->reg_lock); out: diff --git a/drivers/staging/rts_pstor/sd.c b/drivers/staging/rts_pstor/sd.c index 3cc9a489e4e8..c6a581c47cbc 100644 --- a/drivers/staging/rts_pstor/sd.c +++ b/drivers/staging/rts_pstor/sd.c @@ -192,9 +192,9 @@ RTY_SEND_CMD: stat_idx = 16; } else if (rsp_type != SD_RSP_TYPE_R0) { - for (reg_addr = REG_SD_CMD0; reg_addr <= REG_SD_CMD4; reg_addr++) { + for (reg_addr = REG_SD_CMD0; reg_addr <= REG_SD_CMD4; reg_addr++) rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0); - } + stat_idx = 5; } @@ -273,9 +273,8 @@ RTY_SEND_CMD: if ((rsp_type == SD_RSP_TYPE_R1) || (rsp_type == SD_RSP_TYPE_R1b)) { if ((cmd_idx != SEND_RELATIVE_ADDR) && (cmd_idx != SEND_IF_COND)) { if (cmd_idx != STOP_TRANSMISSION) { - if (ptr[1] & 0x80) { + if (ptr[1] & 0x80) TRACE_RET(chip, STATUS_FAIL); - } } #ifdef SUPPORT_SD_LOCK if (ptr[1] & 0x7D) @@ -294,11 +293,10 @@ RTY_SEND_CMD: RTSX_DEBUGP("ptr[3]: 0x%02x\n", ptr[3]); TRACE_RET(chip, STATUS_FAIL); } - if (ptr[3] & 0x01) { + if (ptr[3] & 0x01) sd_card->sd_data_buf_ready = 1; - } else { + else sd_card->sd_data_buf_ready = 0; - } } } @@ -322,17 +320,15 @@ static int sd_read_data(struct rtsx_chip *chip, if (!buf) buf_len = 0; - if (buf_len > 512) { + if (buf_len > 512) TRACE_RET(chip, STATUS_FAIL); - } rtsx_init_cmd(chip); if (cmd_len) { RTSX_DEBUGP("SD/MMC CMD %d\n", cmd[0] - 0x40); - for (i = 0; i < (cmd_len < 6 ? cmd_len : 6); i++) { + for (i = 0; i < (cmd_len < 6 ? cmd_len : 6); i++) rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD0 + i, 0xFF, cmd[i]); - } } rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt); rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_H, 0xFF, (u8)(byte_cnt >> 8)); @@ -344,9 +340,9 @@ static int sd_read_data(struct rtsx_chip *chip, rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG2, 0xFF, SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6); - if (trans_mode != SD_TM_AUTO_TUNING) { + if (trans_mode != SD_TM_AUTO_TUNING) rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER); - } + rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_TRANSFER, 0xFF, trans_mode | SD_TRANSFER_START); rtsx_add_cmd(chip, CHECK_REG_CMD, REG_SD_TRANSFER, SD_TRANSFER_END, SD_TRANSFER_END); @@ -362,9 +358,8 @@ static int sd_read_data(struct rtsx_chip *chip, if (buf && buf_len) { retval = rtsx_read_ppbuf(chip, buf, buf_len); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } return STATUS_SUCCESS; @@ -390,9 +385,8 @@ static int sd_write_data(struct rtsx_chip *chip, u8 trans_mode, if (buf && buf_len) { retval = rtsx_write_ppbuf(chip, buf, buf_len); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } rtsx_init_cmd(chip); @@ -450,15 +444,13 @@ static int sd_check_csd(struct rtsx_chip *chip, char check_wp) break; } - if (i == 6) { + if (i == 6) TRACE_RET(chip, STATUS_FAIL); - } memcpy(sd_card->raw_csd, rsp + 1, 15); - if (CHECK_PID(chip, 0x5209)) { + if (CHECK_PID(chip, 0x5209)) RTSX_READ_REG(chip, REG_SD_CMD5, sd_card->raw_csd + 15); - } RTSX_DEBUGP("CSD Response:\n"); RTSX_DUMP(sd_card->raw_csd, 16); @@ -469,35 +461,34 @@ static int sd_check_csd(struct rtsx_chip *chip, char check_wp) trans_speed = rsp[4]; if ((trans_speed & 0x07) == 0x02) { if ((trans_speed & 0xf8) >= 0x30) { - if (chip->asic_code) { + if (chip->asic_code) sd_card->sd_clock = 47; - } else { + else sd_card->sd_clock = CLK_50; - } + } else if ((trans_speed & 0xf8) == 0x28) { - if (chip->asic_code) { + if (chip->asic_code) sd_card->sd_clock = 39; - } else { + else sd_card->sd_clock = CLK_40; - } + } else if ((trans_speed & 0xf8) == 0x20) { - if (chip->asic_code) { + if (chip->asic_code) sd_card->sd_clock = 29; - } else { + else sd_card->sd_clock = CLK_30; - } + } else if ((trans_speed & 0xf8) >= 0x10) { - if (chip->asic_code) { + if (chip->asic_code) sd_card->sd_clock = 23; - } else { + else sd_card->sd_clock = CLK_20; - } + } else if ((trans_speed & 0x08) >= 0x08) { - if (chip->asic_code) { + if (chip->asic_code) sd_card->sd_clock = 19; - } else { + else sd_card->sd_clock = CLK_20; - } } else { TRACE_RET(chip, STATUS_FAIL); } @@ -527,9 +518,9 @@ static int sd_check_csd(struct rtsx_chip *chip, char check_wp) } if (check_wp) { - if (rsp[15] & 0x30) { + if (rsp[15] & 0x30) chip->card_wp |= SD_CARD; - } + RTSX_DEBUGP("CSD WP Status: 0x%x\n", rsp[15]); } @@ -568,22 +559,21 @@ static int sd_set_sample_push_timing(struct rtsx_chip *chip) CRC_FIX_CLK | SD30_VAR_CLK0 | SAMPLE_VAR_CLK1); RTSX_WRITE_REG(chip, CLK_CTL, CLK_LOW_FREQ, 0); - if ((chip->sd_ctl & SD_PUSH_POINT_CTL_MASK) == SD_PUSH_POINT_AUTO) { + if ((chip->sd_ctl & SD_PUSH_POINT_CTL_MASK) == SD_PUSH_POINT_AUTO) val = SD20_TX_NEG_EDGE; - } else if ((chip->sd_ctl & SD_PUSH_POINT_CTL_MASK) == SD_PUSH_POINT_DELAY) { + else if ((chip->sd_ctl & SD_PUSH_POINT_CTL_MASK) == SD_PUSH_POINT_DELAY) val = SD20_TX_14_AHEAD; - } else { + else val = SD20_TX_NEG_EDGE; - } + RTSX_WRITE_REG(chip, SD_PUSH_POINT_CTL, SD20_TX_SEL_MASK, val); if ((chip->sd_ctl & SD_SAMPLE_POINT_CTL_MASK) == SD_SAMPLE_POINT_AUTO) { if (chip->asic_code) { - if (CHK_SD_HS(sd_card) || CHK_MMC_52M(sd_card)) { + if (CHK_SD_HS(sd_card) || CHK_MMC_52M(sd_card)) val = SD20_RX_14_DELAY; - } else { + else val = SD20_RX_POS_EDGE; - } } else { val = SD20_RX_14_DELAY; } @@ -597,32 +587,28 @@ static int sd_set_sample_push_timing(struct rtsx_chip *chip) } else { u8 val = 0; - if ((chip->sd_ctl & SD_PUSH_POINT_CTL_MASK) == SD_PUSH_POINT_DELAY) { + if ((chip->sd_ctl & SD_PUSH_POINT_CTL_MASK) == SD_PUSH_POINT_DELAY) val |= 0x10; - } if ((chip->sd_ctl & SD_SAMPLE_POINT_CTL_MASK) == SD_SAMPLE_POINT_AUTO) { if (chip->asic_code) { if (CHK_SD_HS(sd_card) || CHK_MMC_52M(sd_card)) { - if (val & 0x10) { + if (val & 0x10) val |= 0x04; - } else { + else val |= 0x08; - } } } else { - if (val & 0x10) { + if (val & 0x10) val |= 0x04; - } else { + else val |= 0x08; - } } } else if ((chip->sd_ctl & SD_SAMPLE_POINT_CTL_MASK) == SD_SAMPLE_POINT_DELAY) { - if (val & 0x10) { + if (val & 0x10) val |= 0x04; - } else { + else val |= 0x08; - } } RTSX_WRITE_REG(chip, REG_SD_CFG1, 0x1C, val); @@ -636,41 +622,40 @@ static void sd_choose_proper_clock(struct rtsx_chip *chip) struct sd_info *sd_card = &(chip->sd_card); if (CHK_SD_SDR104(sd_card)) { - if (chip->asic_code) { + if (chip->asic_code) sd_card->sd_clock = chip->asic_sd_sdr104_clk; - } else { + else sd_card->sd_clock = chip->fpga_sd_sdr104_clk; - } + } else if (CHK_SD_DDR50(sd_card)) { - if (chip->asic_code) { + if (chip->asic_code) sd_card->sd_clock = chip->asic_sd_ddr50_clk; - } else { + else sd_card->sd_clock = chip->fpga_sd_ddr50_clk; - } + } else if (CHK_SD_SDR50(sd_card)) { - if (chip->asic_code) { + if (chip->asic_code) sd_card->sd_clock = chip->asic_sd_sdr50_clk; - } else { + else sd_card->sd_clock = chip->fpga_sd_sdr50_clk; - } + } else if (CHK_SD_HS(sd_card)) { - if (chip->asic_code) { + if (chip->asic_code) sd_card->sd_clock = chip->asic_sd_hs_clk; - } else { + else sd_card->sd_clock = chip->fpga_sd_hs_clk; - } + } else if (CHK_MMC_52M(sd_card) || CHK_MMC_DDR52(sd_card)) { - if (chip->asic_code) { + if (chip->asic_code) sd_card->sd_clock = chip->asic_mmc_52m_clk; - } else { + else sd_card->sd_clock = chip->fpga_mmc_52m_clk; - } + } else if (CHK_MMC_26M(sd_card)) { - if (chip->asic_code) { + if (chip->asic_code) sd_card->sd_clock = 48; - } else { + else sd_card->sd_clock = CLK_50; - } } } @@ -683,13 +668,12 @@ static int sd_set_clock_divider(struct rtsx_chip *chip, u8 clk_div) val = clk_div; } else { mask = 0x60; - if (clk_div == SD_CLK_DIVIDE_0) { + if (clk_div == SD_CLK_DIVIDE_0) val = 0x00; - } else if (clk_div == SD_CLK_DIVIDE_128) { + else if (clk_div == SD_CLK_DIVIDE_128) val = 0x40; - } else if (clk_div == SD_CLK_DIVIDE_256) { + else if (clk_div == SD_CLK_DIVIDE_256) val = 0x20; - } } RTSX_WRITE_REG(chip, REG_SD_CFG1, mask, val); @@ -703,16 +687,14 @@ static int sd_set_init_para(struct rtsx_chip *chip) int retval; retval = sd_set_sample_push_timing(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } sd_choose_proper_clock(chip); retval = switch_clock(chip, sd_card->sd_clock); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -735,9 +717,8 @@ int sd_select_card(struct rtsx_chip *chip, int select) } retval = sd_send_cmd_get_rsp(chip, cmd_idx, addr, cmd_type, NULL, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -750,21 +731,18 @@ static int sd_update_lock_status(struct rtsx_chip *chip) u8 rsp[5]; retval = sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, SD_RSP_TYPE_R1, rsp, 5); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } - if (rsp[1] & 0x02) { + if (rsp[1] & 0x02) sd_card->sd_lock_status |= SD_LOCKED; - } else { + else sd_card->sd_lock_status &= ~SD_LOCKED; - } RTSX_DEBUGP("sd_card->sd_lock_status = 0x%x\n", sd_card->sd_lock_status); - if (rsp[1] & 0x01) { + if (rsp[1] & 0x01) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -779,13 +757,11 @@ static int sd_wait_state_data_ready(struct rtsx_chip *chip, u8 state, u8 data_re for (i = 0; i < polling_cnt; i++) { retval = sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, SD_RSP_TYPE_R1, rsp, 5); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } - if (((rsp[3] & 0x1E) == state) && ((rsp[3] & 0x01) == data_ready)) { + if (((rsp[3] & 0x1E) == state) && ((rsp[3] & 0x01) == data_ready)) return STATUS_SUCCESS; - } } TRACE_RET(chip, STATUS_FAIL); @@ -798,18 +774,16 @@ static int sd_change_bank_voltage(struct rtsx_chip *chip, u8 voltage) if (voltage == SD_IO_3V3) { if (chip->asic_code) { retval = rtsx_write_phy_register(chip, 0x08, 0x4FC0 | chip->phy_voltage); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } else { RTSX_WRITE_REG(chip, SD_PAD_CTL, SD_IO_USING_1V8, 0); } } else if (voltage == SD_IO_1V8) { if (chip->asic_code) { retval = rtsx_write_phy_register(chip, 0x08, 0x4C40 | chip->phy_voltage); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } else { RTSX_WRITE_REG(chip, SD_PAD_CTL, SD_IO_USING_1V8, SD_IO_USING_1V8); } @@ -828,9 +802,8 @@ static int sd_voltage_switch(struct rtsx_chip *chip) RTSX_WRITE_REG(chip, SD_BUS_STAT, SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, SD_CLK_TOGGLE_EN); retval = sd_send_cmd_get_rsp(chip, VOLTAGE_SWITCH, 0, SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } udelay(chip->sd_voltage_switch_delay); @@ -842,9 +815,9 @@ static int sd_voltage_switch(struct rtsx_chip *chip) RTSX_WRITE_REG(chip, SD_BUS_STAT, 0xFF, SD_CLK_FORCE_STOP); retval = sd_change_bank_voltage(chip, SD_IO_1V8); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + wait_timeout(50); RTSX_WRITE_REG(chip, SD_BUS_STAT, 0xFF, SD_CLK_TOGGLE_EN); @@ -893,9 +866,8 @@ static int sd_change_phase(struct rtsx_chip *chip, u8 sample_point, u8 tune_dir) if (tune_dir == TUNE_RX) { SD_VP_CTL = SD_VPRX_CTL; SD_DCMPS_CTL = SD_DCMPS_RX_CTL; - if (CHK_SD_DDR50(sd_card)) { + if (CHK_SD_DDR50(sd_card)) ddr_rx = 1; - } } else { SD_VP_CTL = SD_VPTX_CTL; SD_DCMPS_CTL = SD_DCMPS_TX_CTL; @@ -932,23 +904,22 @@ static int sd_change_phase(struct rtsx_chip *chip, u8 sample_point, u8 tune_dir) rtsx_add_cmd(chip, WRITE_REG_CMD, SD_DCMPS_CTL, DCMPS_CHANGE, DCMPS_CHANGE); rtsx_add_cmd(chip, CHECK_REG_CMD, SD_DCMPS_CTL, DCMPS_CHANGE_DONE, DCMPS_CHANGE_DONE); retval = rtsx_send_cmd(chip, SD_CARD, 100); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, Fail); - } val = *rtsx_get_cmd_data(chip); - if (val & DCMPS_ERROR) { + if (val & DCMPS_ERROR) TRACE_GOTO(chip, Fail); - } - if ((val & DCMPS_CURRENT_PHASE) != sample_point) { + + if ((val & DCMPS_CURRENT_PHASE) != sample_point) TRACE_GOTO(chip, Fail); - } + RTSX_WRITE_REG(chip, SD_DCMPS_CTL, DCMPS_CHANGE, 0); - if (ddr_rx) { + if (ddr_rx) RTSX_WRITE_REG(chip, SD_VP_CTL, PHASE_CHANGE, 0); - } else { + else RTSX_WRITE_REG(chip, CLK_CTL, CHANGE_CLK, 0); - } + udelay(50); } @@ -978,9 +949,8 @@ static int sd_check_spec(struct rtsx_chip *chip, u8 bus_width) u8 cmd[5], buf[8]; retval = sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } cmd[0] = 0x40 | SEND_SCR; cmd[1] = 0; @@ -996,9 +966,8 @@ static int sd_check_spec(struct rtsx_chip *chip, u8 bus_width) memcpy(sd_card->raw_scr, buf, 8); - if ((buf[0] & 0x0F) == 0) { + if ((buf[0] & 0x0F) == 0) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -1172,13 +1141,12 @@ static int sd_check_switch_mode(struct rtsx_chip *chip, u8 mode, */ u16 cc = ((u16)buf[0] << 8) | buf[1]; RTSX_DEBUGP("Maximum current consumption: %dmA\n", cc); - if ((cc == 0) || (cc > 800)) { + if ((cc == 0) || (cc > 800)) TRACE_RET(chip, STATUS_FAIL); - } + retval = sd_query_switch_result(chip, func_group, func_to_switch, buf, 64); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if ((cc > 400) || (func_to_switch > CURRENT_LIMIT_400)) { RTSX_WRITE_REG(chip, OCPPARA2, SD_OCP_THD_MASK, chip->sd_800mA_ocp_thd); @@ -1192,13 +1160,12 @@ static int sd_check_switch_mode(struct rtsx_chip *chip, u8 mode, static u8 downgrade_switch_mode(u8 func_group, u8 func_to_switch) { if (func_group == SD_FUNC_GROUP_1) { - if (func_to_switch > HS_SUPPORT) { + if (func_to_switch > HS_SUPPORT) func_to_switch--; - } + } else if (func_group == SD_FUNC_GROUP_4) { - if (func_to_switch > CURRENT_LIMIT_200) { + if (func_to_switch > CURRENT_LIMIT_200) func_to_switch--; - } } return func_to_switch; @@ -1241,9 +1208,8 @@ static int sd_check_switch(struct rtsx_chip *chip, wait_timeout(20); } - if (!switch_good) { + if (!switch_good) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -1258,9 +1224,8 @@ static int sd_switch_function(struct rtsx_chip *chip, u8 bus_width) /* Get supported functions */ retval = sd_check_switch_mode(chip, SD_CHECK_MODE, NO_ARGUMENT, NO_ARGUMENT, bus_width); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } sd_card->func_group1_mask &= ~(sd_card->sd_switch_fail); @@ -1289,9 +1254,9 @@ static int sd_switch_function(struct rtsx_chip *chip, u8 bus_width) break; case HS_SUPPORT: - if (sd_card->func_group1_mask & HS_SUPPORT_MASK) { + if (sd_card->func_group1_mask & HS_SUPPORT_MASK) func_to_switch = HS_SUPPORT; - } + break; default: @@ -1299,9 +1264,9 @@ static int sd_switch_function(struct rtsx_chip *chip, u8 bus_width) } - if (func_to_switch) { + if (func_to_switch) break; - } + } RTSX_DEBUGP("SD_FUNC_GROUP_1: func_to_switch = 0x%02x", func_to_switch); @@ -1330,23 +1295,21 @@ static int sd_switch_function(struct rtsx_chip *chip, u8 bus_width) TRACE_RET(chip, STATUS_FAIL); } - if (func_to_switch == SDR104_SUPPORT) { + if (func_to_switch == SDR104_SUPPORT) SET_SD_SDR104(sd_card); - } else if (func_to_switch == DDR50_SUPPORT) { + else if (func_to_switch == DDR50_SUPPORT) SET_SD_DDR50(sd_card); - } else if (func_to_switch == SDR50_SUPPORT) { + else if (func_to_switch == SDR50_SUPPORT) SET_SD_SDR50(sd_card); - } else { + else SET_SD_HS(sd_card); - } } if (CHK_SD_DDR50(sd_card)) { RTSX_WRITE_REG(chip, SD_PUSH_POINT_CTL, 0x06, 0x04); retval = sd_set_sample_push_timing(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } if (!func_to_switch || (func_to_switch == HS_SUPPORT)) { @@ -1362,36 +1325,35 @@ static int sd_switch_function(struct rtsx_chip *chip, u8 bus_width) for (i = 0; i < 4; i++) { switch ((u8)(chip->sd_current_prior >> (i*8))) { case CURRENT_LIMIT_800: - if (sd_card->func_group4_mask & CURRENT_LIMIT_800_MASK) { + if (sd_card->func_group4_mask & CURRENT_LIMIT_800_MASK) func_to_switch = CURRENT_LIMIT_800; - } + break; case CURRENT_LIMIT_600: - if (sd_card->func_group4_mask & CURRENT_LIMIT_600_MASK) { + if (sd_card->func_group4_mask & CURRENT_LIMIT_600_MASK) func_to_switch = CURRENT_LIMIT_600; - } + break; case CURRENT_LIMIT_400: - if (sd_card->func_group4_mask & CURRENT_LIMIT_400_MASK) { + if (sd_card->func_group4_mask & CURRENT_LIMIT_400_MASK) func_to_switch = CURRENT_LIMIT_400; - } + break; case CURRENT_LIMIT_200: - if (sd_card->func_group4_mask & CURRENT_LIMIT_200_MASK) { + if (sd_card->func_group4_mask & CURRENT_LIMIT_200_MASK) func_to_switch = CURRENT_LIMIT_200; - } + break; default: continue; } - if (func_to_switch != 0xFF) { + if (func_to_switch != 0xFF) break; - } } RTSX_DEBUGP("SD_FUNC_GROUP_4: func_to_switch = 0x%02x", func_to_switch); @@ -1399,16 +1361,14 @@ static int sd_switch_function(struct rtsx_chip *chip, u8 bus_width) if (func_to_switch <= CURRENT_LIMIT_800) { retval = sd_check_switch(chip, SD_FUNC_GROUP_4, func_to_switch, bus_width); if (retval != STATUS_SUCCESS) { - if (sd_check_err_code(chip, SD_NO_CARD)) { + if (sd_check_err_code(chip, SD_NO_CARD)) TRACE_RET(chip, STATUS_FAIL); - } } RTSX_DEBUGP("Switch current limit finished! (%d)\n", retval); } - if (CHK_SD_DDR50(sd_card)) { + if (CHK_SD_DDR50(sd_card)) RTSX_WRITE_REG(chip, SD_PUSH_POINT_CTL, 0x06, 0); - } return STATUS_SUCCESS; } @@ -1438,9 +1398,8 @@ static int sd_sdr_tuning_rx_cmd(struct rtsx_chip *chip, u8 sample_point) u8 cmd[5]; retval = sd_change_phase(chip, sample_point, TUNE_RX); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } cmd[0] = 0x40 | SEND_TUNING_PATTERN; cmd[1] = 0; @@ -1467,16 +1426,14 @@ static int sd_ddr_tuning_rx_cmd(struct rtsx_chip *chip, u8 sample_point) u8 cmd[5]; retval = sd_change_phase(chip, sample_point, TUNE_RX); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } RTSX_DEBUGP("sd ddr tuning rx\n"); retval = sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } cmd[0] = 0x40 | SD_STATUS; cmd[1] = 0; @@ -1502,18 +1459,16 @@ static int mmc_ddr_tunning_rx_cmd(struct rtsx_chip *chip, u8 sample_point) int retval; u8 cmd[5], bus_width; - if (CHK_MMC_8BIT(sd_card)) { + if (CHK_MMC_8BIT(sd_card)) bus_width = SD_BUS_WIDTH_8; - } else if (CHK_MMC_4BIT(sd_card)) { + else if (CHK_MMC_4BIT(sd_card)) bus_width = SD_BUS_WIDTH_4; - } else { + else bus_width = SD_BUS_WIDTH_1; - } retval = sd_change_phase(chip, sample_point, TUNE_RX); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } RTSX_DEBUGP("mmc ddr tuning rx\n"); @@ -1541,9 +1496,8 @@ static int sd_sdr_tuning_tx_cmd(struct rtsx_chip *chip, u8 sample_point) int retval; retval = sd_change_phase(chip, sample_point, TUNE_TX); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } RTSX_WRITE_REG(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN, SD_RSP_80CLK_TIMEOUT_EN); @@ -1568,26 +1522,23 @@ static int sd_ddr_tuning_tx_cmd(struct rtsx_chip *chip, u8 sample_point) u8 cmd[5], bus_width; retval = sd_change_phase(chip, sample_point, TUNE_TX); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (CHK_SD(sd_card)) { bus_width = SD_BUS_WIDTH_4; } else { - if (CHK_MMC_8BIT(sd_card)) { + if (CHK_MMC_8BIT(sd_card)) bus_width = SD_BUS_WIDTH_8; - } else if (CHK_MMC_4BIT(sd_card)) { + else if (CHK_MMC_4BIT(sd_card)) bus_width = SD_BUS_WIDTH_4; - } else { + else bus_width = SD_BUS_WIDTH_1; - } } retval = sd_wait_state_data_ready(chip, 0x08, 1, 1000); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } RTSX_WRITE_REG(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN, SD_RSP_80CLK_TIMEOUT_EN); @@ -1621,11 +1572,10 @@ static u8 sd_search_final_phase(struct rtsx_chip *chip, u32 phase_map, u8 tune_d u8 final_phase = 0xFF; if (phase_map == 0xFFFFFFFF) { - if (tune_dir == TUNE_RX) { + if (tune_dir == TUNE_RX) final_phase = (u8)chip->sd_default_rx_phase; - } else { + else final_phase = (u8)chip->sd_default_tx_phase; - } goto Search_Finish; } @@ -1666,9 +1616,9 @@ static u8 sd_search_final_phase(struct rtsx_chip *chip, u32 phase_map, u8 tune_d path[0].start = path[cont_path_cnt - 1].start - MAX_PHASE - 1; path[0].len += path[cont_path_cnt - 1].len; path[0].mid = path[0].start + path[0].len / 2; - if (path[0].mid < 0) { + if (path[0].mid < 0) path[0].mid += MAX_PHASE + 1; - } + cont_path_cnt--; } @@ -1696,11 +1646,10 @@ static u8 sd_search_final_phase(struct rtsx_chip *chip, u32 phase_map, u8 tune_d int temp_final_phase = path[final_path_idx].end - (max_len - (6 + temp_mid)); - if (temp_final_phase < 0) { + if (temp_final_phase < 0) final_phase = (u8)(temp_final_phase + MAX_PHASE + 1); - } else { + else final_phase = (u8)temp_final_phase; - } } } else if (CHK_SD_SDR50(sd_card)) { if (max_len > 12) { @@ -1708,11 +1657,10 @@ static u8 sd_search_final_phase(struct rtsx_chip *chip, u32 phase_map, u8 tune_d int temp_final_phase = path[final_path_idx].end - (max_len - (3 + temp_mid)); - if (temp_final_phase < 0) { + if (temp_final_phase < 0) final_phase = (u8)(temp_final_phase + MAX_PHASE + 1); - } else { + else final_phase = (u8)temp_final_phase; - } } } } @@ -1732,17 +1680,16 @@ static int sd_tuning_rx(struct rtsx_chip *chip) int (*tuning_cmd)(struct rtsx_chip *chip, u8 sample_point); if (CHK_SD(sd_card)) { - if (CHK_SD_DDR50(sd_card)) { + if (CHK_SD_DDR50(sd_card)) tuning_cmd = sd_ddr_tuning_rx_cmd; - } else { + else tuning_cmd = sd_sdr_tuning_rx_cmd; - } + } else { - if (CHK_MMC_DDR52(sd_card)) { + if (CHK_MMC_DDR52(sd_card)) tuning_cmd = mmc_ddr_tunning_rx_cmd; - } else { + else TRACE_RET(chip, STATUS_FAIL); - } } for (i = 0; i < 3; i++) { @@ -1754,27 +1701,24 @@ static int sd_tuning_rx(struct rtsx_chip *chip) } retval = tuning_cmd(chip, (u8)j); - if (retval == STATUS_SUCCESS) { + if (retval == STATUS_SUCCESS) raw_phase_map[i] |= 1 << j; - } } } phase_map = raw_phase_map[0] & raw_phase_map[1] & raw_phase_map[2]; - for (i = 0; i < 3; i++) { + for (i = 0; i < 3; i++) RTSX_DEBUGP("RX raw_phase_map[%d] = 0x%08x\n", i, raw_phase_map[i]); - } + RTSX_DEBUGP("RX phase_map = 0x%08x\n", phase_map); final_phase = sd_search_final_phase(chip, phase_map, TUNE_RX); - if (final_phase == 0xFF) { + if (final_phase == 0xFF) TRACE_RET(chip, STATUS_FAIL); - } retval = sd_change_phase(chip, final_phase, TUNE_RX); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -1799,15 +1743,13 @@ static int sd_ddr_pre_tuning_tx(struct rtsx_chip *chip) } retval = sd_change_phase(chip, (u8)i, TUNE_TX); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) continue; - } retval = sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0); - if ((retval == STATUS_SUCCESS) || !sd_check_err_code(chip, SD_RSP_TIMEOUT)) { + if ((retval == STATUS_SUCCESS) || !sd_check_err_code(chip, SD_RSP_TIMEOUT)) phase_map |= 1 << i; - } } RTSX_WRITE_REG(chip, SD_CFG3, SD_RSP_80CLK_TIMEOUT_EN, 0); @@ -1815,14 +1757,12 @@ static int sd_ddr_pre_tuning_tx(struct rtsx_chip *chip) RTSX_DEBUGP("DDR TX pre tune phase_map = 0x%08x\n", phase_map); final_phase = sd_search_final_phase(chip, phase_map, TUNE_TX); - if (final_phase == 0xFF) { + if (final_phase == 0xFF) TRACE_RET(chip, STATUS_FAIL); - } retval = sd_change_phase(chip, final_phase, TUNE_TX); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } RTSX_DEBUGP("DDR TX pre tune phase: %d\n", (int)final_phase); @@ -1839,17 +1779,16 @@ static int sd_tuning_tx(struct rtsx_chip *chip) int (*tuning_cmd)(struct rtsx_chip *chip, u8 sample_point); if (CHK_SD(sd_card)) { - if (CHK_SD_DDR50(sd_card)) { + if (CHK_SD_DDR50(sd_card)) tuning_cmd = sd_ddr_tuning_tx_cmd; - } else { + else tuning_cmd = sd_sdr_tuning_tx_cmd; - } + } else { - if (CHK_MMC_DDR52(sd_card)) { + if (CHK_MMC_DDR52(sd_card)) tuning_cmd = sd_ddr_tuning_tx_cmd; - } else { + else TRACE_RET(chip, STATUS_FAIL); - } } for (i = 0; i < 3; i++) { @@ -1863,27 +1802,24 @@ static int sd_tuning_tx(struct rtsx_chip *chip) } retval = tuning_cmd(chip, (u8)j); - if (retval == STATUS_SUCCESS) { + if (retval == STATUS_SUCCESS) raw_phase_map[i] |= 1 << j; - } } } phase_map = raw_phase_map[0] & raw_phase_map[1] & raw_phase_map[2]; - for (i = 0; i < 3; i++) { + for (i = 0; i < 3; i++) RTSX_DEBUGP("TX raw_phase_map[%d] = 0x%08x\n", i, raw_phase_map[i]); - } + RTSX_DEBUGP("TX phase_map = 0x%08x\n", phase_map); final_phase = sd_search_final_phase(chip, phase_map, TUNE_TX); - if (final_phase == 0xFF) { + if (final_phase == 0xFF) TRACE_RET(chip, STATUS_FAIL); - } retval = sd_change_phase(chip, final_phase, TUNE_TX); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -1893,14 +1829,12 @@ static int sd_sdr_tuning(struct rtsx_chip *chip) int retval; retval = sd_tuning_tx(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = sd_tuning_rx(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -1911,26 +1845,22 @@ static int sd_ddr_tuning(struct rtsx_chip *chip) if (!(chip->sd_ctl & SD_DDR_TX_PHASE_SET_BY_USER)) { retval = sd_ddr_pre_tuning_tx(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } else { retval = sd_change_phase(chip, (u8)chip->sd_ddr_tx_phase, TUNE_TX); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } retval = sd_tuning_rx(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (!(chip->sd_ctl & SD_DDR_TX_PHASE_SET_BY_USER)) { retval = sd_tuning_tx(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } return STATUS_SUCCESS; @@ -1942,26 +1872,22 @@ static int mmc_ddr_tuning(struct rtsx_chip *chip) if (!(chip->sd_ctl & MMC_DDR_TX_PHASE_SET_BY_USER)) { retval = sd_ddr_pre_tuning_tx(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } else { retval = sd_change_phase(chip, (u8)chip->mmc_ddr_tx_phase, TUNE_TX); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } retval = sd_tuning_rx(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (!(chip->sd_ctl & MMC_DDR_TX_PHASE_SET_BY_USER)) { retval = sd_tuning_tx(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } return STATUS_SUCCESS; @@ -1974,9 +1900,8 @@ int sd_switch_clock(struct rtsx_chip *chip) int re_tuning = 0; retval = select_card(chip, SD_CARD); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (CHECK_PID(chip, 0x5209) && (CHK_SD30_SPEED(sd_card) || CHK_MMC_DDR52(sd_card))) { @@ -1987,26 +1912,22 @@ int sd_switch_clock(struct rtsx_chip *chip) } retval = switch_clock(chip, sd_card->sd_clock); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (re_tuning) { if (CHK_SD(sd_card)) { - if (CHK_SD_DDR50(sd_card)) { + if (CHK_SD_DDR50(sd_card)) retval = sd_ddr_tuning(chip); - } else { + else retval = sd_sdr_tuning(chip); - } } else { - if (CHK_MMC_DDR52(sd_card)) { + if (CHK_MMC_DDR52(sd_card)) retval = mmc_ddr_tuning(chip); - } } - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } return STATUS_SUCCESS; @@ -2017,11 +1938,10 @@ static int sd_prepare_reset(struct rtsx_chip *chip) struct sd_info *sd_card = &(chip->sd_card); int retval; - if (chip->asic_code) { + if (chip->asic_code) sd_card->sd_clock = 29; - } else { + else sd_card->sd_clock = CLK_30; - } sd_card->sd_type = 0; sd_card->seq_mode = 0; @@ -2037,9 +1957,8 @@ static int sd_prepare_reset(struct rtsx_chip *chip) chip->sd_io = 0; retval = sd_set_init_para(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, retval); - } if (CHECK_PID(chip, 0x5209)) { RTSX_WRITE_REG(chip, REG_SD_CFG1, 0xFF, @@ -2053,9 +1972,8 @@ static int sd_prepare_reset(struct rtsx_chip *chip) RTSX_WRITE_REG(chip, CARD_STOP, SD_STOP | SD_CLR_ERR, SD_STOP | SD_CLR_ERR); retval = select_card(chip, SD_CARD); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -2122,9 +2040,8 @@ int sd_pull_ctl_enable(struct rtsx_chip *chip) } retval = rtsx_send_cmd(chip, SD_CARD, 100); - if (retval < 0) { + if (retval < 0) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -2133,42 +2050,37 @@ static int sd_init_power(struct rtsx_chip *chip) { int retval; - if (CHECK_PID(chip, 0x5209)) { + if (CHECK_PID(chip, 0x5209)) RTSX_WRITE_REG(chip, PWR_GATE_CTRL, LDO3318_PWR_MASK, LDO_OFF); - } retval = sd_power_off_card3v3(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } - if (!chip->ft2_fast_mode) { + if (!chip->ft2_fast_mode) wait_timeout(250); - } retval = enable_card_clock(chip, SD_CARD); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (chip->asic_code) { retval = sd_pull_ctl_enable(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } else { RTSX_WRITE_REG(chip, FPGA_PULL_CTL, FPGA_SD_PULL_CTL_BIT | 0x20, 0); } if (chip->ft2_fast_mode) { - if (CHECK_PID(chip, 0x5209)) { + if (CHECK_PID(chip, 0x5209)) RTSX_WRITE_REG(chip, PWR_GATE_CTRL, LDO3318_PWR_MASK, LDO_ON); - } + } else { retval = card_power_on(chip, SD_CARD); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + wait_timeout(260); #ifdef SUPPORT_OCP @@ -2214,13 +2126,12 @@ static int sd_read_lba0(struct rtsx_chip *chip) if (CHK_SD(sd_card)) { bus_width = SD_BUS_WIDTH_4; } else { - if (CHK_MMC_8BIT(sd_card)) { + if (CHK_MMC_8BIT(sd_card)) bus_width = SD_BUS_WIDTH_8; - } else if (CHK_MMC_4BIT(sd_card)) { + else if (CHK_MMC_4BIT(sd_card)) bus_width = SD_BUS_WIDTH_4; - } else { + else bus_width = SD_BUS_WIDTH_1; - } } retval = sd_read_data(chip, SD_TM_NORMAL_READ, cmd, @@ -2243,9 +2154,8 @@ static int sd_check_wp_state(struct rtsx_chip *chip) retval = sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } cmd[0] = 0x40 | SD_STATUS; cmd[1] = 0; @@ -2273,9 +2183,8 @@ static int sd_check_wp_state(struct rtsx_chip *chip) /* Check SD Machanical Write-Protect Switch */ val = rtsx_readl(chip, RTSX_BIPR); - if (val & SD_WRITE_PROTECT) { + if (val & SD_WRITE_PROTECT) chip->card_wp |= SD_CARD; - } return STATUS_SUCCESS; } @@ -2307,14 +2216,12 @@ Switch_Fail: #endif retval = sd_prepare_reset(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = sd_dummy_clock(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip) && try_sdio) { int rty_cnt = 0; @@ -2348,9 +2255,8 @@ Switch_Fail: /* Start Initialization Process of SD Card */ RTY_SD_RST: retval = sd_send_cmd_get_rsp(chip, GO_IDLE_STATE, 0, SD_RSP_TYPE_R0, NULL, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } wait_timeout(20); @@ -2377,9 +2283,8 @@ RTY_SD_RST: voltage = SUPPORT_VOLTAGE; retval = sd_send_cmd_get_rsp(chip, GO_IDLE_STATE, 0, SD_RSP_TYPE_R0, NULL, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } wait_timeout(20); } @@ -2393,42 +2298,38 @@ RTY_SD_RST: } j++; - if (j < 3) { + if (j < 3) goto RTY_SD_RST; - } else { + else TRACE_RET(chip, STATUS_FAIL); - } } retval = sd_send_cmd_get_rsp(chip, SD_APP_OP_COND, voltage, SD_RSP_TYPE_R3, rsp, 5); if (retval != STATUS_SUCCESS) { k++; - if (k < 3) { + if (k < 3) goto RTY_SD_RST; - } else { + else TRACE_RET(chip, STATUS_FAIL); - } } i++; wait_timeout(20); } while (!(rsp[1] & 0x80) && (i < 255)); - if (i == 255) { + if (i == 255) TRACE_RET(chip, STATUS_FAIL); - } if (hi_cap_flow) { - if (rsp[1] & 0x40) { + if (rsp[1] & 0x40) SET_SD_HCXC(sd_card); - } else { + else CLR_SD_HCXC(sd_card); - } - if (CHECK_PID(chip, 0x5209) && CHK_SD_HCXC(sd_card) && !sd20_mode) { + + if (CHECK_PID(chip, 0x5209) && CHK_SD_HCXC(sd_card) && !sd20_mode) support_1v8 = (rsp[1] & 0x01) ? 1 : 0; - } else { + else support_1v8 = 0; - } } else { CLR_SD_HCXC(sd_card); support_1v8 = 0; @@ -2437,46 +2338,39 @@ RTY_SD_RST: if (support_1v8) { retval = sd_voltage_switch(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } retval = sd_send_cmd_get_rsp(chip, ALL_SEND_CID, 0, SD_RSP_TYPE_R2, NULL, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } for (i = 0; i < 3; i++) { retval = sd_send_cmd_get_rsp(chip, SEND_RELATIVE_ADDR, 0, SD_RSP_TYPE_R6, rsp, 5); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } sd_card->sd_addr = (u32)rsp[1] << 24; sd_card->sd_addr += (u32)rsp[2] << 16; - if (sd_card->sd_addr) { + if (sd_card->sd_addr) break; - } } retval = sd_check_csd(chip, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = sd_select_card(chip, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } #ifdef SUPPORT_SD_LOCK SD_UNLOCK_ENTRY: retval = sd_update_lock_status(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (sd_card->sd_lock_status & SD_LOCKED) { sd_card->sd_lock_status |= (SD_LOCK_1BIT_MODE | SD_PWD_EXIST); @@ -2487,23 +2381,21 @@ SD_UNLOCK_ENTRY: #endif retval = sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + retval = sd_send_cmd_get_rsp(chip, SET_CLR_CARD_DETECT, 0, SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (support_1v8) { retval = sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + retval = sd_send_cmd_get_rsp(chip, SET_BUS_WIDTH, 2, SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } switch_bus_width = SD_BUS_WIDTH_4; } else { @@ -2511,14 +2403,12 @@ SD_UNLOCK_ENTRY: } retval = sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, 0x200, SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = sd_set_clock_divider(chip, SD_CLK_DIVIDE_0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (!(sd_card->raw_csd[4] & 0x40)) sd_dont_switch = 1; @@ -2537,9 +2427,9 @@ SD_UNLOCK_ENTRY: if (retval == STATUS_SUCCESS) { retval = sd_switch_function(chip, switch_bus_width); if (retval != STATUS_SUCCESS) { - if (CHECK_PID(chip, 0x5209)) { + if (CHECK_PID(chip, 0x5209)) sd_change_bank_voltage(chip, SD_IO_3V3); - } + sd_init_power(chip); sd_dont_switch = 1; try_sdio = 0; @@ -2548,9 +2438,9 @@ SD_UNLOCK_ENTRY: } } else { if (support_1v8) { - if (CHECK_PID(chip, 0x5209)) { + if (CHECK_PID(chip, 0x5209)) sd_change_bank_voltage(chip, SD_IO_3V3); - } + sd_init_power(chip); sd_dont_switch = 1; try_sdio = 0; @@ -2562,13 +2452,12 @@ SD_UNLOCK_ENTRY: if (!support_1v8) { retval = sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + retval = sd_send_cmd_get_rsp(chip, SET_BUS_WIDTH, 2, SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } #ifdef SUPPORT_SD_LOCK @@ -2581,24 +2470,22 @@ SD_UNLOCK_ENTRY: RTSX_WRITE_REG(chip, SD30_DRIVE_SEL, 0x07, chip->sd30_drive_sel_1v8); retval = sd_set_init_para(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } - if (CHK_SD_DDR50(sd_card)) { + if (CHK_SD_DDR50(sd_card)) retval = sd_ddr_tuning(chip); - } else { + else retval = sd_sdr_tuning(chip); - } if (retval != STATUS_SUCCESS) { if (sd20_mode) { TRACE_RET(chip, STATUS_FAIL); } else { retval = sd_init_power(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + try_sdio = 0; sd20_mode = 1; goto Switch_Fail; @@ -2609,9 +2496,8 @@ SD_UNLOCK_ENTRY: if (CHK_SD_DDR50(sd_card)) { retval = sd_wait_state_data_ready(chip, 0x08, 1, 1000); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) read_lba0 = 0; - } } if (read_lba0) { @@ -2621,9 +2507,9 @@ SD_UNLOCK_ENTRY: TRACE_RET(chip, STATUS_FAIL); } else { retval = sd_init_power(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + try_sdio = 0; sd20_mode = 1; goto Switch_Fail; @@ -2633,9 +2519,8 @@ SD_UNLOCK_ENTRY: } retval = sd_check_wp_state(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } chip->card_bus_width[chip->card2lun[SD_CARD]] = 4; @@ -2659,9 +2544,8 @@ static int mmc_test_switch_bus(struct rtsx_chip *chip, u8 width) int len; retval = sd_send_cmd_get_rsp(chip, BUSTEST_W, 0, SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, SWITCH_FAIL); - } if (width == MMC_8BIT_BUS) { buf[0] = 0x55; @@ -2690,9 +2574,8 @@ static int mmc_test_switch_bus(struct rtsx_chip *chip, u8 width) rtsx_read_register(chip, REG_SD_STAT1, &val1); rtsx_read_register(chip, REG_SD_STAT2, &val2); rtsx_clear_sd_error(chip); - if ((val1 & 0xE0) || val2) { + if ((val1 & 0xE0) || val2) TRACE_RET(chip, SWITCH_ERR); - } } else { rtsx_clear_sd_error(chip); rtsx_write_register(chip, REG_SD_CFG3, 0x02, 0); @@ -2712,11 +2595,10 @@ static int mmc_test_switch_bus(struct rtsx_chip *chip, u8 width) rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CMD0, 0xFF, 0x40 | BUSTEST_R); - if (width == MMC_8BIT_BUS) { + if (width == MMC_8BIT_BUS) rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_L, 0xFF, 0x08); - } else { + else rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BYTE_CNT_L, 0xFF, 0x04); - } rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BLOCK_CNT_L, 0xFF, 1); rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_BLOCK_CNT_H, 0xFF, 0); @@ -2729,9 +2611,8 @@ static int mmc_test_switch_bus(struct rtsx_chip *chip, u8 width) rtsx_add_cmd(chip, CHECK_REG_CMD, REG_SD_TRANSFER, SD_TRANSFER_END, SD_TRANSFER_END); rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2, 0, 0); - if (width == MMC_8BIT_BUS) { + if (width == MMC_8BIT_BUS) rtsx_add_cmd(chip, READ_REG_CMD, PPBUF_BASE2 + 1, 0, 0); - } retval = rtsx_send_cmd(chip, SD_CARD, 100); if (retval < 0) { @@ -2747,15 +2628,14 @@ static int mmc_test_switch_bus(struct rtsx_chip *chip, u8 width) u8 rsp[5]; u32 arg; - if (CHK_MMC_DDR52(sd_card)) { + if (CHK_MMC_DDR52(sd_card)) arg = 0x03B70600; - } else { + else arg = 0x03B70200; - } + retval = sd_send_cmd_get_rsp(chip, SWITCH, arg, SD_RSP_TYPE_R1b, rsp, 5); - if ((retval == STATUS_SUCCESS) && !(rsp[4] & MMC_SWITCH_ERR)) { + if ((retval == STATUS_SUCCESS) && !(rsp[4] & MMC_SWITCH_ERR)) return SWITCH_SUCCESS; - } } } else { RTSX_DEBUGP("BUSTEST_R [4bits]: 0x%02x\n", ptr[0]); @@ -2763,15 +2643,14 @@ static int mmc_test_switch_bus(struct rtsx_chip *chip, u8 width) u8 rsp[5]; u32 arg; - if (CHK_MMC_DDR52(sd_card)) { + if (CHK_MMC_DDR52(sd_card)) arg = 0x03B70500; - } else { + else arg = 0x03B70100; - } + retval = sd_send_cmd_get_rsp(chip, SWITCH, arg, SD_RSP_TYPE_R1b, rsp, 5); - if ((retval == STATUS_SUCCESS) && !(rsp[4] & MMC_SWITCH_ERR)) { + if ((retval == STATUS_SUCCESS) && !(rsp[4] & MMC_SWITCH_ERR)) return SWITCH_SUCCESS; - } } } @@ -2845,11 +2724,10 @@ static int mmc_switch_timing_bus(struct rtsx_chip *chip, int switch_ddr) card_type_mask = 0x03; } #else - if (chip->sd_ctl & SUPPORT_MMC_DDR_MODE) { + if (chip->sd_ctl & SUPPORT_MMC_DDR_MODE) card_type_mask = 0x07; - } else { + else card_type_mask = 0x03; - } #endif } else { card_type_mask = 0x03; @@ -2859,11 +2737,10 @@ static int mmc_switch_timing_bus(struct rtsx_chip *chip, int switch_ddr) u8 rsp[5]; if (card_type & 0x04) { - if (switch_ddr) { + if (switch_ddr) SET_MMC_DDR52(sd_card); - } else { + else SET_MMC_52M(sd_card); - } } else if (card_type & 0x02) { SET_MMC_52M(sd_card); } else { @@ -2872,16 +2749,14 @@ static int mmc_switch_timing_bus(struct rtsx_chip *chip, int switch_ddr) retval = sd_send_cmd_get_rsp(chip, SWITCH, 0x03B90100, SD_RSP_TYPE_R1b, rsp, 5); - if ((retval != STATUS_SUCCESS) || (rsp[4] & MMC_SWITCH_ERR)) { + if ((retval != STATUS_SUCCESS) || (rsp[4] & MMC_SWITCH_ERR)) CLR_MMC_HS(sd_card); - } } sd_choose_proper_clock(chip); retval = switch_clock(chip, sd_card->sd_clock); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } /* Test Bus Procedure */ retval = mmc_test_switch_bus(chip, MMC_8BIT_BUS); @@ -2929,17 +2804,15 @@ static int reset_mmc(struct rtsx_chip *chip) Switch_Fail: retval = sd_prepare_reset(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, retval); - } SET_MMC(sd_card); RTY_MMC_RST: retval = sd_send_cmd_get_rsp(chip, GO_IDLE_STATE, 0, SD_RSP_TYPE_R0, NULL, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } do { if (detect_card_cd(chip, SD_CARD) != STATUS_SUCCESS) { @@ -2973,56 +2846,47 @@ RTY_MMC_RST: i++; } while (!(rsp[1] & 0x80) && (i < 255)); - if (i == 255) { + if (i == 255) TRACE_RET(chip, STATUS_FAIL); - } - if ((rsp[1] & 0x60) == 0x40) { + if ((rsp[1] & 0x60) == 0x40) SET_MMC_SECTOR_MODE(sd_card); - } else { + else CLR_MMC_SECTOR_MODE(sd_card); - } retval = sd_send_cmd_get_rsp(chip, ALL_SEND_CID, 0, SD_RSP_TYPE_R2, NULL, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } sd_card->sd_addr = 0x00100000; retval = sd_send_cmd_get_rsp(chip, SET_RELATIVE_ADDR, sd_card->sd_addr, SD_RSP_TYPE_R6, rsp, 5); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = sd_check_csd(chip, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } spec_ver = (sd_card->raw_csd[0] & 0x3C) >> 2; retval = sd_select_card(chip, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, 0x200, SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } #ifdef SUPPORT_SD_LOCK MMC_UNLOCK_ENTRY: retval = sd_update_lock_status(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } #endif retval = sd_set_clock_divider(chip, SD_CLK_DIVIDE_0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } chip->card_bus_width[chip->card2lun[SD_CARD]] = 1; @@ -3039,22 +2903,20 @@ MMC_UNLOCK_ENTRY: } } - if (CHK_MMC_SECTOR_MODE(sd_card) && (sd_card->capacity == 0)) { + if (CHK_MMC_SECTOR_MODE(sd_card) && (sd_card->capacity == 0)) TRACE_RET(chip, STATUS_FAIL); - } if (switch_ddr && CHK_MMC_DDR52(sd_card)) { retval = sd_set_init_para(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = mmc_ddr_tuning(chip); if (retval != STATUS_SUCCESS) { retval = sd_init_power(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + switch_ddr = 0; TRACE_GOTO(chip, Switch_Fail); } @@ -3064,9 +2926,9 @@ MMC_UNLOCK_ENTRY: retval = sd_read_lba0(chip); if (retval != STATUS_SUCCESS) { retval = sd_init_power(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + switch_ddr = 0; TRACE_GOTO(chip, Switch_Fail); } @@ -3082,9 +2944,8 @@ MMC_UNLOCK_ENTRY: #endif temp = rtsx_readl(chip, RTSX_BIPR); - if (temp & SD_WRITE_PROTECT) { + if (temp & SD_WRITE_PROTECT) chip->card_wp |= SD_CARD; - } return STATUS_SUCCESS; } @@ -3100,36 +2961,31 @@ int reset_sd_card(struct rtsx_chip *chip) chip->capacity[chip->card2lun[SD_CARD]] = 0; retval = enable_card_clock(chip, SD_CARD); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (chip->ignore_sd && CHK_SDIO_EXIST(chip) && !CHK_SDIO_IGNORED(chip)) { if (chip->asic_code) { retval = sd_pull_ctl_enable(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } else { retval = rtsx_write_register(chip, FPGA_PULL_CTL, FPGA_SD_PULL_CTL_BIT | 0x20, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } retval = card_share_mode(chip, SD_CARD); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } chip->sd_io = 1; TRACE_RET(chip, STATUS_FAIL); } retval = sd_init_power(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (chip->sd_ctl & RESET_MMC_FIRST) { retval = reset_mmc(chip); @@ -3168,18 +3024,17 @@ int reset_sd_card(struct rtsx_chip *chip) } retval = sd_set_clock_divider(chip, SD_CLK_DIVIDE_0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + RTSX_WRITE_REG(chip, REG_SD_BYTE_CNT_L, 0xFF, 0); RTSX_WRITE_REG(chip, REG_SD_BYTE_CNT_H, 0xFF, 2); chip->capacity[chip->card2lun[SD_CARD]] = sd_card->capacity; retval = sd_set_init_para(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } RTSX_DEBUGP("sd_card->sd_type = 0x%x\n", sd_card->sd_type); @@ -3205,33 +3060,29 @@ static int reset_mmc_only(struct rtsx_chip *chip) chip->capacity[chip->card2lun[SD_CARD]] = sd_card->capacity = 0; retval = enable_card_clock(chip, SD_CARD); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = sd_init_power(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = reset_mmc(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } retval = sd_set_clock_divider(chip, SD_CLK_DIVIDE_0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } + RTSX_WRITE_REG(chip, REG_SD_BYTE_CNT_L, 0xFF, 0); RTSX_WRITE_REG(chip, REG_SD_BYTE_CNT_H, 0xFF, 2); chip->capacity[chip->card2lun[SD_CARD]] = sd_card->capacity; retval = sd_set_init_para(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } RTSX_DEBUGP("In reset_mmc_only, sd_card->sd_type = 0x%x\n", sd_card->sd_type); @@ -3255,9 +3106,8 @@ static int wait_data_buf_ready(struct rtsx_chip *chip) retval = sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (sd_card->sd_data_buf_ready) { return sd_send_cmd_get_rsp(chip, SEND_STATUS, @@ -3277,19 +3127,18 @@ void sd_stop_seq_mode(struct rtsx_chip *chip) if (sd_card->seq_mode) { retval = sd_switch_clock(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) return; - } retval = sd_send_cmd_get_rsp(chip, STOP_TRANSMISSION, 0, SD_RSP_TYPE_R1b, NULL, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) sd_set_err_code(chip, SD_STS_ERR); - } + retval = sd_wait_state_data_ready(chip, 0x08, 1, 1000); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) sd_set_err_code(chip, SD_STS_ERR); - } + sd_card->seq_mode = 0; rtsx_write_register(chip, RBCTL, RB_FLUSH, RB_FLUSH); @@ -3302,9 +3151,8 @@ static inline int sd_auto_tune_clock(struct rtsx_chip *chip) int retval; if (chip->asic_code) { - if (sd_card->sd_clock > 30) { + if (sd_card->sd_clock > 30) sd_card->sd_clock -= 20; - } } else { switch (sd_card->sd_clock) { case CLK_200: @@ -3337,9 +3185,8 @@ static inline int sd_auto_tune_clock(struct rtsx_chip *chip) } retval = sd_switch_clock(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } return STATUS_SUCCESS; } @@ -3377,11 +3224,10 @@ int sd_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip, u32 start_sector, u16 s } } - if (!CHK_SD_HCXC(sd_card) && !CHK_MMC_SECTOR_MODE(sd_card)) { + if (!CHK_SD_HCXC(sd_card) && !CHK_MMC_SECTOR_MODE(sd_card)) data_addr = start_sector << 9; - } else { + else data_addr = start_sector; - } sd_clr_err_code(chip); @@ -3436,21 +3282,19 @@ int sd_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip, u32 start_sector, u16 s rtsx_add_cmd(chip, WRITE_REG_CMD, CARD_DATA_SOURCE, 0x01, RING_BUFFER); - if (CHK_MMC_8BIT(sd_card)) { + if (CHK_MMC_8BIT(sd_card)) rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG1, 0x03, SD_BUS_WIDTH_8); - } else if (CHK_MMC_4BIT(sd_card) || CHK_SD(sd_card)) { + else if (CHK_MMC_4BIT(sd_card) || CHK_SD(sd_card)) rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG1, 0x03, SD_BUS_WIDTH_4); - } else { + else rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG1, 0x03, SD_BUS_WIDTH_1); - } if (sd_card->seq_mode) { cfg2 = SD_NO_CALCULATE_CRC7 | SD_CHECK_CRC16 | SD_NO_WAIT_BUSY_END | SD_NO_CHECK_CRC7 | SD_RSP_LEN_0; if (CHECK_PID(chip, 0x5209)) { - if (!CHK_SD30_SPEED(sd_card)) { + if (!CHK_SD30_SPEED(sd_card)) cfg2 |= SD_NO_CHECK_WAIT_CRC_TO; - } } rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG2, 0xFF, cfg2); @@ -3480,9 +3324,8 @@ int sd_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip, u32 start_sector, u16 s cfg2 = SD_CALCULATE_CRC7 | SD_CHECK_CRC16 | SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6; if (CHECK_PID(chip, 0x5209)) { - if (!CHK_SD30_SPEED(sd_card)) { + if (!CHK_SD30_SPEED(sd_card)) cfg2 |= SD_NO_CHECK_WAIT_CRC_TO; - } } rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG2, 0xFF, cfg2); @@ -3523,9 +3366,8 @@ int sd_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip, u32 start_sector, u16 s cfg2 = SD_NO_CALCULATE_CRC7 | SD_CHECK_CRC16 | SD_NO_WAIT_BUSY_END | SD_NO_CHECK_CRC7 | SD_RSP_LEN_0; if (CHECK_PID(chip, 0x5209)) { - if (!CHK_SD30_SPEED(sd_card)) { + if (!CHK_SD30_SPEED(sd_card)) cfg2 |= SD_NO_CHECK_WAIT_CRC_TO; - } } rtsx_add_cmd(chip, WRITE_REG_CMD, REG_SD_CFG2, 0xFF, cfg2); @@ -3550,11 +3392,10 @@ int sd_rw(struct scsi_cmnd *srb, struct rtsx_chip *chip, u32 start_sector, u16 s sd_card->seq_mode = 0; - if (retval == -ETIMEDOUT) { + if (retval == -ETIMEDOUT) err = STATUS_TIMEDOUT; - } else { + else err = STATUS_FAIL; - } rtsx_read_register(chip, REG_SD_STAT1, &stat); rtsx_clear_sd_error(chip); @@ -3640,9 +3481,8 @@ int ext_sd_send_cmd_get_rsp(struct rtsx_chip *chip, u8 cmd_idx, RTSX_DEBUGP("EXT SD/MMC CMD %d\n", cmd_idx); - if (rsp_type == SD_RSP_TYPE_R1b) { + if (rsp_type == SD_RSP_TYPE_R1b) timeout = 3000; - } RTY_SEND_CMD: @@ -3662,14 +3502,14 @@ RTY_SEND_CMD: rtsx_add_cmd(chip, CHECK_REG_CMD, REG_SD_TRANSFER, SD_TRANSFER_END, SD_TRANSFER_END); if (rsp_type == SD_RSP_TYPE_R2) { - for (reg_addr = PPBUF_BASE2; reg_addr < PPBUF_BASE2 + 16; reg_addr++) { + for (reg_addr = PPBUF_BASE2; reg_addr < PPBUF_BASE2 + 16; reg_addr++) rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0); - } + stat_idx = 17; } else if (rsp_type != SD_RSP_TYPE_R0) { - for (reg_addr = REG_SD_CMD0; reg_addr <= REG_SD_CMD4; reg_addr++) { + for (reg_addr = REG_SD_CMD0; reg_addr <= REG_SD_CMD4; reg_addr++) rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0, 0); - } + stat_idx = 6; } rtsx_add_cmd(chip, READ_REG_CMD, REG_SD_CMD5, 0, 0); @@ -3683,9 +3523,8 @@ RTY_SEND_CMD: if (rsp_type & SD_WAIT_BUSY_END) { retval = sd_check_data0_status(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, retval); - } } else { sd_set_err_code(chip, SD_TO_ERR); } @@ -3693,9 +3532,8 @@ RTY_SEND_CMD: TRACE_RET(chip, STATUS_FAIL); } - if (rsp_type == SD_RSP_TYPE_R0) { + if (rsp_type == SD_RSP_TYPE_R0) return STATUS_SUCCESS; - } ptr = rtsx_get_cmd_data(chip) + 1; @@ -3724,9 +3562,8 @@ RTY_SEND_CMD: if ((cmd_idx == SELECT_CARD) || (cmd_idx == APP_CMD) || (cmd_idx == SEND_STATUS) || (cmd_idx == STOP_TRANSMISSION)) { if ((cmd_idx != STOP_TRANSMISSION) && (special_check == 0)) { - if (ptr[1] & 0x80) { + if (ptr[1] & 0x80) TRACE_RET(chip, STATUS_FAIL); - } } #ifdef SUPPORT_SD_LOCK if (ptr[1] & 0x7D) @@ -3736,26 +3573,23 @@ RTY_SEND_CMD: { TRACE_RET(chip, STATUS_FAIL); } - if (ptr[2] & 0xF8) { + if (ptr[2] & 0xF8) TRACE_RET(chip, STATUS_FAIL); - } if (cmd_idx == SELECT_CARD) { if (rsp_type == SD_RSP_TYPE_R2) { - if ((ptr[3] & 0x1E) != 0x04) { + if ((ptr[3] & 0x1E) != 0x04) TRACE_RET(chip, STATUS_FAIL); - } + } else if (rsp_type == SD_RSP_TYPE_R0) { - if ((ptr[3] & 0x1E) != 0x03) { + if ((ptr[3] & 0x1E) != 0x03) TRACE_RET(chip, STATUS_FAIL); - } } } } - if (rsp && rsp_len) { + if (rsp && rsp_len) memcpy(rsp, ptr, rsp_len); - } return STATUS_SUCCESS; } @@ -3765,29 +3599,27 @@ int ext_sd_get_rsp(struct rtsx_chip *chip, int len, u8 *rsp, u8 rsp_type) int retval, rsp_len; u16 reg_addr; - if (rsp_type == SD_RSP_TYPE_R0) { + if (rsp_type == SD_RSP_TYPE_R0) return STATUS_SUCCESS; - } rtsx_init_cmd(chip); if (rsp_type == SD_RSP_TYPE_R2) { - for (reg_addr = PPBUF_BASE2; reg_addr < PPBUF_BASE2 + 16; reg_addr++) { + for (reg_addr = PPBUF_BASE2; reg_addr < PPBUF_BASE2 + 16; reg_addr++) rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0xFF, 0); - } + rsp_len = 17; } else if (rsp_type != SD_RSP_TYPE_R0) { - for (reg_addr = REG_SD_CMD0; reg_addr <= REG_SD_CMD4; reg_addr++) { + for (reg_addr = REG_SD_CMD0; reg_addr <= REG_SD_CMD4; reg_addr++) rtsx_add_cmd(chip, READ_REG_CMD, reg_addr, 0xFF, 0); - } + rsp_len = 6; } rtsx_add_cmd(chip, READ_REG_CMD, REG_SD_CMD5, 0xFF, 0); retval = rtsx_send_cmd(chip, SD_CARD, 100); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (rsp) { int min_len = (rsp_len < len) ? rsp_len : len; @@ -3858,9 +3690,8 @@ int sd_pass_thru_mode(struct scsi_cmnd *srb, struct rtsx_chip *chip) } buf[5] = (1 == CHK_SD(sd_card)) ? 0x01 : 0x02; - if (chip->card_wp & SD_CARD) { + if (chip->card_wp & SD_CARD) buf[5] |= 0x80; - } buf[6] = (u8)(sd_card->sd_addr >> 16); buf[7] = (u8)(sd_card->sd_addr >> 24); @@ -3875,9 +3706,8 @@ int sd_pass_thru_mode(struct scsi_cmnd *srb, struct rtsx_chip *chip) static inline int get_rsp_type(struct scsi_cmnd *srb, u8 *rsp_type, int *rsp_len) { - if (!rsp_type || !rsp_len) { + if (!rsp_type || !rsp_len) return STATUS_FAIL; - } switch (srb->cmnd[10]) { case 0x03: @@ -3927,9 +3757,8 @@ int sd_execute_no_data(struct scsi_cmnd *srb, struct rtsx_chip *chip) } retval = sd_switch_clock(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } if (sd_card->pre_cmd_err) { sd_card->pre_cmd_err = 0; @@ -3938,12 +3767,11 @@ int sd_execute_no_data(struct scsi_cmnd *srb, struct rtsx_chip *chip) } cmd_idx = srb->cmnd[2] & 0x3F; - if (srb->cmnd[1] & 0x02) { + if (srb->cmnd[1] & 0x02) standby = 1; - } - if (srb->cmnd[1] & 0x01) { + + if (srb->cmnd[1] & 0x01) acmd = 1; - } arg = ((u32)srb->cmnd[3] << 24) | ((u32)srb->cmnd[4] << 16) | ((u32)srb->cmnd[5] << 8) | srb->cmnd[6]; @@ -3956,64 +3784,56 @@ int sd_execute_no_data(struct scsi_cmnd *srb, struct rtsx_chip *chip) sd_card->last_rsp_type = rsp_type; retval = sd_switch_clock(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } #ifdef SUPPORT_SD_LOCK if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) { if (CHK_MMC_8BIT(sd_card)) { retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03, SD_BUS_WIDTH_8); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } + } else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) { retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03, SD_BUS_WIDTH_4); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } } } #else retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03, SD_BUS_WIDTH_4); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } #endif if (standby) { retval = sd_select_card(chip, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Cmd_Failed); - } } if (acmd) { retval = ext_sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Cmd_Failed); - } } retval = ext_sd_send_cmd_get_rsp(chip, cmd_idx, arg, rsp_type, sd_card->rsp, rsp_len, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Cmd_Failed); - } if (standby) { retval = sd_select_card(chip, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Cmd_Failed); - } } #ifdef SUPPORT_SD_LOCK retval = sd_update_lock_status(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Cmd_Failed); - } #endif scsi_set_resid(srb, 0); @@ -4024,9 +3844,8 @@ SD_Execute_Cmd_Failed: set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE); release_sd_card(chip); do_reset_sd_card(chip); - if (!(chip->card_ready & SD_CARD)) { + if (!(chip->card_ready & SD_CARD)) set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - } TRACE_RET(chip, TRANSPORT_FAILED); } @@ -4053,20 +3872,18 @@ int sd_execute_read_data(struct scsi_cmnd *srb, struct rtsx_chip *chip) } retval = sd_switch_clock(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } cmd_idx = srb->cmnd[2] & 0x3F; - if (srb->cmnd[1] & 0x04) { + if (srb->cmnd[1] & 0x04) send_cmd12 = 1; - } - if (srb->cmnd[1] & 0x02) { + + if (srb->cmnd[1] & 0x02) standby = 1; - } - if (srb->cmnd[1] & 0x01) { + + if (srb->cmnd[1] & 0x01) acmd = 1; - } data_len = ((u32)srb->cmnd[7] << 16) | ((u32)srb->cmnd[8] << 8) | srb->cmnd[9]; @@ -4078,19 +3895,17 @@ int sd_execute_read_data(struct scsi_cmnd *srb, struct rtsx_chip *chip) sd_card->last_rsp_type = rsp_type; retval = sd_switch_clock(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } #ifdef SUPPORT_SD_LOCK if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) { - if (CHK_MMC_8BIT(sd_card)) { + if (CHK_MMC_8BIT(sd_card)) bus_width = SD_BUS_WIDTH_8; - } else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) { + else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) bus_width = SD_BUS_WIDTH_4; - } else { + else bus_width = SD_BUS_WIDTH_1; - } } else { bus_width = SD_BUS_WIDTH_4; } @@ -4102,24 +3917,21 @@ int sd_execute_read_data(struct scsi_cmnd *srb, struct rtsx_chip *chip) if (data_len < 512) { retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, data_len, SD_RSP_TYPE_R1, NULL, 0, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); - } } if (standby) { retval = sd_select_card(chip, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); - } } if (acmd) { retval = ext_sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); - } } if (data_len <= 512) { @@ -4138,9 +3950,8 @@ int sd_execute_read_data(struct scsi_cmnd *srb, struct rtsx_chip *chip) cmd[4] = srb->cmnd[6]; buf = kmalloc(data_len, GFP_KERNEL); - if (buf == NULL) { + if (buf == NULL) TRACE_RET(chip, TRANSPORT_ERROR); - } retval = sd_read_data(chip, SD_TM_NORMAL_READ, cmd, 5, byte_cnt, blk_cnt, bus_width, buf, data_len, 2000); @@ -4195,56 +4006,48 @@ int sd_execute_read_data(struct scsi_cmnd *srb, struct rtsx_chip *chip) } retval = ext_sd_get_rsp(chip, rsp_len, sd_card->rsp, rsp_type); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); - } if (standby) { retval = sd_select_card(chip, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); - } } if (send_cmd12) { retval = ext_sd_send_cmd_get_rsp(chip, STOP_TRANSMISSION, 0, SD_RSP_TYPE_R1b, NULL, 0, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); - } } if (data_len < 512) { retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, 0x200, SD_RSP_TYPE_R1, NULL, 0, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); - } retval = rtsx_write_register(chip, SD_BYTE_CNT_H, 0xFF, 0x02); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); - } + retval = rtsx_write_register(chip, SD_BYTE_CNT_L, 0xFF, 0x00); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); - } } - if ((srb->cmnd[1] & 0x02) || (srb->cmnd[1] & 0x04)) { + if ((srb->cmnd[1] & 0x02) || (srb->cmnd[1] & 0x04)) cmd13_checkbit = 1; - } for (i = 0; i < 3; i++) { retval = ext_sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0, cmd13_checkbit); - if (retval == STATUS_SUCCESS) { + if (retval == STATUS_SUCCESS) break; - } } - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Read_Cmd_Failed); - } scsi_set_resid(srb, 0); return TRANSPORT_GOOD; @@ -4252,14 +4055,13 @@ int sd_execute_read_data(struct scsi_cmnd *srb, struct rtsx_chip *chip) SD_Execute_Read_Cmd_Failed: sd_card->pre_cmd_err = 1; set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE); - if (read_err) { + if (read_err) set_sense_type(chip, lun, SENSE_TYPE_MEDIA_UNRECOVER_READ_ERR); - } + release_sd_card(chip); do_reset_sd_card(chip); - if (!(chip->card_ready & SD_CARD)) { + if (!(chip->card_ready & SD_CARD)) set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - } TRACE_RET(chip, TRANSPORT_FAILED); } @@ -4291,20 +4093,18 @@ int sd_execute_write_data(struct scsi_cmnd *srb, struct rtsx_chip *chip) } retval = sd_switch_clock(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } cmd_idx = srb->cmnd[2] & 0x3F; - if (srb->cmnd[1] & 0x04) { + if (srb->cmnd[1] & 0x04) send_cmd12 = 1; - } - if (srb->cmnd[1] & 0x02) { + + if (srb->cmnd[1] & 0x02) standby = 1; - } - if (srb->cmnd[1] & 0x01) { + + if (srb->cmnd[1] & 0x01) acmd = 1; - } data_len = ((u32)srb->cmnd[7] << 16) | ((u32)srb->cmnd[8] << 8) | srb->cmnd[9]; arg = ((u32)srb->cmnd[3] << 24) | ((u32)srb->cmnd[4] << 16) | @@ -4325,75 +4125,66 @@ int sd_execute_write_data(struct scsi_cmnd *srb, struct rtsx_chip *chip) sd_card->last_rsp_type = rsp_type; retval = sd_switch_clock(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } #ifdef SUPPORT_SD_LOCK if ((sd_card->sd_lock_status & SD_LOCK_1BIT_MODE) == 0) { if (CHK_MMC_8BIT(sd_card)) { retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03, SD_BUS_WIDTH_8); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } + } else if (CHK_SD(sd_card) || CHK_MMC_4BIT(sd_card)) { retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03, SD_BUS_WIDTH_4); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } } } #else retval = rtsx_write_register(chip, REG_SD_CFG1, 0x03, SD_BUS_WIDTH_4); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, TRANSPORT_FAILED); - } #endif if (data_len < 512) { retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, data_len, SD_RSP_TYPE_R1, NULL, 0, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); - } } if (standby) { retval = sd_select_card(chip, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); - } } if (acmd) { retval = ext_sd_send_cmd_get_rsp(chip, APP_CMD, sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); - } } retval = ext_sd_send_cmd_get_rsp(chip, cmd_idx, arg, rsp_type, sd_card->rsp, rsp_len, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); - } if (data_len <= 512) { u16 i; u8 *buf; buf = kmalloc(data_len, GFP_KERNEL); - if (buf == NULL) { + if (buf == NULL) TRACE_RET(chip, TRANSPORT_ERROR); - } rtsx_stor_get_xfer_buf(buf, data_len, srb); #ifdef SUPPORT_SD_LOCK - if (cmd_idx == LOCK_UNLOCK) { + if (cmd_idx == LOCK_UNLOCK) lock_cmd_type = buf[0] & 0x0F; - } #endif if (data_len > 256) { @@ -4485,11 +4276,11 @@ int sd_execute_write_data(struct scsi_cmnd *srb, struct rtsx_chip *chip) } rtsx_init_cmd(chip); - if (CHECK_PID(chip, 0x5209)) { + if (CHECK_PID(chip, 0x5209)) rtsx_add_cmd(chip, CHECK_REG_CMD, SD_BUS_STAT, SD_DAT0_STATUS, SD_DAT0_STATUS); - } else { + else rtsx_add_cmd(chip, CHECK_REG_CMD, 0xFD30, 0x02, 0x02); - } + rtsx_send_cmd(chip, SD_CARD, 250); retval = sd_update_lock_status(chip); @@ -4502,61 +4293,53 @@ int sd_execute_write_data(struct scsi_cmnd *srb, struct rtsx_chip *chip) if (standby) { retval = sd_select_card(chip, 1); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); - } } if (send_cmd12) { retval = ext_sd_send_cmd_get_rsp(chip, STOP_TRANSMISSION, 0, SD_RSP_TYPE_R1b, NULL, 0, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); - } } if (data_len < 512) { retval = ext_sd_send_cmd_get_rsp(chip, SET_BLOCKLEN, 0x200, SD_RSP_TYPE_R1, NULL, 0, 0); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); - } retval = rtsx_write_register(chip, SD_BYTE_CNT_H, 0xFF, 0x02); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); - } + rtsx_write_register(chip, SD_BYTE_CNT_L, 0xFF, 0x00); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); - } } - if ((srb->cmnd[1] & 0x02) || (srb->cmnd[1] & 0x04)) { + if ((srb->cmnd[1] & 0x02) || (srb->cmnd[1] & 0x04)) cmd13_checkbit = 1; - } for (i = 0; i < 3; i++) { retval = ext_sd_send_cmd_get_rsp(chip, SEND_STATUS, sd_card->sd_addr, SD_RSP_TYPE_R1, NULL, 0, cmd13_checkbit); - if (retval == STATUS_SUCCESS) { + if (retval == STATUS_SUCCESS) break; - } } - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_GOTO(chip, SD_Execute_Write_Cmd_Failed); - } #ifdef SUPPORT_SD_LOCK if (cmd_idx == LOCK_UNLOCK) { if (!lock_cmd_fail) { RTSX_DEBUGP("lock_cmd_type = 0x%x\n", lock_cmd_type); - if (lock_cmd_type & SD_CLR_PWD) { + if (lock_cmd_type & SD_CLR_PWD) sd_card->sd_lock_status &= ~SD_PWD_EXIST; - } - if (lock_cmd_type & SD_SET_PWD) { + + if (lock_cmd_type & SD_SET_PWD) sd_card->sd_lock_status |= SD_PWD_EXIST; - } } RTSX_DEBUGP("sd_lock_state = 0x%x, sd_card->sd_lock_status = 0x%x\n", @@ -4593,14 +4376,13 @@ int sd_execute_write_data(struct scsi_cmnd *srb, struct rtsx_chip *chip) SD_Execute_Write_Cmd_Failed: sd_card->pre_cmd_err = 1; set_sense_type(chip, lun, SENSE_TYPE_NO_SENSE); - if (write_err) { + if (write_err) set_sense_type(chip, lun, SENSE_TYPE_MEDIA_WRITE_ERR); - } + release_sd_card(chip); do_reset_sd_card(chip); - if (!(chip->card_ready & SD_CARD)) { + if (!(chip->card_ready & SD_CARD)) set_sense_type(chip, lun, SENSE_TYPE_MEDIA_NOT_PRESENT); - } TRACE_RET(chip, TRANSPORT_FAILED); } @@ -4670,9 +4452,8 @@ int sd_hw_rst(struct scsi_cmnd *srb, struct rtsx_chip *chip) switch (srb->cmnd[1] & 0x0F) { case 0: #ifdef SUPPORT_SD_LOCK - if (0x64 == srb->cmnd[9]) { + if (0x64 == srb->cmnd[9]) sd_card->sd_lock_status |= SD_SDR_RST; - } #endif retval = reset_sd_card(chip); if (retval != STATUS_SUCCESS) { @@ -4723,26 +4504,23 @@ int sd_power_off_card3v3(struct rtsx_chip *chip) int retval; retval = disable_card_clock(chip, SD_CARD); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } RTSX_WRITE_REG(chip, CARD_OE, SD_OUTPUT_EN, 0); if (!chip->ft2_fast_mode) { retval = card_power_off(chip, SD_CARD); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } wait_timeout(50); } if (chip->asic_code) { retval = sd_pull_ctl_disable(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } } else { RTSX_WRITE_REG(chip, FPGA_PULL_CTL, FPGA_SD_PULL_CTL_BIT | 0x20, FPGA_SD_PULL_CTL_BIT); @@ -4774,19 +4552,16 @@ int release_sd_card(struct rtsx_chip *chip) memset(sd_card->raw_scr, 0, 8); retval = sd_power_off_card3v3(chip); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } if (CHECK_PID(chip, 0x5209)) { retval = sd_change_bank_voltage(chip, SD_IO_3V3); - if (retval != STATUS_SUCCESS) { + if (retval != STATUS_SUCCESS) TRACE_RET(chip, STATUS_FAIL); - } - if (CHK_SD30_SPEED(sd_card)) { + if (CHK_SD30_SPEED(sd_card)) RTSX_WRITE_REG(chip, SD30_DRIVE_SEL, 0x07, chip->sd30_drive_sel_3v3); - } RTSX_WRITE_REG(chip, OCPPARA2, SD_OCP_THD_MASK, chip->sd_400mA_ocp_thd); } diff --git a/drivers/staging/rts_pstor/trace.h b/drivers/staging/rts_pstor/trace.h index bc83b49a4eb4..cf60a1b872b3 100644 --- a/drivers/staging/rts_pstor/trace.h +++ b/drivers/staging/rts_pstor/trace.h @@ -83,33 +83,9 @@ do { \ #endif #ifdef CONFIG_RTS_PSTOR_DEBUG -static inline void rtsx_dump(u8 *buf, int buf_len) -{ - int i; - u8 tmp[16] = {0}; - u8 *_ptr = buf; - - for (i = 0; i < ((buf_len)/16); i++) { - RTSX_DEBUGP("%02x %02x %02x %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x %02x %02x %02x\n", - _ptr[0], _ptr[1], _ptr[2], _ptr[3], _ptr[4], _ptr[5], - _ptr[6], _ptr[7], _ptr[8], _ptr[9], _ptr[10], _ptr[11], - _ptr[12], _ptr[13], _ptr[14], _ptr[15]); - _ptr += 16; - } - if ((buf_len) % 16) { - memcpy(tmp, _ptr, (buf_len) % 16); - _ptr = tmp; - RTSX_DEBUGP("%02x %02x %02x %02x %02x %02x %02x %02x " - "%02x %02x %02x %02x %02x %02x %02x %02x\n", - _ptr[0], _ptr[1], _ptr[2], _ptr[3], _ptr[4], _ptr[5], - _ptr[6], _ptr[7], _ptr[8], _ptr[9], _ptr[10], _ptr[11], - _ptr[12], _ptr[13], _ptr[14], _ptr[15]); - } -} - -#define RTSX_DUMP(buf, buf_len) rtsx_dump((u8 *)(buf), (buf_len)) - +#define RTSX_DUMP(buf, buf_len) \ + print_hex_dump(KERN_DEBUG, RTSX_STOR, DUMP_PREFIX_NONE, \ + 16, 1, (buf), (buf_len), false) #else #define RTSX_DUMP(buf, buf_len) #endif diff --git a/drivers/staging/sbe-2t3e3/2t3e3.h b/drivers/staging/sbe-2t3e3/2t3e3.h index 383f2cfc1ad2..ccad049c1122 100644 --- a/drivers/staging/sbe-2t3e3/2t3e3.h +++ b/drivers/staging/sbe-2t3e3/2t3e3.h @@ -789,7 +789,6 @@ void dc_restart(struct channel *); void dc_receiver_onoff(struct channel *, u32); void dc_transmitter_onoff(struct channel *, u32); void dc_set_loopback(struct channel *, u32); -u32 dc_init_descriptor_list(struct channel *); void dc_clear_descriptor_list(struct channel *); void dc_drop_descriptor_list(struct channel *); void dc_set_output_port(struct channel *); diff --git a/drivers/staging/sbe-2t3e3/dc.c b/drivers/staging/sbe-2t3e3/dc.c index 9e81d9036a33..daadd6ea4978 100644 --- a/drivers/staging/sbe-2t3e3/dc.c +++ b/drivers/staging/sbe-2t3e3/dc.c @@ -17,6 +17,8 @@ #include "2t3e3.h" #include "ctrl.h" +static int dc_init_descriptor_list(struct channel *sc); + void dc_init(struct channel *sc) { u32 val; @@ -307,7 +309,7 @@ void dc_set_loopback(struct channel *sc, u32 mode) SBE_2T3E3_21143_VAL_FULL_DUPLEX_MODE); } -u32 dc_init_descriptor_list(struct channel *sc) +static int dc_init_descriptor_list(struct channel *sc) { u32 i, j; struct sk_buff *m; @@ -317,7 +319,7 @@ u32 dc_init_descriptor_list(struct channel *sc) sizeof(t3e3_rx_desc_t), GFP_KERNEL); if (sc->ether.rx_ring == NULL) { dev_err(&sc->pdev->dev, "SBE 2T3E3: no buffer space for RX ring\n"); - return ENOMEM; + return -ENOMEM; } if (sc->ether.tx_ring == NULL) @@ -327,7 +329,7 @@ u32 dc_init_descriptor_list(struct channel *sc) kfree(sc->ether.rx_ring); sc->ether.rx_ring = NULL; dev_err(&sc->pdev->dev, "SBE 2T3E3: no buffer space for RX ring\n"); - return ENOMEM; + return -ENOMEM; } @@ -351,7 +353,7 @@ u32 dc_init_descriptor_list(struct channel *sc) sc->ether.tx_ring = NULL; dev_err(&sc->pdev->dev, "SBE 2T3E3: token_alloc err:" " no buffer space for RX ring\n"); - return ENOBUFS; + return -ENOBUFS; } sc->ether.rx_data[i] = m; } diff --git a/drivers/staging/sbe-2t3e3/module.c b/drivers/staging/sbe-2t3e3/module.c index cd778b3a02b2..8adb17816ad9 100644 --- a/drivers/staging/sbe-2t3e3/module.c +++ b/drivers/staging/sbe-2t3e3/module.c @@ -67,6 +67,7 @@ static int __devinit t3e3_init_channel(struct channel *channel, struct pci_dev * dev = alloc_hdlcdev(channel); if (!dev) { printk(KERN_ERR "SBE 2T3E3" ": Out of memory\n"); + err = -ENOMEM; goto free_regions; } @@ -82,8 +83,9 @@ static int __devinit t3e3_init_channel(struct channel *channel, struct pci_dev * else channel->h.slot = 0; - if (setup_device(dev, channel)) - goto free_regions; + err = setup_device(dev, channel); + if (err) + goto free_dev; pci_read_config_dword(channel->pdev, 0x40, &val); /* mask sleep mode */ pci_write_config_dword(channel->pdev, 0x40, val & 0x3FFFFFFF); @@ -92,14 +94,19 @@ static int __devinit t3e3_init_channel(struct channel *channel, struct pci_dev * pci_read_config_dword(channel->pdev, PCI_COMMAND, &channel->h.command); t3e3_init(channel); - if (request_irq(dev->irq, &t3e3_intr, IRQF_SHARED, dev->name, dev)) { + err = request_irq(dev->irq, &t3e3_intr, IRQF_SHARED, dev->name, dev); + if (err) { printk(KERN_WARNING "%s: could not get irq: %d\n", dev->name, dev->irq); - goto free_regions; + goto unregister_dev; } pci_set_drvdata(pdev, channel); return 0; +unregister_dev: + unregister_hdlc_device(dev); +free_dev: + free_netdev(dev); free_regions: pci_release_regions(pdev); disable: diff --git a/drivers/staging/sbe-2t3e3/netdev.c b/drivers/staging/sbe-2t3e3/netdev.c index c7b5e8bb04ff..180c96327b9a 100644 --- a/drivers/staging/sbe-2t3e3/netdev.c +++ b/drivers/staging/sbe-2t3e3/netdev.c @@ -21,13 +21,13 @@ #include <linux/interrupt.h> #include "2t3e3.h" -int t3e3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +static int t3e3_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct channel *sc = dev_to_priv(dev); int cmd_2t3e3, len, rlen; t3e3_param_t param; t3e3_resp_t resp; - void *data = ifr->ifr_data + sizeof(cmd_2t3e3) + sizeof(len); + void __user *data = ifr->ifr_data + sizeof(cmd_2t3e3) + sizeof(len); if (cmd == SIOCWANDEV) return hdlc_ioctl(dev, ifr, cmd); @@ -82,7 +82,7 @@ static struct net_device_stats* t3e3_get_stats(struct net_device *dev) return nstats; } -int t3e3_open(struct net_device *dev) +static int t3e3_open(struct net_device *dev) { struct channel *sc = dev_to_priv(dev); int ret = hdlc_open(dev); @@ -97,7 +97,7 @@ int t3e3_open(struct net_device *dev) return 0; } -int t3e3_close(struct net_device *dev) +static int t3e3_close(struct net_device *dev) { struct channel *sc = dev_to_priv(dev); hdlc_close(dev); diff --git a/drivers/staging/sep/sep_main.c b/drivers/staging/sep/sep_main.c index ca8946acba60..a414e52dd082 100644 --- a/drivers/staging/sep/sep_main.c +++ b/drivers/staging/sep/sep_main.c @@ -719,7 +719,7 @@ static int sep_mmap(struct file *filp, struct vm_area_struct *vma) if (remap_pfn_range(vma, vma->vm_start, bus_addr >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot)) { - dev_dbg(&sep->pdev->dev, "[PID%d] remap_page_range failed\n", + dev_dbg(&sep->pdev->dev, "[PID%d] remap_pfn_range failed\n", current->pid); error = -EAGAIN; goto end_function_with_error; diff --git a/drivers/staging/serqt_usb2/serqt_usb2.c b/drivers/staging/serqt_usb2/serqt_usb2.c index 8a362f7af379..c56609c6094b 100644 --- a/drivers/staging/serqt_usb2/serqt_usb2.c +++ b/drivers/staging/serqt_usb2/serqt_usb2.c @@ -247,7 +247,6 @@ static void ProcessLineStatus(struct quatech_port *qt_port, qt_port->shadowLSR = line_status & (SERIAL_LSR_OE | SERIAL_LSR_PE | SERIAL_LSR_FE | SERIAL_LSR_BI); - return; } static void ProcessModemStatus(struct quatech_port *qt_port, @@ -256,7 +255,6 @@ static void ProcessModemStatus(struct quatech_port *qt_port, qt_port->shadowMSR = modem_status; wake_up_interruptible(&qt_port->wait); - return; } static void ProcessRxChar(struct tty_struct *tty, struct usb_serial_port *port, @@ -706,7 +704,7 @@ static int qt_startup(struct usb_serial *serial) port = serial->port[i]; qt_port = kzalloc(sizeof(*qt_port), GFP_KERNEL); if (!qt_port) { - dbg("%s: kmalloc for quatech_port (%d) failed!.", + dbg("%s: kzalloc for quatech_port (%d) failed!.", __func__, i); for (--i; i >= 0; i--) { port = serial->port[i]; @@ -1412,7 +1410,7 @@ static int qt_tiocmget(struct tty_struct *tty) struct usb_serial_port *port = tty->driver_data; struct usb_serial *serial = get_usb_serial(port, __func__); struct quatech_port *qt_port = qt_get_port_private(port); - int retval = -ENODEV; + int retval; if (!serial) return -ENODEV; @@ -1430,7 +1428,7 @@ static int qt_tiocmset(struct tty_struct *tty, struct usb_serial_port *port = tty->driver_data; struct usb_serial *serial = get_usb_serial(port, __func__); struct quatech_port *qt_port = qt_get_port_private(port); - int retval = -ENODEV; + int retval; if (!serial) return -ENODEV; @@ -1458,7 +1456,6 @@ static void qt_throttle(struct tty_struct *tty) qt_port->RxHolding = 1; mutex_unlock(&qt_port->lock); - return; } static void qt_unthrottle(struct tty_struct *tty) @@ -1499,8 +1496,6 @@ static void qt_unthrottle(struct tty_struct *tty) } } mutex_unlock(&qt_port->lock); - return; - } static int qt_calc_num_ports(struct usb_serial *serial) diff --git a/drivers/staging/silicom/Kconfig b/drivers/staging/silicom/Kconfig new file mode 100644 index 000000000000..eda2e7d73645 --- /dev/null +++ b/drivers/staging/silicom/Kconfig @@ -0,0 +1,46 @@ +# +# Silicom device configuration +# + +config NET_VENDOR_SILICOM + bool "Silicom devices" + default y + depends on PCI + ---help--- + If you have a network card (Ethernet) belonging to this class, + say Y. + + Note that the answer to this question does not directly affect + the kernel: saying N will just case the configurator to skip all + the questions regarding Silicom chipsets. If you say Y, you will be asked + for your specific chipset/driver in the following questions. + +if NET_VENDOR_SILICOM + +config SBYPASS + tristate "Silicom BypassCTL library support" + depends on PCI && NET + depends on m + ---help--- + If you have a network (Ethernet) controller of this type, say Y + + To compile this driver as a module, choose M here. The module + will be called bypass. + +config BPCTL + tristate "Silicom BypassCTL net support" + depends on PCI && NET + depends on m + select SBYPASS + select NET_CORE + select MII + ---help--- + If you have a network (Ethernet) controller of this type, say Y + or M and read the Ethernet-HOWTO, available from + <http://www.tldp.org/docs.html#howto>. + + To compile this driver as a module, choose M here. The module + will be called bpctl_mod. + + +endif # NET_VENDOR_SILICOM diff --git a/drivers/staging/silicom/Makefile b/drivers/staging/silicom/Makefile new file mode 100644 index 000000000000..80e6d12d156b --- /dev/null +++ b/drivers/staging/silicom/Makefile @@ -0,0 +1,9 @@ +# +# Makefile for the Bypass network device drivers. +# + +obj-$(CONFIG_BPCTL) += bpctl_mod.o +obj-$(CONFIG_SBYPASS) += bypasslib/ + + +bpctl_mod-objs := bp_mod.o bp_proc.o diff --git a/drivers/staging/silicom/README b/drivers/staging/silicom/README new file mode 100644 index 000000000000..ae970b37fdc6 --- /dev/null +++ b/drivers/staging/silicom/README @@ -0,0 +1,14 @@ + +Theory of Operation: + +The Silicom Bypass Network Interface Cards (NICs) are network cards with paired ports (2 or 4). +The pairs either act as a "wire" allowing the network packets to pass or insert the device in +between the two ports. When paired with the on-board hardware watchdog or other failsafe, +they provide high availability for the network in the face of software outages or maintenance. + +The software requirements are for a kernel level driver that interfaces with the bypass and watchdog, +as well as for control software. User control can be either the provided standalone executable +(/bin/bpctl) or the API exposed by the Silicom library. + + + diff --git a/drivers/staging/silicom/TODO b/drivers/staging/silicom/TODO new file mode 100644 index 000000000000..09d07b0ea9c0 --- /dev/null +++ b/drivers/staging/silicom/TODO @@ -0,0 +1,8 @@ +TODO: + - checkpatch.pl cleanups + - locking audit + - single module with all functionality + - userland + - fix monolithic build. + + diff --git a/drivers/staging/silicom/bits.h b/drivers/staging/silicom/bits.h new file mode 100644 index 000000000000..8c411d0d4ecd --- /dev/null +++ b/drivers/staging/silicom/bits.h @@ -0,0 +1,56 @@ +/******************************************************************************/ +/* */ +/* Broadcom BCM5700 Linux Network Driver, Copyright (c) 2000 - 2004 Broadcom */ +/* Corporation. */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* History: */ +/* 02/25/00 Hav Khauv Initial version. */ +/******************************************************************************/ + +#ifndef BITS_H +#define BITS_H + +/******************************************************************************/ +/* Bit Mask definitions */ +/******************************************************************************/ + +#define BIT_NONE 0x00 +#define BIT_0 0x01 +#define BIT_1 0x02 +#define BIT_2 0x04 +#define BIT_3 0x08 +#define BIT_4 0x10 +#define BIT_5 0x20 +#define BIT_6 0x40 +#define BIT_7 0x80 +#define BIT_8 0x0100 +#define BIT_9 0x0200 +#define BIT_10 0x0400 +#define BIT_11 0x0800 +#define BIT_12 0x1000 +#define BIT_13 0x2000 +#define BIT_14 0x4000 +#define BIT_15 0x8000 +#define BIT_16 0x010000 +#define BIT_17 0x020000 +#define BIT_18 0x040000 +#define BIT_19 0x080000 +#define BIT_20 0x100000 +#define BIT_21 0x200000 +#define BIT_22 0x400000 +#define BIT_23 0x800000 +#define BIT_24 0x01000000 +#define BIT_25 0x02000000 +#define BIT_26 0x04000000 +#define BIT_27 0x08000000 +#define BIT_28 0x10000000 +#define BIT_29 0x20000000 +#define BIT_30 0x40000000 +#define BIT_31 0x80000000 + +#endif /* BITS_H */ diff --git a/drivers/staging/silicom/bp_ioctl.h b/drivers/staging/silicom/bp_ioctl.h new file mode 100644 index 000000000000..57de34a69e8e --- /dev/null +++ b/drivers/staging/silicom/bp_ioctl.h @@ -0,0 +1,140 @@ +/******************************************************************************/ +/* */ +/* Silicom Bypass Control Utility, Copyright (c) 2005-2007 Silicom */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* */ +/******************************************************************************/ + +#ifndef BP_IOCTL_H +#define BP_IOCTL_H + +#define BP_CAP 0x01 /* BIT_0 */ +#define BP_STATUS_CAP 0x02 +#define BP_STATUS_CHANGE_CAP 0x04 +#define SW_CTL_CAP 0x08 +#define BP_DIS_CAP 0x10 +#define BP_DIS_STATUS_CAP 0x20 +#define STD_NIC_CAP 0x40 +#define BP_PWOFF_ON_CAP 0x80 +#define BP_PWOFF_OFF_CAP 0x0100 +#define BP_PWOFF_CTL_CAP 0x0200 +#define BP_PWUP_ON_CAP 0x0400 +#define BP_PWUP_OFF_CAP 0x0800 +#define BP_PWUP_CTL_CAP 0x1000 +#define WD_CTL_CAP 0x2000 +#define WD_STATUS_CAP 0x4000 +#define WD_TIMEOUT_CAP 0x8000 +#define TX_CTL_CAP 0x10000 +#define TX_STATUS_CAP 0x20000 +#define TAP_CAP 0x40000 +#define TAP_STATUS_CAP 0x80000 +#define TAP_STATUS_CHANGE_CAP 0x100000 +#define TAP_DIS_CAP 0x200000 +#define TAP_DIS_STATUS_CAP 0x400000 +#define TAP_PWUP_ON_CAP 0x800000 +#define TAP_PWUP_OFF_CAP 0x1000000 +#define TAP_PWUP_CTL_CAP 0x2000000 +#define NIC_CAP_NEG 0x4000000 +#define TPL_CAP 0x8000000 +#define DISC_CAP 0x10000000 +#define DISC_DIS_CAP 0x20000000 +#define DISC_PWUP_CTL_CAP 0x40000000 + +#define TPL2_CAP_EX 0x01 +#define DISC_PORT_CAP_EX 0x02 + +#define WD_MIN_TIME_MASK(val) (val & 0xf) +#define WD_STEP_COUNT_MASK(val) ((val & 0xf) << 5) +#define WDT_STEP_TIME 0x10 /* BIT_4 */ + +#define WD_MIN_TIME_GET(desc) (desc & 0xf) +#define WD_STEP_COUNT_GET(desc) ((desc>>5) & 0xf) + +typedef enum { + IF_SCAN, + GET_DEV_NUM, + IS_BYPASS, + GET_BYPASS_SLAVE, + GET_BYPASS_CAPS, + GET_WD_SET_CAPS, + SET_BYPASS, + GET_BYPASS, + GET_BYPASS_CHANGE, + SET_BYPASS_WD, + GET_BYPASS_WD, + GET_WD_EXPIRE_TIME, + RESET_BYPASS_WD_TIMER, + SET_DIS_BYPASS, + GET_DIS_BYPASS, + SET_BYPASS_PWOFF, + GET_BYPASS_PWOFF, + SET_BYPASS_PWUP, + GET_BYPASS_PWUP, + SET_STD_NIC, + GET_STD_NIC, + SET_TX, + GET_TX, + SET_TAP, + GET_TAP, + GET_TAP_CHANGE, + SET_DIS_TAP, + GET_DIS_TAP, + SET_TAP_PWUP, + GET_TAP_PWUP, + SET_WD_EXP_MODE, + GET_WD_EXP_MODE, + SET_WD_AUTORESET, + GET_WD_AUTORESET, + SET_TPL, + GET_TPL, + SET_DISC, + GET_DISC, + GET_DISC_CHANGE, + SET_DIS_DISC, + GET_DIS_DISC, + SET_DISC_PWUP, + GET_DISC_PWUP, + GET_BYPASS_INFO = 100, + GET_BP_WAIT_AT_PWUP, + SET_BP_WAIT_AT_PWUP, + GET_BP_HW_RESET, + SET_BP_HW_RESET, + SET_DISC_PORT, + GET_DISC_PORT, + SET_DISC_PORT_PWUP, + GET_DISC_PORT_PWUP, + SET_BP_FORCE_LINK, + GET_BP_FORCE_LINK, +#ifdef BP_SELF_TEST + SET_BP_SELF_TEST = 200, + GET_BP_SELF_TEST, +#endif + +} CMND_TYPE_SD; + +/* +* The major device number. We can't rely on dynamic +* registration any more, because ioctls need to know +* it. +*/ + +#define MAGIC_NUM 'J' + +/* for passing single values */ +struct bpctl_cmd { + int status; + int data[8]; + int in_param[8]; + int out_param[8]; +}; + +#define IOCTL_TX_MSG(cmd) _IOWR(MAGIC_NUM, cmd, struct bpctl_cmd) + +#define DEVICE_NAME "bpctl" + +#endif diff --git a/drivers/staging/silicom/bp_mod.c b/drivers/staging/silicom/bp_mod.c new file mode 100644 index 000000000000..3cfd0516adfa --- /dev/null +++ b/drivers/staging/silicom/bp_mod.c @@ -0,0 +1,8931 @@ +/******************************************************************************/ +/* */ +/* Bypass Control utility, Copyright (c) 2005-20011 Silicom */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved. */ +/* */ +/* */ +/******************************************************************************/ +#include <linux/version.h> + +#include <linux/kernel.h> /* We're doing kernel work */ +#include <linux/module.h> /* Specifically, a module */ +#include <linux/fs.h> +#include <linux/pci.h> +#include <linux/delay.h> +#include <linux/netdevice.h> +#include <linux/rtnetlink.h> +#include <linux/rcupdate.h> +#include <linux/etherdevice.h> + +#include <linux/uaccess.h> /* for get_user and put_user */ +#include <linux/sched.h> +#include <linux/ethtool.h> +#include <linux/proc_fs.h> + +#include "bp_ioctl.h" +#include "bp_mod.h" +#include "bypass.h" +#include "libbp_sd.h" + +#define SUCCESS 0 +#define BP_MOD_VER "9.0.4" +#define BP_MOD_DESCR "Silicom Bypass-SD Control driver" +#define BP_SYNC_FLAG 1 + +static int Device_Open = 0; +static int major_num = 0; + +MODULE_AUTHOR("Anna Lukin, annal@silicom.co.il"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION(BP_MOD_DESCR); +MODULE_VERSION(BP_MOD_VER); +spinlock_t bpvm_lock; + +#define lock_bpctl() \ +if (down_interruptible(&bpctl_sema)) { \ + return -ERESTARTSYS; \ +} \ + +#define unlock_bpctl() \ + up(&bpctl_sema); + +/* Media Types */ +typedef enum { + bp_copper = 0, + bp_fiber, + bp_cx4, + bp_none, +} bp_media_type; + +struct pfs_unit_sd { + struct proc_dir_entry *proc_entry; + char proc_name[32]; +}; + +struct bypass_pfs_sd { + char dir_name[32]; + struct proc_dir_entry *bypass_entry; + struct pfs_unit_sd bypass_info; + struct pfs_unit_sd bypass_slave; + struct pfs_unit_sd bypass_caps; + struct pfs_unit_sd wd_set_caps; + struct pfs_unit_sd bypass; + struct pfs_unit_sd bypass_change; + struct pfs_unit_sd bypass_wd; + struct pfs_unit_sd wd_expire_time; + struct pfs_unit_sd reset_bypass_wd; + struct pfs_unit_sd dis_bypass; + struct pfs_unit_sd bypass_pwup; + struct pfs_unit_sd bypass_pwoff; + struct pfs_unit_sd std_nic; + struct pfs_unit_sd tap; + struct pfs_unit_sd dis_tap; + struct pfs_unit_sd tap_pwup; + struct pfs_unit_sd tap_change; + struct pfs_unit_sd wd_exp_mode; + struct pfs_unit_sd wd_autoreset; + struct pfs_unit_sd tpl; + +}; + +typedef struct _bpctl_dev { + char *name; + char *desc; + struct pci_dev *pdev; /* PCI device */ + struct net_device *ndev; /* net device */ + unsigned long mem_map; + uint8_t bus; + uint8_t slot; + uint8_t func; + u_int32_t device; + u_int32_t vendor; + u_int32_t subvendor; + u_int32_t subdevice; + int ifindex; + uint32_t bp_caps; + uint32_t bp_caps_ex; + uint8_t bp_fw_ver; + int bp_ext_ver; + int wdt_status; + unsigned long bypass_wdt_on_time; + uint32_t bypass_timer_interval; + struct timer_list bp_timer; + uint32_t reset_time; + uint8_t bp_status_un; + atomic_t wdt_busy; + bp_media_type media_type; + int bp_tpl_flag; + struct timer_list bp_tpl_timer; + spinlock_t bypass_wr_lock; + int bp_10g; + int bp_10gb; + int bp_fiber5; + int bp_10g9; + int bp_i80; + int bp_540; + int (*hard_start_xmit_save) (struct sk_buff *skb, + struct net_device *dev); + const struct net_device_ops *old_ops; + struct net_device_ops new_ops; + int bp_self_test_flag; + char *bp_tx_data; + struct bypass_pfs_sd bypass_pfs_set; + +} bpctl_dev_t; + +static bpctl_dev_t *bpctl_dev_arr; + +static struct semaphore bpctl_sema; +static int device_num = 0; + +static int get_dev_idx(int ifindex); +static bpctl_dev_t *get_master_port_fn(bpctl_dev_t *pbpctl_dev); +static int disc_status(bpctl_dev_t *pbpctl_dev); +static int bypass_status(bpctl_dev_t *pbpctl_dev); +static int wdt_timer(bpctl_dev_t *pbpctl_dev, int *time_left); +static bpctl_dev_t *get_status_port_fn(bpctl_dev_t *pbpctl_dev); +static void if_scan_init(void); + +int bypass_proc_create_dev_sd(bpctl_dev_t *pbp_device_block); +int bypass_proc_remove_dev_sd(bpctl_dev_t *pbp_device_block); +int bp_proc_create(void); + +int is_bypass_fn(bpctl_dev_t *pbpctl_dev); +int get_dev_idx_bsf(int bus, int slot, int func); + +static unsigned long str_to_hex(char *p); +static int bp_device_event(struct notifier_block *unused, + unsigned long event, void *ptr) +{ + struct net_device *dev = ptr; + static bpctl_dev_t *pbpctl_dev = NULL, *pbpctl_dev_m = NULL; + int dev_num = 0, ret = 0, ret_d = 0, time_left = 0; + /* printk("BP_PROC_SUPPORT event =%d %s %d\n", event,dev->name, dev->ifindex ); */ + /* return NOTIFY_DONE; */ + if (!dev) + return NOTIFY_DONE; + if (event == NETDEV_REGISTER) { + { + struct ethtool_drvinfo drvinfo; + char cbuf[32]; + char *buf = NULL; + char res[10]; + int i = 0, ifindex, idx_dev = 0; + int bus = 0, slot = 0, func = 0; + ifindex = dev->ifindex; + + memset(res, 0, 10); + memset(&drvinfo, 0, sizeof(struct ethtool_drvinfo)); + + if (dev->ethtool_ops && dev->ethtool_ops->get_drvinfo) { + memset(&drvinfo, 0, sizeof(drvinfo)); + dev->ethtool_ops->get_drvinfo(dev, &drvinfo); + } else + return NOTIFY_DONE; + if (!drvinfo.bus_info) + return NOTIFY_DONE; + if (!strcmp(drvinfo.bus_info, "N/A")) + return NOTIFY_DONE; + memcpy(&cbuf, drvinfo.bus_info, 32); + buf = &cbuf[0]; + + while (*buf++ != ':') ; + for (i = 0; i < 10; i++, buf++) { + if (*buf == ':') + break; + res[i] = *buf; + + } + buf++; + bus = str_to_hex(res); + memset(res, 0, 10); + + for (i = 0; i < 10; i++, buf++) { + if (*buf == '.') + break; + res[i] = *buf; + + } + buf++; + slot = str_to_hex(res); + func = str_to_hex(buf); + idx_dev = get_dev_idx_bsf(bus, slot, func); + + if (idx_dev != -1) { + + bpctl_dev_arr[idx_dev].ifindex = ifindex; + bpctl_dev_arr[idx_dev].ndev = dev; + + bypass_proc_remove_dev_sd(&bpctl_dev_arr + [idx_dev]); + bypass_proc_create_dev_sd(&bpctl_dev_arr + [idx_dev]); + + } + + } + return NOTIFY_DONE; + + } + if (event == NETDEV_UNREGISTER) { + int idx_dev = 0; + for (idx_dev = 0; + ((bpctl_dev_arr[idx_dev].pdev != NULL) + && (idx_dev < device_num)); idx_dev++) { + if (bpctl_dev_arr[idx_dev].ndev == dev) { + bypass_proc_remove_dev_sd(&bpctl_dev_arr + [idx_dev]); + bpctl_dev_arr[idx_dev].ndev = NULL; + + return NOTIFY_DONE; + + } + + } + return NOTIFY_DONE; + } + if (event == NETDEV_CHANGENAME) { + int idx_dev = 0; + for (idx_dev = 0; + ((bpctl_dev_arr[idx_dev].pdev != NULL) + && (idx_dev < device_num)); idx_dev++) { + if (bpctl_dev_arr[idx_dev].ndev == dev) { + bypass_proc_remove_dev_sd(&bpctl_dev_arr + [idx_dev]); + bypass_proc_create_dev_sd(&bpctl_dev_arr + [idx_dev]); + + return NOTIFY_DONE; + + } + + } + return NOTIFY_DONE; + + } + + switch (event) { + + case NETDEV_CHANGE:{ + if (netif_carrier_ok(dev)) + return NOTIFY_DONE; + + if (((dev_num = get_dev_idx(dev->ifindex)) == -1) || + (!(pbpctl_dev = &bpctl_dev_arr[dev_num]))) + return NOTIFY_DONE; + + if ((is_bypass_fn(pbpctl_dev)) == 1) + pbpctl_dev_m = pbpctl_dev; + else + pbpctl_dev_m = get_master_port_fn(pbpctl_dev); + if (!pbpctl_dev_m) + return NOTIFY_DONE; + ret = bypass_status(pbpctl_dev_m); + if (ret == 1) + printk("bpmod: %s is in the Bypass mode now", + dev->name); + ret_d = disc_status(pbpctl_dev_m); + if (ret_d == 1) + printk + ("bpmod: %s is in the Disconnect mode now", + dev->name); + if (ret || ret_d) { + wdt_timer(pbpctl_dev_m, &time_left); + if (time_left == -1) + printk("; WDT has expired"); + printk(".\n"); + + } + return NOTIFY_DONE; + + } + + default: + return NOTIFY_DONE; + + } + return NOTIFY_DONE; + +} + +static struct notifier_block bp_notifier_block = { + .notifier_call = bp_device_event, +}; + +static int device_open(struct inode *inode, struct file *file) +{ +#ifdef DEBUG + printk("device_open(%p)\n", file); +#endif + Device_Open++; +/* +* Initialize the message +*/ + return SUCCESS; +} + +static int device_release(struct inode *inode, struct file *file) +{ +#ifdef DEBUG + printk("device_release(%p,%p)\n", inode, file); +#endif + Device_Open--; + return SUCCESS; +} + +int is_bypass_fn(bpctl_dev_t *pbpctl_dev); +int wdt_time_left(bpctl_dev_t *pbpctl_dev); + +static void write_pulse(bpctl_dev_t *pbpctl_dev, + unsigned int ctrl_ext, + unsigned char value, unsigned char len) +{ + unsigned char ctrl_val = 0; + unsigned int i = len; + unsigned int ctrl = 0; + bpctl_dev_t *pbpctl_dev_c = NULL; + + if (pbpctl_dev->bp_i80) + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + if (pbpctl_dev->bp_540) + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + + if (pbpctl_dev->bp_10g9) { + if (!(pbpctl_dev_c = get_status_port_fn(pbpctl_dev))) + return; + ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP); + } + + while (i--) { + ctrl_val = (value >> i) & 0x1; + if (ctrl_val) { + if (pbpctl_dev->bp_10g9) { + + /* To start management : MCLK 1, MDIO 1, output */ + /* DATA 1 CLK 1 */ + /*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext|BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9)); */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + ctrl_ext | + BP10G_MDIO_DATA_OUT9); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + (ctrl | BP10G_MCLK_DATA_OUT9 | + BP10G_MCLK_DIR_OUT9)); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, (ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 + | + BPCTLI_CTRL_EXT_MDIO_DIR5 + | + BPCTLI_CTRL_EXT_MDIO_DATA5 + | + BPCTLI_CTRL_EXT_MCLK_DATA5)); + + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, (ctrl_ext | + BPCTLI_CTRL_EXT_MDIO_DIR80 + | + BPCTLI_CTRL_EXT_MDIO_DATA80)); + + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, (ctrl | + BPCTLI_CTRL_EXT_MCLK_DIR80 + | + BPCTLI_CTRL_EXT_MCLK_DATA80)); + + } else if (pbpctl_dev->bp_540) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, (ctrl | + BP540_MDIO_DIR + | + BP540_MDIO_DATA + | + BP540_MCLK_DIR + | + BP540_MCLK_DATA)); + + } else if (pbpctl_dev->bp_10gb) { + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_SET | + BP10GB_MCLK_SET) & + ~(BP10GB_MCLK_DIR | + BP10GB_MDIO_DIR | + BP10GB_MDIO_CLR | + BP10GB_MCLK_CLR)); + + } else if (!pbpctl_dev->bp_10g) + /* To start management : MCLK 1, MDIO 1, output */ + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + (ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR | + BPCTLI_CTRL_EXT_MDIO_DIR | + BPCTLI_CTRL_EXT_MDIO_DATA | + BPCTLI_CTRL_EXT_MCLK_DATA)); + else { + + /* To start management : MCLK 1, MDIO 1, output*/ + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + (ctrl_ext | BP10G_MCLK_DATA_OUT + | BP10G_MDIO_DATA_OUT)); + + } + + usec_delay(PULSE_TIME); + if (pbpctl_dev->bp_10g9) { + + /*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, ((ctrl_ext|BP10G_MDIO_DATA_OUT9)&~(BP10G_MCLK_DATA_OUT9))); */ + /* DATA 1 CLK 0 */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + ctrl_ext | + BP10G_MDIO_DATA_OUT9); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + (ctrl | BP10G_MCLK_DIR_OUT9) & + ~BP10G_MCLK_DATA_OUT9); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 | + BPCTLI_CTRL_EXT_MDIO_DIR5 | + BPCTLI_CTRL_EXT_MDIO_DATA5) + & + ~ + (BPCTLI_CTRL_EXT_MCLK_DATA5))); + + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, (ctrl_ext | + BPCTLI_CTRL_EXT_MDIO_DIR80 + | + BPCTLI_CTRL_EXT_MDIO_DATA80)); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl | + BPCTLI_CTRL_EXT_MCLK_DIR80) + & + ~ + (BPCTLI_CTRL_EXT_MCLK_DATA80))); + + } else if (pbpctl_dev->bp_540) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, + (ctrl | BP540_MDIO_DIR | + BP540_MDIO_DATA | + BP540_MCLK_DIR) & + ~(BP540_MCLK_DATA)); + + } else if (pbpctl_dev->bp_10gb) { + + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_SET | + BP10GB_MCLK_CLR) & + ~(BP10GB_MCLK_DIR | + BP10GB_MDIO_DIR | + BP10GB_MDIO_CLR | + BP10GB_MCLK_SET)); + + } else if (!pbpctl_dev->bp_10g) + + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR | + BPCTLI_CTRL_EXT_MDIO_DIR | + BPCTLI_CTRL_EXT_MDIO_DATA) + & + ~ + (BPCTLI_CTRL_EXT_MCLK_DATA))); + else { + + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + ((ctrl_ext | + BP10G_MDIO_DATA_OUT) & + ~(BP10G_MCLK_DATA_OUT))); + } + + usec_delay(PULSE_TIME); + + } else { + if (pbpctl_dev->bp_10g9) { + /* DATA 0 CLK 1 */ + /*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, ((ctrl_ext|BP10G_MCLK_DATA_OUT9)&~BP10G_MDIO_DATA_OUT9)); */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + (ctrl_ext & + ~BP10G_MDIO_DATA_OUT9)); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + (ctrl | BP10G_MCLK_DATA_OUT9 | + BP10G_MCLK_DIR_OUT9)); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 | + BPCTLI_CTRL_EXT_MDIO_DIR5 | + BPCTLI_CTRL_EXT_MCLK_DATA5) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA5))); + + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + ((ctrl_ext | + BPCTLI_CTRL_EXT_MDIO_DIR80) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA80))); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + (ctrl | + BPCTLI_CTRL_EXT_MCLK_DIR80 | + BPCTLI_CTRL_EXT_MCLK_DATA80)); + + } else if (pbpctl_dev->bp_540) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, + ((ctrl | BP540_MCLK_DIR | + BP540_MCLK_DATA | + BP540_MDIO_DIR) & + ~(BP540_MDIO_DATA))); + + } else if (pbpctl_dev->bp_10gb) { + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_CLR | + BP10GB_MCLK_SET) & + ~(BP10GB_MCLK_DIR | + BP10GB_MDIO_DIR | + BP10GB_MDIO_SET | + BP10GB_MCLK_CLR)); + + } else if (!pbpctl_dev->bp_10g) + + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR | + BPCTLI_CTRL_EXT_MDIO_DIR | + BPCTLI_CTRL_EXT_MCLK_DATA) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA))); + else { + + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + ((ctrl_ext | + BP10G_MCLK_DATA_OUT) & + ~BP10G_MDIO_DATA_OUT)); + + } + usec_delay(PULSE_TIME); + if (pbpctl_dev->bp_10g9) { + /* DATA 0 CLK 0 */ + /*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + (ctrl_ext & + ~BP10G_MDIO_DATA_OUT9)); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + ((ctrl | BP10G_MCLK_DIR_OUT9) & + ~(BP10G_MCLK_DATA_OUT9))); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 | + BPCTLI_CTRL_EXT_MDIO_DIR5) + & + ~(BPCTLI_CTRL_EXT_MCLK_DATA5 + | + BPCTLI_CTRL_EXT_MDIO_DATA5))); + + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + ((ctrl_ext | + BPCTLI_CTRL_EXT_MDIO_DIR80) + & + ~BPCTLI_CTRL_EXT_MDIO_DATA80)); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl | + BPCTLI_CTRL_EXT_MCLK_DIR80) + & + ~ + (BPCTLI_CTRL_EXT_MCLK_DATA80))); + + } else if (pbpctl_dev->bp_540) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, + ((ctrl | BP540_MCLK_DIR | + BP540_MDIO_DIR) & + ~(BP540_MDIO_DATA | + BP540_MCLK_DATA))); + } else if (pbpctl_dev->bp_10gb) { + + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_CLR | + BP10GB_MCLK_CLR) & + ~(BP10GB_MCLK_DIR | + BP10GB_MDIO_DIR | + BP10GB_MDIO_SET | + BP10GB_MCLK_SET)); + + } else if (!pbpctl_dev->bp_10g) + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR | + BPCTLI_CTRL_EXT_MDIO_DIR) & + ~(BPCTLI_CTRL_EXT_MCLK_DATA + | + BPCTLI_CTRL_EXT_MDIO_DATA))); + else { + + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + (ctrl_ext & + ~(BP10G_MCLK_DATA_OUT | + BP10G_MDIO_DATA_OUT))); + } + + usec_delay(PULSE_TIME); + } + + } +} + +static int read_pulse(bpctl_dev_t *pbpctl_dev, unsigned int ctrl_ext, + unsigned char len) +{ + unsigned char ctrl_val = 0; + unsigned int i = len; + unsigned int ctrl = 0; + bpctl_dev_t *pbpctl_dev_c = NULL; + + if (pbpctl_dev->bp_i80) + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + if (pbpctl_dev->bp_540) + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + if (pbpctl_dev->bp_10g9) { + if (!(pbpctl_dev_c = get_status_port_fn(pbpctl_dev))) + return -1; + ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP); + } + + + while (i--) { + if (pbpctl_dev->bp_10g9) { + /*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, ((ctrl_ext|BP10G_MDIO_DATA_OUT9)&~BP10G_MCLK_DATA_OUT9)); */ + /* DATA ? CLK 0 */ + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + ((ctrl | BP10G_MCLK_DIR_OUT9) & + ~(BP10G_MCLK_DATA_OUT9))); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DIR5 + | + BPCTLI_CTRL_EXT_MCLK_DATA5))); + + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + (ctrl_ext & + ~BPCTLI_CTRL_EXT_MDIO_DIR80)); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) + & ~(BPCTLI_CTRL_EXT_MCLK_DATA80))); + + } else if (pbpctl_dev->bp_540) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, + ((ctrl | BP540_MCLK_DIR) & + ~(BP540_MDIO_DIR | BP540_MCLK_DATA))); + + } else if (pbpctl_dev->bp_10gb) { + + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_DIR | + BP10GB_MCLK_CLR) & ~(BP10GB_MCLK_DIR | + BP10GB_MDIO_CLR | + BP10GB_MDIO_SET | + BP10GB_MCLK_SET)); + + } else if (!pbpctl_dev->bp_10g) + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DIR + | + BPCTLI_CTRL_EXT_MCLK_DATA))); + else { + + BP10G_WRITE_REG(pbpctl_dev, EODSDP, ((ctrl_ext | BP10G_MDIO_DATA_OUT) & ~BP10G_MCLK_DATA_OUT)); /* ? */ + /* printk("0x28=0x%x\n",BP10G_READ_REG(pbpctl_dev,EODSDP);); */ + + } + + usec_delay(PULSE_TIME); + if (pbpctl_dev->bp_10g9) { + /*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext|BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9)); */ + /* DATA ? CLK 1 */ + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + (ctrl | BP10G_MCLK_DATA_OUT9 | + BP10G_MCLK_DIR_OUT9)); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 + | + BPCTLI_CTRL_EXT_MCLK_DATA5) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DIR5))); + + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + (ctrl_ext & + ~(BPCTLI_CTRL_EXT_MDIO_DIR80))); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + (ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80 | + BPCTLI_CTRL_EXT_MCLK_DATA80)); + + } else if (pbpctl_dev->bp_540) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, + ((ctrl | BP540_MCLK_DIR | + BP540_MCLK_DATA) & + ~(BP540_MDIO_DIR))); + + } else if (pbpctl_dev->bp_10gb) { + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_DIR | + BP10GB_MCLK_SET) & ~(BP10GB_MCLK_DIR | + BP10GB_MDIO_CLR | + BP10GB_MDIO_SET | + BP10GB_MCLK_CLR)); + + } else if (!pbpctl_dev->bp_10g) + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR + | + BPCTLI_CTRL_EXT_MCLK_DATA) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DIR))); + else { + + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + (ctrl_ext | BP10G_MCLK_DATA_OUT | + BP10G_MDIO_DATA_OUT)); + + } + if (pbpctl_dev->bp_10g9) { + ctrl_ext = BP10G_READ_REG(pbpctl_dev, I2CCTL); + + } else if ((pbpctl_dev->bp_fiber5) || (pbpctl_dev->bp_i80)) { + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL); + } else if (pbpctl_dev->bp_540) { + ctrl_ext = BP10G_READ_REG(pbpctl_dev, ESDP); + } else if (pbpctl_dev->bp_10gb) + ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO); + + else if (!pbpctl_dev->bp_10g) + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + else + ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP); + + usec_delay(PULSE_TIME); + if (pbpctl_dev->bp_10g9) { + if (ctrl_ext & BP10G_MDIO_DATA_IN9) + ctrl_val |= 1 << i; + + } else if (pbpctl_dev->bp_fiber5) { + if (ctrl_ext & BPCTLI_CTRL_EXT_MDIO_DATA5) + ctrl_val |= 1 << i; + } else if (pbpctl_dev->bp_i80) { + if (ctrl_ext & BPCTLI_CTRL_EXT_MDIO_DATA80) + ctrl_val |= 1 << i; + } else if (pbpctl_dev->bp_540) { + if (ctrl_ext & BP540_MDIO_DATA) + ctrl_val |= 1 << i; + } else if (pbpctl_dev->bp_10gb) { + if (ctrl_ext & BP10GB_MDIO_DATA) + ctrl_val |= 1 << i; + + } else if (!pbpctl_dev->bp_10g) { + + if (ctrl_ext & BPCTLI_CTRL_EXT_MDIO_DATA) + ctrl_val |= 1 << i; + } else { + + if (ctrl_ext & BP10G_MDIO_DATA_IN) + ctrl_val |= 1 << i; + } + + } + + return ctrl_val; +} + +static void write_reg(bpctl_dev_t *pbpctl_dev, unsigned char value, + unsigned char addr) +{ + uint32_t ctrl_ext = 0, ctrl = 0; + bpctl_dev_t *pbpctl_dev_c = NULL; + unsigned long flags; + if (pbpctl_dev->bp_10g9) { + if (!(pbpctl_dev_c = get_status_port_fn(pbpctl_dev))) + return; + } + if ((pbpctl_dev->wdt_status == WDT_STATUS_EN) && + (pbpctl_dev->bp_ext_ver < PXG4BPFI_VER)) + wdt_time_left(pbpctl_dev); + +#ifdef BP_SYNC_FLAG + spin_lock_irqsave(&pbpctl_dev->bypass_wr_lock, flags); +#else + atomic_set(&pbpctl_dev->wdt_busy, 1); +#endif + if (pbpctl_dev->bp_10g9) { + + ctrl_ext = BP10G_READ_REG(pbpctl_dev, I2CCTL); + ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP); + /* DATA 0 CLK 0 */ + /* BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + (ctrl_ext & ~BP10G_MDIO_DATA_OUT9)); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + ((ctrl | BP10G_MCLK_DIR_OUT9) & + ~(BP10G_MCLK_DATA_OUT9))); + + } else if (pbpctl_dev->bp_fiber5) { + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 + | + BPCTLI_CTRL_EXT_MDIO_DIR5) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA5 + | + BPCTLI_CTRL_EXT_MCLK_DATA5))); + } else if (pbpctl_dev->bp_i80) { + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL); + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MDIO_DIR80) + & + ~BPCTLI_CTRL_EXT_MDIO_DATA80)); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) & + ~BPCTLI_CTRL_EXT_MCLK_DATA80)); + + } else if (pbpctl_dev->bp_540) { + ctrl = ctrl_ext = BP10G_READ_REG(pbpctl_dev, ESDP); + BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl | + BP540_MDIO_DIR | + BP540_MCLK_DIR) & + ~(BP540_MDIO_DATA | + BP540_MCLK_DATA))); + + } else if (pbpctl_dev->bp_10gb) { + ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO); + + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR) + & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR | + BP10GB_MDIO_SET | BP10GB_MCLK_SET)); + + } else if (!pbpctl_dev->bp_10g) { + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR + | + BPCTLI_CTRL_EXT_MDIO_DIR) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA + | + BPCTLI_CTRL_EXT_MCLK_DATA))); + } else { + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP); + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + (ctrl_ext & + ~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT))); + } + usec_delay(CMND_INTERVAL); + + /*send sync cmd */ + write_pulse(pbpctl_dev, ctrl_ext, SYNC_CMD_VAL, SYNC_CMD_LEN); + /*send wr cmd */ + write_pulse(pbpctl_dev, ctrl_ext, WR_CMD_VAL, WR_CMD_LEN); + write_pulse(pbpctl_dev, ctrl_ext, addr, ADDR_CMD_LEN); + + /*write data */ + write_pulse(pbpctl_dev, ctrl_ext, value, WR_DATA_LEN); + if (pbpctl_dev->bp_10g9) { + /*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */ + /* DATA 0 CLK 0 */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + (ctrl_ext & ~BP10G_MDIO_DATA_OUT9)); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + ((ctrl | BP10G_MCLK_DIR_OUT9) & + ~(BP10G_MCLK_DATA_OUT9))); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 + | + BPCTLI_CTRL_EXT_MDIO_DIR5) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA5 + | + BPCTLI_CTRL_EXT_MCLK_DATA5))); + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MDIO_DIR80) + & + ~BPCTLI_CTRL_EXT_MDIO_DATA80)); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) & + ~BPCTLI_CTRL_EXT_MCLK_DATA80)); + } else if (pbpctl_dev->bp_540) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl | + BP540_MDIO_DIR | + BP540_MCLK_DIR) & + ~(BP540_MDIO_DATA | + BP540_MCLK_DATA))); + } else if (pbpctl_dev->bp_10gb) { + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR) + & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR | + BP10GB_MDIO_SET | BP10GB_MCLK_SET)); + + } else if (!pbpctl_dev->bp_10g) + + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR + | + BPCTLI_CTRL_EXT_MDIO_DIR) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA + | + BPCTLI_CTRL_EXT_MCLK_DATA))); + else { + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + (ctrl_ext & + ~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT))); + + } + + usec_delay(CMND_INTERVAL * 4); + + if ((pbpctl_dev->wdt_status == WDT_STATUS_EN) && + (pbpctl_dev->bp_ext_ver < PXG4BPFI_VER) && (addr == CMND_REG_ADDR)) + pbpctl_dev->bypass_wdt_on_time = jiffies; +#ifdef BP_SYNC_FLAG + spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags); +#else + atomic_set(&pbpctl_dev->wdt_busy, 0); +#endif + +} + +static void write_data(bpctl_dev_t *pbpctl_dev, unsigned char value) +{ + write_reg(pbpctl_dev, value, CMND_REG_ADDR); +} + +static int read_reg(bpctl_dev_t *pbpctl_dev, unsigned char addr) +{ + uint32_t ctrl_ext = 0, ctrl = 0, ctrl_value = 0; + bpctl_dev_t *pbpctl_dev_c = NULL; + +#ifdef BP_SYNC_FLAG + unsigned long flags; + spin_lock_irqsave(&pbpctl_dev->bypass_wr_lock, flags); +#else + atomic_set(&pbpctl_dev->wdt_busy, 1); +#endif + if (pbpctl_dev->bp_10g9) { + if (!(pbpctl_dev_c = get_status_port_fn(pbpctl_dev))) + return -1; + } + + if (pbpctl_dev->bp_10g9) { + ctrl_ext = BP10G_READ_REG(pbpctl_dev, I2CCTL); + ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP); + + /* BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */ + /* DATA 0 CLK 0 */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + (ctrl_ext & ~BP10G_MDIO_DATA_OUT9)); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + ((ctrl | BP10G_MCLK_DIR_OUT9) & + ~(BP10G_MCLK_DATA_OUT9))); + + } else if (pbpctl_dev->bp_fiber5) { + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL); + + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 + | + BPCTLI_CTRL_EXT_MDIO_DIR5) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA5 + | + BPCTLI_CTRL_EXT_MCLK_DATA5))); + } else if (pbpctl_dev->bp_i80) { + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL); + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MDIO_DIR80) + & + ~BPCTLI_CTRL_EXT_MDIO_DATA80)); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) & + ~BPCTLI_CTRL_EXT_MCLK_DATA80)); + } else if (pbpctl_dev->bp_540) { + ctrl_ext = BP10G_READ_REG(pbpctl_dev, ESDP); + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + + BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl | BP540_MCLK_DIR | + BP540_MDIO_DIR) & + ~(BP540_MDIO_DATA | + BP540_MCLK_DATA))); + } else if (pbpctl_dev->bp_10gb) { + ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO); + + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR) + & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR | + BP10GB_MDIO_SET | BP10GB_MCLK_SET)); +#if 0 + + /*BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, (ctrl_ext | BP10GB_MCLK_DIR | BP10GB_MDIO_DIR| + BP10GB_MCLK_CLR|BP10GB_MDIO_CLR)); + ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO); + printk("1reg=%x\n", ctrl_ext); */ + + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, ((ctrl_ext | + BP10GB_MCLK_SET | + BP10GB_MDIO_CLR)) + & ~(BP10GB_MCLK_CLR | BP10GB_MDIO_SET | + BP10GB_MCLK_DIR | BP10GB_MDIO_DIR)); + + /* bnx2x_set_spio(pbpctl_dev, 5, MISC_REGISTERS_SPIO_OUTPUT_LOW); + bnx2x_set_spio(pbpctl_dev, 4, MISC_REGISTERS_SPIO_OUTPUT_LOW); + bnx2x_set_spio(pbpctl_dev, 4, MISC_REGISTERS_SPIO_INPUT_HI_Z); */ + + ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO); + + printk("2reg=%x\n", ctrl_ext); + +#ifdef BP_SYNC_FLAG + spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags); +#else + atomic_set(&pbpctl_dev->wdt_busy, 0); +#endif + + return 0; + +#endif + + } else if (!pbpctl_dev->bp_10g) { + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR + | + BPCTLI_CTRL_EXT_MDIO_DIR) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA + | + BPCTLI_CTRL_EXT_MCLK_DATA))); + } else { + + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP); + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + (ctrl_ext & + ~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT))); + + } + + usec_delay(CMND_INTERVAL); + + /*send sync cmd */ + write_pulse(pbpctl_dev, ctrl_ext, SYNC_CMD_VAL, SYNC_CMD_LEN); + /*send rd cmd */ + write_pulse(pbpctl_dev, ctrl_ext, RD_CMD_VAL, RD_CMD_LEN); + /*send addr */ + write_pulse(pbpctl_dev, ctrl_ext, addr, ADDR_CMD_LEN); + /*read data */ + /* zero */ + if (pbpctl_dev->bp_10g9) { + /* DATA 0 CLK 1 */ + /*BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext|BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9)); */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + (ctrl_ext | BP10G_MDIO_DATA_OUT9)); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + (ctrl | BP10G_MCLK_DATA_OUT9 | + BP10G_MCLK_DIR_OUT9)); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 + | + BPCTLI_CTRL_EXT_MCLK_DATA5) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DIR5 + | + BPCTLI_CTRL_EXT_MDIO_DATA5))); + + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + (ctrl_ext & + ~(BPCTLI_CTRL_EXT_MDIO_DATA80 | + BPCTLI_CTRL_EXT_MDIO_DIR80))); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + (ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80 | + BPCTLI_CTRL_EXT_MCLK_DATA80)); + + } else if (pbpctl_dev->bp_540) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, + (((ctrl | BP540_MDIO_DIR | BP540_MCLK_DIR | + BP540_MCLK_DATA) & ~BP540_MDIO_DATA))); + + } else if (pbpctl_dev->bp_10gb) { + + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_DIR | BP10GB_MCLK_SET) + & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_SET | + BP10GB_MDIO_CLR | BP10GB_MCLK_CLR)); + + } else if (!pbpctl_dev->bp_10g) + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR + | + BPCTLI_CTRL_EXT_MCLK_DATA) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DIR + | + BPCTLI_CTRL_EXT_MDIO_DATA))); + else { + + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + (ctrl_ext | BP10G_MCLK_DATA_OUT | + BP10G_MDIO_DATA_OUT)); + + + } + usec_delay(PULSE_TIME); + + ctrl_value = read_pulse(pbpctl_dev, ctrl_ext, RD_DATA_LEN); + + if (pbpctl_dev->bp_10g9) { + ctrl_ext = BP10G_READ_REG(pbpctl_dev, I2CCTL); + ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP); + + /* BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */ + /* DATA 0 CLK 0 */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + (ctrl_ext & ~BP10G_MDIO_DATA_OUT9)); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + ((ctrl | BP10G_MCLK_DIR_OUT9) & + ~(BP10G_MCLK_DATA_OUT9))); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 + | + BPCTLI_CTRL_EXT_MDIO_DIR5) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA5 + | + BPCTLI_CTRL_EXT_MCLK_DATA5))); + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MDIO_DIR80) + & + ~BPCTLI_CTRL_EXT_MDIO_DATA80)); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) & + ~BPCTLI_CTRL_EXT_MCLK_DATA80)); + + } else if (pbpctl_dev->bp_540) { + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl | BP540_MCLK_DIR | + BP540_MDIO_DIR) & + ~(BP540_MDIO_DATA | + BP540_MCLK_DATA))); + + } else if (pbpctl_dev->bp_10gb) { + ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO); + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR) + & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR | + BP10GB_MDIO_SET | BP10GB_MCLK_SET)); + + } else if (!pbpctl_dev->bp_10g) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR + | + BPCTLI_CTRL_EXT_MDIO_DIR) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA + | + BPCTLI_CTRL_EXT_MCLK_DATA))); + } else { + + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP); + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + (ctrl_ext & + ~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT))); + + } + + usec_delay(CMND_INTERVAL * 4); +#ifdef BP_SYNC_FLAG + spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags); +#else + atomic_set(&pbpctl_dev->wdt_busy, 0); +#endif + + return ctrl_value; +} + +static int wdt_pulse(bpctl_dev_t *pbpctl_dev) +{ + uint32_t ctrl_ext = 0, ctrl = 0; + bpctl_dev_t *pbpctl_dev_c = NULL; + +#ifdef BP_SYNC_FLAG + unsigned long flags; + + spin_lock_irqsave(&pbpctl_dev->bypass_wr_lock, flags); +#else + + if ((atomic_read(&pbpctl_dev->wdt_busy)) == 1) + return -1; +#endif + if (pbpctl_dev->bp_10g9) { + if (!(pbpctl_dev_c = get_status_port_fn(pbpctl_dev))) + return -1; + } + + if (pbpctl_dev->bp_10g9) { + ctrl_ext = BP10G_READ_REG(pbpctl_dev, I2CCTL); + ctrl = BP10G_READ_REG(pbpctl_dev_c, ESDP); + + /* BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */ + /* DATA 0 CLK 0 */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + (ctrl_ext & ~BP10G_MDIO_DATA_OUT9)); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + ((ctrl | BP10G_MCLK_DIR_OUT9) & + ~(BP10G_MCLK_DATA_OUT9))); + + } else if (pbpctl_dev->bp_fiber5) { + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 + | + BPCTLI_CTRL_EXT_MDIO_DIR5) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA5 + | + BPCTLI_CTRL_EXT_MCLK_DATA5))); + } else if (pbpctl_dev->bp_i80) { + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL); + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MDIO_DIR80) + & + ~BPCTLI_CTRL_EXT_MDIO_DATA80)); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) & + ~BPCTLI_CTRL_EXT_MCLK_DATA80)); + } else if (pbpctl_dev->bp_540) { + ctrl_ext = ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl | BP540_MCLK_DIR | + BP540_MDIO_DIR) & + ~(BP540_MDIO_DATA | + BP540_MCLK_DATA))); + } else if (pbpctl_dev->bp_10gb) { + ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO); + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR) + & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR | + BP10GB_MDIO_SET | BP10GB_MCLK_SET)); + + } else if (!pbpctl_dev->bp_10g) { + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR + | + BPCTLI_CTRL_EXT_MDIO_DIR) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA + | + BPCTLI_CTRL_EXT_MCLK_DATA))); + } else { + + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + ctrl_ext = BP10G_READ_REG(pbpctl_dev, EODSDP); + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + (ctrl_ext & + ~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT))); + + } + if (pbpctl_dev->bp_10g9) { + /* BP10G_WRITE_REG(pbpctl_dev, I2CCTL, ((ctrl_ext|BP10G_MCLK_DATA_OUT9)&~BP10G_MDIO_DATA_OUT9)); */ + /* DATA 0 CLK 1 */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + (ctrl_ext & ~BP10G_MDIO_DATA_OUT9)); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + (ctrl | BP10G_MCLK_DATA_OUT9 | + BP10G_MCLK_DIR_OUT9)); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 + | + BPCTLI_CTRL_EXT_MDIO_DIR5 + | + BPCTLI_CTRL_EXT_MCLK_DATA5) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA5))); + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MDIO_DIR80) + & + ~BPCTLI_CTRL_EXT_MDIO_DATA80)); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + (ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80 | + BPCTLI_CTRL_EXT_MCLK_DATA80)); + + } else if (pbpctl_dev->bp_540) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl | + BP540_MDIO_DIR | + BP540_MCLK_DIR | + BP540_MCLK_DATA) & + ~BP540_MDIO_DATA)); + + } else if (pbpctl_dev->bp_10gb) { + ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO); + + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_SET) + & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR | + BP10GB_MDIO_SET | BP10GB_MCLK_CLR)); + + } else if (!pbpctl_dev->bp_10g) + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR + | + BPCTLI_CTRL_EXT_MDIO_DIR + | + BPCTLI_CTRL_EXT_MCLK_DATA) + & + ~ + (BPCTLI_CTRL_EXT_MDIO_DATA))); + else { + + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + ((ctrl_ext | BP10G_MCLK_DATA_OUT) & + ~BP10G_MDIO_DATA_OUT)); + + } + + usec_delay(WDT_INTERVAL); + if (pbpctl_dev->bp_10g9) { + /* BP10G_WRITE_REG(pbpctl_dev, I2CCTL, (ctrl_ext&~(BP10G_MCLK_DATA_OUT9|BP10G_MDIO_DATA_OUT9))); */ + /* DATA 0 CLK 0 */ + BP10G_WRITE_REG(pbpctl_dev, I2CCTL, + (ctrl_ext & ~BP10G_MDIO_DATA_OUT9)); + BP10G_WRITE_REG(pbpctl_dev_c, ESDP, + ((ctrl | BP10G_MCLK_DIR_OUT9) & + ~(BP10G_MCLK_DATA_OUT9))); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR5 + | + BPCTLI_CTRL_EXT_MDIO_DIR5) + & + ~ + (BPCTLI_CTRL_EXT_MCLK_DATA5 + | + BPCTLI_CTRL_EXT_MDIO_DATA5))); + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, ((ctrl_ext | + BPCTLI_CTRL_EXT_MDIO_DIR80) + & + ~BPCTLI_CTRL_EXT_MDIO_DATA80)); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl | BPCTLI_CTRL_EXT_MCLK_DIR80) & + ~BPCTLI_CTRL_EXT_MCLK_DATA80)); + + } else if (pbpctl_dev->bp_540) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, ((ctrl | BP540_MCLK_DIR | + BP540_MDIO_DIR) & + ~(BP540_MDIO_DATA | + BP540_MCLK_DATA))); + + } else if (pbpctl_dev->bp_10gb) { + ctrl_ext = BP10GB_READ_REG(pbpctl_dev, MISC_REG_SPIO); + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_SPIO, + (ctrl_ext | BP10GB_MDIO_CLR | BP10GB_MCLK_CLR) + & ~(BP10GB_MCLK_DIR | BP10GB_MDIO_DIR | + BP10GB_MDIO_SET | BP10GB_MCLK_SET)); + + } else if (!pbpctl_dev->bp_10g) + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR + | + BPCTLI_CTRL_EXT_MDIO_DIR) + & + ~ + (BPCTLI_CTRL_EXT_MCLK_DATA + | + BPCTLI_CTRL_EXT_MDIO_DATA))); + else { + + BP10G_WRITE_REG(pbpctl_dev, EODSDP, + (ctrl_ext & + ~(BP10G_MCLK_DATA_OUT | BP10G_MDIO_DATA_OUT))); + } + if ((pbpctl_dev->wdt_status == WDT_STATUS_EN) /*&& + (pbpctl_dev->bp_ext_ver<PXG4BPFI_VER) */ ) + pbpctl_dev->bypass_wdt_on_time = jiffies; +#ifdef BP_SYNC_FLAG + spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags); +#endif + usec_delay(CMND_INTERVAL * 4); + return 0; +} + +static void data_pulse(bpctl_dev_t *pbpctl_dev, unsigned char value) +{ + + uint32_t ctrl_ext = 0; +#ifdef BP_SYNC_FLAG + unsigned long flags; +#endif + wdt_time_left(pbpctl_dev); +#ifdef BP_SYNC_FLAG + spin_lock_irqsave(&pbpctl_dev->bypass_wr_lock, flags); +#else + atomic_set(&pbpctl_dev->wdt_busy, 1); +#endif + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_SDP6_DIR | + BPCTLI_CTRL_EXT_SDP7_DIR) & + ~(BPCTLI_CTRL_EXT_SDP6_DATA | + BPCTLI_CTRL_EXT_SDP7_DATA))); + + usec_delay(INIT_CMND_INTERVAL); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_SDP6_DIR | + BPCTLI_CTRL_EXT_SDP7_DIR | + BPCTLI_CTRL_EXT_SDP6_DATA) & + ~ + (BPCTLI_CTRL_EXT_SDP7_DATA))); + usec_delay(INIT_CMND_INTERVAL); + + while (value) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ctrl_ext | + BPCTLI_CTRL_EXT_SDP6_DIR | + BPCTLI_CTRL_EXT_SDP7_DIR | + BPCTLI_CTRL_EXT_SDP6_DATA | + BPCTLI_CTRL_EXT_SDP7_DATA); + usec_delay(PULSE_INTERVAL); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_SDP6_DIR + | + BPCTLI_CTRL_EXT_SDP7_DIR + | + BPCTLI_CTRL_EXT_SDP6_DATA) + & + ~BPCTLI_CTRL_EXT_SDP7_DATA)); + usec_delay(PULSE_INTERVAL); + value--; + + } + usec_delay(INIT_CMND_INTERVAL - PULSE_INTERVAL); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_SDP6_DIR | + BPCTLI_CTRL_EXT_SDP7_DIR) & + ~(BPCTLI_CTRL_EXT_SDP6_DATA | + BPCTLI_CTRL_EXT_SDP7_DATA))); + usec_delay(WDT_TIME_CNT); + if (pbpctl_dev->wdt_status == WDT_STATUS_EN) + pbpctl_dev->bypass_wdt_on_time = jiffies; +#ifdef BP_SYNC_FLAG + spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags); +#else + atomic_set(&pbpctl_dev->wdt_busy, 0); +#endif + +} + +static int send_wdt_pulse(bpctl_dev_t *pbpctl_dev) +{ + uint32_t ctrl_ext = 0; + +#ifdef BP_SYNC_FLAG + unsigned long flags; + + spin_lock_irqsave(&pbpctl_dev->bypass_wr_lock, flags); +#else + + if ((atomic_read(&pbpctl_dev->wdt_busy)) == 1) + return -1; +#endif + wdt_time_left(pbpctl_dev); + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ctrl_ext | /* 1 */ + BPCTLI_CTRL_EXT_SDP7_DIR | + BPCTLI_CTRL_EXT_SDP7_DATA); + usec_delay(PULSE_INTERVAL); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | /* 0 */ + BPCTLI_CTRL_EXT_SDP7_DIR) & + ~BPCTLI_CTRL_EXT_SDP7_DATA)); + + usec_delay(PULSE_INTERVAL); + if (pbpctl_dev->wdt_status == WDT_STATUS_EN) + pbpctl_dev->bypass_wdt_on_time = jiffies; +#ifdef BP_SYNC_FLAG + spin_unlock_irqrestore(&pbpctl_dev->bypass_wr_lock, flags); +#endif + + return 0; +} + +void send_bypass_clear_pulse(bpctl_dev_t *pbpctl_dev, unsigned int value) +{ + uint32_t ctrl_ext = 0; + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | /* 0 */ + BPCTLI_CTRL_EXT_SDP6_DIR) & + ~BPCTLI_CTRL_EXT_SDP6_DATA)); + + usec_delay(PULSE_INTERVAL); + while (value) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ctrl_ext | /* 1 */ + BPCTLI_CTRL_EXT_SDP6_DIR | + BPCTLI_CTRL_EXT_SDP6_DATA); + usec_delay(PULSE_INTERVAL); + value--; + } + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | /* 0 */ + BPCTLI_CTRL_EXT_SDP6_DIR) & + ~BPCTLI_CTRL_EXT_SDP6_DATA)); + usec_delay(PULSE_INTERVAL); +} + +/* #endif OLD_FW */ +#ifdef BYPASS_DEBUG + +int pulse_set_fn(bpctl_dev_t *pbpctl_dev, unsigned int counter) +{ + uint32_t ctrl_ext = 0; + + if (!pbpctl_dev) + return -1; + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + write_pulse_1(pbpctl_dev, ctrl_ext, counter, counter); + + pbpctl_dev->bypass_wdt_status = 0; + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + write_pulse_1(pbpctl_dev, ctrl_ext, counter, counter); + } else { + wdt_time_left(pbpctl_dev); + if (pbpctl_dev->wdt_status == WDT_STATUS_EN) { + pbpctl_dev->wdt_status = 0; + data_pulse(pbpctl_dev, counter); + pbpctl_dev->wdt_status = WDT_STATUS_EN; + pbpctl_dev->bypass_wdt_on_time = jiffies; + + } else + data_pulse(pbpctl_dev, counter); + } + + return 0; +} + +int zero_set_fn(bpctl_dev_t *pbpctl_dev) +{ + uint32_t ctrl_ext = 0, ctrl_value = 0; + if (!pbpctl_dev) + return -1; + + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + printk("zero_set"); + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_MCLK_DIR) + & + ~ + (BPCTLI_CTRL_EXT_MCLK_DATA + | + BPCTLI_CTRL_EXT_MDIO_DIR + | + BPCTLI_CTRL_EXT_MDIO_DATA))); + + } + return ctrl_value; +} + +int pulse_get2_fn(bpctl_dev_t *pbpctl_dev) +{ + uint32_t ctrl_ext = 0, ctrl_value = 0; + if (!pbpctl_dev) + return -1; + + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + printk("pulse_get_fn\n"); + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + ctrl_value = read_pulse_2(pbpctl_dev, ctrl_ext); + printk("read:%d\n", ctrl_value); + } + return ctrl_value; +} + +int pulse_get1_fn(bpctl_dev_t *pbpctl_dev) +{ + uint32_t ctrl_ext = 0, ctrl_value = 0; + if (!pbpctl_dev) + return -1; + + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + + printk("pulse_get_fn\n"); + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + ctrl_value = read_pulse_1(pbpctl_dev, ctrl_ext); + printk("read:%d\n", ctrl_value); + } + return ctrl_value; +} + +int gpio6_set_fn(bpctl_dev_t *pbpctl_dev) +{ + uint32_t ctrl_ext = 0; + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ctrl_ext | + BPCTLI_CTRL_EXT_SDP6_DIR | + BPCTLI_CTRL_EXT_SDP6_DATA); + return 0; +} + +int gpio7_set_fn(bpctl_dev_t *pbpctl_dev) +{ + uint32_t ctrl_ext = 0; + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ctrl_ext | + BPCTLI_CTRL_EXT_SDP7_DIR | + BPCTLI_CTRL_EXT_SDP7_DATA); + return 0; +} + +int gpio7_clear_fn(bpctl_dev_t *pbpctl_dev) +{ + uint32_t ctrl_ext = 0; + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_SDP7_DIR) & + ~BPCTLI_CTRL_EXT_SDP7_DATA)); + return 0; +} + +int gpio6_clear_fn(bpctl_dev_t *pbpctl_dev) +{ + uint32_t ctrl_ext = 0; + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, ((ctrl_ext | + BPCTLI_CTRL_EXT_SDP6_DIR) & + ~BPCTLI_CTRL_EXT_SDP6_DATA)); + return 0; +} +#endif /*BYPASS_DEBUG */ + +static bpctl_dev_t *get_status_port_fn(bpctl_dev_t *pbpctl_dev) +{ + int idx_dev = 0; + + if (pbpctl_dev == NULL) + return NULL; + + if ((pbpctl_dev->func == 0) || (pbpctl_dev->func == 2)) { + for (idx_dev = 0; + ((bpctl_dev_arr[idx_dev].pdev != NULL) + && (idx_dev < device_num)); idx_dev++) { + if ((bpctl_dev_arr[idx_dev].bus == pbpctl_dev->bus) + && (bpctl_dev_arr[idx_dev].slot == pbpctl_dev->slot) + && ((bpctl_dev_arr[idx_dev].func == 1) + && (pbpctl_dev->func == 0))) { + + return &(bpctl_dev_arr[idx_dev]); + } + if ((bpctl_dev_arr[idx_dev].bus == pbpctl_dev->bus) && + (bpctl_dev_arr[idx_dev].slot == pbpctl_dev->slot) && + ((bpctl_dev_arr[idx_dev].func == 3) + && (pbpctl_dev->func == 2))) { + + return &(bpctl_dev_arr[idx_dev]); + } + } + } + return NULL; +} + +static bpctl_dev_t *get_master_port_fn(bpctl_dev_t *pbpctl_dev) +{ + int idx_dev = 0; + + if (pbpctl_dev == NULL) + return NULL; + + if ((pbpctl_dev->func == 1) || (pbpctl_dev->func == 3)) { + for (idx_dev = 0; + ((bpctl_dev_arr[idx_dev].pdev != NULL) + && (idx_dev < device_num)); idx_dev++) { + if ((bpctl_dev_arr[idx_dev].bus == pbpctl_dev->bus) + && (bpctl_dev_arr[idx_dev].slot == pbpctl_dev->slot) + && ((bpctl_dev_arr[idx_dev].func == 0) + && (pbpctl_dev->func == 1))) { + + return &(bpctl_dev_arr[idx_dev]); + } + if ((bpctl_dev_arr[idx_dev].bus == pbpctl_dev->bus) && + (bpctl_dev_arr[idx_dev].slot == pbpctl_dev->slot) && + ((bpctl_dev_arr[idx_dev].func == 2) + && (pbpctl_dev->func == 3))) { + + return &(bpctl_dev_arr[idx_dev]); + } + } + } + return NULL; +} + +/**************************************/ +/**************INTEL API***************/ +/**************************************/ + +static void write_data_port_int(bpctl_dev_t *pbpctl_dev, + unsigned char ctrl_value) +{ + uint32_t value; + + value = BPCTL_READ_REG(pbpctl_dev, CTRL); +/* Make SDP0 Pin Directonality to Output */ + value |= BPCTLI_CTRL_SDP0_DIR; + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, value); + + value &= ~BPCTLI_CTRL_SDP0_DATA; + value |= ((ctrl_value & 0x1) << BPCTLI_CTRL_SDP0_SHIFT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, value); + + value = (BPCTL_READ_REG(pbpctl_dev, CTRL_EXT)); +/* Make SDP2 Pin Directonality to Output */ + value |= BPCTLI_CTRL_EXT_SDP6_DIR; + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, value); + + value &= ~BPCTLI_CTRL_EXT_SDP6_DATA; + value |= (((ctrl_value & 0x2) >> 1) << BPCTLI_CTRL_EXT_SDP6_SHIFT); + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, value); + +} + +static int write_data_int(bpctl_dev_t *pbpctl_dev, unsigned char value) +{ + bpctl_dev_t *pbpctl_dev_b = NULL; + + if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) + return -1; + atomic_set(&pbpctl_dev->wdt_busy, 1); + write_data_port_int(pbpctl_dev, value & 0x3); + write_data_port_int(pbpctl_dev_b, ((value & 0xc) >> 2)); + atomic_set(&pbpctl_dev->wdt_busy, 0); + + return 0; +} + +static int wdt_pulse_int(bpctl_dev_t *pbpctl_dev) +{ + + if ((atomic_read(&pbpctl_dev->wdt_busy)) == 1) + return -1; + + if ((write_data_int(pbpctl_dev, RESET_WDT_INT)) < 0) + return -1; + msec_delay_bp(CMND_INTERVAL_INT); + if ((write_data_int(pbpctl_dev, CMND_OFF_INT)) < 0) + return -1; + msec_delay_bp(CMND_INTERVAL_INT); + + if (pbpctl_dev->wdt_status == WDT_STATUS_EN) + pbpctl_dev->bypass_wdt_on_time = jiffies; + + return 0; +} + +/*************************************/ +/************* COMMANDS **************/ +/*************************************/ + +/* CMND_ON 0x4 (100)*/ +int cmnd_on(bpctl_dev_t *pbpctl_dev) +{ + int ret = BP_NOT_CAP; + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) + return 0; + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) + write_data(pbpctl_dev, CMND_ON); + else + data_pulse(pbpctl_dev, CMND_ON); + ret = 0; + } + return ret; +} + +/* CMND_OFF 0x2 (10)*/ +int cmnd_off(bpctl_dev_t *pbpctl_dev) +{ + int ret = BP_NOT_CAP; + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) { + write_data_int(pbpctl_dev, CMND_OFF_INT); + msec_delay_bp(CMND_INTERVAL_INT); + } else if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) + write_data(pbpctl_dev, CMND_OFF); + else + data_pulse(pbpctl_dev, CMND_OFF); + ret = 0; + }; + return ret; +} + +/* BYPASS_ON (0xa)*/ +int bypass_on(bpctl_dev_t *pbpctl_dev) +{ + int ret = BP_NOT_CAP; + + if (pbpctl_dev->bp_caps & BP_CAP) { + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) { + write_data_int(pbpctl_dev, BYPASS_ON_INT); + msec_delay_bp(BYPASS_DELAY_INT); + pbpctl_dev->bp_status_un = 0; + } else if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + write_data(pbpctl_dev, BYPASS_ON); + if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) + msec_delay_bp(LATCH_DELAY); + } else + data_pulse(pbpctl_dev, BYPASS_ON); + ret = 0; + }; + return ret; +} + +/* BYPASS_OFF (0x8 111)*/ +int bypass_off(bpctl_dev_t *pbpctl_dev) +{ + int ret = BP_NOT_CAP; + + if (pbpctl_dev->bp_caps & BP_CAP) { + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) { + write_data_int(pbpctl_dev, DIS_BYPASS_CAP_INT); + msec_delay_bp(BYPASS_DELAY_INT); + write_data_int(pbpctl_dev, PWROFF_BYPASS_ON_INT); + msec_delay_bp(BYPASS_DELAY_INT); + pbpctl_dev->bp_status_un = 0; + } else if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + write_data(pbpctl_dev, BYPASS_OFF); + if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) + msec_delay_bp(LATCH_DELAY); + } else + data_pulse(pbpctl_dev, BYPASS_OFF); + ret = 0; + } + return ret; +} + +/* TAP_OFF (0x9)*/ +int tap_off(bpctl_dev_t *pbpctl_dev) +{ + int ret = BP_NOT_CAP; + if ((pbpctl_dev->bp_caps & TAP_CAP) + && (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)) { + write_data(pbpctl_dev, TAP_OFF); + msec_delay_bp(LATCH_DELAY); + ret = 0; + }; + return ret; +} + +/* TAP_ON (0xb)*/ +int tap_on(bpctl_dev_t *pbpctl_dev) +{ + int ret = BP_NOT_CAP; + if ((pbpctl_dev->bp_caps & TAP_CAP) + && (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)) { + write_data(pbpctl_dev, TAP_ON); + msec_delay_bp(LATCH_DELAY); + ret = 0; + }; + return ret; +} + +/* DISC_OFF (0x9)*/ +int disc_off(bpctl_dev_t *pbpctl_dev) +{ + int ret = 0; + if ((pbpctl_dev->bp_caps & DISC_CAP) && (pbpctl_dev->bp_ext_ver >= 0x8)) { + write_data(pbpctl_dev, DISC_OFF); + msec_delay_bp(LATCH_DELAY); + } else + ret = BP_NOT_CAP; + return ret; +} + +/* DISC_ON (0xb)*/ +int disc_on(bpctl_dev_t *pbpctl_dev) +{ + int ret = 0; + if ((pbpctl_dev->bp_caps & DISC_CAP) && (pbpctl_dev->bp_ext_ver >= 0x8)) { + write_data(pbpctl_dev, /*DISC_ON */ 0x85); + msec_delay_bp(LATCH_DELAY); + } else + ret = BP_NOT_CAP; + return ret; +} + +/* DISC_PORT_ON */ +int disc_port_on(bpctl_dev_t *pbpctl_dev) +{ + int ret = 0; + bpctl_dev_t *pbpctl_dev_m; + + if ((is_bypass_fn(pbpctl_dev)) == 1) + pbpctl_dev_m = pbpctl_dev; + else + pbpctl_dev_m = get_master_port_fn(pbpctl_dev); + if (pbpctl_dev_m == NULL) + return BP_NOT_CAP; + + if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) { + if (is_bypass_fn(pbpctl_dev) == 1) { + + write_data(pbpctl_dev_m, TX_DISA); + } else { + + write_data(pbpctl_dev_m, TX_DISB); + } + + msec_delay_bp(LATCH_DELAY); + + } + return ret; +} + +/* DISC_PORT_OFF */ +int disc_port_off(bpctl_dev_t *pbpctl_dev) +{ + int ret = 0; + bpctl_dev_t *pbpctl_dev_m; + + if ((is_bypass_fn(pbpctl_dev)) == 1) + pbpctl_dev_m = pbpctl_dev; + else + pbpctl_dev_m = get_master_port_fn(pbpctl_dev); + if (pbpctl_dev_m == NULL) + return BP_NOT_CAP; + + if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) { + if (is_bypass_fn(pbpctl_dev) == 1) + write_data(pbpctl_dev_m, TX_ENA); + else + write_data(pbpctl_dev_m, TX_ENB); + + msec_delay_bp(LATCH_DELAY); + + } + return ret; +} + +/*TWO_PORT_LINK_HW_EN (0xe)*/ +int tpl_hw_on(bpctl_dev_t *pbpctl_dev) +{ + int ret = 0, ctrl = 0; + bpctl_dev_t *pbpctl_dev_b = NULL; + + if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) + return BP_NOT_CAP; + + if (pbpctl_dev->bp_caps_ex & TPL2_CAP_EX) { + cmnd_on(pbpctl_dev); + write_data(pbpctl_dev, TPL2_ON); + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + cmnd_off(pbpctl_dev); + return ret; + } + + if (TPL_IF_SERIES(pbpctl_dev->subdevice)) { + ctrl = BPCTL_READ_REG(pbpctl_dev_b, CTRL); + BPCTL_BP_WRITE_REG(pbpctl_dev_b, CTRL, + ((ctrl | BPCTLI_CTRL_SWDPIO0) & + ~BPCTLI_CTRL_SWDPIN0)); + } else + ret = BP_NOT_CAP; + return ret; +} + +/*TWO_PORT_LINK_HW_DIS (0xc)*/ +int tpl_hw_off(bpctl_dev_t *pbpctl_dev) +{ + int ret = 0, ctrl = 0; + bpctl_dev_t *pbpctl_dev_b = NULL; + + if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) + return BP_NOT_CAP; + if (pbpctl_dev->bp_caps_ex & TPL2_CAP_EX) { + cmnd_on(pbpctl_dev); + write_data(pbpctl_dev, TPL2_OFF); + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + cmnd_off(pbpctl_dev); + return ret; + } + if (TPL_IF_SERIES(pbpctl_dev->subdevice)) { + ctrl = BPCTL_READ_REG(pbpctl_dev_b, CTRL); + BPCTL_BP_WRITE_REG(pbpctl_dev_b, CTRL, + (ctrl | BPCTLI_CTRL_SWDPIO0 | + BPCTLI_CTRL_SWDPIN0)); + } else + ret = BP_NOT_CAP; + return ret; +} + +/* WDT_OFF (0x6 110)*/ +int wdt_off(bpctl_dev_t *pbpctl_dev) +{ + int ret = BP_NOT_CAP; + + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) { + bypass_off(pbpctl_dev); + } else if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) + write_data(pbpctl_dev, WDT_OFF); + else + data_pulse(pbpctl_dev, WDT_OFF); + pbpctl_dev->wdt_status = WDT_STATUS_DIS; + ret = 0; + }; + return ret; +} + +/* WDT_ON (0x10)*/ + +/***Global***/ +static unsigned int + wdt_val_array[] = { 1000, 1500, 2000, 3000, 4000, 8000, 16000, 32000, 0 }; + +int wdt_on(bpctl_dev_t *pbpctl_dev, unsigned int timeout) +{ + + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + unsigned int pulse = 0, temp_value = 0, temp_cnt = 0; + pbpctl_dev->wdt_status = 0; + + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) { + for (; wdt_val_array[temp_cnt]; temp_cnt++) + if (timeout <= wdt_val_array[temp_cnt]) + break; + + if (!wdt_val_array[temp_cnt]) + temp_cnt--; + + timeout = wdt_val_array[temp_cnt]; + temp_cnt += 0x7; + + write_data_int(pbpctl_dev, DIS_BYPASS_CAP_INT); + msec_delay_bp(BYPASS_DELAY_INT); + pbpctl_dev->bp_status_un = 0; + write_data_int(pbpctl_dev, temp_cnt); + pbpctl_dev->bypass_wdt_on_time = jiffies; + msec_delay_bp(CMND_INTERVAL_INT); + pbpctl_dev->bypass_timer_interval = timeout; + } else { + timeout = + (timeout < + TIMEOUT_UNIT ? TIMEOUT_UNIT : (timeout > + WDT_TIMEOUT_MAX ? + WDT_TIMEOUT_MAX : + timeout)); + temp_value = timeout / 100; + while ((temp_value >>= 1)) + temp_cnt++; + if (timeout > ((1 << temp_cnt) * 100)) + temp_cnt++; + pbpctl_dev->bypass_wdt_on_time = jiffies; + pulse = (WDT_ON | temp_cnt); + if (pbpctl_dev->bp_ext_ver == OLD_IF_VER) + data_pulse(pbpctl_dev, pulse); + else + write_data(pbpctl_dev, pulse); + pbpctl_dev->bypass_timer_interval = + (1 << temp_cnt) * 100; + } + pbpctl_dev->wdt_status = WDT_STATUS_EN; + return 0; + } + return BP_NOT_CAP; +} + +void bp75_put_hw_semaphore_generic(bpctl_dev_t *pbpctl_dev) +{ + u32 swsm; + + swsm = BPCTL_READ_REG(pbpctl_dev, SWSM); + + swsm &= ~(BPCTLI_SWSM_SMBI | BPCTLI_SWSM_SWESMBI); + + BPCTL_WRITE_REG(pbpctl_dev, SWSM, swsm); +} + +s32 bp75_get_hw_semaphore_generic(bpctl_dev_t *pbpctl_dev) +{ + u32 swsm; + s32 ret_val = 0; + s32 timeout = 8192 + 1; + s32 i = 0; + + /* Get the SW semaphore */ + while (i < timeout) { + swsm = BPCTL_READ_REG(pbpctl_dev, SWSM); + if (!(swsm & BPCTLI_SWSM_SMBI)) + break; + + usec_delay(50); + i++; + } + + if (i == timeout) { + printk + ("bpctl_mod: Driver can't access device - SMBI bit is set.\n"); + ret_val = -1; + goto out; + } + + /* Get the FW semaphore. */ + for (i = 0; i < timeout; i++) { + swsm = BPCTL_READ_REG(pbpctl_dev, SWSM); + BPCTL_WRITE_REG(pbpctl_dev, SWSM, swsm | BPCTLI_SWSM_SWESMBI); + + /* Semaphore acquired if bit latched */ + if (BPCTL_READ_REG(pbpctl_dev, SWSM) & BPCTLI_SWSM_SWESMBI) + break; + + usec_delay(50); + } + + if (i == timeout) { + /* Release semaphores */ + bp75_put_hw_semaphore_generic(pbpctl_dev); + printk("bpctl_mod: Driver can't access the NVM\n"); + ret_val = -1; + goto out; + } + + out: + return ret_val; +} + +static void bp75_release_phy(bpctl_dev_t *pbpctl_dev) +{ + u16 mask = BPCTLI_SWFW_PHY0_SM; + u32 swfw_sync; + + if ((pbpctl_dev->func == 1) || (pbpctl_dev->func == 3)) + mask = BPCTLI_SWFW_PHY1_SM; + + while (bp75_get_hw_semaphore_generic(pbpctl_dev) != 0) ; + /* Empty */ + + swfw_sync = BPCTL_READ_REG(pbpctl_dev, SW_FW_SYNC); + swfw_sync &= ~mask; + BPCTL_WRITE_REG(pbpctl_dev, SW_FW_SYNC, swfw_sync); + + bp75_put_hw_semaphore_generic(pbpctl_dev); +} + +static s32 bp75_acquire_phy(bpctl_dev_t *pbpctl_dev) +{ + u16 mask = BPCTLI_SWFW_PHY0_SM; + u32 swfw_sync; + u32 swmask; + u32 fwmask; + s32 ret_val = 0; + s32 i = 0, timeout = 200; + + if ((pbpctl_dev->func == 1) || (pbpctl_dev->func == 3)) + mask = BPCTLI_SWFW_PHY1_SM; + + swmask = mask; + fwmask = mask << 16; + + while (i < timeout) { + if (bp75_get_hw_semaphore_generic(pbpctl_dev)) { + ret_val = -1; + goto out; + } + + swfw_sync = BPCTL_READ_REG(pbpctl_dev, SW_FW_SYNC); + if (!(swfw_sync & (fwmask | swmask))) + break; + + bp75_put_hw_semaphore_generic(pbpctl_dev); + mdelay(5); + i++; + } + + if (i == timeout) { + printk + ("bpctl_mod: Driver can't access resource, SW_FW_SYNC timeout.\n"); + ret_val = -1; + goto out; + } + + swfw_sync |= swmask; + BPCTL_WRITE_REG(pbpctl_dev, SW_FW_SYNC, swfw_sync); + + bp75_put_hw_semaphore_generic(pbpctl_dev); + + out: + return ret_val; +} + +s32 bp75_read_phy_reg_mdic(bpctl_dev_t *pbpctl_dev, u32 offset, u16 *data) +{ + u32 i, mdic = 0; + s32 ret_val = 0; + u32 phy_addr = 1; + + mdic = ((offset << BPCTLI_MDIC_REG_SHIFT) | + (phy_addr << BPCTLI_MDIC_PHY_SHIFT) | (BPCTLI_MDIC_OP_READ)); + + BPCTL_WRITE_REG(pbpctl_dev, MDIC, mdic); + + for (i = 0; i < (BPCTLI_GEN_POLL_TIMEOUT * 3); i++) { + usec_delay(50); + mdic = BPCTL_READ_REG(pbpctl_dev, MDIC); + if (mdic & BPCTLI_MDIC_READY) + break; + } + if (!(mdic & BPCTLI_MDIC_READY)) { + printk("bpctl_mod: MDI Read did not complete\n"); + ret_val = -1; + goto out; + } + if (mdic & BPCTLI_MDIC_ERROR) { + printk("bpctl_mod: MDI Error\n"); + ret_val = -1; + goto out; + } + *data = (u16) mdic; + + out: + return ret_val; +} + +s32 bp75_write_phy_reg_mdic(bpctl_dev_t *pbpctl_dev, u32 offset, u16 data) +{ + u32 i, mdic = 0; + s32 ret_val = 0; + u32 phy_addr = 1; + + mdic = (((u32) data) | + (offset << BPCTLI_MDIC_REG_SHIFT) | + (phy_addr << BPCTLI_MDIC_PHY_SHIFT) | (BPCTLI_MDIC_OP_WRITE)); + + BPCTL_WRITE_REG(pbpctl_dev, MDIC, mdic); + + for (i = 0; i < (BPCTLI_GEN_POLL_TIMEOUT * 3); i++) { + usec_delay(50); + mdic = BPCTL_READ_REG(pbpctl_dev, MDIC); + if (mdic & BPCTLI_MDIC_READY) + break; + } + if (!(mdic & BPCTLI_MDIC_READY)) { + printk("bpctl_mod: MDI Write did not complete\n"); + ret_val = -1; + goto out; + } + if (mdic & BPCTLI_MDIC_ERROR) { + printk("bpctl_mod: MDI Error\n"); + ret_val = -1; + goto out; + } + + out: + return ret_val; +} + +static s32 bp75_read_phy_reg(bpctl_dev_t *pbpctl_dev, u32 offset, u16 *data) +{ + s32 ret_val = 0; + + ret_val = bp75_acquire_phy(pbpctl_dev); + if (ret_val) + goto out; + + if (offset > BPCTLI_MAX_PHY_MULTI_PAGE_REG) { + ret_val = bp75_write_phy_reg_mdic(pbpctl_dev, + BPCTLI_IGP01E1000_PHY_PAGE_SELECT, + (u16) offset); + if (ret_val) + goto release; + } + + ret_val = + bp75_read_phy_reg_mdic(pbpctl_dev, + BPCTLI_MAX_PHY_REG_ADDRESS & offset, data); + + release: + bp75_release_phy(pbpctl_dev); + out: + return ret_val; +} + +static s32 bp75_write_phy_reg(bpctl_dev_t *pbpctl_dev, u32 offset, u16 data) +{ + s32 ret_val = 0; + + ret_val = bp75_acquire_phy(pbpctl_dev); + if (ret_val) + goto out; + + if (offset > BPCTLI_MAX_PHY_MULTI_PAGE_REG) { + ret_val = bp75_write_phy_reg_mdic(pbpctl_dev, + BPCTLI_IGP01E1000_PHY_PAGE_SELECT, + (u16) offset); + if (ret_val) + goto release; + } + + ret_val = + bp75_write_phy_reg_mdic(pbpctl_dev, + BPCTLI_MAX_PHY_REG_ADDRESS & offset, data); + + release: + bp75_release_phy(pbpctl_dev); + + out: + return ret_val; +} + +/* SET_TX (non-Bypass command :)) */ +static int set_tx(bpctl_dev_t *pbpctl_dev, int tx_state) +{ + int ret = 0, ctrl = 0; + bpctl_dev_t *pbpctl_dev_m; + if ((is_bypass_fn(pbpctl_dev)) == 1) + pbpctl_dev_m = pbpctl_dev; + else + pbpctl_dev_m = get_master_port_fn(pbpctl_dev); + if (pbpctl_dev_m == NULL) + return BP_NOT_CAP; + if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) { + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL); + if (!tx_state) { + if (pbpctl_dev->bp_540) { + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + BP10G_WRITE_REG(pbpctl_dev, ESDP, + (ctrl | BP10G_SDP1_DIR | + BP10G_SDP1_DATA)); + + } else { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + (ctrl | BPCTLI_CTRL_SDP1_DIR + | BPCTLI_CTRL_SWDPIN1)); + } + } else { + if (pbpctl_dev->bp_540) { + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + BP10G_WRITE_REG(pbpctl_dev, ESDP, + ((ctrl | BP10G_SDP1_DIR) & + ~BP10G_SDP1_DATA)); + } else { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + ((ctrl | + BPCTLI_CTRL_SDP1_DIR) & + ~BPCTLI_CTRL_SWDPIN1)); + } + return ret; + + } + } else if (pbpctl_dev->bp_caps & TX_CTL_CAP) { + if (PEG5_IF_SERIES(pbpctl_dev->subdevice)) { + if (tx_state) { + uint16_t mii_reg; + if (! + (ret = + bp75_read_phy_reg(pbpctl_dev, + BPCTLI_PHY_CONTROL, + &mii_reg))) { + if (mii_reg & BPCTLI_MII_CR_POWER_DOWN) { + ret = + bp75_write_phy_reg + (pbpctl_dev, + BPCTLI_PHY_CONTROL, + mii_reg & + ~BPCTLI_MII_CR_POWER_DOWN); + } + } + } else { + uint16_t mii_reg; + if (! + (ret = + bp75_read_phy_reg(pbpctl_dev, + BPCTLI_PHY_CONTROL, + &mii_reg))) { + + mii_reg |= BPCTLI_MII_CR_POWER_DOWN; + ret = + bp75_write_phy_reg(pbpctl_dev, + BPCTLI_PHY_CONTROL, + mii_reg); + } + } + + } + if (pbpctl_dev->bp_fiber5) { + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + + } else if (pbpctl_dev->bp_10gb) + ctrl = BP10GB_READ_REG(pbpctl_dev, MISC_REG_GPIO); + + else if (!pbpctl_dev->bp_10g) + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL); + else + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + + if (!tx_state) + if (pbpctl_dev->bp_10g9) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, + (ctrl | BP10G_SDP3_DATA | + BP10G_SDP3_DIR)); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + (ctrl | + BPCTLI_CTRL_EXT_SDP6_DIR | + BPCTLI_CTRL_EXT_SDP6_DATA)); + + } else if (pbpctl_dev->bp_10gb) { + if ((pbpctl_dev->func == 1) + || (pbpctl_dev->func == 3)) + BP10GB_WRITE_REG(pbpctl_dev, + MISC_REG_GPIO, + (ctrl | + BP10GB_GPIO0_SET_P1) & + ~(BP10GB_GPIO0_CLR_P1 | + BP10GB_GPIO0_OE_P1)); + else + BP10GB_WRITE_REG(pbpctl_dev, + MISC_REG_GPIO, + (ctrl | + BP10GB_GPIO0_OE_P0 | + BP10GB_GPIO0_SET_P0)); + + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + (ctrl | BPCTLI_CTRL_SDP1_DIR + | BPCTLI_CTRL_SWDPIN1)); + + } else if (pbpctl_dev->bp_540) { + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + BP10G_WRITE_REG(pbpctl_dev, ESDP, + (ctrl | BP10G_SDP1_DIR | + BP10G_SDP1_DATA)); + + } + + else if (!pbpctl_dev->bp_10g) + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + (ctrl | BPCTLI_CTRL_SWDPIO0 | + BPCTLI_CTRL_SWDPIN0)); + + else + BP10G_WRITE_REG(pbpctl_dev, ESDP, + (ctrl | BP10G_SDP0_DATA | + BP10G_SDP0_DIR)); + + else { + if (pbpctl_dev->bp_10g9) { + BP10G_WRITE_REG(pbpctl_dev, ESDP, + ((ctrl | BP10G_SDP3_DIR) & + ~BP10G_SDP3_DATA)); + + } else if (pbpctl_dev->bp_fiber5) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL_EXT, + ((ctrl | + BPCTLI_CTRL_EXT_SDP6_DIR) & + ~BPCTLI_CTRL_EXT_SDP6_DATA)); + + } else if (pbpctl_dev->bp_10gb) { + if ((bpctl_dev_arr->func == 1) + || (bpctl_dev_arr->func == 3)) + BP10GB_WRITE_REG(pbpctl_dev, + MISC_REG_GPIO, + (ctrl | + BP10GB_GPIO0_CLR_P1) & + ~(BP10GB_GPIO0_SET_P1 | + BP10GB_GPIO0_OE_P1)); + else + BP10GB_WRITE_REG(pbpctl_dev, + MISC_REG_GPIO, + (ctrl | + BP10GB_GPIO0_OE_P0 | + BP10GB_GPIO0_CLR_P0)); + + } else if (pbpctl_dev->bp_i80) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + ((ctrl | + BPCTLI_CTRL_SDP1_DIR) & + ~BPCTLI_CTRL_SWDPIN1)); + } else if (pbpctl_dev->bp_540) { + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + BP10G_WRITE_REG(pbpctl_dev, ESDP, + ((ctrl | BP10G_SDP1_DIR) & + ~BP10G_SDP1_DATA)); + } + + else if (!pbpctl_dev->bp_10g) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + ((ctrl | BPCTLI_CTRL_SWDPIO0) + & ~BPCTLI_CTRL_SWDPIN0)); + if (!PEGF_IF_SERIES(pbpctl_dev->subdevice)) { + BPCTL_BP_WRITE_REG(pbpctl_dev, CTRL, + (ctrl & + ~ + (BPCTLI_CTRL_SDP0_DATA + | + BPCTLI_CTRL_SDP0_DIR))); + } + } else + BP10G_WRITE_REG(pbpctl_dev, ESDP, + ((ctrl | BP10G_SDP0_DIR) & + ~BP10G_SDP0_DATA)); + + } + + } else + ret = BP_NOT_CAP; + return ret; + +} + +/* SET_FORCE_LINK (non-Bypass command :)) */ +static int set_bp_force_link(bpctl_dev_t *pbpctl_dev, int tx_state) +{ + int ret = 0, ctrl = 0; + + if (DBI_IF_SERIES(pbpctl_dev->subdevice)) { + + if ((pbpctl_dev->bp_10g) || (pbpctl_dev->bp_10g9)) { + + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL); + if (!tx_state) + BP10G_WRITE_REG(pbpctl_dev, ESDP, + ctrl & ~BP10G_SDP1_DIR); + else + BP10G_WRITE_REG(pbpctl_dev, ESDP, + ((ctrl | BP10G_SDP1_DIR) & + ~BP10G_SDP1_DATA)); + return ret; + } + + } + return BP_NOT_CAP; +} + +/*RESET_CONT 0x20 */ +int reset_cont(bpctl_dev_t *pbpctl_dev) +{ + int ret = BP_NOT_CAP; + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) + return BP_NOT_CAP; + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) + write_data(pbpctl_dev, RESET_CONT); + else + data_pulse(pbpctl_dev, RESET_CONT); + ret = 0; + }; + return ret; +} + +/*DIS_BYPASS_CAP 0x22 */ +int dis_bypass_cap(bpctl_dev_t *pbpctl_dev) +{ + + if (pbpctl_dev->bp_caps & BP_DIS_CAP) { + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) { + write_data_int(pbpctl_dev, DIS_BYPASS_CAP_INT); + msec_delay_bp(BYPASS_DELAY_INT); + } else { + write_data(pbpctl_dev, BYPASS_OFF); + msec_delay_bp(LATCH_DELAY); + write_data(pbpctl_dev, DIS_BYPASS_CAP); + msec_delay_bp(BYPASS_CAP_DELAY); + } + return 0; + } + return BP_NOT_CAP; +} + +/*EN_BYPASS_CAP 0x24 */ +int en_bypass_cap(bpctl_dev_t *pbpctl_dev) +{ + if (pbpctl_dev->bp_caps & BP_DIS_CAP) { + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) { + write_data_int(pbpctl_dev, PWROFF_BYPASS_ON_INT); + msec_delay_bp(BYPASS_DELAY_INT); + } else { + write_data(pbpctl_dev, EN_BYPASS_CAP); + msec_delay_bp(BYPASS_CAP_DELAY); + } + return 0; + } + return BP_NOT_CAP; +} + +/* BYPASS_STATE_PWRON 0x26*/ +int bypass_state_pwron(bpctl_dev_t *pbpctl_dev) +{ + if (pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP) { + write_data(pbpctl_dev, BYPASS_STATE_PWRON); + if (pbpctl_dev->bp_ext_ver == PXG2BPI_VER) + msec_delay_bp(DFLT_PWRON_DELAY); + else + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + return 0; + } + return BP_NOT_CAP; +} + +/* NORMAL_STATE_PWRON 0x28*/ +int normal_state_pwron(bpctl_dev_t *pbpctl_dev) +{ + if ((pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP) + || (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP)) { + write_data(pbpctl_dev, NORMAL_STATE_PWRON); + if (pbpctl_dev->bp_ext_ver == PXG2BPI_VER) + msec_delay_bp(DFLT_PWRON_DELAY); + else + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + return 0; + } + return BP_NOT_CAP; +} + +/* BYPASS_STATE_PWROFF 0x27*/ +int bypass_state_pwroff(bpctl_dev_t *pbpctl_dev) +{ + if (pbpctl_dev->bp_caps & BP_PWOFF_CTL_CAP) { + write_data(pbpctl_dev, BYPASS_STATE_PWROFF); + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + return 0; + } + return BP_NOT_CAP; +} + +/* NORMAL_STATE_PWROFF 0x29*/ +int normal_state_pwroff(bpctl_dev_t *pbpctl_dev) +{ + if ((pbpctl_dev->bp_caps & BP_PWOFF_CTL_CAP)) { + write_data(pbpctl_dev, NORMAL_STATE_PWROFF); + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + return 0; + } + return BP_NOT_CAP; +} + +/*TAP_STATE_PWRON 0x2a*/ +int tap_state_pwron(bpctl_dev_t *pbpctl_dev) +{ + if (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) { + write_data(pbpctl_dev, TAP_STATE_PWRON); + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + return 0; + } + return BP_NOT_CAP; +} + +/*DIS_TAP_CAP 0x2c*/ +int dis_tap_cap(bpctl_dev_t *pbpctl_dev) +{ + if (pbpctl_dev->bp_caps & TAP_DIS_CAP) { + write_data(pbpctl_dev, DIS_TAP_CAP); + msec_delay_bp(BYPASS_CAP_DELAY); + return 0; + } + return BP_NOT_CAP; +} + +/*EN_TAP_CAP 0x2e*/ +int en_tap_cap(bpctl_dev_t *pbpctl_dev) +{ + if (pbpctl_dev->bp_caps & TAP_DIS_CAP) { + write_data(pbpctl_dev, EN_TAP_CAP); + msec_delay_bp(BYPASS_CAP_DELAY); + return 0; + } + return BP_NOT_CAP; +} + +/*DISC_STATE_PWRON 0x2a*/ +int disc_state_pwron(bpctl_dev_t *pbpctl_dev) +{ + if (pbpctl_dev->bp_caps & DISC_PWUP_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= 0x8) { + write_data(pbpctl_dev, DISC_STATE_PWRON); + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + return BP_OK; + } + } + return BP_NOT_CAP; +} + +/*DIS_DISC_CAP 0x2c*/ +int dis_disc_cap(bpctl_dev_t *pbpctl_dev) +{ + if (pbpctl_dev->bp_caps & DISC_DIS_CAP) { + if (pbpctl_dev->bp_ext_ver >= 0x8) { + write_data(pbpctl_dev, DIS_DISC_CAP); + msec_delay_bp(BYPASS_CAP_DELAY); + return BP_OK; + } + } + return BP_NOT_CAP; +} + +/*DISC_STATE_PWRON 0x2a*/ +int disc_port_state_pwron(bpctl_dev_t *pbpctl_dev) +{ + int ret = 0; + bpctl_dev_t *pbpctl_dev_m; + + return BP_NOT_CAP; + + if ((is_bypass_fn(pbpctl_dev)) == 1) + pbpctl_dev_m = pbpctl_dev; + else + pbpctl_dev_m = get_master_port_fn(pbpctl_dev); + if (pbpctl_dev_m == NULL) + return BP_NOT_CAP; + + if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) { + if (is_bypass_fn(pbpctl_dev) == 1) + write_data(pbpctl_dev_m, TX_DISA_PWRUP); + else + write_data(pbpctl_dev_m, TX_DISB_PWRUP); + + msec_delay_bp(LATCH_DELAY); + + } + return ret; +} + +int normal_port_state_pwron(bpctl_dev_t *pbpctl_dev) +{ + int ret = 0; + bpctl_dev_t *pbpctl_dev_m; + return BP_NOT_CAP; + + if ((is_bypass_fn(pbpctl_dev)) == 1) + pbpctl_dev_m = pbpctl_dev; + else + pbpctl_dev_m = get_master_port_fn(pbpctl_dev); + if (pbpctl_dev_m == NULL) + return BP_NOT_CAP; + + if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) { + if (is_bypass_fn(pbpctl_dev) == 1) + write_data(pbpctl_dev_m, TX_ENA_PWRUP); + else + write_data(pbpctl_dev_m, TX_ENB_PWRUP); + + msec_delay_bp(LATCH_DELAY); + + } + return ret; +} + +/*EN_TAP_CAP 0x2e*/ +int en_disc_cap(bpctl_dev_t *pbpctl_dev) +{ + if (pbpctl_dev->bp_caps & DISC_DIS_CAP) { + if (pbpctl_dev->bp_ext_ver >= 0x8) { + write_data(pbpctl_dev, EN_DISC_CAP); + msec_delay_bp(BYPASS_CAP_DELAY); + return BP_OK; + } + } + return BP_NOT_CAP; +} + +int std_nic_on(bpctl_dev_t *pbpctl_dev) +{ + + if (pbpctl_dev->bp_caps & STD_NIC_CAP) { + + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) { + write_data_int(pbpctl_dev, DIS_BYPASS_CAP_INT); + msec_delay_bp(BYPASS_DELAY_INT); + pbpctl_dev->bp_status_un = 0; + return BP_OK; + } + + if (pbpctl_dev->bp_ext_ver >= 0x8) { + write_data(pbpctl_dev, STD_NIC_ON); + msec_delay_bp(BYPASS_CAP_DELAY); + return BP_OK; + + } + + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + wdt_off(pbpctl_dev); + + if (pbpctl_dev->bp_caps & BP_CAP) { + write_data(pbpctl_dev, BYPASS_OFF); + msec_delay_bp(LATCH_DELAY); + } + + if (pbpctl_dev->bp_caps & TAP_CAP) { + write_data(pbpctl_dev, TAP_OFF); + msec_delay_bp(LATCH_DELAY); + } + + write_data(pbpctl_dev, NORMAL_STATE_PWRON); + if (pbpctl_dev->bp_ext_ver == PXG2BPI_VER) + msec_delay_bp(DFLT_PWRON_DELAY); + else + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + + if (pbpctl_dev->bp_caps & BP_DIS_CAP) { + write_data(pbpctl_dev, DIS_BYPASS_CAP); + msec_delay_bp(BYPASS_CAP_DELAY); + } + + if (pbpctl_dev->bp_caps & TAP_DIS_CAP) { + write_data(pbpctl_dev, DIS_TAP_CAP); + msec_delay_bp(BYPASS_CAP_DELAY); + + } + return 0; + } + } + return BP_NOT_CAP; +} + +int std_nic_off(bpctl_dev_t *pbpctl_dev) +{ + + if (pbpctl_dev->bp_caps & STD_NIC_CAP) { + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) { + write_data_int(pbpctl_dev, PWROFF_BYPASS_ON_INT); + msec_delay_bp(BYPASS_DELAY_INT); + return BP_OK; + } + if (pbpctl_dev->bp_ext_ver >= 0x8) { + write_data(pbpctl_dev, STD_NIC_OFF); + msec_delay_bp(BYPASS_CAP_DELAY); + return BP_OK; + + } + + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + + if (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) { + write_data(pbpctl_dev, TAP_STATE_PWRON); + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + } + + if (pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP) { + write_data(pbpctl_dev, BYPASS_STATE_PWRON); + if (pbpctl_dev->bp_ext_ver > PXG2BPI_VER) + msec_delay_bp(LATCH_DELAY + + EEPROM_WR_DELAY); + else + msec_delay_bp(DFLT_PWRON_DELAY); + } + + if (pbpctl_dev->bp_caps & TAP_DIS_CAP) { + write_data(pbpctl_dev, EN_TAP_CAP); + msec_delay_bp(BYPASS_CAP_DELAY); + } + if (pbpctl_dev->bp_caps & DISC_DIS_CAP) { + write_data(pbpctl_dev, EN_DISC_CAP); + msec_delay_bp(BYPASS_CAP_DELAY); + } + + if (pbpctl_dev->bp_caps & BP_DIS_CAP) { + write_data(pbpctl_dev, EN_BYPASS_CAP); + msec_delay_bp(BYPASS_CAP_DELAY); + } + + return 0; + } + } + return BP_NOT_CAP; +} + +int wdt_time_left(bpctl_dev_t *pbpctl_dev) +{ + + /* unsigned long curr_time=((long long)(jiffies*1000))/HZ, delta_time=0,wdt_on_time=((long long)(pbpctl_dev->bypass_wdt_on_time*1000))/HZ; */ + unsigned long curr_time = jiffies, delta_time = 0, wdt_on_time = + pbpctl_dev->bypass_wdt_on_time, delta_time_msec = 0; + int time_left = 0; + + switch (pbpctl_dev->wdt_status) { + case WDT_STATUS_DIS: + time_left = 0; + break; + case WDT_STATUS_EN: + delta_time = + (curr_time >= + wdt_on_time) ? (curr_time - wdt_on_time) : (~wdt_on_time + + curr_time); + delta_time_msec = jiffies_to_msecs(delta_time); + time_left = pbpctl_dev->bypass_timer_interval - delta_time_msec; + if (time_left < 0) { + time_left = -1; + pbpctl_dev->wdt_status = WDT_STATUS_EXP; + } + break; + case WDT_STATUS_EXP: + time_left = -1; + break; + } + + return time_left; +} + +static int wdt_timer(bpctl_dev_t *pbpctl_dev, int *time_left) +{ + int ret = 0; + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + { + if (pbpctl_dev->wdt_status == WDT_STATUS_UNKNOWN) + ret = BP_NOT_CAP; + else + *time_left = wdt_time_left(pbpctl_dev); + } + + } else + ret = BP_NOT_CAP; + return ret; +} + +static int wdt_timer_reload(bpctl_dev_t *pbpctl_dev) +{ + + int ret = 0; + + if ((pbpctl_dev->bp_caps & WD_CTL_CAP) && + (pbpctl_dev->wdt_status != WDT_STATUS_UNKNOWN)) { + if (pbpctl_dev->wdt_status == WDT_STATUS_DIS) + return 0; + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) + ret = wdt_pulse(pbpctl_dev); + else if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) + ret = wdt_pulse_int(pbpctl_dev); + else + ret = send_wdt_pulse(pbpctl_dev); + /* if (ret==-1) + mod_timer(&pbpctl_dev->bp_timer, jiffies+1);*/ + return 1; + } + return BP_NOT_CAP; +} + +static void wd_reset_timer(unsigned long param) +{ + bpctl_dev_t *pbpctl_dev = (bpctl_dev_t *) param; +#ifdef BP_SELF_TEST + struct sk_buff *skb_tmp; +#endif + + if ((pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) && + ((atomic_read(&pbpctl_dev->wdt_busy)) == 1)) { + mod_timer(&pbpctl_dev->bp_timer, jiffies + 1); + return; + } +#ifdef BP_SELF_TEST + + if (pbpctl_dev->bp_self_test_flag == 1) { + skb_tmp = dev_alloc_skb(BPTEST_DATA_LEN + 2); + if ((skb_tmp) && (pbpctl_dev->ndev) && (pbpctl_dev->bp_tx_data)) { + memcpy(skb_put(skb_tmp, BPTEST_DATA_LEN), + pbpctl_dev->bp_tx_data, BPTEST_DATA_LEN); + skb_tmp->dev = pbpctl_dev->ndev; + skb_tmp->protocol = + eth_type_trans(skb_tmp, pbpctl_dev->ndev); + skb_tmp->ip_summed = CHECKSUM_UNNECESSARY; + netif_receive_skb(skb_tmp); + goto bp_timer_reload; + return; + } + } +#endif + + wdt_timer_reload(pbpctl_dev); +#ifdef BP_SELF_TEST + bp_timer_reload: +#endif + if (pbpctl_dev->reset_time) { + mod_timer(&pbpctl_dev->bp_timer, + jiffies + (HZ * pbpctl_dev->reset_time) / 1000); + } +} + +/*WAIT_AT_PWRUP 0x80 */ +int bp_wait_at_pwup_en(bpctl_dev_t *pbpctl_dev) +{ + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER8) { + write_data(pbpctl_dev, BP_WAIT_AT_PWUP_EN); + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + + return BP_OK; + } + } + return BP_NOT_CAP; +} + +/*DIS_WAIT_AT_PWRUP 0x81 */ +int bp_wait_at_pwup_dis(bpctl_dev_t *pbpctl_dev) +{ + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + + if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER8) { + write_data(pbpctl_dev, BP_WAIT_AT_PWUP_DIS); + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + + return BP_OK; + } + } + return BP_NOT_CAP; +} + +/*EN_HW_RESET 0x82 */ + +int bp_hw_reset_en(bpctl_dev_t *pbpctl_dev) +{ + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER8) { + write_data(pbpctl_dev, BP_HW_RESET_EN); + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + + return BP_OK; + } + } + return BP_NOT_CAP; +} + +/*DIS_HW_RESET 0x83 */ + +int bp_hw_reset_dis(bpctl_dev_t *pbpctl_dev) +{ + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER8) { + write_data(pbpctl_dev, BP_HW_RESET_DIS); + msec_delay_bp(LATCH_DELAY + EEPROM_WR_DELAY); + + return BP_OK; + } + } + return BP_NOT_CAP; +} + + +int wdt_exp_mode(bpctl_dev_t *pbpctl_dev, int mode) +{ + uint32_t status_reg = 0, status_reg1 = 0; + + if ((pbpctl_dev->bp_caps & (TAP_STATUS_CAP | DISC_CAP)) && + (pbpctl_dev->bp_caps & BP_CAP)) { + if (pbpctl_dev->bp_ext_ver >= PXE2TBPI_VER) { + + if ((pbpctl_dev->bp_ext_ver >= 0x8) && + (mode == 2) && (pbpctl_dev->bp_caps & DISC_CAP)) { + status_reg1 = + read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR); + if (!(status_reg1 & WDTE_DISC_BPN_MASK)) + write_reg(pbpctl_dev, + status_reg1 | + WDTE_DISC_BPN_MASK, + STATUS_DISC_REG_ADDR); + return BP_OK; + } + } + status_reg = read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR); + + if ((mode == 0) && (pbpctl_dev->bp_caps & BP_CAP)) { + if (pbpctl_dev->bp_ext_ver >= 0x8) { + status_reg1 = + read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR); + if (status_reg1 & WDTE_DISC_BPN_MASK) + write_reg(pbpctl_dev, + status_reg1 & + ~WDTE_DISC_BPN_MASK, + STATUS_DISC_REG_ADDR); + } + if (status_reg & WDTE_TAP_BPN_MASK) + write_reg(pbpctl_dev, + status_reg & ~WDTE_TAP_BPN_MASK, + STATUS_TAP_REG_ADDR); + return BP_OK; + + } else if ((mode == 1) && (pbpctl_dev->bp_caps & TAP_CAP)) { + if (!(status_reg & WDTE_TAP_BPN_MASK)) + write_reg(pbpctl_dev, + status_reg | WDTE_TAP_BPN_MASK, + STATUS_TAP_REG_ADDR); + /*else return BP_NOT_CAP; */ + return BP_OK; + } + + } + return BP_NOT_CAP; +} + +int bypass_fw_ver(bpctl_dev_t *pbpctl_dev) +{ + if (is_bypass_fn(pbpctl_dev)) + return read_reg(pbpctl_dev, VER_REG_ADDR); + else + return BP_NOT_CAP; +} + +int bypass_sign_check(bpctl_dev_t *pbpctl_dev) +{ + + if (is_bypass_fn(pbpctl_dev)) + return (((read_reg(pbpctl_dev, PIC_SIGN_REG_ADDR)) == + PIC_SIGN_VALUE) ? 1 : 0); + else + return BP_NOT_CAP; +} + +static int tx_status(bpctl_dev_t *pbpctl_dev) +{ + uint32_t ctrl = 0; + bpctl_dev_t *pbpctl_dev_m; + if ((is_bypass_fn(pbpctl_dev)) == 1) + pbpctl_dev_m = pbpctl_dev; + else + pbpctl_dev_m = get_master_port_fn(pbpctl_dev); + if (pbpctl_dev_m == NULL) + return BP_NOT_CAP; + if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) { + + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL); + if (pbpctl_dev->bp_i80) + return ((ctrl & BPCTLI_CTRL_SWDPIN1) != 0 ? 0 : 1); + if (pbpctl_dev->bp_540) { + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + + return ((ctrl & BP10G_SDP1_DATA) != 0 ? 0 : 1); + } + + } + + if (pbpctl_dev->bp_caps & TX_CTL_CAP) { + if (PEG5_IF_SERIES(pbpctl_dev->subdevice)) { + uint16_t mii_reg; + if (! + (bp75_read_phy_reg + (pbpctl_dev, BPCTLI_PHY_CONTROL, &mii_reg))) { + if (mii_reg & BPCTLI_MII_CR_POWER_DOWN) + return 0; + + else + return 1; + } + return -1; + } + + if (pbpctl_dev->bp_10g9) { + return ((BP10G_READ_REG(pbpctl_dev, ESDP) & + BP10G_SDP3_DATA) != 0 ? 0 : 1); + + } else if (pbpctl_dev->bp_fiber5) { + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + if (ctrl & BPCTLI_CTRL_EXT_SDP6_DATA) + return 0; + return 1; + } else if (pbpctl_dev->bp_10gb) { + ctrl = BP10GB_READ_REG(pbpctl_dev, MISC_REG_GPIO); + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_GPIO, + (ctrl | BP10GB_GPIO0_OE_P1) & + ~(BP10GB_GPIO0_SET_P1 | + BP10GB_GPIO0_CLR_P1)); + + if ((pbpctl_dev->func == 1) || (pbpctl_dev->func == 3)) + return (((BP10GB_READ_REG + (pbpctl_dev, + MISC_REG_GPIO)) & BP10GB_GPIO0_P1) != + 0 ? 0 : 1); + else + return (((BP10GB_READ_REG + (pbpctl_dev, + MISC_REG_GPIO)) & BP10GB_GPIO0_P0) != + 0 ? 0 : 1); + } + + if (!pbpctl_dev->bp_10g) { + + ctrl = BPCTL_READ_REG(pbpctl_dev, CTRL); + if (pbpctl_dev->bp_i80) + return ((ctrl & BPCTLI_CTRL_SWDPIN1) != + 0 ? 0 : 1); + if (pbpctl_dev->bp_540) { + ctrl = BP10G_READ_REG(pbpctl_dev, ESDP); + + return ((ctrl & BP10G_SDP1_DATA) != 0 ? 0 : 1); + } + + return ((ctrl & BPCTLI_CTRL_SWDPIN0) != 0 ? 0 : 1); + } else + return ((BP10G_READ_REG(pbpctl_dev, ESDP) & + BP10G_SDP0_DATA) != 0 ? 0 : 1); + + } + return BP_NOT_CAP; +} + +static int bp_force_link_status(bpctl_dev_t *pbpctl_dev) +{ + + if (DBI_IF_SERIES(pbpctl_dev->subdevice)) { + + if ((pbpctl_dev->bp_10g) || (pbpctl_dev->bp_10g9)) { + return ((BP10G_READ_REG(pbpctl_dev, ESDP) & + BP10G_SDP1_DIR) != 0 ? 1 : 0); + + } + } + return BP_NOT_CAP; +} + +int bypass_from_last_read(bpctl_dev_t *pbpctl_dev) +{ + uint32_t ctrl_ext = 0; + bpctl_dev_t *pbpctl_dev_b = NULL; + + if ((pbpctl_dev->bp_caps & SW_CTL_CAP) + && (pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) { + ctrl_ext = BPCTL_READ_REG(pbpctl_dev_b, CTRL_EXT); + BPCTL_BP_WRITE_REG(pbpctl_dev_b, CTRL_EXT, + (ctrl_ext & ~BPCTLI_CTRL_EXT_SDP7_DIR)); + ctrl_ext = BPCTL_READ_REG(pbpctl_dev_b, CTRL_EXT); + if (ctrl_ext & BPCTLI_CTRL_EXT_SDP7_DATA) + return 0; + return 1; + } else + return BP_NOT_CAP; +} + +int bypass_status_clear(bpctl_dev_t *pbpctl_dev) +{ + bpctl_dev_t *pbpctl_dev_b = NULL; + + if ((pbpctl_dev->bp_caps & SW_CTL_CAP) + && (pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) { + + send_bypass_clear_pulse(pbpctl_dev_b, 1); + return 0; + } else + return BP_NOT_CAP; +} + +int bypass_flag_status(bpctl_dev_t *pbpctl_dev) +{ + + if ((pbpctl_dev->bp_caps & BP_CAP)) { + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + return ((((read_reg(pbpctl_dev, STATUS_REG_ADDR)) & + BYPASS_FLAG_MASK) == + BYPASS_FLAG_MASK) ? 1 : 0); + } + } + return BP_NOT_CAP; +} + +int bypass_flag_status_clear(bpctl_dev_t *pbpctl_dev) +{ + + if (pbpctl_dev->bp_caps & BP_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + uint32_t status_reg = 0; + status_reg = read_reg(pbpctl_dev, STATUS_REG_ADDR); + write_reg(pbpctl_dev, status_reg & ~BYPASS_FLAG_MASK, + STATUS_REG_ADDR); + return 0; + } + } + return BP_NOT_CAP; +} + +int bypass_change_status(bpctl_dev_t *pbpctl_dev) +{ + int ret = BP_NOT_CAP; + + if (pbpctl_dev->bp_caps & BP_STATUS_CHANGE_CAP) { + if (pbpctl_dev->bp_ext_ver >= 0x8) { + ret = bypass_flag_status(pbpctl_dev); + bypass_flag_status_clear(pbpctl_dev); + } else if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + ret = bypass_flag_status(pbpctl_dev); + bypass_flag_status_clear(pbpctl_dev); + } else { + ret = bypass_from_last_read(pbpctl_dev); + bypass_status_clear(pbpctl_dev); + } + } + return ret; +} + +int bypass_off_status(bpctl_dev_t *pbpctl_dev) +{ + + if (pbpctl_dev->bp_caps & BP_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + return ((((read_reg(pbpctl_dev, STATUS_REG_ADDR)) & + BYPASS_OFF_MASK) == BYPASS_OFF_MASK) ? 1 : 0); + } + } + return BP_NOT_CAP; +} + +static int bypass_status(bpctl_dev_t *pbpctl_dev) +{ + u32 ctrl_ext = 0; + if (pbpctl_dev->bp_caps & BP_CAP) { + + bpctl_dev_t *pbpctl_dev_b = NULL; + + if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) + return BP_NOT_CAP; + + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) { + + if (!pbpctl_dev->bp_status_un) + return (((BPCTL_READ_REG + (pbpctl_dev_b, + CTRL_EXT)) & + BPCTLI_CTRL_EXT_SDP7_DATA) != + 0 ? 1 : 0); + else + return BP_NOT_CAP; + } + if (pbpctl_dev->bp_ext_ver >= 0x8) { + + if (pbpctl_dev->bp_10g9) { + ctrl_ext = BP10G_READ_REG(pbpctl_dev_b, I2CCTL); + BP10G_WRITE_REG(pbpctl_dev_b, I2CCTL, + (ctrl_ext | BP10G_I2C_CLK_OUT)); + return ((BP10G_READ_REG(pbpctl_dev_b, I2CCTL) & + BP10G_I2C_CLK_IN) != 0 ? 0 : 1); + + } else if (pbpctl_dev->bp_540) { + return (((BP10G_READ_REG(pbpctl_dev_b, ESDP)) & + BP10G_SDP0_DATA) != 0 ? 0 : 1); + } + + else if ((pbpctl_dev->bp_fiber5) + || (pbpctl_dev->bp_i80)) { + return (((BPCTL_READ_REG(pbpctl_dev_b, CTRL)) & + BPCTLI_CTRL_SWDPIN0) != 0 ? 0 : 1); + } else if (pbpctl_dev->bp_10gb) { + ctrl_ext = + BP10GB_READ_REG(pbpctl_dev, MISC_REG_GPIO); + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_GPIO, + (ctrl_ext | BP10GB_GPIO3_OE_P0) + & ~(BP10GB_GPIO3_SET_P0 | + BP10GB_GPIO3_CLR_P0)); + + return (((BP10GB_READ_REG + (pbpctl_dev, + MISC_REG_GPIO)) & BP10GB_GPIO3_P0) != + 0 ? 0 : 1); + } + + else if (!pbpctl_dev->bp_10g) + return (((BPCTL_READ_REG + (pbpctl_dev_b, + CTRL_EXT)) & + BPCTLI_CTRL_EXT_SDP7_DATA) != + 0 ? 0 : 1); + + else { + ctrl_ext = BP10G_READ_REG(pbpctl_dev_b, EODSDP); + BP10G_WRITE_REG(pbpctl_dev_b, EODSDP, + (ctrl_ext | + BP10G_SDP7_DATA_OUT)); + return ((BP10G_READ_REG(pbpctl_dev_b, EODSDP) & + BP10G_SDP7_DATA_IN) != 0 ? 0 : 1); + } + + } else if (pbpctl_dev->media_type == bp_copper) { + + return (((BPCTL_READ_REG(pbpctl_dev_b, CTRL)) & + BPCTLI_CTRL_SWDPIN1) != 0 ? 1 : 0); + } else { + if ((bypass_status_clear(pbpctl_dev)) >= 0) + return bypass_from_last_read(pbpctl_dev); + } + + } + return BP_NOT_CAP; +} + +int default_pwron_status(bpctl_dev_t *pbpctl_dev) +{ + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + return ((((read_reg + (pbpctl_dev, + STATUS_REG_ADDR)) & DFLT_PWRON_MASK) + == DFLT_PWRON_MASK) ? 0 : 1); + } + } /*else if ((!pbpctl_dev->bp_caps&BP_DIS_CAP)&& + (pbpctl_dev->bp_caps&BP_PWUP_ON_CAP)) + return 1; */ + } + return BP_NOT_CAP; +} + +static int default_pwroff_status(bpctl_dev_t *pbpctl_dev) +{ + + /*if ((!pbpctl_dev->bp_caps&BP_DIS_CAP)&& + (pbpctl_dev->bp_caps&BP_PWOFF_ON_CAP)) + return 1; */ + if ((pbpctl_dev->bp_caps & SW_CTL_CAP) + && (pbpctl_dev->bp_caps & BP_PWOFF_CTL_CAP)) { + return ((((read_reg(pbpctl_dev, STATUS_REG_ADDR)) & + DFLT_PWROFF_MASK) == DFLT_PWROFF_MASK) ? 0 : 1); + } + return BP_NOT_CAP; +} + +int dis_bypass_cap_status(bpctl_dev_t *pbpctl_dev) +{ + + if (pbpctl_dev->bp_caps & BP_DIS_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + return ((((read_reg(pbpctl_dev, STATUS_REG_ADDR)) & + DIS_BYPASS_CAP_MASK) == + DIS_BYPASS_CAP_MASK) ? 1 : 0); + } + } + return BP_NOT_CAP; +} + +int cmd_en_status(bpctl_dev_t *pbpctl_dev) +{ + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + return ((((read_reg(pbpctl_dev, STATUS_REG_ADDR)) & + CMND_EN_MASK) == CMND_EN_MASK) ? 1 : 0); + } + } + return BP_NOT_CAP; +} + +int wdt_en_status(bpctl_dev_t *pbpctl_dev) +{ + + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + return ((((read_reg(pbpctl_dev, STATUS_REG_ADDR)) & + WDT_EN_MASK) == WDT_EN_MASK) ? 1 : 0); + } + } + return BP_NOT_CAP; +} + +int wdt_programmed(bpctl_dev_t *pbpctl_dev, int *timeout) +{ + int ret = 0; + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + if ((read_reg(pbpctl_dev, STATUS_REG_ADDR)) & + WDT_EN_MASK) { + u8 wdt_val; + wdt_val = read_reg(pbpctl_dev, WDT_REG_ADDR); + *timeout = (1 << wdt_val) * 100; + } else + *timeout = 0; + } else { + int curr_wdt_status = pbpctl_dev->wdt_status; + if (curr_wdt_status == WDT_STATUS_UNKNOWN) + *timeout = -1; + else + *timeout = + curr_wdt_status == + 0 ? 0 : pbpctl_dev->bypass_timer_interval; + }; + } else + ret = BP_NOT_CAP; + return ret; +} + +int bypass_support(bpctl_dev_t *pbpctl_dev) +{ + int ret = 0; + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) { + ret = + ((((read_reg(pbpctl_dev, PRODUCT_CAP_REG_ADDR)) & + BYPASS_SUPPORT_MASK) == + BYPASS_SUPPORT_MASK) ? 1 : 0); + } else if (pbpctl_dev->bp_ext_ver == PXG2BPI_VER) + ret = 1; + } else + ret = BP_NOT_CAP; + return ret; +} + +int tap_support(bpctl_dev_t *pbpctl_dev) +{ + int ret = 0; + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) { + ret = + ((((read_reg(pbpctl_dev, PRODUCT_CAP_REG_ADDR)) & + TAP_SUPPORT_MASK) == TAP_SUPPORT_MASK) ? 1 : 0); + } else if (pbpctl_dev->bp_ext_ver == PXG2BPI_VER) + ret = 0; + } else + ret = BP_NOT_CAP; + return ret; +} + +int normal_support(bpctl_dev_t *pbpctl_dev) +{ + int ret = BP_NOT_CAP; + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) { + ret = + ((((read_reg(pbpctl_dev, PRODUCT_CAP_REG_ADDR)) & + NORMAL_UNSUPPORT_MASK) == + NORMAL_UNSUPPORT_MASK) ? 0 : 1); + } else + ret = 1; + }; + return ret; +} + +int get_bp_prod_caps(bpctl_dev_t *pbpctl_dev) +{ + if ((pbpctl_dev->bp_caps & SW_CTL_CAP) && + (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER)) + return read_reg(pbpctl_dev, PRODUCT_CAP_REG_ADDR); + return BP_NOT_CAP; + +} + +int tap_flag_status(bpctl_dev_t *pbpctl_dev) +{ + + if (pbpctl_dev->bp_caps & TAP_STATUS_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) + return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) & + TAP_FLAG_MASK) == TAP_FLAG_MASK) ? 1 : 0); + + } + return BP_NOT_CAP; +} + +int tap_flag_status_clear(bpctl_dev_t *pbpctl_dev) +{ + uint32_t status_reg = 0; + if (pbpctl_dev->bp_caps & TAP_STATUS_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) { + status_reg = read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR); + write_reg(pbpctl_dev, status_reg & ~TAP_FLAG_MASK, + STATUS_TAP_REG_ADDR); + return 0; + } + } + return BP_NOT_CAP; +} + +int tap_change_status(bpctl_dev_t *pbpctl_dev) +{ + int ret = BP_NOT_CAP; + if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) { + if (pbpctl_dev->bp_caps & TAP_CAP) { + if (pbpctl_dev->bp_caps & BP_CAP) { + ret = tap_flag_status(pbpctl_dev); + tap_flag_status_clear(pbpctl_dev); + } else { + ret = bypass_from_last_read(pbpctl_dev); + bypass_status_clear(pbpctl_dev); + } + } + } + return ret; +} + +int tap_off_status(bpctl_dev_t *pbpctl_dev) +{ + if (pbpctl_dev->bp_caps & TAP_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) + return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) & + TAP_OFF_MASK) == TAP_OFF_MASK) ? 1 : 0); + } + return BP_NOT_CAP; +} + +int tap_status(bpctl_dev_t *pbpctl_dev) +{ + u32 ctrl_ext = 0; + + if (pbpctl_dev->bp_caps & TAP_CAP) { + bpctl_dev_t *pbpctl_dev_b = NULL; + + if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) + return BP_NOT_CAP; + + if (pbpctl_dev->bp_ext_ver >= 0x8) { + if (!pbpctl_dev->bp_10g) + return (((BPCTL_READ_REG + (pbpctl_dev_b, + CTRL_EXT)) & + BPCTLI_CTRL_EXT_SDP6_DATA) != + 0 ? 0 : 1); + else { + ctrl_ext = BP10G_READ_REG(pbpctl_dev_b, EODSDP); + BP10G_WRITE_REG(pbpctl_dev_b, EODSDP, + (ctrl_ext | + BP10G_SDP6_DATA_OUT)); + return ((BP10G_READ_REG(pbpctl_dev_b, EODSDP) & + BP10G_SDP6_DATA_IN) != 0 ? 0 : 1); + } + + } else if (pbpctl_dev->media_type == bp_copper) + return (((BPCTL_READ_REG(pbpctl_dev, CTRL)) & + BPCTLI_CTRL_SWDPIN0) != 0 ? 1 : 0); + else { + if ((bypass_status_clear(pbpctl_dev)) >= 0) + return bypass_from_last_read(pbpctl_dev); + } + + } + return BP_NOT_CAP; +} + +int default_pwron_tap_status(bpctl_dev_t *pbpctl_dev) +{ + if (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) + return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) & + DFLT_PWRON_TAP_MASK) == + DFLT_PWRON_TAP_MASK) ? 1 : 0); + } + return BP_NOT_CAP; +} + +int dis_tap_cap_status(bpctl_dev_t *pbpctl_dev) +{ + if (pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) + return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) & + DIS_TAP_CAP_MASK) == + DIS_TAP_CAP_MASK) ? 1 : 0); + } + return BP_NOT_CAP; +} + +int disc_flag_status(bpctl_dev_t *pbpctl_dev) +{ + + if (pbpctl_dev->bp_caps & DISC_CAP) { + if (pbpctl_dev->bp_ext_ver >= 0x8) + return ((((read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR)) & + DISC_FLAG_MASK) == DISC_FLAG_MASK) ? 1 : 0); + + } + return BP_NOT_CAP; +} + +int disc_flag_status_clear(bpctl_dev_t *pbpctl_dev) +{ + uint32_t status_reg = 0; + if (pbpctl_dev->bp_caps & DISC_CAP) { + if (pbpctl_dev->bp_ext_ver >= 0x8) { + status_reg = read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR); + write_reg(pbpctl_dev, status_reg & ~DISC_FLAG_MASK, + STATUS_DISC_REG_ADDR); + return BP_OK; + } + } + return BP_NOT_CAP; +} + +int disc_change_status(bpctl_dev_t *pbpctl_dev) +{ + int ret = BP_NOT_CAP; + if (pbpctl_dev->bp_caps & DISC_CAP) { + ret = disc_flag_status(pbpctl_dev); + disc_flag_status_clear(pbpctl_dev); + return ret; + } + return BP_NOT_CAP; +} + +int disc_off_status(bpctl_dev_t *pbpctl_dev) +{ + bpctl_dev_t *pbpctl_dev_b = NULL; + u32 ctrl_ext = 0; + + if (pbpctl_dev->bp_caps & DISC_CAP) { + if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) + return BP_NOT_CAP; + if (DISCF_IF_SERIES(pbpctl_dev->subdevice)) + return ((((read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR)) & + DISC_OFF_MASK) == DISC_OFF_MASK) ? 1 : 0); + + if (pbpctl_dev->bp_i80) { + return (((BPCTL_READ_REG(pbpctl_dev_b, CTRL_EXT)) & + BPCTLI_CTRL_EXT_SDP6_DATA) != 0 ? 1 : 0); + + } + if (pbpctl_dev->bp_540) { + ctrl_ext = BP10G_READ_REG(pbpctl_dev_b, ESDP); + return ((BP10G_READ_REG(pbpctl_dev_b, ESDP) & + BP10G_SDP2_DATA) != 0 ? 1 : 0); + + } + if (pbpctl_dev->media_type == bp_copper) { + +#if 0 + return ((((read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR)) & + DISC_OFF_MASK) == DISC_OFF_MASK) ? 1 : 0); +#endif + if (!pbpctl_dev->bp_10g) + return (((BPCTL_READ_REG(pbpctl_dev_b, CTRL)) & + BPCTLI_CTRL_SWDPIN1) != 0 ? 1 : 0); + else + return ((BP10G_READ_REG(pbpctl_dev_b, ESDP) & + BP10G_SDP1_DATA) != 0 ? 1 : 0); + + } else { + + if (pbpctl_dev->bp_10g9) { + ctrl_ext = BP10G_READ_REG(pbpctl_dev_b, I2CCTL); + BP10G_WRITE_REG(pbpctl_dev_b, I2CCTL, + (ctrl_ext | + BP10G_I2C_DATA_OUT)); + return ((BP10G_READ_REG(pbpctl_dev_b, I2CCTL) & + BP10G_I2C_DATA_IN) != 0 ? 1 : 0); + + } else if (pbpctl_dev->bp_fiber5) { + return (((BPCTL_READ_REG(pbpctl_dev_b, CTRL)) & + BPCTLI_CTRL_SWDPIN1) != 0 ? 1 : 0); + } else if (pbpctl_dev->bp_10gb) { + ctrl_ext = + BP10GB_READ_REG(pbpctl_dev, MISC_REG_GPIO); + BP10GB_WRITE_REG(pbpctl_dev, MISC_REG_GPIO, + (ctrl_ext | BP10GB_GPIO3_OE_P1) + & ~(BP10GB_GPIO3_SET_P1 | + BP10GB_GPIO3_CLR_P1)); + + return (((BP10GB_READ_REG + (pbpctl_dev, + MISC_REG_GPIO)) & BP10GB_GPIO3_P1) != + 0 ? 1 : 0); + } + if (!pbpctl_dev->bp_10g) { + + return (((BPCTL_READ_REG + (pbpctl_dev_b, + CTRL_EXT)) & + BPCTLI_CTRL_EXT_SDP6_DATA) != + 0 ? 1 : 0); + } else { + ctrl_ext = BP10G_READ_REG(pbpctl_dev_b, EODSDP); + BP10G_WRITE_REG(pbpctl_dev_b, EODSDP, + (ctrl_ext | + BP10G_SDP6_DATA_OUT)); + return (((BP10G_READ_REG(pbpctl_dev_b, EODSDP)) + & BP10G_SDP6_DATA_IN) != 0 ? 1 : 0); + } + + } + } + return BP_NOT_CAP; +} + +static int disc_status(bpctl_dev_t *pbpctl_dev) +{ + int ctrl = 0; + if (pbpctl_dev->bp_caps & DISC_CAP) { + + if ((ctrl = disc_off_status(pbpctl_dev)) < 0) + return ctrl; + return ((ctrl == 0) ? 1 : 0); + + } + return BP_NOT_CAP; +} + +int default_pwron_disc_status(bpctl_dev_t *pbpctl_dev) +{ + if (pbpctl_dev->bp_caps & DISC_PWUP_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= 0x8) + return ((((read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR)) & + DFLT_PWRON_DISC_MASK) == + DFLT_PWRON_DISC_MASK) ? 1 : 0); + } + return BP_NOT_CAP; +} + +int dis_disc_cap_status(bpctl_dev_t *pbpctl_dev) +{ + if (pbpctl_dev->bp_caps & DIS_DISC_CAP) { + if (pbpctl_dev->bp_ext_ver >= 0x8) + return ((((read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR)) & + DIS_DISC_CAP_MASK) == + DIS_DISC_CAP_MASK) ? 1 : 0); + } + return BP_NOT_CAP; +} + +int disc_port_status(bpctl_dev_t *pbpctl_dev) +{ + int ret = BP_NOT_CAP; + bpctl_dev_t *pbpctl_dev_m; + + if ((is_bypass_fn(pbpctl_dev)) == 1) + pbpctl_dev_m = pbpctl_dev; + else + pbpctl_dev_m = get_master_port_fn(pbpctl_dev); + if (pbpctl_dev_m == NULL) + return BP_NOT_CAP; + + if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) { + if (is_bypass_fn(pbpctl_dev) == 1) { + return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) & + TX_DISA_MASK) == TX_DISA_MASK) ? 1 : 0); + } else + return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) & + TX_DISB_MASK) == TX_DISB_MASK) ? 1 : 0); + + } + return ret; +} + +int default_pwron_disc_port_status(bpctl_dev_t *pbpctl_dev) +{ + int ret = BP_NOT_CAP; + bpctl_dev_t *pbpctl_dev_m; + + if ((is_bypass_fn(pbpctl_dev)) == 1) + pbpctl_dev_m = pbpctl_dev; + else + pbpctl_dev_m = get_master_port_fn(pbpctl_dev); + if (pbpctl_dev_m == NULL) + return BP_NOT_CAP; + + if (pbpctl_dev_m->bp_caps_ex & DISC_PORT_CAP_EX) { + if (is_bypass_fn(pbpctl_dev) == 1) + return ret; + /* return((((read_reg(pbpctl_dev,STATUS_TAP_REG_ADDR)) & TX_DISA_MASK)==TX_DISA_MASK)?1:0); */ + else + return ret; + /* return((((read_reg(pbpctl_dev,STATUS_TAP_REG_ADDR)) & TX_DISA_MASK)==TX_DISA_MASK)?1:0); */ + + } + return ret; +} + +int wdt_exp_mode_status(bpctl_dev_t *pbpctl_dev) +{ + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver <= PXG2BPI_VER) + return 0; /* bypass mode */ + else if (pbpctl_dev->bp_ext_ver == PXG2TBPI_VER) + return 1; /* tap mode */ + else if (pbpctl_dev->bp_ext_ver >= PXE2TBPI_VER) { + if (pbpctl_dev->bp_ext_ver >= 0x8) { + if (((read_reg + (pbpctl_dev, + STATUS_DISC_REG_ADDR)) & + WDTE_DISC_BPN_MASK) == WDTE_DISC_BPN_MASK) + return 2; + } + return ((((read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR)) & + WDTE_TAP_BPN_MASK) == + WDTE_TAP_BPN_MASK) ? 1 : 0); + } + } + return BP_NOT_CAP; +} + +int tpl2_flag_status(bpctl_dev_t *pbpctl_dev) +{ + + if (pbpctl_dev->bp_caps_ex & TPL2_CAP_EX) { + return ((((read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR)) & + TPL2_FLAG_MASK) == TPL2_FLAG_MASK) ? 1 : 0); + + } + return BP_NOT_CAP; +} + +int tpl_hw_status(bpctl_dev_t *pbpctl_dev) +{ + bpctl_dev_t *pbpctl_dev_b = NULL; + + if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) + return BP_NOT_CAP; + + if (TPL_IF_SERIES(pbpctl_dev->subdevice)) + return (((BPCTL_READ_REG(pbpctl_dev, CTRL)) & + BPCTLI_CTRL_SWDPIN0) != 0 ? 1 : 0); + return BP_NOT_CAP; +} + + +int bp_wait_at_pwup_status(bpctl_dev_t *pbpctl_dev) +{ + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + if (pbpctl_dev->bp_ext_ver >= 0x8) + return ((((read_reg(pbpctl_dev, CONT_CONFIG_REG_ADDR)) & + WAIT_AT_PWUP_MASK) == + WAIT_AT_PWUP_MASK) ? 1 : 0); + } + return BP_NOT_CAP; +} + +int bp_hw_reset_status(bpctl_dev_t *pbpctl_dev) +{ + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + + if (pbpctl_dev->bp_ext_ver >= 0x8) + return ((((read_reg(pbpctl_dev, CONT_CONFIG_REG_ADDR)) & + EN_HW_RESET_MASK) == + EN_HW_RESET_MASK) ? 1 : 0); + } + return BP_NOT_CAP; +} + + +int std_nic_status(bpctl_dev_t *pbpctl_dev) +{ + int status_val = 0; + + if (pbpctl_dev->bp_caps & STD_NIC_CAP) { + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) + return BP_NOT_CAP; + if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER8) { + return ((((read_reg(pbpctl_dev, STATUS_DISC_REG_ADDR)) & + STD_NIC_ON_MASK) == STD_NIC_ON_MASK) ? 1 : 0); + } + + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + if (pbpctl_dev->bp_caps & BP_CAP) { + status_val = + read_reg(pbpctl_dev, STATUS_REG_ADDR); + if (((!(status_val & WDT_EN_MASK)) + && ((status_val & STD_NIC_MASK) == + STD_NIC_MASK))) + status_val = 1; + else + return 0; + } + if (pbpctl_dev->bp_caps & TAP_CAP) { + status_val = + read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR); + if ((status_val & STD_NIC_TAP_MASK) == + STD_NIC_TAP_MASK) + status_val = 1; + else + return 0; + } + if (pbpctl_dev->bp_caps & TAP_CAP) { + if ((disc_off_status(pbpctl_dev))) + status_val = 1; + else + return 0; + } + + return status_val; + } + } + return BP_NOT_CAP; +} + +/******************************************************/ +/**************SW_INIT*********************************/ +/******************************************************/ +void bypass_caps_init(bpctl_dev_t *pbpctl_dev) +{ + u_int32_t ctrl_ext = 0; + bpctl_dev_t *pbpctl_dev_m = NULL; + +#ifdef BYPASS_DEBUG + int ret = 0; + if (!(INTEL_IF_SERIES(adapter->bp_device_block.subdevice))) { + ret = read_reg(pbpctl_dev, VER_REG_ADDR); + printk("VER_REG reg1=%x\n", ret); + ret = read_reg(pbpctl_dev, PRODUCT_CAP_REG_ADDR); + printk("PRODUCT_CAP reg=%x\n", ret); + ret = read_reg(pbpctl_dev, STATUS_TAP_REG_ADDR); + printk("STATUS_TAP reg1=%x\n", ret); + ret = read_reg(pbpctl_dev, 0x7); + printk("SIG_REG reg1=%x\n", ret); + ret = read_reg(pbpctl_dev, STATUS_REG_ADDR); + printk("STATUS_REG_ADDR=%x\n", ret); + ret = read_reg(pbpctl_dev, WDT_REG_ADDR); + printk("WDT_REG_ADDR=%x\n", ret); + ret = read_reg(pbpctl_dev, TMRL_REG_ADDR); + printk("TMRL_REG_ADDR=%x\n", ret); + ret = read_reg(pbpctl_dev, TMRH_REG_ADDR); + printk("TMRH_REG_ADDR=%x\n", ret); + } +#endif + if ((pbpctl_dev->bp_fiber5) || (pbpctl_dev->bp_10g9)) { + pbpctl_dev->media_type = bp_fiber; + } else if (pbpctl_dev->bp_10gb) { + if (BP10GB_CX4_SERIES(pbpctl_dev->subdevice)) + pbpctl_dev->media_type = bp_cx4; + else + pbpctl_dev->media_type = bp_fiber; + + } + + else if (pbpctl_dev->bp_540) + pbpctl_dev->media_type = bp_none; + else if (!pbpctl_dev->bp_10g) { + + ctrl_ext = BPCTL_READ_REG(pbpctl_dev, CTRL_EXT); + if ((ctrl_ext & BPCTLI_CTRL_EXT_LINK_MODE_MASK) == 0x0) + pbpctl_dev->media_type = bp_copper; + else + pbpctl_dev->media_type = bp_fiber; + + } else { + if (BP10G_CX4_SERIES(pbpctl_dev->subdevice)) + pbpctl_dev->media_type = bp_cx4; + else + pbpctl_dev->media_type = bp_fiber; + } + + if (is_bypass_fn(pbpctl_dev)) { + + pbpctl_dev->bp_caps |= BP_PWOFF_ON_CAP; + if (pbpctl_dev->media_type == bp_fiber) + pbpctl_dev->bp_caps |= + (TX_CTL_CAP | TX_STATUS_CAP | TPL_CAP); + + if (TPL_IF_SERIES(pbpctl_dev->subdevice)) { + pbpctl_dev->bp_caps |= TPL_CAP; + } + + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) { + pbpctl_dev->bp_caps |= + (BP_CAP | BP_STATUS_CAP | SW_CTL_CAP | + BP_PWUP_ON_CAP | BP_PWUP_OFF_CAP | BP_PWOFF_OFF_CAP + | WD_CTL_CAP | WD_STATUS_CAP | STD_NIC_CAP | + WD_TIMEOUT_CAP); + + pbpctl_dev->bp_ext_ver = OLD_IF_VER; + return; + } + + if ((pbpctl_dev->bp_fw_ver == 0xff) && + OLD_IF_SERIES(pbpctl_dev->subdevice)) { + + pbpctl_dev->bp_caps |= + (BP_CAP | BP_STATUS_CAP | BP_STATUS_CHANGE_CAP | + SW_CTL_CAP | BP_PWUP_ON_CAP | WD_CTL_CAP | + WD_STATUS_CAP | WD_TIMEOUT_CAP); + + pbpctl_dev->bp_ext_ver = OLD_IF_VER; + return; + } + + else { + switch (pbpctl_dev->bp_fw_ver) { + case BP_FW_VER_A0: + case BP_FW_VER_A1:{ + pbpctl_dev->bp_ext_ver = + (pbpctl_dev-> + bp_fw_ver & EXT_VER_MASK); + break; + } + default:{ + if ((bypass_sign_check(pbpctl_dev)) != + 1) { + pbpctl_dev->bp_caps = 0; + return; + } + pbpctl_dev->bp_ext_ver = + (pbpctl_dev-> + bp_fw_ver & EXT_VER_MASK); + } + } + } + + if (pbpctl_dev->bp_ext_ver == PXG2BPI_VER) + pbpctl_dev->bp_caps |= + (BP_CAP | BP_STATUS_CAP | BP_STATUS_CHANGE_CAP | + SW_CTL_CAP | BP_DIS_CAP | BP_DIS_STATUS_CAP | + BP_PWUP_ON_CAP | BP_PWUP_OFF_CAP | BP_PWUP_CTL_CAP + | WD_CTL_CAP | STD_NIC_CAP | WD_STATUS_CAP | + WD_TIMEOUT_CAP); + else if (pbpctl_dev->bp_ext_ver >= PXG2TBPI_VER) { + int cap_reg; + + pbpctl_dev->bp_caps |= + (SW_CTL_CAP | WD_CTL_CAP | WD_STATUS_CAP | + WD_TIMEOUT_CAP); + cap_reg = get_bp_prod_caps(pbpctl_dev); + + if ((cap_reg & NORMAL_UNSUPPORT_MASK) == + NORMAL_UNSUPPORT_MASK) + pbpctl_dev->bp_caps |= NIC_CAP_NEG; + else + pbpctl_dev->bp_caps |= STD_NIC_CAP; + + if ((normal_support(pbpctl_dev)) == 1) + + pbpctl_dev->bp_caps |= STD_NIC_CAP; + + else + pbpctl_dev->bp_caps |= NIC_CAP_NEG; + if ((cap_reg & BYPASS_SUPPORT_MASK) == + BYPASS_SUPPORT_MASK) { + pbpctl_dev->bp_caps |= + (BP_CAP | BP_STATUS_CAP | + BP_STATUS_CHANGE_CAP | BP_DIS_CAP | + BP_DIS_STATUS_CAP | BP_PWUP_ON_CAP | + BP_PWUP_OFF_CAP | BP_PWUP_CTL_CAP); + if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER7) + pbpctl_dev->bp_caps |= + BP_PWOFF_ON_CAP | BP_PWOFF_OFF_CAP | + BP_PWOFF_CTL_CAP; + } + if ((cap_reg & TAP_SUPPORT_MASK) == TAP_SUPPORT_MASK) { + pbpctl_dev->bp_caps |= + (TAP_CAP | TAP_STATUS_CAP | + TAP_STATUS_CHANGE_CAP | TAP_DIS_CAP | + TAP_DIS_STATUS_CAP | TAP_PWUP_ON_CAP | + TAP_PWUP_OFF_CAP | TAP_PWUP_CTL_CAP); + } + if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER8) { + if ((cap_reg & DISC_SUPPORT_MASK) == + DISC_SUPPORT_MASK) + pbpctl_dev->bp_caps |= + (DISC_CAP | DISC_DIS_CAP | + DISC_PWUP_CTL_CAP); + if ((cap_reg & TPL2_SUPPORT_MASK) == + TPL2_SUPPORT_MASK) { + pbpctl_dev->bp_caps_ex |= TPL2_CAP_EX; + pbpctl_dev->bp_caps |= TPL_CAP; + pbpctl_dev->bp_tpl_flag = + tpl2_flag_status(pbpctl_dev); + } + + } + + if (pbpctl_dev->bp_ext_ver >= BP_FW_EXT_VER9) { + if ((cap_reg & DISC_PORT_SUPPORT_MASK) == + DISC_PORT_SUPPORT_MASK) { + pbpctl_dev->bp_caps_ex |= + DISC_PORT_CAP_EX; + pbpctl_dev->bp_caps |= + (TX_CTL_CAP | TX_STATUS_CAP); + } + + } + + } + if (pbpctl_dev->bp_ext_ver >= PXG2BPI_VER) { + if ((read_reg(pbpctl_dev, STATUS_REG_ADDR)) & + WDT_EN_MASK) + pbpctl_dev->wdt_status = WDT_STATUS_EN; + else + pbpctl_dev->wdt_status = WDT_STATUS_DIS; + } + + } else if ((P2BPFI_IF_SERIES(pbpctl_dev->subdevice)) || + (PEGF5_IF_SERIES(pbpctl_dev->subdevice)) || + (PEGF80_IF_SERIES(pbpctl_dev->subdevice)) || + (BP10G9_IF_SERIES(pbpctl_dev->subdevice))) { + pbpctl_dev->bp_caps |= (TX_CTL_CAP | TX_STATUS_CAP); + } + if ((pbpctl_dev->subdevice & 0xa00) == 0xa00) + pbpctl_dev->bp_caps |= (TX_CTL_CAP | TX_STATUS_CAP); + if (PEG5_IF_SERIES(pbpctl_dev->subdevice)) + pbpctl_dev->bp_caps |= (TX_CTL_CAP | TX_STATUS_CAP); + + if (BP10GB_IF_SERIES(pbpctl_dev->subdevice)) { + pbpctl_dev->bp_caps &= ~(TX_CTL_CAP | TX_STATUS_CAP); + } + pbpctl_dev_m = get_master_port_fn(pbpctl_dev); + if (pbpctl_dev_m != NULL) { + int cap_reg = 0; + if (pbpctl_dev_m->bp_ext_ver >= 0x9) { + cap_reg = get_bp_prod_caps(pbpctl_dev_m); + if ((cap_reg & DISC_PORT_SUPPORT_MASK) == + DISC_PORT_SUPPORT_MASK) + pbpctl_dev->bp_caps |= + (TX_CTL_CAP | TX_STATUS_CAP); + pbpctl_dev->bp_caps_ex |= DISC_PORT_CAP_EX; + } + } +} + +int bypass_off_init(bpctl_dev_t *pbpctl_dev) +{ + int ret = 0; + + if ((ret = cmnd_on(pbpctl_dev)) < 0) + return ret; + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) + return dis_bypass_cap(pbpctl_dev); + wdt_off(pbpctl_dev); + if (pbpctl_dev->bp_caps & BP_CAP) + bypass_off(pbpctl_dev); + if (pbpctl_dev->bp_caps & TAP_CAP) + tap_off(pbpctl_dev); + cmnd_off(pbpctl_dev); + return 0; +} + +void remove_bypass_wd_auto(bpctl_dev_t *pbpctl_dev) +{ +#ifdef BP_SELF_TEST + bpctl_dev_t *pbpctl_dev_sl = NULL; +#endif + + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + + del_timer_sync(&pbpctl_dev->bp_timer); +#ifdef BP_SELF_TEST + pbpctl_dev_sl = get_status_port_fn(pbpctl_dev); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)) + if (pbpctl_dev_sl && (pbpctl_dev_sl->ndev) + && (pbpctl_dev_sl->ndev->hard_start_xmit) + && (pbpctl_dev_sl->hard_start_xmit_save)) { + rtnl_lock(); + pbpctl_dev_sl->ndev->hard_start_xmit = + pbpctl_dev_sl->hard_start_xmit_save; + rtnl_unlock(); + } +#else + if (pbpctl_dev_sl && (pbpctl_dev_sl->ndev)) { + if ((pbpctl_dev_sl->ndev->netdev_ops) + && (pbpctl_dev_sl->old_ops)) { + rtnl_lock(); + pbpctl_dev_sl->ndev->netdev_ops = + pbpctl_dev_sl->old_ops; + pbpctl_dev_sl->old_ops = NULL; + + rtnl_unlock(); + + } + + } + +#endif +#endif + } + +} + +int init_bypass_wd_auto(bpctl_dev_t *pbpctl_dev) +{ + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + init_timer(&pbpctl_dev->bp_timer); + pbpctl_dev->bp_timer.function = &wd_reset_timer; + pbpctl_dev->bp_timer.data = (unsigned long)pbpctl_dev; + return 1; + } + return BP_NOT_CAP; +} + +#ifdef BP_SELF_TEST +int bp_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + bpctl_dev_t *pbpctl_dev = NULL, *pbpctl_dev_m = NULL; + int idx_dev = 0; + struct ethhdr *eth = (struct ethhdr *)skb->data; + + for (idx_dev = 0; + ((bpctl_dev_arr[idx_dev].ndev != NULL) && (idx_dev < device_num)); + idx_dev++) { + if (bpctl_dev_arr[idx_dev].ndev == dev) { + pbpctl_dev = &bpctl_dev_arr[idx_dev]; + break; + } + } + if (!pbpctl_dev) + return 1; + if ((htons(ETH_P_BPTEST) == eth->h_proto)) { + + pbpctl_dev_m = get_master_port_fn(pbpctl_dev); + if (pbpctl_dev_m) { + + if (bypass_status(pbpctl_dev_m)) { + cmnd_on(pbpctl_dev_m); + bypass_off(pbpctl_dev_m); + cmnd_off(pbpctl_dev_m); + } + wdt_timer_reload(pbpctl_dev_m); + } + dev_kfree_skb_irq(skb); + return 0; + } + return pbpctl_dev->hard_start_xmit_save(skb, dev); +} +#endif + +int set_bypass_wd_auto(bpctl_dev_t *pbpctl_dev, unsigned int param) +{ + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + if (pbpctl_dev->reset_time != param) { + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) + pbpctl_dev->reset_time = + (param < + WDT_AUTO_MIN_INT) ? WDT_AUTO_MIN_INT : + param; + else + pbpctl_dev->reset_time = param; + if (param) + mod_timer(&pbpctl_dev->bp_timer, jiffies); + } + return 0; + } + return BP_NOT_CAP; +} + +int get_bypass_wd_auto(bpctl_dev_t *pbpctl_dev) +{ + + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + return pbpctl_dev->reset_time; + } + return BP_NOT_CAP; +} + +#ifdef BP_SELF_TEST + +int set_bp_self_test(bpctl_dev_t *pbpctl_dev, unsigned int param) +{ + bpctl_dev_t *pbpctl_dev_sl = NULL; + + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + pbpctl_dev->bp_self_test_flag = param == 0 ? 0 : 1; + pbpctl_dev_sl = get_status_port_fn(pbpctl_dev); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)) + if ((pbpctl_dev_sl->ndev) && + (pbpctl_dev_sl->ndev->hard_start_xmit)) { + rtnl_lock(); + if (pbpctl_dev->bp_self_test_flag == 1) { + + pbpctl_dev_sl->hard_start_xmit_save = + pbpctl_dev_sl->ndev->hard_start_xmit; + pbpctl_dev_sl->ndev->hard_start_xmit = + bp_hard_start_xmit; + } else if (pbpctl_dev_sl->hard_start_xmit_save) { + pbpctl_dev_sl->ndev->hard_start_xmit = + pbpctl_dev_sl->hard_start_xmit_save; + } + rtnl_unlock(); + } +#else + if ((pbpctl_dev_sl->ndev) && (pbpctl_dev_sl->ndev->netdev_ops)) { + rtnl_lock(); + if (pbpctl_dev->bp_self_test_flag == 1) { + + pbpctl_dev_sl->old_ops = + pbpctl_dev_sl->ndev->netdev_ops; + pbpctl_dev_sl->new_ops = + *pbpctl_dev_sl->old_ops; + pbpctl_dev_sl->new_ops.ndo_start_xmit = + bp_hard_start_xmit; + pbpctl_dev_sl->ndev->netdev_ops = + &pbpctl_dev_sl->new_ops; + + } else if (pbpctl_dev_sl->old_ops) { + pbpctl_dev_sl->ndev->netdev_ops = + pbpctl_dev_sl->old_ops; + pbpctl_dev_sl->old_ops = NULL; + } + rtnl_unlock(); + } +#endif + + set_bypass_wd_auto(pbpctl_dev, param); + return 0; + } + return BP_NOT_CAP; +} + +int get_bp_self_test(bpctl_dev_t *pbpctl_dev) +{ + + if (pbpctl_dev->bp_caps & WD_CTL_CAP) { + if (pbpctl_dev->bp_self_test_flag == 1) + return pbpctl_dev->reset_time; + else + return 0; + } + return BP_NOT_CAP; +} + +#endif + +/**************************************************************/ +/************************* API ********************************/ +/**************************************************************/ + +int is_bypass_fn(bpctl_dev_t *pbpctl_dev) +{ + if (!pbpctl_dev) + return -1; + + return (((pbpctl_dev->func == 0) || (pbpctl_dev->func == 2)) ? 1 : 0); +} + +int set_bypass_fn(bpctl_dev_t *pbpctl_dev, int bypass_mode) +{ + int ret = 0; + + if (!(pbpctl_dev->bp_caps & BP_CAP)) + return BP_NOT_CAP; + if ((ret = cmnd_on(pbpctl_dev)) < 0) + return ret; + if (!bypass_mode) + ret = bypass_off(pbpctl_dev); + else + ret = bypass_on(pbpctl_dev); + cmnd_off(pbpctl_dev); + + return ret; +} + +int get_bypass_fn(bpctl_dev_t *pbpctl_dev) +{ + return bypass_status(pbpctl_dev); +} + +int get_bypass_change_fn(bpctl_dev_t *pbpctl_dev) +{ + if (!pbpctl_dev) + return -1; + + return bypass_change_status(pbpctl_dev); +} + +int set_dis_bypass_fn(bpctl_dev_t *pbpctl_dev, int dis_param) +{ + int ret = 0; + if (!pbpctl_dev) + return -1; + + if (!(pbpctl_dev->bp_caps & BP_DIS_CAP)) + return BP_NOT_CAP; + if ((ret = cmnd_on(pbpctl_dev)) < 0) + return ret; + if (dis_param) + ret = dis_bypass_cap(pbpctl_dev); + else + ret = en_bypass_cap(pbpctl_dev); + cmnd_off(pbpctl_dev); + return ret; +} + +int get_dis_bypass_fn(bpctl_dev_t *pbpctl_dev) +{ + if (!pbpctl_dev) + return -1; + + return dis_bypass_cap_status(pbpctl_dev); +} + +int set_bypass_pwoff_fn(bpctl_dev_t *pbpctl_dev, int bypass_mode) +{ + int ret = 0; + if (!pbpctl_dev) + return -1; + + if (!(pbpctl_dev->bp_caps & BP_PWOFF_CTL_CAP)) + return BP_NOT_CAP; + if ((ret = cmnd_on(pbpctl_dev)) < 0) + return ret; + if (bypass_mode) + ret = bypass_state_pwroff(pbpctl_dev); + else + ret = normal_state_pwroff(pbpctl_dev); + cmnd_off(pbpctl_dev); + return ret; +} + +int get_bypass_pwoff_fn(bpctl_dev_t *pbpctl_dev) +{ + if (!pbpctl_dev) + return -1; + + return default_pwroff_status(pbpctl_dev); +} + +int set_bypass_pwup_fn(bpctl_dev_t *pbpctl_dev, int bypass_mode) +{ + int ret = 0; + if (!pbpctl_dev) + return -1; + + if (!(pbpctl_dev->bp_caps & BP_PWUP_CTL_CAP)) + return BP_NOT_CAP; + if ((ret = cmnd_on(pbpctl_dev)) < 0) + return ret; + if (bypass_mode) + ret = bypass_state_pwron(pbpctl_dev); + else + ret = normal_state_pwron(pbpctl_dev); + cmnd_off(pbpctl_dev); + return ret; +} + +int get_bypass_pwup_fn(bpctl_dev_t *pbpctl_dev) +{ + if (!pbpctl_dev) + return -1; + + return default_pwron_status(pbpctl_dev); +} + +int set_bypass_wd_fn(bpctl_dev_t *pbpctl_dev, int timeout) +{ + int ret = 0; + if (!pbpctl_dev) + return -1; + + if (!(pbpctl_dev->bp_caps & WD_CTL_CAP)) + return BP_NOT_CAP; + + if ((ret = cmnd_on(pbpctl_dev)) < 0) + return ret; + if (!timeout) + ret = wdt_off(pbpctl_dev); + else { + wdt_on(pbpctl_dev, timeout); + ret = pbpctl_dev->bypass_timer_interval; + } + cmnd_off(pbpctl_dev); + return ret; +} + +int get_bypass_wd_fn(bpctl_dev_t *pbpctl_dev, int *timeout) +{ + if (!pbpctl_dev) + return -1; + + return wdt_programmed(pbpctl_dev, timeout); +} + +int get_wd_expire_time_fn(bpctl_dev_t *pbpctl_dev, int *time_left) +{ + if (!pbpctl_dev) + return -1; + + return wdt_timer(pbpctl_dev, time_left); +} + +int reset_bypass_wd_timer_fn(bpctl_dev_t *pbpctl_dev) +{ + if (!pbpctl_dev) + return -1; + + return wdt_timer_reload(pbpctl_dev); +} + +int get_wd_set_caps_fn(bpctl_dev_t *pbpctl_dev) +{ + int bp_status = 0; + + unsigned int step_value = TIMEOUT_MAX_STEP + 1, bit_cnt = 0; + if (!pbpctl_dev) + return -1; + + if (INTEL_IF_SERIES(pbpctl_dev->subdevice)) + return BP_NOT_CAP; + + while ((step_value >>= 1)) + bit_cnt++; + + if (is_bypass_fn(pbpctl_dev)) { + bp_status = + WD_STEP_COUNT_MASK(bit_cnt) | WDT_STEP_TIME | + WD_MIN_TIME_MASK(TIMEOUT_UNIT / 100); + } else + return -1; + + return bp_status; +} + +int set_std_nic_fn(bpctl_dev_t *pbpctl_dev, int nic_mode) +{ + int ret = 0; + if (!pbpctl_dev) + return -1; + + if (!(pbpctl_dev->bp_caps & STD_NIC_CAP)) + return BP_NOT_CAP; + + if ((ret = cmnd_on(pbpctl_dev)) < 0) + return ret; + if (nic_mode) + ret = std_nic_on(pbpctl_dev); + else + ret = std_nic_off(pbpctl_dev); + cmnd_off(pbpctl_dev); + return ret; +} + +int get_std_nic_fn(bpctl_dev_t *pbpctl_dev) +{ + if (!pbpctl_dev) + return -1; + + return std_nic_status(pbpctl_dev); +} + +int set_tap_fn(bpctl_dev_t *pbpctl_dev, int tap_mode) +{ + if (!pbpctl_dev) + return -1; + + if ((pbpctl_dev->bp_caps & TAP_CAP) && ((cmnd_on(pbpctl_dev)) >= 0)) { + if (!tap_mode) + tap_off(pbpctl_dev); + else + tap_on(pbpctl_dev); + cmnd_off(pbpctl_dev); + return 0; + } + return BP_NOT_CAP; +} + +int get_tap_fn(bpctl_dev_t *pbpctl_dev) +{ + if (!pbpctl_dev) + return -1; + + return tap_status(pbpctl_dev); +} + +int set_tap_pwup_fn(bpctl_dev_t *pbpctl_dev, int tap_mode) +{ + int ret = 0; + if (!pbpctl_dev) + return -1; + + if ((pbpctl_dev->bp_caps & TAP_PWUP_CTL_CAP) + && ((cmnd_on(pbpctl_dev)) >= 0)) { + if (tap_mode) + ret = tap_state_pwron(pbpctl_dev); + else + ret = normal_state_pwron(pbpctl_dev); + cmnd_off(pbpctl_dev); + } else + ret = BP_NOT_CAP; + return ret; +} + +int get_tap_pwup_fn(bpctl_dev_t *pbpctl_dev) +{ + int ret = 0; + if (!pbpctl_dev) + return -1; + + if ((ret = default_pwron_tap_status(pbpctl_dev)) < 0) + return ret; + return ((ret == 0) ? 1 : 0); +} + +int get_tap_change_fn(bpctl_dev_t *pbpctl_dev) +{ + if (!pbpctl_dev) + return -1; + + return tap_change_status(pbpctl_dev); +} + +int set_dis_tap_fn(bpctl_dev_t *pbpctl_dev, int dis_param) +{ + int ret = 0; + if (!pbpctl_dev) + return -1; + + if ((pbpctl_dev->bp_caps & TAP_DIS_CAP) && ((cmnd_on(pbpctl_dev)) >= 0)) { + if (dis_param) + ret = dis_tap_cap(pbpctl_dev); + else + ret = en_tap_cap(pbpctl_dev); + cmnd_off(pbpctl_dev); + return ret; + } else + return BP_NOT_CAP; +} + +int get_dis_tap_fn(bpctl_dev_t *pbpctl_dev) +{ + if (!pbpctl_dev) + return -1; + + return dis_tap_cap_status(pbpctl_dev); +} + +int set_disc_fn(bpctl_dev_t *pbpctl_dev, int disc_mode) +{ + if (!pbpctl_dev) + return -1; + + if ((pbpctl_dev->bp_caps & DISC_CAP) && ((cmnd_on(pbpctl_dev)) >= 0)) { + if (!disc_mode) + disc_off(pbpctl_dev); + else + disc_on(pbpctl_dev); + cmnd_off(pbpctl_dev); + + return BP_OK; + } + return BP_NOT_CAP; +} + +int get_disc_fn(bpctl_dev_t *pbpctl_dev) +{ + int ret = 0; + if (!pbpctl_dev) + return -1; + + ret = disc_status(pbpctl_dev); + + return ret; +} + +int set_disc_pwup_fn(bpctl_dev_t *pbpctl_dev, int disc_mode) +{ + int ret = 0; + if (!pbpctl_dev) + return -1; + + if ((pbpctl_dev->bp_caps & DISC_PWUP_CTL_CAP) + && ((cmnd_on(pbpctl_dev)) >= 0)) { + if (disc_mode) + ret = disc_state_pwron(pbpctl_dev); + else + ret = normal_state_pwron(pbpctl_dev); + cmnd_off(pbpctl_dev); + } else + ret = BP_NOT_CAP; + return ret; +} + +int get_disc_pwup_fn(bpctl_dev_t *pbpctl_dev) +{ + int ret = 0; + if (!pbpctl_dev) + return -1; + + ret = default_pwron_disc_status(pbpctl_dev); + return (ret == 0 ? 1 : (ret < 0 ? BP_NOT_CAP : 0)); +} + +int get_disc_change_fn(bpctl_dev_t *pbpctl_dev) +{ + int ret = 0; + if (!pbpctl_dev) + return -1; + + ret = disc_change_status(pbpctl_dev); + return ret; +} + +int set_dis_disc_fn(bpctl_dev_t *pbpctl_dev, int dis_param) +{ + int ret = 0; + if (!pbpctl_dev) + return -1; + + if ((pbpctl_dev->bp_caps & DISC_DIS_CAP) + && ((cmnd_on(pbpctl_dev)) >= 0)) { + if (dis_param) + ret = dis_disc_cap(pbpctl_dev); + else + ret = en_disc_cap(pbpctl_dev); + cmnd_off(pbpctl_dev); + return ret; + } else + return BP_NOT_CAP; +} + +int get_dis_disc_fn(bpctl_dev_t *pbpctl_dev) +{ + int ret = 0; + if (!pbpctl_dev) + return -1; + + ret = dis_disc_cap_status(pbpctl_dev); + + return ret; +} + +int set_disc_port_fn(bpctl_dev_t *pbpctl_dev, int disc_mode) +{ + int ret = BP_NOT_CAP; + if (!pbpctl_dev) + return -1; + + if (!disc_mode) + ret = disc_port_off(pbpctl_dev); + else + ret = disc_port_on(pbpctl_dev); + + return ret; +} + +int get_disc_port_fn(bpctl_dev_t *pbpctl_dev) +{ + if (!pbpctl_dev) + return -1; + + return disc_port_status(pbpctl_dev); +} + +int set_disc_port_pwup_fn(bpctl_dev_t *pbpctl_dev, int disc_mode) +{ + int ret = BP_NOT_CAP; + if (!pbpctl_dev) + return -1; + + if (!disc_mode) + ret = normal_port_state_pwron(pbpctl_dev); + else + ret = disc_port_state_pwron(pbpctl_dev); + + return ret; +} + +int get_disc_port_pwup_fn(bpctl_dev_t *pbpctl_dev) +{ + int ret = 0; + if (!pbpctl_dev) + return -1; + + if ((ret = default_pwron_disc_port_status(pbpctl_dev)) < 0) + return ret; + return ((ret == 0) ? 1 : 0); +} + +int get_wd_exp_mode_fn(bpctl_dev_t *pbpctl_dev) +{ + if (!pbpctl_dev) + return -1; + + return wdt_exp_mode_status(pbpctl_dev); +} + +int set_wd_exp_mode_fn(bpctl_dev_t *pbpctl_dev, int param) +{ + if (!pbpctl_dev) + return -1; + + return wdt_exp_mode(pbpctl_dev, param); +} + +int reset_cont_fn(bpctl_dev_t *pbpctl_dev) +{ + int ret = 0; + if (!pbpctl_dev) + return -1; + + if ((ret = cmnd_on(pbpctl_dev)) < 0) + return ret; + return reset_cont(pbpctl_dev); +} + +int set_tx_fn(bpctl_dev_t *pbpctl_dev, int tx_state) +{ + + bpctl_dev_t *pbpctl_dev_b = NULL; + if (!pbpctl_dev) + return -1; + + if ((pbpctl_dev->bp_caps & TPL_CAP) && + (pbpctl_dev->bp_caps & SW_CTL_CAP)) { + if ((pbpctl_dev->bp_tpl_flag)) + return BP_NOT_CAP; + } else if ((pbpctl_dev_b = get_master_port_fn(pbpctl_dev))) { + if ((pbpctl_dev_b->bp_caps & TPL_CAP) && + (pbpctl_dev_b->bp_tpl_flag)) + return BP_NOT_CAP; + } + return set_tx(pbpctl_dev, tx_state); +} + +int set_bp_force_link_fn(int dev_num, int tx_state) +{ + static bpctl_dev_t *bpctl_dev_curr; + + if ((dev_num < 0) || (dev_num > device_num) + || (bpctl_dev_arr[dev_num].pdev == NULL)) + return -1; + bpctl_dev_curr = &bpctl_dev_arr[dev_num]; + + return set_bp_force_link(bpctl_dev_curr, tx_state); +} + +int set_wd_autoreset_fn(bpctl_dev_t *pbpctl_dev, int param) +{ + if (!pbpctl_dev) + return -1; + + return set_bypass_wd_auto(pbpctl_dev, param); +} + +int get_wd_autoreset_fn(bpctl_dev_t *pbpctl_dev) +{ + if (!pbpctl_dev) + return -1; + + return get_bypass_wd_auto(pbpctl_dev); +} + +#ifdef BP_SELF_TEST +int set_bp_self_test_fn(bpctl_dev_t *pbpctl_dev, int param) +{ + if (!pbpctl_dev) + return -1; + + return set_bp_self_test(pbpctl_dev, param); +} + +int get_bp_self_test_fn(bpctl_dev_t *pbpctl_dev) +{ + if (!pbpctl_dev) + return -1; + + return get_bp_self_test(pbpctl_dev); +} + +#endif + +int get_bypass_caps_fn(bpctl_dev_t *pbpctl_dev) +{ + if (!pbpctl_dev) + return -1; + + return pbpctl_dev->bp_caps; + +} + +int get_bypass_slave_fn(bpctl_dev_t *pbpctl_dev, bpctl_dev_t **pbpctl_dev_out) +{ + int idx_dev = 0; + if (!pbpctl_dev) + return -1; + + if ((pbpctl_dev->func == 0) || (pbpctl_dev->func == 2)) { + for (idx_dev = 0; + ((bpctl_dev_arr[idx_dev].pdev != NULL) + && (idx_dev < device_num)); idx_dev++) { + if ((bpctl_dev_arr[idx_dev].bus == pbpctl_dev->bus) + && (bpctl_dev_arr[idx_dev].slot == + pbpctl_dev->slot)) { + if ((pbpctl_dev->func == 0) + && (bpctl_dev_arr[idx_dev].func == 1)) { + *pbpctl_dev_out = + &bpctl_dev_arr[idx_dev]; + return 1; + } + if ((pbpctl_dev->func == 2) && + (bpctl_dev_arr[idx_dev].func == 3)) { + *pbpctl_dev_out = + &bpctl_dev_arr[idx_dev]; + return 1; + } + } + } + return -1; + } else + return 0; +} + +int is_bypass(bpctl_dev_t *pbpctl_dev) +{ + if (!pbpctl_dev) + return -1; + + if ((pbpctl_dev->func == 0) || (pbpctl_dev->func == 2)) + return 1; + else + return 0; +} + +int get_tx_fn(bpctl_dev_t *pbpctl_dev) +{ + bpctl_dev_t *pbpctl_dev_b = NULL; + if (!pbpctl_dev) + return -1; + + if ((pbpctl_dev->bp_caps & TPL_CAP) && + (pbpctl_dev->bp_caps & SW_CTL_CAP)) { + if ((pbpctl_dev->bp_tpl_flag)) + return BP_NOT_CAP; + } else if ((pbpctl_dev_b = get_master_port_fn(pbpctl_dev))) { + if ((pbpctl_dev_b->bp_caps & TPL_CAP) && + (pbpctl_dev_b->bp_tpl_flag)) + return BP_NOT_CAP; + } + return tx_status(pbpctl_dev); +} + +int get_bp_force_link_fn(int dev_num) +{ + static bpctl_dev_t *bpctl_dev_curr; + + if ((dev_num < 0) || (dev_num > device_num) + || (bpctl_dev_arr[dev_num].pdev == NULL)) + return -1; + bpctl_dev_curr = &bpctl_dev_arr[dev_num]; + + return bp_force_link_status(bpctl_dev_curr); +} + +static int get_bypass_link_status(bpctl_dev_t *pbpctl_dev) +{ + if (!pbpctl_dev) + return -1; + + if (pbpctl_dev->media_type == bp_fiber) + return ((BPCTL_READ_REG(pbpctl_dev, CTRL) & + BPCTLI_CTRL_SWDPIN1)); + else + return ((BPCTL_READ_REG(pbpctl_dev, STATUS) & + BPCTLI_STATUS_LU)); + +} + +static void bp_tpl_timer_fn(unsigned long param) +{ + bpctl_dev_t *pbpctl_dev = (bpctl_dev_t *) param; + uint32_t link1, link2; + bpctl_dev_t *pbpctl_dev_b = NULL; + + if (!(pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) + return; + + if (!pbpctl_dev->bp_tpl_flag) { + set_tx(pbpctl_dev_b, 1); + set_tx(pbpctl_dev, 1); + return; + } + link1 = get_bypass_link_status(pbpctl_dev); + + link2 = get_bypass_link_status(pbpctl_dev_b); + if ((link1) && (tx_status(pbpctl_dev))) { + if ((!link2) && (tx_status(pbpctl_dev_b))) { + set_tx(pbpctl_dev, 0); + } else if (!tx_status(pbpctl_dev_b)) { + set_tx(pbpctl_dev_b, 1); + } + } else if ((!link1) && (tx_status(pbpctl_dev))) { + if ((link2) && (tx_status(pbpctl_dev_b))) { + set_tx(pbpctl_dev_b, 0); + } + } else if ((link1) && (!tx_status(pbpctl_dev))) { + if ((link2) && (tx_status(pbpctl_dev_b))) { + set_tx(pbpctl_dev, 1); + } + } else if ((!link1) && (!tx_status(pbpctl_dev))) { + if ((link2) && (tx_status(pbpctl_dev_b))) { + set_tx(pbpctl_dev, 1); + } + } + + mod_timer(&pbpctl_dev->bp_tpl_timer, jiffies + BP_LINK_MON_DELAY * HZ); +} + +void remove_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev) +{ + bpctl_dev_t *pbpctl_dev_b = NULL; + if (!pbpctl_dev) + return; + pbpctl_dev_b = get_status_port_fn(pbpctl_dev); + + if (pbpctl_dev->bp_caps & TPL_CAP) { + del_timer_sync(&pbpctl_dev->bp_tpl_timer); + pbpctl_dev->bp_tpl_flag = 0; + pbpctl_dev_b = get_status_port_fn(pbpctl_dev); + if (pbpctl_dev_b) + set_tx(pbpctl_dev_b, 1); + set_tx(pbpctl_dev, 1); + } + return; +} + +int init_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev) +{ + if (!pbpctl_dev) + return -1; + if (pbpctl_dev->bp_caps & TPL_CAP) { + init_timer(&pbpctl_dev->bp_tpl_timer); + pbpctl_dev->bp_tpl_timer.function = &bp_tpl_timer_fn; + pbpctl_dev->bp_tpl_timer.data = (unsigned long)pbpctl_dev; + return BP_OK; + } + return BP_NOT_CAP; +} + +int set_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev, unsigned int param) +{ + if (!pbpctl_dev) + return -1; + if (pbpctl_dev->bp_caps & TPL_CAP) { + if ((param) && (!pbpctl_dev->bp_tpl_flag)) { + pbpctl_dev->bp_tpl_flag = param; + mod_timer(&pbpctl_dev->bp_tpl_timer, jiffies + 1); + return BP_OK; + }; + if ((!param) && (pbpctl_dev->bp_tpl_flag)) + remove_bypass_tpl_auto(pbpctl_dev); + + return BP_OK; + } + return BP_NOT_CAP; +} + +int get_bypass_tpl_auto(bpctl_dev_t *pbpctl_dev) +{ + if (!pbpctl_dev) + return -1; + if (pbpctl_dev->bp_caps & TPL_CAP) { + return pbpctl_dev->bp_tpl_flag; + } + return BP_NOT_CAP; +} + +int set_tpl_fn(bpctl_dev_t *pbpctl_dev, int tpl_mode) +{ + + bpctl_dev_t *pbpctl_dev_b = NULL; + if (!pbpctl_dev) + return -1; + + pbpctl_dev_b = get_status_port_fn(pbpctl_dev); + + if (pbpctl_dev->bp_caps & TPL_CAP) { + if (tpl_mode) { + if ((pbpctl_dev_b = get_status_port_fn(pbpctl_dev))) + set_tx(pbpctl_dev_b, 1); + set_tx(pbpctl_dev, 1); + } + if ((TPL_IF_SERIES(pbpctl_dev->subdevice)) || + (pbpctl_dev->bp_caps_ex & TPL2_CAP_EX)) { + pbpctl_dev->bp_tpl_flag = tpl_mode; + if (!tpl_mode) + tpl_hw_off(pbpctl_dev); + else + tpl_hw_on(pbpctl_dev); + } else + set_bypass_tpl_auto(pbpctl_dev, tpl_mode); + return 0; + } + return BP_NOT_CAP; +} + +int get_tpl_fn(bpctl_dev_t *pbpctl_dev) +{ + int ret = BP_NOT_CAP; + if (!pbpctl_dev) + return -1; + + if (pbpctl_dev->bp_caps & TPL_CAP) { + if (pbpctl_dev->bp_caps_ex & TPL2_CAP_EX) + return tpl2_flag_status(pbpctl_dev); + ret = pbpctl_dev->bp_tpl_flag; + } + return ret; +} + +int set_bp_wait_at_pwup_fn(bpctl_dev_t *pbpctl_dev, int tap_mode) +{ + if (!pbpctl_dev) + return -1; + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + /* bp_lock(pbp_device_block); */ + cmnd_on(pbpctl_dev); + if (!tap_mode) + bp_wait_at_pwup_dis(pbpctl_dev); + else + bp_wait_at_pwup_en(pbpctl_dev); + cmnd_off(pbpctl_dev); + + /* bp_unlock(pbp_device_block); */ + return BP_OK; + } + return BP_NOT_CAP; +} + +int get_bp_wait_at_pwup_fn(bpctl_dev_t *pbpctl_dev) +{ + int ret = 0; + if (!pbpctl_dev) + return -1; + + /* bp_lock(pbp_device_block); */ + ret = bp_wait_at_pwup_status(pbpctl_dev); + /* bp_unlock(pbp_device_block); */ + + return ret; +} + +int set_bp_hw_reset_fn(bpctl_dev_t *pbpctl_dev, int tap_mode) +{ + if (!pbpctl_dev) + return -1; + + if (pbpctl_dev->bp_caps & SW_CTL_CAP) { + /* bp_lock(pbp_device_block); */ + cmnd_on(pbpctl_dev); + + if (!tap_mode) + bp_hw_reset_dis(pbpctl_dev); + else + bp_hw_reset_en(pbpctl_dev); + cmnd_off(pbpctl_dev); + /* bp_unlock(pbp_device_block); */ + return BP_OK; + } + return BP_NOT_CAP; +} + +int get_bp_hw_reset_fn(bpctl_dev_t *pbpctl_dev) +{ + int ret = 0; + if (!pbpctl_dev) + return -1; + + /* bp_lock(pbp_device_block); */ + ret = bp_hw_reset_status(pbpctl_dev); + + /* bp_unlock(pbp_device_block); */ + + return ret; +} + + +int get_bypass_info_fn(bpctl_dev_t *pbpctl_dev, char *dev_name, + char *add_param) +{ + if (!pbpctl_dev) + return -1; + if (!is_bypass_fn(pbpctl_dev)) + return -1; + strcpy(dev_name, pbpctl_dev->name); + *add_param = pbpctl_dev->bp_fw_ver; + return 0; +} + +int get_dev_idx_bsf(int bus, int slot, int func) +{ + int idx_dev = 0; + for (idx_dev = 0; + ((bpctl_dev_arr[idx_dev].pdev != NULL) && (idx_dev < device_num)); + idx_dev++) { + if ((bus == bpctl_dev_arr[idx_dev].bus) + && (slot == bpctl_dev_arr[idx_dev].slot) + && (func == bpctl_dev_arr[idx_dev].func)) + + return idx_dev; + } + return -1; +} + +static void str_low(char *str) +{ + int i; + + for (i = 0; i < strlen(str); i++) + if ((str[i] >= 65) && (str[i] <= 90)) + str[i] += 32; +} + +static unsigned long str_to_hex(char *p) +{ + unsigned long hex = 0; + unsigned long length = strlen(p), shift = 0; + unsigned char dig = 0; + + str_low(p); + length = strlen(p); + + if (length == 0) + return 0; + + do { + dig = p[--length]; + dig = dig < 'a' ? (dig - '0') : (dig - 'a' + 0xa); + hex |= (dig << shift); + shift += 4; + } while (length); + return hex; +} + +static int get_dev_idx(int ifindex) +{ + int idx_dev = 0; + + for (idx_dev = 0; + ((bpctl_dev_arr[idx_dev].pdev != NULL) && (idx_dev < device_num)); + idx_dev++) { + if (ifindex == bpctl_dev_arr[idx_dev].ifindex) + return idx_dev; + } + + return -1; +} + +static bpctl_dev_t *get_dev_idx_p(int ifindex) +{ + int idx_dev = 0; + + for (idx_dev = 0; + ((bpctl_dev_arr[idx_dev].pdev != NULL) && (idx_dev < device_num)); + idx_dev++) { + if (ifindex == bpctl_dev_arr[idx_dev].ifindex) + return &bpctl_dev_arr[idx_dev]; + } + + return NULL; +} + +static void if_scan_init(void) +{ + int idx_dev = 0; + struct net_device *dev; + int ifindex; + /* rcu_read_lock(); */ + /* rtnl_lock(); */ + /* rcu_read_lock(); */ +#if 1 +#if (LINUX_VERSION_CODE >= 0x020618) + for_each_netdev(&init_net, dev) +#elif (LINUX_VERSION_CODE >= 0x20616) + for_each_netdev(dev) +#else + for (dev = dev_base; dev; dev = dev->next) +#endif + { + + struct ethtool_drvinfo drvinfo; + char cbuf[32]; + char *buf = NULL; + char res[10]; + int i = 0; + int bus = 0, slot = 0, func = 0; + ifindex = dev->ifindex; + + memset(res, 0, 10); + memset(&drvinfo, 0, sizeof(struct ethtool_drvinfo)); + + if (dev->ethtool_ops && dev->ethtool_ops->get_drvinfo) { + memset(&drvinfo, 0, sizeof(drvinfo)); + dev->ethtool_ops->get_drvinfo(dev, &drvinfo); + } else + continue; + if (!drvinfo.bus_info) + continue; + if (!strcmp(drvinfo.bus_info, "N/A")) + continue; + memcpy(&cbuf, drvinfo.bus_info, 32); + buf = &cbuf[0]; + + while (*buf++ != ':') ; + for (i = 0; i < 10; i++, buf++) { + if (*buf == ':') + break; + res[i] = *buf; + + } + buf++; + bus = str_to_hex(res); + memset(res, 0, 10); + + for (i = 0; i < 10; i++, buf++) { + if (*buf == '.') + break; + res[i] = *buf; + + } + buf++; + slot = str_to_hex(res); + func = str_to_hex(buf); + idx_dev = get_dev_idx_bsf(bus, slot, func); + + if (idx_dev != -1) { + + bpctl_dev_arr[idx_dev].ifindex = ifindex; + bpctl_dev_arr[idx_dev].ndev = dev; + + } + + } +#endif + /* rtnl_unlock(); */ + /* rcu_read_unlock(); */ + +} + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) +static int device_ioctl(struct inode *inode, /* see include/linux/fs.h */ + struct file *file, /* ditto */ + unsigned int ioctl_num, /* number and param for ioctl */ + unsigned long ioctl_param) +#else +static long device_ioctl(struct file *file, /* ditto */ + unsigned int ioctl_num, /* number and param for ioctl */ + unsigned long ioctl_param) +#endif +{ + struct bpctl_cmd bpctl_cmd; + int dev_idx = 0; + bpctl_dev_t *pbpctl_dev_out; + void __user *argp = (void __user *)ioctl_param; + int ret = 0; + unsigned long flags; + + static bpctl_dev_t *pbpctl_dev; + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)) + /* lock_kernel(); */ +#endif + lock_bpctl(); + /* local_irq_save(flags); */ + /* if(!spin_trylock_irqsave(&bpvm_lock)){ + local_irq_restore(flags); + unlock_bpctl(); + unlock_kernel(); + return -1; + } */ + /* spin_lock_irqsave(&bpvm_lock, flags); */ + +/* +* Switch according to the ioctl called +*/ + if (ioctl_num == IOCTL_TX_MSG(IF_SCAN)) { + if_scan_init(); + ret = SUCCESS; + goto bp_exit; + } + if (copy_from_user(&bpctl_cmd, argp, sizeof(struct bpctl_cmd))) { + + ret = -EFAULT; + goto bp_exit; + } + + if (ioctl_num == IOCTL_TX_MSG(GET_DEV_NUM)) { + bpctl_cmd.out_param[0] = device_num; + if (copy_to_user + (argp, (void *)&bpctl_cmd, sizeof(struct bpctl_cmd))) { + ret = -EFAULT; + goto bp_exit; + } + ret = SUCCESS; + goto bp_exit; + + } + /* lock_bpctl(); */ + /* preempt_disable(); */ + local_irq_save(flags); + if (!spin_trylock(&bpvm_lock)) { + local_irq_restore(flags); + unlock_bpctl(); + return -1; + } + +/* preempt_disable(); + rcu_read_lock(); + spin_lock_irqsave(&bpvm_lock, flags); +*/ + if ((bpctl_cmd.in_param[5]) || + (bpctl_cmd.in_param[6]) || (bpctl_cmd.in_param[7])) + dev_idx = get_dev_idx_bsf(bpctl_cmd.in_param[5], + bpctl_cmd.in_param[6], + bpctl_cmd.in_param[7]); + else if (bpctl_cmd.in_param[1] == 0) + dev_idx = bpctl_cmd.in_param[0]; + else + dev_idx = get_dev_idx(bpctl_cmd.in_param[1]); + + if (dev_idx < 0 || dev_idx > device_num) { + /* unlock_bpctl(); + preempt_enable(); */ + ret = -EOPNOTSUPP; + /* preempt_enable(); + rcu_read_unlock(); */ + spin_unlock_irqrestore(&bpvm_lock, flags); + goto bp_exit; + } + + bpctl_cmd.out_param[0] = bpctl_dev_arr[dev_idx].bus; + bpctl_cmd.out_param[1] = bpctl_dev_arr[dev_idx].slot; + bpctl_cmd.out_param[2] = bpctl_dev_arr[dev_idx].func; + bpctl_cmd.out_param[3] = bpctl_dev_arr[dev_idx].ifindex; + + if ((bpctl_dev_arr[dev_idx].bp_10gb) + && (!(bpctl_dev_arr[dev_idx].ifindex))) { + printk("Please load network driver for %s adapter!\n", + bpctl_dev_arr[dev_idx].name); + bpctl_cmd.status = -1; + ret = SUCCESS; + /* preempt_enable(); */ + /* rcu_read_unlock(); */ + spin_unlock_irqrestore(&bpvm_lock, flags); + goto bp_exit; + + } + if ((bpctl_dev_arr[dev_idx].bp_10gb) && (bpctl_dev_arr[dev_idx].ndev)) { + if (!(bpctl_dev_arr[dev_idx].ndev->flags & IFF_UP)) { + if (!(bpctl_dev_arr[dev_idx].ndev->flags & IFF_UP)) { + printk + ("Please bring up network interfaces for %s adapter!\n", + bpctl_dev_arr[dev_idx].name); + bpctl_cmd.status = -1; + ret = SUCCESS; + /* preempt_enable(); */ + /* rcu_read_unlock(); */ + spin_unlock_irqrestore(&bpvm_lock, flags); + goto bp_exit; + } + + } + } + + if ((dev_idx < 0) || (dev_idx > device_num) + || (bpctl_dev_arr[dev_idx].pdev == NULL)) { + bpctl_cmd.status = -1; + goto bpcmd_exit; + } + + pbpctl_dev = &bpctl_dev_arr[dev_idx]; + + switch (ioctl_num) { + case IOCTL_TX_MSG(SET_BYPASS_PWOFF): + bpctl_cmd.status = + set_bypass_pwoff_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_BYPASS_PWOFF): + bpctl_cmd.status = get_bypass_pwoff_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(SET_BYPASS_PWUP): + bpctl_cmd.status = + set_bypass_pwup_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_BYPASS_PWUP): + bpctl_cmd.status = get_bypass_pwup_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(SET_BYPASS_WD): + bpctl_cmd.status = + set_bypass_wd_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_BYPASS_WD): + bpctl_cmd.status = + get_bypass_wd_fn(pbpctl_dev, (int *)&(bpctl_cmd.data[0])); + break; + + case IOCTL_TX_MSG(GET_WD_EXPIRE_TIME): + bpctl_cmd.status = + get_wd_expire_time_fn(pbpctl_dev, + (int *)&(bpctl_cmd.data[0])); + break; + + case IOCTL_TX_MSG(RESET_BYPASS_WD_TIMER): + bpctl_cmd.status = reset_bypass_wd_timer_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(GET_WD_SET_CAPS): + bpctl_cmd.status = get_wd_set_caps_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(SET_STD_NIC): + bpctl_cmd.status = + set_std_nic_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_STD_NIC): + bpctl_cmd.status = get_std_nic_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(SET_TAP): + bpctl_cmd.status = + set_tap_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_TAP): + bpctl_cmd.status = get_tap_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(GET_TAP_CHANGE): + bpctl_cmd.status = get_tap_change_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(SET_DIS_TAP): + bpctl_cmd.status = + set_dis_tap_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_DIS_TAP): + bpctl_cmd.status = get_dis_tap_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(SET_TAP_PWUP): + bpctl_cmd.status = + set_tap_pwup_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_TAP_PWUP): + bpctl_cmd.status = get_tap_pwup_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(SET_WD_EXP_MODE): + bpctl_cmd.status = + set_wd_exp_mode_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_WD_EXP_MODE): + bpctl_cmd.status = get_wd_exp_mode_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(GET_DIS_BYPASS): + bpctl_cmd.status = get_dis_bypass_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(SET_DIS_BYPASS): + bpctl_cmd.status = + set_dis_bypass_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_BYPASS_CHANGE): + bpctl_cmd.status = get_bypass_change_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(GET_BYPASS): + bpctl_cmd.status = get_bypass_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(SET_BYPASS): + bpctl_cmd.status = + set_bypass_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_BYPASS_CAPS): + bpctl_cmd.status = get_bypass_caps_fn(pbpctl_dev); + /*preempt_enable(); */ + /*rcu_read_unlock();*/ + spin_unlock_irqrestore(&bpvm_lock, flags); + if (copy_to_user + (argp, (void *)&bpctl_cmd, sizeof(struct bpctl_cmd))) { + /*unlock_bpctl(); */ + /*preempt_enable(); */ + ret = -EFAULT; + goto bp_exit; + } + goto bp_exit; + + case IOCTL_TX_MSG(GET_BYPASS_SLAVE): + bpctl_cmd.status = + get_bypass_slave_fn(pbpctl_dev, &pbpctl_dev_out); + if (bpctl_cmd.status == 1) { + bpctl_cmd.out_param[4] = pbpctl_dev_out->bus; + bpctl_cmd.out_param[5] = pbpctl_dev_out->slot; + bpctl_cmd.out_param[6] = pbpctl_dev_out->func; + bpctl_cmd.out_param[7] = pbpctl_dev_out->ifindex; + } + break; + + case IOCTL_TX_MSG(IS_BYPASS): + bpctl_cmd.status = is_bypass(pbpctl_dev); + break; + case IOCTL_TX_MSG(SET_TX): + bpctl_cmd.status = set_tx_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + case IOCTL_TX_MSG(GET_TX): + bpctl_cmd.status = get_tx_fn(pbpctl_dev); + break; + case IOCTL_TX_MSG(SET_WD_AUTORESET): + bpctl_cmd.status = + set_wd_autoreset_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + + break; + case IOCTL_TX_MSG(GET_WD_AUTORESET): + + bpctl_cmd.status = get_wd_autoreset_fn(pbpctl_dev); + break; + case IOCTL_TX_MSG(SET_DISC): + bpctl_cmd.status = + set_disc_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + case IOCTL_TX_MSG(GET_DISC): + bpctl_cmd.status = get_disc_fn(pbpctl_dev); + break; + case IOCTL_TX_MSG(GET_DISC_CHANGE): + bpctl_cmd.status = get_disc_change_fn(pbpctl_dev); + break; + case IOCTL_TX_MSG(SET_DIS_DISC): + bpctl_cmd.status = + set_dis_disc_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + case IOCTL_TX_MSG(GET_DIS_DISC): + bpctl_cmd.status = get_dis_disc_fn(pbpctl_dev); + break; + case IOCTL_TX_MSG(SET_DISC_PWUP): + bpctl_cmd.status = + set_disc_pwup_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + case IOCTL_TX_MSG(GET_DISC_PWUP): + bpctl_cmd.status = get_disc_pwup_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(GET_BYPASS_INFO): + + bpctl_cmd.status = + get_bypass_info_fn(pbpctl_dev, (char *)&bpctl_cmd.data, + (char *)&bpctl_cmd.out_param[4]); + break; + + case IOCTL_TX_MSG(SET_TPL): + bpctl_cmd.status = + set_tpl_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_TPL): + bpctl_cmd.status = get_tpl_fn(pbpctl_dev); + break; + case IOCTL_TX_MSG(SET_BP_WAIT_AT_PWUP): + bpctl_cmd.status = + set_bp_wait_at_pwup_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_BP_WAIT_AT_PWUP): + bpctl_cmd.status = get_bp_wait_at_pwup_fn(pbpctl_dev); + break; + case IOCTL_TX_MSG(SET_BP_HW_RESET): + bpctl_cmd.status = + set_bp_hw_reset_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_BP_HW_RESET): + bpctl_cmd.status = get_bp_hw_reset_fn(pbpctl_dev); + break; +#ifdef BP_SELF_TEST + case IOCTL_TX_MSG(SET_BP_SELF_TEST): + bpctl_cmd.status = + set_bp_self_test_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + + break; + case IOCTL_TX_MSG(GET_BP_SELF_TEST): + bpctl_cmd.status = get_bp_self_test_fn(pbpctl_dev); + break; + +#endif +#if 0 + case IOCTL_TX_MSG(SET_DISC_PORT): + bpctl_cmd.status = + set_disc_port_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_DISC_PORT): + bpctl_cmd.status = get_disc_port_fn(pbpctl_dev); + break; + + case IOCTL_TX_MSG(SET_DISC_PORT_PWUP): + bpctl_cmd.status = + set_disc_port_pwup_fn(pbpctl_dev, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_DISC_PORT_PWUP): + bpctl_cmd.status = get_disc_port_pwup_fn(pbpctl_dev); + break; +#endif + case IOCTL_TX_MSG(SET_BP_FORCE_LINK): + bpctl_cmd.status = + set_bp_force_link_fn(dev_idx, bpctl_cmd.in_param[2]); + break; + + case IOCTL_TX_MSG(GET_BP_FORCE_LINK): + bpctl_cmd.status = get_bp_force_link_fn(dev_idx); + break; + + default: + /* unlock_bpctl(); */ + + ret = -EOPNOTSUPP; + /* preempt_enable(); */ + /* rcu_read_unlock();*/ + spin_unlock_irqrestore(&bpvm_lock, flags); + goto bp_exit; + } + /* unlock_bpctl(); */ + /* preempt_enable(); */ + bpcmd_exit: + /* rcu_read_unlock(); */ + spin_unlock_irqrestore(&bpvm_lock, flags); + if (copy_to_user(argp, (void *)&bpctl_cmd, sizeof(struct bpctl_cmd))) + ret = -EFAULT; + ret = SUCCESS; + bp_exit: +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,30)) + /* unlock_kernel(); */ +#endif + /* spin_unlock_irqrestore(&bpvm_lock, flags); */ + unlock_bpctl(); + /* unlock_kernel(); */ + return ret; +} + +struct file_operations Fops = { + .owner = THIS_MODULE, +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)) + .ioctl = device_ioctl, +#else + .unlocked_ioctl = device_ioctl, +#endif + + .open = device_open, + .release = device_release, /* a.k.a. close */ +}; + +#ifndef PCI_DEVICE +#define PCI_DEVICE(vend,dev) \ + .vendor = (vend), .device = (dev), \ + .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID +#endif + +#define SILICOM_E1000BP_ETHERNET_DEVICE(device_id) {\ + PCI_DEVICE(SILICOM_VID, device_id)} + +typedef enum { + PXG2BPFI, + PXG2BPFIL, + PXG2BPFILX, + PXG2BPFILLX, + PXGBPI, + PXGBPIG, + PXG2TBFI, + PXG4BPI, + PXG4BPFI, + PEG4BPI, + PEG2BPI, + PEG4BPIN, + PEG2BPFI, + PEG2BPFILX, + PMCXG2BPFI, + PMCXG2BPFIN, + PEG4BPII, + PEG4BPFII, + PXG4BPFILX, + PMCXG2BPIN, + PMCXG4BPIN, + PXG2BISC1, + PEG2TBFI, + PXG2TBI, + PXG4BPFID, + PEG4BPFI, + PEG4BPIPT, + PXG6BPI, + PEG4BPIL, + PMCXG2BPIN2, + PMCXG4BPIN2, + PMCX2BPI, + PEG2BPFID, + PEG2BPFIDLX, + PMCX4BPI, + MEG2BPFILN, + MEG2BPFINX, + PEG4BPFILX, + PE10G2BPISR, + PE10G2BPILR, + MHIO8AD, + PE10G2BPICX4, + PEG2BPI5, + PEG6BPI, + PEG4BPFI5, + PEG4BPFI5LX, + MEG2BPFILXLN, + PEG2BPIX1, + MEG2BPFILXNX, + XE10G2BPIT, + XE10G2BPICX4, + XE10G2BPISR, + XE10G2BPILR, + PEG4BPIIO, + XE10G2BPIXR, + PE10GDBISR, + PE10GDBILR, + PEG2BISC6, + PEG6BPIFC, + PE10G2BPTCX4, + PE10G2BPTSR, + PE10G2BPTLR, + PE10G2BPTT, + PEG4BPI6, + PEG4BPFI6, + PEG4BPFI6LX, + PEG4BPFI6ZX, + PEG2BPI6, + PEG2BPFI6, + PEG2BPFI6LX, + PEG2BPFI6ZX, + PEG2BPFI6FLXM, + PEG4BPI6FC, + PEG4BPFI6FC, + PEG4BPFI6FCLX, + PEG4BPFI6FCZX, + PEG6BPI6, + PEG2BPI6SC6, + MEG2BPI6, + XEG2BPI6, + MEG4BPI6, + PEG2BPFI5, + PEG2BPFI5LX, + PXEG4BPFI, + M1EG2BPI6, + M1EG2BPFI6, + M1EG2BPFI6LX, + M1EG2BPFI6ZX, + M1EG4BPI6, + M1EG4BPFI6, + M1EG4BPFI6LX, + M1EG4BPFI6ZX, + M1EG6BPI6, + M1E2G4BPi80, + M1E2G4BPFi80, + M1E2G4BPFi80LX, + M1E2G4BPFi80ZX, + PE210G2SPI9, + M1E10G2BPI9CX4, + M1E10G2BPI9SR, + M1E10G2BPI9LR, + M1E10G2BPI9T, + PE210G2BPI9CX4, + PE210G2BPI9SR, + PE210G2BPI9LR, + PE210G2BPI9T, + M2EG2BPFI6, + M2EG2BPFI6LX, + M2EG2BPFI6ZX, + M2EG4BPI6, + M2EG4BPFI6, + M2EG4BPFI6LX, + M2EG4BPFI6ZX, + M2EG6BPI6, + PEG2DBI6, + PEG2DBFI6, + PEG2DBFI6LX, + PEG2DBFI6ZX, + PE2G4BPi80, + PE2G4BPFi80, + PE2G4BPFi80LX, + PE2G4BPFi80ZX, + PE2G4BPi80L, + M6E2G8BPi80A, + + PE2G2BPi35, + PAC1200BPi35, + PE2G2BPFi35, + PE2G2BPFi35LX, + PE2G2BPFi35ZX, + PE2G4BPi35, + PE2G4BPi35L, + PE2G4BPFi35, + PE2G4BPFi35LX, + PE2G4BPFi35ZX, + + PE2G6BPi35, + PE2G6BPi35CX, + + PE2G2BPi80, + PE2G2BPFi80, + PE2G2BPFi80LX, + PE2G2BPFi80ZX, + M2E10G2BPI9CX4, + M2E10G2BPI9SR, + M2E10G2BPI9LR, + M2E10G2BPI9T, + M6E2G8BPi80, + PE210G2DBi9SR, + PE210G2DBi9SRRB, + PE210G2DBi9LR, + PE210G2DBi9LRRB, + PE310G4DBi940SR, + PE310G4BPi9T, + PE310G4BPi9SR, + PE310G4BPi9LR, + PE210G2BPi40, +} board_t; + +typedef struct _bpmod_info_t { + unsigned int vendor; + unsigned int device; + unsigned int subvendor; + unsigned int subdevice; + unsigned int index; + char *bp_name; + +} bpmod_info_t; + +typedef struct _dev_desc { + char *name; +} dev_desc_t; + +dev_desc_t dev_desc[] = { + {"Silicom Bypass PXG2BPFI-SD series adapter"}, + {"Silicom Bypass PXG2BPFIL-SD series adapter"}, + {"Silicom Bypass PXG2BPFILX-SD series adapter"}, + {"Silicom Bypass PXG2BPFILLX-SD series adapter"}, + {"Silicom Bypass PXG2BPI-SD series adapter"}, + {"Silicom Bypass PXG2BPIG-SD series adapter"}, + {"Silicom Bypass PXG2TBFI-SD series adapter"}, + {"Silicom Bypass PXG4BPI-SD series adapter"}, + {"Silicom Bypass PXG4BPFI-SD series adapter"}, + {"Silicom Bypass PEG4BPI-SD series adapter"}, + {"Silicom Bypass PEG2BPI-SD series adapter"}, + {"Silicom Bypass PEG4BPIN-SD series adapter"}, + {"Silicom Bypass PEG2BPFI-SD series adapter"}, + {"Silicom Bypass PEG2BPFI-LX-SD series adapter"}, + {"Silicom Bypass PMCX2BPFI-SD series adapter"}, + {"Silicom Bypass PMCX2BPFI-N series adapter"}, + {"Intel Bypass PEG2BPII series adapter"}, + {"Intel Bypass PEG2BPFII series adapter"}, + {"Silicom Bypass PXG4BPFILX-SD series adapter"}, + {"Silicom Bypass PMCX2BPI-N series adapter"}, + {"Silicom Bypass PMCX4BPI-N series adapter"}, + {"Silicom Bypass PXG2BISC1-SD series adapter"}, + {"Silicom Bypass PEG2TBFI-SD series adapter"}, + {"Silicom Bypass PXG2TBI-SD series adapter"}, + {"Silicom Bypass PXG4BPFID-SD series adapter"}, + {"Silicom Bypass PEG4BPFI-SD series adapter"}, + {"Silicom Bypass PEG4BPIPT-SD series adapter"}, + {"Silicom Bypass PXG6BPI-SD series adapter"}, + {"Silicom Bypass PEG4BPIL-SD series adapter"}, + {"Silicom Bypass PMCX2BPI-N2 series adapter"}, + {"Silicom Bypass PMCX4BPI-N2 series adapter"}, + {"Silicom Bypass PMCX2BPI-SD series adapter"}, + {"Silicom Bypass PEG2BPFID-SD series adapter"}, + {"Silicom Bypass PEG2BPFIDLX-SD series adapter"}, + {"Silicom Bypass PMCX4BPI-SD series adapter"}, + {"Silicom Bypass MEG2BPFILN-SD series adapter"}, + {"Silicom Bypass MEG2BPFINX-SD series adapter"}, + {"Silicom Bypass PEG4BPFILX-SD series adapter"}, + {"Silicom Bypass PE10G2BPISR-SD series adapter"}, + {"Silicom Bypass PE10G2BPILR-SD series adapter"}, + {"Silicom Bypass MHIO8AD-SD series adapter"}, + {"Silicom Bypass PE10G2BPICX4-SD series adapter"}, + {"Silicom Bypass PEG2BPI5-SD series adapter"}, + {"Silicom Bypass PEG6BPI5-SD series adapter"}, + {"Silicom Bypass PEG4BPFI5-SD series adapter"}, + {"Silicom Bypass PEG4BPFI5LX-SD series adapter"}, + {"Silicom Bypass MEG2BPFILXLN-SD series adapter"}, + {"Silicom Bypass PEG2BPIX1-SD series adapter"}, + {"Silicom Bypass MEG2BPFILXNX-SD series adapter"}, + {"Silicom Bypass XE10G2BPIT-SD series adapter"}, + {"Silicom Bypass XE10G2BPICX4-SD series adapter"}, + {"Silicom Bypass XE10G2BPISR-SD series adapter"}, + {"Silicom Bypass XE10G2BPILR-SD series adapter"}, + {"Intel Bypass PEG2BPFII0 series adapter"}, + {"Silicom Bypass XE10G2BPIXR series adapter"}, + {"Silicom Bypass PE10G2DBISR series adapter"}, + {"Silicom Bypass PEG2BI5SC6 series adapter"}, + {"Silicom Bypass PEG6BPI5FC series adapter"}, + + {"Silicom Bypass PE10G2BPTCX4 series adapter"}, + {"Silicom Bypass PE10G2BPTSR series adapter"}, + {"Silicom Bypass PE10G2BPTLR series adapter"}, + {"Silicom Bypass PE10G2BPTT series adapter"}, + {"Silicom Bypass PEG4BPI6 series adapter"}, + {"Silicom Bypass PEG4BPFI6 series adapter"}, + {"Silicom Bypass PEG4BPFI6LX series adapter"}, + {"Silicom Bypass PEG4BPFI6ZX series adapter"}, + {"Silicom Bypass PEG2BPI6 series adapter"}, + {"Silicom Bypass PEG2BPFI6 series adapter"}, + {"Silicom Bypass PEG2BPFI6LX series adapter"}, + {"Silicom Bypass PEG2BPFI6ZX series adapter"}, + {"Silicom Bypass PEG2BPFI6FLXM series adapter"}, + {"Silicom Bypass PEG4BPI6FC series adapter"}, + {"Silicom Bypass PEG4BPFI6FC series adapter"}, + {"Silicom Bypass PEG4BPFI6FCLX series adapter"}, + {"Silicom Bypass PEG4BPFI6FCZX series adapter"}, + {"Silicom Bypass PEG6BPI6 series adapter"}, + {"Silicom Bypass PEG2BPI6SC6 series adapter"}, + {"Silicom Bypass MEG2BPI6 series adapter"}, + {"Silicom Bypass XEG2BPI6 series adapter"}, + {"Silicom Bypass MEG4BPI6 series adapter"}, + {"Silicom Bypass PEG2BPFI5-SD series adapter"}, + {"Silicom Bypass PEG2BPFI5LX-SD series adapter"}, + {"Silicom Bypass PXEG4BPFI-SD series adapter"}, + {"Silicom Bypass MxEG2BPI6 series adapter"}, + {"Silicom Bypass MxEG2BPFI6 series adapter"}, + {"Silicom Bypass MxEG2BPFI6LX series adapter"}, + {"Silicom Bypass MxEG2BPFI6ZX series adapter"}, + {"Silicom Bypass MxEG4BPI6 series adapter"}, + {"Silicom Bypass MxEG4BPFI6 series adapter"}, + {"Silicom Bypass MxEG4BPFI6LX series adapter"}, + {"Silicom Bypass MxEG4BPFI6ZX series adapter"}, + {"Silicom Bypass MxEG6BPI6 series adapter"}, + {"Silicom Bypass MxE2G4BPi80 series adapter"}, + {"Silicom Bypass MxE2G4BPFi80 series adapter"}, + {"Silicom Bypass MxE2G4BPFi80LX series adapter"}, + {"Silicom Bypass MxE2G4BPFi80ZX series adapter"}, + + {"Silicom Bypass PE210G2SPI9 series adapter"}, + + {"Silicom Bypass MxE210G2BPI9CX4 series adapter"}, + {"Silicom Bypass MxE210G2BPI9SR series adapter"}, + {"Silicom Bypass MxE210G2BPI9LR series adapter"}, + {"Silicom Bypass MxE210G2BPI9T series adapter"}, + + {"Silicom Bypass PE210G2BPI9CX4 series adapter"}, + {"Silicom Bypass PE210G2BPI9SR series adapter"}, + {"Silicom Bypass PE210G2BPI9LR series adapter"}, + {"Silicom Bypass PE210G2BPI9T series adapter"}, + + {"Silicom Bypass M2EG2BPFI6 series adapter"}, + {"Silicom Bypass M2EG2BPFI6LX series adapter"}, + {"Silicom Bypass M2EG2BPFI6ZX series adapter"}, + {"Silicom Bypass M2EG4BPI6 series adapter"}, + {"Silicom Bypass M2EG4BPFI6 series adapter"}, + {"Silicom Bypass M2EG4BPFI6LX series adapter"}, + {"Silicom Bypass M2EG4BPFI6ZX series adapter"}, + {"Silicom Bypass M2EG6BPI6 series adapter"}, + + {"Silicom Bypass PEG2DBI6 series adapter"}, + {"Silicom Bypass PEG2DBFI6 series adapter"}, + {"Silicom Bypass PEG2DBFI6LX series adapter"}, + {"Silicom Bypass PEG2DBFI6ZX series adapter"}, + + {"Silicom Bypass PE2G4BPi80 series adapter"}, + {"Silicom Bypass PE2G4BPFi80 series adapter"}, + {"Silicom Bypass PE2G4BPFi80LX series adapter"}, + {"Silicom Bypass PE2G4BPFi80ZX series adapter"}, + + {"Silicom Bypass PE2G4BPi80L series adapter"}, + {"Silicom Bypass MxE2G8BPi80A series adapter"}, + + {"Silicom Bypass PE2G2BPi35 series adapter"}, + {"Silicom Bypass PAC1200BPi35 series adapter"}, + {"Silicom Bypass PE2G2BPFi35 series adapter"}, + {"Silicom Bypass PE2G2BPFi35LX series adapter"}, + {"Silicom Bypass PE2G2BPFi35ZX series adapter"}, + + {"Silicom Bypass PE2G4BPi35 series adapter"}, + {"Silicom Bypass PE2G4BPi35L series adapter"}, + {"Silicom Bypass PE2G4BPFi35 series adapter"}, + {"Silicom Bypass PE2G4BPFi35LX series adapter"}, + {"Silicom Bypass PE2G4BPFi35ZX series adapter"}, + + {"Silicom Bypass PE2G6BPi35 series adapter"}, + {"Silicom Bypass PE2G6BPi35CX series adapter"}, + + {"Silicom Bypass PE2G2BPi80 series adapter"}, + {"Silicom Bypass PE2G2BPFi80 series adapter"}, + {"Silicom Bypass PE2G2BPFi80LX series adapter"}, + {"Silicom Bypass PE2G2BPFi80ZX series adapter"}, + + {"Silicom Bypass M2E10G2BPI9CX4 series adapter"}, + {"Silicom Bypass M2E10G2BPI9SR series adapter"}, + {"Silicom Bypass M2E10G2BPI9LR series adapter"}, + {"Silicom Bypass M2E10G2BPI9T series adapter"}, + {"Silicom Bypass MxE2G8BPi80 series adapter"}, + {"Silicom Bypass PE210G2DBi9SR series adapter"}, + {"Silicom Bypass PE210G2DBi9SRRB series adapter"}, + {"Silicom Bypass PE210G2DBi9LR series adapter"}, + {"Silicom Bypass PE210G2DBi9LRRB series adapter"}, + {"Silicom Bypass PE310G4DBi9-SR series adapter"}, + {"Silicom Bypass PE310G4BPi9T series adapter"}, + {"Silicom Bypass PE310G4BPi9SR series adapter"}, + {"Silicom Bypass PE310G4BPi9LR series adapter"}, + {"Silicom Bypass PE210G2BPi40T series adapter"}, + {0}, +}; + +static bpmod_info_t tx_ctl_pci_tbl[] = { + {0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG2BPFI_SSID, PXG2BPFI, + "PXG2BPFI-SD"}, + {0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG2BPFIL_SSID, PXG2BPFIL, + "PXG2BPFIL-SD"}, + {0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG2BPFILX_SSID, PXG2BPFILX, + "PXG2BPFILX-SD"}, + {0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG2BPFILLX_SSID, PXG2BPFILLX, + "PXG2BPFILLXSD"}, + {0x8086, 0x1010, SILICOM_SVID, SILICOM_PXGBPI_SSID, PXGBPI, + "PXG2BPI-SD"}, + {0x8086, 0x1079, SILICOM_SVID, SILICOM_PXGBPIG_SSID, PXGBPIG, + "PXG2BPIG-SD"}, + {0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG2TBFI_SSID, PXG2TBFI, + "PXG2TBFI-SD"}, + {0x8086, 0x1079, SILICOM_SVID, SILICOM_PXG4BPI_SSID, PXG4BPI, + "PXG4BPI-SD"}, + {0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG4BPFI_SSID, PXG4BPFI, + "PXG4BPFI-SD"}, + {0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG4BPFILX_SSID, PXG4BPFILX, + "PXG4BPFILX-SD"}, + {0x8086, 0x1079, SILICOM_SVID, SILICOM_PEG4BPI_SSID, PEG4BPI, + "PEXG4BPI-SD"}, + {0x8086, 0x105e, SILICOM_SVID, SILICOM_PEG2BPI_SSID, PEG2BPI, + "PEG2BPI-SD"}, + {0x8086, 0x105e, SILICOM_SVID, SILICOM_PEG4BPIN_SSID, PEG4BPIN, + "PEG4BPI-SD"}, + {0x8086, 0x105f, SILICOM_SVID, SILICOM_PEG2BPFI_SSID, PEG2BPFI, + "PEG2BPFI-SD"}, + {0x8086, 0x105f, SILICOM_SVID, SILICOM_PEG2BPFILX_SSID, PEG2BPFILX, + "PEG2BPFILX-SD"}, + {0x8086, 0x107a, SILICOM_SVID, SILICOM_PMCXG2BPFI_SSID, PMCXG2BPFI, + "PMCX2BPFI-SD"}, + {0x8086, 0x107a, NOKIA_PMCXG2BPFIN_SVID, NOKIA_PMCXG2BPFIN_SSID, + PMCXG2BPFIN, "PMCX2BPFI-N"}, + {0x8086, INTEL_PEG4BPII_PID, 0x8086, INTEL_PEG4BPII_SSID, PEG4BPII, + "PEG4BPII"}, + {0x8086, INTEL_PEG4BPIIO_PID, 0x8086, INTEL_PEG4BPIIO_SSID, PEG4BPIIO, + "PEG4BPII0"}, + {0x8086, INTEL_PEG4BPFII_PID, 0x8086, INTEL_PEG4BPFII_SSID, PEG4BPFII, + "PEG4BPFII"}, + {0x8086, 0x1079, NOKIA_PMCXG2BPFIN_SVID, NOKIA_PMCXG2BPIN_SSID, + PMCXG2BPIN, "PMCX2BPI-N"}, + {0x8086, 0x1079, NOKIA_PMCXG2BPFIN_SVID, NOKIA_PMCXG4BPIN_SSID, + PMCXG4BPIN, "PMCX4BPI-N"}, + {0x8086, 0x1079, SILICOM_SVID, SILICOM_PXG2BISC1_SSID, PXG2BISC1, + "PXG2BISC1-SD"}, + {0x8086, 0x105f, SILICOM_SVID, SILICOM_PEG2TBFI_SSID, PEG2TBFI, + "PEG2TBFI-SD"}, + {0x8086, 0x1079, SILICOM_SVID, SILICOM_PXG2TBI_SSID, PXG2TBI, + "PXG2TBI-SD"}, + {0x8086, 0x107a, SILICOM_SVID, SILICOM_PXG4BPFID_SSID, PXG4BPFID, + "PXG4BPFID-SD"}, + {0x8086, 0x105f, SILICOM_SVID, SILICOM_PEG4BPFI_SSID, PEG4BPFI, + "PEG4BPFI-SD"}, + {0x8086, 0x105e, SILICOM_SVID, SILICOM_PEG4BPIPT_SSID, PEG4BPIPT, + "PEG4BPIPT-SD"}, + {0x8086, 0x1079, SILICOM_SVID, SILICOM_PXG6BPI_SSID, PXG6BPI, + "PXG6BPI-SD"}, + {0x8086, 0x10a7, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG4BPIL_SSID /*PCI_ANY_ID */ , PEG4BPIL, "PEG4BPIL-SD"}, + {0x8086, 0x1079, NOKIA_PMCXG2BPFIN_SVID, NOKIA_PMCXG2BPIN2_SSID, + PMCXG2BPIN2, "PMCX2BPI-N2"}, + {0x8086, 0x1079, NOKIA_PMCXG2BPFIN_SVID, NOKIA_PMCXG4BPIN2_SSID, + PMCXG4BPIN2, "PMCX4BPI-N2"}, + {0x8086, 0x1079, SILICOM_SVID, SILICOM_PMCX2BPI_SSID, PMCX2BPI, + "PMCX2BPI-SD"}, + {0x8086, 0x1079, SILICOM_SVID, SILICOM_PMCX4BPI_SSID, PMCX4BPI, + "PMCX4BPI-SD"}, + {0x8086, 0x105f, SILICOM_SVID, SILICOM_PEG2BPFID_SSID, PEG2BPFID, + "PEG2BPFID-SD"}, + {0x8086, 0x105f, SILICOM_SVID, SILICOM_PEG2BPFIDLX_SSID, PEG2BPFIDLX, + "PEG2BPFIDLXSD"}, + {0x8086, 0x105f, SILICOM_SVID, SILICOM_MEG2BPFILN_SSID, MEG2BPFILN, + "MEG2BPFILN-SD"}, + {0x8086, 0x105f, SILICOM_SVID, SILICOM_MEG2BPFINX_SSID, MEG2BPFINX, + "MEG2BPFINX-SD"}, + {0x8086, 0x105f, SILICOM_SVID, SILICOM_PEG4BPFILX_SSID, PEG4BPFILX, + "PEG4BPFILX-SD"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID, SILICOM_PE10G2BPISR_SSID, + PE10G2BPISR, "PE10G2BPISR"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID, SILICOM_PE10G2BPILR_SSID, + PE10G2BPILR, "PE10G2BPILR"}, + {0x8086, 0x10a9, SILICOM_SVID, SILICOM_MHIO8AD_SSID, MHIO8AD, + "MHIO8AD-SD"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID, SILICOM_PE10G2BPICX4_SSID, + PE10G2BPISR, "PE10G2BPICX4"}, + {0x8086, 0x10a7, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2BPI5_SSID /*PCI_ANY_ID */ , PEG2BPI5, "PEG2BPI5-SD"}, + {0x8086, 0x10a7, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG6BPI_SSID /*PCI_ANY_ID */ , PEG6BPI, "PEG6BPI5"}, + {0x8086, 0x10a9, SILICOM_SVID /*PCI_ANY_ID */ , SILICOM_PEG4BPFI5_SSID, + PEG4BPFI5, "PEG4BPFI5"}, + {0x8086, 0x10a9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG4BPFI5LX_SSID, PEG4BPFI5LX, "PEG4BPFI5LX"}, + {0x8086, 0x105f, SILICOM_SVID, SILICOM_MEG2BPFILXLN_SSID, MEG2BPFILXLN, + "MEG2BPFILXLN"}, + {0x8086, 0x105e, SILICOM_SVID, SILICOM_PEG2BPIX1_SSID, PEG2BPIX1, + "PEG2BPIX1-SD"}, + {0x8086, 0x105f, SILICOM_SVID, SILICOM_MEG2BPFILXNX_SSID, MEG2BPFILXNX, + "MEG2BPFILXNX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID, SILICOM_XE10G2BPIT_SSID, XE10G2BPIT, + "XE10G2BPIT"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID, SILICOM_XE10G2BPICX4_SSID, + XE10G2BPICX4, "XE10G2BPICX4"}, + {0x8086, 0x10C6, SILICOM_SVID, SILICOM_XE10G2BPISR_SSID, XE10G2BPISR, + "XE10G2BPISR"}, + {0x8086, 0x10C6, SILICOM_SVID, SILICOM_XE10G2BPILR_SSID, XE10G2BPILR, + "XE10G2BPILR"}, + {0x8086, 0x10C6, NOKIA_XE10G2BPIXR_SVID, NOKIA_XE10G2BPIXR_SSID, + XE10G2BPIXR, "XE10G2BPIXR"}, + {0x8086, 0x10C6, SILICOM_SVID, SILICOM_PE10GDBISR_SSID, PE10GDBISR, + "PE10G2DBISR"}, + {0x8086, 0x10C6, SILICOM_SVID, SILICOM_PE10GDBILR_SSID, PE10GDBILR, + "PE10G2DBILR"}, + {0x8086, 0x10a7, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2BISC6_SSID /*PCI_ANY_ID */ , PEG2BISC6, "PEG2BI5SC6"}, + {0x8086, 0x10a7, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG6BPIFC_SSID /*PCI_ANY_ID */ , PEG6BPIFC, "PEG6BPI5FC"}, + + {BROADCOM_VID, BROADCOM_PE10G2_PID, SILICOM_SVID, + SILICOM_PE10G2BPTCX4_SSID, PE10G2BPTCX4, "PE10G2BPTCX4"}, + {BROADCOM_VID, BROADCOM_PE10G2_PID, SILICOM_SVID, + SILICOM_PE10G2BPTSR_SSID, PE10G2BPTSR, "PE10G2BPTSR"}, + {BROADCOM_VID, BROADCOM_PE10G2_PID, SILICOM_SVID, + SILICOM_PE10G2BPTLR_SSID, PE10G2BPTLR, "PE10G2BPTLR"}, + {BROADCOM_VID, BROADCOM_PE10G2_PID, SILICOM_SVID, + SILICOM_PE10G2BPTT_SSID, PE10G2BPTT, "PE10G2BPTT"}, + + /* {BROADCOM_VID, BROADCOM_PE10G2_PID, PCI_ANY_ID, PCI_ANY_ID, PE10G2BPTCX4, "PE10G2BPTCX4"}, */ + + {0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG4BPI6_SSID /*PCI_ANY_ID */ , PEG4BPI6, "PEG4BPI6"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG4BPFI6_SSID /*PCI_ANY_ID */ , PEG4BPFI6, "PEG4BPFI6"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG4BPFI6LX_SSID /*PCI_ANY_ID */ , PEG4BPFI6LX, "PEG4BPFI6LX"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG4BPFI6ZX_SSID /*PCI_ANY_ID */ , PEG4BPFI6ZX, "PEG4BPFI6ZX"}, + {0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2BPI6_SSID /*PCI_ANY_ID */ , PEG2BPI6, "PEG2BPI6"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2BPFI6_SSID /*PCI_ANY_ID */ , PEG2BPFI6, "PEG2BPFI6"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2BPFI6LX_SSID /*PCI_ANY_ID */ , PEG2BPFI6LX, "PEG2BPFI6LX"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2BPFI6ZX_SSID /*PCI_ANY_ID */ , PEG2BPFI6ZX, "PEG2BPFI6ZX"}, + {0x8086, 0x10e7, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2BPFI6FLXM_SSID /*PCI_ANY_ID */ , PEG2BPFI6FLXM, + "PEG2BPFI6FLXM"}, + {0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG4BPI6FC_SSID /*PCI_ANY_ID */ , PEG4BPI6FC, "PEG4BPI6FC"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG4BPFI6FC_SSID /*PCI_ANY_ID */ , PEG4BPFI6FC, "PEG4BPFI6FC"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG4BPFI6FCLX_SSID /*PCI_ANY_ID */ , PEG4BPFI6FCLX, + "PEG4BPFI6FCLX"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG4BPFI6FCZX_SSID /*PCI_ANY_ID */ , PEG4BPFI6FCZX, + "PEG4BPFI6FCZX"}, + {0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG6BPI6_SSID /*PCI_ANY_ID */ , PEG6BPI6, "PEG6BPI6"}, + {0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2BPI6SC6_SSID /*PCI_ANY_ID */ , PEG2BPI6SC6, + "PEG6BPI62SC6"}, + {0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_MEG2BPI6_SSID /*PCI_ANY_ID */ , MEG2BPI6, "MEG2BPI6"}, + {0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_XEG2BPI6_SSID /*PCI_ANY_ID */ , XEG2BPI6, "XEG2BPI6"}, + {0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_MEG4BPI6_SSID /*PCI_ANY_ID */ , MEG4BPI6, "MEG4BPI6"}, + + {0x8086, 0x10a9, SILICOM_SVID /*PCI_ANY_ID */ , SILICOM_PEG2BPFI5_SSID, + PEG2BPFI5, "PEG2BPFI5"}, + {0x8086, 0x10a9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2BPFI5LX_SSID, PEG2BPFI5LX, "PEG2BPFI5LX"}, + + {0x8086, 0x105f, SILICOM_SVID, SILICOM_PXEG4BPFI_SSID, PXEG4BPFI, + "PXEG4BPFI-SD"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1EG2BPI6_SSID /*PCI_ANY_ID */ , M1EG2BPI6, "MxEG2BPI6"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1EG2BPFI6_SSID /*PCI_ANY_ID */ , M1EG2BPFI6, "MxEG2BPFI6"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1EG2BPFI6LX_SSID /*PCI_ANY_ID */ , M1EG2BPFI6LX, + "MxEG2BPFI6LX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1EG2BPFI6ZX_SSID /*PCI_ANY_ID */ , M1EG2BPFI6ZX, + "MxEG2BPFI6ZX"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1EG4BPI6_SSID /*PCI_ANY_ID */ , M1EG4BPI6, "MxEG4BPI6"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1EG4BPFI6_SSID /*PCI_ANY_ID */ , M1EG4BPFI6, "MxEG4BPFI6"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1EG4BPFI6LX_SSID /*PCI_ANY_ID */ , M1EG4BPFI6LX, + "MxEG4BPFI6LX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1EG4BPFI6ZX_SSID /*PCI_ANY_ID */ , M1EG4BPFI6ZX, + "MxEG4BPFI6ZX"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1EG6BPI6_SSID /*PCI_ANY_ID */ , M1EG6BPI6, "MxEG6BPI6"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1E2G4BPi80_SSID /*PCI_ANY_ID */ , M1E2G4BPi80, "MxE2G4BPi80"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1E2G4BPFi80_SSID /*PCI_ANY_ID */ , M1E2G4BPFi80, + "MxE2G4BPFi80"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1E2G4BPFi80LX_SSID /*PCI_ANY_ID */ , M1E2G4BPFi80LX, + "MxE2G4BPFi80LX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1E2G4BPFi80ZX_SSID /*PCI_ANY_ID */ , M1E2G4BPFi80ZX, + "MxE2G4BPFi80ZX"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2EG2BPFI6_SSID /*PCI_ANY_ID */ , M2EG2BPFI6, "M2EG2BPFI6"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2EG2BPFI6LX_SSID /*PCI_ANY_ID */ , M2EG2BPFI6LX, + "M2EG2BPFI6LX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2EG2BPFI6ZX_SSID /*PCI_ANY_ID */ , M2EG2BPFI6ZX, + "M2EG2BPFI6ZX"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2EG4BPI6_SSID /*PCI_ANY_ID */ , M2EG4BPI6, "M2EG4BPI6"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2EG4BPFI6_SSID /*PCI_ANY_ID */ , M2EG4BPFI6, "M2EG4BPFI6"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2EG4BPFI6LX_SSID /*PCI_ANY_ID */ , M2EG4BPFI6LX, + "M2EG4BPFI6LX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2EG4BPFI6ZX_SSID /*PCI_ANY_ID */ , M2EG4BPFI6ZX, + "M2EG4BPFI6ZX"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2EG6BPI6_SSID /*PCI_ANY_ID */ , M2EG6BPI6, "M2EG6BPI6"}, + + {0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2DBI6_SSID /*PCI_ANY_ID */ , PEG2DBI6, "PEG2DBI6"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2DBFI6_SSID /*PCI_ANY_ID */ , PEG2DBFI6, "PEG2DBFI6"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2DBFI6LX_SSID /*PCI_ANY_ID */ , PEG2DBFI6LX, "PEG2DBFI6LX"}, + {0x8086, 0x10e6, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PEG2DBFI6ZX_SSID /*PCI_ANY_ID */ , PEG2DBFI6ZX, "PEG2DBFI6ZX"}, + + {0x8086, 0x10F9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE210G2DBi9SR_SSID, PE210G2DBi9SR, "PE210G2DBi9SR"}, + {0x8086, 0x10F9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE210G2DBi9LR_SSID, PE210G2DBi9LR, "PE210G2DBi9LR"}, + {0x8086, 0x10F9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE310G4DBi940SR_SSID, PE310G4DBi940SR, "PE310G4DBi9SR"}, + + {0x8086, 0x10Fb, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE310G4BPi9T_SSID, PE310G4BPi9T, "PE310G4BPi9T"}, + {0x8086, 0x10Fb, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE310G4BPi9SR_SSID, PE310G4BPi9SR, "PE310G4BPi9SR"}, + {0x8086, 0x10Fb, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE310G4BPi9LR_SSID, PE310G4BPi9LR, "PE310G4BPi9LR"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G4BPi80_SSID /*PCI_ANY_ID */ , PE2G4BPi80, "PE2G4BPi80"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G4BPFi80_SSID /*PCI_ANY_ID */ , PE2G4BPFi80, "PE2G4BPFi80"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G4BPFi80LX_SSID /*PCI_ANY_ID */ , PE2G4BPFi80LX, + "PE2G4BPFi80LX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G4BPFi80ZX_SSID /*PCI_ANY_ID */ , PE2G4BPFi80ZX, + "PE2G4BPFi80ZX"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G4BPi80L_SSID /*PCI_ANY_ID */ , PE2G4BPi80L, "PE2G4BPi80L"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M6E2G8BPi80A_SSID /*PCI_ANY_ID */ , M6E2G8BPi80A, + "MxE2G8BPi80A"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G2BPi35_SSID /*PCI_ANY_ID */ , PE2G2BPi35, "PE2G2BPi35"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PAC1200BPi35_SSID /*PCI_ANY_ID */ , PAC1200BPi35, + "PAC1200BPi35"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G2BPFi35_SSID /*PCI_ANY_ID */ , PE2G2BPFi35, "PE2G2BPFi35"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G2BPFi35LX_SSID /*PCI_ANY_ID */ , PE2G2BPFi35LX, + "PE2G2BPFi35LX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G2BPFi35ZX_SSID /*PCI_ANY_ID */ , PE2G2BPFi35ZX, + "PE2G2BPFi35ZX"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G4BPi35_SSID /*PCI_ANY_ID */ , PE2G4BPi35, "PE2G4BPi35"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G4BPi35L_SSID /*PCI_ANY_ID */ , PE2G4BPi35L, "PE2G4BPi35L"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G4BPFi35_SSID /*PCI_ANY_ID */ , PE2G4BPFi35, "PE2G4BPFi35"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G4BPFi35LX_SSID /*PCI_ANY_ID */ , PE2G4BPFi35LX, + "PE2G4BPFi35LX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G4BPFi35ZX_SSID /*PCI_ANY_ID */ , PE2G4BPFi35ZX, + "PE2G4BPFi35ZX"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G6BPi35_SSID /*PCI_ANY_ID */ , PE2G6BPi35, "PE2G6BPi35"}, + + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa0, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa1, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa2, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa3, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa4, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa5, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa6, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa7, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa8, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaa9, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaaa, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaab, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaac, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaad, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaae, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaaf, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab0, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab1, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab2, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab3, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab4, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab5, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab6, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab7, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab8, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xab9, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xaba, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xabb, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xabc, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xabd, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xabe, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , 0xabf, PE2G6BPi35CX, + "PE2G6BPi35CX"}, + + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G2BPi80_SSID /*PCI_ANY_ID */ , PE2G2BPi80, "PE2G2BPi80"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G2BPFi80_SSID /*PCI_ANY_ID */ , PE2G2BPFi80, "PE2G2BPFi80"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G2BPFi80LX_SSID /*PCI_ANY_ID */ , PE2G2BPFi80LX, + "PE2G2BPFi80LX"}, + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE2G2BPFi80ZX_SSID /*PCI_ANY_ID */ , PE2G2BPFi80ZX, + "PE2G2BPFi80ZX"}, + + {0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_MEG2BPI6_SSID /*PCI_ANY_ID */ , MEG2BPI6, "MEG2BPI6"}, + {0x8086, 0x10c9, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_XEG2BPI6_SSID /*PCI_ANY_ID */ , XEG2BPI6, "XEG2BPI6"}, + +#if 0 + {0x8086, 0x10fb, 0x8086, INTEL_PE210G2SPI9_SSID, PE210G2SPI9, + "PE210G2SPI9"}, +#endif + {0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1E10G2BPI9CX4_SSID /*PCI_ANY_ID */ , M1E10G2BPI9CX4, + "MxE210G2BPI9CX4"}, + {0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1E10G2BPI9SR_SSID /*PCI_ANY_ID */ , M1E10G2BPI9SR, + "MxE210G2BPI9SR"}, + {0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1E10G2BPI9LR_SSID /*PCI_ANY_ID */ , M1E10G2BPI9LR, + "MxE210G2BPI9LR"}, + {0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M1E10G2BPI9T_SSID /*PCI_ANY_ID */ , M1E10G2BPI9T, + "MxE210G2BPI9T"}, + + {0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2E10G2BPI9CX4_SSID /*PCI_ANY_ID */ , M2E10G2BPI9CX4, + "M2E10G2BPI9CX4"}, + {0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2E10G2BPI9SR_SSID /*PCI_ANY_ID */ , M2E10G2BPI9SR, + "M2E10G2BPI9SR"}, + {0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2E10G2BPI9LR_SSID /*PCI_ANY_ID */ , M2E10G2BPI9LR, + "M2E10G2BPI9LR"}, + {0x8086, 0x10fb, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M2E10G2BPI9T_SSID /*PCI_ANY_ID */ , M2E10G2BPI9T, + "M2E10G2BPI9T"}, + + {0x8086, 0x10fb, SILICOM_SVID, SILICOM_PE210G2BPI9CX4_SSID, + PE210G2BPI9CX4, "PE210G2BPI9CX4"}, + {0x8086, 0x10fb, SILICOM_SVID, SILICOM_PE210G2BPI9SR_SSID, + PE210G2BPI9SR, "PE210G2BPI9SR"}, + {0x8086, 0x10fb, SILICOM_SVID, SILICOM_PE210G2BPI9LR_SSID, + PE210G2BPI9LR, "PE210G2BPI9LR"}, + {0x8086, 0x10fb, SILICOM_SVID, SILICOM_PE210G2BPI9T_SSID, PE210G2BPI9T, + "PE210G2BPI9T"}, + +#if 0 + {0x1374, 0x2c, SILICOM_SVID, SILICOM_PXG4BPI_SSID, PXG4BPI, + "PXG4BPI-SD"}, + + {0x1374, 0x2d, SILICOM_SVID, SILICOM_PXG4BPFI_SSID, PXG4BPFI, + "PXG4BPFI-SD"}, + + {0x1374, 0x3f, SILICOM_SVID, SILICOM_PXG2TBI_SSID, PXG2TBI, + "PXG2TBI-SD"}, + + {0x1374, 0x3d, SILICOM_SVID, SILICOM_PXG2BISC1_SSID, PXG2BISC1, + "PXG2BISC1-SD"}, + + {0x1374, 0x40, SILICOM_SVID, SILICOM_PEG4BPFI_SSID, PEG4BPFI, + "PEG4BPFI-SD"}, + +#ifdef BP_SELF_TEST + {0x1374, 0x28, SILICOM_SVID, 0x28, PXGBPI, "PXG2BPI-SD"}, +#endif +#endif + {0x8086, PCI_ANY_ID, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_M6E2G8BPi80_SSID /*PCI_ANY_ID */ , M6E2G8BPi80, "MxE2G8BPi80"}, + {0x8086, 0x1528, SILICOM_SVID /*PCI_ANY_ID */ , + SILICOM_PE210G2BPi40_SSID /*PCI_ANY_ID */ , PE210G2BPi40, + "PE210G2BPi40T"}, + + /* required last entry */ + {0,} +}; + +/* +* Initialize the module - Register the character device +*/ + +static int __init bypass_init_module(void) +{ + int ret_val, idx, idx_dev = 0; + struct pci_dev *pdev1 = NULL; + unsigned long mmio_start, mmio_len; + + printk(BP_MOD_DESCR " v" BP_MOD_VER "\n"); + ret_val = register_chrdev(major_num, DEVICE_NAME, &Fops); + if (ret_val < 0) { + printk("%s failed with %d\n", DEVICE_NAME, ret_val); + return ret_val; + } + major_num = ret_val; /* dynamic */ + for (idx = 0; tx_ctl_pci_tbl[idx].vendor; idx++) { + while ((pdev1 = pci_get_subsys(tx_ctl_pci_tbl[idx].vendor, + tx_ctl_pci_tbl[idx].device, + tx_ctl_pci_tbl[idx].subvendor, + tx_ctl_pci_tbl[idx].subdevice, + pdev1))) { + + device_num++; + } + } + if (!device_num) { + printk("No such device\n"); + unregister_chrdev(major_num, DEVICE_NAME); + return -1; + } + + bpctl_dev_arr = kmalloc((device_num) * sizeof(bpctl_dev_t), GFP_KERNEL); + + if (!bpctl_dev_arr) { + printk("Allocation error\n"); + unregister_chrdev(major_num, DEVICE_NAME); + return -1; + } + memset(bpctl_dev_arr, 0, ((device_num) * sizeof(bpctl_dev_t))); + + pdev1 = NULL; + for (idx = 0; tx_ctl_pci_tbl[idx].vendor; idx++) { + while ((pdev1 = pci_get_subsys(tx_ctl_pci_tbl[idx].vendor, + tx_ctl_pci_tbl[idx].device, + tx_ctl_pci_tbl[idx].subvendor, + tx_ctl_pci_tbl[idx].subdevice, + pdev1))) { + bpctl_dev_arr[idx_dev].pdev = pdev1; + + mmio_start = pci_resource_start(pdev1, 0); + mmio_len = pci_resource_len(pdev1, 0); + + bpctl_dev_arr[idx_dev].desc = + dev_desc[tx_ctl_pci_tbl[idx].index].name; + bpctl_dev_arr[idx_dev].name = + tx_ctl_pci_tbl[idx].bp_name; + bpctl_dev_arr[idx_dev].device = + tx_ctl_pci_tbl[idx].device; + bpctl_dev_arr[idx_dev].vendor = + tx_ctl_pci_tbl[idx].vendor; + bpctl_dev_arr[idx_dev].subdevice = + tx_ctl_pci_tbl[idx].subdevice; + bpctl_dev_arr[idx_dev].subvendor = + tx_ctl_pci_tbl[idx].subvendor; + /* bpctl_dev_arr[idx_dev].pdev=pdev1; */ + bpctl_dev_arr[idx_dev].func = PCI_FUNC(pdev1->devfn); + bpctl_dev_arr[idx_dev].slot = PCI_SLOT(pdev1->devfn); + bpctl_dev_arr[idx_dev].bus = pdev1->bus->number; + bpctl_dev_arr[idx_dev].mem_map = + (unsigned long)ioremap(mmio_start, mmio_len); +#ifdef BP_SYNC_FLAG + spin_lock_init(&bpctl_dev_arr[idx_dev].bypass_wr_lock); +#endif + if (BP10G9_IF_SERIES(bpctl_dev_arr[idx_dev].subdevice)) + bpctl_dev_arr[idx_dev].bp_10g9 = 1; + if (BP10G_IF_SERIES(bpctl_dev_arr[idx_dev].subdevice)) + bpctl_dev_arr[idx_dev].bp_10g = 1; + if (PEG540_IF_SERIES(bpctl_dev_arr[idx_dev].subdevice)) { + + bpctl_dev_arr[idx_dev].bp_540 = 1; + } + if (PEGF5_IF_SERIES(bpctl_dev_arr[idx_dev].subdevice)) + bpctl_dev_arr[idx_dev].bp_fiber5 = 1; + if (PEG80_IF_SERIES(bpctl_dev_arr[idx_dev].subdevice)) + bpctl_dev_arr[idx_dev].bp_i80 = 1; + if (PEGF80_IF_SERIES(bpctl_dev_arr[idx_dev].subdevice)) + bpctl_dev_arr[idx_dev].bp_i80 = 1; + if ((bpctl_dev_arr[idx_dev].subdevice & 0xa00) == 0xa00) + bpctl_dev_arr[idx_dev].bp_i80 = 1; + if (BP10GB_IF_SERIES(bpctl_dev_arr[idx_dev].subdevice)) { + if (bpctl_dev_arr[idx_dev].ifindex == 0) { + unregister_chrdev(major_num, + DEVICE_NAME); + printk + ("Please load network driver for %s adapter!\n", + bpctl_dev_arr[idx_dev].name); + return -1; + } + + if (bpctl_dev_arr[idx_dev].ndev) { + if (! + (bpctl_dev_arr[idx_dev].ndev-> + flags & IFF_UP)) { + if (! + (bpctl_dev_arr[idx_dev]. + ndev->flags & IFF_UP)) { + unregister_chrdev + (major_num, + DEVICE_NAME); + printk + ("Please bring up network interfaces for %s adapter!\n", + bpctl_dev_arr + [idx_dev].name); + return -1; + } + + } + } + bpctl_dev_arr[idx_dev].bp_10gb = 1; + } + + if (!bpctl_dev_arr[idx_dev].bp_10g9) { + + if (is_bypass_fn(&bpctl_dev_arr[idx_dev])) { + printk(KERN_INFO "%s found, ", + bpctl_dev_arr[idx_dev].name); + if ((OLD_IF_SERIES + (bpctl_dev_arr[idx_dev].subdevice)) + || + (INTEL_IF_SERIES + (bpctl_dev_arr[idx_dev]. + subdevice))) + bpctl_dev_arr[idx_dev]. + bp_fw_ver = 0xff; + else + bpctl_dev_arr[idx_dev]. + bp_fw_ver = + bypass_fw_ver(&bpctl_dev_arr + [idx_dev]); + if ((bpctl_dev_arr[idx_dev].bp_10gb == + 1) + && (bpctl_dev_arr[idx_dev]. + bp_fw_ver == 0xff)) { + int cnt = 100; + while (cnt--) { + iounmap((void + *) + (bpctl_dev_arr + [idx_dev]. + mem_map)); + mmio_start = + pci_resource_start + (pdev1, 0); + mmio_len = + pci_resource_len + (pdev1, 0); + + bpctl_dev_arr[idx_dev]. + mem_map = + (unsigned long) + ioremap(mmio_start, + mmio_len); + + bpctl_dev_arr[idx_dev]. + bp_fw_ver = + bypass_fw_ver + (&bpctl_dev_arr + [idx_dev]); + if (bpctl_dev_arr + [idx_dev]. + bp_fw_ver == 0xa8) + break; + + } + } + /* bpctl_dev_arr[idx_dev].bp_fw_ver=0xa8; */ + printk("firmware version: 0x%x\n", + bpctl_dev_arr[idx_dev]. + bp_fw_ver); + } + bpctl_dev_arr[idx_dev].wdt_status = + WDT_STATUS_UNKNOWN; + bpctl_dev_arr[idx_dev].reset_time = 0; + atomic_set(&bpctl_dev_arr[idx_dev].wdt_busy, 0); + bpctl_dev_arr[idx_dev].bp_status_un = 1; + + bypass_caps_init(&bpctl_dev_arr[idx_dev]); + + init_bypass_wd_auto(&bpctl_dev_arr[idx_dev]); + init_bypass_tpl_auto(&bpctl_dev_arr[idx_dev]); + if (NOKIA_SERIES + (bpctl_dev_arr[idx_dev].subdevice)) + reset_cont(&bpctl_dev_arr[idx_dev]); + } +#ifdef BP_SELF_TEST + if ((bpctl_dev_arr[idx_dev].bp_tx_data = + kmalloc(BPTEST_DATA_LEN, GFP_KERNEL))) { + + memset(bpctl_dev_arr[idx_dev].bp_tx_data, 0x0, + BPTEST_DATA_LEN); + + memset(bpctl_dev_arr[idx_dev].bp_tx_data, 0xff, + 6); + memset(bpctl_dev_arr[idx_dev].bp_tx_data + 6, + 0x0, 1); + memset(bpctl_dev_arr[idx_dev].bp_tx_data + 7, + 0xaa, 5); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)) + bpctl_dev_arr[idx_dev].bp_tx_data[12] = + (ETH_P_BPTEST >> 8) & 0xff; + bpctl_dev_arr[idx_dev].bp_tx_data[13] = + ETH_P_BPTEST & 0xff; +#else + *(__be16 *) (bpctl_dev_arr[idx_dev].bp_tx_data + + 12) = htons(ETH_P_BPTEST); +#endif + + } else + printk("bp_ctl: Memory allocation error!\n"); +#endif + idx_dev++; + + } + } + if_scan_init(); + + sema_init(&bpctl_sema, 1); + spin_lock_init(&bpvm_lock); + { + + bpctl_dev_t *pbpctl_dev_c = NULL; + for (idx_dev = 0; + ((bpctl_dev_arr[idx_dev].pdev != NULL) + && (idx_dev < device_num)); idx_dev++) { + if (bpctl_dev_arr[idx_dev].bp_10g9) { + pbpctl_dev_c = + get_status_port_fn(&bpctl_dev_arr[idx_dev]); + if (is_bypass_fn(&bpctl_dev_arr[idx_dev])) { + printk(KERN_INFO "%s found, ", + bpctl_dev_arr[idx_dev].name); + bpctl_dev_arr[idx_dev].bp_fw_ver = + bypass_fw_ver(&bpctl_dev_arr + [idx_dev]); + printk("firmware version: 0x%x\n", + bpctl_dev_arr[idx_dev]. + bp_fw_ver); + + } + bpctl_dev_arr[idx_dev].wdt_status = + WDT_STATUS_UNKNOWN; + bpctl_dev_arr[idx_dev].reset_time = 0; + atomic_set(&bpctl_dev_arr[idx_dev].wdt_busy, 0); + bpctl_dev_arr[idx_dev].bp_status_un = 1; + + bypass_caps_init(&bpctl_dev_arr[idx_dev]); + + init_bypass_wd_auto(&bpctl_dev_arr[idx_dev]); + init_bypass_tpl_auto(&bpctl_dev_arr[idx_dev]); + + } + + } + } + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) + inter_module_register("is_bypass_sd", THIS_MODULE, &is_bypass_sd); + inter_module_register("get_bypass_slave_sd", THIS_MODULE, + &get_bypass_slave_sd); + inter_module_register("get_bypass_caps_sd", THIS_MODULE, + &get_bypass_caps_sd); + inter_module_register("get_wd_set_caps_sd", THIS_MODULE, + &get_wd_set_caps_sd); + inter_module_register("set_bypass_sd", THIS_MODULE, &set_bypass_sd); + inter_module_register("get_bypass_sd", THIS_MODULE, &get_bypass_sd); + inter_module_register("get_bypass_change_sd", THIS_MODULE, + &get_bypass_change_sd); + inter_module_register("set_dis_bypass_sd", THIS_MODULE, + &set_dis_bypass_sd); + inter_module_register("get_dis_bypass_sd", THIS_MODULE, + &get_dis_bypass_sd); + inter_module_register("set_bypass_pwoff_sd", THIS_MODULE, + &set_bypass_pwoff_sd); + inter_module_register("get_bypass_pwoff_sd", THIS_MODULE, + &get_bypass_pwoff_sd); + inter_module_register("set_bypass_pwup_sd", THIS_MODULE, + &set_bypass_pwup_sd); + inter_module_register("get_bypass_pwup_sd", THIS_MODULE, + &get_bypass_pwup_sd); + inter_module_register("get_bypass_wd_sd", THIS_MODULE, + &get_bypass_wd_sd); + inter_module_register("set_bypass_wd_sd", THIS_MODULE, + &set_bypass_wd_sd); + inter_module_register("get_wd_expire_time_sd", THIS_MODULE, + &get_wd_expire_time_sd); + inter_module_register("reset_bypass_wd_timer_sd", THIS_MODULE, + &reset_bypass_wd_timer_sd); + inter_module_register("set_std_nic_sd", THIS_MODULE, &set_std_nic_sd); + inter_module_register("get_std_nic_sd", THIS_MODULE, &get_std_nic_sd); + inter_module_register("set_tx_sd", THIS_MODULE, &set_tx_sd); + inter_module_register("get_tx_sd", THIS_MODULE, &get_tx_sd); + inter_module_register("set_tpl_sd", THIS_MODULE, &set_tpl_sd); + inter_module_register("get_tpl_sd", THIS_MODULE, &get_tpl_sd); + + inter_module_register("set_bp_hw_reset_sd", THIS_MODULE, + &set_bp_hw_reset_sd); + inter_module_register("get_bp_hw_reset_sd", THIS_MODULE, + &get_bp_hw_reset_sd); + + inter_module_register("set_tap_sd", THIS_MODULE, &set_tap_sd); + inter_module_register("get_tap_sd", THIS_MODULE, &get_tap_sd); + inter_module_register("get_tap_change_sd", THIS_MODULE, + &get_tap_change_sd); + inter_module_register("set_dis_tap_sd", THIS_MODULE, &set_dis_tap_sd); + inter_module_register("get_dis_tap_sd", THIS_MODULE, &get_dis_tap_sd); + inter_module_register("set_tap_pwup_sd", THIS_MODULE, &set_tap_pwup_sd); + inter_module_register("get_tap_pwup_sd", THIS_MODULE, &get_tap_pwup_sd); + inter_module_register("set_bp_disc_sd", THIS_MODULE, &set_bp_disc_sd); + inter_module_register("get_bp_disc_sd", THIS_MODULE, &get_bp_disc_sd); + inter_module_register("get_bp_disc_change_sd", THIS_MODULE, + &get_bp_disc_change_sd); + inter_module_register("set_bp_dis_disc_sd", THIS_MODULE, + &set_bp_dis_disc_sd); + inter_module_register("get_bp_dis_disc_sd", THIS_MODULE, + &get_bp_dis_disc_sd); + inter_module_register("set_bp_disc_pwup_sd", THIS_MODULE, + &set_bp_disc_pwup_sd); + inter_module_register("get_bp_disc_pwup_sd", THIS_MODULE, + &get_bp_disc_pwup_sd); + inter_module_register("set_wd_exp_mode_sd", THIS_MODULE, + &set_wd_exp_mode_sd); + inter_module_register("get_wd_exp_mode_sd", THIS_MODULE, + &get_wd_exp_mode_sd); + inter_module_register("set_wd_autoreset_sd", THIS_MODULE, + &set_wd_autoreset_sd); + inter_module_register("get_wd_autoreset_sd", THIS_MODULE, + &get_wd_autoreset_sd); + inter_module_register("get_bypass_info_sd", THIS_MODULE, + &get_bypass_info_sd); + inter_module_register("bp_if_scan_sd", THIS_MODULE, &bp_if_scan_sd); + +#endif + register_netdevice_notifier(&bp_notifier_block); +#ifdef BP_PROC_SUPPORT + { + int i = 0; + /* unsigned long flags; */ + /* rcu_read_lock(); */ + bp_proc_create(); + for (i = 0; i < device_num; i++) { + if (bpctl_dev_arr[i].ifindex) { + /* spin_lock_irqsave(&bpvm_lock, flags); */ + bypass_proc_remove_dev_sd(&bpctl_dev_arr[i]); + bypass_proc_create_dev_sd(&bpctl_dev_arr[i]); + /* spin_unlock_irqrestore(&bpvm_lock, flags); */ + } + + } + /* rcu_read_unlock(); */ + } +#endif + + return 0; +} + +/* +* Cleanup - unregister the appropriate file from /proc +*/ +static void __exit bypass_cleanup_module(void) +{ + int i; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)) + int ret; +#endif + unregister_netdevice_notifier(&bp_notifier_block); + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)) + inter_module_unregister("is_bypass_sd"); + inter_module_unregister("get_bypass_slave_sd"); + inter_module_unregister("get_bypass_caps_sd"); + inter_module_unregister("get_wd_set_caps_sd"); + inter_module_unregister("set_bypass_sd"); + inter_module_unregister("get_bypass_sd"); + inter_module_unregister("get_bypass_change_sd"); + inter_module_unregister("set_dis_bypass_sd"); + inter_module_unregister("get_dis_bypass_sd"); + inter_module_unregister("set_bypass_pwoff_sd"); + inter_module_unregister("get_bypass_pwoff_sd"); + inter_module_unregister("set_bypass_pwup_sd"); + inter_module_unregister("get_bypass_pwup_sd"); + inter_module_unregister("set_bypass_wd_sd"); + inter_module_unregister("get_bypass_wd_sd"); + inter_module_unregister("get_wd_expire_time_sd"); + inter_module_unregister("reset_bypass_wd_timer_sd"); + inter_module_unregister("set_std_nic_sd"); + inter_module_unregister("get_std_nic_sd"); + inter_module_unregister("set_tx_sd"); + inter_module_unregister("get_tx_sd"); + inter_module_unregister("set_tpl_sd"); + inter_module_unregister("get_tpl_sd"); + inter_module_unregister("set_tap_sd"); + inter_module_unregister("get_tap_sd"); + inter_module_unregister("get_tap_change_sd"); + inter_module_unregister("set_dis_tap_sd"); + inter_module_unregister("get_dis_tap_sd"); + inter_module_unregister("set_tap_pwup_sd"); + inter_module_unregister("get_tap_pwup_sd"); + inter_module_unregister("set_bp_disc_sd"); + inter_module_unregister("get_bp_disc_sd"); + inter_module_unregister("get_bp_disc_change_sd"); + inter_module_unregister("set_bp_dis_disc_sd"); + inter_module_unregister("get_bp_dis_disc_sd"); + inter_module_unregister("set_bp_disc_pwup_sd"); + inter_module_unregister("get_bp_disc_pwup_sd"); + inter_module_unregister("set_wd_exp_mode_sd"); + inter_module_unregister("get_wd_exp_mode_sd"); + inter_module_unregister("set_wd_autoreset_sd"); + inter_module_unregister("get_wd_autoreset_sd"); + inter_module_unregister("get_bypass_info_sd"); + inter_module_unregister("bp_if_scan_sd"); + +#endif + + for (i = 0; i < device_num; i++) { + /* unsigned long flags; */ +#ifdef BP_PROC_SUPPORT +/* spin_lock_irqsave(&bpvm_lock, flags); + rcu_read_lock(); */ + bypass_proc_remove_dev_sd(&bpctl_dev_arr[i]); +/* spin_unlock_irqrestore(&bpvm_lock, flags); + rcu_read_unlock(); */ +#endif + remove_bypass_wd_auto(&bpctl_dev_arr[i]); + bpctl_dev_arr[i].reset_time = 0; + + remove_bypass_tpl_auto(&bpctl_dev_arr[i]); + } + + /* unmap all devices */ + for (i = 0; i < device_num; i++) { +#ifdef BP_SELF_TEST + if (bpctl_dev_arr[i].bp_tx_data) + kfree(bpctl_dev_arr[i].bp_tx_data); +#endif + iounmap((void *)(bpctl_dev_arr[i].mem_map)); + } + + /* free all devices space */ + if (bpctl_dev_arr) + kfree(bpctl_dev_arr); + +/* +* Unregister the device +*/ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)) + ret = unregister_chrdev(major_num, DEVICE_NAME); +/* +* If there's an error, report it +*/ + if (ret < 0) + printk("Error in module_unregister_chrdev: %d\n", ret); +#else + unregister_chrdev(major_num, DEVICE_NAME); + +#endif +} + +module_init(bypass_init_module); +module_exit(bypass_cleanup_module); + +int is_bypass_sd(int ifindex) +{ + return is_bypass(get_dev_idx_p(ifindex)); +} + +int set_bypass_sd(int ifindex, int bypass_mode) +{ + + return set_bypass_fn(get_dev_idx_p(ifindex), bypass_mode); +} + +int get_bypass_sd(int ifindex) +{ + + return get_bypass_fn(get_dev_idx_p(ifindex)); +} + +int get_bypass_change_sd(int ifindex) +{ + + return get_bypass_change_fn(get_dev_idx_p(ifindex)); +} + +int set_dis_bypass_sd(int ifindex, int dis_param) +{ + return set_dis_bypass_fn(get_dev_idx_p(ifindex), dis_param); +} + +int get_dis_bypass_sd(int ifindex) +{ + + return get_dis_bypass_fn(get_dev_idx_p(ifindex)); +} + +int set_bypass_pwoff_sd(int ifindex, int bypass_mode) +{ + return set_bypass_pwoff_fn(get_dev_idx_p(ifindex), bypass_mode); + +} + +int get_bypass_pwoff_sd(int ifindex) +{ + return get_bypass_pwoff_fn(get_dev_idx_p(ifindex)); + +} + +int set_bypass_pwup_sd(int ifindex, int bypass_mode) +{ + return set_bypass_pwup_fn(get_dev_idx_p(ifindex), bypass_mode); + +} + +int get_bypass_pwup_sd(int ifindex) +{ + return get_bypass_pwup_fn(get_dev_idx_p(ifindex)); + +} + +int set_bypass_wd_sd(int if_index, int ms_timeout, int *ms_timeout_set) +{ + if ((is_bypass(get_dev_idx_p(if_index))) <= 0) + return BP_NOT_CAP; + *ms_timeout_set = set_bypass_wd_fn(get_dev_idx_p(if_index), ms_timeout); + return 0; +} + +int get_bypass_wd_sd(int ifindex, int *timeout) +{ + return get_bypass_wd_fn(get_dev_idx_p(ifindex), timeout); + +} + +int get_wd_expire_time_sd(int ifindex, int *time_left) +{ + return get_wd_expire_time_fn(get_dev_idx_p(ifindex), time_left); +} + +int reset_bypass_wd_timer_sd(int ifindex) +{ + return reset_bypass_wd_timer_fn(get_dev_idx_p(ifindex)); + +} + +int get_wd_set_caps_sd(int ifindex) +{ + return get_wd_set_caps_fn(get_dev_idx_p(ifindex)); + +} + +int set_std_nic_sd(int ifindex, int nic_mode) +{ + return set_std_nic_fn(get_dev_idx_p(ifindex), nic_mode); + +} + +int get_std_nic_sd(int ifindex) +{ + return get_std_nic_fn(get_dev_idx_p(ifindex)); + +} + +int set_tap_sd(int ifindex, int tap_mode) +{ + return set_tap_fn(get_dev_idx_p(ifindex), tap_mode); + +} + +int get_tap_sd(int ifindex) +{ + return get_tap_fn(get_dev_idx_p(ifindex)); + +} + +int set_tap_pwup_sd(int ifindex, int tap_mode) +{ + return set_tap_pwup_fn(get_dev_idx_p(ifindex), tap_mode); + +} + +int get_tap_pwup_sd(int ifindex) +{ + return get_tap_pwup_fn(get_dev_idx_p(ifindex)); + +} + +int get_tap_change_sd(int ifindex) +{ + return get_tap_change_fn(get_dev_idx_p(ifindex)); + +} + +int set_dis_tap_sd(int ifindex, int dis_param) +{ + return set_dis_tap_fn(get_dev_idx_p(ifindex), dis_param); + +} + +int get_dis_tap_sd(int ifindex) +{ + return get_dis_tap_fn(get_dev_idx_p(ifindex)); + +} + +int set_bp_disc_sd(int ifindex, int disc_mode) +{ + return set_disc_fn(get_dev_idx_p(ifindex), disc_mode); + +} + +int get_bp_disc_sd(int ifindex) +{ + return get_disc_fn(get_dev_idx_p(ifindex)); + +} + +int set_bp_disc_pwup_sd(int ifindex, int disc_mode) +{ + return set_disc_pwup_fn(get_dev_idx_p(ifindex), disc_mode); + +} + +int get_bp_disc_pwup_sd(int ifindex) +{ + return get_disc_pwup_fn(get_dev_idx_p(ifindex)); + +} + +int get_bp_disc_change_sd(int ifindex) +{ + return get_disc_change_fn(get_dev_idx_p(ifindex)); + +} + +int set_bp_dis_disc_sd(int ifindex, int dis_param) +{ + return set_dis_disc_fn(get_dev_idx_p(ifindex), dis_param); + +} + +int get_bp_dis_disc_sd(int ifindex) +{ + return get_dis_disc_fn(get_dev_idx_p(ifindex)); + +} + +int get_wd_exp_mode_sd(int ifindex) +{ + return get_wd_exp_mode_fn(get_dev_idx_p(ifindex)); +} + +int set_wd_exp_mode_sd(int ifindex, int param) +{ + return set_wd_exp_mode_fn(get_dev_idx_p(ifindex), param); + +} + +int reset_cont_sd(int ifindex) +{ + return reset_cont_fn(get_dev_idx_p(ifindex)); + +} + +int set_tx_sd(int ifindex, int tx_state) +{ + return set_tx_fn(get_dev_idx_p(ifindex), tx_state); + +} + +int set_tpl_sd(int ifindex, int tpl_state) +{ + return set_tpl_fn(get_dev_idx_p(ifindex), tpl_state); + +} + +int set_bp_hw_reset_sd(int ifindex, int status) +{ + return set_bp_hw_reset_fn(get_dev_idx_p(ifindex), status); + +} + +int set_wd_autoreset_sd(int ifindex, int param) +{ + return set_wd_autoreset_fn(get_dev_idx_p(ifindex), param); + +} + +int get_wd_autoreset_sd(int ifindex) +{ + return get_wd_autoreset_fn(get_dev_idx_p(ifindex)); + +} + +int get_bypass_caps_sd(int ifindex) +{ + return get_bypass_caps_fn(get_dev_idx_p(ifindex)); +} + +int get_bypass_slave_sd(int ifindex) +{ + bpctl_dev_t *pbpctl_dev_out; + int ret = get_bypass_slave_fn(get_dev_idx_p(ifindex), &pbpctl_dev_out); + if (ret == 1) + return pbpctl_dev_out->ifindex; + return -1; + +} + +int get_tx_sd(int ifindex) +{ + return get_tx_fn(get_dev_idx_p(ifindex)); + +} + +int get_tpl_sd(int ifindex) +{ + return get_tpl_fn(get_dev_idx_p(ifindex)); + +} + +int get_bp_hw_reset_sd(int ifindex) +{ + return get_bp_hw_reset_fn(get_dev_idx_p(ifindex)); + +} + +int get_bypass_info_sd(int ifindex, struct bp_info *bp_info) +{ + return get_bypass_info_fn(get_dev_idx_p(ifindex), bp_info->prod_name, &bp_info->fw_ver); +} + +int bp_if_scan_sd(void) +{ + if_scan_init(); + return 0; +} + +EXPORT_SYMBOL_NOVERS(is_bypass_sd); +EXPORT_SYMBOL_NOVERS(get_bypass_slave_sd); +EXPORT_SYMBOL_NOVERS(get_bypass_caps_sd); +EXPORT_SYMBOL_NOVERS(get_wd_set_caps_sd); +EXPORT_SYMBOL_NOVERS(set_bypass_sd); +EXPORT_SYMBOL_NOVERS(get_bypass_sd); +EXPORT_SYMBOL_NOVERS(get_bypass_change_sd); +EXPORT_SYMBOL_NOVERS(set_dis_bypass_sd); +EXPORT_SYMBOL_NOVERS(get_dis_bypass_sd); +EXPORT_SYMBOL_NOVERS(set_bypass_pwoff_sd); +EXPORT_SYMBOL_NOVERS(get_bypass_pwoff_sd); +EXPORT_SYMBOL_NOVERS(set_bypass_pwup_sd); +EXPORT_SYMBOL_NOVERS(get_bypass_pwup_sd); +EXPORT_SYMBOL_NOVERS(set_bypass_wd_sd); +EXPORT_SYMBOL_NOVERS(get_bypass_wd_sd); +EXPORT_SYMBOL_NOVERS(get_wd_expire_time_sd); +EXPORT_SYMBOL_NOVERS(reset_bypass_wd_timer_sd); +EXPORT_SYMBOL_NOVERS(set_std_nic_sd); +EXPORT_SYMBOL_NOVERS(get_std_nic_sd); +EXPORT_SYMBOL_NOVERS(set_tx_sd); +EXPORT_SYMBOL_NOVERS(get_tx_sd); +EXPORT_SYMBOL_NOVERS(set_tpl_sd); +EXPORT_SYMBOL_NOVERS(get_tpl_sd); +EXPORT_SYMBOL_NOVERS(set_bp_hw_reset_sd); +EXPORT_SYMBOL_NOVERS(get_bp_hw_reset_sd); +EXPORT_SYMBOL_NOVERS(set_tap_sd); +EXPORT_SYMBOL_NOVERS(get_tap_sd); +EXPORT_SYMBOL_NOVERS(get_tap_change_sd); +EXPORT_SYMBOL_NOVERS(set_dis_tap_sd); +EXPORT_SYMBOL_NOVERS(get_dis_tap_sd); +EXPORT_SYMBOL_NOVERS(set_tap_pwup_sd); +EXPORT_SYMBOL_NOVERS(get_tap_pwup_sd); +EXPORT_SYMBOL_NOVERS(set_wd_exp_mode_sd); +EXPORT_SYMBOL_NOVERS(get_wd_exp_mode_sd); +EXPORT_SYMBOL_NOVERS(set_wd_autoreset_sd); +EXPORT_SYMBOL_NOVERS(get_wd_autoreset_sd); +EXPORT_SYMBOL_NOVERS(set_bp_disc_sd); +EXPORT_SYMBOL_NOVERS(get_bp_disc_sd); +EXPORT_SYMBOL_NOVERS(get_bp_disc_change_sd); +EXPORT_SYMBOL_NOVERS(set_bp_dis_disc_sd); +EXPORT_SYMBOL_NOVERS(get_bp_dis_disc_sd); +EXPORT_SYMBOL_NOVERS(set_bp_disc_pwup_sd); +EXPORT_SYMBOL_NOVERS(get_bp_disc_pwup_sd); +EXPORT_SYMBOL_NOVERS(get_bypass_info_sd); +EXPORT_SYMBOL_NOVERS(bp_if_scan_sd); + +#define BP_PROC_DIR "bypass" + +#define GPIO6_SET_ENTRY_SD "gpio6_set" +#define GPIO6_CLEAR_ENTRY_SD "gpio6_clear" + +#define GPIO7_SET_ENTRY_SD "gpio7_set" +#define GPIO7_CLEAR_ENTRY_SD "gpio7_clear" + +#define PULSE_SET_ENTRY_SD "pulse_set" +#define ZERO_SET_ENTRY_SD "zero_set" +#define PULSE_GET1_ENTRY_SD "pulse_get1" +#define PULSE_GET2_ENTRY_SD "pulse_get2" + +#define CMND_ON_ENTRY_SD "cmnd_on" +#define CMND_OFF_ENTRY_SD "cmnd_off" +#define RESET_CONT_ENTRY_SD "reset_cont" + + /*COMMANDS*/ +#define BYPASS_INFO_ENTRY_SD "bypass_info" +#define BYPASS_SLAVE_ENTRY_SD "bypass_slave" +#define BYPASS_CAPS_ENTRY_SD "bypass_caps" +#define WD_SET_CAPS_ENTRY_SD "wd_set_caps" +#define BYPASS_ENTRY_SD "bypass" +#define BYPASS_CHANGE_ENTRY_SD "bypass_change" +#define BYPASS_WD_ENTRY_SD "bypass_wd" +#define WD_EXPIRE_TIME_ENTRY_SD "wd_expire_time" +#define RESET_BYPASS_WD_ENTRY_SD "reset_bypass_wd" +#define DIS_BYPASS_ENTRY_SD "dis_bypass" +#define BYPASS_PWUP_ENTRY_SD "bypass_pwup" +#define BYPASS_PWOFF_ENTRY_SD "bypass_pwoff" +#define STD_NIC_ENTRY_SD "std_nic" +#define STD_NIC_ENTRY_SD "std_nic" +#define TAP_ENTRY_SD "tap" +#define TAP_CHANGE_ENTRY_SD "tap_change" +#define DIS_TAP_ENTRY_SD "dis_tap" +#define TAP_PWUP_ENTRY_SD "tap_pwup" +#define TWO_PORT_LINK_ENTRY_SD "two_port_link" +#define WD_EXP_MODE_ENTRY_SD "wd_exp_mode" +#define WD_AUTORESET_ENTRY_SD "wd_autoreset" +#define TPL_ENTRY_SD "tpl" +#define WAIT_AT_PWUP_ENTRY_SD "wait_at_pwup" +#define HW_RESET_ENTRY_SD "hw_reset" +#define DISC_ENTRY_SD "disc" +#define DISC_CHANGE_ENTRY_SD "disc_change" +#define DIS_DISC_ENTRY_SD "dis_disc" +#define DISC_PWUP_ENTRY_SD "disc_pwup" +static struct proc_dir_entry *bp_procfs_dir; + +static struct proc_dir_entry *proc_getdir(char *name, + struct proc_dir_entry *proc_dir) +{ + struct proc_dir_entry *pde = proc_dir; + + for (pde = pde->subdir; pde; pde = pde->next) { + if (pde->namelen && (strcmp(name, pde->name) == 0)) { + /* directory exists */ + break; + } + } + if (pde == (struct proc_dir_entry *)0) { + /* create the directory */ +#if (LINUX_VERSION_CODE > 0x20300) + pde = proc_mkdir(name, proc_dir); +#else + pde = create_proc_entry(name, S_IFDIR, proc_dir); +#endif + if (pde == (struct proc_dir_entry *)0) { + + return pde; + } + } + + return pde; +} + +int bp_proc_create(void) +{ + bp_procfs_dir = proc_getdir(BP_PROC_DIR, init_net.proc_net); + if (bp_procfs_dir == (struct proc_dir_entry *)0) { + printk(KERN_DEBUG + "Could not create procfs nicinfo directory %s\n", + BP_PROC_DIR); + return -1; + } + return 0; +} + +int +bypass_proc_create_entry_sd(struct pfs_unit_sd *pfs_unit_curr, + char *proc_name, + write_proc_t *write_proc, + read_proc_t *read_proc, + struct proc_dir_entry *parent_pfs, void *data) +{ + strcpy(pfs_unit_curr->proc_name, proc_name); + pfs_unit_curr->proc_entry = create_proc_entry(pfs_unit_curr->proc_name, + S_IFREG | S_IRUSR | + S_IWUSR | S_IRGRP | + S_IROTH, parent_pfs); + if (pfs_unit_curr->proc_entry == NULL) + return -1; + + pfs_unit_curr->proc_entry->read_proc = read_proc; + pfs_unit_curr->proc_entry->write_proc = write_proc; + pfs_unit_curr->proc_entry->data = data; + + return 0; + +} + +int +get_bypass_info_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + int len = 0; + + len += sprintf(page, "Name\t\t\t%s\n", pbp_device_block->name); + len += + sprintf(page + len, "Firmware version\t0x%x\n", + pbp_device_block->bp_fw_ver); + + *eof = 1; + return len; +} + +int +get_bypass_slave_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0; + bpctl_dev_t *pbp_device_block_slave = NULL; + int idx_dev = 0; + struct net_device *net_slave_dev = NULL; + + if ((pbp_device_block->func == 0) || (pbp_device_block->func == 2)) { + for (idx_dev = 0; + ((bpctl_dev_arr[idx_dev].pdev != NULL) + && (idx_dev < device_num)); idx_dev++) { + if ((bpctl_dev_arr[idx_dev].bus == + pbp_device_block->bus) + && (bpctl_dev_arr[idx_dev].slot == + pbp_device_block->slot)) { + if ((pbp_device_block->func == 0) + && (bpctl_dev_arr[idx_dev].func == 1)) { + pbp_device_block_slave = + &bpctl_dev_arr[idx_dev]; + break; + } + if ((pbp_device_block->func == 2) && + (bpctl_dev_arr[idx_dev].func == 3)) { + pbp_device_block_slave = + &bpctl_dev_arr[idx_dev]; + break; + } + } + } + } else + pbp_device_block_slave = pbp_device_block; + if (!pbp_device_block_slave) { + len = sprintf(page, "fail\n"); + *eof = 1; + return len; + } + net_slave_dev = pbp_device_block_slave->ndev; + if (net_slave_dev) { + if (net_slave_dev) + len = sprintf(page, "%s\n", net_slave_dev->name); + else + len = sprintf(page, "fail\n"); + + } + + *eof = 1; + return len; +} + +int +get_bypass_caps_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_bypass_caps_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "-1\n"); + else + len = sprintf(page, "0x%x\n", ret); + *eof = 1; + return len; + +} + +int +get_wd_set_caps_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_wd_set_caps_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "-1\n"); + else + len = sprintf(page, "0x%x\n", ret); + *eof = 1; + return len; +} + +int +set_bypass_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int bypass_param = 0, length = 0; + + if (count > (sizeof(kbuf) - 1)) + return -1; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + bypass_param = 1; + else if (strcmp(kbuf, "off") == 0) + bypass_param = 0; + + set_bypass_fn(pbp_device_block, bypass_param); + + return count; +} + +int +set_tap_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int tap_param = 0, length = 0; + + if (count > (sizeof(kbuf) - 1)) + return -1; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + tap_param = 1; + else if (strcmp(kbuf, "off") == 0) + tap_param = 0; + + set_tap_fn(pbp_device_block, tap_param); + + return count; +} + +int +set_disc_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int tap_param = 0, length = 0; + + if (count > (sizeof(kbuf) - 1)) + return -1; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + tap_param = 1; + else if (strcmp(kbuf, "off") == 0) + tap_param = 0; + + set_disc_fn(pbp_device_block, tap_param); + + return count; +} + +int +get_bypass_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_bypass_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 1) + len = sprintf(page, "on\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + + *eof = 1; + return len; +} + +int +get_tap_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_tap_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 1) + len = sprintf(page, "on\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + + *eof = 1; + return len; +} + +int +get_disc_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_disc_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 1) + len = sprintf(page, "on\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + + *eof = 1; + return len; +} + +int +get_bypass_change_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_bypass_change_fn(pbp_device_block); + if (ret == 1) + len = sprintf(page, "on\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + else + len = sprintf(page, "fail\n"); + + *eof = 1; + return len; +} + +int +get_tap_change_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_tap_change_fn(pbp_device_block); + if (ret == 1) + len = sprintf(page, "on\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + else + len = sprintf(page, "fail\n"); + + *eof = 1; + return len; +} + +int +get_disc_change_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_disc_change_fn(pbp_device_block); + if (ret == 1) + len = sprintf(page, "on\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + else + len = sprintf(page, "fail\n"); + + *eof = 1; + return len; +} + +#define isdigit(c) (c >= '0' && c <= '9') +__inline static int atoi(char **s) +{ + int i = 0; + while (isdigit(**s)) + i = i * 10 + *((*s)++) - '0'; + return i; +} + +int +set_bypass_wd_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + int timeout; + int ret; + + ret = kstrtoint_from_user(buffer, count, 10, &timeout); + if (ret) + return ret; + set_bypass_wd_fn(pbp_device_block, timeout); + + return count; +} + +int +get_bypass_wd_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0, timeout = 0; + + ret = get_bypass_wd_fn(pbp_device_block, &timeout); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (timeout == -1) + len = sprintf(page, "unknown\n"); + else if (timeout == 0) + len = sprintf(page, "disable\n"); + else + len = sprintf(page, "%d\n", timeout); + + *eof = 1; + return len; +} + +int +get_wd_expire_time_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0, timeout = 0; + + ret = get_wd_expire_time_fn(pbp_device_block, &timeout); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (timeout == -1) + len = sprintf(page, "expire\n"); + else if (timeout == 0) + len = sprintf(page, "disable\n"); + + else + len = sprintf(page, "%d\n", timeout); + *eof = 1; + return len; +} + +int +get_tpl_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_tpl_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 1) + len = sprintf(page, "on\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + + *eof = 1; + return len; +} + +#ifdef PMC_FIX_FLAG +int +get_wait_at_pwup_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_bp_wait_at_pwup_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 1) + len = sprintf(page, "on\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + + *eof = 1; + return len; +} + +int +get_hw_reset_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_bp_hw_reset_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 1) + len = sprintf(page, "on\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + + *eof = 1; + return len; +} + +#endif /*PMC_WAIT_FLAG */ + +int +reset_bypass_wd_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = reset_bypass_wd_timer_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 0) + len = sprintf(page, "disable\n"); + else if (ret == 1) + len = sprintf(page, "success\n"); + + *eof = 1; + return len; +} + +int +set_dis_bypass_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int bypass_param = 0, length = 0; + + if (count >= sizeof(kbuf)) + return -EINVAL; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + bypass_param = 1; + else if (strcmp(kbuf, "off") == 0) + bypass_param = 0; + + set_dis_bypass_fn(pbp_device_block, bypass_param); + + return count; +} + +int +set_dis_tap_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int tap_param = 0, length = 0; + + if (count >= sizeof(kbuf)) + return -EINVAL; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + tap_param = 1; + else if (strcmp(kbuf, "off") == 0) + tap_param = 0; + + set_dis_tap_fn(pbp_device_block, tap_param); + + return count; +} + +int +set_dis_disc_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int tap_param = 0, length = 0; + + if (count >= sizeof(kbuf)) + return -EINVAL; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + tap_param = 1; + else if (strcmp(kbuf, "off") == 0) + tap_param = 0; + + set_dis_disc_fn(pbp_device_block, tap_param); + + return count; +} + +int +get_dis_bypass_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_dis_bypass_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + else + len = sprintf(page, "on\n"); + + *eof = 1; + return len; +} + +int +get_dis_tap_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_dis_tap_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + else + len = sprintf(page, "on\n"); + + *eof = 1; + return len; +} + +int +get_dis_disc_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_dis_disc_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + else + len = sprintf(page, "on\n"); + + *eof = 1; + return len; +} + +int +set_bypass_pwup_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int bypass_param = 0, length = 0; + + if (count >= sizeof(kbuf)) + return -EINVAL; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + bypass_param = 1; + else if (strcmp(kbuf, "off") == 0) + bypass_param = 0; + + set_bypass_pwup_fn(pbp_device_block, bypass_param); + + return count; +} + +int +set_bypass_pwoff_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int bypass_param = 0, length = 0; + + if (count >= sizeof(kbuf)) + return -EINVAL; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + bypass_param = 1; + else if (strcmp(kbuf, "off") == 0) + bypass_param = 0; + + set_bypass_pwoff_fn(pbp_device_block, bypass_param); + + return count; +} + +int +set_tap_pwup_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int tap_param = 0, length = 0; + + if (count >= sizeof(kbuf)) + return -EINVAL; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + tap_param = 1; + else if (strcmp(kbuf, "off") == 0) + tap_param = 0; + + set_tap_pwup_fn(pbp_device_block, tap_param); + + return count; +} + +int +set_disc_pwup_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int tap_param = 0, length = 0; + + if (count >= sizeof(kbuf)) + return -EINVAL; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + tap_param = 1; + else if (strcmp(kbuf, "off") == 0) + tap_param = 0; + + set_disc_pwup_fn(pbp_device_block, tap_param); + + return count; +} + +int +get_bypass_pwup_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_bypass_pwup_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + else + len = sprintf(page, "on\n"); + + *eof = 1; + return len; +} + +int +get_bypass_pwoff_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_bypass_pwoff_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + else + len = sprintf(page, "on\n"); + + *eof = 1; + return len; +} + +int +get_tap_pwup_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_tap_pwup_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + else + len = sprintf(page, "on\n"); + + *eof = 1; + return len; +} + +int +get_disc_pwup_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_disc_pwup_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + else + len = sprintf(page, "on\n"); + + *eof = 1; + return len; +} + +int +set_std_nic_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int bypass_param = 0, length = 0; + + if (count >= sizeof(kbuf)) + return -EINVAL; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + bypass_param = 1; + else if (strcmp(kbuf, "off") == 0) + bypass_param = 0; + + set_std_nic_fn(pbp_device_block, bypass_param); + + return count; +} + +int +get_std_nic_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_std_nic_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + else + len = sprintf(page, "on\n"); + + *eof = 1; + return len; +} + +int +get_wd_exp_mode_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_wd_exp_mode_fn(pbp_device_block); + if (ret == 1) + len = sprintf(page, "tap\n"); + else if (ret == 0) + len = sprintf(page, "bypass\n"); + else if (ret == 2) + len = sprintf(page, "disc\n"); + + else + len = sprintf(page, "fail\n"); + + *eof = 1; + return len; +} + +int +set_wd_exp_mode_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int bypass_param = 0, length = 0; + + if (count > (sizeof(kbuf) - 1)) + return -1; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "tap") == 0) + bypass_param = 1; + else if (strcmp(kbuf, "bypass") == 0) + bypass_param = 0; + else if (strcmp(kbuf, "disc") == 0) + bypass_param = 2; + + set_wd_exp_mode_fn(pbp_device_block, bypass_param); + + return count; +} + +int +get_wd_autoreset_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_wd_autoreset_fn(pbp_device_block); + if (ret >= 0) + len = sprintf(page, "%d\n", ret); + else + len = sprintf(page, "fail\n"); + + *eof = 1; + return len; +} + +int +set_wd_autoreset_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + int timeout; + int ret; + + ret = kstrtoint_from_user(buffer, count, 10, &timeout); + if (ret) + return ret; + set_wd_autoreset_fn(pbp_device_block, timeout); + + return count; +} + +int +set_tpl_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int tpl_param = 0, length = 0; + + if (count > (sizeof(kbuf) - 1)) + return -1; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + tpl_param = 1; + else if (strcmp(kbuf, "off") == 0) + tpl_param = 0; + + set_tpl_fn(pbp_device_block, tpl_param); + + return count; +} + +#ifdef PMC_FIX_FLAG +int +set_wait_at_pwup_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int tpl_param = 0, length = 0; + + if (count > (sizeof(kbuf) - 1)) + return -1; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + tpl_param = 1; + else if (strcmp(kbuf, "off") == 0) + tpl_param = 0; + + set_bp_wait_at_pwup_fn(pbp_device_block, tpl_param); + + return count; +} + +int +set_hw_reset_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int tpl_param = 0, length = 0; + + if (count > (sizeof(kbuf) - 1)) + return -1; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + tpl_param = 1; + else if (strcmp(kbuf, "off") == 0) + tpl_param = 0; + + set_bp_hw_reset_fn(pbp_device_block, tpl_param); + + return count; +} + +#endif /*PMC_FIX_FLAG */ + +int bypass_proc_create_dev_sd(bpctl_dev_t *pbp_device_block) +{ + struct bypass_pfs_sd *current_pfs = &(pbp_device_block->bypass_pfs_set); + static struct proc_dir_entry *procfs_dir = NULL; + int ret = 0; + + if (!pbp_device_block->ndev) + return -1; + sprintf(current_pfs->dir_name, "bypass_%s", + pbp_device_block->ndev->name); + + if (!bp_procfs_dir) + return -1; + + /* create device proc dir */ + procfs_dir = proc_getdir(current_pfs->dir_name, bp_procfs_dir); + if (procfs_dir == 0) { + printk(KERN_DEBUG "Could not create procfs directory %s\n", + current_pfs->dir_name); + return -1; + } + current_pfs->bypass_entry = procfs_dir; + + if (bypass_proc_create_entry_sd(&(current_pfs->bypass_info), BYPASS_INFO_ENTRY_SD, NULL, /* write */ + get_bypass_info_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + + if (pbp_device_block->bp_caps & SW_CTL_CAP) { + + /* Create set param proc's */ + if (bypass_proc_create_entry_sd(&(current_pfs->bypass_slave), BYPASS_SLAVE_ENTRY_SD, NULL, /* write */ + get_bypass_slave_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->bypass_caps), BYPASS_CAPS_ENTRY_SD, NULL, /* write */ + get_bypass_caps_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->wd_set_caps), WD_SET_CAPS_ENTRY_SD, NULL, /* write */ + get_wd_set_caps_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + if (bypass_proc_create_entry_sd(&(current_pfs->bypass_wd), BYPASS_WD_ENTRY_SD, set_bypass_wd_pfs, /* write */ + get_bypass_wd_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->wd_expire_time), WD_EXPIRE_TIME_ENTRY_SD, NULL, /* write */ + get_wd_expire_time_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->reset_bypass_wd), RESET_BYPASS_WD_ENTRY_SD, NULL, /* write */ + reset_bypass_wd_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->std_nic), STD_NIC_ENTRY_SD, set_std_nic_pfs, /* write */ + get_std_nic_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + + if (pbp_device_block->bp_caps & BP_CAP) { + if (bypass_proc_create_entry_sd(&(current_pfs->bypass), BYPASS_ENTRY_SD, set_bypass_pfs, /* write */ + get_bypass_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->dis_bypass), DIS_BYPASS_ENTRY_SD, set_dis_bypass_pfs, /* write */ + get_dis_bypass_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->bypass_pwup), BYPASS_PWUP_ENTRY_SD, set_bypass_pwup_pfs, /* write */ + get_bypass_pwup_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; + if (bypass_proc_create_entry_sd(&(current_pfs->bypass_pwoff), BYPASS_PWOFF_ENTRY_SD, set_bypass_pwoff_pfs, /* write */ + get_bypass_pwoff_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->bypass_change), BYPASS_CHANGE_ENTRY_SD, NULL, /* write */ + get_bypass_change_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; + } + + if (pbp_device_block->bp_caps & TAP_CAP) { + + if (bypass_proc_create_entry_sd(&(current_pfs->tap), TAP_ENTRY_SD, set_tap_pfs, /* write */ + get_tap_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->dis_tap), DIS_TAP_ENTRY_SD, set_dis_tap_pfs, /* write */ + get_dis_tap_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->tap_pwup), TAP_PWUP_ENTRY_SD, set_tap_pwup_pfs, /* write */ + get_tap_pwup_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->tap_change), TAP_CHANGE_ENTRY_SD, NULL, /* write */ + get_tap_change_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; + } + if (pbp_device_block->bp_caps & DISC_CAP) { + + if (bypass_proc_create_entry_sd(&(current_pfs->tap), DISC_ENTRY_SD, set_disc_pfs, /* write */ + get_disc_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; +#if 1 + + if (bypass_proc_create_entry_sd(&(current_pfs->dis_tap), DIS_DISC_ENTRY_SD, set_dis_disc_pfs, /* write */ + get_dis_disc_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; +#endif + + if (bypass_proc_create_entry_sd(&(current_pfs->tap_pwup), DISC_PWUP_ENTRY_SD, set_disc_pwup_pfs, /* write */ + get_disc_pwup_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->tap_change), DISC_CHANGE_ENTRY_SD, NULL, /* write */ + get_disc_change_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; + } + + if (bypass_proc_create_entry_sd(&(current_pfs->wd_exp_mode), WD_EXP_MODE_ENTRY_SD, set_wd_exp_mode_pfs, /* write */ + get_wd_exp_mode_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->wd_autoreset), WD_AUTORESET_ENTRY_SD, set_wd_autoreset_pfs, /* write */ + get_wd_autoreset_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + if (bypass_proc_create_entry_sd(&(current_pfs->tpl), TPL_ENTRY_SD, set_tpl_pfs, /* write */ + get_tpl_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; +#ifdef PMC_FIX_FLAG + if (bypass_proc_create_entry_sd(&(current_pfs->tpl), WAIT_AT_PWUP_ENTRY_SD, set_wait_at_pwup_pfs, /* write */ + get_wait_at_pwup_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + if (bypass_proc_create_entry_sd(&(current_pfs->tpl), HW_RESET_ENTRY_SD, set_hw_reset_pfs, /* write */ + get_hw_reset_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + +#endif + + } + if (ret < 0) + printk(KERN_DEBUG "Create proc entry failed\n"); + + return ret; +} + +int bypass_proc_remove_dev_sd(bpctl_dev_t *pbp_device_block) +{ + + struct bypass_pfs_sd *current_pfs = &pbp_device_block->bypass_pfs_set; + struct proc_dir_entry *pde = current_pfs->bypass_entry, *pde_curr = + NULL; + char name[256]; + + if (!pde) + return 0; + for (pde = pde->subdir; pde;) { + strcpy(name, pde->name); + pde_curr = pde; + pde = pde->next; + remove_proc_entry(name, current_pfs->bypass_entry); + } + if (!pde) + remove_proc_entry(current_pfs->dir_name, bp_procfs_dir); + current_pfs->bypass_entry = NULL; + + return 0; +} diff --git a/drivers/staging/silicom/bp_mod.h b/drivers/staging/silicom/bp_mod.h new file mode 100644 index 000000000000..b8275f5611fa --- /dev/null +++ b/drivers/staging/silicom/bp_mod.h @@ -0,0 +1,704 @@ +/******************************************************************************/ +/* */ +/* Bypass Control utility, Copyright (c) 2005 Silicom */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* */ +/* bp_mod.h */ +/* */ +/******************************************************************************/ + +#ifndef BP_MOD_H +#define BP_MOD_H +#include "bits.h" + +#define EXPORT_SYMBOL_NOVERS EXPORT_SYMBOL + +#define usec_delay(x) udelay(x) +#ifndef msec_delay_bp +#define msec_delay_bp(x) \ +do { \ + int i; \ + if (1) { \ + for (i = 0; i < 1000; i++) { \ + udelay(x) ; \ + } \ + } else { \ + msleep(x); \ + } \ +} while (0) + +#endif + +#include <linux/param.h> + +#ifndef jiffies_to_msecs +#define jiffies_to_msecs(x) _kc_jiffies_to_msecs(x) +static inline unsigned int jiffies_to_msecs(const unsigned long j) +{ +#if HZ <= 1000 && !(1000 % HZ) + return (1000 / HZ) * j; +#elif HZ > 1000 && !(HZ % 1000) + return (j + (HZ / 1000) - 1) / (HZ / 1000); +#else + return (j * 1000) / HZ; +#endif +} +#endif + +#define SILICOM_VID 0x1374 +#define SILICOM_SVID 0x1374 + +#define SILICOM_PXG2BPFI_SSID 0x0026 +#define SILICOM_PXG2BPFILX_SSID 0x0027 +#define SILICOM_PXGBPI_SSID 0x0028 +#define SILICOM_PXGBPIG_SSID 0x0029 +#define SILICOM_PXG2TBFI_SSID 0x002a +#define SILICOM_PXG4BPI_SSID 0x002c +#define SILICOM_PXG4BPFI_SSID 0x002d +#define SILICOM_PXG4BPFILX_SSID 0x002e +#define SILICOM_PXG2BPFIL_SSID 0x002F +#define SILICOM_PXG2BPFILLX_SSID 0x0030 +#define SILICOM_PEG4BPI_SSID 0x0031 +#define SILICOM_PEG2BPI_SSID 0x0037 +#define SILICOM_PEG4BPIN_SSID 0x0038 +#define SILICOM_PEG2BPFI_SSID 0x0039 +#define SILICOM_PEG2BPFILX_SSID 0x003A +#define SILICOM_PMCXG2BPFI_SSID 0x003B +#define NOKIA_PMCXG2BPFIN_SSID 0x0510 +#define NOKIA_PMCXG2BPIN_SSID 0x0513 +#define NOKIA_PMCXG4BPIN_SSID 0x0514 +#define NOKIA_PMCXG2BPFIN_SVID 0x13B8 +#define NOKIA_PMCXG2BPIN2_SSID 0x0515 +#define NOKIA_PMCXG4BPIN2_SSID 0x0516 +#define SILICOM_PMCX2BPI_SSID 0x041 +#define SILICOM_PMCX4BPI_SSID 0x042 +#define SILICOM_PXG2BISC1_SSID 0x003d +#define SILICOM_PEG2TBFI_SSID 0x003E +#define SILICOM_PXG2TBI_SSID 0x003f +#define SILICOM_PXG4BPFID_SSID 0x0043 +#define SILICOM_PEG4BPFI_SSID 0x0040 +#define SILICOM_PEG4BPIPT_SSID 0x0044 +#define SILICOM_PXG6BPI_SSID 0x0045 +#define SILICOM_PEG4BPIL_SSID 0x0046 +#define SILICOM_PEG2BPI5_SSID 0x0052 +#define SILICOM_PEG6BPI_SSID 0x0053 +#define SILICOM_PEG4BPFI5_SSID 0x0050 +#define SILICOM_PEG4BPFI5LX_SSID 0x0051 +#define SILICOM_PEG2BISC6_SSID 0x54 + +#define SILICOM_PEG6BPIFC_SSID 0x55 + +#define SILICOM_PEG2BPFI5_SSID 0x0056 +#define SILICOM_PEG2BPFI5LX_SSID 0x0057 + +#define SILICOM_PXEG4BPFI_SSID 0x0058 + +#define SILICOM_PEG2BPFID_SSID 0x0047 +#define SILICOM_PEG2BPFIDLX_SSID 0x004C +#define SILICOM_MEG2BPFILN_SSID 0x0048 +#define SILICOM_MEG2BPFINX_SSID 0x0049 +#define SILICOM_PEG4BPFILX_SSID 0x004A +#define SILICOM_MHIO8AD_SSID 0x004F + +#define SILICOM_MEG2BPFILXLN_SSID 0x004b +#define SILICOM_PEG2BPIX1_SSID 0x004d +#define SILICOM_MEG2BPFILXNX_SSID 0x004e + +#define SILICOM_PE10G2BPISR_SSID 0x0102 +#define SILICOM_PE10G2BPILR_SSID 0x0103 +#define SILICOM_PE10G2BPICX4_SSID 0x0101 + +#define SILICOM_XE10G2BPILR_SSID 0x0163 +#define SILICOM_XE10G2BPISR_SSID 0x0162 +#define SILICOM_XE10G2BPICX4_SSID 0x0161 +#define SILICOM_XE10G2BPIT_SSID 0x0160 + +#define SILICOM_PE10GDBISR_SSID 0x0181 +#define SILICOM_PE10GDBILR_SSID 0x0182 + +#define SILICOM_PE210G2DBi9SR_SSID 0x0188 +#define SILICOM_PE210G2DBi9SRRB_SSID 0x0188 +#define SILICOM_PE210G2DBi9LR_SSID 0x0189 +#define SILICOM_PE210G2DBi9LRRB_SSID 0x0189 +#define SILICOM_PE310G4DBi940SR_SSID 0x018C + +#define SILICOM_PE310G4BPi9T_SSID 0x130 +#define SILICOM_PE310G4BPi9SR_SSID 0x132 +#define SILICOM_PE310G4BPi9LR_SSID 0x133 + +#define NOKIA_XE10G2BPIXR_SVID 0x13B8 +#define NOKIA_XE10G2BPIXR_SSID 0x051C + +#define INTEL_PEG4BPII_PID 0x10A0 +#define INTEL_PEG4BPFII_PID 0x10A1 +#define INTEL_PEG4BPII_SSID 0x11A0 +#define INTEL_PEG4BPFII_SSID 0x11A1 + +#define INTEL_PEG4BPIIO_SSID 0x10A0 +#define INTEL_PEG4BPIIO_PID 0x105e + +#define BROADCOM_VID 0x14e4 +#define BROADCOM_PE10G2_PID 0x164e + +#define SILICOM_PE10G2BPTCX4_SSID 0x0141 +#define SILICOM_PE10G2BPTSR_SSID 0x0142 +#define SILICOM_PE10G2BPTLR_SSID 0x0143 +#define SILICOM_PE10G2BPTT_SSID 0x0140 + +#define SILICOM_PEG4BPI6_SSID 0x0320 +#define SILICOM_PEG4BPFI6_SSID 0x0321 +#define SILICOM_PEG4BPFI6LX_SSID 0x0322 +#define SILICOM_PEG4BPFI6ZX_SSID 0x0323 + +#define SILICOM_PEG2BPI6_SSID 0x0300 +#define SILICOM_PEG2BPFI6_SSID 0x0301 +#define SILICOM_PEG2BPFI6LX_SSID 0x0302 +#define SILICOM_PEG2BPFI6ZX_SSID 0x0303 +#define SILICOM_PEG2BPFI6FLXM_SSID 0x0304 + +#define SILICOM_PEG2DBI6_SSID 0x0308 +#define SILICOM_PEG2DBFI6_SSID 0x0309 +#define SILICOM_PEG2DBFI6LX_SSID 0x030A +#define SILICOM_PEG2DBFI6ZX_SSID 0x030B + +#define SILICOM_MEG2BPI6_SSID 0x0310 +#define SILICOM_XEG2BPI6_SSID 0x0318 +#define SILICOM_PEG4BPI6FC_SSID 0x0328 +#define SILICOM_PEG4BPFI6FC_SSID 0x0329 +#define SILICOM_PEG4BPFI6FCLX_SSID 0x032A +#define SILICOM_PEG4BPFI6FCZX_SSID 0x032B + +#define SILICOM_PEG6BPI6_SSID 0x0340 + +#define SILICOM_PEG2BPI6SC6_SSID 0x0360 + +#define SILICOM_MEG2BPI6_SSID 0x0310 +#define SILICOM_XEG2BPI6_SSID 0x0318 +#define SILICOM_MEG4BPI6_SSID 0x0330 + +#define SILICOM_PE2G4BPi80L_SSID 0x0380 + +#define SILICOM_M6E2G8BPi80A_SSID 0x0474 + +#define SILICOM_PE2G4BPi35_SSID 0x03d8 + +#define SILICOM_PE2G4BPFi80_SSID 0x0381 +#define SILICOM_PE2G4BPFi80LX_SSID 0x0382 +#define SILICOM_PE2G4BPFi80ZX_SSID 0x0383 + +#define SILICOM_PE2G4BPi80_SSID 0x0388 + +#define SILICOM_PE2G2BPi80_SSID 0x0390 +#define SILICOM_PE2G2BPFi80_SSID 0x0391 +#define SILICOM_PE2G2BPFi80LX_SSID 0x0392 +#define SILICOM_PE2G2BPFi80ZX_SSID 0x0393 + +#define SILICOM_PE2G4BPi35L_SSID 0x03D0 +#define SILICOM_PE2G4BPFi35_SSID 0x03D1 +#define SILICOM_PE2G4BPFi35LX_SSID 0x03D2 +#define SILICOM_PE2G4BPFi35ZX_SSID 0x03D3 + +#define SILICOM_PE2G2BPi35_SSID 0x03c0 +#define SILICOM_PAC1200BPi35_SSID 0x03cc +#define SILICOM_PE2G2BPFi35_SSID 0x03C1 +#define SILICOM_PE2G2BPFi35LX_SSID 0x03C2 +#define SILICOM_PE2G2BPFi35ZX_SSID 0x03C3 + +#define SILICOM_PE2G6BPi35_SSID 0x03E0 +#define SILICOM_PE2G6BPi35CX_SSID 0x0AA0 + +#define INTEL_PE210G2SPI9_SSID 0x00C + +#define SILICOM_M1EG2BPI6_SSID 0x400 + +#define SILICOM_M1EG2BPFI6_SSID 0x0401 +#define SILICOM_M1EG2BPFI6LX_SSID 0x0402 +#define SILICOM_M1EG2BPFI6ZX_SSID 0x0403 + +#define SILICOM_M1EG4BPI6_SSID 0x0420 + +#define SILICOM_M1EG4BPFI6_SSID 0x0421 +#define SILICOM_M1EG4BPFI6LX_SSID 0x0422 +#define SILICOM_M1EG4BPFI6ZX_SSID 0x0423 + +#define SILICOM_M1EG6BPI6_SSID 0x0440 + +#define SILICOM_M1E2G4BPi80_SSID 0x0460 +#define SILICOM_M1E2G4BPFi80_SSID 0x0461 +#define SILICOM_M1E2G4BPFi80LX_SSID 0x0462 +#define SILICOM_M1E2G4BPFi80ZX_SSID 0x0463 + +#define SILICOM_M6E2G8BPi80_SSID 0x0470 +#define SILICOM_PE210G2BPi40_SSID 0x01a0 + +#define PEG540_IF_SERIES(pid) \ + ((pid == SILICOM_PE210G2BPi40_SSID)) + +#define OLD_IF_SERIES(pid)\ + ((pid == SILICOM_PXG2BPFI_SSID) || \ + (pid == SILICOM_PXG2BPFILX_SSID)) + +#define P2BPFI_IF_SERIES(pid) \ + ((pid == SILICOM_PXG2BPFI_SSID) || \ + (pid == SILICOM_PXG2BPFILX_SSID) || \ + (pid == SILICOM_PEG2BPFI_SSID) || \ + (pid == SILICOM_PEG2BPFID_SSID) || \ + (pid == SILICOM_PEG2BPFIDLX_SSID) || \ + (pid == SILICOM_MEG2BPFILN_SSID) || \ + (pid == SILICOM_MEG2BPFINX_SSID) || \ + (pid == SILICOM_PEG4BPFILX_SSID) || \ + (pid == SILICOM_PEG4BPFI_SSID) || \ + (pid == SILICOM_PXEG4BPFI_SSID) || \ + (pid == SILICOM_PXG4BPFID_SSID) || \ + (pid == SILICOM_PEG2TBFI_SSID) || \ + (pid == SILICOM_PE10G2BPISR_SSID) || \ + (pid == SILICOM_PE10G2BPILR_SSID) || \ + (pid == SILICOM_PEG2BPFILX_SSID) || \ + (pid == SILICOM_PMCXG2BPFI_SSID) || \ + (pid == SILICOM_MHIO8AD_SSID) || \ + (pid == SILICOM_PEG4BPFI5LX_SSID) || \ + (pid == SILICOM_PEG4BPFI5_SSID) || \ + (pid == SILICOM_PEG4BPFI6FC_SSID) || \ + (pid == SILICOM_PEG4BPFI6FCLX_SSID) || \ + (pid == SILICOM_PEG4BPFI6FCZX_SSID) || \ + (pid == NOKIA_PMCXG2BPFIN_SSID) || \ + (pid == SILICOM_MEG2BPFILXLN_SSID) || \ + (pid == SILICOM_MEG2BPFILXNX_SSID) || \ + (pid == SILICOM_XE10G2BPIT_SSID) || \ + (pid == SILICOM_XE10G2BPICX4_SSID) || \ + (pid == SILICOM_XE10G2BPISR_SSID) || \ + (pid == NOKIA_XE10G2BPIXR_SSID) || \ + (pid == SILICOM_PE10GDBISR_SSID) || \ + (pid == SILICOM_PE10GDBILR_SSID) || \ + (pid == SILICOM_XE10G2BPILR_SSID)) + +#define INTEL_IF_SERIES(pid) \ + ((pid == INTEL_PEG4BPII_SSID) || \ + (pid == INTEL_PEG4BPIIO_SSID) || \ + (pid == INTEL_PEG4BPFII_SSID)) + +#define NOKIA_SERIES(pid) \ + ((pid == NOKIA_PMCXG2BPIN_SSID) || \ + (pid == NOKIA_PMCXG4BPIN_SSID) || \ + (pid == SILICOM_PMCX4BPI_SSID) || \ + (pid == NOKIA_PMCXG2BPFIN_SSID) || \ + (pid == SILICOM_PMCXG2BPFI_SSID) || \ + (pid == NOKIA_PMCXG2BPIN2_SSID) || \ + (pid == NOKIA_PMCXG4BPIN2_SSID) || \ + (pid == SILICOM_PMCX2BPI_SSID)) + +#define DISCF_IF_SERIES(pid) \ + (pid == SILICOM_PEG2TBFI_SSID) + +#define PEGF_IF_SERIES(pid) \ + ((pid == SILICOM_PEG2BPFI_SSID) || \ + (pid == SILICOM_PEG2BPFID_SSID) || \ + (pid == SILICOM_PEG2BPFIDLX_SSID) || \ + (pid == SILICOM_PEG2BPFILX_SSID) || \ + (pid == SILICOM_PEG4BPFI_SSID) || \ + (pid == SILICOM_PXEG4BPFI_SSID) || \ + (pid == SILICOM_MEG2BPFILN_SSID) || \ + (pid == SILICOM_MEG2BPFINX_SSID) || \ + (pid == SILICOM_PEG4BPFILX_SSID) || \ + (pid == SILICOM_PEG2TBFI_SSID) || \ + (pid == SILICOM_MEG2BPFILXLN_SSID) || \ + (pid == SILICOM_MEG2BPFILXNX_SSID)) + +#define TPL_IF_SERIES(pid) \ + ((pid == SILICOM_PXG2BPFIL_SSID) || \ + (pid == SILICOM_PXG2BPFILLX_SSID) || \ + (pid == SILICOM_PXG2TBFI_SSID) || \ + (pid == SILICOM_PXG4BPFID_SSID) || \ + (pid == SILICOM_PXG4BPFI_SSID)) + +#define BP10G_IF_SERIES(pid) \ + ((pid == SILICOM_PE10G2BPISR_SSID) || \ + (pid == SILICOM_PE10G2BPICX4_SSID) || \ + (pid == SILICOM_PE10G2BPILR_SSID) || \ + (pid == SILICOM_XE10G2BPIT_SSID) || \ + (pid == SILICOM_XE10G2BPICX4_SSID) || \ + (pid == SILICOM_XE10G2BPISR_SSID) || \ + (pid == NOKIA_XE10G2BPIXR_SSID) || \ + (pid == SILICOM_PE10GDBISR_SSID) || \ + (pid == SILICOM_PE10GDBILR_SSID) || \ + (pid == SILICOM_XE10G2BPILR_SSID)) + +#define BP10GB_IF_SERIES(pid) \ + ((pid == SILICOM_PE10G2BPTCX4_SSID) || \ + (pid == SILICOM_PE10G2BPTSR_SSID) || \ + (pid == SILICOM_PE10G2BPTLR_SSID) || \ + (pid == SILICOM_PE10G2BPTT_SSID)) + +#define BP10G_CX4_SERIES(pid) \ + (pid == SILICOM_PE10G2BPICX4_SSID) + +#define BP10GB_CX4_SERIES(pid) \ + (pid == SILICOM_PE10G2BPTCX4_SSID) + +#define SILICOM_M2EG2BPFI6_SSID 0x0501 +#define SILICOM_M2EG2BPFI6LX_SSID 0x0502 +#define SILICOM_M2EG2BPFI6ZX_SSID 0x0503 +#define SILICOM_M2EG4BPI6_SSID 0x0520 + +#define SILICOM_M2EG4BPFI6_SSID 0x0521 +#define SILICOM_M2EG4BPFI6LX_SSID 0x0522 +#define SILICOM_M2EG4BPFI6ZX_SSID 0x0523 + +#define SILICOM_M2EG6BPI6_SSID 0x0540 + +#define SILICOM_M1E10G2BPI9CX4_SSID 0x481 +#define SILICOM_M1E10G2BPI9SR_SSID 0x482 +#define SILICOM_M1E10G2BPI9LR_SSID 0x483 +#define SILICOM_M1E10G2BPI9T_SSID 0x480 + +#define SILICOM_M2E10G2BPI9CX4_SSID 0x581 +#define SILICOM_M2E10G2BPI9SR_SSID 0x582 +#define SILICOM_M2E10G2BPI9LR_SSID 0x583 +#define SILICOM_M2E10G2BPI9T_SSID 0x580 + +#define SILICOM_PE210G2BPI9CX4_SSID 0x121 +#define SILICOM_PE210G2BPI9SR_SSID 0x122 +#define SILICOM_PE210G2BPI9LR_SSID 0x123 +#define SILICOM_PE210G2BPI9T_SSID 0x120 + +#define DBI_IF_SERIES(pid) \ + ((pid == SILICOM_PE10GDBISR_SSID) || \ + (pid == SILICOM_PE10GDBILR_SSID) || \ + (pid == SILICOM_XE10G2BPILR_SSID) || \ + (pid == SILICOM_PE210G2DBi9LR_SSID)) + +#define PEGF5_IF_SERIES(pid) \ + ((pid == SILICOM_PEG2BPFI5_SSID) || \ + (pid == SILICOM_PEG2BPFI5LX_SSID) || \ + (pid == SILICOM_PEG4BPFI6_SSID) || \ + (pid == SILICOM_PEG4BPFI6LX_SSID) || \ + (pid == SILICOM_PEG4BPFI6ZX_SSID) || \ + (pid == SILICOM_PEG2BPFI6_SSID) || \ + (pid == SILICOM_PEG2BPFI6LX_SSID) || \ + (pid == SILICOM_PEG2BPFI6ZX_SSID) || \ + (pid == SILICOM_PEG2BPFI6FLXM_SSID) || \ + (pid == SILICOM_PEG2DBFI6_SSID) || \ + (pid == SILICOM_PEG2DBFI6LX_SSID) || \ + (pid == SILICOM_PEG2DBFI6ZX_SSID) || \ + (pid == SILICOM_PEG4BPI6FC_SSID) || \ + (pid == SILICOM_PEG4BPFI6FCLX_SSID) || \ + (pid == SILICOM_PEG4BPI6FC_SSID) || \ + (pid == SILICOM_M1EG2BPFI6_SSID) || \ + (pid == SILICOM_M1EG2BPFI6LX_SSID) || \ + (pid == SILICOM_M1EG2BPFI6ZX_SSID) || \ + (pid == SILICOM_M1EG4BPFI6_SSID) || \ + (pid == SILICOM_M1EG4BPFI6LX_SSID) || \ + (pid == SILICOM_M1EG4BPFI6ZX_SSID) || \ + (pid == SILICOM_M2EG2BPFI6_SSID) || \ + (pid == SILICOM_M2EG2BPFI6LX_SSID) || \ + (pid == SILICOM_M2EG2BPFI6ZX_SSID) || \ + (pid == SILICOM_M2EG4BPFI6_SSID) || \ + (pid == SILICOM_M2EG4BPFI6LX_SSID) || \ + (pid == SILICOM_M2EG4BPFI6ZX_SSID) || \ + (pid == SILICOM_PEG4BPFI6FCZX_SSID)) + +#define PEG5_IF_SERIES(pid) \ + ((pid == SILICOM_PEG4BPI6_SSID) || \ + (pid == SILICOM_PEG2BPI6_SSID) || \ + (pid == SILICOM_PEG4BPI6FC_SSID) || \ + (pid == SILICOM_PEG6BPI6_SSID) || \ + (pid == SILICOM_PEG2BPI6SC6_SSID) || \ + (pid == SILICOM_MEG2BPI6_SSID) || \ + (pid == SILICOM_XEG2BPI6_SSID) || \ + (pid == SILICOM_MEG4BPI6_SSID) || \ + (pid == SILICOM_M1EG2BPI6_SSID) || \ + (pid == SILICOM_M1EG4BPI6_SSID) || \ + (pid == SILICOM_M1EG6BPI6_SSID) || \ + (pid == SILICOM_PEG6BPI_SSID) || \ + (pid == SILICOM_PEG4BPIL_SSID) || \ + (pid == SILICOM_PEG2BISC6_SSID) || \ + (pid == SILICOM_PEG2BPI5_SSID)) + +#define PEG80_IF_SERIES(pid) \ + ((pid == SILICOM_M1E2G4BPi80_SSID) || \ + (pid == SILICOM_M6E2G8BPi80_SSID) || \ + (pid == SILICOM_PE2G4BPi80L_SSID) || \ + (pid == SILICOM_M6E2G8BPi80A_SSID) || \ + (pid == SILICOM_PE2G2BPi35_SSID) || \ + (pid == SILICOM_PAC1200BPi35_SSID) || \ + (pid == SILICOM_PE2G4BPi35_SSID) || \ + (pid == SILICOM_PE2G4BPi35L_SSID) || \ + (pid == SILICOM_PE2G6BPi35_SSID) || \ + (pid == SILICOM_PE2G2BPi80_SSID) || \ + (pid == SILICOM_PE2G4BPi80_SSID) || \ + (pid == SILICOM_PE2G4BPFi80_SSID) || \ + (pid == SILICOM_PE2G4BPFi80LX_SSID) || \ + (pid == SILICOM_PE2G4BPFi80ZX_SSID) || \ + (pid == SILICOM_PE2G4BPFi80ZX_SSID) || \ + (pid == SILICOM_PE2G2BPFi80_SSID) || \ + (pid == SILICOM_PE2G2BPFi80LX_SSID) || \ + (pid == SILICOM_PE2G2BPFi80ZX_SSID) || \ + (pid == SILICOM_PE2G2BPFi35_SSID) || \ + (pid == SILICOM_PE2G2BPFi35LX_SSID) || \ + (pid == SILICOM_PE2G2BPFi35ZX_SSID) || \ + (pid == SILICOM_PE2G4BPFi35_SSID) || \ + (pid == SILICOM_PE2G4BPFi35LX_SSID) || \ + (pid == SILICOM_PE2G4BPFi35ZX_SSID)) + +#define PEGF80_IF_SERIES(pid) \ + ((pid == SILICOM_PE2G4BPFi80_SSID) || \ + (pid == SILICOM_PE2G4BPFi80LX_SSID) || \ + (pid == SILICOM_PE2G4BPFi80ZX_SSID) || \ + (pid == SILICOM_PE2G4BPFi80ZX_SSID) || \ + (pid == SILICOM_M1E2G4BPFi80_SSID) || \ + (pid == SILICOM_M1E2G4BPFi80LX_SSID) || \ + (pid == SILICOM_M1E2G4BPFi80ZX_SSID) || \ + (pid == SILICOM_PE2G2BPFi80_SSID) || \ + (pid == SILICOM_PE2G2BPFi80LX_SSID) || \ + (pid == SILICOM_PE2G2BPFi80ZX_SSID) || \ + (pid == SILICOM_PE2G2BPFi35_SSID) || \ + (pid == SILICOM_PE2G2BPFi35LX_SSID) || \ + (pid == SILICOM_PE2G2BPFi35ZX_SSID) || \ + (pid == SILICOM_PE2G4BPFi35_SSID) || \ + (pid == SILICOM_PE2G4BPFi35LX_SSID) || \ + (pid == SILICOM_PE2G4BPFi35ZX_SSID)) + +#define BP10G9_IF_SERIES(pid) \ + ((pid == INTEL_PE210G2SPI9_SSID) || \ + (pid == SILICOM_M1E10G2BPI9CX4_SSID) || \ + (pid == SILICOM_M1E10G2BPI9SR_SSID) || \ + (pid == SILICOM_M1E10G2BPI9LR_SSID) || \ + (pid == SILICOM_M1E10G2BPI9T_SSID) || \ + (pid == SILICOM_M2E10G2BPI9CX4_SSID) || \ + (pid == SILICOM_M2E10G2BPI9SR_SSID) || \ + (pid == SILICOM_M2E10G2BPI9LR_SSID) || \ + (pid == SILICOM_M2E10G2BPI9T_SSID) || \ + (pid == SILICOM_PE210G2BPI9CX4_SSID) || \ + (pid == SILICOM_PE210G2BPI9SR_SSID) || \ + (pid == SILICOM_PE210G2BPI9LR_SSID) || \ + (pid == SILICOM_PE210G2DBi9SR_SSID) || \ + (pid == SILICOM_PE210G2DBi9SRRB_SSID) || \ + (pid == SILICOM_PE210G2DBi9LR_SSID) || \ + (pid == SILICOM_PE210G2DBi9LRRB_SSID) || \ + (pid == SILICOM_PE310G4DBi940SR_SSID) || \ + (pid == SILICOM_PEG2BISC6_SSID) || \ + (pid == SILICOM_PE310G4BPi9T_SSID) || \ + (pid == SILICOM_PE310G4BPi9SR_SSID) || \ + (pid == SILICOM_PE310G4BPi9LR_SSID) || \ + (pid == SILICOM_PE210G2BPI9T_SSID)) + +/*******************************************************/ +/* 1G INTERFACE ****************************************/ +/*******************************************************/ + +/* Intel Registers */ +#define BPCTLI_CTRL 0x00000 +#define BPCTLI_CTRL_SWDPIO0 0x00400000 +#define BPCTLI_CTRL_SWDPIN0 0x00040000 + +#define BPCTLI_CTRL_EXT 0x00018 /* Extended Device Control - RW */ +#define BPCTLI_STATUS 0x00008 /* Device Status - RO */ + +/* HW related */ +#define BPCTLI_CTRL_EXT_SDP6_DATA 0x00000040 /* Value of SW Defineable Pin 6 */ +#define BPCTLI_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */ +#define BPCTLI_CTRL_SDP0_DATA 0x00040000 /* SWDPIN 0 value */ +#define BPCTLI_CTRL_EXT_SDP6_DIR 0x00000400 /* Direction of SDP6 0=in 1=out */ +#define BPCTLI_CTRL_EXT_SDP7_DIR 0x00000800 /* Direction of SDP7 0=in 1=out */ +#define BPCTLI_CTRL_SDP0_DIR 0x00400000 /* SDP0 Input or output */ +#define BPCTLI_CTRL_SWDPIN1 0x00080000 +#define BPCTLI_CTRL_SDP1_DIR 0x00800000 + +#define BPCTLI_STATUS_LU 0x00000002 /* Link up.0=no,1=link */ + +#define BPCTLI_CTRL_SDP0_SHIFT 18 +#define BPCTLI_CTRL_EXT_SDP6_SHIFT 6 + +#define BPCTLI_STATUS_TBIMODE 0x00000020 +#define BPCTLI_CTRL_EXT_LINK_MODE_PCIE_SERDES 0x00C00000 +#define BPCTLI_CTRL_EXT_LINK_MODE_MASK 0x00C00000 + +#define BPCTLI_CTRL_EXT_MCLK_DIR BPCTLI_CTRL_EXT_SDP7_DIR +#define BPCTLI_CTRL_EXT_MCLK_DATA BPCTLI_CTRL_EXT_SDP7_DATA +#define BPCTLI_CTRL_EXT_MDIO_DIR BPCTLI_CTRL_EXT_SDP6_DIR +#define BPCTLI_CTRL_EXT_MDIO_DATA BPCTLI_CTRL_EXT_SDP6_DATA + +#define BPCTLI_CTRL_EXT_MCLK_DIR5 BPCTLI_CTRL_SDP1_DIR +#define BPCTLI_CTRL_EXT_MCLK_DATA5 BPCTLI_CTRL_SWDPIN1 +#define BPCTLI_CTRL_EXT_MCLK_DIR80 BPCTLI_CTRL_EXT_SDP6_DIR +#define BPCTLI_CTRL_EXT_MCLK_DATA80 BPCTLI_CTRL_EXT_SDP6_DATA +#define BPCTLI_CTRL_EXT_MDIO_DIR5 BPCTLI_CTRL_SWDPIO0 +#define BPCTLI_CTRL_EXT_MDIO_DATA5 BPCTLI_CTRL_SWDPIN0 +#define BPCTLI_CTRL_EXT_MDIO_DIR80 BPCTLI_CTRL_SWDPIO0 +#define BPCTLI_CTRL_EXT_MDIO_DATA80 BPCTLI_CTRL_SWDPIN0 + +#define BPCTL_WRITE_REG(a, reg, value) \ + (writel((value), (void *)(((a)->mem_map) + BPCTLI_##reg))) + +#define BPCTL_READ_REG(a, reg) ( \ + readl((void *)((a)->mem_map) + BPCTLI_##reg)) + +#define BPCTL_WRITE_FLUSH(a) BPCTL_READ_REG(a, STATUS) + +#define BPCTL_BP_WRITE_REG(a, reg, value) ({ \ + BPCTL_WRITE_REG(a, reg, value); \ + BPCTL_WRITE_FLUSH(a); }) + +/**************************************************************/ +/************** 82575 Interface********************************/ +/**************************************************************/ + +#define BPCTLI_MII_CR_POWER_DOWN 0x0800 +#define BPCTLI_PHY_CONTROL 0x00 /* Control Register */ +#define BPCTLI_MDIC 0x00020 /* MDI Control - RW */ +#define BPCTLI_IGP01E1000_PHY_PAGE_SELECT 0x1F /* Page Select */ +#define BPCTLI_MAX_PHY_REG_ADDRESS 0x1F /* 5 bit address bus (0-0x1F) */ + +#define BPCTLI_MDIC_DATA_MASK 0x0000FFFF +#define BPCTLI_MDIC_REG_MASK 0x001F0000 +#define BPCTLI_MDIC_REG_SHIFT 16 +#define BPCTLI_MDIC_PHY_MASK 0x03E00000 +#define BPCTLI_MDIC_PHY_SHIFT 21 +#define BPCTLI_MDIC_OP_WRITE 0x04000000 +#define BPCTLI_MDIC_OP_READ 0x08000000 +#define BPCTLI_MDIC_READY 0x10000000 +#define BPCTLI_MDIC_INT_EN 0x20000000 +#define BPCTLI_MDIC_ERROR 0x40000000 + +#define BPCTLI_SWFW_PHY0_SM 0x02 +#define BPCTLI_SWFW_PHY1_SM 0x04 + +#define BPCTLI_SW_FW_SYNC 0x05B5C /* Software-Firmware Synchronization - RW */ + +#define BPCTLI_SWSM 0x05B50 /* SW Semaphore */ +#define BPCTLI_FWSM 0x05B54 /* FW Semaphore */ + +#define BPCTLI_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */ +#define BPCTLI_SWSM_SWESMBI 0x00000002 /* FW Semaphore bit */ +#define BPCTLI_MAX_PHY_MULTI_PAGE_REG 0xF +#define BPCTLI_GEN_POLL_TIMEOUT 640 + +/********************************************************/ + +/********************************************************/ +/* 10G INTERFACE ****************************************/ +/********************************************************/ + +#define BP10G_I2CCTL 0x28 + +/* I2CCTL Bit Masks */ +#define BP10G_I2C_CLK_IN 0x00000001 +#define BP10G_I2C_CLK_OUT 0x00000002 +#define BP10G_I2C_DATA_IN 0x00000004 +#define BP10G_I2C_DATA_OUT 0x00000008 + +#define BP10G_ESDP 0x20 + +#define BP10G_SDP0_DIR 0x100 +#define BP10G_SDP1_DIR 0x200 +#define BP10G_SDP3_DIR 0x800 +#define BP10G_SDP4_DIR BIT_12 +#define BP10G_SDP5_DIR 0x2000 +#define BP10G_SDP0_DATA 0x001 +#define BP10G_SDP1_DATA 0x002 +#define BP10G_SDP3_DATA 0x008 +#define BP10G_SDP4_DATA 0x010 +#define BP10G_SDP5_DATA 0x020 + +#define BP10G_SDP2_DIR 0x400 +#define BP10G_SDP2_DATA 0x4 + +#define BP10G_EODSDP 0x28 + +#define BP10G_SDP6_DATA_IN 0x001 +#define BP10G_SDP6_DATA_OUT 0x002 + +#define BP10G_SDP7_DATA_IN 0x004 +#define BP10G_SDP7_DATA_OUT 0x008 + +#define BP10G_MCLK_DATA_OUT BP10G_SDP7_DATA_OUT +#define BP10G_MDIO_DATA_OUT BP10G_SDP6_DATA_OUT +#define BP10G_MDIO_DATA_IN BP10G_SDP6_DATA_IN + +#define BP10G_MDIO_DATA /*BP10G_SDP5_DATA*/ BP10G_SDP3_DATA +#define BP10G_MDIO_DIR /*BP10G_SDP5_DIR*/ BP10G_SDP3_DATA + +/*#define BP10G_MCLK_DATA_OUT9 BP10G_I2C_CLK_OUT +#define BP10G_MDIO_DATA_OUT9 BP10G_I2C_DATA_OUT*/ + + /*#define BP10G_MCLK_DATA_OUT9*//*BP10G_I2C_DATA_OUT */ +#define BP10G_MDIO_DATA_OUT9 BP10G_I2C_DATA_OUT /*BP10G_I2C_CLK_OUT */ + +/* VIA EOSDP ! */ +#define BP10G_MCLK_DATA_OUT9 BP10G_SDP4_DATA +#define BP10G_MCLK_DIR_OUT9 BP10G_SDP4_DIR + +/*#define BP10G_MDIO_DATA_IN9 BP10G_I2C_DATA_IN*/ + +#define BP10G_MDIO_DATA_IN9 BP10G_I2C_DATA_IN /*BP10G_I2C_CLK_IN */ + +#define BP540_MDIO_DATA /*BP10G_SDP5_DATA*/ BP10G_SDP0_DATA +#define BP540_MDIO_DIR /*BP10G_SDP5_DIR*/ BP10G_SDP0_DIR +#define BP540_MCLK_DATA BP10G_SDP2_DATA +#define BP540_MCLK_DIR BP10G_SDP2_DIR + +#define BP10G_WRITE_REG(a, reg, value) \ + (writel((value), (void *)(((a)->mem_map) + BP10G_##reg))) + +#define BP10G_READ_REG(a, reg) ( \ + readl((void *)((a)->mem_map) + BP10G_##reg)) + +/*****BROADCOM*******************************************/ + +#define BP10GB_MISC_REG_GPIO 0xa490 +#define BP10GB_GPIO3_P0 BIT_3 +#define BP10GB_GPIO3_P1 BIT_7 + +#define BP10GB_GPIO3_SET_P0 BIT_11 +#define BP10GB_GPIO3_CLR_P0 BIT_19 +#define BP10GB_GPIO3_OE_P0 BIT_27 + +#define BP10GB_GPIO3_SET_P1 BIT_15 +#define BP10GB_GPIO3_CLR_P1 BIT_23 +#define BP10GB_GPIO3_OE_P1 BIT_31 + +#define BP10GB_GPIO0_P1 0x10 +#define BP10GB_GPIO0_P0 0x1 +#define BP10GB_GPIO0_CLR_P0 0x10000 +#define BP10GB_GPIO0_CLR_P1 0x100000 +#define BP10GB_GPIO0_SET_P0 0x100 +#define BP10GB_GPIO0_SET_P1 0x1000 + +#define BP10GB_GPIO0_OE_P1 0x10000000 +#define BP10GB_GPIO0_OE_P0 0x1000000 + +#define BP10GB_MISC_REG_SPIO 0xa4fc +#define BP10GB_GPIO4_OE BIT_28 +#define BP10GB_GPIO5_OE BIT_29 +#define BP10GB_GPIO4_CLR BIT_20 +#define BP10GB_GPIO5_CLR BIT_21 +#define BP10GB_GPIO4_SET BIT_12 +#define BP10GB_GPIO5_SET BIT_13 +#define BP10GB_GPIO4 BIT_4 +#define BP10GB_GPIO5 BIT_5 + +#define BP10GB_MCLK_DIR BP10GB_GPIO5_OE +#define BP10GB_MDIO_DIR BP10GB_GPIO4_OE + +#define BP10GB_MCLK_DATA BP10GB_GPIO5 +#define BP10GB_MDIO_DATA BP10GB_GPIO4 + +#define BP10GB_MCLK_SET BP10GB_GPIO5_SET +#define BP10GB_MDIO_SET BP10GB_GPIO4_SET + +#define BP10GB_MCLK_CLR BP10GB_GPIO5_CLR +#define BP10GB_MDIO_CLR BP10GB_GPIO4_CLR + +#define BP10GB_WRITE_REG(a, reg, value) \ + (writel((value), (void *)(((a)->mem_map) + BP10GB_##reg))) + +#define BP10GB_READ_REG(a, reg) ( \ + readl((void *)((a)->mem_map) + BP10GB_##reg)) + +#endif + +int bp_proc_create(void); diff --git a/drivers/staging/silicom/bp_proc.c b/drivers/staging/silicom/bp_proc.c new file mode 100644 index 000000000000..6ad4b27472e4 --- /dev/null +++ b/drivers/staging/silicom/bp_proc.c @@ -0,0 +1,1350 @@ +/******************************************************************************/ +/* */ +/* Copyright (c) 2004-2006 Silicom, Ltd */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* */ +/******************************************************************************/ + +#include <linux/version.h> +#if defined(CONFIG_SMP) && ! defined(__SMP__) +#define __SMP__ +#endif + +#include <linux/proc_fs.h> +#include <linux/netdevice.h> +#include <asm/uaccess.h> +//#include <linux/smp_lock.h> +#include "bp_mod.h" + +#define BP_PROC_DIR "bypass" +//#define BYPASS_SUPPORT "bypass" + +#ifdef BYPASS_SUPPORT + +#define GPIO6_SET_ENTRY_SD "gpio6_set" +#define GPIO6_CLEAR_ENTRY_SD "gpio6_clear" + +#define GPIO7_SET_ENTRY_SD "gpio7_set" +#define GPIO7_CLEAR_ENTRY_SD "gpio7_clear" + +#define PULSE_SET_ENTRY_SD "pulse_set" +#define ZERO_SET_ENTRY_SD "zero_set" +#define PULSE_GET1_ENTRY_SD "pulse_get1" +#define PULSE_GET2_ENTRY_SD "pulse_get2" + +#define CMND_ON_ENTRY_SD "cmnd_on" +#define CMND_OFF_ENTRY_SD "cmnd_off" +#define RESET_CONT_ENTRY_SD "reset_cont" + + /*COMMANDS*/ +#define BYPASS_INFO_ENTRY_SD "bypass_info" +#define BYPASS_SLAVE_ENTRY_SD "bypass_slave" +#define BYPASS_CAPS_ENTRY_SD "bypass_caps" +#define WD_SET_CAPS_ENTRY_SD "wd_set_caps" +#define BYPASS_ENTRY_SD "bypass" +#define BYPASS_CHANGE_ENTRY_SD "bypass_change" +#define BYPASS_WD_ENTRY_SD "bypass_wd" +#define WD_EXPIRE_TIME_ENTRY_SD "wd_expire_time" +#define RESET_BYPASS_WD_ENTRY_SD "reset_bypass_wd" +#define DIS_BYPASS_ENTRY_SD "dis_bypass" +#define BYPASS_PWUP_ENTRY_SD "bypass_pwup" +#define BYPASS_PWOFF_ENTRY_SD "bypass_pwoff" +#define STD_NIC_ENTRY_SD "std_nic" +#define STD_NIC_ENTRY_SD "std_nic" +#define TAP_ENTRY_SD "tap" +#define TAP_CHANGE_ENTRY_SD "tap_change" +#define DIS_TAP_ENTRY_SD "dis_tap" +#define TAP_PWUP_ENTRY_SD "tap_pwup" +#define TWO_PORT_LINK_ENTRY_SD "two_port_link" +#define WD_EXP_MODE_ENTRY_SD "wd_exp_mode" +#define WD_AUTORESET_ENTRY_SD "wd_autoreset" +#define TPL_ENTRY_SD "tpl" +#define WAIT_AT_PWUP_ENTRY_SD "wait_at_pwup" +#define HW_RESET_ENTRY_SD "hw_reset" +#define DISC_ENTRY_SD "disc" +#define DISC_CHANGE_ENTRY_SD "disc_change" +#define DIS_DISC_ENTRY_SD "dis_disc" +#define DISC_PWUP_ENTRY_SD "disc_pwup" +#endif //bypass_support +static struct proc_dir_entry *bp_procfs_dir; + +static struct proc_dir_entry *proc_getdir(char *name, + struct proc_dir_entry *proc_dir) +{ + struct proc_dir_entry *pde = proc_dir; + for (pde = pde->subdir; pde; pde = pde->next) { + if (pde->namelen && (strcmp(name, pde->name) == 0)) { + /* directory exists */ + break; + } + } + if (pde == (struct proc_dir_entry *)0) { + /* create the directory */ + pde = create_proc_entry(name, S_IFDIR, proc_dir); + if (pde == (struct proc_dir_entry *)0) { + return (pde); + } + } + return (pde); +} + +#ifdef BYPASS_SUPPORT + +int +bypass_proc_create_entry_sd(struct pfs_unit *pfs_unit_curr, + char *proc_name, + write_proc_t * write_proc, + read_proc_t * read_proc, + struct proc_dir_entry *parent_pfs, void *data) +{ + strcpy(pfs_unit_curr->proc_name, proc_name); + pfs_unit_curr->proc_entry = create_proc_entry(pfs_unit_curr->proc_name, + S_IFREG | S_IRUSR | + S_IWUSR | S_IRGRP | + S_IROTH, parent_pfs); + if (pfs_unit_curr->proc_entry == 0) { + + return -1; + } + + pfs_unit_curr->proc_entry->read_proc = read_proc; + pfs_unit_curr->proc_entry->write_proc = write_proc; + pfs_unit_curr->proc_entry->data = data; + + return 0; + +} + +int +get_bypass_info_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + int len = 0; + + len += sprintf(page, "Name\t\t\t%s\n", pbp_device_block->bp_name); + len += + sprintf(page + len, "Firmware version\t0x%x\n", + pbp_device_block->bp_fw_ver); + + *eof = 1; + return len; +} + +int +get_bypass_slave_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + struct pci_dev *pci_slave_dev = pbp_device_block->bp_slave; + struct net_device *net_slave_dev; + int len = 0; + + if (is_bypass_fn(pbp_device_block)) { + net_slave_dev = pci_get_drvdata(pci_slave_dev); + if (net_slave_dev) + len = sprintf(page, "%s\n", net_slave_dev->name); + else + len = sprintf(page, "fail\n"); + } else + len = sprintf(page, "fail\n"); + + *eof = 1; + return len; +} + +int +get_bypass_caps_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_bypass_caps_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "-1\n"); + else + len = sprintf(page, "0x%x\n", ret); + *eof = 1; + return len; + +} + +int +get_wd_set_caps_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_wd_set_caps_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "-1\n"); + else + len = sprintf(page, "0x%x\n", ret); + *eof = 1; + return len; +} + +int +set_bypass_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int bypass_param = 0, length = 0; + + if (count > (sizeof(kbuf) - 1)) + return -1; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + bypass_param = 1; + else if (strcmp(kbuf, "off") == 0) + bypass_param = 0; + + set_bypass_fn(pbp_device_block, bypass_param); + + return count; +} + +int +set_tap_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int tap_param = 0, length = 0; + + if (count > (sizeof(kbuf) - 1)) + return -1; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + tap_param = 1; + else if (strcmp(kbuf, "off") == 0) + tap_param = 0; + + set_tap_fn(pbp_device_block, tap_param); + + return count; +} + +int +set_disc_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int tap_param = 0, length = 0; + + if (count > (sizeof(kbuf) - 1)) + return -1; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + tap_param = 1; + else if (strcmp(kbuf, "off") == 0) + tap_param = 0; + + set_disc_fn(pbp_device_block, tap_param); + + return count; +} + +int +get_bypass_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_bypass_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 1) + len = sprintf(page, "on\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + + *eof = 1; + return len; +} + +int +get_tap_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_tap_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 1) + len = sprintf(page, "on\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + + *eof = 1; + return len; +} + +int +get_disc_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_disc_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 1) + len = sprintf(page, "on\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + + *eof = 1; + return len; +} + +int +get_bypass_change_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_bypass_change_fn(pbp_device_block); + if (ret == 1) + len = sprintf(page, "on\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + else + len = sprintf(page, "fail\n"); + + *eof = 1; + return len; +} + +int +get_tap_change_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_tap_change_fn(pbp_device_block); + if (ret == 1) + len = sprintf(page, "on\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + else + len = sprintf(page, "fail\n"); + + *eof = 1; + return len; +} + +int +get_disc_change_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_disc_change_fn(pbp_device_block); + if (ret == 1) + len = sprintf(page, "on\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + else + len = sprintf(page, "fail\n"); + + *eof = 1; + return len; +} + +int +set_bypass_wd_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + unsigned int timeout = 0; + char *timeout_ptr = kbuf; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + timeout_ptr = kbuf; + timeout = atoi(&timeout_ptr); + + set_bypass_wd_fn(pbp_device_block, timeout); + + return count; +} + +int +get_bypass_wd_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0, timeout = 0; + + ret = get_bypass_wd_fn(pbp_device_block, &timeout); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (timeout == -1) + len = sprintf(page, "unknown\n"); + else if (timeout == 0) + len = sprintf(page, "disable\n"); + else + len = sprintf(page, "%d\n", timeout); + + *eof = 1; + return len; +} + +int +get_wd_expire_time_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0, timeout = 0; + + ret = get_wd_expire_time_fn(pbp_device_block, &timeout); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (timeout == -1) + len = sprintf(page, "expire\n"); + else if (timeout == 0) + len = sprintf(page, "disable\n"); + + else + len = sprintf(page, "%d\n", timeout); + *eof = 1; + return len; +} + +int +get_tpl_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_tpl_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 1) + len = sprintf(page, "on\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + + *eof = 1; + return len; +} + +#ifdef PMC_FIX_FLAG +int +get_wait_at_pwup_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_bp_wait_at_pwup_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 1) + len = sprintf(page, "on\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + + *eof = 1; + return len; +} + +int +get_hw_reset_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_bp_hw_reset_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 1) + len = sprintf(page, "on\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + + *eof = 1; + return len; +} + +#endif /*PMC_WAIT_FLAG */ + +int +reset_bypass_wd_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = reset_bypass_wd_timer_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 0) + len = sprintf(page, "disable\n"); + else if (ret == 1) + len = sprintf(page, "success\n"); + + *eof = 1; + return len; +} + +int +set_dis_bypass_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int bypass_param = 0, length = 0; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + bypass_param = 1; + else if (strcmp(kbuf, "off") == 0) + bypass_param = 0; + + set_dis_bypass_fn(pbp_device_block, bypass_param); + + return count; +} + +int +set_dis_tap_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int tap_param = 0, length = 0; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + tap_param = 1; + else if (strcmp(kbuf, "off") == 0) + tap_param = 0; + + set_dis_tap_fn(pbp_device_block, tap_param); + + return count; +} + +int +set_dis_disc_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int tap_param = 0, length = 0; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + tap_param = 1; + else if (strcmp(kbuf, "off") == 0) + tap_param = 0; + + set_dis_disc_fn(pbp_device_block, tap_param); + + return count; +} + +int +get_dis_bypass_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_dis_bypass_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + else + len = sprintf(page, "on\n"); + + *eof = 1; + return len; +} + +int +get_dis_tap_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_dis_tap_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + else + len = sprintf(page, "on\n"); + + *eof = 1; + return len; +} + +int +get_dis_disc_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_dis_disc_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + else + len = sprintf(page, "on\n"); + + *eof = 1; + return len; +} + +int +set_bypass_pwup_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int bypass_param = 0, length = 0; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + bypass_param = 1; + else if (strcmp(kbuf, "off") == 0) + bypass_param = 0; + + set_bypass_pwup_fn(pbp_device_block, bypass_param); + + return count; +} + +int +set_bypass_pwoff_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int bypass_param = 0, length = 0; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + bypass_param = 1; + else if (strcmp(kbuf, "off") == 0) + bypass_param = 0; + + set_bypass_pwoff_fn(pbp_device_block, bypass_param); + + return count; +} + +int +set_tap_pwup_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int tap_param = 0, length = 0; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + tap_param = 1; + else if (strcmp(kbuf, "off") == 0) + tap_param = 0; + + set_tap_pwup_fn(pbp_device_block, tap_param); + + return count; +} + +int +set_disc_pwup_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int tap_param = 0, length = 0; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + tap_param = 1; + else if (strcmp(kbuf, "off") == 0) + tap_param = 0; + + set_disc_pwup_fn(pbp_device_block, tap_param); + + return count; +} + +int +get_bypass_pwup_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_bypass_pwup_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + else + len = sprintf(page, "on\n"); + + *eof = 1; + return len; +} + +int +get_bypass_pwoff_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_bypass_pwoff_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + else + len = sprintf(page, "on\n"); + + *eof = 1; + return len; +} + +int +get_tap_pwup_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_tap_pwup_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + else + len = sprintf(page, "on\n"); + + *eof = 1; + return len; +} + +int +get_disc_pwup_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_disc_pwup_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + else + len = sprintf(page, "on\n"); + + *eof = 1; + return len; +} + +int +set_std_nic_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int bypass_param = 0, length = 0; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + bypass_param = 1; + else if (strcmp(kbuf, "off") == 0) + bypass_param = 0; + + set_std_nic_fn(pbp_device_block, bypass_param); + + return count; +} + +int +get_std_nic_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_std_nic_fn(pbp_device_block); + if (ret == BP_NOT_CAP) + len = sprintf(page, "fail\n"); + else if (ret == 0) + len = sprintf(page, "off\n"); + else + len = sprintf(page, "on\n"); + + *eof = 1; + return len; +} + +int +get_wd_exp_mode_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_wd_exp_mode_fn(pbp_device_block); + if (ret == 1) + len = sprintf(page, "tap\n"); + else if (ret == 0) + len = sprintf(page, "bypass\n"); + else if (ret == 2) + len = sprintf(page, "disc\n"); + + else + len = sprintf(page, "fail\n"); + + *eof = 1; + return len; +} + +int +set_wd_exp_mode_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int bypass_param = 0, length = 0; + + if (count > (sizeof(kbuf) - 1)) + return -1; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "tap") == 0) + bypass_param = 1; + else if (strcmp(kbuf, "bypass") == 0) + bypass_param = 0; + else if (strcmp(kbuf, "disc") == 0) + bypass_param = 2; + + set_wd_exp_mode_fn(pbp_device_block, bypass_param); + + return count; +} + +int +get_wd_autoreset_pfs(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int len = 0, ret = 0; + + ret = get_wd_autoreset_fn(pbp_device_block); + if (ret >= 0) + len = sprintf(page, "%d\n", ret); + else + len = sprintf(page, "fail\n"); + + *eof = 1; + return len; +} + +int +set_wd_autoreset_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + u32 timeout = 0; + char *timeout_ptr = kbuf; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + timeout_ptr = kbuf; + timeout = atoi(&timeout_ptr); + + set_wd_autoreset_fn(pbp_device_block, timeout); + + return count; +} + +int +set_tpl_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int tpl_param = 0, length = 0; + + if (count > (sizeof(kbuf) - 1)) + return -1; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + tpl_param = 1; + else if (strcmp(kbuf, "off") == 0) + tpl_param = 0; + + set_tpl_fn(pbp_device_block, tpl_param); + + return count; +} + +#ifdef PMC_FIX_FLAG +int +set_wait_at_pwup_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int tpl_param = 0, length = 0; + + if (count > (sizeof(kbuf) - 1)) + return -1; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + tpl_param = 1; + else if (strcmp(kbuf, "off") == 0) + tpl_param = 0; + + set_bp_wait_at_pwup_fn(pbp_device_block, tpl_param); + + return count; +} + +int +set_hw_reset_pfs(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + + char kbuf[256]; + bpctl_dev_t *pbp_device_block = (bpctl_dev_t *) data; + + int tpl_param = 0, length = 0; + + if (count > (sizeof(kbuf) - 1)) + return -1; + + if (copy_from_user(&kbuf, buffer, count)) { + return -1; + } + + kbuf[count] = '\0'; + length = strlen(kbuf); + if (kbuf[length - 1] == '\n') + kbuf[--length] = '\0'; + + if (strcmp(kbuf, "on") == 0) + tpl_param = 1; + else if (strcmp(kbuf, "off") == 0) + tpl_param = 0; + + set_bp_hw_reset_fn(pbp_device_block, tpl_param); + + return count; +} + +#endif /*PMC_FIX_FLAG */ + +int bypass_proc_create_dev_sd(bpctl_dev_t * pbp_device_block) +{ + struct bypass_pfs_sd *current_pfs = &(pbp_device_block->bypass_pfs_set); + static struct proc_dir_entry *procfs_dir = NULL; + int ret = 0; + + sprintf(current_pfs->dir_name, "bypass_%s", dev->name); + + if (!bp_procfs_dir) + return -1; + + /* create device proc dir */ + procfs_dir = proc_getdir(current_pfs->dir_name, bp_procfs_dir); + if (procfs_dir == 0) { + printk(KERN_DEBUG "Could not create procfs directory %s\n", + current_pfs->dir_name); + return -1; + } + current_pfs->bypass_entry = procfs_dir; + + if (bypass_proc_create_entry(&(current_pfs->bypass_info), BYPASS_INFO_ENTRY_SD, NULL, /* write */ + get_bypass_info_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + + if (pbp_device_block->bp_caps & SW_CTL_CAP) { + + /* Create set param proc's */ + if (bypass_proc_create_entry_sd(&(current_pfs->bypass_slave), BYPASS_SLAVE_ENTRY_SD, NULL, /* write */ + get_bypass_slave_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->bypass_caps), BYPASS_CAPS_ENTRY_SD, NULL, /* write */ + get_bypass_caps_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->wd_set_caps), WD_SET_CAPS_ENTRY_SD, NULL, /* write */ + get_wd_set_caps_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + if (bypass_proc_create_entry_sd(&(current_pfs->bypass_wd), BYPASS_WD_ENTRY_SD, set_bypass_wd_pfs, /* write */ + get_bypass_wd_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->wd_expire_time), WD_EXPIRE_TIME_ENTRY_SD, NULL, /* write */ + get_wd_expire_time_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->reset_bypass_wd), RESET_BYPASS_WD_ENTRY_SD, NULL, /* write */ + reset_bypass_wd_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->std_nic), STD_NIC_ENTRY_SD, set_std_nic_pfs, /* write */ + get_std_nic_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + + if (pbp_device_block->bp_caps & BP_CAP) { + if (bypass_proc_create_entry_sd(&(current_pfs->bypass), BYPASS_ENTRY_SD, set_bypass_pfs, /* write */ + get_bypass_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->dis_bypass), DIS_BYPASS_ENTRY_SD, set_dis_bypass_pfs, /* write */ + get_dis_bypass_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->bypass_pwup), BYPASS_PWUP_ENTRY_SD, set_bypass_pwup_pfs, /* write */ + get_bypass_pwup_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; + if (bypass_proc_create_entry_sd(&(current_pfs->bypass_pwoff), BYPASS_PWOFF_ENTRY_SD, set_bypass_pwoff_pfs, /* write */ + get_bypass_pwoff_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->bypass_change), BYPASS_CHANGE_ENTRY_SD, NULL, /* write */ + get_bypass_change_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; + } + + if (pbp_device_block->bp_caps & TAP_CAP) { + + if (bypass_proc_create_entry_sd(&(current_pfs->tap), TAP_ENTRY_SD, set_tap_pfs, /* write */ + get_tap_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->dis_tap), DIS_TAP_ENTRY_SD, set_dis_tap_pfs, /* write */ + get_dis_tap_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->tap_pwup), TAP_PWUP_ENTRY_SD, set_tap_pwup_pfs, /* write */ + get_tap_pwup_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->tap_change), TAP_CHANGE_ENTRY_SD, NULL, /* write */ + get_tap_change_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; + } + if (pbp_device_block->bp_caps & DISC_CAP) { + + if (bypass_proc_create_entry_sd(&(current_pfs->tap), DISC_ENTRY_SD, set_disc_pfs, /* write */ + get_disc_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; +#if 1 + + if (bypass_proc_create_entry_sd(&(current_pfs->dis_tap), DIS_DISC_ENTRY_SD, set_dis_disc_pfs, /* write */ + get_dis_disc_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; +#endif + + if (bypass_proc_create_entry_sd(&(current_pfs->tap_pwup), DISC_PWUP_ENTRY_SD, set_disc_pwup_pfs, /* write */ + get_disc_pwup_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->tap_change), DISC_CHANGE_ENTRY_SD, NULL, /* write */ + get_disc_change_pfs, /* read */ + procfs_dir, + pbp_device_block)) + ret = -1; + } + + if (bypass_proc_create_entry_sd(&(current_pfs->wd_exp_mode), WD_EXP_MODE_ENTRY_SD, set_wd_exp_mode_pfs, /* write */ + get_wd_exp_mode_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + + if (bypass_proc_create_entry_sd(&(current_pfs->wd_autoreset), WD_AUTORESET_ENTRY_SD, set_wd_autoreset_pfs, /* write */ + get_wd_autoreset_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + if (bypass_proc_create_entry_sd(&(current_pfs->tpl), TPL_ENTRY_SD, set_tpl_pfs, /* write */ + get_tpl_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; +#ifdef PMC_FIX_FLAG + if (bypass_proc_create_entry_sd(&(current_pfs->tpl), WAIT_AT_PWUP_ENTRY_SD, set_wait_at_pwup_pfs, /* write */ + get_wait_at_pwup_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + if (bypass_proc_create_entry_sd(&(current_pfs->tpl), HW_RESET_ENTRY_SD, set_hw_reset_pfs, /* write */ + get_hw_reset_pfs, /* read */ + procfs_dir, pbp_device_block)) + ret = -1; + +#endif + + } + if (ret < 0) + printk(KERN_DEBUG "Create proc entry failed\n"); + + return ret; +} + +int bypass_proc_remove_dev_sd(bpctl_dev_t * pbp_device_block) +{ + + struct bypass_pfs_sd *current_pfs = &pbp_device_block->bypass_pfs_set; + struct proc_dir_entry *pde = current_pfs->bypass_entry, *pde_curr = + NULL; + char name[256]; + + for (pde = pde->subdir; pde;) { + strcpy(name, pde->name); + pde_curr = pde; + pde = pde->next; + remove_proc_entry(name, current_pfs->bypass_entry); + } + if (!pde) + remove_proc_entry(current_pfs->dir_name, bp_procfs_dir); + + return 0; +} + +#endif /* BYPASS_SUPPORT */ diff --git a/drivers/staging/silicom/bypass.h b/drivers/staging/silicom/bypass.h new file mode 100644 index 000000000000..08fa7a0fc8d8 --- /dev/null +++ b/drivers/staging/silicom/bypass.h @@ -0,0 +1,202 @@ +/******************************************************************************/ +/* */ +/* Bypass Control utility, Copyright (c) 2005 Silicom */ +/* All rights reserved. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* */ +/******************************************************************************/ + +#ifndef BYPASS_H +#define BYPASS_H + +/* Bypass related */ + +#define SYNC_CMD_VAL 2 /* 10b */ +#define SYNC_CMD_LEN 2 + +#define WR_CMD_VAL 2 /* 10b */ +#define WR_CMD_LEN 2 + +#define RD_CMD_VAL 1 /* 10b */ +#define RD_CMD_LEN 2 + +#define ADDR_CMD_LEN 4 + +#define WR_DATA_LEN 8 +#define RD_DATA_LEN 8 + +#define PIC_SIGN_REG_ADDR 0x7 +#define PIC_SIGN_VALUE 0xcd + +#define STATUS_REG_ADDR 0 +#define WDT_EN_MASK 0x01 /* BIT_0 */ +#define CMND_EN_MASK 0x02 /* BIT_1 */ +#define DIS_BYPASS_CAP_MASK 0x04 /* BIT_2 Bypass Cap is disable*/ +#define DFLT_PWRON_MASK 0x08 /* BIT_3 */ +#define BYPASS_OFF_MASK 0x10 /* BIT_4 */ +#define BYPASS_FLAG_MASK 0x20 /* BIT_5 */ +#define STD_NIC_MASK (DIS_BYPASS_CAP_MASK | BYPASS_OFF_MASK | DFLT_PWRON_MASK) +#define WD_EXP_FLAG_MASK 0x40 /* BIT_6 */ +#define DFLT_PWROFF_MASK 0x80 /* BIT_7 */ +#define STD_NIC_PWOFF_MASK (DIS_BYPASS_CAP_MASK | BYPASS_OFF_MASK | DFLT_PWRON_MASK | DFLT_PWROFF_MASK) + +#define PRODUCT_CAP_REG_ADDR 0x5 +#define BYPASS_SUPPORT_MASK 0x01 /* BIT_0 */ +#define TAP_SUPPORT_MASK 0x02 /* BIT_1 */ +#define NORMAL_UNSUPPORT_MASK 0x04 /* BIT_2 */ +#define DISC_SUPPORT_MASK 0x08 /* BIT_3 */ +#define TPL2_SUPPORT_MASK 0x10 /* BIT_4 */ +#define DISC_PORT_SUPPORT_MASK 0x20 /* BIT_5 */ + +#define STATUS_TAP_REG_ADDR 0x6 +#define WDTE_TAP_BPN_MASK 0x01 /* BIT_1 1 when wdt expired -> TAP, 0 - Bypass */ +#define DIS_TAP_CAP_MASK 0x04 /* BIT_2 TAP Cap is disable*/ +#define DFLT_PWRON_TAP_MASK 0x08 /* BIT_3 */ +#define TAP_OFF_MASK 0x10 /* BIT_4 */ +#define TAP_FLAG_MASK 0x20 /* BIT_5 */ +#define TX_DISA_MASK 0x40 +#define TX_DISB_MASK 0x80 + +#define STD_NIC_TAP_MASK (DIS_TAP_CAP_MASK | TAP_OFF_MASK | DFLT_PWRON_TAP_MASK) + +#define STATUS_DISC_REG_ADDR 13 +#define WDTE_DISC_BPN_MASK 0x01 /* BIT_0 1 when wdt expired -> TAP, 0 - Bypass */ +#define STD_NIC_ON_MASK 0x02 /* BIT_1 */ +#define DIS_DISC_CAP_MASK 0x04 /* BIT_2 TAP Cap is disable*/ +#define DFLT_PWRON_DISC_MASK 0x08 /* BIT_3 */ +#define DISC_OFF_MASK 0x10 /* BIT_4 */ +#define DISC_FLAG_MASK 0x20 /* BIT_5 */ +#define TPL2_FLAG_MASK 0x40 /* BIT_6 */ +#define STD_NIC_DISC_MASK DIS_DISC_CAP_MASK + +#define CONT_CONFIG_REG_ADDR 12 +#define EN_HW_RESET_MASK 0x2 /* BIT_1 */ +#define WAIT_AT_PWUP_MASK 0x1 /* BIT_0 */ + +#define VER_REG_ADDR 0x1 +#define BP_FW_VER_A0 0xa0 +#define BP_FW_VER_A1 0xa1 + +#define INT_VER_MASK 0xf0 +#define EXT_VER_MASK 0xf +/* */ +#define PXG2BPI_VER 0x0 +#define PXG2TBPI_VER 0x1 +#define PXE2TBPI_VER 0x2 +#define PXG4BPFI_VER 0x4 +#define BP_FW_EXT_VER7 0x6 +#define BP_FW_EXT_VER8 0x8 +#define BP_FW_EXT_VER9 0x9 + +#define OLD_IF_VER -1 + +#define CMND_REG_ADDR 10 /* 1010b */ +#define WDT_REG_ADDR 4 +#define TMRL_REG_ADDR 2 +#define TMRH_REG_ADDR 3 + +/* NEW_FW */ +#define WDT_INTERVAL 1 /* 5 //8 */ +#define WDT_CMND_INTERVAL 200 /* 50 */ +#define CMND_INTERVAL 200 /* 100 usec */ +#define PULSE_TIME 100 + +/* OLD_FW */ +#define INIT_CMND_INTERVAL 40 +#define PULSE_INTERVAL 5 +#define WDT_TIME_CNT 3 + +/* Intel Commands */ + +#define CMND_OFF_INT 0xf +#define PWROFF_BYPASS_ON_INT 0x5 +#define BYPASS_ON_INT 0x6 +#define DIS_BYPASS_CAP_INT 0x4 +#define RESET_WDT_INT 0x1 + +/* Intel timing */ + +#define BYPASS_DELAY_INT 4 /* msec */ +#define CMND_INTERVAL_INT 2 /* msec */ + +/* Silicom Commands */ +#define CMND_ON 0x4 +#define CMND_OFF 0x2 +#define BYPASS_ON 0xa +#define BYPASS_OFF 0x8 +#define PORT_LINK_EN 0xe +#define PORT_LINK_DIS 0xc +#define WDT_ON 0x10 /* 0x1f (11111) - max */ +#define TIMEOUT_UNIT 100 +#define TIMEOUT_MAX_STEP 15 +#define WDT_TIMEOUT_MIN 100 /* msec */ +#define WDT_TIMEOUT_MAX 3276800 /* msec */ +#define WDT_AUTO_MIN_INT 500 +#define WDT_TIMEOUT_DEF WDT_TIMEOUT_MIN +#define WDT_OFF 0x6 +#define WDT_RELOAD 0x9 +#define RESET_CONT 0x20 +#define DIS_BYPASS_CAP 0x22 +#define EN_BYPASS_CAP 0x24 +#define BYPASS_STATE_PWRON 0x26 +#define NORMAL_STATE_PWRON 0x28 +#define BYPASS_STATE_PWROFF 0x27 +#define NORMAL_STATE_PWROFF 0x29 +#define TAP_ON 0xb +#define TAP_OFF 0x9 +#define TAP_STATE_PWRON 0x2a +#define DIS_TAP_CAP 0x2c +#define EN_TAP_CAP 0x2e +#define STD_NIC_OFF 0x86 +#define STD_NIC_ON 0x84 +#define DISC_ON 0x85 +#define DISC_OFF 0x8a +#define DISC_STATE_PWRON 0x87 +#define DIS_DISC_CAP 0x88 +#define EN_DISC_CAP 0x89 +#define TPL2_ON 0x8c +#define TPL2_OFF 0x8b +#define BP_WAIT_AT_PWUP_EN 0x80 +#define BP_WAIT_AT_PWUP_DIS 0x81 +#define BP_HW_RESET_EN 0x82 +#define BP_HW_RESET_DIS 0x83 + +#define TX_DISA 0x8d +#define TX_DISB 0x8e +#define TX_ENA 0xA0 +#define TX_ENB 0xA1 + +#define TX_DISA_PWRUP 0xA2 +#define TX_DISB_PWRUP 0xA3 +#define TX_ENA_PWRUP 0xA4 +#define TX_ENB_PWRUP 0xA5 + +#define BYPASS_CAP_DELAY 21 /* msec */ +#define DFLT_PWRON_DELAY 10 /* msec */ +#define LATCH_DELAY 13 /* msec */ +#define EEPROM_WR_DELAY 8 /* msec */ + +#define BP_LINK_MON_DELAY 4 /* sec */ + +#define BP_FW_EXT_VER0 0xa0 +#define BP_FW_EXT_VER1 0xa1 +#define BP_FW_EXT_VER2 0xb1 + +#define BP_OK 0 +#define BP_NOT_CAP -1 +#define WDT_STATUS_EXP -2 +#define WDT_STATUS_UNKNOWN -1 +#define WDT_STATUS_EN 1 +#define WDT_STATUS_DIS 0 + +#ifdef BP_SELF_TEST +#define ETH_P_BPTEST 0xabba + +#define BPTEST_DATA_LEN 60 +#endif + +#endif /* BYPASS_H */ diff --git a/drivers/staging/silicom/bypasslib/Makefile b/drivers/staging/silicom/bypasslib/Makefile new file mode 100644 index 000000000000..80e8b9bc9357 --- /dev/null +++ b/drivers/staging/silicom/bypasslib/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the Bypass network device drivers. +# + +obj-$(CONFIG_SBYPASS) += bypass.o + diff --git a/drivers/staging/silicom/bypasslib/bp_ioctl.h b/drivers/staging/silicom/bypasslib/bp_ioctl.h new file mode 100644 index 000000000000..040c6fa8d5ad --- /dev/null +++ b/drivers/staging/silicom/bypasslib/bp_ioctl.h @@ -0,0 +1,198 @@ +/******************************************************************************/ +/* */ +/* bypass library, Copyright (c) 2004-2006 Silicom, Ltd */ +/* Corporation. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* */ +/* */ +/******************************************************************************/ + +#ifndef BP_IOCTL_H +#define BP_IOCTL_H + +#define BP_CAP 0x01 //BIT_0 +#define BP_STATUS_CAP 0x02 //BIT_1 +#define BP_STATUS_CHANGE_CAP 0x04 //BIT_2 +#define SW_CTL_CAP 0x08 //BIT_3 +#define BP_DIS_CAP 0x10 //BIT_4 +#define BP_DIS_STATUS_CAP 0x20 //BIT_5 +#define STD_NIC_CAP 0x40 //BIT_6 +#define BP_PWOFF_ON_CAP 0x80 //BIT_7 +#define BP_PWOFF_OFF_CAP 0x0100 //BIT_8 +#define BP_PWOFF_CTL_CAP 0x0200 //BIT_9 +#define BP_PWUP_ON_CAP 0x0400 //BIT_10 +#define BP_PWUP_OFF_CAP 0x0800 //BIT_11 +#define BP_PWUP_CTL_CAP 0x1000 //BIT_12 +#define WD_CTL_CAP 0x2000 //BIT_13 +#define WD_STATUS_CAP 0x4000 //BIT_14 +#define WD_TIMEOUT_CAP 0x8000 //BIT_15 +#define TX_CTL_CAP 0x10000 //BIT_16 +#define TX_STATUS_CAP 0x20000 //BIT_17 +#define TAP_CAP 0x40000 //BIT_18 +#define TAP_STATUS_CAP 0x80000 //BIT_19 +#define TAP_STATUS_CHANGE_CAP 0x100000 //BIT_20 +#define TAP_DIS_CAP 0x200000 //BIT_21 +#define TAP_DIS_STATUS_CAP 0x400000 //BIT_22 +#define TAP_PWUP_ON_CAP 0x800000 //BIT_23 +#define TAP_PWUP_OFF_CAP 0x1000000 //BIT 24 +#define TAP_PWUP_CTL_CAP 0x2000000 //BIT 25 +#define NIC_CAP_NEG 0x4000000 //BIT 26 +#define TPL_CAP 0x8000000 //BIT 27 +#define DISC_CAP 0x10000000 //BIT 28 +#define DISC_DIS_CAP 0x20000000 //BIT 29 +#define DISC_PWUP_CTL_CAP 0x40000000 //BIT 30 + +#define WD_MIN_TIME_MASK(val) (val & 0xf) +#define WD_STEP_COUNT_MASK(val) ((val & 0xf) << 5) +#define WDT_STEP_TIME 0x10 //BIT_4 + +#define WD_MIN_TIME_GET(desc) (desc & 0xf) +#define WD_STEP_COUNT_GET(desc) (desc>>5) & 0xf + +typedef enum { + IS_BYPASS = 1, + GET_BYPASS_SLAVE, + GET_BYPASS_CAPS, + GET_WD_SET_CAPS, + SET_BYPASS, + GET_BYPASS, + GET_BYPASS_CHANGE, + SET_BYPASS_WD, + GET_BYPASS_WD, + GET_WD_EXPIRE_TIME, + RESET_BYPASS_WD_TIMER, + SET_DIS_BYPASS, + GET_DIS_BYPASS, + SET_BYPASS_PWOFF, + GET_BYPASS_PWOFF, + SET_BYPASS_PWUP, + GET_BYPASS_PWUP, + SET_STD_NIC, + GET_STD_NIC, + SET_TX, + GET_TX, + SET_TAP, + GET_TAP, + GET_TAP_CHANGE, + SET_DIS_TAP, + GET_DIS_TAP, + SET_TAP_PWUP, + GET_TAP_PWUP, + SET_WD_EXP_MODE, + GET_WD_EXP_MODE, + SET_WD_AUTORESET, + GET_WD_AUTORESET, + SET_TPL, + GET_TPL, + SET_DISC, + GET_DISC, + GET_DISC_CHANGE, + SET_DIS_DISC, + GET_DIS_DISC, + SET_DISC_PWUP, + GET_DISC_PWUP, + + GET_BYPASS_INFO = 100, + GET_BP_WAIT_AT_PWUP, + SET_BP_WAIT_AT_PWUP, + GET_BP_HW_RESET, + SET_BP_HW_RESET, +} CMND_TYPE; + +typedef enum { + IF_SCAN_SD, + GET_DEV_NUM_SD, + IS_BYPASS_SD, + GET_BYPASS_SLAVE_SD, + GET_BYPASS_CAPS_SD, + GET_WD_SET_CAPS_SD, + SET_BYPASS_SD, + GET_BYPASS_SD, + GET_BYPASS_CHANGE_SD, + SET_BYPASS_WD_SD, + GET_BYPASS_WD_SD, + GET_WD_EXPIRE_TIME_SD, + RESET_BYPASS_WD_TIMER_SD, + SET_DIS_BYPASS_SD, + GET_DIS_BYPASS_SD, + SET_BYPASS_PWOFF_SD, + GET_BYPASS_PWOFF_SD, + SET_BYPASS_PWUP_SD, + GET_BYPASS_PWUP_SD, + SET_STD_NIC_SD, + GET_STD_NIC_SD, + SET_TX_SD, + GET_TX_SD, + SET_TAP_SD, + GET_TAP_SD, + GET_TAP_CHANGE_SD, + SET_DIS_TAP_SD, + GET_DIS_TAP_SD, + SET_TAP_PWUP_SD, + GET_TAP_PWUP_SD, + SET_WD_EXP_MODE_SD, + GET_WD_EXP_MODE_SD, + SET_WD_AUTORESET_SD, + GET_WD_AUTORESET_SD, + SET_TPL_SD, + GET_TPL_SD, + SET_DISC_SD, + GET_DISC_SD, + GET_DISC_CHANGE_SD, + SET_DIS_DISC_SD, + GET_DIS_DISC_SD, + SET_DISC_PWUP_SD, + GET_DISC_PWUP_SD, + + GET_BYPASS_INFO_SD = 100, + GET_BP_WAIT_AT_PWUP_SD, + SET_BP_WAIT_AT_PWUP_SD, + GET_BP_HW_RESET_SD, + SET_BP_HW_RESET_SD, + +} CMND_TYPE_SD; + +#define SIOCGIFBYPASS SIOCDEVPRIVATE+10 + +struct bp_info { + char prod_name[14]; + unsigned char fw_ver; +}; + +/* for passing single values */ +struct if_bypass { + char if_name[IFNAMSIZ]; + int cmd; + int data; +}; +struct if_bypass_info { + char if_name[IFNAMSIZ]; + char cmd; + struct bp_info bp_info; +}; + +/* +* The major device number. We can't rely on dynamic +* registration any more, because ioctls need to know +* it. +*/ + +#define MAGIC_NUM 'J' + +/* for passing single values */ +struct bpctl_cmd { + int status; + int data[8]; + int in_param[8]; + int out_param[8]; +}; + +#define IOCTL_TX_MSG(cmd) _IOWR(MAGIC_NUM, cmd, struct bpctl_cmd) + +#define DEVICE_NAME "bpctl" + +#endif diff --git a/drivers/staging/silicom/bypasslib/bplibk.h b/drivers/staging/silicom/bypasslib/bplibk.h new file mode 100644 index 000000000000..a1c85eec02f0 --- /dev/null +++ b/drivers/staging/silicom/bypasslib/bplibk.h @@ -0,0 +1,47 @@ +/******************************************************************************/ +/* */ +/* bypass library, Copyright (c) 2004 Silicom, Ltd */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* */ +/* bplib.h */ +/* */ +/******************************************************************************/ +#ifndef BYPASS_H +#define BYPASS_H + +#include "bp_ioctl.h" +#include "libbp_sd.h" + +#define IF_NAME "eth" +#define SILICOM_VID 0x1374 +#define SILICOM_BP_PID_MIN 0x24 +#define SILICOM_BP_PID_MAX 0x5f +#define INTEL_PEG4BPII_PID 0x10a0 +#define INTEL_PEG4BPFII_PID 0x10a1 + +#define PEGII_IF_SERIES(vid, pid) \ + ((vid==0x8086)&& \ + ((pid==INTEL_PEG4BPII_PID)|| \ + (pid==INTEL_PEG4BPFII_PID))) + +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)) +#define pci_get_class pci_find_class + +#define pci_get_device pci_find_device + +#endif + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10)) +#define EXPORT_SYMBOL_NOVERS EXPORT_SYMBOL +#endif + +#ifdef BP_VENDOR_SUPPORT +char *bp_desc_array[] = + { "e1000bp", "e1000bpe", "slcm5700", "bnx2xbp", "ixgbp", "ixgbpe", NULL }; +#endif + +#endif diff --git a/drivers/staging/silicom/bypasslib/bypass.c b/drivers/staging/silicom/bypasslib/bypass.c new file mode 100644 index 000000000000..527829d58133 --- /dev/null +++ b/drivers/staging/silicom/bypasslib/bypass.c @@ -0,0 +1,529 @@ +/******************************************************************************/ +/* */ +/* bypass library, Copyright (c) 2004-2007 Silicom, Ltd */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* */ +/* bypass.c */ +/* */ +/******************************************************************************/ + +#include <linux/version.h> +#if defined(CONFIG_SMP) && ! defined(__SMP__) +#define __SMP__ +#endif + +#include <linux/module.h> +#include <linux/kernel.h> +#include <asm/unistd.h> + +#include <linux/sched.h> +#include <linux/wait.h> + +#include <linux/netdevice.h> // struct device, and other headers +#include <linux/kernel_stat.h> +#include <linux/pci.h> +#include <linux/rtnetlink.h> +#include <linux/ethtool.h> + +#include <net/net_namespace.h> + +#include "bplibk.h" + +#define MOD_NAME "bypass" + +#define VERSION "\n"MOD_NAME" version 9.0.4\n" + +MODULE_AUTHOR("www.silicom.co.il"); + +MODULE_LICENSE("GPL"); + +int init_lib_module(void); +void cleanup_lib_module(void); + +static int do_cmd(struct net_device *dev, struct ifreq *ifr, int cmd, int *data) +{ + int ret = -1; + struct if_bypass *bypass_cb; + static int (*ioctl) (struct net_device *, struct ifreq *, int); + + bypass_cb = (struct if_bypass *)ifr; + bypass_cb->cmd = cmd; + bypass_cb->data = *data; + if ((dev->netdev_ops) && (ioctl = dev->netdev_ops->ndo_do_ioctl)) { + ret = ioctl(dev, ifr, SIOCGIFBYPASS); + *data = bypass_cb->data; + } + + return ret; +} + +static int doit(int cmd, int if_index, int *data) +{ + struct ifreq ifr; + int ret = -1; + struct net_device *dev; + struct net_device *n; + for_each_netdev_safe(&init_net, dev, n) { + + if (dev->ifindex == if_index) { + ret = do_cmd(dev, &ifr, cmd, data); + if (ret < 0) + ret = -1; + + } + } + + return ret; +} + +#define bp_symbol_get(fn_name) symbol_get(fn_name) +#define bp_symbol_put(fn_name) symbol_put(fn_name) + +#define SET_BPLIB_INT_FN(fn_name, arg_type, arg, ret) \ + ({ int (* fn_ex)(arg_type)=NULL; \ + fn_ex=bp_symbol_get(fn_name##_sd); \ + if(fn_ex) { \ + ret= fn_ex(arg); \ + bp_symbol_put(fn_name##_sd); \ + } else ret=-1; \ + }) + +#define SET_BPLIB_INT_FN2(fn_name, arg_type, arg, arg_type1, arg1, ret) \ + ({ int (* fn_ex)(arg_type,arg_type1)=NULL; \ + fn_ex=bp_symbol_get(fn_name##_sd); \ + if(fn_ex) { \ + ret= fn_ex(arg,arg1); \ + bp_symbol_put(fn_name##_sd); \ + } else ret=-1; \ + }) +#define SET_BPLIB_INT_FN3(fn_name, arg_type, arg, arg_type1, arg1,arg_type2, arg2, ret) \ + ({ int (* fn_ex)(arg_type,arg_type1, arg_type2)=NULL; \ + fn_ex=bp_symbol_get(fn_name##_sd); \ + if(fn_ex) { \ + ret= fn_ex(arg,arg1,arg2); \ + bp_symbol_put(fn_name##_sd); \ + } else ret=-1; \ + }) + +#define DO_BPLIB_GET_ARG_FN(fn_name,ioctl_val, if_index) \ + ({ int data, ret=0; \ + if(is_dev_sd(if_index)){ \ + SET_BPLIB_INT_FN(fn_name, int, if_index, ret); \ + return ret; \ + } \ + return doit(ioctl_val,if_index, &data); \ + }) + +#define DO_BPLIB_SET_ARG_FN(fn_name,ioctl_val,if_index,arg) \ + ({ int data, ret=0; \ + if(is_dev_sd(if_index)){ \ + SET_BPLIB_INT_FN2(fn_name, int, if_index, int, arg, ret); \ + return ret; \ + } \ + data=arg; \ + return doit(ioctl_val,if_index, &data); \ + }) + +static int is_dev_sd(int if_index) +{ + int ret = 0; + SET_BPLIB_INT_FN(is_bypass, int, if_index, ret); + return (ret >= 0 ? 1 : 0); +} + +int is_bypass_dev(int if_index) +{ + struct pci_dev *pdev = NULL; + struct net_device *dev = NULL; + struct ifreq ifr; + int ret = 0, data = 0; + + while ((pdev = pci_get_class(PCI_CLASS_NETWORK_ETHERNET << 8, pdev))) { + if ((dev = pci_get_drvdata(pdev)) != NULL) + if (((dev = pci_get_drvdata(pdev)) != NULL) && + (dev->ifindex == if_index)) { + if ((pdev->vendor == SILICOM_VID) && + (pdev->device >= SILICOM_BP_PID_MIN) && + (pdev->device <= SILICOM_BP_PID_MAX)) + goto send_cmd; +#if defined(BP_VENDOR_SUPPORT) && defined(ETHTOOL_GDRVINFO) + else { + struct ethtool_drvinfo info; + const struct ethtool_ops *ops = + dev->ethtool_ops; + int k = 0; + + if (ops->get_drvinfo) { + memset(&info, 0, sizeof(info)); + info.cmd = ETHTOOL_GDRVINFO; + ops->get_drvinfo(dev, &info); + for (; bp_desc_array[k]; k++) + if (! + (strcmp + (bp_desc_array[k], + info.driver))) + goto send_cmd; + + } + + } +#endif + return -1; + } + } + send_cmd: + ret = do_cmd(dev, &ifr, IS_BYPASS, &data); + return (ret < 0 ? -1 : ret); +} + +int is_bypass(int if_index) +{ + int ret = 0; + SET_BPLIB_INT_FN(is_bypass, int, if_index, ret); + + if (ret < 0) + return is_bypass_dev(if_index); + return ret; +} + +int get_bypass_slave(int if_index) +{ + DO_BPLIB_GET_ARG_FN(get_bypass_slave, GET_BYPASS_SLAVE, if_index); +} + +int get_bypass_caps(int if_index) +{ + DO_BPLIB_GET_ARG_FN(get_bypass_caps, GET_BYPASS_CAPS, if_index); +} + +int get_wd_set_caps(int if_index) +{ + DO_BPLIB_GET_ARG_FN(get_wd_set_caps, GET_WD_SET_CAPS, if_index); +} + +int set_bypass(int if_index, int bypass_mode) +{ + DO_BPLIB_SET_ARG_FN(set_bypass, SET_BYPASS, if_index, bypass_mode); +} + +int get_bypass(int if_index) +{ + DO_BPLIB_GET_ARG_FN(get_bypass, GET_BYPASS, if_index); +} + +int get_bypass_change(int if_index) +{ + DO_BPLIB_GET_ARG_FN(get_bypass_change, GET_BYPASS_CHANGE, if_index); +} + +int set_dis_bypass(int if_index, int dis_bypass) +{ + DO_BPLIB_SET_ARG_FN(set_dis_bypass, SET_DIS_BYPASS, if_index, + dis_bypass); +} + +int get_dis_bypass(int if_index) +{ + DO_BPLIB_GET_ARG_FN(get_dis_bypass, GET_DIS_BYPASS, if_index); +} + +int set_bypass_pwoff(int if_index, int bypass_mode) +{ + DO_BPLIB_SET_ARG_FN(set_bypass_pwoff, SET_BYPASS_PWOFF, if_index, + bypass_mode); +} + +int get_bypass_pwoff(int if_index) +{ + DO_BPLIB_GET_ARG_FN(get_bypass_pwoff, GET_BYPASS_PWOFF, if_index); +} + +int set_bypass_pwup(int if_index, int bypass_mode) +{ + DO_BPLIB_SET_ARG_FN(set_bypass_pwup, SET_BYPASS_PWUP, if_index, + bypass_mode); +} + +int get_bypass_pwup(int if_index) +{ + DO_BPLIB_GET_ARG_FN(get_bypass_pwup, GET_BYPASS_PWUP, if_index); +} + +int set_bypass_wd(int if_index, int ms_timeout, int *ms_timeout_set) +{ + int data = ms_timeout, ret = 0; + if (is_dev_sd(if_index)) + SET_BPLIB_INT_FN3(set_bypass_wd, int, if_index, int, ms_timeout, + int *, ms_timeout_set, ret); + else { + ret = doit(SET_BYPASS_WD, if_index, &data); + if (ret > 0) { + *ms_timeout_set = ret; + ret = 0; + } + } + return ret; +} + +int get_bypass_wd(int if_index, int *ms_timeout_set) +{ + int *data = ms_timeout_set, ret = 0; + if (is_dev_sd(if_index)) + SET_BPLIB_INT_FN2(get_bypass_wd, int, if_index, int *, + ms_timeout_set, ret); + else + ret = doit(GET_BYPASS_WD, if_index, data); + return ret; +} + +int get_wd_expire_time(int if_index, int *ms_time_left) +{ + int *data = ms_time_left, ret = 0; + if (is_dev_sd(if_index)) + SET_BPLIB_INT_FN2(get_wd_expire_time, int, if_index, int *, + ms_time_left, ret); + else { + ret = doit(GET_WD_EXPIRE_TIME, if_index, data); + if ((ret == 0) && (*data != 0)) + ret = 1; + } + return ret; +} + +int reset_bypass_wd_timer(int if_index) +{ + DO_BPLIB_GET_ARG_FN(reset_bypass_wd_timer, RESET_BYPASS_WD_TIMER, + if_index); +} + +int set_std_nic(int if_index, int bypass_mode) +{ + DO_BPLIB_SET_ARG_FN(set_std_nic, SET_STD_NIC, if_index, bypass_mode); +} + +int get_std_nic(int if_index) +{ + DO_BPLIB_GET_ARG_FN(get_std_nic, GET_STD_NIC, if_index); +} + +int set_tx(int if_index, int tx_state) +{ + DO_BPLIB_SET_ARG_FN(set_tx, SET_TX, if_index, tx_state); +} + +int get_tx(int if_index) +{ + DO_BPLIB_GET_ARG_FN(get_tx, GET_TX, if_index); +} + +int set_tap(int if_index, int tap_mode) +{ + DO_BPLIB_SET_ARG_FN(set_tap, SET_TAP, if_index, tap_mode); +} + +int get_tap(int if_index) +{ + DO_BPLIB_GET_ARG_FN(get_tap, GET_TAP, if_index); +} + +int get_tap_change(int if_index) +{ + DO_BPLIB_GET_ARG_FN(get_tap_change, GET_TAP_CHANGE, if_index); +} + +int set_dis_tap(int if_index, int dis_tap) +{ + DO_BPLIB_SET_ARG_FN(set_dis_tap, SET_DIS_TAP, if_index, dis_tap); +} + +int get_dis_tap(int if_index) +{ + DO_BPLIB_GET_ARG_FN(get_dis_tap, GET_DIS_TAP, if_index); +} + +int set_tap_pwup(int if_index, int tap_mode) +{ + DO_BPLIB_SET_ARG_FN(set_tap_pwup, SET_TAP_PWUP, if_index, tap_mode); +} + +int get_tap_pwup(int if_index) +{ + DO_BPLIB_GET_ARG_FN(get_tap_pwup, GET_TAP_PWUP, if_index); +} + +int set_bp_disc(int if_index, int disc_mode) +{ + DO_BPLIB_SET_ARG_FN(set_bp_disc, SET_DISC, if_index, disc_mode); +} + +int get_bp_disc(int if_index) +{ + DO_BPLIB_GET_ARG_FN(get_bp_disc, GET_DISC, if_index); +} + +int get_bp_disc_change(int if_index) +{ + DO_BPLIB_GET_ARG_FN(get_bp_disc_change, GET_DISC_CHANGE, if_index); +} + +int set_bp_dis_disc(int if_index, int dis_disc) +{ + DO_BPLIB_SET_ARG_FN(set_bp_dis_disc, SET_DIS_DISC, if_index, dis_disc); +} + +int get_bp_dis_disc(int if_index) +{ + DO_BPLIB_GET_ARG_FN(get_bp_dis_disc, GET_DIS_DISC, if_index); +} + +int set_bp_disc_pwup(int if_index, int disc_mode) +{ + DO_BPLIB_SET_ARG_FN(set_bp_disc_pwup, SET_DISC_PWUP, if_index, + disc_mode); +} + +int get_bp_disc_pwup(int if_index) +{ + DO_BPLIB_GET_ARG_FN(get_bp_disc_pwup, GET_DISC_PWUP, if_index); +} + +int set_wd_exp_mode(int if_index, int mode) +{ + DO_BPLIB_SET_ARG_FN(set_wd_exp_mode, SET_WD_EXP_MODE, if_index, mode); +} + +int get_wd_exp_mode(int if_index) +{ + DO_BPLIB_GET_ARG_FN(get_wd_exp_mode, GET_WD_EXP_MODE, if_index); +} + +int set_wd_autoreset(int if_index, int time) +{ + DO_BPLIB_SET_ARG_FN(set_wd_autoreset, SET_WD_AUTORESET, if_index, time); +} + +int get_wd_autoreset(int if_index) +{ + DO_BPLIB_GET_ARG_FN(get_wd_autoreset, GET_WD_AUTORESET, if_index); +} + +int set_tpl(int if_index, int tpl_mode) +{ + DO_BPLIB_SET_ARG_FN(set_tpl, SET_TPL, if_index, tpl_mode); +} + +int get_tpl(int if_index) +{ + DO_BPLIB_GET_ARG_FN(get_tpl, GET_TPL, if_index); +} + +int set_bp_hw_reset(int if_index, int mode) +{ + DO_BPLIB_SET_ARG_FN(set_tpl, SET_BP_HW_RESET, if_index, mode); +} + +int get_bp_hw_reset(int if_index) +{ + DO_BPLIB_GET_ARG_FN(get_tpl, GET_BP_HW_RESET, if_index); +} + +int get_bypass_info(int if_index, struct bp_info *bp_info) +{ + int ret = 0; + if (is_dev_sd(if_index)) { + SET_BPLIB_INT_FN2(get_bypass_info, int, if_index, + struct bp_info *, bp_info, ret); + } else { + static int (*ioctl) (struct net_device *, struct ifreq *, int); + struct net_device *dev; + + struct net_device *n; + for_each_netdev_safe(&init_net, dev, n) { + if (dev->ifindex == if_index) { + struct if_bypass_info *bypass_cb; + struct ifreq ifr; + + memset(&ifr, 0, sizeof(ifr)); + bypass_cb = (struct if_bypass_info *)𝔦 + bypass_cb->cmd = GET_BYPASS_INFO; + + if ((dev->netdev_ops) && + (ioctl = dev->netdev_ops->ndo_do_ioctl)) { + ret = ioctl(dev, &ifr, SIOCGIFBYPASS); + } + + else + ret = -1; + if (ret == 0) + memcpy(bp_info, &bypass_cb->bp_info, + sizeof(struct bp_info)); + ret = (ret < 0 ? -1 : 0); + break; + } + } + } + return ret; +} + +int init_lib_module() +{ + + printk(VERSION); + return 0; +} + +void cleanup_lib_module() +{ +} + +EXPORT_SYMBOL_NOVERS(is_bypass); +EXPORT_SYMBOL_NOVERS(get_bypass_slave); +EXPORT_SYMBOL_NOVERS(get_bypass_caps); +EXPORT_SYMBOL_NOVERS(get_wd_set_caps); +EXPORT_SYMBOL_NOVERS(set_bypass); +EXPORT_SYMBOL_NOVERS(get_bypass); +EXPORT_SYMBOL_NOVERS(get_bypass_change); +EXPORT_SYMBOL_NOVERS(set_dis_bypass); +EXPORT_SYMBOL_NOVERS(get_dis_bypass); +EXPORT_SYMBOL_NOVERS(set_bypass_pwoff); +EXPORT_SYMBOL_NOVERS(get_bypass_pwoff); +EXPORT_SYMBOL_NOVERS(set_bypass_pwup); +EXPORT_SYMBOL_NOVERS(get_bypass_pwup); +EXPORT_SYMBOL_NOVERS(set_bypass_wd); +EXPORT_SYMBOL_NOVERS(get_bypass_wd); +EXPORT_SYMBOL_NOVERS(get_wd_expire_time); +EXPORT_SYMBOL_NOVERS(reset_bypass_wd_timer); +EXPORT_SYMBOL_NOVERS(set_std_nic); +EXPORT_SYMBOL_NOVERS(get_std_nic); +EXPORT_SYMBOL_NOVERS(set_tx); +EXPORT_SYMBOL_NOVERS(get_tx); +EXPORT_SYMBOL_NOVERS(set_tap); +EXPORT_SYMBOL_NOVERS(get_tap); +EXPORT_SYMBOL_NOVERS(get_tap_change); +EXPORT_SYMBOL_NOVERS(set_dis_tap); +EXPORT_SYMBOL_NOVERS(get_dis_tap); +EXPORT_SYMBOL_NOVERS(set_tap_pwup); +EXPORT_SYMBOL_NOVERS(get_tap_pwup); +EXPORT_SYMBOL_NOVERS(set_bp_disc); +EXPORT_SYMBOL_NOVERS(get_bp_disc); +EXPORT_SYMBOL_NOVERS(get_bp_disc_change); +EXPORT_SYMBOL_NOVERS(set_bp_dis_disc); +EXPORT_SYMBOL_NOVERS(get_bp_dis_disc); +EXPORT_SYMBOL_NOVERS(set_bp_disc_pwup); +EXPORT_SYMBOL_NOVERS(get_bp_disc_pwup); +EXPORT_SYMBOL_NOVERS(set_wd_exp_mode); +EXPORT_SYMBOL_NOVERS(get_wd_exp_mode); +EXPORT_SYMBOL_NOVERS(set_wd_autoreset); +EXPORT_SYMBOL_NOVERS(get_wd_autoreset); +EXPORT_SYMBOL_NOVERS(set_tpl); +EXPORT_SYMBOL_NOVERS(get_tpl); +EXPORT_SYMBOL_NOVERS(set_bp_hw_reset); +EXPORT_SYMBOL_NOVERS(get_bp_hw_reset); +EXPORT_SYMBOL_NOVERS(get_bypass_info); + +module_init(init_lib_module); +module_exit(cleanup_lib_module); diff --git a/drivers/staging/silicom/bypasslib/libbp_sd.h b/drivers/staging/silicom/bypasslib/libbp_sd.h new file mode 100644 index 000000000000..3b4f8364ed18 --- /dev/null +++ b/drivers/staging/silicom/bypasslib/libbp_sd.h @@ -0,0 +1,509 @@ +/******************************************************************************/ +/* */ +/* bypass library, Copyright (c) 2004 Silicom, Ltd */ +/* Corporation. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* Ver 1.0.0 */ +/* */ +/* libbypass.h */ +/* */ +/******************************************************************************/ + +/** + * is_bypass - check if device is a Bypass controlling device + * @if_index: network device index + * + * Output: + * 1 - if device is bypass controlling device, + * 0 - if device is bypass slave device + * -1 - device not support Bypass + **/ +int is_bypass_sd(int if_index); + +/** + * get_bypass_slave - get second port participate in the Bypass pair + * @if_index: network device index + * + * Output: + * network device index of the slave device + * -1 - on failure (device not support Bypass or it's a slave device) + **/ +int get_bypass_slave_sd(int if_index); + +/** + * get_bypass_caps - get second port participate in the Bypass pair + * @if_index: network device index + * + * Output: + * flags word on success;flag word is a 32-bit mask word with each bit defines different + * capability as described bellow. + * Value of 1 for supporting this feature. 0 for not supporting this feature. + * -1 - on failure (if the device is not capable of the operation or not a Bypass device) + * Bit feature description + * + * 0 BP_CAP The interface is Bypass capable in general + * + * 1 BP_STATUS_CAP The interface can report of the current Bypass mode + * + * 2 BP_STATUS_CHANGE_CAP The interface can report on a change to bypass mode from + * the last time the mode was defined + * + * 3 SW_CTL_CAP The interface is Software controlled capable for bypass/non bypass modes. + * + * 4 BP_DIS_CAP The interface is capable of disabling the Bypass mode at all times. + * This mode will retain its mode even during power loss and also after + * power recovery. This will overcome on any bypass operation due to + * watchdog timeout or set bypass command. + * + * 5 BP_DIS_STATUS_CAP The interface can report of the current DIS_BP_CAP + * + * 6 STD_NIC_CAP The interface is capable to be configured to operate as standard, non Bypass, + * NIC interface (have direct connection to interfaces at all power modes) + * + * 7 BP_PWOFF_NO_CAP The interface can be in Bypass mode at power off state + * + * 8 BP_PWOFF_OFF_CAP The interface can disconnect the Bypass mode at power off state without + * effecting all the other states of operation + * + * 9 BP_PWOFF_CTL_CAP The behavior of the Bypass mode at Power-off state can be controlled by + * software without effecting any other state + * + *10 BP_PWUP_ON_CAP The interface can be in Bypass mode when power is turned on + * (until the system take control of the bypass functionality) + * + *11 BP_PWUP_OFF_CAP The interface can disconnect from Bypass mode when power is turned on + * (until the system take control of the bypass functionality) + * + *12 BP_PWUP_CTL_CAP The behavior of the Bypass mode at Power-up can be controlled by software + * + *13 WD_CTL_CAP The interface has watchdog capabilities to turn to Bypass mode when not reset + * for defined period of time. + * + *14 WD_STATUS_CAP The interface can report on the watchdog status (Active/inactive) + * + *15 WD_TIMEOUT_CAP The interface can report the time left till watchdog triggers to Bypass mode. + * + *16-31 RESERVED + * + * **/ +int get_bypass_caps_sd(int if_index); + +/** + * get_wd_set_caps - Obtain watchdog timer setting capabilities + * @if_index: network device index + * + * Output: + * + * Set of numbers defining the various parameters of the watchdog capable + * to be set to as described bellow. + * -1 - on failure (device not support Bypass or it's a slave device) + * + * Bit feature description + * + * 0-3 WD_MIN_TIME The interface WD minimal time period in 100mS units + * + * 4 WD_STEP_TIME The steps of the WD timer in + * 0 - for linear steps (WD_MIN_TIME * X) + * 1 - for multiply by 2 from previous step (WD_MIN_TIME * 2^X) + * + * 5-8 WD_STEP_COUNT Number of steps the WD timer supports in 2^X + * (X bit available for defining the value) + * + * + * + **/ +int get_wd_set_caps_sd(int if_index); + +/** + * set_bypass - set Bypass state + * @if_index: network device index of the controlling device + * @bypass_mode: bypass mode (1=on, 0=off) + * Output: + * 0 - on success + * -1 - on failure (device not support Bypass or it's a slave device) + **/ +int set_bypass_sd(int if_index, int bypass_mode); + +/** + * get_bypass - Get Bypass mode state + * @if_index: network device index of the controlling device + * Output: + * 0/1 - (off/on) on success + * -1 - on failure (device not support Bypass or it's a slave device) + **/ +int get_bypass_sd(int if_index); + +/** + * get_bypass_change - Get change of Bypass mode state from last status check + * @if_index: network device index of the controlling device + * Output: + * 0/1 - (off/on) on success + * -1 - on failure (device not support Bypass or it's a slave device) + **/ +int get_bypass_change_sd(int if_index); + +/** + * set_dis_bypass - Set Disable Bypass mode + * @if_index: network device index of the controlling device + * @dis_bypass: disable bypass(1=dis, 0=en) + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device) + **/ +int set_dis_bypass_sd(int if_index, int dis_bypass); + +/** + * get_dis_bypass - Get Disable Bypass mode state + * @if_index: network device index of the controlling device + * Output: + * 0/1 - on success (normal Bypass mode/ Disable bypass) + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device) + **/ +int get_dis_bypass_sd(int if_index); + +/** + * set_bypass_pwoff - Set Bypass mode at power-off state + * @if_index: network device index of the controlling device + * @bypass_mode: bypass mode setting at power off state (1=BP en, 0=BP Dis) + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device) + **/ +int set_bypass_pwoff_sd(int if_index, int bypass_mode); + +/** + * get_bypass_pwoff - Get Bypass mode state at power-off state + * @if_index: network device index of the controlling device + * Output: + * 0/1 - on success (Disable bypass at power off state / normal Bypass mode) + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device) + **/ +int get_bypass_pwoff_sd(int if_index); + +/** + * set_bypass_pwup - Set Bypass mode at power-up state + * @if_index: network device index of the controlling device + * @bypass_mode: bypass mode setting at power up state (1=BP en, 0=BP Dis) + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device) + **/ +int set_bypass_pwup_sd(int if_index, int bypass_mode); + +/** + * get_bypass_pwup - Get Bypass mode state at power-up state + * @if_index: network device index of the controlling device + * Output: + * 0/1 - on success (Disable bypass at power up state / normal Bypass mode) + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device) + **/ +int get_bypass_pwup_sd(int if_index); + +/** + * set_bypass_wd - Set watchdog state + * @if_index: network device index of the controlling device + * @ms_timeout: requested timeout (in ms units), 0 for disabling the watchdog timer + * @ms_timeout_set(output): requested timeout (in ms units), + * that the adapter supports and will be used by the watchdog + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device) + **/ +int set_bypass_wd_sd(int if_index, int ms_timeout, int *ms_timeout_set); + +/** + * get_bypass_wd - Get watchdog state + * @if_index: network device index of the controlling device + * @ms_timeout (output): WDT timeout (in ms units), + * -1 for unknown wdt status + * 0 if WDT is disabled + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device) + **/ +int get_bypass_wd_sd(int if_index, int *ms_timeout_set); + +/** + * get_wd_expire_time - Get watchdog expire + * @if_index: network device index of the controlling device + * @ms_time_left (output): time left till watchdog time expire, + * -1 if WDT has expired + * 0 if WDT is disabled + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device or unknown wdt status) + **/ +int get_wd_expire_time_sd(int if_index, int *ms_time_left); + +/** + * reset_bypass_wd_timer - Reset watchdog timer + * @if_index: network device index of the controlling device + * + * Output: + * 1 - on success + * 0 - watchdog is not configured + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device or unknown wdt status) + **/ +int reset_bypass_wd_timer_sd(int if_index); + +/** + * set_std_nic - Standard NIC mode of operation + * @if_index: network device index of the controlling device + * @nic_mode: 0/1 (Default Bypass mode / Standard NIC mode) + * + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device) + **/ +int set_std_nic_sd(int if_index, int nic_mode); + +/** + * get_std_nic - Get Standard NIC mode setting + * @if_index: network device index of the controlling device + * + * Output: + * 0/1 (Default Bypass mode / Standard NIC mode) on success + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device) + **/ +int get_std_nic_sd(int if_index); + +/** + * set_tx - set transmitter enable/disable + * @if_index: network device index of the controlling device + * @tx_state: 0/1 (Transmit Disable / Transmit Enable) + * + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ) + **/ +int set_tx_sd(int if_index, int tx_state); + +/** + * get_std_nic - get transmitter state (disable / enable) + * @if_index: network device index of the controlling device + * + * Output: + * 0/1 (ransmit Disable / Transmit Enable) on success + * -1 - on failure (device is not capable of the operation ordevice not support Bypass) + **/ +int get_tx_sd(int if_index); + +/** + * set_tap - set TAP state + * @if_index: network device index of the controlling device + * @tap_mode: 1 tap mode , 0 normal nic mode + * Output: + * 0 - on success + * -1 - on failure (device not support TAP or it's a slave device) + **/ +int set_tap_sd(int if_index, int tap_mode); + +/** + * get_tap - Get TAP mode state + * @if_index: network device index of the controlling device + * Output: + * 0/1 - (off/on) on success + * -1 - on failure (device not support TAP or it's a slave device) + **/ +int get_tap_sd(int if_index); + +/** + * get_tap_change - Get change of TAP mode state from last status check + * @if_index: network device index of the controlling device + * Output: + * 0/1 - (off/on) on success + * -1 - on failure (device not support TAP or it's a slave device) + **/ +int get_tap_change_sd(int if_index); + +/** + * set_dis_tap - Set Disable TAP mode + * @if_index: network device index of the controlling device + * @dis_tap: disable tap(1=dis, 0=en) + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ordevice not support TAP + * or it's a slave device) + **/ +int set_dis_tap_sd(int if_index, int dis_tap); + +/** + * get_dis_tap - Get Disable TAP mode state + * @if_index: network device index of the controlling device + * Output: + * 0/1 - on success (normal TAP mode/ Disable TAP) + * -1 - on failure (device is not capable of the operation ordevice not support TAP + * or it's a slave device) + **/ +int get_dis_tap_sd(int if_index); + +/** + * set_tap_pwup - Set TAP mode at power-up state + * @if_index: network device index of the controlling device + * @bypass_mode: tap mode setting at power up state (1=TAP en, 0=TAP Dis) + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ordevice not support TAP + * or it's a slave device) + **/ +int set_tap_pwup_sd(int if_index, int tap_mode); + +/** + * get_tap_pwup - Get TAP mode state at power-up state + * @if_index: network device index of the controlling device + * Output: + * 0/1 - on success (Disable TAP at power up state / normal TAP mode) + * -1 - on failure (device is not capable of the operation ordevice not support TAP + * or it's a slave device) + **/ +int get_tap_pwup_sd(int if_index); + +/** + * set_bp_disc - set Disconnect state + * @if_index: network device index of the controlling device + * @tap_mode: 1 disc mode , 0 non-disc mode + * Output: + * 0 - on success + * -1 - on failure (device not support Disconnect or it's a slave device) + **/ +int set_bp_disc_sd(int if_index, int disc_mode); + +/** + * get_bp_disc - Get Disconnect mode state + * @if_index: network device index of the controlling device + * Output: + * 0/1 - (off/on) on success + * -1 - on failure (device not support Disconnect or it's a slave device) + **/ +int get_bp_disc_sd(int if_index); + +/** + * get_bp_disc_change - Get change of Disconnect mode state from last status check + * @if_index: network device index of the controlling device + * Output: + * 0/1 - (off/on) on success + * -1 - on failure (device not support Disconnect or it's a slave device) + **/ +int get_bp_disc_change_sd(int if_index); + +/** + * set_bp_dis_disc - Set Disable Disconnect mode + * @if_index: network device index of the controlling device + * @dis_tap: disable tap(1=dis, 0=en) + * Output: + * 0 - on success + * -1 - on failure (device is not capable ofthe operation ordevice not support Disconnect + * or it's a slave device) + **/ +int set_bp_dis_disc_sd(int if_index, int dis_disc); + +/** + * get_dis_tap - Get Disable Disconnect mode state + * @if_index: network device index of the controlling device + * Output: + * 0/1 - on success (normal Disconnect mode/ Disable Disconnect) + * -1 - on failure (device is not capable of the operation ordevice not support Disconnect + * or it's a slave device) + **/ +int get_bp_dis_disc_sd(int if_index); + +/** + * set_bp_disc_pwup - Set Disconnect mode at power-up state + * @if_index: network device index of the controlling device + * @disc_mode: tap mode setting at power up state (1=Disc en, 0=Disc Dis) + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ordevice not support Disconnect + * or it's a slave device) + **/ +int set_bp_disc_pwup_sd(int if_index, int disc_mode); + +/** + * get_bp_disc_pwup - Get Disconnect mode state at power-up state + * @if_index: network device index of the controlling device + * Output: + * 0/1 - on success (Disable Disconnect at power up state / normal Disconnect mode) + * -1 - on failure (device is not capable of the operation ordevice not support TAP + * or it's a slave device) + **/ +int get_bp_disc_pwup_sd(int if_index); + +/** + * set_wd_exp_mode - Set adapter state when WDT expired. + * @if_index: network device index of the controlling device + * @bypass_mode: adapter mode (1=tap mode, 0=bypass mode) + * Output: + * 0 - on success + * -1 - on failure (device not support Bypass or it's a slave device) + **/ +int set_wd_exp_mode_sd(int if_index, int bypass_mode); + +/** + * get_wd_exp_mode - Get adapter state when WDT expired. + * @if_index: network device index of the controlling device + * Output: + * 0/1 - (bypass/tap) on success + * -1 - on failure (device not support Bypass or it's a slave device) + **/ +int get_wd_exp_mode_sd(int if_index); + +/** + * set_wd_autoreset - reset WDT periodically. + * @if_index: network device index of the controlling device + * @bypass_mode: adapter mode (1=tap mode, 0=bypass mode) + * Output: + * 1 - on success + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device or unknown wdt status) + **/ +int set_wd_autoreset_sd(int if_index, int time); + +/** + * set_wd_autoreset - reset WDT periodically. + * @if_index: network device index of the controlling device + * @bypass_mode: adapter mode (1=tap mode, 0=bypass mode) + * Output: + * 1 - on success + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device or unknown wdt status) + **/ +int get_wd_autoreset_sd(int if_index); + +/** + * set_tpl - set TPL state + * @if_index: network device index of the controlling device + * @tpl_mode: 1 tpl mode , 0 normal nic mode + * Output: + * 0 - on success + * -1 - on failure (device not support TPL) + **/ +int set_tpl_sd(int if_index, int tpl_mode); + +/** + * get_tpl - Get TPL mode state + * @if_index: network device index of the controlling device + * Output: + * 0/1 - (off/on) on success + * -1 - on failure (device not support TPL or it's a slave device) + **/ +int get_tpl_sd(int if_index); + +int get_bypass_info_sd(int if_index, struct bp_info *bp_info); +int bp_if_scan_sd(void); +/*int get_dev_num_sd(void);*/ diff --git a/drivers/staging/silicom/libbp_sd.h b/drivers/staging/silicom/libbp_sd.h new file mode 100644 index 000000000000..065277f81c78 --- /dev/null +++ b/drivers/staging/silicom/libbp_sd.h @@ -0,0 +1,550 @@ +/******************************************************************************/ +/* */ +/* bypass library, Copyright (c) 2004 Silicom, Ltd */ +/* Corporation. */ +/* */ +/* This program is free software; you can redistribute it and/or modify */ +/* it under the terms of the GNU General Public License as published by */ +/* the Free Software Foundation, located in the file LICENSE. */ +/* */ +/* Ver 1.0.0 */ +/* */ +/* libbypass.h */ +/* */ +/******************************************************************************/ + +#define BP_CAP 0x01 /* BIT_0 */ +#define BP_STATUS_CAP 0x02 +#define BP_STATUS_CHANGE_CAP 0x04 +#define SW_CTL_CAP 0x08 +#define BP_DIS_CAP 0x10 +#define BP_DIS_STATUS_CAP 0x20 +#define STD_NIC_CAP 0x40 +#define BP_PWOFF_ON_CAP 0x80 +#define BP_PWOFF_OFF_CAP 0x0100 +#define BP_PWOFF_CTL_CAP 0x0200 +#define BP_PWUP_ON_CAP 0x0400 +#define BP_PWUP_OFF_CAP 0x0800 +#define BP_PWUP_CTL_CAP 0x1000 +#define WD_CTL_CAP 0x2000 +#define WD_STATUS_CAP 0x4000 +#define WD_TIMEOUT_CAP 0x8000 +#define TX_CTL_CAP 0x10000 +#define TX_STATUS_CAP 0x20000 +#define TAP_CAP 0x40000 +#define TAP_STATUS_CAP 0x80000 +#define TAP_STATUS_CHANGE_CAP 0x100000 +#define TAP_DIS_CAP 0x200000 +#define TAP_DIS_STATUS_CAP 0x400000 +#define TAP_PWUP_ON_CAP 0x800000 +#define TAP_PWUP_OFF_CAP 0x1000000 +#define TAP_PWUP_CTL_CAP 0x2000000 +#define NIC_CAP_NEG 0x4000000 /* BIT 26 */ + +#define WD_MIN_TIME_GET(desc) (desc & 0xf) +#define WDT_STEP_TIME 0x10 + +struct bp_info { + char prod_name[14]; + unsigned char fw_ver; +}; + +/** + * is_bypass - check if device is a Bypass controlling device + * @if_index: network device index + * + * Output: + * 1 - if device is bypass controlling device, + * 0 - if device is bypass slave device + * -1 - device not support Bypass + **/ +int is_bypass_sd(int if_index); + +/** + * get_bypass_slave - get second port participate in the Bypass pair + * @if_index: network device index + * + * Output: + * network device index of the slave device + * -1 - on failure (device not support Bypass or it's a slave device) + **/ +int get_bypass_slave_sd(int if_index); + +/** + * get_bypass_caps - get second port participate in the Bypass pair + * @if_index: network device index + * + * Output: + * flags word on success;flag word is a 32-bit mask word with each bit defines different + * capability as described bellow. + * Value of 1 for supporting this feature. 0 for not supporting this feature. + * -1 - on failure (if the device is not capable of the operation or not a Bypass device) + * Bit feature description + * + * 0 BP_CAP The interface is Bypass capable in general + * + * 1 BP_STATUS_CAP The interface can report of the current Bypass mode + * + * 2 BP_STATUS_CHANGE_CAP The interface can report on a change to bypass mode from + * the last time the mode was defined + * + * 3 SW_CTL_CAP The interface is Software controlled capable for bypass/non bypass modes. + * + * 4 BP_DIS_CAP The interface is capable of disabling the Bypass mode at all times. + * This mode will retain its mode even during power loss and also after + * power recovery. This will overcome on any bypass operation due to + * watchdog timeout or set bypass command. + * + * 5 BP_DIS_STATUS_CAP The interface can report of the current DIS_BP_CAP + * + * 6 STD_NIC_CAP The interface is capable to be configured to operate as standard, non Bypass, + * NIC interface (have direct connection to interfaces at all power modes) + * + * 7 BP_PWOFF_NO_CAP The interface can be in Bypass mode at power off state + * + * 8 BP_PWOFF_OFF_CAP The interface can disconnect the Bypass mode at power off state without + * effecting all the other states of operation + * + * 9 BP_PWOFF_CTL_CAP The behavior of the Bypass mode at Power-off state can be controlled by + * software without effecting any other state + * + *10 BP_PWUP_ON_CAP The interface can be in Bypass mode when power is turned on + * (until the system take control of the bypass functionality) + * + *11 BP_PWUP_OFF_CAP The interface can disconnect from Bypass mode when power is turned on + * (until the system take control of the bypass functionality) + * + *12 BP_PWUP_CTL_CAP The behavior of the Bypass mode at Power-up can be controlled by software + * + *13 WD_CTL_CAP The interface has watchdog capabilities to turn to Bypass mode when not reset + * for defined period of time. + * + *14 WD_STATUS_CAP The interface can report on the watchdog status (Active/inactive) + * + *15 WD_TIMEOUT_CAP The interface can report the time left till watchdog triggers to Bypass mode. + * + *16-31 RESERVED + * + * **/ +int get_bypass_caps_sd(int if_index); + +/** + * get_wd_set_caps - Obtain watchdog timer setting capabilities + * @if_index: network device index + * + * Output: + * + * Set of numbers defining the various parameters of the watchdog capable + * to be set to as described bellow. + * -1 - on failure (device not support Bypass or it's a slave device) + * + * Bit feature description + * + * 0-3 WD_MIN_TIME The interface WD minimal time period in 100mS units + * + * 4 WD_STEP_TIME The steps of the WD timer in + * 0 - for linear steps (WD_MIN_TIME * X) + * 1 - for multiply by 2 from previous step (WD_MIN_TIME * 2^X) + * + * 5-8 WD_STEP_COUNT Number of steps the WD timer supports in 2^X + * (X bit available for defining the value) + * + * + * + **/ +int get_wd_set_caps_sd(int if_index); + +/** + * set_bypass - set Bypass state + * @if_index: network device index of the controlling device + * @bypass_mode: bypass mode (1=on, 0=off) + * Output: + * 0 - on success + * -1 - on failure (device not support Bypass or it's a slave device) + **/ +int set_bypass_sd(int if_index, int bypass_mode); + +/** + * get_bypass - Get Bypass mode state + * @if_index: network device index of the controlling device + * Output: + * 0/1 - (off/on) on success + * -1 - on failure (device not support Bypass or it's a slave device) + **/ +int get_bypass_sd(int if_index); + +/** + * get_bypass_change - Get change of Bypass mode state from last status check + * @if_index: network device index of the controlling device + * Output: + * 0/1 - (off/on) on success + * -1 - on failure (device not support Bypass or it's a slave device) + **/ +int get_bypass_change_sd(int if_index); + +/** + * set_dis_bypass - Set Disable Bypass mode + * @if_index: network device index of the controlling device + * @dis_bypass: disable bypass(1=dis, 0=en) + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device) + **/ +int set_dis_bypass_sd(int if_index, int dis_bypass); + +/** + * get_dis_bypass - Get Disable Bypass mode state + * @if_index: network device index of the controlling device + * Output: + * 0/1 - on success (normal Bypass mode/ Disable bypass) + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device) + **/ +int get_dis_bypass_sd(int if_index); + +/** + * set_bypass_pwoff - Set Bypass mode at power-off state + * @if_index: network device index of the controlling device + * @bypass_mode: bypass mode setting at power off state (1=BP en, 0=BP Dis) + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device) + **/ +int set_bypass_pwoff_sd(int if_index, int bypass_mode); + +/** + * get_bypass_pwoff - Get Bypass mode state at power-off state + * @if_index: network device index of the controlling device + * Output: + * 0/1 - on success (Disable bypass at power off state / normal Bypass mode) + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device) + **/ +int get_bypass_pwoff_sd(int if_index); + +/** + * set_bypass_pwup - Set Bypass mode at power-up state + * @if_index: network device index of the controlling device + * @bypass_mode: bypass mode setting at power up state (1=BP en, 0=BP Dis) + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device) + **/ +int set_bypass_pwup_sd(int if_index, int bypass_mode); + +/** + * get_bypass_pwup - Get Bypass mode state at power-up state + * @if_index: network device index of the controlling device + * Output: + * 0/1 - on success (Disable bypass at power up state / normal Bypass mode) + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device) + **/ +int get_bypass_pwup_sd(int if_index); + +/** + * set_bypass_wd - Set watchdog state + * @if_index: network device index of the controlling device + * @ms_timeout: requested timeout (in ms units), 0 for disabling the watchdog timer + * @ms_timeout_set(output): requested timeout (in ms units), + * that the adapter supports and will be used by the watchdog + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device) + **/ +int set_bypass_wd_sd(int if_index, int ms_timeout, int *ms_timeout_set); + +/** + * get_bypass_wd - Get watchdog state + * @if_index: network device index of the controlling device + * @ms_timeout (output): WDT timeout (in ms units), + * -1 for unknown wdt status + * 0 if WDT is disabled + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device) + **/ +int get_bypass_wd_sd(int if_index, int *ms_timeout_set); + +/** + * get_wd_expire_time - Get watchdog expire + * @if_index: network device index of the controlling device + * @ms_time_left (output): time left till watchdog time expire, + * -1 if WDT has expired + * 0 if WDT is disabled + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device or unknown wdt status) + **/ +int get_wd_expire_time_sd(int if_index, int *ms_time_left); + +/** + * reset_bypass_wd_timer - Reset watchdog timer + * @if_index: network device index of the controlling device + * + * Output: + * 1 - on success + * 0 - watchdog is not configured + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device or unknown wdt status) + **/ +int reset_bypass_wd_timer_sd(int if_index); + +/** + * set_std_nic - Standard NIC mode of operation + * @if_index: network device index of the controlling device + * @nic_mode: 0/1 (Default Bypass mode / Standard NIC mode) + * + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device) + **/ +int set_std_nic_sd(int if_index, int nic_mode); + +/** + * get_std_nic - Get Standard NIC mode setting + * @if_index: network device index of the controlling device + * + * Output: + * 0/1 (Default Bypass mode / Standard NIC mode) on success + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device) + **/ +int get_std_nic_sd(int if_index); + +/** + * set_tx - set transmitter enable/disable + * @if_index: network device index of the controlling device + * @tx_state: 0/1 (Transmit Disable / Transmit Enable) + * + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ) + **/ +int set_tx_sd(int if_index, int tx_state); + +/** + * get_tx - get transmitter state (disable / enable) + * @if_index: network device index of the controlling device + * + * Output: + * 0/1 (ransmit Disable / Transmit Enable) on success + * -1 - on failure (device is not capable of the operation ordevice not support Bypass) + **/ +int get_tx_sd(int if_index); + +/** + * set_tpl - set TPL enable/disable + * @if_index: network device index of the controlling device + * @tx_state: 0/1 (TPL Disable / TPL Enable) + * + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ) + **/ +int set_tpl_sd(int if_index, int tpl_state); + +/** + * get_tpl - get TPL state (disable / enable) + * @if_index: network device index of the controlling device + * + * Output: + * 0/1 (TPL Disable / TPL Enable) on success + * -1 - on failure (device is not capable of the operation) + **/ +int get_tpl_sd(int if_index); + +int get_bp_hw_reset_sd(int if_index); + +int set_bp_hw_reset_sd(int if_index, int status); + +/** + * set_tap - set TAP state + * @if_index: network device index of the controlling device + * @tap_mode: 1 tap mode , 0 normal nic mode + * Output: + * 0 - on success + * -1 - on failure (device not support TAP or it's a slave device) + **/ +int set_tap_sd(int if_index, int tap_mode); + +/** + * get_tap - Get TAP mode state + * @if_index: network device index of the controlling device + * Output: + * 0/1 - (off/on) on success + * -1 - on failure (device not support TAP or it's a slave device) + **/ +int get_tap_sd(int if_index); + +/** + * get_tap_change - Get change of TAP mode state from last status check + * @if_index: network device index of the controlling device + * Output: + * 0/1 - (off/on) on success + * -1 - on failure (device not support TAP or it's a slave device) + **/ +int get_tap_change_sd(int if_index); + +/** + * set_dis_tap - Set Disable TAP mode + * @if_index: network device index of the controlling device + * @dis_tap: disable tap(1=dis, 0=en) + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ordevice not support TAP + * or it's a slave device) + **/ +int set_dis_tap_sd(int if_index, int dis_tap); + +/** + * get_dis_tap - Get Disable TAP mode state + * @if_index: network device index of the controlling device + * Output: + * 0/1 - on success (normal TAP mode/ Disable TAP) + * -1 - on failure (device is not capable of the operation ordevice not support TAP + * or it's a slave device) + **/ +int get_dis_tap_sd(int if_index); + +/** + * set_tap_pwup - Set TAP mode at power-up state + * @if_index: network device index of the controlling device + * @bypass_mode: tap mode setting at power up state (1=TAP en, 0=TAP Dis) + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ordevice not support TAP + * or it's a slave device) + **/ +int set_tap_pwup_sd(int if_index, int tap_mode); + +/** + * get_tap_pwup - Get TAP mode state at power-up state + * @if_index: network device index of the controlling device + * Output: + * 0/1 - on success (Disable TAP at power up state / normal TAP mode) + * -1 - on failure (device is not capable of the operation ordevice not support TAP + * or it's a slave device) + **/ +int get_tap_pwup_sd(int if_index); + +/** + * set_wd_exp_mode - Set adapter state when WDT expired. + * @if_index: network device index of the controlling device + * @bypass_mode: adapter mode (1=tap mode, 0=bypass mode) + * Output: + * 0 - on success + * -1 - on failure (device not support Bypass or it's a slave device) + **/ +int set_wd_exp_mode_sd(int if_index, int bypass_mode); + +/** + * get_wd_exp_mode - Get adapter state when WDT expired. + * @if_index: network device index of the controlling device + * Output: + * 0/1 - (bypass/tap) on success + * -1 - on failure (device not support Bypass or it's a slave device) + **/ +int get_wd_exp_mode_sd(int if_index); + +/** + * set_wd_autoreset - reset WDT periodically. + * @if_index: network device index of the controlling device + * @bypass_mode: adapter mode (1=tap mode, 0=bypass mode) + * Output: + * 1 - on success + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device or unknown wdt status) + **/ +int set_wd_autoreset_sd(int if_index, int time); + +/** + * set_wd_autoreset - reset WDT periodically. + * @if_index: network device index of the controlling device + * @bypass_mode: adapter mode (1=tap mode, 0=bypass mode) + * Output: + * 1 - on success + * -1 - on failure (device is not capable of the operation ordevice not support Bypass + * or it's a slave device or unknown wdt status) + **/ +int get_wd_autoreset_sd(int if_index); +/** + * set_disc - set DISC state + * @if_index: network device index of the controlling device + * @tap_mode: 1 DISC mode , 0 normal nic mode + * Output: + * 0 - on success + * -1 - on failure (device not support disconnect or it's a slave device) + **/ +int set_bp_disc_sd(int if_index, int disc_mode); + +/** + * get_disc - Get disc mode state + * @if_index: network device index of the controlling device + * Output: + * 0/1 - (off/on) on success + * -1 - on failure (device not support disconnect or it's a slave device) + **/ +int get_bp_disc_sd(int if_index); + +/** + * get_disc_change - Get change of DISC mode state from last status check + * @if_index: network device index of the controlling device + * Output: + * 0/1 - (off/on) on success + * -1 - on failure (device not support disconnect or it's a slave device) + **/ +int get_bp_disc_change_sd(int if_index); + +/** + * set_dis_disc - Set Disable DISC mode + * @if_index: network device index of the controlling device + * @dis_disc: disable disconnect(1=dis, 0=en) + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ordevice not support DISC + * or it's a slave device) + **/ +int set_bp_dis_disc_sd(int if_index, int dis_disc); + +/** + * get_dis_disc - Get Disable DISC mode state + * @if_index: network device index of the controlling device + * Output: + * 0/1 - on success (normal DISC mode/ Disable DISC) + * -1 - on failure (device is not capable of the operation ordevice not support TAP + * or it's a slave device) + **/ +int get_bp_dis_disc_sd(int if_index); + +/** + * set_disc_pwup - Set DISC mode at power-up state + * @if_index: network device index of the controlling device + * @disc_mode: DISC mode setting at power up state (1= en, 0= Dis) + * Output: + * 0 - on success + * -1 - on failure (device is not capable of the operation ordevice not support DISC + * or it's a slave device) + **/ +int set_bp_disc_pwup_sd(int if_index, int disc_mode); + +/** + * get_disc_pwup - Get DISC mode state at power-up state + * @if_index: network device index of the controlling device + * Output: + * 0/1 - on success (Disable DISC at power up state / normal DISC mode) + * -1 - on failure (device is not capable of the operation ordevice not support DISC + * or it's a slave device) + **/ +int get_bp_disc_pwup_sd(int if_index); + +int get_bypass_info_sd(int if_index, struct bp_info *bp_info); +int bp_if_scan_sd(void); +/*int get_dev_num_sd(void);*/ diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c index 56829fc032ff..cd920dad85cd 100644 --- a/drivers/staging/slicoss/slicoss.c +++ b/drivers/staging/slicoss/slicoss.c @@ -514,8 +514,7 @@ static int slic_card_download_gbrcv(struct adapter *adapter) file = "slicoss/gbrcvucode.sys"; break; default: - ASSERT(0); - break; + return -ENOENT; } ret = request_firmware(&fw, file, &adapter->pcidev->dev); @@ -529,15 +528,16 @@ static int slic_card_download_gbrcv(struct adapter *adapter) index += 4; switch (adapter->devid) { case SLIC_2GB_DEVICE_ID: - if (rcvucodelen != OasisRcvUCodeLen) + if (rcvucodelen != OasisRcvUCodeLen) { + release_firmware(fw); return -EINVAL; + } break; case SLIC_1GB_DEVICE_ID: - if (rcvucodelen != GBRcvUCodeLen) + if (rcvucodelen != GBRcvUCodeLen) { + release_firmware(fw); return -EINVAL; - break; - default: - ASSERT(0); + } break; } /* start download */ @@ -2552,7 +2552,6 @@ static void slic_mcast_set_list(struct net_device *dev) if (status == 0) slic_mcast_set_mask(adapter); } - return; } #define XMIT_FAIL_LINK_STATE 1 @@ -3132,7 +3131,6 @@ static int slic_entry_open(struct net_device *dev) { struct adapter *adapter = netdev_priv(dev); struct sliccard *card = adapter->card; - u32 locked = 0; int status; ASSERT(adapter); @@ -3142,7 +3140,6 @@ static int slic_entry_open(struct net_device *dev) spin_lock_irqsave(&slic_global.driver_lock.lock, slic_global.driver_lock.flags); - locked = 1; if (!adapter->activated) { card->adapters_activated++; slic_global.num_slic_ports_active++; @@ -3156,23 +3153,15 @@ static int slic_entry_open(struct net_device *dev) slic_global.num_slic_ports_active--; adapter->activated = 0; } - if (locked) { - spin_unlock_irqrestore(&slic_global.driver_lock.lock, - slic_global.driver_lock.flags); - locked = 0; - } - return status; + goto spin_unlock; } if (!card->master) card->master = adapter; - if (locked) { - spin_unlock_irqrestore(&slic_global.driver_lock.lock, - slic_global.driver_lock.flags); - locked = 0; - } - - return 0; +spin_unlock: + spin_unlock_irqrestore(&slic_global.driver_lock.lock, + slic_global.driver_lock.flags); + return status; } static void slic_card_cleanup(struct sliccard *card) @@ -3712,9 +3701,8 @@ static void slic_init_adapter(struct net_device *netdev, phys_shmem); ASSERT(adapter->pshmem); - memset(adapter->pshmem, 0, sizeof(struct slic_shmem)); - - return; + if (adapter->pshmem) + memset(adapter->pshmem, 0, sizeof(struct slic_shmem)); } static const struct net_device_ops slic_netdev_ops = { diff --git a/drivers/staging/sm7xxfb/sm7xx.h b/drivers/staging/sm7xxfb/sm7xx.h index 333f33c3dc66..85998615b801 100644 --- a/drivers/staging/sm7xxfb/sm7xx.h +++ b/drivers/staging/sm7xxfb/sm7xx.h @@ -29,7 +29,7 @@ #define dac_reg (0x3c8) #define dac_val (0x3c9) -extern char __iomem *smtc_RegBaseAddress; +extern void __iomem *smtc_RegBaseAddress; #define smtc_mmiowb(dat, reg) writeb(dat, smtc_RegBaseAddress + reg) #define smtc_mmioww(dat, reg) writew(dat, smtc_RegBaseAddress + reg) #define smtc_mmiowl(dat, reg) writel(dat, smtc_RegBaseAddress + reg) diff --git a/drivers/staging/sm7xxfb/sm7xxfb.c b/drivers/staging/sm7xxfb/sm7xxfb.c index 1c1780c70fbb..f27182d4dea6 100644 --- a/drivers/staging/sm7xxfb/sm7xxfb.c +++ b/drivers/staging/sm7xxfb/sm7xxfb.c @@ -43,11 +43,11 @@ struct smtcfb_info { u16 chip_id; u8 chip_rev_id; - unsigned char __iomem *m_pMMIO; - char __iomem *m_pLFB; - char *m_pDPR; - char *m_pVPR; - char *m_pCPR; + void __iomem *lfb; /* linear frame buffer */ + void __iomem *dp_regs; /* drawing processor control regs */ + void __iomem *vp_regs; /* video processor control regs */ + void __iomem *cp_regs; /* capture processor control regs */ + void __iomem *mmio; /* memory map IO port */ u_int width; u_int height; @@ -56,8 +56,7 @@ struct smtcfb_info { u32 colreg[17]; }; -char __iomem *smtc_RegBaseAddress; /* Memory Map IO starting address */ -char __iomem *smtc_VRAMBaseAddress; /* video memory starting address */ +void __iomem *smtc_RegBaseAddress; /* Memory Map IO starting address */ static struct fb_var_screeninfo smtcfb_var = { .xres = 1024, @@ -72,14 +71,20 @@ static struct fb_var_screeninfo smtcfb_var = { .height = -1, .width = -1, .vmode = FB_VMODE_NONINTERLACED, + .nonstd = 0, + .accel_flags = FB_ACCELF_TEXT, }; static struct fb_fix_screeninfo smtcfb_fix = { - .id = "sm712fb", + .id = "smXXXfb", .type = FB_TYPE_PACKED_PIXELS, .visual = FB_VISUAL_TRUECOLOR, .line_length = 800 * 3, .accel = FB_ACCEL_SMI_LYNX, + .type_aux = 0, + .xpanstep = 0, + .ypanstep = 0, + .ywrapstep = 0, }; struct vesa_mode { @@ -545,28 +550,28 @@ static void sm7xx_set_timing(struct smtcfb_info *sfb) smtc_mmiowb(0x67, 0x3c2); /* set VPR registers */ - writel(0x0, sfb->m_pVPR + 0x0C); - writel(0x0, sfb->m_pVPR + 0x40); + writel(0x0, sfb->vp_regs + 0x0C); + writel(0x0, sfb->vp_regs + 0x40); /* set data width */ m_nScreenStride = (sfb->width * sfb->fb.var.bits_per_pixel) / 64; switch (sfb->fb.var.bits_per_pixel) { case 8: - writel(0x0, sfb->m_pVPR + 0x0); + writel(0x0, sfb->vp_regs + 0x0); break; case 16: - writel(0x00020000, sfb->m_pVPR + 0x0); + writel(0x00020000, sfb->vp_regs + 0x0); break; case 24: - writel(0x00040000, sfb->m_pVPR + 0x0); + writel(0x00040000, sfb->vp_regs + 0x0); break; case 32: - writel(0x00030000, sfb->m_pVPR + 0x0); + writel(0x00030000, sfb->vp_regs + 0x0); break; } writel((u32) (((m_nScreenStride + 2) << 16) | m_nScreenStride), - sfb->m_pVPR + 0x10); + sfb->vp_regs + 0x10); } @@ -673,9 +678,9 @@ static struct fb_ops smtcfb_ops = { }; /* - * alloc struct smtcfb_info and assign the default value + * alloc struct smtcfb_info and assign default values */ -static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *pdev, char *name) +static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *pdev) { struct smtcfb_info *sfb; @@ -686,32 +691,12 @@ static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *pdev, char *name) sfb->pdev = pdev; - /* init sfb->fb with default value */ - - sfb->fb.flags = FBINFO_FLAG_DEFAULT; - sfb->fb.fbops = &smtcfb_ops; - - sfb->fb.fix = smtcfb_fix; - strcpy(sfb->fb.fix.id, name); - - sfb->fb.fix.type = FB_TYPE_PACKED_PIXELS; - sfb->fb.fix.type_aux = 0; - sfb->fb.fix.xpanstep = 0; - sfb->fb.fix.ypanstep = 0; - sfb->fb.fix.ywrapstep = 0; - sfb->fb.fix.accel = FB_ACCEL_SMI_LYNX; - - sfb->fb.var = smtcfb_var; - sfb->fb.var.nonstd = 0; - sfb->fb.var.activate = FB_ACTIVATE_NOW; - sfb->fb.var.height = -1; - sfb->fb.var.width = -1; - sfb->fb.var.accel_flags = FB_ACCELF_TEXT; - sfb->fb.var.vmode = FB_VMODE_NONINTERLACED; - - sfb->fb.pseudo_palette = sfb->colreg; - - sfb->fb.par = sfb; + sfb->fb.flags = FBINFO_FLAG_DEFAULT; + sfb->fb.fbops = &smtcfb_ops; + sfb->fb.fix = smtcfb_fix; + sfb->fb.var = smtcfb_var; + sfb->fb.pseudo_palette = sfb->colreg; + sfb->fb.par = sfb; return sfb; } @@ -751,7 +736,7 @@ static int smtc_map_smem(struct smtcfb_info *sfb, sfb->fb.fix.smem_len = smem_len; - sfb->fb.screen_base = smtc_VRAMBaseAddress; + sfb->fb.screen_base = sfb->lfb; if (!sfb->fb.screen_base) { dev_err(&pdev->dev, @@ -788,9 +773,8 @@ static int __devinit smtcfb_pci_probe(struct pci_dev *pdev, { struct smtcfb_info *sfb; u_long smem_size = 0x00800000; /* default 8MB */ - char name[16]; int err; - unsigned long pFramebufferPhysical; + unsigned long mmio_base; dev_info(&pdev->dev, "Silicon Motion display driver."); @@ -798,7 +782,9 @@ static int __devinit smtcfb_pci_probe(struct pci_dev *pdev, if (err) return err; - sfb = smtc_alloc_fb_info(pdev, name); + sprintf(smtcfb_fix.id, "sm%Xfb", ent->device); + + sfb = smtc_alloc_fb_info(pdev); if (!sfb) { err = -ENOMEM; @@ -806,7 +792,6 @@ static int __devinit smtcfb_pci_probe(struct pci_dev *pdev, } sfb->chip_id = ent->device; - sprintf(name, "sm%Xfb", sfb->chip_id); pci_set_drvdata(pdev, sfb); @@ -829,33 +814,28 @@ static int __devinit smtcfb_pci_probe(struct pci_dev *pdev, sfb->fb.var.bits_per_pixel = (smtc_scr_info.lfb_depth = 32); #endif /* Map address and memory detection */ - pFramebufferPhysical = pci_resource_start(pdev, 0); + mmio_base = pci_resource_start(pdev, 0); pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id); switch (sfb->chip_id) { case 0x710: case 0x712: - sfb->fb.fix.mmio_start = pFramebufferPhysical + 0x00400000; + sfb->fb.fix.mmio_start = mmio_base + 0x00400000; sfb->fb.fix.mmio_len = 0x00400000; smem_size = SM712_VIDEOMEMORYSIZE; #ifdef __BIG_ENDIAN - sfb->m_pLFB = (smtc_VRAMBaseAddress = - ioremap(pFramebufferPhysical, 0x00c00000)); + sfb->lfb = ioremap(mmio_base, 0x00c00000); #else - sfb->m_pLFB = (smtc_VRAMBaseAddress = - ioremap(pFramebufferPhysical, 0x00800000)); + sfb->lfb = ioremap(mmio_base, 0x00800000); #endif - sfb->m_pMMIO = (smtc_RegBaseAddress = - smtc_VRAMBaseAddress + 0x00700000); - sfb->m_pDPR = smtc_VRAMBaseAddress + 0x00408000; - sfb->m_pVPR = sfb->m_pLFB + 0x0040c000; + sfb->mmio = (smtc_RegBaseAddress = + sfb->lfb + 0x00700000); + sfb->dp_regs = sfb->lfb + 0x00408000; + sfb->vp_regs = sfb->lfb + 0x0040c000; #ifdef __BIG_ENDIAN if (sfb->fb.var.bits_per_pixel == 32) { - smtc_VRAMBaseAddress += 0x800000; - sfb->m_pLFB += 0x800000; - dev_info(&pdev->dev, - "smtc_VRAMBaseAddress=%p sfb->m_pLFB=%p", - smtc_VRAMBaseAddress, sfb->m_pLFB); + sfb->lfb += 0x800000; + dev_info(&pdev->dev, "sfb->lfb=%p", sfb->lfb); } #endif if (!smtc_RegBaseAddress) { @@ -879,15 +859,14 @@ static int __devinit smtcfb_pci_probe(struct pci_dev *pdev, #endif break; case 0x720: - sfb->fb.fix.mmio_start = pFramebufferPhysical; + sfb->fb.fix.mmio_start = mmio_base; sfb->fb.fix.mmio_len = 0x00200000; smem_size = SM722_VIDEOMEMORYSIZE; - sfb->m_pDPR = ioremap(pFramebufferPhysical, 0x00a00000); - sfb->m_pLFB = (smtc_VRAMBaseAddress = - sfb->m_pDPR + 0x00200000); - sfb->m_pMMIO = (smtc_RegBaseAddress = - sfb->m_pDPR + 0x000c0000); - sfb->m_pVPR = sfb->m_pDPR + 0x800; + sfb->dp_regs = ioremap(mmio_base, 0x00a00000); + sfb->lfb = sfb->dp_regs + 0x00200000; + sfb->mmio = (smtc_RegBaseAddress = + sfb->dp_regs + 0x000c0000); + sfb->vp_regs = sfb->dp_regs + 0x800; smtc_seqw(0x62, 0xff); smtc_seqw(0x6a, 0x0d); diff --git a/drivers/staging/speakup/i18n.c b/drivers/staging/speakup/i18n.c index ca01734d13c5..7c1658b971dc 100644 --- a/drivers/staging/speakup/i18n.c +++ b/drivers/staging/speakup/i18n.c @@ -555,6 +555,7 @@ ssize_t msg_set(enum msg_index_t index, char *text, size_t length) && index <= MSG_FORMATTED_END) && !fmt_validate(speakup_default_msgs[index], newstr)) { + kfree(newstr); return -EINVAL; } spk_lock(flags); diff --git a/drivers/staging/speakup/speakup_soft.c b/drivers/staging/speakup/speakup_soft.c index 42cdafeea35e..e2f5c81e7548 100644 --- a/drivers/staging/speakup/speakup_soft.c +++ b/drivers/staging/speakup/speakup_soft.c @@ -40,13 +40,13 @@ static int softsynth_is_alive(struct spk_synth *synth); static unsigned char get_index(void); static struct miscdevice synth_device; -static int initialized; +static int init_pos; static int misc_registered; static struct var_t vars[] = { { CAPS_START, .u.s = {"\x01+3p" } }, { CAPS_STOP, .u.s = {"\x01-3p" } }, - { RATE, .u.n = {"\x01%ds", 5, 0, 9, 0, 0, NULL } }, + { RATE, .u.n = {"\x01%ds", 2, 0, 9, 0, 0, NULL } }, { PITCH, .u.n = {"\x01%dp", 5, 0, 9, 0, 0, NULL } }, { VOL, .u.n = {"\x01%dv", 5, 0, 9, 0, 0, NULL } }, { TONE, .u.n = {"\x01%dx", 1, 0, 2, 0, 0, NULL } }, @@ -194,7 +194,7 @@ static int softsynth_close(struct inode *inode, struct file *fp) unsigned long flags; spk_lock(flags); synth_soft.alive = 0; - initialized = 0; + init_pos = 0; spk_unlock(flags); /* Make sure we let applications go before leaving */ speakup_start_ttys(); @@ -239,13 +239,8 @@ static ssize_t softsynth_read(struct file *fp, char *buf, size_t count, ch = '\x18'; } else if (synth_buffer_empty()) { break; - } else if (!initialized) { - if (*init) { - ch = *init; - init++; - } else { - initialized = 1; - } + } else if (init[init_pos]) { + ch = init[init_pos++]; } else { ch = synth_buffer_getc(); } diff --git a/drivers/staging/telephony/ixj.c b/drivers/staging/telephony/ixj.c index b303c9192e17..1cfa0b07d725 100644 --- a/drivers/staging/telephony/ixj.c +++ b/drivers/staging/telephony/ixj.c @@ -7057,7 +7057,7 @@ static int ixj_selfprobe(IXJ *j) printk(KERN_INFO "Enable Line Monitor\n"); if (ixjdebug & 0x0002) - printk(KERN_INFO "Set Line Monitor to Asyncronous Mode\n"); + printk(KERN_INFO "Set Line Monitor to Asynchronous Mode\n"); if (ixj_WriteDSPCommand(0x7E01, j)) /* Asynchronous Line Monitor */ return -1; @@ -7068,7 +7068,7 @@ static int ixj_selfprobe(IXJ *j) if (ixj_WriteDSPCommand(0x5151, j)) /* Enable DTMF detection */ return -1; - if (ixj_WriteDSPCommand(0x6E01, j)) /* Set Asyncronous Tone Generation */ + if (ixj_WriteDSPCommand(0x6E01, j)) /* Set Asynchronous Tone Generation */ return -1; set_rec_depth(j, 2); /* Set Record Channel Limit to 2 frames */ diff --git a/drivers/staging/tidspbridge/Documentation/error-codes b/drivers/staging/tidspbridge/Documentation/error-codes index 12826e2a3aaa..ad73cba058eb 100644 --- a/drivers/staging/tidspbridge/Documentation/error-codes +++ b/drivers/staging/tidspbridge/Documentation/error-codes @@ -69,7 +69,7 @@ The error codes used by this driver are: Invalid pointer or handler. [EEXIST] - Attempted to create a channel manager when one already exists. + Attempted to create a channel manager when one already exists. [EINVAL] Invalid argument. diff --git a/drivers/staging/tidspbridge/core/_tiomap.h b/drivers/staging/tidspbridge/core/_tiomap.h index 7cb587103975..543a127c7d4d 100644 --- a/drivers/staging/tidspbridge/core/_tiomap.h +++ b/drivers/staging/tidspbridge/core/_tiomap.h @@ -219,7 +219,7 @@ static const struct map_l4_peripheral l4_peripheral_table[] = { /* MBX_PM_MAX_RESOURCES: CORE 2 Clock Resources. */ #define MBX_CORE2_RESOURCES 1 -/* MBX_PM_MAX_RESOURCES: TOTAL Clock Reosurces. */ +/* MBX_PM_MAX_RESOURCES: TOTAL Clock Resources. */ #define MBX_PM_MAX_RESOURCES 11 /* Power Management Commands */ diff --git a/drivers/staging/tidspbridge/core/chnl_sm.c b/drivers/staging/tidspbridge/core/chnl_sm.c index e0c7e4c470c8..16fa3462fbbe 100644 --- a/drivers/staging/tidspbridge/core/chnl_sm.c +++ b/drivers/staging/tidspbridge/core/chnl_sm.c @@ -20,7 +20,7 @@ * The lower edge functions must be implemented by the Bridge driver * writer, and are declared in chnl_sm.h. * - * Care is taken in this code to prevent simulataneous access to channel + * Care is taken in this code to prevent simultaneous access to channel * queues from * 1. Threads. * 2. io_dpc(), scheduled from the io_isr() as an event. @@ -34,7 +34,7 @@ * Channel Invariant: * There is an important invariant condition which must be maintained per * channel outside of bridge_chnl_get_ioc() and IO_Dispatch(), violation of - * which may cause timeouts and/or failure offunction sync_wait_on_event. + * which may cause timeouts and/or failure of function sync_wait_on_event. * This invariant condition is: * * list_empty(&pchnl->io_completions) ==> pchnl->sync_event is reset @@ -94,7 +94,7 @@ int bridge_chnl_add_io_req(struct chnl_object *chnl_obj, void *host_buf, struct dev_object *dev_obj; u8 dw_state; bool is_eos; - struct chnl_mgr *chnl_mgr_obj = pchnl->chnl_mgr_obj; + struct chnl_mgr *chnl_mgr_obj; u8 *host_sys_buf = NULL; bool sched_dpc = false; u16 mb_val = 0; @@ -153,6 +153,7 @@ func_cont: * If DPC is scheduled in process context (iosm_schedule) and any * non-mailbox interrupt occurs, that DPC will run and break CS. Hence * we disable ALL DPCs. We will try to disable ONLY IO DPC later. */ + chnl_mgr_obj = pchnl->chnl_mgr_obj; spin_lock_bh(&chnl_mgr_obj->chnl_mgr_lock); omap_mbox_disable_irq(dev_ctxt->mbox, IRQ_RX); if (pchnl->chnl_type == CHNL_PCPY) { @@ -602,7 +603,7 @@ int bridge_chnl_get_ioc(struct chnl_object *chnl_obj, u32 timeout, /* Since DSPStream_Reclaim() does not take a timeout * parameter, we pass the stream's timeout value to * bridge_chnl_get_ioc. We cannot determine whether or not - * we have waited in User mode. Since the stream's timeout + * we have waited in user mode. Since the stream's timeout * value may be non-zero, we still have to set the event. * Therefore, this optimization is taken out. * diff --git a/drivers/staging/tidspbridge/core/dsp-clock.c b/drivers/staging/tidspbridge/core/dsp-clock.c index c7df34e6b60b..7eac01e5fe0b 100644 --- a/drivers/staging/tidspbridge/core/dsp-clock.c +++ b/drivers/staging/tidspbridge/core/dsp-clock.c @@ -16,6 +16,8 @@ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. */ +#define L4_34XX_BASE 0x48000000 + #include <linux/types.h> /* ----------------------------------- Host OS */ diff --git a/drivers/staging/tidspbridge/core/io_sm.c b/drivers/staging/tidspbridge/core/io_sm.c index 480a3845a24c..e322fb7aebe1 100644 --- a/drivers/staging/tidspbridge/core/io_sm.c +++ b/drivers/staging/tidspbridge/core/io_sm.c @@ -837,8 +837,8 @@ static void io_dispatch_pm(struct io_mgr *pio_mgr) /* * ======== io_dpc ======== * Deferred procedure call for shared memory channel driver ISR. Carries - * out the dispatch of I/O as a non-preemptible event.It can only be - * pre-empted by an ISR. + * out the dispatch of I/O as a non-preemptible event. It can only be + * pre-empted by an ISR. */ void io_dpc(unsigned long ref_data) { @@ -877,7 +877,7 @@ void io_dpc(unsigned long ref_data) pio_mgr->intr_val); } } - /* Proc-copy chanel dispatch */ + /* Proc-copy channel dispatch */ input_chnl(pio_mgr, NULL, IO_SERVICE); output_chnl(pio_mgr, NULL, IO_SERVICE); @@ -938,7 +938,7 @@ int io_mbox_msg(struct notifier_block *self, unsigned long len, void *msg) /* * ======== io_request_chnl ======== * Purpose: - * Request chanenel I/O from the DSP. Sets flags in shared memory, then + * Request channel I/O from the DSP. Sets flags in shared memory, then * interrupts the DSP. */ void io_request_chnl(struct io_mgr *io_manager, struct chnl_object *pchnl, @@ -2208,7 +2208,7 @@ void dump_dl_modules(struct bridge_dev_context *bridge_context) module_struct->num_sects); /* - * The section name strings start immedialty following + * The section name strings start immediately following * the array of dll_sect structures. */ sect_str = (char *) &module_struct-> diff --git a/drivers/staging/tidspbridge/core/sync.c b/drivers/staging/tidspbridge/core/sync.c index 995986a9d03b..7bb550acaf4a 100644 --- a/drivers/staging/tidspbridge/core/sync.c +++ b/drivers/staging/tidspbridge/core/sync.c @@ -49,7 +49,7 @@ void sync_set_event(struct sync_object *event) * @timeout timeout on waiting for the evetns. * @pu_index index of the event set. * - * This functios will wait until any of the array element is set or until + * These functions will wait until any of the array element is set or until * timeout. In case of success the function will return 0 and * @pu_index will store the index of the array element set or in case * of timeout the function will return -ETIME or in case of diff --git a/drivers/staging/tidspbridge/core/tiomap3430.c b/drivers/staging/tidspbridge/core/tiomap3430.c index f9609ce2c163..012c5a0cc6c8 100644 --- a/drivers/staging/tidspbridge/core/tiomap3430.c +++ b/drivers/staging/tidspbridge/core/tiomap3430.c @@ -328,7 +328,7 @@ static int bridge_brd_read(struct bridge_dev_context *dev_ctxt, ul_num_bytes, mem_type); return status; } - /* copy the data from DSP memory, */ + /* copy the data from DSP memory */ memcpy(host_buff, (void *)(dsp_base_addr + offset), ul_num_bytes); return status; } @@ -415,10 +415,10 @@ static int bridge_brd_start(struct bridge_dev_context *dev_ctxt, /* Assert RST1 i.e only the RST only for DSP megacell */ if (!status) { /* - * XXX: ioremapping MUST be removed once ctrl + * XXX: OMAP343X_CTRL_BASE ioremapping MUST be removed once ctrl * function is made available. */ - void __iomem *ctrl = ioremap(OMAP343X_CTRL_BASE, SZ_4K); + void __iomem *ctrl = ioremap(0x48002000, SZ_4K); if (!ctrl) return -ENOMEM; @@ -1745,7 +1745,7 @@ static int mem_map_vmalloc(struct bridge_dev_context *dev_context, pa_next = page_to_phys(page[0]); while (!status && (i < num_pages)) { /* - * Reuse pa_next from the previous iteraion to avoid + * Reuse pa_next from the previous iteration to avoid * an extra va2pa call */ pa_curr = pa_next; diff --git a/drivers/staging/tidspbridge/core/tiomap3430_pwr.c b/drivers/staging/tidspbridge/core/tiomap3430_pwr.c index 16a4aafa86ae..58a1d6dcf098 100644 --- a/drivers/staging/tidspbridge/core/tiomap3430_pwr.c +++ b/drivers/staging/tidspbridge/core/tiomap3430_pwr.c @@ -356,7 +356,7 @@ int pre_scale_dsp(struct bridge_dev_context *dev_context, void *pargs) dev_dbg(bridge, "OPP: %s IVA in sleep. No message to DSP\n"); return 0; } else if ((dev_context->brd_state == BRD_RUNNING)) { - /* Send a prenotificatio to DSP */ + /* Send a prenotification to DSP */ dev_dbg(bridge, "OPP: %s sent notification to DSP\n", __func__); sm_interrupt_dsp(dev_context, MBX_PM_SETPOINT_PRENOTIFY); return 0; diff --git a/drivers/staging/tidspbridge/core/wdt.c b/drivers/staging/tidspbridge/core/wdt.c index 870f934f4f3b..e5adad08f1c4 100644 --- a/drivers/staging/tidspbridge/core/wdt.c +++ b/drivers/staging/tidspbridge/core/wdt.c @@ -25,7 +25,8 @@ #include <dspbridge/host_os.h> -#define OMAP34XX_WDT3_BASE (L4_PER_34XX_BASE + 0x30000) +#define OMAP34XX_WDT3_BASE (0x49000000 + 0x30000) +#define INT_34XX_WDT3_IRQ 36 static struct dsp_wdt_setting dsp_wdt; @@ -61,9 +62,9 @@ int dsp_wdt_init(void) dsp_wdt.fclk = clk_get(NULL, "wdt3_fck"); - if (dsp_wdt.fclk) { + if (!IS_ERR(dsp_wdt.fclk)) { dsp_wdt.iclk = clk_get(NULL, "wdt3_ick"); - if (!dsp_wdt.iclk) { + if (IS_ERR(dsp_wdt.iclk)) { clk_put(dsp_wdt.fclk); dsp_wdt.fclk = NULL; ret = -EFAULT; diff --git a/drivers/staging/tidspbridge/dynload/tramp.c b/drivers/staging/tidspbridge/dynload/tramp.c index 60d22ea47055..404af1895980 100644 --- a/drivers/staging/tidspbridge/dynload/tramp.c +++ b/drivers/staging/tidspbridge/dynload/tramp.c @@ -81,7 +81,7 @@ static u8 priv_h2a(u8 value) * Description: Generate a trampoline symbol name (ASCII) using the value * of the symbol. This places the new name into the user buffer. * The name is fixed in length and of the form: __$dbTR__xxxxxxxx - * (where "xxxxxxxx" is the hex value. + * (where "xxxxxxxx" is the hex value). */ static void priv_tramp_sym_gen_name(u32 value, char *dst) { @@ -414,7 +414,7 @@ static int priv_tramp_sym_finalize(struct dload_state *dlthis) /* Copy the symbol contents into the flat table */ *new_sym = cur_sym->sym_info; - /* Now finaize the symbol. If it is in the tramp + /* Now finalize the symbol. If it is in the tramp * section, we need to adjust for the section start. * If it is external then we don't need to adjust at * all. @@ -773,7 +773,7 @@ static int priv_img_pkt_dup(struct dload_state *dlthis, int ret_val = 0; struct tramp_img_dup_relo *dup_relo = NULL; - /* Determinne if this image packet is already being tracked in the + /* Determine if this image packet is already being tracked in the dup list for other trampolines. */ dup_pkt = priv_dup_find(dlthis, secnn, image_offset); @@ -998,7 +998,7 @@ int dload_tramp_generate(struct dload_state *dlthis, s16 secnn, /* * Function: dload_tramp_pkt_update * Description: Update the duplicate copy of this image packet, which the - * trampoline layer is already tracking. This is call is critical + * trampoline layer is already tracking. This call is critical * to make if trampolines were generated anywhere within the * packet and first pass relo continued on the remainder. The * trampoline layer needs the updates image data so when 2nd diff --git a/drivers/staging/tidspbridge/gen/uuidutil.c b/drivers/staging/tidspbridge/gen/uuidutil.c index b44656cf7858..b7d8313d1acb 100644 --- a/drivers/staging/tidspbridge/gen/uuidutil.c +++ b/drivers/staging/tidspbridge/gen/uuidutil.c @@ -26,27 +26,6 @@ /* ----------------------------------- This */ #include <dspbridge/uuidutil.h> -/* - * ======== uuid_uuid_to_string ======== - * Purpose: - * Converts a struct dsp_uuid to a string. - * Note: snprintf format specifier is: - * %[flags] [width] [.precision] [{h | l | I64 | L}]type - */ -void uuid_uuid_to_string(struct dsp_uuid *uuid_obj, char *sz_uuid, - s32 size) -{ - s32 i; /* return result from snprintf. */ - - i = snprintf(sz_uuid, size, - "%.8X_%.4X_%.4X_%.2X%.2X_%.2X%.2X%.2X%.2X%.2X%.2X", - uuid_obj->data1, uuid_obj->data2, uuid_obj->data3, - uuid_obj->data4, uuid_obj->data5, - uuid_obj->data6[0], uuid_obj->data6[1], - uuid_obj->data6[2], uuid_obj->data6[3], - uuid_obj->data6[4], uuid_obj->data6[5]); -} - static s32 uuid_hex_to_bin(char *buf, s32 len) { s32 i; diff --git a/drivers/staging/tidspbridge/hw/hw_mmu.c b/drivers/staging/tidspbridge/hw/hw_mmu.c index 8a93d55ca596..71cb82293649 100644 --- a/drivers/staging/tidspbridge/hw/hw_mmu.c +++ b/drivers/staging/tidspbridge/hw/hw_mmu.c @@ -61,7 +61,7 @@ enum hw_mmu_page_size_t { * Type : hw_status * Description : 0 -- No errors occurred * RET_BAD_NULL_PARAM -- A Pointer - * Paramater was set to NULL + * Parameter was set to NULL * * PURPOSE: : Flush the TLB entry pointed by the * lock counter register @@ -103,7 +103,7 @@ static hw_status mmu_flush_entry(const void __iomem *base_address); * * Type : hw_status * Description : 0 -- No errors occurred - * RET_BAD_NULL_PARAM -- A Pointer Paramater + * RET_BAD_NULL_PARAM -- A Pointer Parameter * was set to NULL * RET_PARAM_OUT_OF_RANGE -- Input Parameter out * of Range @@ -148,7 +148,7 @@ static hw_status mmu_set_cam_entry(const void __iomem *base_address, * * Type : hw_status * Description : 0 -- No errors occurred - * RET_BAD_NULL_PARAM -- A Pointer Paramater + * RET_BAD_NULL_PARAM -- A Pointer Parameter * was set to NULL * RET_PARAM_OUT_OF_RANGE -- Input Parameter * out of Range diff --git a/drivers/staging/tidspbridge/include/dspbridge/dspioctl.h b/drivers/staging/tidspbridge/include/dspbridge/dspioctl.h index 0c7ec04448f1..0fcda1978921 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/dspioctl.h +++ b/drivers/staging/tidspbridge/include/dspbridge/dspioctl.h @@ -51,7 +51,7 @@ #define BRDIOCTL_POSTSCALE_NOTIFY (BRDIOCTL_PWRCONTROL + 0xA) #define BRDIOCTL_CONSTRAINT_REQUEST (BRDIOCTL_PWRCONTROL + 0xB) -/* Number of actual DSP-MMU TLB entrries */ +/* Number of actual DSP-MMU TLB entries */ #define BRDIOCTL_NUMOFMMUTLB 32 struct bridge_ioctl_extproc { diff --git a/drivers/staging/tidspbridge/include/dspbridge/mbx_sh.h b/drivers/staging/tidspbridge/include/dspbridge/mbx_sh.h index 7424c888d637..d4cb3948baba 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/mbx_sh.h +++ b/drivers/staging/tidspbridge/include/dspbridge/mbx_sh.h @@ -22,7 +22,7 @@ * mailbox interrupt's cmd value received. The class value are defined * as a bit (10 thru 15) being set. * - * Note: Only 16 bits of each is used. Other 16 bit data reg available. + * Note: Only 16 bits of each is used. Other 16 bit data reg available. * * 16 bit Mbx bit defns: * diff --git a/drivers/staging/tidspbridge/include/dspbridge/node.h b/drivers/staging/tidspbridge/include/dspbridge/node.h index 7397b7a12f7a..68ed74a86c95 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/node.h +++ b/drivers/staging/tidspbridge/include/dspbridge/node.h @@ -220,7 +220,7 @@ extern int node_create_mgr(struct node_mgr **node_man, * Parameters: * noderes: Node resource info handle returned from * node_allocate(). - * pr_ctxt: Poninter to process context data. + * pr_ctxt: Pointer to process context data. * Returns: * 0: Success. * -EFAULT: Invalid hnode. diff --git a/drivers/staging/tidspbridge/include/dspbridge/ntfy.h b/drivers/staging/tidspbridge/include/dspbridge/ntfy.h index cbc8819c61cc..6bb94d20e99a 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/ntfy.h +++ b/drivers/staging/tidspbridge/include/dspbridge/ntfy.h @@ -78,7 +78,7 @@ static inline void ntfy_init(struct ntfy_object *no) * ntfy_delete() - delete list of nofy events registered. * @ntfy_obj: Pointer to the ntfy object structure. * - * This function is used to remove all the notify events registered. + * This function is used to remove all the notify events registered. * unregister function is not needed in this function, to unregister * a ntfy_event please look at ntfy_register function. * diff --git a/drivers/staging/tidspbridge/include/dspbridge/proc.h b/drivers/staging/tidspbridge/include/dspbridge/proc.h index a82380ebc041..851b356d7a51 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/proc.h +++ b/drivers/staging/tidspbridge/include/dspbridge/proc.h @@ -263,7 +263,7 @@ extern int proc_get_processor_id(void *proc, u32 * proc_id); * Returns: * 0 : Success. * -EFAULT : Invalid processor handle. - * -EPERM : General failure while retireving processor trace + * -EPERM : General failure while retrieving processor trace * Buffer. * Requires: * pbuf is not NULL diff --git a/drivers/staging/tidspbridge/include/dspbridge/strm.h b/drivers/staging/tidspbridge/include/dspbridge/strm.h index dacf0c234fd1..97aee4c63d24 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/strm.h +++ b/drivers/staging/tidspbridge/include/dspbridge/strm.h @@ -203,7 +203,7 @@ extern int strm_issue(struct strm_object *stream_obj, u8 * pbuf, * index: Stream index. * pattr: Pointer to structure containing attributes to be * applied to stream. Cannot be NULL. - * strmres: Location to store stream resuorce info handle on output. + * strmres: Location to store stream resource info handle on output. * Returns: * 0: Success. * -EFAULT: Invalid hnode. diff --git a/drivers/staging/tidspbridge/include/dspbridge/sync.h b/drivers/staging/tidspbridge/include/dspbridge/sync.h index b1e75eb8847c..58a0d5c5543d 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/sync.h +++ b/drivers/staging/tidspbridge/include/dspbridge/sync.h @@ -78,7 +78,7 @@ void sync_set_event(struct sync_object *event); * @event: events to wait for it. * @timeout timeout on waiting for the evetn. * - * This functios will wait until @event is set or until timeout. In case of + * This function will wait until @event is set or until timeout. In case of * success the function will return 0 and * in case of timeout the function will return -ETIME * in case of signal the function will return -ERESTARTSYS @@ -106,7 +106,7 @@ static inline int sync_wait_on_event(struct sync_object *event, * @timeout timeout on waiting for the evetns. * @pu_index index of the event set. * - * This functios will wait until any of the array element is set or until + * This function will wait until any of the array element is set or until * timeout. In case of success the function will return 0 and * @pu_index will store the index of the array element set and in case * of timeout the function will return -ETIME. diff --git a/drivers/staging/tidspbridge/include/dspbridge/uuidutil.h b/drivers/staging/tidspbridge/include/dspbridge/uuidutil.h index 9a994753e9ba..414bf71d652d 100644 --- a/drivers/staging/tidspbridge/include/dspbridge/uuidutil.h +++ b/drivers/staging/tidspbridge/include/dspbridge/uuidutil.h @@ -22,26 +22,6 @@ #define MAXUUIDLEN 37 /* - * ======== uuid_uuid_to_string ======== - * Purpose: - * Converts a dsp_uuid to an ANSI string. - * Parameters: - * uuid_obj: Pointer to a dsp_uuid object. - * sz_uuid: Pointer to a buffer to receive a NULL-terminated UUID - * string. - * size: Maximum size of the sz_uuid string. - * Returns: - * Requires: - * uuid_obj & sz_uuid are non-NULL values. - * Ensures: - * Lenghth of sz_uuid is less than MAXUUIDLEN. - * Details: - * UUID string limit currently set at MAXUUIDLEN. - */ -void uuid_uuid_to_string(struct dsp_uuid *uuid_obj, char *sz_uuid, - s32 size); - -/* * ======== uuid_uuid_from_string ======== * Purpose: * Converts an ANSI string to a dsp_uuid. diff --git a/drivers/staging/tidspbridge/rmgr/dbdcd.c b/drivers/staging/tidspbridge/rmgr/dbdcd.c index 12a1d34b3954..9d52c3cb92f0 100644 --- a/drivers/staging/tidspbridge/rmgr/dbdcd.c +++ b/drivers/staging/tidspbridge/rmgr/dbdcd.c @@ -346,11 +346,13 @@ int dcd_get_object_def(struct dcd_manager *hdcd_mgr, struct dcd_manager *dcd_mgr_obj = hdcd_mgr; /* ptr to DCD mgr */ struct cod_libraryobj *lib = NULL; int status = 0; + int len; u32 ul_addr = 0; /* Used by cod_get_section */ u32 ul_len = 0; /* Used by cod_get_section */ u32 dw_buf_size; /* Used by REG functions */ char sz_reg_key[DCD_MAXPATHLENGTH]; char *sz_uuid; /*[MAXUUIDLEN]; */ + char *tmp; struct dcd_key_elem *dcd_key = NULL; char sz_sect_name[MAXUUIDLEN + 2]; /* ".[UUID]\0" */ char *psz_coff_buf; @@ -395,7 +397,7 @@ int dcd_get_object_def(struct dcd_manager *hdcd_mgr, } /* Create UUID value to set in registry. */ - uuid_uuid_to_string(obj_uuid, sz_uuid, MAXUUIDLEN); + snprintf(sz_uuid, MAXUUIDLEN, "%pUL", obj_uuid); if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH) strncat(sz_reg_key, sz_uuid, MAXUUIDLEN); @@ -429,12 +431,27 @@ int dcd_get_object_def(struct dcd_manager *hdcd_mgr, } /* Ensure sz_uuid + 1 is not greater than sizeof sz_sect_name. */ + len = strlen(sz_uuid); + if (len + 1 > sizeof(sz_sect_name)) { + status = -EPERM; + goto func_end; + } /* Create section name based on node UUID. A period is * pre-pended to the UUID string to form the section name. * I.e. ".24BC8D90_BB45_11d4_B756_006008BDB66F" */ + + len -= 4; /* uuid has 4 delimiters '-' */ + tmp = sz_uuid; + strncpy(sz_sect_name, ".", 2); - strncat(sz_sect_name, sz_uuid, strlen(sz_uuid)); + do { + char *uuid = strsep(&tmp, "-"); + if (!uuid) + break; + len -= strlen(uuid); + strncat(sz_sect_name, uuid, strlen(uuid) + 1); + } while (len && strncat(sz_sect_name, "_", 2)); /* Get section information. */ status = cod_get_section(lib, sz_sect_name, &ul_addr, &ul_len); @@ -463,7 +480,7 @@ int dcd_get_object_def(struct dcd_manager *hdcd_mgr, status = cod_read_section(lib, sz_sect_name, psz_coff_buf, ul_len); #endif if (!status) { - /* Compres DSP buffer to conform to PC format. */ + /* Compress DSP buffer to conform to PC format. */ if (strstr(dcd_key->path, "iva") == NULL) { compress_buf(psz_coff_buf, ul_len, DSPWORDSIZE); } else { @@ -666,7 +683,7 @@ int dcd_get_library_name(struct dcd_manager *hdcd_mgr, status = -EPERM; } /* Create UUID value to find match in registry. */ - uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN); + snprintf(sz_uuid, MAXUUIDLEN, "%pUL", uuid_obj); if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH) strncat(sz_reg_key, sz_uuid, MAXUUIDLEN); else @@ -706,7 +723,7 @@ int dcd_get_library_name(struct dcd_manager *hdcd_mgr, } else { status = -EPERM; } - uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN); + snprintf(sz_uuid, MAXUUIDLEN, "%pUL", uuid_obj); if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH) strncat(sz_reg_key, sz_uuid, MAXUUIDLEN); else @@ -797,7 +814,7 @@ int dcd_register_object(struct dsp_uuid *uuid_obj, status = -EPERM; /* Create UUID value to set in registry. */ - uuid_uuid_to_string(uuid_obj, sz_uuid, MAXUUIDLEN); + snprintf(sz_uuid, MAXUUIDLEN, "%pUL", uuid_obj); if ((strlen(sz_reg_key) + MAXUUIDLEN) < DCD_MAXPATHLENGTH) strncat(sz_reg_key, sz_uuid, MAXUUIDLEN); else diff --git a/drivers/staging/tidspbridge/rmgr/drv_interface.c b/drivers/staging/tidspbridge/rmgr/drv_interface.c index 3cac01492063..6acea2b56aa4 100644 --- a/drivers/staging/tidspbridge/rmgr/drv_interface.c +++ b/drivers/staging/tidspbridge/rmgr/drv_interface.c @@ -613,16 +613,6 @@ static struct platform_driver bridge_driver = { #endif }; -static int __init bridge_init(void) -{ - return platform_driver_register(&bridge_driver); -} - -static void __exit bridge_exit(void) -{ - platform_driver_unregister(&bridge_driver); -} - /* To remove all process resources before removing the process from the * process context list */ int drv_remove_all_resources(void *process_ctxt) @@ -636,6 +626,4 @@ int drv_remove_all_resources(void *process_ctxt) return status; } -/* Bridge driver initialization and de-initialization functions */ -module_init(bridge_init); -module_exit(bridge_exit); +module_platform_driver(bridge_driver); diff --git a/drivers/staging/tidspbridge/rmgr/dspdrv.c b/drivers/staging/tidspbridge/rmgr/dspdrv.c index dc767b183cdf..d460f5823c6b 100644 --- a/drivers/staging/tidspbridge/rmgr/dspdrv.c +++ b/drivers/staging/tidspbridge/rmgr/dspdrv.c @@ -72,7 +72,7 @@ u32 dsp_init(u32 *init_status) /* Unwind whatever was loaded */ if (status) { - /* irrespective of the status of dev_remove_device we conitinue + /* irrespective of the status of dev_remove_device we continue * unloading. Get the Driver Object iterate through and remove. * Reset the status to E_FAIL to avoid going through * api_init_complete2. */ @@ -92,7 +92,7 @@ u32 dsp_init(u32 *init_status) func_cont: /* Attempt to Start the Board */ if (!status) { - /* BRD_AutoStart could fail if the dsp execuetable is not the + /* BRD_AutoStart could fail if the dsp executable is not the * correct one. We should not propagate that error * into the device loader. */ (void)api_init_complete2(); diff --git a/drivers/staging/tidspbridge/rmgr/mgr.c b/drivers/staging/tidspbridge/rmgr/mgr.c index 8a1e9287cff6..b32ba0ad2a07 100644 --- a/drivers/staging/tidspbridge/rmgr/mgr.c +++ b/drivers/staging/tidspbridge/rmgr/mgr.c @@ -262,8 +262,8 @@ int mgr_enum_processor_info(u32 processor_id, IVAPROCTYPE_ARM7) proc_detect = true; } - /* User applciatiuons aonly check for chip type, so - * this clumsy overwrite */ + /* User applications only check for chip type, so + * this is a clumsy overwrite */ processor_info->processor_type = DSPTYPE64; } else { dev_dbg(bridge, "%s: Failed to get DCD processor info " diff --git a/drivers/staging/tidspbridge/rmgr/nldr.c b/drivers/staging/tidspbridge/rmgr/nldr.c index 30d5480fcdcc..6309221b64a5 100644 --- a/drivers/staging/tidspbridge/rmgr/nldr.c +++ b/drivers/staging/tidspbridge/rmgr/nldr.c @@ -898,7 +898,7 @@ static int add_ovly_info(void *handle, struct dbll_sect_info *sect_info, nldr_obj->ovly_table[i].execute_sects++; } else { - /* Put in "other" sectins */ + /* Put in "other" sections */ status = add_ovly_sect(nldr_obj, &nldr_obj-> diff --git a/drivers/staging/tidspbridge/rmgr/node.c b/drivers/staging/tidspbridge/rmgr/node.c index 7fb426c5251c..c2fc6137c770 100644 --- a/drivers/staging/tidspbridge/rmgr/node.c +++ b/drivers/staging/tidspbridge/rmgr/node.c @@ -1613,7 +1613,7 @@ int node_get_attr(struct node_object *hnode, return -EFAULT; hnode_mgr = hnode->node_mgr; - /* Enter hnode_mgr critical section (since we're accessing + /* Enter hnode_mgr critical section since we're accessing * data that could be changed by node_change_priority() and * node_connect(). */ mutex_lock(&hnode_mgr->node_mgr_lock); @@ -2714,8 +2714,7 @@ static int get_node_props(struct dcd_manager *hdcd_mgr, hnode->ntype = node_type = pndb_props->ntype; /* Create UUID value to set in registry. */ - uuid_uuid_to_string((struct dsp_uuid *)node_uuid, sz_uuid, - MAXUUIDLEN); + snprintf(sz_uuid, MAXUUIDLEN, "%pUL", node_uuid); dev_dbg(bridge, "(node) UUID: %s\n", sz_uuid); /* Fill in message args that come from NDB */ diff --git a/drivers/staging/tidspbridge/rmgr/proc.c b/drivers/staging/tidspbridge/rmgr/proc.c index 7e4f12f6be42..5e43938ab7fa 100644 --- a/drivers/staging/tidspbridge/rmgr/proc.c +++ b/drivers/staging/tidspbridge/rmgr/proc.c @@ -300,7 +300,7 @@ proc_attach(u32 processor_id, if (status) goto func_end; - /* If we made it this far, create the Proceesor object: */ + /* If we made it this far, create the Processor object: */ p_proc_object = kzalloc(sizeof(struct proc_object), GFP_KERNEL); /* Fill out the Processor Object: */ if (p_proc_object == NULL) { diff --git a/drivers/staging/usbip/Kconfig b/drivers/staging/usbip/Kconfig index dd13c0220681..199b1d4c0b85 100644 --- a/drivers/staging/usbip/Kconfig +++ b/drivers/staging/usbip/Kconfig @@ -1,6 +1,6 @@ config USBIP_CORE - tristate "USB/IP support (EXPERIMENTAL)" - depends on USB && NET && EXPERIMENTAL + tristate "USB/IP support" + depends on USB && NET default N ---help--- This enables pushing USB packets over IP to allow remote diff --git a/drivers/staging/usbip/stub_dev.c b/drivers/staging/usbip/stub_dev.c index 92ced35e6b7f..c8d79a7f0e0e 100644 --- a/drivers/staging/usbip/stub_dev.c +++ b/drivers/staging/usbip/stub_dev.c @@ -187,10 +187,14 @@ static void stub_shutdown_connection(struct usbip_device *ud) } /* 1. stop threads */ - if (ud->tcp_rx) + if (ud->tcp_rx) { kthread_stop_put(ud->tcp_rx); - if (ud->tcp_tx) + ud->tcp_rx = NULL; + } + if (ud->tcp_tx) { kthread_stop_put(ud->tcp_tx); + ud->tcp_tx = NULL; + } /* * 2. close the socket diff --git a/drivers/staging/usbip/stub_rx.c b/drivers/staging/usbip/stub_rx.c index 1d5b3fc62160..694cfd7596f3 100644 --- a/drivers/staging/usbip/stub_rx.c +++ b/drivers/staging/usbip/stub_rx.c @@ -155,7 +155,7 @@ static int tweak_set_configuration_cmd(struct urb *urb) * eventually reassigned to the device as far as driver matching * condition is kept. * - * Unfortunatelly, an existing usbip connection will be dropped + * Unfortunately, an existing usbip connection will be dropped * due to this driver unbinding. So, skip here. * A user may need to set a special configuration value before * exporting the device. diff --git a/drivers/staging/usbip/usbip_common.c b/drivers/staging/usbip/usbip_common.c index 70f230269329..891984238cdc 100644 --- a/drivers/staging/usbip/usbip_common.c +++ b/drivers/staging/usbip/usbip_common.c @@ -22,7 +22,9 @@ #include <linux/fs.h> #include <linux/kernel.h> #include <linux/slab.h> +#include <linux/stat.h> #include <linux/module.h> +#include <linux/moduleparam.h> #include <net/sock.h> #include "usbip_common.h" @@ -36,6 +38,8 @@ unsigned long usbip_debug_flag = 0xffffffff; unsigned long usbip_debug_flag; #endif EXPORT_SYMBOL_GPL(usbip_debug_flag); +module_param(usbip_debug_flag, ulong, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(usbip_debug_flag, "debug flags (defined in usbip_common.h)"); /* FIXME */ struct device_attribute dev_attr_usbip_debug; diff --git a/drivers/staging/usbip/userspace/configure.ac b/drivers/staging/usbip/userspace/configure.ac index bf5cf49cb554..43e641e5ac06 100644 --- a/drivers/staging/usbip/userspace/configure.ac +++ b/drivers/staging/usbip/userspace/configure.ac @@ -56,11 +56,11 @@ AC_ARG_WITH([tcp-wrappers], [AS_HELP_STRING([--with-tcp-wrappers], [use the libwrap (TCP wrappers) library])], dnl [ACTION-IF-GIVEN] - [saved_LIBS="$LIBS" - if test "$withval" = "yes"; then + [if test "$withval" = "yes"; then AC_MSG_RESULT([yes]) AC_MSG_CHECKING([for hosts_access in -lwrap]) - LIBS="-lwrap $LIBS" + saved_LIBS="$LIBS" + LIBS="-lwrap $saved_LIBS" AC_TRY_LINK( [int hosts_access(); int allow_severity, deny_severity;], [hosts_access()], @@ -69,9 +69,9 @@ AC_ARG_WITH([tcp-wrappers], [use tcp wrapper]) wrap_LIB="-lwrap"], [AC_MSG_RESULT([not found]); exit 1]) else - AC_MSG_RESULT([no]) - fi - LIBS="$saved_LIBS"], + AC_MSG_RESULT([no]); + LIBS="$saved_LIBS" + fi], dnl [ACTION-IF-NOT-GIVEN] [AC_MSG_RESULT([(default)]) AC_MSG_CHECKING([for hosts_access in -lwrap]) diff --git a/drivers/staging/usbip/userspace/doc/usbip.8 b/drivers/staging/usbip/userspace/doc/usbip.8 index 1653bb2cd7d1..6e0d74503792 100644 --- a/drivers/staging/usbip/userspace/doc/usbip.8 +++ b/drivers/staging/usbip/userspace/doc/usbip.8 @@ -3,69 +3,87 @@ usbip \- manage USB/IP devices .SH SYNOPSIS .B usbip -[\fIoptions\fR] +[\foptions\R] <\fIcommand\fR> <\fIargs\fR> .SH DESCRIPTION -Devices exported by USB/IP servers can be listed, attached and -detached using this program. +On a USB/IP server, devices can be listed, bound, and unbound using +this program. On a USB/IP client, devices exported by USB/IP servers +can be listed, attached and detached. .SH OPTIONS .HP -\fB\-a\fR, \fB\-\-attach\fR <host> <bus_id> +\fB\-\-debug\fR .IP -Attach a remote USB device. +Print debugging information. +.PP + +.HP +\fB\-\-log\fR +.IP +Log to syslog. +.PP + +.SH COMMANDS +.HP +\fBversion\fR +.IP +Show version and exit. .PP .HP -\fB\-x\fR, \fB\-\-attachall\fR <host> +\fBhelp\fR [\fIcommand\fR] .IP -Attach all remote USB devices on the specific host. +Print the program help message, or help on a specific command, and +then exit. .PP .HP -\fB\-d\fR, \fB\-\-detach\fR <ports> +\fBattach\fR \-\-host=<\fIhost\fR> \-\-busid=<\fIbus_id\fR> +.IP +Attach a remote USB device. +.PP + +.HP +\fBdetach\fR \-\-port=<\fIport\fR> .IP Detach an imported USB device. .PP .HP -\fB\-l\fR, \fB\-\-list\fR <hosts> +\fBbind\fR \-\-busid=<\fIbusid\fR> .IP -List exported USB devices. +Make a device exportable. .PP .HP -\fB\-p\fR, \fB\-\-port\fR +\fBunbind\fR \-\-busid=<\fIbusid\fR> .IP -List virtual USB port status. +Stop exporting a device so it can be used by a local driver. .PP .HP -\fB\-D\fR, \fB\-\-debug\fR +\fBlist\fR \-\-remote=<\fIhost\fR> .IP -Print debugging information. +List USB devices exported by a remote host. .PP .HP -\fB\-v\fR, \fB\-\-version\fR +\fBlist\fR \-\-local .IP -Show version. +List local USB devices. .PP + .SH EXAMPLES - client:# usbip --list server + client:# usbip list --remote=server - List exportable usb devices on the server. - client:# usbip --attach server 1-2 + client:# usbip attach --host=server --busid=1-2 - Connect the remote USB device. - client:# usbip --port - - Show virtual port status. - - client:# usbip --detach 0 + client:# usbip detach --port=0 - Detach the usb device. .SH "SEE ALSO" -\fBusbipd\fP\fB(8)\fB\fP, -\fBusbip_attach_driver\fP\fB(8)\fB\fP +\fBusbipd\fP\fB(8)\fB\fP diff --git a/drivers/staging/usbip/userspace/doc/usbip_bind_driver.8 b/drivers/staging/usbip/userspace/doc/usbip_bind_driver.8 deleted file mode 100644 index d43bbd6be934..000000000000 --- a/drivers/staging/usbip/userspace/doc/usbip_bind_driver.8 +++ /dev/null @@ -1,42 +0,0 @@ -.TH USBIP_BIND_DRIVER "8" "February 2009" "usbip" "System Administration Utilities" -.SH NAME -usbip_bind_driver \- change driver binding for USB/IP - -.SH SYNOPSIS -.B usbip_bind_driver -[\fIoptions\fR] - -.SH DESCRIPTION -Driver bindings for USB devices can be changed using -this program. It is used to export and unexport USB -devices over USB/IP. - -.SH OPTIONS -.TP -\fB\-u\fR, \fB\-\-usbip\fR <busid> -Make a device exportable -.TP -\fB\-o\fR, \fB\-\-other\fR <busid> -Use a device by a local driver -.TP -\fB\-l\fR, \fB\-\-list\fR -Print usb devices and their drivers -.TP -\fB\-L\fR, \fB\-\-list2\fR -Print usb devices and their drivers in parseable mode - -.SH EXAMPLES - - server:# usbip_bind_driver --list - - List driver assignments for usb devices. - - server:# usbip_bind_driver --usbip 1-2 - - Bind usbip-host.ko to the device of busid 1-2. - - A usb device 1-2 is now exportable to other hosts! - - server:# usbip_bind_driver --other 1-2 - - Shutdown exporting and use the device locally. - -.SH "SEE ALSO" -\fBusbip\fP\fB(8)\fB\fP, -\fBusbipd\fP\fB(8)\fB\fP diff --git a/drivers/staging/usbip/userspace/doc/usbipd.8 b/drivers/staging/usbip/userspace/doc/usbipd.8 index 006559f1df25..d896936f1780 100644 --- a/drivers/staging/usbip/userspace/doc/usbipd.8 +++ b/drivers/staging/usbip/userspace/doc/usbipd.8 @@ -10,7 +10,7 @@ usbipd \- USB/IP server daemon provides USB/IP clients access to exported USB devices. Devices have to explicitly be exported using -.B usbip_bind_driver +.B usbip bind before usbipd makes them available to other hosts. The daemon accepts connections from USB/IP clients @@ -29,6 +29,11 @@ Run as a daemon process. Print debugging information. .PP +\fB\-h\fR, \fB\-\-help\fR +.IP +Print the program help message and exit. +.PP + .HP \fB\-v\fR, \fB\-\-version\fR .IP @@ -48,15 +53,14 @@ USB/IP client can connect and use exported devices. server:# usbipd -D - Start usbip daemon. - server:# usbip_bind_driver --list + server:# usbip list --local - List driver assignments for usb devices. - server:# usbip_bind_driver --usbip 1-2 + server:# usbip bind --busid=1-2 - Bind usbip-host.ko to the device of busid 1-2. - A usb device 1-2 is now exportable to other hosts! - - Use 'usbip_bind_driver --other 1-2' when you want to shutdown exporting and use the device locally. + - Use 'usbip unbind --busid=1-2' when you want to shutdown exporting and use the device locally. .SH "SEE ALSO" -\fBusbip\fP\fB(8)\fB\fP, -\fBusbip_attach_driver\fP\fB(8)\fB\fP +\fBusbip\fP\fB(8)\fB\fP diff --git a/drivers/staging/usbip/vhci_hcd.c b/drivers/staging/usbip/vhci_hcd.c index 12a9a5fbc797..620d1beb4587 100644 --- a/drivers/staging/usbip/vhci_hcd.c +++ b/drivers/staging/usbip/vhci_hcd.c @@ -220,7 +220,7 @@ static int vhci_hub_status(struct usb_hcd *hcd, char *buf) pr_info("changed %d\n", changed); - if (hcd->state == HC_STATE_SUSPENDED) + if ((hcd->state == HC_STATE_SUSPENDED) && (changed == 1)) usb_hcd_resume_root_hub(hcd); done: @@ -749,6 +749,7 @@ static void vhci_device_unlink_cleanup(struct vhci_device *vdev) { struct vhci_unlink *unlink, *tmp; + spin_lock(&the_controller->lock); spin_lock(&vdev->priv_lock); list_for_each_entry_safe(unlink, tmp, &vdev->unlink_tx, list) { @@ -757,9 +758,12 @@ static void vhci_device_unlink_cleanup(struct vhci_device *vdev) kfree(unlink); } - list_for_each_entry_safe(unlink, tmp, &vdev->unlink_rx, list) { + while (!list_empty(&vdev->unlink_rx)) { struct urb *urb; + unlink = list_first_entry(&vdev->unlink_rx, struct vhci_unlink, + list); + /* give back URB of unanswered unlink request */ pr_info("unlink cleanup rx %lu\n", unlink->unlink_seqnum); @@ -774,18 +778,24 @@ static void vhci_device_unlink_cleanup(struct vhci_device *vdev) urb->status = -ENODEV; - spin_lock(&the_controller->lock); usb_hcd_unlink_urb_from_ep(vhci_to_hcd(the_controller), urb); + + list_del(&unlink->list); + + spin_unlock(&vdev->priv_lock); spin_unlock(&the_controller->lock); usb_hcd_giveback_urb(vhci_to_hcd(the_controller), urb, urb->status); - list_del(&unlink->list); + spin_lock(&the_controller->lock); + spin_lock(&vdev->priv_lock); + kfree(unlink); } spin_unlock(&vdev->priv_lock); + spin_unlock(&the_controller->lock); } /* @@ -804,11 +814,14 @@ static void vhci_shutdown_connection(struct usbip_device *ud) } /* kill threads related to this sdev, if v.c. exists */ - if (vdev->ud.tcp_rx) + if (vdev->ud.tcp_rx) { kthread_stop_put(vdev->ud.tcp_rx); - if (vdev->ud.tcp_tx) + vdev->ud.tcp_rx = NULL; + } + if (vdev->ud.tcp_tx) { kthread_stop_put(vdev->ud.tcp_tx); - + vdev->ud.tcp_tx = NULL; + } pr_info("stop threads\n"); /* active connection is closed */ @@ -828,11 +841,11 @@ static void vhci_shutdown_connection(struct usbip_device *ud) * disable endpoints. pending urbs are unlinked(dequeued). * * NOTE: After calling rh_port_disconnect(), the USB device drivers of a - * deteched device should release used urbs in a cleanup function(i.e. + * detached device should release used urbs in a cleanup function (i.e. * xxx_disconnect()). Therefore, vhci_hcd does not need to release * pushed urbs and their private data in this function. * - * NOTE: vhci_dequeue() must be considered carefully. When shutdowning + * NOTE: vhci_dequeue() must be considered carefully. When shutting down * a connection, vhci_shutdown_connection() expects vhci_dequeue() * gives back pushed urbs and frees their private data by request of * the cleanup function of a USB driver. When unlinking a urb with an diff --git a/drivers/staging/vme/devices/vme_pio2_core.c b/drivers/staging/vme/devices/vme_pio2_core.c index 4bf8e05ac312..dad8281915bf 100644 --- a/drivers/staging/vme/devices/vme_pio2_core.c +++ b/drivers/staging/vme/devices/vme_pio2_core.c @@ -10,6 +10,8 @@ * option) any later version. */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/module.h> #include <linux/moduleparam.h> #include <linux/types.h> @@ -163,15 +165,13 @@ static int __init pio2_init(void) int retval = 0; if (bus_num == 0) { - printk(KERN_ERR "%s: No cards, skipping registration\n", - driver_name); + pr_err("No cards, skipping registration\n"); goto err_nocard; } if (bus_num > PIO2_CARDS_MAX) { - printk(KERN_ERR - "%s: Driver only able to handle %d PIO2 Cards\n", - driver_name, PIO2_CARDS_MAX); + pr_err("Driver only able to handle %d PIO2 Cards\n", + PIO2_CARDS_MAX); bus_num = PIO2_CARDS_MAX; } diff --git a/drivers/staging/vme/devices/vme_user.c b/drivers/staging/vme/devices/vme_user.c index e25645e226e3..c3f94f311ca7 100644 --- a/drivers/staging/vme/devices/vme_user.c +++ b/drivers/staging/vme/devices/vme_user.c @@ -64,13 +64,13 @@ static unsigned int bus_num; * * However the VME driver at http://www.vmelinux.org/ is rather old and doesn't * even support the tsi148 chipset (which has 8 master and 8 slave windows). - * We'll run with this or now as far as possible, however it probably makes + * We'll run with this for now as far as possible, however it probably makes * sense to get rid of the old mappings and just do everything dynamically. * * So for now, we'll restrict the driver to providing 4 masters and 4 slaves as * defined above and try to support at least some of the interface from - * http://www.vmelinux.org/ as an alternative drive can be written providing a - * saner interface later. + * http://www.vmelinux.org/ as an alternative the driver can be written + * providing a saner interface later. * * The vmelinux.org driver never supported slave images, the devices reserved * for slaves were repurposed to support all 8 master images on the UniverseII! @@ -242,7 +242,7 @@ static ssize_t resource_to_user(int minor, char __user *buf, size_t count, } /* - * We are going ot alloc a page during init per window for small transfers. + * We are going to alloc a page during init per window for small transfers. * Small transfers will go user space -> buffer -> VME. Larger (more than a * page) transfers will lock the user space buffer into memory and then * transfer the data directly from the user space buffers out to VME. @@ -396,7 +396,7 @@ static ssize_t vme_user_write(struct file *file, const char __user *buf, default: retval = -EINVAL; } - + mutex_unlock(&image[minor].mutex); if (retval > 0) diff --git a/drivers/staging/vt6655/80211mgr.h b/drivers/staging/vt6655/80211mgr.h index 3bdab3f56f1c..65780f28db41 100644 --- a/drivers/staging/vt6655/80211mgr.h +++ b/drivers/staging/vt6655/80211mgr.h @@ -186,7 +186,7 @@ // -// Cipher Suite Selectors defiened in 802.11i +// Cipher Suite Selectors defined in 802.11i // #define WLAN_11i_CSS_USE_GROUP 0 #define WLAN_11i_CSS_WEP40 1 diff --git a/drivers/staging/vt6655/baseband.c b/drivers/staging/vt6655/baseband.c index e7b93a21e3b2..8d2c6a789ab2 100644 --- a/drivers/staging/vt6655/baseband.c +++ b/drivers/staging/vt6655/baseband.c @@ -28,8 +28,8 @@ * Functions: * BBuGetFrameTime - Calculate data frame transmitting time * BBvCaculateParameter - Caculate PhyLength, PhyService and Phy Signal parameter for baseband Tx - * BBbReadEmbeded - Embeded read baseband register via MAC - * BBbWriteEmbeded - Embeded write baseband register via MAC + * BBbReadEmbedded - Embedded read baseband register via MAC + * BBbWriteEmbedded - Embedded write baseband register via MAC * BBbIsRegBitsOn - Test if baseband register bits on * BBbIsRegBitsOff - Test if baseband register bits off * BBbVT3253Init - VIA VT3253 baseband chip init code @@ -40,7 +40,7 @@ * Revision History: * 06-10-2003 Bryan YC Fan: Re-write codes to support VT3253 spec. * 08-07-2003 Bryan YC Fan: Add MAXIM2827/2825 and RFMD2959 support. - * 08-26-2003 Kyle Hsu : Modify BBuGetFrameTime() and BBvCaculateParameter(). + * 08-26-2003 Kyle Hsu : Modify BBuGetFrameTime() and BBvCalculateParameter(). * cancel the setting of MAC_REG_SOFTPWRCTL on BBbVT3253Init(). * Add the comments. * 09-01-2003 Bryan YC Fan: RF & BB tables updated. @@ -1826,7 +1826,7 @@ BBuGetFrameTime ( } /* - * Description: Caculate Length, Service, and Signal fields of Phy for Tx + * Description: Calculate Length, Service, and Signal fields of Phy for Tx * * Parameters: * In: @@ -1842,7 +1842,7 @@ BBuGetFrameTime ( * */ void -BBvCaculateParameter ( +BBvCalculateParameter ( PSDevice pDevice, unsigned int cbFrameLength, unsigned short wRate, @@ -2001,7 +2001,7 @@ BBvCaculateParameter ( } /* - * Description: Read a byte from BASEBAND, by embeded programming + * Description: Read a byte from BASEBAND, by embedded programming * * Parameters: * In: @@ -2013,7 +2013,7 @@ BBvCaculateParameter ( * Return Value: true if succeeded; false if failed. * */ -bool BBbReadEmbeded (unsigned long dwIoBase, unsigned char byBBAddr, unsigned char *pbyData) +bool BBbReadEmbedded (unsigned long dwIoBase, unsigned char byBBAddr, unsigned char *pbyData) { unsigned short ww; unsigned char byValue; @@ -2043,7 +2043,7 @@ bool BBbReadEmbeded (unsigned long dwIoBase, unsigned char byBBAddr, unsigned ch /* - * Description: Write a Byte to BASEBAND, by embeded programming + * Description: Write a Byte to BASEBAND, by embedded programming * * Parameters: * In: @@ -2056,7 +2056,7 @@ bool BBbReadEmbeded (unsigned long dwIoBase, unsigned char byBBAddr, unsigned ch * Return Value: true if succeeded; false if failed. * */ -bool BBbWriteEmbeded (unsigned long dwIoBase, unsigned char byBBAddr, unsigned char byData) +bool BBbWriteEmbedded (unsigned long dwIoBase, unsigned char byBBAddr, unsigned char byData) { unsigned short ww; unsigned char byValue; @@ -2102,7 +2102,7 @@ bool BBbIsRegBitsOn (unsigned long dwIoBase, unsigned char byBBAddr, unsigned ch { unsigned char byOrgData; - BBbReadEmbeded(dwIoBase, byBBAddr, &byOrgData); + BBbReadEmbedded(dwIoBase, byBBAddr, &byOrgData); return (byOrgData & byTestBits) == byTestBits; } @@ -2125,7 +2125,7 @@ bool BBbIsRegBitsOff (unsigned long dwIoBase, unsigned char byBBAddr, unsigned c { unsigned char byOrgData; - BBbReadEmbeded(dwIoBase, byBBAddr, &byOrgData); + BBbReadEmbedded(dwIoBase, byBBAddr, &byOrgData); return (byOrgData & byTestBits) == 0; } @@ -2155,14 +2155,14 @@ bool BBbVT3253Init (PSDevice pDevice) if (byRFType == RF_RFMD2959) { if (byLocalID <= REV_ID_VT3253_A1) { for (ii = 0; ii < CB_VT3253_INIT_FOR_RFMD; ii++) { - bResult &= BBbWriteEmbeded(dwIoBase,byVT3253InitTab_RFMD[ii][0],byVT3253InitTab_RFMD[ii][1]); + bResult &= BBbWriteEmbedded(dwIoBase,byVT3253InitTab_RFMD[ii][0],byVT3253InitTab_RFMD[ii][1]); } } else { for (ii = 0; ii < CB_VT3253B0_INIT_FOR_RFMD; ii++) { - bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_RFMD[ii][0],byVT3253B0_RFMD[ii][1]); + bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_RFMD[ii][0],byVT3253B0_RFMD[ii][1]); } for (ii = 0; ii < CB_VT3253B0_AGC_FOR_RFMD2959; ii++) { - bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AGC4_RFMD2959[ii][0],byVT3253B0_AGC4_RFMD2959[ii][1]); + bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AGC4_RFMD2959[ii][0],byVT3253B0_AGC4_RFMD2959[ii][1]); } VNSvOutPortD(dwIoBase + MAC_REG_ITRTMSET, 0x23); MACvRegBitsOn(dwIoBase, MAC_REG_PAPEDELAY, BIT0); @@ -2177,10 +2177,10 @@ bool BBbVT3253Init (PSDevice pDevice) pDevice->ldBmThreshold[3] = 0; } else if ((byRFType == RF_AIROHA) || (byRFType == RF_AL2230S) ) { for (ii = 0; ii < CB_VT3253B0_INIT_FOR_AIROHA2230; ii++) { - bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AIROHA2230[ii][0],byVT3253B0_AIROHA2230[ii][1]); + bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AIROHA2230[ii][0],byVT3253B0_AIROHA2230[ii][1]); } for (ii = 0; ii < CB_VT3253B0_AGC; ii++) { - bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]); + bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]); } pDevice->abyBBVGA[0] = 0x1C; pDevice->abyBBVGA[1] = 0x10; @@ -2192,10 +2192,10 @@ bool BBbVT3253Init (PSDevice pDevice) pDevice->ldBmThreshold[3] = 0; } else if (byRFType == RF_UW2451) { for (ii = 0; ii < CB_VT3253B0_INIT_FOR_UW2451; ii++) { - bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_UW2451[ii][0],byVT3253B0_UW2451[ii][1]); + bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_UW2451[ii][0],byVT3253B0_UW2451[ii][1]); } for (ii = 0; ii < CB_VT3253B0_AGC; ii++) { - bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]); + bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]); } VNSvOutPortB(dwIoBase + MAC_REG_ITRTMSET, 0x23); MACvRegBitsOn(dwIoBase, MAC_REG_PAPEDELAY, BIT0); @@ -2210,28 +2210,28 @@ bool BBbVT3253Init (PSDevice pDevice) pDevice->ldBmThreshold[3] = 0; } else if (byRFType == RF_UW2452) { for (ii = 0; ii < CB_VT3253B0_INIT_FOR_UW2451; ii++) { - bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_UW2451[ii][0],byVT3253B0_UW2451[ii][1]); + bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_UW2451[ii][0],byVT3253B0_UW2451[ii][1]); } // Init ANT B select,TX Config CR09 = 0x61->0x45, 0x45->0x41(VC1/VC2 define, make the ANT_A, ANT_B inverted) - //bResult &= BBbWriteEmbeded(dwIoBase,0x09,0x41); + //bResult &= BBbWriteEmbedded(dwIoBase,0x09,0x41); // Init ANT B select,RX Config CR10 = 0x28->0x2A, 0x2A->0x28(VC1/VC2 define, make the ANT_A, ANT_B inverted) - //bResult &= BBbWriteEmbeded(dwIoBase,0x0a,0x28); + //bResult &= BBbWriteEmbedded(dwIoBase,0x0a,0x28); // Select VC1/VC2, CR215 = 0x02->0x06 - bResult &= BBbWriteEmbeded(dwIoBase,0xd7,0x06); + bResult &= BBbWriteEmbedded(dwIoBase,0xd7,0x06); //{{RobertYu:20050125, request by Jack - bResult &= BBbWriteEmbeded(dwIoBase,0x90,0x20); - bResult &= BBbWriteEmbeded(dwIoBase,0x97,0xeb); + bResult &= BBbWriteEmbedded(dwIoBase,0x90,0x20); + bResult &= BBbWriteEmbedded(dwIoBase,0x97,0xeb); //}} //{{RobertYu:20050221, request by Jack - bResult &= BBbWriteEmbeded(dwIoBase,0xa6,0x00); - bResult &= BBbWriteEmbeded(dwIoBase,0xa8,0x30); + bResult &= BBbWriteEmbedded(dwIoBase,0xa6,0x00); + bResult &= BBbWriteEmbedded(dwIoBase,0xa8,0x30); //}} - bResult &= BBbWriteEmbeded(dwIoBase,0xb0,0x58); + bResult &= BBbWriteEmbedded(dwIoBase,0xb0,0x58); for (ii = 0; ii < CB_VT3253B0_AGC; ii++) { - bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]); + bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]); } //VNSvOutPortB(dwIoBase + MAC_REG_ITRTMSET, 0x23); // RobertYu: 20050104, 20050131 disable PA_Delay //MACvRegBitsOn(dwIoBase, MAC_REG_PAPEDELAY, BIT0); // RobertYu: 20050104, 20050131 disable PA_Delay @@ -2248,10 +2248,10 @@ bool BBbVT3253Init (PSDevice pDevice) } else if (byRFType == RF_VT3226) { for (ii = 0; ii < CB_VT3253B0_INIT_FOR_AIROHA2230; ii++) { - bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AIROHA2230[ii][0],byVT3253B0_AIROHA2230[ii][1]); + bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AIROHA2230[ii][0],byVT3253B0_AIROHA2230[ii][1]); } for (ii = 0; ii < CB_VT3253B0_AGC; ii++) { - bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]); + bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]); } pDevice->abyBBVGA[0] = 0x1C; pDevice->abyBBVGA[1] = 0x10; @@ -2266,20 +2266,20 @@ bool BBbVT3253Init (PSDevice pDevice) //{{ RobertYu: 20050104 } else if (byRFType == RF_AIROHA7230) { for (ii = 0; ii < CB_VT3253B0_INIT_FOR_AIROHA2230; ii++) { - bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AIROHA2230[ii][0],byVT3253B0_AIROHA2230[ii][1]); + bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AIROHA2230[ii][0],byVT3253B0_AIROHA2230[ii][1]); } //{{ RobertYu:20050223, request by JerryChung // Init ANT B select,TX Config CR09 = 0x61->0x45, 0x45->0x41(VC1/VC2 define, make the ANT_A, ANT_B inverted) - //bResult &= BBbWriteEmbeded(dwIoBase,0x09,0x41); + //bResult &= BBbWriteEmbedded(dwIoBase,0x09,0x41); // Init ANT B select,RX Config CR10 = 0x28->0x2A, 0x2A->0x28(VC1/VC2 define, make the ANT_A, ANT_B inverted) - //bResult &= BBbWriteEmbeded(dwIoBase,0x0a,0x28); + //bResult &= BBbWriteEmbedded(dwIoBase,0x0a,0x28); // Select VC1/VC2, CR215 = 0x02->0x06 - bResult &= BBbWriteEmbeded(dwIoBase,0xd7,0x06); + bResult &= BBbWriteEmbedded(dwIoBase,0xd7,0x06); //}} for (ii = 0; ii < CB_VT3253B0_AGC; ii++) { - bResult &= BBbWriteEmbeded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]); + bResult &= BBbWriteEmbedded(dwIoBase,byVT3253B0_AGC[ii][0],byVT3253B0_AGC[ii][1]); } pDevice->abyBBVGA[0] = 0x1C; pDevice->abyBBVGA[1] = 0x10; @@ -2297,8 +2297,8 @@ bool BBbVT3253Init (PSDevice pDevice) } if (byLocalID > REV_ID_VT3253_A1) { - BBbWriteEmbeded(dwIoBase, 0x04, 0x7F); - BBbWriteEmbeded(dwIoBase, 0x0D, 0x01); + BBbWriteEmbedded(dwIoBase, 0x04, 0x7F); + BBbWriteEmbedded(dwIoBase, 0x0D, 0x01); } return bResult; @@ -2324,7 +2324,7 @@ void BBvReadAllRegs (unsigned long dwIoBase, unsigned char *pbyBBRegs) int ii; unsigned char byBase = 1; for (ii = 0; ii < BB_MAX_CONTEXT_SIZE; ii++) { - BBbReadEmbeded(dwIoBase, (unsigned char)(ii*byBase), pbyBBRegs); + BBbReadEmbedded(dwIoBase, (unsigned char)(ii*byBase), pbyBBRegs); pbyBBRegs += byBase; } } @@ -2350,39 +2350,39 @@ void BBvLoopbackOn (PSDevice pDevice) unsigned long dwIoBase = pDevice->PortOffset; //CR C9 = 0x00 - BBbReadEmbeded(dwIoBase, 0xC9, &pDevice->byBBCRc9);//CR201 - BBbWriteEmbeded(dwIoBase, 0xC9, 0); - BBbReadEmbeded(dwIoBase, 0x4D, &pDevice->byBBCR4d);//CR77 - BBbWriteEmbeded(dwIoBase, 0x4D, 0x90); + BBbReadEmbedded(dwIoBase, 0xC9, &pDevice->byBBCRc9);//CR201 + BBbWriteEmbedded(dwIoBase, 0xC9, 0); + BBbReadEmbedded(dwIoBase, 0x4D, &pDevice->byBBCR4d);//CR77 + BBbWriteEmbedded(dwIoBase, 0x4D, 0x90); //CR 88 = 0x02(CCK), 0x03(OFDM) - BBbReadEmbeded(dwIoBase, 0x88, &pDevice->byBBCR88);//CR136 + BBbReadEmbedded(dwIoBase, 0x88, &pDevice->byBBCR88);//CR136 if (pDevice->uConnectionRate <= RATE_11M) { //CCK // Enable internal digital loopback: CR33 |= 0000 0001 - BBbReadEmbeded(dwIoBase, 0x21, &byData);//CR33 - BBbWriteEmbeded(dwIoBase, 0x21, (unsigned char)(byData | 0x01));//CR33 + BBbReadEmbedded(dwIoBase, 0x21, &byData);//CR33 + BBbWriteEmbedded(dwIoBase, 0x21, (unsigned char)(byData | 0x01));//CR33 // CR154 = 0x00 - BBbWriteEmbeded(dwIoBase, 0x9A, 0); //CR154 + BBbWriteEmbedded(dwIoBase, 0x9A, 0); //CR154 - BBbWriteEmbeded(dwIoBase, 0x88, 0x02);//CR239 + BBbWriteEmbedded(dwIoBase, 0x88, 0x02);//CR239 } else { //OFDM // Enable internal digital loopback:CR154 |= 0000 0001 - BBbReadEmbeded(dwIoBase, 0x9A, &byData);//CR154 - BBbWriteEmbeded(dwIoBase, 0x9A, (unsigned char)(byData | 0x01));//CR154 + BBbReadEmbedded(dwIoBase, 0x9A, &byData);//CR154 + BBbWriteEmbedded(dwIoBase, 0x9A, (unsigned char)(byData | 0x01));//CR154 // CR33 = 0x00 - BBbWriteEmbeded(dwIoBase, 0x21, 0); //CR33 + BBbWriteEmbedded(dwIoBase, 0x21, 0); //CR33 - BBbWriteEmbeded(dwIoBase, 0x88, 0x03);//CR239 + BBbWriteEmbedded(dwIoBase, 0x88, 0x03);//CR239 } //CR14 = 0x00 - BBbWriteEmbeded(dwIoBase, 0x0E, 0);//CR14 + BBbWriteEmbedded(dwIoBase, 0x0E, 0);//CR14 // Disable TX_IQUN - BBbReadEmbeded(pDevice->PortOffset, 0x09, &pDevice->byBBCR09); - BBbWriteEmbeded(pDevice->PortOffset, 0x09, (unsigned char)(pDevice->byBBCR09 & 0xDE)); + BBbReadEmbedded(pDevice->PortOffset, 0x09, &pDevice->byBBCR09); + BBbWriteEmbedded(pDevice->PortOffset, 0x09, (unsigned char)(pDevice->byBBCR09 & 0xDE)); } /* @@ -2403,22 +2403,22 @@ void BBvLoopbackOff (PSDevice pDevice) unsigned char byData; unsigned long dwIoBase = pDevice->PortOffset; - BBbWriteEmbeded(dwIoBase, 0xC9, pDevice->byBBCRc9);//CR201 - BBbWriteEmbeded(dwIoBase, 0x88, pDevice->byBBCR88);//CR136 - BBbWriteEmbeded(dwIoBase, 0x09, pDevice->byBBCR09);//CR136 - BBbWriteEmbeded(dwIoBase, 0x4D, pDevice->byBBCR4d);//CR77 + BBbWriteEmbedded(dwIoBase, 0xC9, pDevice->byBBCRc9);//CR201 + BBbWriteEmbedded(dwIoBase, 0x88, pDevice->byBBCR88);//CR136 + BBbWriteEmbedded(dwIoBase, 0x09, pDevice->byBBCR09);//CR136 + BBbWriteEmbedded(dwIoBase, 0x4D, pDevice->byBBCR4d);//CR77 if (pDevice->uConnectionRate <= RATE_11M) { // CCK // Set the CR33 Bit2 to disable internal Loopback. - BBbReadEmbeded(dwIoBase, 0x21, &byData);//CR33 - BBbWriteEmbeded(dwIoBase, 0x21, (unsigned char)(byData & 0xFE));//CR33 + BBbReadEmbedded(dwIoBase, 0x21, &byData);//CR33 + BBbWriteEmbedded(dwIoBase, 0x21, (unsigned char)(byData & 0xFE));//CR33 } else { // OFDM - BBbReadEmbeded(dwIoBase, 0x9A, &byData);//CR154 - BBbWriteEmbeded(dwIoBase, 0x9A, (unsigned char)(byData & 0xFE));//CR154 + BBbReadEmbedded(dwIoBase, 0x9A, &byData);//CR154 + BBbWriteEmbedded(dwIoBase, 0x9A, (unsigned char)(byData & 0xFE));//CR154 } - BBbReadEmbeded(dwIoBase, 0x0E, &byData);//CR14 - BBbWriteEmbeded(dwIoBase, 0x0E, (unsigned char)(byData | 0x80));//CR14 + BBbReadEmbedded(dwIoBase, 0x0E, &byData);//CR14 + BBbWriteEmbedded(dwIoBase, 0x0E, (unsigned char)(byData | 0x80));//CR14 } @@ -2442,7 +2442,7 @@ BBvSetShortSlotTime (PSDevice pDevice) unsigned char byBBRxConf=0; unsigned char byBBVGA=0; - BBbReadEmbeded(pDevice->PortOffset, 0x0A, &byBBRxConf);//CR10 + BBbReadEmbedded(pDevice->PortOffset, 0x0A, &byBBRxConf);//CR10 if (pDevice->bShortSlotTime) { byBBRxConf &= 0xDF;//1101 1111 @@ -2451,12 +2451,12 @@ BBvSetShortSlotTime (PSDevice pDevice) } // patch for 3253B0 Baseband with Cardbus module - BBbReadEmbeded(pDevice->PortOffset, 0xE7, &byBBVGA); + BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byBBVGA); if (byBBVGA == pDevice->abyBBVGA[0]) { byBBRxConf |= 0x20;//0010 0000 } - BBbWriteEmbeded(pDevice->PortOffset, 0x0A, byBBRxConf);//CR10 + BBbWriteEmbedded(pDevice->PortOffset, 0x0A, byBBRxConf);//CR10 } @@ -2464,9 +2464,9 @@ void BBvSetVGAGainOffset(PSDevice pDevice, unsigned char byData) { unsigned char byBBRxConf=0; - BBbWriteEmbeded(pDevice->PortOffset, 0xE7, byData); + BBbWriteEmbedded(pDevice->PortOffset, 0xE7, byData); - BBbReadEmbeded(pDevice->PortOffset, 0x0A, &byBBRxConf);//CR10 + BBbReadEmbedded(pDevice->PortOffset, 0x0A, &byBBRxConf);//CR10 // patch for 3253B0 Baseband with Cardbus module if (byData == pDevice->abyBBVGA[0]) { byBBRxConf |= 0x20;//0010 0000 @@ -2476,7 +2476,7 @@ void BBvSetVGAGainOffset(PSDevice pDevice, unsigned char byData) byBBRxConf |= 0x20;//0010 0000 } pDevice->byBBVGACurrent = byData; - BBbWriteEmbeded(pDevice->PortOffset, 0x0A, byBBRxConf);//CR10 + BBbWriteEmbedded(pDevice->PortOffset, 0x0A, byBBRxConf);//CR10 } @@ -2495,10 +2495,10 @@ void BBvSetVGAGainOffset(PSDevice pDevice, unsigned char byData) void BBvSoftwareReset (unsigned long dwIoBase) { - BBbWriteEmbeded(dwIoBase, 0x50, 0x40); - BBbWriteEmbeded(dwIoBase, 0x50, 0); - BBbWriteEmbeded(dwIoBase, 0x9C, 0x01); - BBbWriteEmbeded(dwIoBase, 0x9C, 0); + BBbWriteEmbedded(dwIoBase, 0x50, 0x40); + BBbWriteEmbedded(dwIoBase, 0x50, 0); + BBbWriteEmbedded(dwIoBase, 0x9C, 0x01); + BBbWriteEmbedded(dwIoBase, 0x9C, 0); } /* @@ -2518,9 +2518,9 @@ BBvPowerSaveModeON (unsigned long dwIoBase) { unsigned char byOrgData; - BBbReadEmbeded(dwIoBase, 0x0D, &byOrgData); + BBbReadEmbedded(dwIoBase, 0x0D, &byOrgData); byOrgData |= BIT0; - BBbWriteEmbeded(dwIoBase, 0x0D, byOrgData); + BBbWriteEmbedded(dwIoBase, 0x0D, byOrgData); } /* @@ -2540,9 +2540,9 @@ BBvPowerSaveModeOFF (unsigned long dwIoBase) { unsigned char byOrgData; - BBbReadEmbeded(dwIoBase, 0x0D, &byOrgData); + BBbReadEmbedded(dwIoBase, 0x0D, &byOrgData); byOrgData &= ~(BIT0); - BBbWriteEmbeded(dwIoBase, 0x0D, byOrgData); + BBbWriteEmbedded(dwIoBase, 0x0D, byOrgData); } /* @@ -2567,7 +2567,7 @@ BBvSetTxAntennaMode (unsigned long dwIoBase, unsigned char byAntennaMode) #ifdef PLICE_DEBUG //printk("Enter BBvSetTxAntennaMode\n"); #endif - BBbReadEmbeded(dwIoBase, 0x09, &byBBTxConf);//CR09 + BBbReadEmbedded(dwIoBase, 0x09, &byBBTxConf);//CR09 if (byAntennaMode == ANT_DIVERSITY) { // bit 1 is diversity byBBTxConf |= 0x02; @@ -2581,7 +2581,7 @@ BBvSetTxAntennaMode (unsigned long dwIoBase, unsigned char byAntennaMode) byBBTxConf &= 0xFD; // 1111 1101 byBBTxConf |= 0x04; } - BBbWriteEmbeded(dwIoBase, 0x09, byBBTxConf);//CR09 + BBbWriteEmbedded(dwIoBase, 0x09, byBBTxConf);//CR09 } @@ -2606,7 +2606,7 @@ BBvSetRxAntennaMode (unsigned long dwIoBase, unsigned char byAntennaMode) { unsigned char byBBRxConf; - BBbReadEmbeded(dwIoBase, 0x0A, &byBBRxConf);//CR10 + BBbReadEmbedded(dwIoBase, 0x0A, &byBBRxConf);//CR10 if (byAntennaMode == ANT_DIVERSITY) { byBBRxConf |= 0x01; @@ -2616,7 +2616,7 @@ BBvSetRxAntennaMode (unsigned long dwIoBase, unsigned char byAntennaMode) byBBRxConf &= 0xFE; // 1111 1110 byBBRxConf |= 0x02; } - BBbWriteEmbeded(dwIoBase, 0x0A, byBBRxConf);//CR10 + BBbWriteEmbedded(dwIoBase, 0x0A, byBBRxConf);//CR10 } @@ -2635,15 +2635,15 @@ BBvSetRxAntennaMode (unsigned long dwIoBase, unsigned char byAntennaMode) void BBvSetDeepSleep (unsigned long dwIoBase, unsigned char byLocalID) { - BBbWriteEmbeded(dwIoBase, 0x0C, 0x17);//CR12 - BBbWriteEmbeded(dwIoBase, 0x0D, 0xB9);//CR13 + BBbWriteEmbedded(dwIoBase, 0x0C, 0x17);//CR12 + BBbWriteEmbedded(dwIoBase, 0x0D, 0xB9);//CR13 } void BBvExitDeepSleep (unsigned long dwIoBase, unsigned char byLocalID) { - BBbWriteEmbeded(dwIoBase, 0x0C, 0x00);//CR12 - BBbWriteEmbeded(dwIoBase, 0x0D, 0x01);//CR13 + BBbWriteEmbedded(dwIoBase, 0x0C, 0x00);//CR12 + BBbWriteEmbedded(dwIoBase, 0x0D, 0x01);//CR13 } diff --git a/drivers/staging/vt6655/baseband.h b/drivers/staging/vt6655/baseband.h index be2d68909490..9b5bc9c58d9f 100644 --- a/drivers/staging/vt6655/baseband.h +++ b/drivers/staging/vt6655/baseband.h @@ -73,12 +73,12 @@ #define BBvClearFOE(dwIoBase) \ { \ - BBbWriteEmbeded(dwIoBase, 0xB1, 0); \ + BBbWriteEmbedded(dwIoBase, 0xB1, 0); \ } #define BBvSetFOE(dwIoBase) \ { \ - BBbWriteEmbeded(dwIoBase, 0xB1, 0x0C); \ + BBbWriteEmbedded(dwIoBase, 0xB1, 0x0C); \ } @@ -97,7 +97,7 @@ BBuGetFrameTime( ); void -BBvCaculateParameter ( +BBvCalculateParameter ( PSDevice pDevice, unsigned int cbFrameLength, unsigned short wRate, @@ -107,8 +107,8 @@ BBvCaculateParameter ( unsigned char *pbyPhySgn ); -bool BBbReadEmbeded(unsigned long dwIoBase, unsigned char byBBAddr, unsigned char *pbyData); -bool BBbWriteEmbeded(unsigned long dwIoBase, unsigned char byBBAddr, unsigned char byData); +bool BBbReadEmbedded(unsigned long dwIoBase, unsigned char byBBAddr, unsigned char *pbyData); +bool BBbWriteEmbedded(unsigned long dwIoBase, unsigned char byBBAddr, unsigned char byData); void BBvReadAllRegs(unsigned long dwIoBase, unsigned char *pbyBBRegs); void BBvLoopbackOn(PSDevice pDevice); diff --git a/drivers/staging/vt6655/bssdb.c b/drivers/staging/vt6655/bssdb.c index fcffa4f0f4e3..fe57fb880a8f 100644 --- a/drivers/staging/vt6655/bssdb.c +++ b/drivers/staging/vt6655/bssdb.c @@ -784,8 +784,8 @@ BSSDBbIsSTAInNodeDB(void *pMgmtObject, unsigned char *abyDstAddr, /*+ * * Routine Description: - * Find an empty node and allocated; if no empty found, - * instand used of most inactive one. + * Find an empty node and allocat it; if there is no empty node, + * then use the most inactive one. * * Return Value: * None diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c index 2721e0798496..319ca482f003 100644 --- a/drivers/staging/vt6655/card.c +++ b/drivers/staging/vt6655/card.c @@ -28,9 +28,9 @@ * CARDbIsOFDMinBasicRate - Check if any OFDM rate is in BasicRateSet * CARDvSetLoopbackMode - Set Loopback mode * CARDbSoftwareReset - Sortware reset NIC - * CARDqGetTSFOffset - Caculate TSFOffset + * CARDqGetTSFOffset - Calculate TSFOffset * CARDbGetCurrentTSF - Read Current NIC TSF counter - * CARDqGetNextTBTT - Caculate Next Beacon TSF counter + * CARDqGetNextTBTT - Calculate Next Beacon TSF counter * CARDvSetFirstNextTBTT - Set NIC Beacon time * CARDvUpdateNextTBTT - Sync. NIC Beacon time * CARDbRadioPowerOff - Turn Off NIC Radio Power @@ -100,7 +100,7 @@ const unsigned short cwRXBCNTSFOff[MAX_RATE] = static void -s_vCaculateOFDMRParameter( +s_vCalculateOFDMRParameter( unsigned char byRate, CARD_PHY_TYPE ePHYType, unsigned char *pbyTxRate, @@ -111,7 +111,7 @@ s_vCaculateOFDMRParameter( /*--------------------- Export Functions --------------------------*/ /* - * Description: Caculate TxRate and RsvTime fields for RSPINF in OFDM mode. + * Description: Calculate TxRate and RsvTime fields for RSPINF in OFDM mode. * * Parameters: * In: @@ -126,7 +126,7 @@ s_vCaculateOFDMRParameter( */ static void -s_vCaculateOFDMRParameter ( +s_vCalculateOFDMRParameter ( unsigned char byRate, CARD_PHY_TYPE ePHYType, unsigned char *pbyTxRate, @@ -251,7 +251,7 @@ s_vSetRSPINF (PSDevice pDevice, CARD_PHY_TYPE ePHYType, void *pvSupportRateIEs, MACvSelectPage1(pDevice->PortOffset); //RSPINF_b_1 - BBvCaculateParameter(pDevice, + BBvCalculateParameter(pDevice, 14, VNTWIFIbyGetACKTxRate(RATE_1M, pvSupportRateIEs, pvExtSupportRateIEs), PK_TYPE_11B, @@ -262,7 +262,7 @@ s_vSetRSPINF (PSDevice pDevice, CARD_PHY_TYPE ePHYType, void *pvSupportRateIEs, VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_1, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ))); ///RSPINF_b_2 - BBvCaculateParameter(pDevice, + BBvCalculateParameter(pDevice, 14, VNTWIFIbyGetACKTxRate(RATE_2M, pvSupportRateIEs, pvExtSupportRateIEs), PK_TYPE_11B, @@ -273,7 +273,7 @@ s_vSetRSPINF (PSDevice pDevice, CARD_PHY_TYPE ePHYType, void *pvSupportRateIEs, VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_2, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ))); //RSPINF_b_5 - BBvCaculateParameter(pDevice, + BBvCalculateParameter(pDevice, 14, VNTWIFIbyGetACKTxRate(RATE_5M, pvSupportRateIEs, pvExtSupportRateIEs), PK_TYPE_11B, @@ -284,7 +284,7 @@ s_vSetRSPINF (PSDevice pDevice, CARD_PHY_TYPE ePHYType, void *pvSupportRateIEs, VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_5, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ))); //RSPINF_b_11 - BBvCaculateParameter(pDevice, + BBvCalculateParameter(pDevice, 14, VNTWIFIbyGetACKTxRate(RATE_11M, pvSupportRateIEs, pvExtSupportRateIEs), PK_TYPE_11B, @@ -295,51 +295,51 @@ s_vSetRSPINF (PSDevice pDevice, CARD_PHY_TYPE ePHYType, void *pvSupportRateIEs, VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_11, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ))); //RSPINF_a_6 - s_vCaculateOFDMRParameter(RATE_6M, + s_vCalculateOFDMRParameter(RATE_6M, ePHYType, &byTxRate, &byRsvTime); VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_6, MAKEWORD(byTxRate,byRsvTime)); //RSPINF_a_9 - s_vCaculateOFDMRParameter(RATE_9M, + s_vCalculateOFDMRParameter(RATE_9M, ePHYType, &byTxRate, &byRsvTime); VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_9, MAKEWORD(byTxRate,byRsvTime)); //RSPINF_a_12 - s_vCaculateOFDMRParameter(RATE_12M, + s_vCalculateOFDMRParameter(RATE_12M, ePHYType, &byTxRate, &byRsvTime); VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_12, MAKEWORD(byTxRate,byRsvTime)); //RSPINF_a_18 - s_vCaculateOFDMRParameter(RATE_18M, + s_vCalculateOFDMRParameter(RATE_18M, ePHYType, &byTxRate, &byRsvTime); VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_18, MAKEWORD(byTxRate,byRsvTime)); //RSPINF_a_24 - s_vCaculateOFDMRParameter(RATE_24M, + s_vCalculateOFDMRParameter(RATE_24M, ePHYType, &byTxRate, &byRsvTime); VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_24, MAKEWORD(byTxRate,byRsvTime)); //RSPINF_a_36 - s_vCaculateOFDMRParameter( + s_vCalculateOFDMRParameter( VNTWIFIbyGetACKTxRate(RATE_36M, pvSupportRateIEs, pvExtSupportRateIEs), ePHYType, &byTxRate, &byRsvTime); VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_36, MAKEWORD(byTxRate,byRsvTime)); //RSPINF_a_48 - s_vCaculateOFDMRParameter( + s_vCalculateOFDMRParameter( VNTWIFIbyGetACKTxRate(RATE_48M, pvSupportRateIEs, pvExtSupportRateIEs), ePHYType, &byTxRate, &byRsvTime); VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_48, MAKEWORD(byTxRate,byRsvTime)); //RSPINF_a_54 - s_vCaculateOFDMRParameter( + s_vCalculateOFDMRParameter( VNTWIFIbyGetACKTxRate(RATE_54M, pvSupportRateIEs, pvExtSupportRateIEs), ePHYType, &byTxRate, @@ -461,22 +461,22 @@ bool CARDbSetPhyParameter (void *pDeviceHandler, CARD_PHY_TYPE ePHYType, unsigne pDevice->abyBBVGA[0] = 0x20; pDevice->abyBBVGA[2] = 0x10; pDevice->abyBBVGA[3] = 0x10; - BBbReadEmbeded(pDevice->PortOffset, 0xE7, &byData); + BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData); if (byData == 0x1C) { - BBbWriteEmbeded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]); + BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]); } } else if (pDevice->byRFType == RF_UW2452) { MACvSetBBType(pDevice->PortOffset, BB_TYPE_11A); pDevice->abyBBVGA[0] = 0x18; - BBbReadEmbeded(pDevice->PortOffset, 0xE7, &byData); + BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData); if (byData == 0x14) { - BBbWriteEmbeded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]); - BBbWriteEmbeded(pDevice->PortOffset, 0xE1, 0x57); + BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]); + BBbWriteEmbedded(pDevice->PortOffset, 0xE1, 0x57); } } else { MACvSetBBType(pDevice->PortOffset, BB_TYPE_11A); } - BBbWriteEmbeded(pDevice->PortOffset, 0x88, 0x03); + BBbWriteEmbedded(pDevice->PortOffset, 0x88, 0x03); bySlot = C_SLOT_SHORT; bySIFS = C_SIFS_A; byDIFS = C_SIFS_A + 2*C_SLOT_SHORT; @@ -490,19 +490,19 @@ bool CARDbSetPhyParameter (void *pDeviceHandler, CARD_PHY_TYPE ePHYType, unsigne pDevice->abyBBVGA[0] = 0x1C; pDevice->abyBBVGA[2] = 0x00; pDevice->abyBBVGA[3] = 0x00; - BBbReadEmbeded(pDevice->PortOffset, 0xE7, &byData); + BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData); if (byData == 0x20) { - BBbWriteEmbeded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]); + BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]); } } else if (pDevice->byRFType == RF_UW2452) { pDevice->abyBBVGA[0] = 0x14; - BBbReadEmbeded(pDevice->PortOffset, 0xE7, &byData); + BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData); if (byData == 0x18) { - BBbWriteEmbeded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]); - BBbWriteEmbeded(pDevice->PortOffset, 0xE1, 0xD3); + BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]); + BBbWriteEmbedded(pDevice->PortOffset, 0xE1, 0xD3); } } - BBbWriteEmbeded(pDevice->PortOffset, 0x88, 0x02); + BBbWriteEmbedded(pDevice->PortOffset, 0x88, 0x02); bySlot = C_SLOT_LONG; bySIFS = C_SIFS_BG; byDIFS = C_SIFS_BG + 2*C_SLOT_LONG; @@ -517,19 +517,19 @@ bool CARDbSetPhyParameter (void *pDeviceHandler, CARD_PHY_TYPE ePHYType, unsigne pDevice->abyBBVGA[0] = 0x1C; pDevice->abyBBVGA[2] = 0x00; pDevice->abyBBVGA[3] = 0x00; - BBbReadEmbeded(pDevice->PortOffset, 0xE7, &byData); + BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData); if (byData == 0x20) { - BBbWriteEmbeded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]); + BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]); } } else if (pDevice->byRFType == RF_UW2452) { pDevice->abyBBVGA[0] = 0x14; - BBbReadEmbeded(pDevice->PortOffset, 0xE7, &byData); + BBbReadEmbedded(pDevice->PortOffset, 0xE7, &byData); if (byData == 0x18) { - BBbWriteEmbeded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]); - BBbWriteEmbeded(pDevice->PortOffset, 0xE1, 0xD3); + BBbWriteEmbedded(pDevice->PortOffset, 0xE7, pDevice->abyBBVGA[0]); + BBbWriteEmbedded(pDevice->PortOffset, 0xE1, 0xD3); } } - BBbWriteEmbeded(pDevice->PortOffset, 0x88, 0x08); + BBbWriteEmbedded(pDevice->PortOffset, 0x88, 0x08); bySIFS = C_SIFS_BG; if(VNTWIFIbIsShortSlotTime(wCapInfo)) { bySlot = C_SLOT_SHORT; @@ -1354,7 +1354,8 @@ CARDbSetQuiet ( /* * * Description: - * Do Quiet, It will called by either ISR (after start) or VNTWIFI (before start) so do not need SPINLOCK + * Do Quiet, It will be called by either ISR(after start) + * or VNTWIFI(before start) so we do not need a SPINLOCK * * Parameters: * In: @@ -1738,7 +1739,7 @@ void CARDvSetRSPINF (void *pDeviceHandler, CARD_PHY_TYPE ePHYType) MACvSelectPage1(pDevice->PortOffset); //RSPINF_b_1 - BBvCaculateParameter(pDevice, + BBvCalculateParameter(pDevice, 14, CARDwGetCCKControlRate((void *)pDevice, RATE_1M), PK_TYPE_11B, @@ -1749,7 +1750,7 @@ void CARDvSetRSPINF (void *pDeviceHandler, CARD_PHY_TYPE ePHYType) VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_1, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ))); ///RSPINF_b_2 - BBvCaculateParameter(pDevice, + BBvCalculateParameter(pDevice, 14, CARDwGetCCKControlRate((void *)pDevice, RATE_2M), PK_TYPE_11B, @@ -1760,7 +1761,7 @@ void CARDvSetRSPINF (void *pDeviceHandler, CARD_PHY_TYPE ePHYType) VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_2, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ))); //RSPINF_b_5 - BBvCaculateParameter(pDevice, + BBvCalculateParameter(pDevice, 14, CARDwGetCCKControlRate((void *)pDevice, RATE_5M), PK_TYPE_11B, @@ -1771,7 +1772,7 @@ void CARDvSetRSPINF (void *pDeviceHandler, CARD_PHY_TYPE ePHYType) VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_5, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ))); //RSPINF_b_11 - BBvCaculateParameter(pDevice, + BBvCalculateParameter(pDevice, 14, CARDwGetCCKControlRate((void *)pDevice, RATE_11M), PK_TYPE_11B, @@ -1782,56 +1783,56 @@ void CARDvSetRSPINF (void *pDeviceHandler, CARD_PHY_TYPE ePHYType) VNSvOutPortD(pDevice->PortOffset + MAC_REG_RSPINF_B_11, MAKEDWORD(wLen,MAKEWORD(bySignal,byServ))); //RSPINF_a_6 - s_vCaculateOFDMRParameter(RATE_6M, + s_vCalculateOFDMRParameter(RATE_6M, ePHYType, &byTxRate, &byRsvTime); VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_6, MAKEWORD(byTxRate,byRsvTime)); //RSPINF_a_9 - s_vCaculateOFDMRParameter(RATE_9M, + s_vCalculateOFDMRParameter(RATE_9M, ePHYType, &byTxRate, &byRsvTime); VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_9, MAKEWORD(byTxRate,byRsvTime)); //RSPINF_a_12 - s_vCaculateOFDMRParameter(RATE_12M, + s_vCalculateOFDMRParameter(RATE_12M, ePHYType, &byTxRate, &byRsvTime); VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_12, MAKEWORD(byTxRate,byRsvTime)); //RSPINF_a_18 - s_vCaculateOFDMRParameter(RATE_18M, + s_vCalculateOFDMRParameter(RATE_18M, ePHYType, &byTxRate, &byRsvTime); VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_18, MAKEWORD(byTxRate,byRsvTime)); //RSPINF_a_24 - s_vCaculateOFDMRParameter(RATE_24M, + s_vCalculateOFDMRParameter(RATE_24M, ePHYType, &byTxRate, &byRsvTime); VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_24, MAKEWORD(byTxRate,byRsvTime)); //RSPINF_a_36 - s_vCaculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_36M), + s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_36M), ePHYType, &byTxRate, &byRsvTime); VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_36, MAKEWORD(byTxRate,byRsvTime)); //RSPINF_a_48 - s_vCaculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_48M), + s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_48M), ePHYType, &byTxRate, &byRsvTime); VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_48, MAKEWORD(byTxRate,byRsvTime)); //RSPINF_a_54 - s_vCaculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_54M), + s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_54M), ePHYType, &byTxRate, &byRsvTime); VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_54, MAKEWORD(byTxRate,byRsvTime)); //RSPINF_a_72 - s_vCaculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_54M), + s_vCalculateOFDMRParameter(CARDwGetOFDMControlRate((void *)pDevice, RATE_54M), ePHYType, &byTxRate, &byRsvTime); @@ -2041,7 +2042,7 @@ bool CARDbSoftwareReset (void *pDeviceHandler) /* - * Description: Caculate TSF offset of two TSF input + * Description: Calculate TSF offset of two TSF input * Get TSF Offset from RxBCN's TSF and local TSF * * Parameters: diff --git a/drivers/staging/vt6655/datarate.c b/drivers/staging/vt6655/datarate.c index efbb8f45f728..b86ec1b6d187 100644 --- a/drivers/staging/vt6655/datarate.c +++ b/drivers/staging/vt6655/datarate.c @@ -126,7 +126,7 @@ DATARATEbyGetRateIdx ( /*+ * * Routine Description: - * Rate fallback Algorithm Implementaion + * Rate fallback Algorithm Implementation * * Parameters: * In: diff --git a/drivers/staging/vt6655/device.h b/drivers/staging/vt6655/device.h index c5e6b98d3e4e..e54e00bc5665 100644 --- a/drivers/staging/vt6655/device.h +++ b/drivers/staging/vt6655/device.h @@ -327,7 +327,7 @@ typedef struct tagSDeFragControlBlock //flags for driver status #define DEVICE_FLAGS_OPENED 0x00010000UL #define DEVICE_FLAGS_WOL_ENABLED 0x00080000UL -//flags for capbilities +//flags for capabilities #define DEVICE_FLAGS_TX_ALIGN 0x01000000UL #define DEVICE_FLAGS_HAVE_CAM 0x02000000UL #define DEVICE_FLAGS_FLOW_CTRL 0x04000000UL @@ -567,7 +567,7 @@ typedef struct __device_info { bool bPrvActive4RadioOFF; bool bGPIOBlockRead; - // Beacon releated + // Beacon related unsigned short wSeqCounter; unsigned short wBCNBufLen; bool bBeaconBufReady; diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c index 89d1c22695a0..9e3b3f2bbe53 100644 --- a/drivers/staging/vt6655/device_main.c +++ b/drivers/staging/vt6655/device_main.c @@ -290,7 +290,7 @@ DEFINE_PCI_DEVICE_TABLE(vt6655_pci_id_table) = { static int vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent); -static bool vt6655_init_info(struct pci_dev* pcid, PSDevice* ppDevice, PCHIP_INFO); +static void vt6655_init_info(struct pci_dev* pcid, PSDevice* ppDevice, PCHIP_INFO); static void device_free_info(PSDevice pDevice); static bool device_get_pci_info(PSDevice, struct pci_dev* pcid); static void device_print_info(PSDevice pDevice); @@ -347,21 +347,22 @@ static int Config_FileGetParameter(unsigned char *string, -static char* get_chip_name(int chip_id) { - int i; - for (i=0;chip_info_table[i].name!=NULL;i++) - if (chip_info_table[i].chip_id==chip_id) - break; - return chip_info_table[i].name; +static char* get_chip_name(int chip_id) +{ + int i; + for (i = 0; chip_info_table[i].name != NULL; i++) + if (chip_info_table[i].chip_id == chip_id) + break; + return chip_info_table[i].name; } static void __devexit vt6655_remove(struct pci_dev *pcid) { - PSDevice pDevice=pci_get_drvdata(pcid); + PSDevice pDevice = pci_get_drvdata(pcid); - if (pDevice==NULL) - return; - device_free_info(pDevice); + if (pDevice == NULL) + return; + device_free_info(pDevice); } @@ -397,31 +398,29 @@ device_set_bool_opt(unsigned int *opt, int val,bool def,u32 flag, char* name,cha } } */ -static void -device_get_options(PSDevice pDevice, int index, char* devname) { - - POPTIONS pOpts = &(pDevice->sOpts); - pOpts->nRxDescs0=RX_DESC_DEF0; - pOpts->nRxDescs1=RX_DESC_DEF1; - pOpts->nTxDescs[0]=TX_DESC_DEF0; - pOpts->nTxDescs[1]=TX_DESC_DEF1; -pOpts->flags|=DEVICE_FLAGS_IP_ALIGN; - pOpts->int_works=INT_WORKS_DEF; - pOpts->rts_thresh=RTS_THRESH_DEF; - pOpts->frag_thresh=FRAG_THRESH_DEF; - pOpts->data_rate=DATA_RATE_DEF; - pOpts->channel_num=CHANNEL_DEF; - -pOpts->flags|=DEVICE_FLAGS_PREAMBLE_TYPE; -pOpts->flags|=DEVICE_FLAGS_OP_MODE; -//pOpts->flags|=DEVICE_FLAGS_PS_MODE; - pOpts->short_retry=SHORT_RETRY_DEF; - pOpts->long_retry=LONG_RETRY_DEF; - pOpts->bbp_type=BBP_TYPE_DEF; -pOpts->flags|=DEVICE_FLAGS_80211h_MODE; -pOpts->flags|=DEVICE_FLAGS_DiversityANT; - - +static void device_get_options(PSDevice pDevice, int index, char* devname) +{ + POPTIONS pOpts = &(pDevice->sOpts); + + pOpts->nRxDescs0 = RX_DESC_DEF0; + pOpts->nRxDescs1 = RX_DESC_DEF1; + pOpts->nTxDescs[0] = TX_DESC_DEF0; + pOpts->nTxDescs[1] = TX_DESC_DEF1; + pOpts->flags |= DEVICE_FLAGS_IP_ALIGN; + pOpts->int_works = INT_WORKS_DEF; + pOpts->rts_thresh = RTS_THRESH_DEF; + pOpts->frag_thresh = FRAG_THRESH_DEF; + pOpts->data_rate = DATA_RATE_DEF; + pOpts->channel_num = CHANNEL_DEF; + + pOpts->flags |= DEVICE_FLAGS_PREAMBLE_TYPE; + pOpts->flags |= DEVICE_FLAGS_OP_MODE; + //pOpts->flags|=DEVICE_FLAGS_PS_MODE; + pOpts->short_retry = SHORT_RETRY_DEF; + pOpts->long_retry = LONG_RETRY_DEF; + pOpts->bbp_type = BBP_TYPE_DEF; + pOpts->flags |= DEVICE_FLAGS_80211h_MODE; + pOpts->flags |= DEVICE_FLAGS_DiversityANT; } static void @@ -518,7 +517,7 @@ static void s_vCompleteCurrentMeasure (PSDevice pDevice, unsigned char byResult) // -// Initialiation of MAC & BBP registers +// Initialisation of MAC & BBP registers // static void device_init_registers(PSDevice pDevice, DEVICE_INIT_TYPE InitType) @@ -894,18 +893,15 @@ static bool device_release_WPADEV(PSDevice pDevice) return true; } - static const struct net_device_ops device_netdev_ops = { - .ndo_open = device_open, - .ndo_stop = device_close, - .ndo_do_ioctl = device_ioctl, - .ndo_get_stats = device_get_stats, - .ndo_start_xmit = device_xmit, - .ndo_set_rx_mode = device_set_multi, + .ndo_open = device_open, + .ndo_stop = device_close, + .ndo_do_ioctl = device_ioctl, + .ndo_get_stats = device_get_stats, + .ndo_start_xmit = device_xmit, + .ndo_set_rx_mode = device_set_multi, }; - - static int __devinit vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent) { @@ -926,7 +922,7 @@ vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent) if (dev == NULL) { printk(KERN_ERR DEVICE_NAME ": allocate net device failed \n"); - return -ENODEV; + return -ENOMEM; } // Chain it all together @@ -939,9 +935,7 @@ vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent) bFirst=false; } - if (!vt6655_init_info(pcid, &pDevice, pChip_info)) { - return -ENOMEM; - } + vt6655_init_info(pcid, &pDevice, pChip_info); pDevice->dev = dev; pDevice->next_module = root_device_dev; root_device_dev = dev; @@ -1064,7 +1058,7 @@ vt6655_probe(struct pci_dev *pcid, const struct pci_device_id *ent) //Mask out the options cannot be set to the chip pDevice->sOpts.flags &= pChip_info->flags; - //Enable the chip specified capbilities + //Enable the chip specified capabilities pDevice->flags = pDevice->sOpts.flags | (pChip_info->flags & 0xFF000000UL); pDevice->tx_80211 = device_dma0_tx_80211; pDevice->sMgmtObj.pAdapter = (void *)pDevice; @@ -1105,7 +1099,7 @@ static void device_print_info(PSDevice pDevice) } -static bool __devinit vt6655_init_info(struct pci_dev* pcid, PSDevice* ppDevice, +static void __devinit vt6655_init_info(struct pci_dev* pcid, PSDevice* ppDevice, PCHIP_INFO pChip_info) { PSDevice p; @@ -1129,8 +1123,6 @@ static bool __devinit vt6655_init_info(struct pci_dev* pcid, PSDevice* ppDevice, (*ppDevice)->multicast_limit =32; spin_lock_init(&((*ppDevice)->lock)); - - return true; } static bool device_get_pci_info(PSDevice pDevice, struct pci_dev* pcid) { @@ -1678,7 +1670,7 @@ static int device_tx_srv(PSDevice pDevice, unsigned int uIdx) { uFrameSize = pTD->pTDInfo->dwReqCount - uFIFOHeaderSize; pTxBufHead = (PSTxBufHead) (pTD->pTDInfo->buf); // Update the statistics based on the Transmit status - // now, we DO'NT check TSR0_CDH + // now, we DONT check TSR0_CDH STAvUpdateTDStatCounter(&pDevice->scStatistic, byTsr0, byTsr1, @@ -2660,7 +2652,7 @@ static irqreturn_t device_intr(int irq, void *dev_instance) { (pDevice->byLocalID != REV_ID_VT3253_B0) && (pDevice->bBSSIDFilter == true)) { // update RSSI - //BBbReadEmbeded(pDevice->PortOffset, 0x3E, &byRSSI); + //BBbReadEmbedded(pDevice->PortOffset, 0x3E, &byRSSI); //pDevice->uCurrRSSI = byRSSI; } */ diff --git a/drivers/staging/vt6655/dpc.c b/drivers/staging/vt6655/dpc.c index e8a71ba4b92c..373e9e4fc87d 100644 --- a/drivers/staging/vt6655/dpc.c +++ b/drivers/staging/vt6655/dpc.c @@ -718,7 +718,7 @@ device_receive_frame ( if ((*pbyRSSI != 0) && (pMgmt->pCurrBSS!=NULL)) { RFvRSSITodBm(pDevice, *pbyRSSI, &ldBm); - // Moniter if RSSI is too strong. + // Monitor if RSSI is too strong. pMgmt->pCurrBSS->byRSSIStatCnt++; pMgmt->pCurrBSS->byRSSIStatCnt %= RSSI_STAT_COUNT; pMgmt->pCurrBSS->ldBmAverage[pMgmt->pCurrBSS->byRSSIStatCnt] = ldBm; diff --git a/drivers/staging/vt6655/hostap.c b/drivers/staging/vt6655/hostap.c index 6ac6f452b261..67b1b88b1b89 100644 --- a/drivers/staging/vt6655/hostap.c +++ b/drivers/staging/vt6655/hostap.c @@ -495,9 +495,7 @@ static int hostap_set_encryption(PSDevice pDevice, return -EINVAL; } - if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && - param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && - param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { + if (is_broadcast_ether_addr(param->sta_addr)) { if (param->u.crypt.idx >= MAX_GROUP_KEY) return -EINVAL; iNodeIndex = 0; @@ -716,9 +714,7 @@ static int hostap_get_encryption(PSDevice pDevice, param->u.crypt.err = 0; - if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && - param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && - param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { + if (is_broadcast_ether_addr(param->sta_addr)) { iNodeIndex = 0; } else { if (BSSDBbIsSTAInNodeDB(pMgmt, param->sta_addr, &iNodeIndex) == false) { diff --git a/drivers/staging/vt6655/ioctl.c b/drivers/staging/vt6655/ioctl.c index ef197efab049..afed6e33dfc7 100644 --- a/drivers/staging/vt6655/ioctl.c +++ b/drivers/staging/vt6655/ioctl.c @@ -111,7 +111,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) break; case WLAN_CMD_ZONETYPE_SET: - /* mike add :cann't support. */ + /* mike add :can't support. */ result = -EOPNOTSUPP; break; @@ -539,11 +539,8 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) pMgmt->abyIBSSSuppRates[3] |= BIT7; } - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Support Rate= %x %x %x %x\n", - pMgmt->abyIBSSSuppRates[2], - pMgmt->abyIBSSSuppRates[3], - pMgmt->abyIBSSSuppRates[4], - pMgmt->abyIBSSSuppRates[5]); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Support Rate= %*ph\n", + 4, pMgmt->abyIBSSSuppRates + 2); netif_stop_queue(pDevice->dev); spin_lock_irq(&pDevice->lock); diff --git a/drivers/staging/vt6655/iwctl.c b/drivers/staging/vt6655/iwctl.c index 77aad7f5ae76..5cdda8dab854 100644 --- a/drivers/staging/vt6655/iwctl.c +++ b/drivers/staging/vt6655/iwctl.c @@ -358,7 +358,7 @@ int iwctl_giwscan(struct net_device *dev, /* - * Wireless Handler : set frequence or channel + * Wireless Handler : set frequency or channel */ int iwctl_siwfreq(struct net_device *dev, @@ -404,7 +404,7 @@ int iwctl_siwfreq(struct net_device *dev, } /* - * Wireless Handler : get frequence or channel + * Wireless Handler : get frequency or channel */ int iwctl_giwfreq(struct net_device *dev, @@ -1346,7 +1346,7 @@ if((wrq->flags & IW_ENCODE_DISABLED)==0){ }else if(index>0){ //when the length is 0 the request only changes the default transmit key index - //check the new key has a non zero lenget + //check the new key if it has a non zero length if(pDevice->bEncryptionEnable==false) { rc = -EINVAL; diff --git a/drivers/staging/vt6655/key.c b/drivers/staging/vt6655/key.c index 774b0d4a7e06..194fedc715fa 100644 --- a/drivers/staging/vt6655/key.c +++ b/drivers/staging/vt6655/key.c @@ -372,7 +372,7 @@ bool KeybRemoveKey ( int i; if (is_broadcast_ether_addr(pbyBSSID)) { - // dealte all key + // delete all keys if ((dwKeyIndex & PAIRWISE_KEY) != 0) { for (i=0;i<MAX_KEY_TABLE;i++) { pTable->KeyTable[i].PairwiseKey.bKeyValid = false; diff --git a/drivers/staging/vt6655/mac.c b/drivers/staging/vt6655/mac.c index f8d1651341f8..30c261579412 100644 --- a/drivers/staging/vt6655/mac.c +++ b/drivers/staging/vt6655/mac.c @@ -56,9 +56,9 @@ * MACbSafeStop - Stop MAC function * MACbShutdown - Shut down MAC * MACvInitialize - Initialize MAC - * MACvSetCurrRxDescAddr - Set Rx Descriptos Address - * MACvSetCurrTx0DescAddr - Set Tx0 Descriptos Address - * MACvSetCurrTx1DescAddr - Set Tx1 Descriptos Address + * MACvSetCurrRxDescAddr - Set Rx Descriptors Address + * MACvSetCurrTx0DescAddr - Set Tx0 Descriptors Address + * MACvSetCurrTx1DescAddr - Set Tx1 Descriptors Address * MACvTimer0MicroSDelay - Micro Second Delay Loop by MAC * * Revision History: @@ -1498,7 +1498,7 @@ int ii; wOffset += (uKeyIdx * 4); for (ii=0;ii<4;ii++) { - // alway push 128 bits + // always push 128 bits DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"3.(%d) wOffset: %d, Data: %lX\n", ii, wOffset+ii, *pdwKey); VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset+ii); VNSvOutPortD(dwIoBase + MAC_REG_MISCFFDATA, *pdwKey++); @@ -1567,7 +1567,7 @@ int ii; wOffset++; wOffset++; wOffset += (uKeyIdx * 4); - // alway push 128 bits + // always push 128 bits for (ii=0; ii<3; ii++) { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"(%d) wOffset: %d, Data: %lX\n", ii, wOffset+ii, *pdwKey); VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset+ii); @@ -1696,7 +1696,7 @@ int ii; wOffset += (uKeyIdx * 4); DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"1. wOffset: %d, Data: %lX, idx:%d\n", wOffset, *pdwKey, uKeyIdx); - // alway push 128 bits + // always push 128 bits for (ii=0; ii<4; ii++) { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"2.(%d) wOffset: %d, Data: %lX\n", ii, wOffset+ii, *pdwKey); VNSvOutPortW(dwIoBase + MAC_REG_MISCFFNDEX, wOffset+ii); diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h index e3ccfee90268..adfb366f4901 100644 --- a/drivers/staging/vt6655/mac.h +++ b/drivers/staging/vt6655/mac.h @@ -586,7 +586,7 @@ #define PKT_TYPE_NONE 0x00 // turn off receiver #define PKT_TYPE_ALL_MULTICAST 0x80 #define PKT_TYPE_PROMISCUOUS 0x40 -#define PKT_TYPE_DIRECTED 0x20 // obselete, directed address is always accepted +#define PKT_TYPE_DIRECTED 0x20 // obsolete, directed address is always accepted #define PKT_TYPE_BROADCAST 0x10 #define PKT_TYPE_MULTICAST 0x08 #define PKT_TYPE_ERROR_WPA 0x04 diff --git a/drivers/staging/vt6655/mib.c b/drivers/staging/vt6655/mib.c index 1b91a8370954..63ae4adddf2f 100644 --- a/drivers/staging/vt6655/mib.c +++ b/drivers/staging/vt6655/mib.c @@ -191,7 +191,7 @@ void STAvUpdateRDStatCounter (PSStatCounter pStatistic, pStatistic->ullRsrOK++; if (cbFrameLength >= ETH_ALEN) { - // update counters in case that successful transmit + // update counters in case of successful transmit if (byRSR & RSR_ADDRBROAD) { pStatistic->ullRxBroadcastFrames++; pStatistic->ullRxBroadcastBytes += (unsigned long long) cbFrameLength; diff --git a/drivers/staging/vt6655/power.c b/drivers/staging/vt6655/power.c index 4c0b02e8f0b5..661d534304cc 100644 --- a/drivers/staging/vt6655/power.c +++ b/drivers/staging/vt6655/power.c @@ -207,7 +207,7 @@ PSbConsiderPowerDown( if (pDevice->bCmdRunning) return false; - // Froce PSEN on + // Force PSEN on MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PSEN); // check if all TD are empty, diff --git a/drivers/staging/vt6655/rf.c b/drivers/staging/vt6655/rf.c index aa696650b86c..aaa231aaf4e9 100644 --- a/drivers/staging/vt6655/rf.c +++ b/drivers/staging/vt6655/rf.c @@ -26,7 +26,7 @@ * Date: Feb. 19, 2004 * * Functions: - * IFRFbWriteEmbeded - Embeded write RF register via MAC + * IFRFbWriteEmbedded - Embedded write RF register via MAC * * Revision History: * @@ -453,18 +453,18 @@ bool s_bAL7230Init (unsigned long dwIoBase) BBvPowerSaveModeOFF(dwIoBase); //RobertYu:20050106, have DC value for Calibration for (ii = 0; ii < CB_AL7230_INIT_SEQ; ii++) - bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[ii]); + bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[ii]); // PLL On MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3); //Calibration MACvTimer0MicroSDelay(dwIoBase, 150);//150us - bResult &= IFRFbWriteEmbeded(dwIoBase, (0x9ABA8F00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW)); //TXDCOC:active, RCK:diable + bResult &= IFRFbWriteEmbedded(dwIoBase, (0x9ABA8F00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW)); //TXDCOC:active, RCK:disable MACvTimer0MicroSDelay(dwIoBase, 30);//30us - bResult &= IFRFbWriteEmbeded(dwIoBase, (0x3ABA8F00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW)); //TXDCOC:diable, RCK:active + bResult &= IFRFbWriteEmbedded(dwIoBase, (0x3ABA8F00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW)); //TXDCOC:disable, RCK:active MACvTimer0MicroSDelay(dwIoBase, 30);//30us - bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[CB_AL7230_INIT_SEQ-1]); //TXDCOC:diable, RCK:diable + bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[CB_AL7230_INIT_SEQ-1]); //TXDCOC:disable, RCK:disable MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPE3 | SOFTPWRCTL_SWPE2 | @@ -490,9 +490,9 @@ bool s_bAL7230SelectChannel (unsigned long dwIoBase, unsigned char byChannel) // PLLON Off MACvWordRegBitsOff(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3); - bResult &= IFRFbWriteEmbeded (dwIoBase, dwAL7230ChannelTable0[byChannel-1]); //Reg0 - bResult &= IFRFbWriteEmbeded (dwIoBase, dwAL7230ChannelTable1[byChannel-1]); //Reg1 - bResult &= IFRFbWriteEmbeded (dwIoBase, dwAL7230ChannelTable2[byChannel-1]); //Reg4 + bResult &= IFRFbWriteEmbedded (dwIoBase, dwAL7230ChannelTable0[byChannel-1]); //Reg0 + bResult &= IFRFbWriteEmbedded (dwIoBase, dwAL7230ChannelTable1[byChannel-1]); //Reg1 + bResult &= IFRFbWriteEmbedded (dwIoBase, dwAL7230ChannelTable2[byChannel-1]); //Reg4 // PLLOn On MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3); @@ -574,7 +574,7 @@ bool s_bAL7230SelectChannel (unsigned long dwIoBase, unsigned char byChannel) /*--------------------- Export Functions --------------------------*/ /* - * Description: Write to IF/RF, by embeded programming + * Description: Write to IF/RF, by embedded programming * * Parameters: * In: @@ -586,7 +586,7 @@ bool s_bAL7230SelectChannel (unsigned long dwIoBase, unsigned char byChannel) * Return Value: true if succeeded; false if failed. * */ -bool IFRFbWriteEmbeded (unsigned long dwIoBase, unsigned long dwData) +bool IFRFbWriteEmbedded (unsigned long dwIoBase, unsigned long dwData) { unsigned short ww; unsigned long dwValue; @@ -669,11 +669,11 @@ bool RFbAL2230Init (unsigned long dwIoBase) //patch abnormal AL2230 frequency output //2008-8-21 chester <add> - IFRFbWriteEmbeded(dwIoBase, (0x07168700+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW)); + IFRFbWriteEmbedded(dwIoBase, (0x07168700+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW)); for (ii = 0; ii < CB_AL2230_INIT_SEQ; ii++) - bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL2230InitTable[ii]); + bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL2230InitTable[ii]); //2008-8-21 chester <add> MACvTimer0MicroSDelay(dwIoBase, 30); //delay 30 us @@ -681,11 +681,11 @@ MACvTimer0MicroSDelay(dwIoBase, 30); //delay 30 us MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_SWPE3); MACvTimer0MicroSDelay(dwIoBase, 150);//150us - bResult &= IFRFbWriteEmbeded(dwIoBase, (0x00d80f00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW)); + bResult &= IFRFbWriteEmbedded(dwIoBase, (0x00d80f00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW)); MACvTimer0MicroSDelay(dwIoBase, 30);//30us - bResult &= IFRFbWriteEmbeded(dwIoBase, (0x00780f00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW)); + bResult &= IFRFbWriteEmbedded(dwIoBase, (0x00780f00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW)); MACvTimer0MicroSDelay(dwIoBase, 30);//30us - bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL2230InitTable[CB_AL2230_INIT_SEQ-1]); + bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL2230InitTable[CB_AL2230_INIT_SEQ-1]); MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, (SOFTPWRCTL_SWPE3 | SOFTPWRCTL_SWPE2 | @@ -704,8 +704,8 @@ bool RFbAL2230SelectChannel (unsigned long dwIoBase, unsigned char byChannel) bResult = true; - bResult &= IFRFbWriteEmbeded (dwIoBase, dwAL2230ChannelTable0[byChannel-1]); - bResult &= IFRFbWriteEmbeded (dwIoBase, dwAL2230ChannelTable1[byChannel-1]); + bResult &= IFRFbWriteEmbedded (dwIoBase, dwAL2230ChannelTable0[byChannel-1]); + bResult &= IFRFbWriteEmbedded (dwIoBase, dwAL2230ChannelTable1[byChannel-1]); // Set Channel[7] = 0 to tell H/W channel is changing now. VNSvOutPortB(dwIoBase + MAC_REG_CHANNEL, (byChannel & 0x7F)); @@ -817,7 +817,7 @@ bool bResult = true; switch (pDevice->byRFType) { case RF_AIROHA7230 : - bResult = IFRFbWriteEmbeded (pDevice->PortOffset, 0x1ABAEF00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW); + bResult = IFRFbWriteEmbedded (pDevice->PortOffset, 0x1ABAEF00+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW); break; default : bResult = true; @@ -1072,23 +1072,23 @@ unsigned long dwMax7230Pwr = 0; switch (pDevice->byRFType) { case RF_AIROHA : - bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, dwAL2230PowerTable[byPwr]); + bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, dwAL2230PowerTable[byPwr]); if (uRATE <= RATE_11M) { - bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, 0x0001B400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); + bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x0001B400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); } else { - bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); + bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); } break; case RF_AL2230S : - bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, dwAL2230PowerTable[byPwr]); + bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, dwAL2230PowerTable[byPwr]); if (uRATE <= RATE_11M) { - bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, 0x040C1400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); - bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, 0x00299B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); + bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x040C1400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); + bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x00299B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); }else { - bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); - bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, 0x00099B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); + bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); + bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, 0x00099B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); } break; @@ -1098,7 +1098,7 @@ unsigned long dwMax7230Pwr = 0; dwMax7230Pwr = 0x080C0B00 | ( (byPwr) << 12 ) | (BY_AL7230_REG_LEN << 3 ) | IFREGCTL_REGW; - bResult &= IFRFbWriteEmbeded(pDevice->PortOffset, dwMax7230Pwr); + bResult &= IFRFbWriteEmbedded(pDevice->PortOffset, dwMax7230Pwr); break; @@ -1166,24 +1166,24 @@ bool RFbAL7230SelectChannelPostProcess (unsigned long dwIoBase, unsigned char by if( (byOldChannel <= CB_MAX_CHANNEL_24G) && (byNewChannel > CB_MAX_CHANNEL_24G) ) { // Change from 2.4G to 5G - bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTableAMode[2]); //Reg2 - bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTableAMode[3]); //Reg3 - bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTableAMode[5]); //Reg5 - bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTableAMode[7]); //Reg7 - bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTableAMode[10]);//Reg10 - bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTableAMode[12]);//Reg12 - bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTableAMode[15]);//Reg15 + bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[2]); //Reg2 + bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[3]); //Reg3 + bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[5]); //Reg5 + bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[7]); //Reg7 + bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[10]);//Reg10 + bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[12]);//Reg12 + bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTableAMode[15]);//Reg15 } else if( (byOldChannel > CB_MAX_CHANNEL_24G) && (byNewChannel <= CB_MAX_CHANNEL_24G) ) { // change from 5G to 2.4G - bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[2]); //Reg2 - bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[3]); //Reg3 - bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[5]); //Reg5 - bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[7]); //Reg7 - bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[10]);//Reg10 - bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[12]);//Reg12 - bResult &= IFRFbWriteEmbeded(dwIoBase, dwAL7230InitTable[15]);//Reg15 + bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[2]); //Reg2 + bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[3]); //Reg3 + bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[5]); //Reg5 + bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[7]); //Reg7 + bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[10]);//Reg10 + bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[12]);//Reg12 + bResult &= IFRFbWriteEmbedded(dwIoBase, dwAL7230InitTable[15]);//Reg15 } return bResult; diff --git a/drivers/staging/vt6655/rf.h b/drivers/staging/vt6655/rf.h index 73f09693ee7a..1da0fdeb2e1c 100644 --- a/drivers/staging/vt6655/rf.h +++ b/drivers/staging/vt6655/rf.h @@ -75,7 +75,7 @@ /*--------------------- Export Functions --------------------------*/ -bool IFRFbWriteEmbeded(unsigned long dwIoBase, unsigned long dwData); +bool IFRFbWriteEmbedded(unsigned long dwIoBase, unsigned long dwData); bool RFbSelectChannel(unsigned long dwIoBase, unsigned char byRFType, unsigned char byChannel); bool RFbInit ( PSDevice pDevice diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c index 6935b37d5444..4972e57845c2 100644 --- a/drivers/staging/vt6655/rxtx.c +++ b/drivers/staging/vt6655/rxtx.c @@ -27,7 +27,7 @@ * Functions: * s_vGenerateTxParameter - Generate tx dma required parameter. * vGenerateMACHeader - Translate 802.3 to 802.11 header - * cbGetFragCount - Caculate fragment number count + * cbGetFragCount - Calculate fragment number count * csBeacon_xmit - beacon tx function * csMgmt_xmit - management tx function * s_cbFillTxBufHead - fulfill tx dma buffer header @@ -733,11 +733,11 @@ s_uFillDataHead ( if (byFBOption == AUTO_FB_NONE) { PSTxDataHead_g pBuf = (PSTxDataHead_g)pTxDataHead; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType, + BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType, (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_a), (unsigned char *)&(pBuf->bySignalField_a) ); pBuf->wTransmitLength_a = cpu_to_le16(wLen); - BBvCaculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B, + BBvCalculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B, (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b) ); pBuf->wTransmitLength_b = cpu_to_le16(wLen); @@ -759,11 +759,11 @@ s_uFillDataHead ( // Auto Fallback PSTxDataHead_g_FB pBuf = (PSTxDataHead_g_FB)pTxDataHead; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType, + BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType, (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_a), (unsigned char *)&(pBuf->bySignalField_a) ); pBuf->wTransmitLength_a = cpu_to_le16(wLen); - BBvCaculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B, + BBvCalculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B, (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b) ); pBuf->wTransmitLength_b = cpu_to_le16(wLen); @@ -788,7 +788,7 @@ s_uFillDataHead ( // Auto Fallback PSTxDataHead_a_FB pBuf = (PSTxDataHead_a_FB)pTxDataHead; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType, + BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType, (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField) ); pBuf->wTransmitLength = cpu_to_le16(wLen); @@ -805,7 +805,7 @@ s_uFillDataHead ( } else { PSTxDataHead_ab pBuf = (PSTxDataHead_ab)pTxDataHead; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType, + BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType, (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField) ); pBuf->wTransmitLength = cpu_to_le16(wLen); @@ -823,7 +823,7 @@ s_uFillDataHead ( else { PSTxDataHead_ab pBuf = (PSTxDataHead_ab)pTxDataHead; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType, + BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType, (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField) ); pBuf->wTransmitLength = cpu_to_le16(wLen); @@ -871,11 +871,11 @@ s_vFillRTSHead ( if (byFBOption == AUTO_FB_NONE) { PSRTS_g pBuf = (PSRTS_g)pvRTS; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, + BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b) ); pBuf->wTransmitLength_b = cpu_to_le16(wLen); - BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType, + BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType, (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_a), (unsigned char *)&(pBuf->bySignalField_a) ); pBuf->wTransmitLength_a = cpu_to_le16(wLen); @@ -904,11 +904,11 @@ s_vFillRTSHead ( else { PSRTS_g_FB pBuf = (PSRTS_g_FB)pvRTS; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, + BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b) ); pBuf->wTransmitLength_b = cpu_to_le16(wLen); - BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType, + BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType, (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_a), (unsigned char *)&(pBuf->bySignalField_a) ); pBuf->wTransmitLength_a = cpu_to_le16(wLen); @@ -946,7 +946,7 @@ s_vFillRTSHead ( if (byFBOption == AUTO_FB_NONE) { PSRTS_ab pBuf = (PSRTS_ab)pvRTS; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType, + BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType, (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField) ); pBuf->wTransmitLength = cpu_to_le16(wLen); @@ -975,7 +975,7 @@ s_vFillRTSHead ( else { PSRTS_a_FB pBuf = (PSRTS_a_FB)pvRTS; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType, + BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType, (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField) ); pBuf->wTransmitLength = cpu_to_le16(wLen); @@ -1005,7 +1005,7 @@ s_vFillRTSHead ( else if (byPktType == PK_TYPE_11B) { PSRTS_ab pBuf = (PSRTS_ab)pvRTS; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, + BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField), (unsigned char *)&(pBuf->bySignalField) ); pBuf->wTransmitLength = cpu_to_le16(wLen); @@ -1065,7 +1065,7 @@ s_vFillCTSHead ( // Auto Fall back PSCTS_FB pBuf = (PSCTS_FB)pvCTS; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, + BBvCalculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b) ); @@ -1092,7 +1092,7 @@ s_vFillCTSHead ( } else { //if (byFBOption != AUTO_FB_NONE && uDMAIdx != TYPE_ATIMDMA && uDMAIdx != TYPE_BEACONDMA) PSCTS pBuf = (PSCTS)pvCTS; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, + BBvCalculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, (unsigned short *)&(wLen), (unsigned char *)&(pBuf->byServiceField_b), (unsigned char *)&(pBuf->bySignalField_b) ); pBuf->wTransmitLength_b = cpu_to_le16(wLen); @@ -2568,7 +2568,7 @@ CMD_STATUS csMgmt_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket) { if (bIsPSPOLL) { // The MAC will automatically replace the Duration-field of MAC header by Duration-field // of FIFO control header. - // This will cause AID-field of PS-POLL packet be incorrect (Because PS-POLL's AID field is + // This will cause AID-field of PS-POLL packet to be incorrect (Because PS-POLL's AID field is // in the same place of other packet's Duration-field). // And it will cause Cisco-AP to issue Disassociation-packet if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) { @@ -2664,7 +2664,7 @@ CMD_STATUS csBeacon_xmit(PSDevice pDevice, PSTxMgmtPacket pPacket) { wCurrentRate, false, 0, 0, 1, AUTO_FB_NONE)); } - BBvCaculateParameter(pDevice, cbFrameSize, wCurrentRate, byPktType, + BBvCalculateParameter(pDevice, cbFrameSize, wCurrentRate, byPktType, (unsigned short *)&(wLen), (unsigned char *)&(pTxDataHead->byServiceField), (unsigned char *)&(pTxDataHead->bySignalField) ); pTxDataHead->wTransmitLength = cpu_to_le16(wLen); @@ -2860,7 +2860,7 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, unsigned char *pbMPDU, un // SetPower will cause error power TX state for OFDM Date packet in TX buffer. // 2004.11.11 Kyle -- Using OFDM power to tx MngPkt will decrease the connection capability. - // And cmd timer will wait data pkt TX finish before scanning so it's OK + // And cmd timer will wait data pkt TX to finish before scanning so it's OK // to set power here. if (pDevice->pMgmt->eScanState != WMAC_NO_SCANNING) { RFbSetPower(pDevice, wCurrentRate, pDevice->byCurrentCh); @@ -2957,7 +2957,7 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb, unsigned char *pbMPDU, un pTxBufHead->wFragCtl |= cpu_to_le16((unsigned short)cbMacHdLen << 10); // Notes: - // Although spec says MMPDU can be fragmented; In most case, + // Although spec says MMPDU can be fragmented; In most casses, // no one will send a MMPDU under fragmentation. With RTS may occur. pDevice->bAES = false; //Set FRAGCTL_WEPTYP diff --git a/drivers/staging/vt6655/tcrc.c b/drivers/staging/vt6655/tcrc.c index f9c28bf8a6af..1313c4cd0860 100644 --- a/drivers/staging/vt6655/tcrc.c +++ b/drivers/staging/vt6655/tcrc.c @@ -18,7 +18,7 @@ * * File: tcrc.c * - * Purpose: Implement functions to caculate CRC + * Purpose: Implement functions to calculate CRC * * Author: Tevin Chen * diff --git a/drivers/staging/vt6655/tcrc.h b/drivers/staging/vt6655/tcrc.h index d0449855beb1..a2044212d1c9 100644 --- a/drivers/staging/vt6655/tcrc.h +++ b/drivers/staging/vt6655/tcrc.h @@ -18,7 +18,7 @@ * * File: tcrc.h * - * Purpose: Implement functions to caculate CRC + * Purpose: Implement functions to calculate CRC * * Author: Tevin Chen * diff --git a/drivers/staging/vt6655/tether.c b/drivers/staging/vt6655/tether.c index 1cf8508e407d..28554bf75549 100644 --- a/drivers/staging/vt6655/tether.c +++ b/drivers/staging/vt6655/tether.c @@ -25,7 +25,7 @@ * Date: May 21, 1996 * * Functions: - * ETHbyGetHashIndexByCrc32 - Caculate multicast hash value by CRC32 + * ETHbyGetHashIndexByCrc32 - Calculate multicast hash value by CRC32 * ETHbIsBufferCrc32Ok - Check CRC value of the buffer if Ok or not * * Revision History: @@ -50,7 +50,7 @@ /* - * Description: Caculate multicast hash value by CRC32 + * Description: Calculate multicast hash value by CRC32 * * Parameters: * In: diff --git a/drivers/staging/vt6655/tkip.c b/drivers/staging/vt6655/tkip.c index ed3eac17ae8d..f141ba1cbb9b 100644 --- a/drivers/staging/vt6655/tkip.c +++ b/drivers/staging/vt6655/tkip.c @@ -170,7 +170,7 @@ unsigned int rotr1(unsigned int a) /* - * Description: Caculate RC4Key fom TK, TA, and TSC + * Description: Calculate RC4Key fom TK, TA, and TSC * * Parameters: * In: diff --git a/drivers/staging/vt6655/vntwifi.c b/drivers/staging/vt6655/vntwifi.c index d645ecd89417..62c44b87d310 100644 --- a/drivers/staging/vt6655/vntwifi.c +++ b/drivers/staging/vt6655/vntwifi.c @@ -60,7 +60,7 @@ * Parameters: * In: * pMgmtHandle - pointer to management object - * eOPMode - Opreation Mode + * eOPMode - Operation Mode * Out: * none * diff --git a/drivers/staging/vt6655/wcmd.c b/drivers/staging/vt6655/wcmd.c index 7b5b99c8cf14..94bd1fc42c93 100644 --- a/drivers/staging/vt6655/wcmd.c +++ b/drivers/staging/vt6655/wcmd.c @@ -121,7 +121,7 @@ vAdHocBeaconStop(PSDevice pDevice) /* * temporarily stop Beacon packet for AdHoc Server - * if all of the following coditions are met: + * if all of the following conditions are met: * (1) STA is in AdHoc mode * (2) VT3253 is programmed as automatic Beacon Transmitting * (3) One of the following conditions is met @@ -812,8 +812,8 @@ printk("chester-abyDesireSSID=%s\n",((PWLAN_IE_SSID)pMgmt->abyDesireSSID)->abySS DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "sta ps tx fail \n"); } pMgmt->sNodeDBTable[ii].wEnQueueCnt--; - // check if sta ps enable, wait next pspoll - // if sta ps disable, send all pending buffers. + // check if sta ps enabled, and wait next pspoll. + // if sta ps disable, then send all pending buffers. if (pMgmt->sNodeDBTable[ii].bPSEnable) break; } diff --git a/drivers/staging/vt6655/wmgr.c b/drivers/staging/vt6655/wmgr.c index c46d51908ac0..b6f99ecbbeb5 100644 --- a/drivers/staging/vt6655/wmgr.c +++ b/drivers/staging/vt6655/wmgr.c @@ -26,8 +26,8 @@ * Date: May 8, 2002 * * Functions: - * nsMgrObjectInitial - Initialize Management Objet data structure - * vMgrObjectReset - Reset Management Objet data structure + * nsMgrObjectInitial - Initialize Management Object data structure + * vMgrObjectReset - Reset Management Object data structure * vMgrAssocBeginSta - Start associate function * vMgrReAssocBeginSta - Start reassociate function * vMgrDisassocBeginSta - Start disassociate function @@ -54,7 +54,7 @@ * bMgrPrepareBeaconToSend - Prepare Beacon frame * s_vMgrLogStatus - Log 802.11 Status * vMgrRxManagePacket - Rcv management frame dispatch function - * s_vMgrFormatTIM- Assember TIM field of beacon + * s_vMgrFormatTIM- Assembler TIM field of beacon * vMgrTimerInit- Initial 1-sec and command call back funtions * * Revision History: @@ -425,7 +425,7 @@ vMgrTimerInit( /*+ * * Routine Description: - * Reset the management object structure. + * Reset the management object structure. * * Return Value: * None. @@ -1287,14 +1287,14 @@ s_vMgrRxAuthentication( vMgrDecodeAuthen(&sFrame); switch (cpu_to_le16((*(sFrame.pwAuthSequence )))){ case 1: - //AP funciton + //AP function s_vMgrRxAuthenSequence_1(pDevice,pMgmt, &sFrame); break; case 2: s_vMgrRxAuthenSequence_2(pDevice, pMgmt, &sFrame); break; case 3: - //AP funciton + //AP function s_vMgrRxAuthenSequence_3(pDevice, pMgmt, &sFrame); break; case 4: @@ -1923,7 +1923,7 @@ s_vMgrRxBeacon( byIEChannel = sFrame.pDSParms->byCurrChannel; } if (byCurrChannel != byIEChannel) { - // adjust channel info. bcs we rcv adjcent channel pakckets + // adjust channel info. bcs we rcv adjacent channel packets bChannelHit = false; byCurrChannel = byIEChannel; } @@ -2081,7 +2081,7 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==true) } } // - // Basic Rate Set may change dynamiclly + // Basic Rate Set may change dynamically // if (pBSSList->eNetworkTypeInUse == PHY_TYPE_11B) { uRateLen = WLAN_RATES_MAXLEN_11B; @@ -2134,7 +2134,7 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==true) } // DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"Beacon 2 \n"); - // check if CF field exisit + // check if CF field exists if (WLAN_GET_CAP_INFO_ESS(*sFrame.pwCapInfo)) { if (sFrame.pCFParms->wCFPDurRemaining > 0) { // TODO: deal with CFP period to set NAV @@ -2244,7 +2244,7 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==true) if (pMgmt->sNodeDBTable[0].uInActiveCount != 0) pMgmt->sNodeDBTable[0].uInActiveCount = 0; - // adhoc mode:TSF updated only when beacon larger then local TSF + // adhoc mode:TSF updated only when beacon larger than local TSF if (bTSFLargeDiff && bTSFOffsetPostive && (pMgmt->eCurrState == WMAC_STATE_JOINTED)) bUpdateTSF = true; @@ -2252,7 +2252,7 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==true) // During dpc, already in spinlocked. if (BSSDBbIsSTAInNodeDB(pMgmt, sFrame.pHdr->sA3.abyAddr2, &uNodeIndex)) { - // Update the STA, (Techically the Beacons of all the IBSS nodes + // Update the STA, (Technically the Beacons of all the IBSS nodes // should be identical, but that's not happening in practice. pMgmt->abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pSuppRates, (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates, @@ -2305,7 +2305,7 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==true) */ } - // if other stations jointed, indicate connect to upper layer.. + // if other stations joined, indicate connection to upper layer.. if (pMgmt->eCurrState == WMAC_STATE_STARTED) { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Current IBSS State: [Started]........to: [Jointed] \n"); pMgmt->eCurrState = WMAC_STATE_JOINTED; @@ -3081,8 +3081,8 @@ s_vMgrSynchBSS ( // } // } // if( uSameBssidNum>=2) { //we only check AP in hidden sssid mode - if ((pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) || //networkmanager 0.7.0 does not give the pairwise-key selsection, - (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) { // so we need re-selsect it according to real pairwise-key info. + if ((pMgmt->eAuthenMode == WMAC_AUTH_WPAPSK) || //networkmanager 0.7.0 does not give the pairwise-key selection, + (pMgmt->eAuthenMode == WMAC_AUTH_WPA2PSK)) { // so we need re-select it according to real pairwise-key info. if(pCurr->bWPAValid == true) { //WPA-PSK pMgmt->eAuthenMode = WMAC_AUTH_WPAPSK; if(pCurr->abyPKType[0] == WPA_TKIP) { @@ -3193,7 +3193,7 @@ s_vMgrFormatTIM( * * * Return Value: - * PTR to frame; or NULL on allocation failue + * PTR to frame; or NULL on allocation failure * -*/ @@ -3310,7 +3310,7 @@ s_MgrMakeBeacon( *((unsigned short *)(sFrame.pBuf + sFrame.len + sFrame.pRSNWPA->len))=0; sFrame.pRSNWPA->len +=2; - // RSN Capabilites + // RSN Capabilities *((unsigned short *)(sFrame.pBuf + sFrame.len + sFrame.pRSNWPA->len))=0; sFrame.pRSNWPA->len +=2; sFrame.len += sFrame.pRSNWPA->len + WLAN_IEHDR_LEN; @@ -3420,7 +3420,7 @@ s_MgrMakeBeacon( * * * Return Value: - * PTR to frame; or NULL on allocation failue + * PTR to frame; or NULL on allocation failure * -*/ @@ -3611,7 +3611,7 @@ s_MgrMakeProbeResponse( * * * Return Value: - * A ptr to frame or NULL on allocation failue + * A ptr to frame or NULL on allocation failure * -*/ @@ -3652,7 +3652,7 @@ s_MgrMakeAssocRequest( memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); - // Set the capibility and listen interval + // Set the capability and listen interval *(sFrame.pwCapInfo) = cpu_to_le16(wCurrCapInfo); *(sFrame.pwListenInterval) = cpu_to_le16(wListenInterval); @@ -3762,7 +3762,7 @@ s_MgrMakeAssocRequest( sFrame.pRSNWPA->len +=6; - // RSN Capabilites + // RSN Capabilities *pbyRSN++=0x00; *pbyRSN++=0x00; @@ -3831,7 +3831,7 @@ s_MgrMakeAssocRequest( } sFrame.pRSN->len +=6; - // RSN Capabilites + // RSN Capabilities if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == true) { memcpy(&sFrame.pRSN->abyRSN[16], &pMgmt->pCurrBSS->sRSNCapObj.wRSNCap, 2); } else { @@ -3886,7 +3886,7 @@ s_MgrMakeAssocRequest( * * * Return Value: - * A ptr to frame or NULL on allocation failue + * A ptr to frame or NULL on allocation failure * -*/ @@ -3929,7 +3929,7 @@ s_MgrMakeReAssocRequest( memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); - /* Set the capibility and listen interval */ + /* Set the capability and listen interval */ *(sFrame.pwCapInfo) = cpu_to_le16(wCurrCapInfo); *(sFrame.pwListenInterval) = cpu_to_le16(wListenInterval); @@ -4019,7 +4019,7 @@ s_MgrMakeReAssocRequest( sFrame.pRSNWPA->len +=6; - // RSN Capabilites + // RSN Capabilities *pbyRSN++=0x00; *pbyRSN++=0x00; sFrame.pRSNWPA->len +=2; @@ -4087,7 +4087,7 @@ s_MgrMakeReAssocRequest( } sFrame.pRSN->len +=6; - // RSN Capabilites + // RSN Capabilities if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == true) { memcpy(&sFrame.pRSN->abyRSN[16], &pMgmt->pCurrBSS->sRSNCapObj.wRSNCap, 2); } else { @@ -4138,7 +4138,7 @@ s_MgrMakeReAssocRequest( * * * Return Value: - * PTR to frame; or NULL on allocation failue + * PTR to frame; or NULL on allocation failure * -*/ @@ -4212,7 +4212,7 @@ s_MgrMakeAssocResponse( * * * Return Value: - * PTR to frame; or NULL on allocation failue + * PTR to frame; or NULL on allocation failure * -*/ @@ -4333,7 +4333,7 @@ s_vMgrRxProbeResponse( byIEChannel = sFrame.pDSParms->byCurrChannel; } if (byCurrChannel != byIEChannel) { - // adjust channel info. bcs we rcv adjcent channel pakckets + // adjust channel info. bcs we rcv adjacent channel packets bChannelHit = false; byCurrChannel = byIEChannel; } diff --git a/drivers/staging/vt6655/wmgr.h b/drivers/staging/vt6655/wmgr.h index e3ae562f521a..bfa67ae5d40a 100644 --- a/drivers/staging/vt6655/wmgr.h +++ b/drivers/staging/vt6655/wmgr.h @@ -286,7 +286,7 @@ typedef struct tagSMgmtObject CMD_STATE eCommandState; unsigned int uScanChannel; - // Desire joinning BSS vars + // Desire joining BSS vars unsigned char abyDesireSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1]; unsigned char abyDesireBSSID[WLAN_BSSID_LEN]; @@ -310,7 +310,7 @@ typedef struct tagSMgmtObject unsigned int uScanEndCh; unsigned short wScanSteps; unsigned int uScanBSSType; - // Desire scannig vars + // Desire scanning vars unsigned char abyScanSSID[WLAN_IEHDR_LEN + WLAN_SSID_MAXLEN + 1]; unsigned char abyScanBSSID[WLAN_BSSID_LEN]; diff --git a/drivers/staging/vt6655/wpa.c b/drivers/staging/vt6655/wpa.c index 0afb9fe0379a..4412fe9396a4 100644 --- a/drivers/staging/vt6655/wpa.c +++ b/drivers/staging/vt6655/wpa.c @@ -229,7 +229,7 @@ WPA_ParseRSN ( * Parameters: * In: * byCmd - Search type - * byEncrypt- Encrcypt Type + * byEncrypt- Encrypt Type * pBSSList - BSS list * Out: * none diff --git a/drivers/staging/vt6655/wpa2.c b/drivers/staging/vt6655/wpa2.c index 744799cfe832..884db1abe123 100644 --- a/drivers/staging/vt6655/wpa2.c +++ b/drivers/staging/vt6655/wpa2.c @@ -175,16 +175,16 @@ WPA2vParseRSN ( pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_USE_GROUP; bUseGK = true; } else if ( !memcmp(pbyOUI, abyOUIWEP40, 4)) { - // Invialid CSS, continue to parsing + // Invalid CSS, continue to parsing } else if ( !memcmp(pbyOUI, abyOUITKIP, 4)) { if (pBSSNode->byCSSGK != WLAN_11i_CSS_CCMP) pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_TKIP; else - ; // Invialid CSS, continue to parsing + ; // Invalid CSS, continue to parsing } else if ( !memcmp(pbyOUI, abyOUICCMP, 4)) { pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_CCMP; } else if ( !memcmp(pbyOUI, abyOUIWEP104, 4)) { - // Invialid CSS, continue to parsing + // Invalid CSS, continue to parsing } else { // any vendor checks here pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_UNKNOWN; @@ -329,7 +329,7 @@ WPA2uSetIEs( } pRSNIEs->len +=6; - // RSN Capabilites + // RSN Capabilities if (pMgmt->pCurrBSS->sRSNCapObj.bRSNCapExist == true) { memcpy(&pRSNIEs->abyRSN[16], &pMgmt->pCurrBSS->sRSNCapObj.wRSNCap, 2); } else { diff --git a/drivers/staging/vt6655/wpactl.c b/drivers/staging/vt6655/wpactl.c index 732ba88dc796..2b6ae1e403bf 100644 --- a/drivers/staging/vt6655/wpactl.c +++ b/drivers/staging/vt6655/wpactl.c @@ -77,7 +77,7 @@ static void wpadev_setup(struct net_device *dev) /* * Description: - * register netdev for wpa supplicant deamon + * register netdev for wpa supplicant daemon * * Parameters: * In: @@ -164,7 +164,7 @@ static int wpa_release_wpadev(PSDevice pDevice) /* * Description: - * Set enable/disable dev for wpa supplicant deamon + * Set enable/disable dev for wpa supplicant daemon * * Parameters: * In: @@ -847,7 +847,7 @@ else if(!bWepEnabled) pDevice->eEncryptionStatus = Ndis802_11EncryptionDisabled; else pDevice->eEncryptionStatus = Ndis802_11Encryption1Enabled; //pMgmt->eAuthenMode = WMAC_AUTH_OPEN; - //pMgmt->bShareKeyAlgorithm = false; //20080717-06,<Modify> by chester//Fix Open mode, WEP encrytion + //pMgmt->bShareKeyAlgorithm = false; //20080717-06,<Modify> by chester//Fix Open mode, WEP encryption } //mike save old encryption status pDevice->eOldEncryptionStatus = pDevice->eEncryptionStatus; diff --git a/drivers/staging/vt6655/wroute.c b/drivers/staging/vt6655/wroute.c index 66e2eeae628b..82e93cb82053 100644 --- a/drivers/staging/vt6655/wroute.c +++ b/drivers/staging/vt6655/wroute.c @@ -18,7 +18,7 @@ * * File: wroute.c * - * Purpose: handle WMAC frame relay & filterring + * Purpose: handle WMAC frame relay & filtering * * Author: Lyndon Chen * diff --git a/drivers/staging/vt6656/80211mgr.h b/drivers/staging/vt6656/80211mgr.h index 515b9c1d4d10..e5db73be0e71 100644 --- a/drivers/staging/vt6656/80211mgr.h +++ b/drivers/staging/vt6656/80211mgr.h @@ -191,7 +191,7 @@ // -// Cipher Suite Selectors defiened in 802.11i +// Cipher Suite Selectors defined in 802.11i // #define WLAN_11i_CSS_USE_GROUP 0 #define WLAN_11i_CSS_WEP40 1 @@ -720,7 +720,7 @@ typedef struct tagWLAN_FR_AUTHEN { } WLAN_FR_AUTHEN, *PWLAN_FR_AUTHEN; -// Deauthenication +// Deauthentication typedef struct tagWLAN_FR_DEAUTHEN { unsigned int uType; diff --git a/drivers/staging/vt6656/baseband.c b/drivers/staging/vt6656/baseband.c index 06f27f624db4..385501595b4d 100644 --- a/drivers/staging/vt6656/baseband.c +++ b/drivers/staging/vt6656/baseband.c @@ -27,7 +27,7 @@ * * Functions: * BBuGetFrameTime - Calculate data frame transmitting time - * BBvCaculateParameter - Caculate PhyLength, PhyService and Phy Signal parameter for baseband Tx + * BBvCalculateParameter - Calculate PhyLength, PhyService and Phy Signal parameter for baseband Tx * BBbVT3184Init - VIA VT3184 baseband chip init code * BBvLoopbackOn - Turn on BaseBand Loopback mode * BBvLoopbackOff - Turn off BaseBand Loopback mode @@ -741,7 +741,7 @@ BBuGetFrameTime ( } /* - * Description: Caculate Length, Service, and Signal fields of Phy for Tx + * Description: Calculate Length, Service, and Signal fields of Phy for Tx * * Parameters: * In: @@ -757,7 +757,7 @@ BBuGetFrameTime ( * */ void -BBvCaculateParameter ( +BBvCalculateParameter ( PSDevice pDevice, unsigned int cbFrameLength, WORD wRate, diff --git a/drivers/staging/vt6656/baseband.h b/drivers/staging/vt6656/baseband.h index 8db8cd07d5f5..844d5a8b13e5 100644 --- a/drivers/staging/vt6656/baseband.h +++ b/drivers/staging/vt6656/baseband.h @@ -104,7 +104,7 @@ BBuGetFrameTime( WORD wRate ); -void BBvCaculateParameter(PSDevice pDevice, +void BBvCalculateParameter(PSDevice pDevice, unsigned int cbFrameLength, WORD wRate, BYTE byPacketType, diff --git a/drivers/staging/vt6656/bssdb.c b/drivers/staging/vt6656/bssdb.c index 099936771e69..2ac066df8340 100644 --- a/drivers/staging/vt6656/bssdb.c +++ b/drivers/staging/vt6656/bssdb.c @@ -226,7 +226,7 @@ PKnownBSS BSSpSearchBSSList(void *hDeviceContext, if (pSelect == NULL) { pSelect = pCurrBSS; } else { - // compare RSSI, select signal strong one + // compare RSSI, select the strongest signal if (pCurrBSS->uRSSI < pSelect->uRSSI) { pSelect = pCurrBSS; } @@ -274,9 +274,9 @@ void BSSvClearBSSList(void *hDeviceContext, BOOL bKeepCurrBSSID) if (pMgmt->sBSSList[ii].bActive && !compare_ether_addr(pMgmt->sBSSList[ii].abyBSSID, pMgmt->abyCurrBSSID)) { - //mike mark: there are two same BSSID in list if that AP is in hidden ssid mode,one 's SSID is null, - // but other's is obvious, so if it acssociate with your STA exactly,you must keep two - // of them!!!!!!!!! + //mike mark: there are two BSSID's in list. If that AP is in hidden ssid mode, one SSID is null, + // but other's might not be obvious, so if it associate's with your STA, + // you must keep the two of them!! // bKeepCurrBSSID = FALSE; continue; } @@ -489,7 +489,7 @@ BOOL BSSbInsertToBSSList(void *hDeviceContext, } if (pDevice->bUpdateBBVGA) { - // Moniter if RSSI is too strong. + // Monitor if RSSI is too strong. pBSSList->byRSSIStatCnt = 0; RFvRSSITodBm(pDevice, (BYTE)(pRxPacket->uRSSI), &pBSSList->ldBmMAX); pBSSList->ldBmAverage[0] = pBSSList->ldBmMAX; @@ -621,7 +621,7 @@ BOOL BSSbUpdateToBSSList(void *hDeviceContext, if (pRxPacket->uRSSI != 0) { RFvRSSITodBm(pDevice, (BYTE)(pRxPacket->uRSSI), &ldBm); - // Moniter if RSSI is too strong. + // Monitor if RSSI is too strong. pBSSList->byRSSIStatCnt++; pBSSList->byRSSIStatCnt %= RSSI_STAT_COUNT; pBSSList->ldBmAverage[pBSSList->byRSSIStatCnt] = ldBm; @@ -687,8 +687,8 @@ BOOL BSSbIsSTAInNodeDB(void *hDeviceContext, /*+ * * Routine Description: - * Find an empty node and allocated; if no empty found, - * instand used of most inactive one. + * Find an empty node and allocate it; if no empty node + * is found, then use the most inactive one. * * Return Value: * None @@ -718,7 +718,7 @@ void BSSvCreateOneNode(void *hDeviceContext, unsigned int *puNodeIndex) } } - // if not found replace uInActiveCount is largest one. + // if not found replace uInActiveCount with the largest one. if ( ii == (MAX_NODE_NUM + 1)) { *puNodeIndex = SelectIndex; DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Replace inactive node = %d\n", SelectIndex); diff --git a/drivers/staging/vt6656/card.c b/drivers/staging/vt6656/card.c index e3ddc0b55317..826520b03383 100644 --- a/drivers/staging/vt6656/card.c +++ b/drivers/staging/vt6656/card.c @@ -28,9 +28,9 @@ * CARDbIsOFDMinBasicRate - Check if any OFDM rate is in BasicRateSet * CARDvSetLoopbackMode - Set Loopback mode * CARDbSoftwareReset - Sortware reset NIC - * CARDqGetTSFOffset - Caculate TSFOffset + * CARDqGetTSFOffset - Calculate TSFOffset * CARDbGetCurrentTSF - Read Current NIC TSF counter - * CARDqGetNextTBTT - Caculate Next Beacon TSF counter + * CARDqGetNextTBTT - Calculate Next Beacon TSF counter * CARDvSetFirstNextTBTT - Set NIC Beacon time * CARDvUpdateNextTBTT - Sync. NIC Beacon time * CARDbRadioPowerOff - Turn Off NIC Radio Power @@ -40,7 +40,7 @@ * * Revision History: * 06-10-2003 Bryan YC Fan: Re-write codes to support VT3253 spec. - * 08-26-2003 Kyle Hsu: Modify the defination type of dwIoBase. + * 08-26-2003 Kyle Hsu: Modify the definition type of dwIoBase. * 09-01-2003 Bryan YC Fan: Add vUpdateIFS(). * */ @@ -200,7 +200,7 @@ static WORD swGetOFDMControlRate(void *pDeviceHandler, WORD wRateIdx) } /* - * Description: Caculate TxRate and RsvTime fields for RSPINF in OFDM mode. + * Description: Calculate TxRate and RsvTime fields for RSPINF in OFDM mode. * * Parameters: * In: @@ -214,7 +214,7 @@ static WORD swGetOFDMControlRate(void *pDeviceHandler, WORD wRateIdx) * */ void -CARDvCaculateOFDMRParameter ( +CARDvCalculateOFDMRParameter ( WORD wRate, BYTE byBBType, PBYTE pbyTxRate, @@ -337,7 +337,7 @@ void CARDvSetRSPINF(void *pDeviceHandler, BYTE byBBType) int i; //RSPINF_b_1 - BBvCaculateParameter(pDevice, + BBvCalculateParameter(pDevice, 14, swGetCCKControlRate(pDevice, RATE_1M), PK_TYPE_11B, @@ -347,7 +347,7 @@ void CARDvSetRSPINF(void *pDeviceHandler, BYTE byBBType) ); ///RSPINF_b_2 - BBvCaculateParameter(pDevice, + BBvCalculateParameter(pDevice, 14, swGetCCKControlRate(pDevice, RATE_2M), PK_TYPE_11B, @@ -357,7 +357,7 @@ void CARDvSetRSPINF(void *pDeviceHandler, BYTE byBBType) ); //RSPINF_b_5 - BBvCaculateParameter(pDevice, + BBvCalculateParameter(pDevice, 14, swGetCCKControlRate(pDevice, RATE_5M), PK_TYPE_11B, @@ -367,7 +367,7 @@ void CARDvSetRSPINF(void *pDeviceHandler, BYTE byBBType) ); //RSPINF_b_11 - BBvCaculateParameter(pDevice, + BBvCalculateParameter(pDevice, 14, swGetCCKControlRate(pDevice, RATE_11M), PK_TYPE_11B, @@ -377,55 +377,55 @@ void CARDvSetRSPINF(void *pDeviceHandler, BYTE byBBType) ); //RSPINF_a_6 - CARDvCaculateOFDMRParameter (RATE_6M, + CARDvCalculateOFDMRParameter (RATE_6M, byBBType, &abyTxRate[0], &abyRsvTime[0]); //RSPINF_a_9 - CARDvCaculateOFDMRParameter (RATE_9M, + CARDvCalculateOFDMRParameter (RATE_9M, byBBType, &abyTxRate[1], &abyRsvTime[1]); //RSPINF_a_12 - CARDvCaculateOFDMRParameter (RATE_12M, + CARDvCalculateOFDMRParameter (RATE_12M, byBBType, &abyTxRate[2], &abyRsvTime[2]); //RSPINF_a_18 - CARDvCaculateOFDMRParameter (RATE_18M, + CARDvCalculateOFDMRParameter (RATE_18M, byBBType, &abyTxRate[3], &abyRsvTime[3]); //RSPINF_a_24 - CARDvCaculateOFDMRParameter (RATE_24M, + CARDvCalculateOFDMRParameter (RATE_24M, byBBType, &abyTxRate[4], &abyRsvTime[4]); //RSPINF_a_36 - CARDvCaculateOFDMRParameter (swGetOFDMControlRate(pDevice, RATE_36M), + CARDvCalculateOFDMRParameter (swGetOFDMControlRate(pDevice, RATE_36M), byBBType, &abyTxRate[5], &abyRsvTime[5]); //RSPINF_a_48 - CARDvCaculateOFDMRParameter (swGetOFDMControlRate(pDevice, RATE_48M), + CARDvCalculateOFDMRParameter (swGetOFDMControlRate(pDevice, RATE_48M), byBBType, &abyTxRate[6], &abyRsvTime[6]); //RSPINF_a_54 - CARDvCaculateOFDMRParameter (swGetOFDMControlRate(pDevice, RATE_54M), + CARDvCalculateOFDMRParameter (swGetOFDMControlRate(pDevice, RATE_54M), byBBType, &abyTxRate[7], &abyRsvTime[7]); //RSPINF_a_72 - CARDvCaculateOFDMRParameter (swGetOFDMControlRate(pDevice, RATE_54M), + CARDvCalculateOFDMRParameter (swGetOFDMControlRate(pDevice, RATE_54M), byBBType, &abyTxRate[8], &abyRsvTime[8]); @@ -640,7 +640,7 @@ BYTE CARDbyGetPktType(void *pDeviceHandler) /* - * Description: Caculate TSF offset of two TSF input + * Description: Calculate TSF offset of two TSF input * Get TSF Offset from RxBCN's TSF and local TSF * * Parameters: diff --git a/drivers/staging/vt6656/device.h b/drivers/staging/vt6656/device.h index 171dd68cf5b2..6370d1039103 100644 --- a/drivers/staging/vt6656/device.h +++ b/drivers/staging/vt6656/device.h @@ -478,7 +478,7 @@ typedef struct __device_info { unsigned int cbTD; // - // Variables to track resources for the Interript In Pipe + // Variables to track resources for the Interrupt In Pipe // INT_BUFFER intBuf; BOOL fKillEventPollingThread; diff --git a/drivers/staging/vt6656/dpc.c b/drivers/staging/vt6656/dpc.c index 3aa895ec6507..28edf9e7efcb 100644 --- a/drivers/staging/vt6656/dpc.c +++ b/drivers/staging/vt6656/dpc.c @@ -748,7 +748,7 @@ RXbBulkInProcessData ( if ((*pbyRSSI != 0) && (pMgmt->pCurrBSS!=NULL)) { RFvRSSITodBm(pDevice, *pbyRSSI, &ldBm); - // Moniter if RSSI is too strong. + // Monitor if RSSI is too strong. pMgmt->pCurrBSS->byRSSIStatCnt++; pMgmt->pCurrBSS->byRSSIStatCnt %= RSSI_STAT_COUNT; pMgmt->pCurrBSS->ldBmAverage[pMgmt->pCurrBSS->byRSSIStatCnt] = ldBm; diff --git a/drivers/staging/vt6656/hostap.c b/drivers/staging/vt6656/hostap.c index 682002a5b8d7..0a73d4060ee1 100644 --- a/drivers/staging/vt6656/hostap.c +++ b/drivers/staging/vt6656/hostap.c @@ -18,7 +18,7 @@ * * File: hostap.c * - * Purpose: handle hostap deamon ioctl input/out functions + * Purpose: handle hostap daemon ioctl input/out functions * * Author: Lyndon Chen * @@ -48,7 +48,7 @@ static int msglevel =MSG_LEVEL_INFO; /* * Description: - * register net_device (AP) for hostap deamon + * register net_device (AP) for hostap daemon * * Parameters: * In: @@ -176,7 +176,7 @@ int vt6656_hostap_set_hostapd(PSDevice pDevice, int val, int rtnl_locked) /* * Description: - * remove station function supported for hostap deamon + * remove station function supported for hostap daemon * * Parameters: * In: @@ -204,7 +204,7 @@ static int hostap_remove_sta(PSDevice pDevice, /* * Description: - * add a station from hostap deamon + * add a station from hostap daemon * * Parameters: * In: @@ -439,9 +439,7 @@ static int hostap_set_encryption(PSDevice pDevice, return -EINVAL; } - if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && - param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && - param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { + if (is_broadcast_ether_addr(param->sta_addr)) { if (param->u.crypt.idx >= MAX_GROUP_KEY) return -EINVAL; iNodeIndex = 0; @@ -663,9 +661,7 @@ static int hostap_get_encryption(PSDevice pDevice, param->u.crypt.err = 0; - if (param->sta_addr[0] == 0xff && param->sta_addr[1] == 0xff && - param->sta_addr[2] == 0xff && param->sta_addr[3] == 0xff && - param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { + if (is_broadcast_ether_addr(param->sta_addr)) { iNodeIndex = 0; } else { if (BSSbIsSTAInNodeDB(pDevice, param->sta_addr, &iNodeIndex) == FALSE) { @@ -686,7 +682,7 @@ static int hostap_get_encryption(PSDevice pDevice, /* * Description: - * vt6656_hostap_ioctl main function supported for hostap deamon. + * vt6656_hostap_ioctl main function supported for hostap daemon. * * Parameters: * In: @@ -732,8 +728,8 @@ int vt6656_hostap_ioctl(PSDevice pDevice, struct iw_point *p) break; case VIAWGET_HOSTAPD_SET_ASSOC_AP_ADDR: DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_SET_ASSOC_AP_ADDR \n"); - return -EOPNOTSUPP; - break; + ret = -EOPNOTSUPP; + goto out; case VIAWGET_HOSTAPD_FLUSH: DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_FLUSH \n"); spin_lock_irq(&pDevice->lock); @@ -777,13 +773,13 @@ int vt6656_hostap_ioctl(PSDevice pDevice, struct iw_point *p) case VIAWGET_HOSTAPD_STA_CLEAR_STATS: DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "VIAWGET_HOSTAPD_STA_CLEAR_STATS \n"); - return -EOPNOTSUPP; - + ret = -EOPNOTSUPP; + goto out; default: DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "vt6656_hostap_ioctl: unknown cmd=%d\n", (int)param->cmd); - return -EOPNOTSUPP; - break; + ret = -EOPNOTSUPP; + goto out; } diff --git a/drivers/staging/vt6656/int.c b/drivers/staging/vt6656/int.c index eba4b5061cf7..bba31caae036 100644 --- a/drivers/staging/vt6656/int.c +++ b/drivers/staging/vt6656/int.c @@ -149,7 +149,7 @@ void INTnsProcessData(PSDevice pDevice) pMgmt->sNodeDBTable[0].bRxPSPoll = FALSE; } else if (pMgmt->byDTIMCount == 0) { - /* check if mutltcast tx bufferring */ + /* check if multicast tx buffering */ pMgmt->byDTIMCount = pMgmt->byDTIMPeriod-1; pMgmt->sNodeDBTable[0].bRxPSPoll = TRUE; diff --git a/drivers/staging/vt6656/ioctl.c b/drivers/staging/vt6656/ioctl.c index 5b9a84f95185..b6af5f691128 100644 --- a/drivers/staging/vt6656/ioctl.c +++ b/drivers/staging/vt6656/ioctl.c @@ -526,11 +526,8 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) pMgmt->abyIBSSSuppRates[3] |= BIT7; } - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Support Rate= %x %x %x %x\n", - pMgmt->abyIBSSSuppRates[2], - pMgmt->abyIBSSSuppRates[3], - pMgmt->abyIBSSSuppRates[4], - pMgmt->abyIBSSSuppRates[5]); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Support Rate= %*ph\n", + 4, pMgmt->abyIBSSSuppRates + 2); netif_stop_queue(pDevice->dev); spin_lock_irq(&pDevice->lock); @@ -620,7 +617,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) result = -EFAULT; break; } - /* for some AP maybe good authenticate */ + /* for some AP's maybe a good authentication */ if (wpa_Result.key_mgmt == 0x20) pMgmt->Cisco_cckm = 1; else @@ -644,7 +641,7 @@ int private_ioctl(PSDevice pDevice, struct ifreq *rq) break; default: - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Private command not support..\n"); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Private command not supported..\n"); } return result; diff --git a/drivers/staging/vt6656/iwctl.c b/drivers/staging/vt6656/iwctl.c index 8b9894b1146a..8f198749ca51 100644 --- a/drivers/staging/vt6656/iwctl.c +++ b/drivers/staging/vt6656/iwctl.c @@ -674,7 +674,7 @@ int iwctl_giwaplist(struct net_device *dev, struct iw_request_info *info, jj++; } - wrq->flags = 1; // Should be define'd + wrq->flags = 1; // Should be defined wrq->length = jj; memcpy(extra, sock, sizeof(struct sockaddr) * jj); memcpy(extra + sizeof(struct sockaddr) * jj, qual, sizeof(struct iw_quality) * jj); diff --git a/drivers/staging/vt6656/key.c b/drivers/staging/vt6656/key.c index ee62a06a75f4..a61fcb9591aa 100644 --- a/drivers/staging/vt6656/key.c +++ b/drivers/staging/vt6656/key.c @@ -403,7 +403,7 @@ BOOL KeybRemoveKey( BOOL bReturnValue = FALSE; if (is_broadcast_ether_addr(pbyBSSID)) { - // dealte all key + // delete all keys if ((dwKeyIndex & PAIRWISE_KEY) != 0) { for (i=0;i<MAX_KEY_TABLE;i++) { pTable->KeyTable[i].PairwiseKey.bKeyValid = FALSE; @@ -618,7 +618,7 @@ BOOL KeybGetTransmitKey(PSKeyManagement pTable, PBYTE pbyBSSID, DWORD dwKeyType, /* - * Description: Check Pairewise Key + * Description: Check Pairwise Key * * Parameters: * In: diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c index d536756549e6..ad422dea702b 100644 --- a/drivers/staging/vt6656/main_usb.c +++ b/drivers/staging/vt6656/main_usb.c @@ -29,14 +29,14 @@ * vt6656_probe - module initial (insmod) driver entry * device_remove1 - module remove entry * device_open - allocate dma/descripter resource & initial mac/bbp function - * device_xmit - asynchrous data tx function + * device_xmit - asynchronous data tx function * device_set_multi - set mac filter * device_ioctl - ioctl entry - * device_close - shutdown mac/bbp & free dma/descripter resource + * device_close - shutdown mac/bbp & free dma/descriptor resource * device_alloc_frag_buf - rx fragement pre-allocated function * device_free_tx_bufs - free tx buffer function * device_dma0_tx_80211- tx 802.11 frame via dma0 - * device_dma0_xmit- tx PS bufferred frame via dma0 + * device_dma0_xmit- tx PS buffered frame via dma0 * device_init_registers- initial MAC & BBP & RF internal registers. * device_init_rings- initial tx/rx ring buffer * device_init_defrag_cb- initial & allocate de-fragement buffer. @@ -316,7 +316,7 @@ static void device_init_diversity_timer(PSDevice pDevice) // -// Initialiation of MAC & BBP registers +// Initialization of MAC & BBP registers // static BOOL device_init_registers(PSDevice pDevice, DEVICE_INIT_TYPE InitType) @@ -639,7 +639,7 @@ static BOOL device_release_WPADEV(PSDevice pDevice) viawget_wpa_header *wpahdr; int ii=0; // wait_queue_head_t Set_wait; - //send device close to wpa_supplicnat layer + //send device close to wpa_supplicant layer if (pDevice->bWPADEVUp==TRUE) { wpahdr = (viawget_wpa_header *)pDevice->skb->data; wpahdr->type = VIAWGET_DEVICECLOSE_MSG; @@ -1010,7 +1010,7 @@ static int device_open(struct net_device *dev) { } if (device_init_defrag_cb(pDevice)== FALSE) { - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Initial defragement cb fail \n"); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO " Initial defragment cb fail \n"); goto free_rx_tx; } @@ -1296,7 +1296,7 @@ static inline u32 ether_crc(int length, unsigned char *data) return crc; } -//find out the start position of str2 from str1 +//find out the start position of str2 from str1 static unsigned char *kstrstr(const unsigned char *str1, const unsigned char *str2) { int str1_len = strlen(str1); @@ -1345,7 +1345,7 @@ static int Config_FileGetParameter(unsigned char *string, } memset(buf2,0,100); - memcpy(buf2,start_p,end_p-start_p); //get the tartget line + memcpy(buf2,start_p,end_p-start_p); //get the target line buf2[end_p-start_p]='\0'; //find value @@ -1396,7 +1396,7 @@ static unsigned char *Config_FileOperation(PSDevice pDevice) } if(!(filp->f_op) || !(filp->f_op->read) ||!(filp->f_op->write)) { - printk("file %s cann't readable or writable?\n",config_path); + printk("file %s is not read or writeable?\n",config_path); result = -1; goto error1; } @@ -1969,7 +1969,7 @@ static int device_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { default: rc = -EOPNOTSUPP; - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Ioctl command not support..%x\n", cmd); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "Ioctl command not supported..%x\n", cmd); } diff --git a/drivers/staging/vt6656/power.c b/drivers/staging/vt6656/power.c index b3136773b5da..ab3a55462056 100644 --- a/drivers/staging/vt6656/power.c +++ b/drivers/staging/vt6656/power.c @@ -19,7 +19,7 @@ * * File: power.c * - * Purpose: Handles 802.11 power management functions + * Purpose: Handles 802.11 power management functions * * Author: Lyndon Chen * diff --git a/drivers/staging/vt6656/rf.c b/drivers/staging/vt6656/rf.c index 3fd0478a9a54..593cdc713b0e 100644 --- a/drivers/staging/vt6656/rf.c +++ b/drivers/staging/vt6656/rf.c @@ -26,7 +26,7 @@ * Date: Feb. 19, 2004 * * Functions: - * IFRFbWriteEmbeded - Embeded write RF register via MAC + * IFRFbWriteEmbedded - Embedded write RF register via MAC * * Revision History: * @@ -711,7 +711,7 @@ const BYTE RFaby11aChannelIndex[200] = { /*--------------------- Export Functions --------------------------*/ /* - * Description: Write to IF/RF, by embeded programming + * Description: Write to IF/RF, by embedded programming * * Parameters: * In: @@ -722,7 +722,7 @@ const BYTE RFaby11aChannelIndex[200] = { * Return Value: TRUE if succeeded; FALSE if failed. * */ -BOOL IFRFbWriteEmbeded (PSDevice pDevice, DWORD dwData) +BOOL IFRFbWriteEmbedded (PSDevice pDevice, DWORD dwData) { BYTE pbyData[4]; @@ -828,23 +828,23 @@ BOOL bResult = TRUE; case RF_AL2230 : if (pDevice->byCurPwr >= AL2230_PWR_IDX_LEN) return FALSE; - bResult &= IFRFbWriteEmbeded(pDevice, dwAL2230PowerTable[pDevice->byCurPwr]); + bResult &= IFRFbWriteEmbedded(pDevice, dwAL2230PowerTable[pDevice->byCurPwr]); if (uRATE <= RATE_11M) - bResult &= IFRFbWriteEmbeded(pDevice, 0x0001B400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); + bResult &= IFRFbWriteEmbedded(pDevice, 0x0001B400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); else - bResult &= IFRFbWriteEmbeded(pDevice, 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); + bResult &= IFRFbWriteEmbedded(pDevice, 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); break; case RF_AL2230S : if (pDevice->byCurPwr >= AL2230_PWR_IDX_LEN) return FALSE; - bResult &= IFRFbWriteEmbeded(pDevice, dwAL2230PowerTable[pDevice->byCurPwr]); + bResult &= IFRFbWriteEmbedded(pDevice, dwAL2230PowerTable[pDevice->byCurPwr]); if (uRATE <= RATE_11M) { - bResult &= IFRFbWriteEmbeded(pDevice, 0x040C1400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); - bResult &= IFRFbWriteEmbeded(pDevice, 0x00299B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); + bResult &= IFRFbWriteEmbedded(pDevice, 0x040C1400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); + bResult &= IFRFbWriteEmbedded(pDevice, 0x00299B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); }else { - bResult &= IFRFbWriteEmbeded(pDevice, 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); - bResult &= IFRFbWriteEmbeded(pDevice, 0x00099B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); + bResult &= IFRFbWriteEmbedded(pDevice, 0x0005A400+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); + bResult &= IFRFbWriteEmbedded(pDevice, 0x00099B00+(BY_AL2230_REG_LEN<<3)+IFREGCTL_REGW); } break; @@ -854,10 +854,10 @@ BOOL bResult = TRUE; DWORD dwMax7230Pwr; if (uRATE <= RATE_11M) { //RobertYu:20060426, for better 11b mask - bResult &= IFRFbWriteEmbeded(pDevice, 0x111BB900+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW); + bResult &= IFRFbWriteEmbedded(pDevice, 0x111BB900+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW); } else { - bResult &= IFRFbWriteEmbeded(pDevice, 0x221BB900+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW); + bResult &= IFRFbWriteEmbedded(pDevice, 0x221BB900+(BY_AL7230_REG_LEN<<3)+IFREGCTL_REGW); } if (pDevice->byCurPwr > AL7230_PWR_IDX_LEN) return FALSE; @@ -866,7 +866,7 @@ BOOL bResult = TRUE; dwMax7230Pwr = 0x080C0B00 | ( (pDevice->byCurPwr) << 12 ) | (BY_AL7230_REG_LEN << 3 ) | IFREGCTL_REGW; - bResult &= IFRFbWriteEmbeded(pDevice, dwMax7230Pwr); + bResult &= IFRFbWriteEmbedded(pDevice, dwMax7230Pwr); break; } break; @@ -879,7 +879,7 @@ BOOL bResult = TRUE; return FALSE; dwVT3226Pwr = ((0x3F-pDevice->byCurPwr) << 20 ) | ( 0x17 << 8 ) /* Reg7 */ | (BY_VT3226_REG_LEN << 3 ) | IFREGCTL_REGW; - bResult &= IFRFbWriteEmbeded(pDevice, dwVT3226Pwr); + bResult &= IFRFbWriteEmbedded(pDevice, dwVT3226Pwr); break; } @@ -894,27 +894,27 @@ BOOL bResult = TRUE; dwVT3226Pwr = ((0x3F-pDevice->byCurPwr) << 20 ) | ( 0xE07 << 8 ) /* Reg7 */ | //RobertYu:20060420, TWIF 1.10 (BY_VT3226_REG_LEN << 3 ) | IFREGCTL_REGW; - bResult &= IFRFbWriteEmbeded(pDevice, dwVT3226Pwr); + bResult &= IFRFbWriteEmbedded(pDevice, dwVT3226Pwr); - bResult &= IFRFbWriteEmbeded(pDevice, 0x03C6A200+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW); + bResult &= IFRFbWriteEmbedded(pDevice, 0x03C6A200+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW); if (pDevice->sMgmtObj.eScanState != WMAC_NO_SCANNING) { // scanning, the channel number is pDevice->uScanChannel DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"@@@@ RFbRawSetPower> 11B mode uCurrChannel[%d]\n", pDevice->sMgmtObj.uScanChannel); - bResult &= IFRFbWriteEmbeded(pDevice, dwVT3226D0LoCurrentTable[pDevice->sMgmtObj.uScanChannel-1]); //RobertYu:20060420, sometimes didn't change channel just set power with different rate + bResult &= IFRFbWriteEmbedded(pDevice, dwVT3226D0LoCurrentTable[pDevice->sMgmtObj.uScanChannel-1]); //RobertYu:20060420, sometimes didn't change channel just set power with different rate } else { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"@@@@ RFbRawSetPower> 11B mode uCurrChannel[%d]\n", pDevice->sMgmtObj.uCurrChannel); - bResult &= IFRFbWriteEmbeded(pDevice, dwVT3226D0LoCurrentTable[pDevice->sMgmtObj.uCurrChannel-1]); //RobertYu:20060420, sometimes didn't change channel just set power with different rate + bResult &= IFRFbWriteEmbedded(pDevice, dwVT3226D0LoCurrentTable[pDevice->sMgmtObj.uCurrChannel-1]); //RobertYu:20060420, sometimes didn't change channel just set power with different rate } - bResult &= IFRFbWriteEmbeded(pDevice, 0x015C0800+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW); //RobertYu:20060420, ok now, new switching power (mini-pci can have bigger power consumption) + bResult &= IFRFbWriteEmbedded(pDevice, 0x015C0800+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW); //RobertYu:20060420, ok now, new switching power (mini-pci can have bigger power consumption) } else { DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO"@@@@ RFbRawSetPower> 11G mode\n"); dwVT3226Pwr = ((0x3F-pDevice->byCurPwr) << 20 ) | ( 0x7 << 8 ) /* Reg7 */ | //RobertYu:20060420, TWIF 1.10 (BY_VT3226_REG_LEN << 3 ) | IFREGCTL_REGW; - bResult &= IFRFbWriteEmbeded(pDevice, dwVT3226Pwr); - bResult &= IFRFbWriteEmbeded(pDevice, 0x00C6A200+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW); //RobertYu:20060327 - bResult &= IFRFbWriteEmbeded(pDevice, 0x016BC600+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW); //RobertYu:20060111 - bResult &= IFRFbWriteEmbeded(pDevice, 0x00900800+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW); //RobertYu:20060111 + bResult &= IFRFbWriteEmbedded(pDevice, dwVT3226Pwr); + bResult &= IFRFbWriteEmbedded(pDevice, 0x00C6A200+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW); //RobertYu:20060327 + bResult &= IFRFbWriteEmbedded(pDevice, 0x016BC600+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW); //RobertYu:20060111 + bResult &= IFRFbWriteEmbedded(pDevice, 0x00900800+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW); //RobertYu:20060111 } break; } @@ -929,7 +929,7 @@ BOOL bResult = TRUE; dwVT3342Pwr = ((0x3F-pDevice->byCurPwr) << 20 ) | ( 0x27 << 8 ) /* Reg7 */ | (BY_VT3342_REG_LEN << 3 ) | IFREGCTL_REGW; - bResult &= IFRFbWriteEmbeded(pDevice, dwVT3342Pwr); + bResult &= IFRFbWriteEmbedded(pDevice, dwVT3342Pwr); break; } @@ -1048,7 +1048,7 @@ BYTE abyArray[256]; wLength1, abyArray ); - //Channle Table 0 + //Channel Table 0 wValue = 0; while ( wLength2 > 0 ) { @@ -1106,7 +1106,7 @@ BYTE abyArray[256]; wLength1, abyArray); - //Channle Table 0 + //Channel Table 0 wValue = 0; while ( wLength2 > 0 ) { @@ -1141,9 +1141,9 @@ BOOL s_bVT3226D0_11bLoCurrentAdjust( bResult = TRUE; if( b11bMode ) - bResult &= IFRFbWriteEmbeded(pDevice, dwVT3226D0LoCurrentTable[byChannel-1]); + bResult &= IFRFbWriteEmbedded(pDevice, dwVT3226D0LoCurrentTable[byChannel-1]); else - bResult &= IFRFbWriteEmbeded(pDevice, 0x016BC600+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW); //RobertYu:20060412 + bResult &= IFRFbWriteEmbedded(pDevice, 0x016BC600+(BY_VT3226_REG_LEN<<3)+IFREGCTL_REGW); //RobertYu:20060412 return bResult; } diff --git a/drivers/staging/vt6656/rf.h b/drivers/staging/vt6656/rf.h index f5ba8fd7f816..72eb27ac436b 100644 --- a/drivers/staging/vt6656/rf.h +++ b/drivers/staging/vt6656/rf.h @@ -63,7 +63,7 @@ extern const BYTE RFaby11aChannelIndex[200]; /*--------------------- Export Functions --------------------------*/ -BOOL IFRFbWriteEmbeded(PSDevice pDevice, DWORD dwData); +BOOL IFRFbWriteEmbedded(PSDevice pDevice, DWORD dwData); BOOL RFbSetPower(PSDevice pDevice, unsigned int uRATE, unsigned int uCH); BOOL RFbRawSetPower( diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c index b6e04e7b629b..339083879883 100644 --- a/drivers/staging/vt6656/rxtx.c +++ b/drivers/staging/vt6656/rxtx.c @@ -841,7 +841,7 @@ s_uFillDataHead ( if ((uDMAIdx == TYPE_ATIMDMA) || (uDMAIdx == TYPE_BEACONDMA)) { PSTxDataHead_ab pBuf = (PSTxDataHead_ab) pTxDataHead; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType, + BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType, (PWORD)&(pBuf->wTransmitLength), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField) ); //Get Duration and TimeStampOff @@ -858,10 +858,10 @@ s_uFillDataHead ( if (byFBOption == AUTO_FB_NONE) { PSTxDataHead_g pBuf = (PSTxDataHead_g)pTxDataHead; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType, + BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType, (PWORD)&(pBuf->wTransmitLength_a), (PBYTE)&(pBuf->byServiceField_a), (PBYTE)&(pBuf->bySignalField_a) ); - BBvCaculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B, + BBvCalculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B, (PWORD)&(pBuf->wTransmitLength_b), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b) ); //Get Duration and TimeStamp @@ -881,10 +881,10 @@ s_uFillDataHead ( // Auto Fallback PSTxDataHead_g_FB pBuf = (PSTxDataHead_g_FB)pTxDataHead; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType, + BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType, (PWORD)&(pBuf->wTransmitLength_a), (PBYTE)&(pBuf->byServiceField_a), (PBYTE)&(pBuf->bySignalField_a) ); - BBvCaculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B, + BBvCalculateParameter(pDevice, cbFrameLength, pDevice->byTopCCKBasicRate, PK_TYPE_11B, (PWORD)&(pBuf->wTransmitLength_b), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b) ); //Get Duration and TimeStamp @@ -907,7 +907,7 @@ s_uFillDataHead ( // Auto Fallback PSTxDataHead_a_FB pBuf = (PSTxDataHead_a_FB)pTxDataHead; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType, + BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType, (PWORD)&(pBuf->wTransmitLength), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField) ); //Get Duration and TimeStampOff @@ -924,7 +924,7 @@ s_uFillDataHead ( } else { PSTxDataHead_ab pBuf = (PSTxDataHead_ab)pTxDataHead; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType, + BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType, (PWORD)&(pBuf->wTransmitLength), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField) ); //Get Duration and TimeStampOff @@ -942,7 +942,7 @@ s_uFillDataHead ( else if (byPktType == PK_TYPE_11B) { PSTxDataHead_ab pBuf = (PSTxDataHead_ab)pTxDataHead; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType, + BBvCalculateParameter(pDevice, cbFrameLength, wCurrentRate, byPktType, (PWORD)&(pBuf->wTransmitLength), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField) ); //Get Duration and TimeStampOff @@ -987,17 +987,17 @@ s_vFillRTSHead ( uRTSFrameLen -= 4; } - // Note: So far RTSHead dosen't appear in ATIM & Beacom DMA, so we don't need to take them into account. + // Note: So far RTSHead doesn't appear in ATIM & Beacom DMA, so we don't need to take them into account. // Otherwise, we need to modified codes for them. if (byPktType == PK_TYPE_11GB || byPktType == PK_TYPE_11GA) { if (byFBOption == AUTO_FB_NONE) { PSRTS_g pBuf = (PSRTS_g)pvRTS; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, + BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b) ); pBuf->wTransmitLength_b = cpu_to_le16(wLen); - BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType, + BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType, (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_a), (PBYTE)&(pBuf->bySignalField_a) ); pBuf->wTransmitLength_a = cpu_to_le16(wLen); @@ -1035,11 +1035,11 @@ s_vFillRTSHead ( else { PSRTS_g_FB pBuf = (PSRTS_g_FB)pvRTS; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, + BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b) ); pBuf->wTransmitLength_b = cpu_to_le16(wLen); - BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType, + BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType, (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_a), (PBYTE)&(pBuf->bySignalField_a) ); pBuf->wTransmitLength_a = cpu_to_le16(wLen); @@ -1084,7 +1084,7 @@ s_vFillRTSHead ( if (byFBOption == AUTO_FB_NONE) { PSRTS_ab pBuf = (PSRTS_ab)pvRTS; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType, + BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType, (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField) ); pBuf->wTransmitLength = cpu_to_le16(wLen); @@ -1119,7 +1119,7 @@ s_vFillRTSHead ( else { PSRTS_a_FB pBuf = (PSRTS_a_FB)pvRTS; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType, + BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopOFDMBasicRate, byPktType, (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField) ); pBuf->wTransmitLength = cpu_to_le16(wLen); @@ -1155,7 +1155,7 @@ s_vFillRTSHead ( else if (byPktType == PK_TYPE_11B) { PSRTS_ab pBuf = (PSRTS_ab)pvRTS; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, + BBvCalculateParameter(pDevice, uRTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField), (PBYTE)&(pBuf->bySignalField) ); pBuf->wTransmitLength = cpu_to_le16(wLen); @@ -1221,7 +1221,7 @@ s_vFillCTSHead ( // Auto Fall back PSCTS_FB pBuf = (PSCTS_FB)pvCTS; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, + BBvCalculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b) ); pBuf->wTransmitLength_b = cpu_to_le16(wLen); @@ -1246,7 +1246,7 @@ s_vFillCTSHead ( } else { //if (byFBOption != AUTO_FB_NONE && uDMAIdx != TYPE_ATIMDMA && uDMAIdx != TYPE_BEACONDMA) PSCTS pBuf = (PSCTS)pvCTS; //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, + BBvCalculateParameter(pDevice, uCTSFrameLen, pDevice->byTopCCKBasicRate, PK_TYPE_11B, (PWORD)&(wLen), (PBYTE)&(pBuf->byServiceField_b), (PBYTE)&(pBuf->bySignalField_b) ); pBuf->wTransmitLength_b = cpu_to_le16(wLen); @@ -1827,7 +1827,7 @@ s_bPacketToWirelessUsb( * * Parameters: * In: - * pDevice - Pointer to adpater + * pDevice - Pointer to adapter * dwTxBufferAddr - Transmit Buffer * pPacket - Packet from upper layer * cbPacketSize - Transmit Data Length @@ -2198,7 +2198,7 @@ CMD_STATUS csMgmt_xmit( if (bIsPSPOLL) { // The MAC will automatically replace the Duration-field of MAC header by Duration-field - // of FIFO control header. + // of FIFO control header. // This will cause AID-field of PS-POLL packet be incorrect (Because PS-POLL's AID field is // in the same place of other packet's Duration-field). // And it will cause Cisco-AP to issue Disassociation-packet @@ -2272,7 +2272,7 @@ csBeacon_xmit( wCurrentRate = RATE_6M; pTxDataHead = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize); //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, cbFrameSize, wCurrentRate, PK_TYPE_11A, + BBvCalculateParameter(pDevice, cbFrameSize, wCurrentRate, PK_TYPE_11A, (PWORD)&(pTxDataHead->wTransmitLength), (PBYTE)&(pTxDataHead->byServiceField), (PBYTE)&(pTxDataHead->bySignalField) ); //Get Duration and TimeStampOff @@ -2285,7 +2285,7 @@ csBeacon_xmit( pTxBufHead->wFIFOCtl |= FIFOCTL_11B; pTxDataHead = (PSTxDataHead_ab) (pbyTxBufferAddr + wTxBufSize); //Get SignalField,ServiceField,Length - BBvCaculateParameter(pDevice, cbFrameSize, wCurrentRate, PK_TYPE_11B, + BBvCalculateParameter(pDevice, cbFrameSize, wCurrentRate, PK_TYPE_11B, (PWORD)&(pTxDataHead->wTransmitLength), (PBYTE)&(pTxDataHead->byServiceField), (PBYTE)&(pTxDataHead->bySignalField) ); //Get Duration and TimeStampOff @@ -2473,7 +2473,7 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb) { cbMacHdLen = WLAN_HDR_ADDR3_LEN; } - // hostapd deamon ext support rate patch + // hostapd daemon ext support rate patch if (WLAN_GET_FC_FSTYPE(p80211Header->sA4.wFrameCtl) == WLAN_FSTYPE_ASSOCRESP) { if (((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates)->len != 0) { @@ -2591,7 +2591,7 @@ vDMA0_tx_80211(PSDevice pDevice, struct sk_buff *skb) { pMACHeader->wFrameCtl &= cpu_to_le16(0xfffc); memcpy(pbyPayloadHead, (skb->data + cbMacHdLen), cbFrameBodySize); - // replace support rate, patch for hostapd deamon( only support 11M) + // replace support rate, patch for hostapd daemon( only support 11M) if (WLAN_GET_FC_FSTYPE(p80211Header->sA4.wFrameCtl) == WLAN_FSTYPE_ASSOCRESP) { if (cbExtSuppRate != 0) { if (((PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates)->len != 0) @@ -2770,7 +2770,7 @@ int nsDMA_tx_packet(PSDevice pDevice, unsigned int uDMAIdx, struct sk_buff *skb) pMgmt->abyPSTxMap[0] |= byMask[0]; return 0; } - // muticast/broadcast data rate + // multicast/broadcast data rate if (pDevice->byBBType != BB_TYPE_11A) pDevice->wCurrentRate = RATE_2M; @@ -2855,7 +2855,7 @@ int nsDMA_tx_packet(PSDevice pDevice, unsigned int uDMAIdx, struct sk_buff *skb) } PRINT_K("Authentication completed!!\n"); } - else if((Key_info & BIT3) && (Descriptor_type==2) && //RSN pairse-key challenge + else if((Key_info & BIT3) && (Descriptor_type==2) && //RSN pairwise-key challenge (Key_info & BIT8) && (Key_info & BIT9)) { pDevice->fWPA_Authened = TRUE; PRINT_K("WPA2 Authentication completed!!\n"); diff --git a/drivers/staging/vt6656/tcrc.c b/drivers/staging/vt6656/tcrc.c index e25021e850a0..2237eeb5ec5b 100644 --- a/drivers/staging/vt6656/tcrc.c +++ b/drivers/staging/vt6656/tcrc.c @@ -18,7 +18,7 @@ * * File: tcrc.c * - * Purpose: Implement functions to caculate CRC + * Purpose: Implement functions to calculate CRC * * Author: Tevin Chen * diff --git a/drivers/staging/vt6656/tcrc.h b/drivers/staging/vt6656/tcrc.h index 4dfd01e477a4..dc54bd8fc4fc 100644 --- a/drivers/staging/vt6656/tcrc.h +++ b/drivers/staging/vt6656/tcrc.h @@ -18,7 +18,7 @@ * * File: tcrc.h * - * Purpose: Implement functions to caculate CRC + * Purpose: Implement functions to calculate CRC * * Author: Tevin Chen * diff --git a/drivers/staging/vt6656/tether.c b/drivers/staging/vt6656/tether.c index 4f368f174b21..083b2153a271 100644 --- a/drivers/staging/vt6656/tether.c +++ b/drivers/staging/vt6656/tether.c @@ -25,7 +25,7 @@ * Date: May 21, 1996 * * Functions: - * ETHbyGetHashIndexByCrc32 - Caculate multicast hash value by CRC32 + * ETHbyGetHashIndexByCrc32 - Calculate multicast hash value by CRC32 * ETHbIsBufferCrc32Ok - Check CRC value of the buffer if Ok or not * * Revision History: @@ -50,7 +50,7 @@ /* - * Description: Caculate multicast hash value by CRC32 + * Description: Calculate multicast hash value by CRC32 * * Parameters: * In: diff --git a/drivers/staging/vt6656/tkip.c b/drivers/staging/vt6656/tkip.c index 0715636cb9cb..003123e550f6 100644 --- a/drivers/staging/vt6656/tkip.c +++ b/drivers/staging/vt6656/tkip.c @@ -168,7 +168,7 @@ static unsigned int rotr1(unsigned int a) /* - * Description: Caculate RC4Key fom TK, TA, and TSC + * Description: Calculate RC4Key fom TK, TA, and TSC * * Parameters: * In: diff --git a/drivers/staging/vt6656/wcmd.c b/drivers/staging/vt6656/wcmd.c index 9d2caa819f47..586fbe1627f7 100644 --- a/drivers/staging/vt6656/wcmd.c +++ b/drivers/staging/vt6656/wcmd.c @@ -263,7 +263,7 @@ s_vProbeChannel( * * * Return Value: - * A ptr to Tx frame or NULL on allocation failue + * A ptr to Tx frame or NULL on allocation failure * -*/ @@ -751,7 +751,7 @@ void vRunCommand(void *hDeviceContext) pDevice->nTxDataTimeCout = 0; } else { - // printk("mike:-->First time triger TimerTxData InSleep\n"); + // printk("mike:-->First time trigger TimerTxData InSleep\n"); } pDevice->IsTxDataTrigger = TRUE; add_timer(&pDevice->sTimerTxData); @@ -794,7 +794,7 @@ void vRunCommand(void *hDeviceContext) DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "vMgrCreateOwnIBSS fail!\n"); } - // alway turn off unicast bit + // always turn off unicast bit MACvRegBitsOff(pDevice, MAC_REG_RCR, RCR_UNICAST); pDevice->byRxMode &= ~RCR_UNICAST; DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "wcmd: rx_mode = %x\n", pDevice->byRxMode ); @@ -946,7 +946,7 @@ void vRunCommand(void *hDeviceContext) pItemSSID = (PWLAN_IE_SSID)pMgmt->abyCurrSSID; pItemSSID->len = 0; memset(pItemSSID->abySSID, 0, WLAN_SSID_MAXLEN); - //clear dessire SSID + //clear desired SSID pItemSSID = (PWLAN_IE_SSID)pMgmt->abyDesireSSID; pItemSSID->len = 0; memset(pItemSSID->abySSID, 0, WLAN_SSID_MAXLEN); diff --git a/drivers/staging/vt6656/wctl.c b/drivers/staging/vt6656/wctl.c index c231ae7176f5..9249263b2da8 100644 --- a/drivers/staging/vt6656/wctl.c +++ b/drivers/staging/vt6656/wctl.c @@ -89,7 +89,7 @@ BOOL WCTLbIsDuplicate (PSCache pCache, PS802_11Header pMACHeader) ADD_ONE_WITH_WRAP_AROUND(uIndex, DUPLICATE_RX_CACHE_LENGTH); } } - /* Not fount in cache - insert */ + /* Not found in cache - insert */ pCacheEntry = &pCache->asCacheEntry[pCache->uInPtr]; pCacheEntry->wFmSequence = pMACHeader->wSeqCtl; memcpy(&(pCacheEntry->abyAddr2[0]), &(pMACHeader->abyAddr2[0]), ETH_ALEN); diff --git a/drivers/staging/vt6656/wmgr.c b/drivers/staging/vt6656/wmgr.c index f08e2d15c7b3..7db6a8d3508b 100644 --- a/drivers/staging/vt6656/wmgr.c +++ b/drivers/staging/vt6656/wmgr.c @@ -27,7 +27,7 @@ * * Functions: * nsMgrObjectInitial - Initialize Management Objet data structure - * vMgrObjectReset - Reset Management Objet data structure + * vMgrObjectReset - Reset Management Object data structure * vMgrAssocBeginSta - Start associate function * vMgrReAssocBeginSta - Start reassociate function * vMgrDisassocBeginSta - Start disassociate function @@ -54,7 +54,7 @@ * bMgrPrepareBeaconToSend - Prepare Beacon frame * s_vMgrLogStatus - Log 802.11 Status * vMgrRxManagePacket - Rcv management frame dispatch function - * s_vMgrFormatTIM- Assember TIM field of beacon + * s_vMgrFormatTIM- Assembler TIM field of beacon * vMgrTimerInit- Initial 1-sec and command call back funtions * * Revision History: @@ -2032,7 +2032,7 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE) } // - // Preamble may change dynamiclly + // Preamble may change dynamically // byOldPreambleType = pDevice->byPreambleType; if (WLAN_GET_CAP_INFO_SHORTPREAMBLE(pBSSList->wCapInfo)) { @@ -2044,7 +2044,7 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE) if (pDevice->byPreambleType != byOldPreambleType) CARDvSetRSPINF(pDevice, (BYTE)pDevice->byBBType); // - // Basic Rate Set may change dynamiclly + // Basic Rate Set may change dynamically // if (pBSSList->eNetworkTypeInUse == PHY_TYPE_11B) { uRateLen = WLAN_RATES_MAXLEN_11B; @@ -2188,7 +2188,7 @@ if(ChannelExceedZoneType(pDevice,byCurrChannel)==TRUE) // During dpc, already in spinlocked. if (BSSbIsSTAInNodeDB(pDevice, sFrame.pHdr->sA3.abyAddr2, &uNodeIndex)) { - // Update the STA, (Techically the Beacons of all the IBSS nodes + // Update the STA, (Technically the Beacons of all the IBSS nodes // should be identical, but that's not happening in practice. pMgmt->abyCurrSuppRates[1] = RATEuSetIE((PWLAN_IE_SUPP_RATES)sFrame.pSuppRates, (PWLAN_IE_SUPP_RATES)pMgmt->abyCurrSuppRates, @@ -2722,7 +2722,7 @@ void vMgrJoinBSSBegin(void *hDeviceContext, PCMD_STATUS pStatus) memcpy(pDevice->abyBSSID, pCurr->abyBSSID, WLAN_BSSID_LEN); // Add current BSS to Candidate list - // This should only works for WPA2 BSS, and WPA2 BSS check must be done before. + // This should only work for WPA2 BSS, and WPA2 BSS check must be done before. if (pMgmt->eAuthenMode == WMAC_AUTH_WPA2) { BOOL bResult = bAdd_PMKID_Candidate((void *) pDevice, pMgmt->abyCurrBSSID, @@ -3181,7 +3181,7 @@ s_vMgrFormatTIM( * * * Return Value: - * PTR to frame; or NULL on allocation failue + * PTR to frame; or NULL on allocation failure * -*/ @@ -3353,7 +3353,7 @@ s_MgrMakeBeacon( * * * Return Value: - * PTR to frame; or NULL on allocation failue + * PTR to frame; or NULL on allocation failure * -*/ @@ -3528,7 +3528,7 @@ s_MgrMakeAssocRequest( memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); - // Set the capibility and listen interval + // Set the capability and listen interval *(sFrame.pwCapInfo) = cpu_to_le16(wCurrCapInfo); *(sFrame.pwListenInterval) = cpu_to_le16(wListenInterval); @@ -3749,7 +3749,7 @@ s_MgrMakeAssocRequest( * * * Return Value: - * A ptr to frame or NULL on allocation failue + * A ptr to frame or NULL on allocation failure * -*/ @@ -3792,7 +3792,7 @@ s_MgrMakeReAssocRequest( memcpy( sFrame.pHdr->sA3.abyAddr2, pMgmt->abyMACAddr, WLAN_ADDR_LEN); memcpy( sFrame.pHdr->sA3.abyAddr3, pMgmt->abyCurrBSSID, WLAN_BSSID_LEN); - /* Set the capibility and listen interval */ + /* Set the capability and listen interval */ *(sFrame.pwCapInfo) = cpu_to_le16(wCurrCapInfo); *(sFrame.pwListenInterval) = cpu_to_le16(wListenInterval); @@ -4004,7 +4004,7 @@ s_MgrMakeReAssocRequest( * * * Return Value: - * PTR to frame; or NULL on allocation failue + * PTR to frame; or NULL on allocation failure * -*/ @@ -4077,7 +4077,7 @@ s_MgrMakeAssocResponse( * * * Return Value: - * PTR to frame; or NULL on allocation failue + * PTR to frame; or NULL on allocation failure * -*/ diff --git a/drivers/staging/vt6656/wpa.c b/drivers/staging/vt6656/wpa.c index b16d4ddc117b..f6429a26ae0f 100644 --- a/drivers/staging/vt6656/wpa.c +++ b/drivers/staging/vt6656/wpa.c @@ -231,7 +231,7 @@ WPA_ParseRSN( * Parameters: * In: * byCmd - Search type - * byEncrypt- Encrcypt Type + * byEncrypt- Encrypt Type * pBSSList - BSS list * Out: * none diff --git a/drivers/staging/vt6656/wpa2.c b/drivers/staging/vt6656/wpa2.c index d4f3f7530ee4..c0926976627d 100644 --- a/drivers/staging/vt6656/wpa2.c +++ b/drivers/staging/vt6656/wpa2.c @@ -174,16 +174,16 @@ WPA2vParseRSN ( pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_USE_GROUP; bUseGK = TRUE; } else if ( !memcmp(pbyOUI, abyOUIWEP40, 4)) { - // Invialid CSS, continue to parsing + // Invalid CSS, continue parsing } else if ( !memcmp(pbyOUI, abyOUITKIP, 4)) { if (pBSSNode->byCSSGK != WLAN_11i_CSS_CCMP) pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_TKIP; else - ; // Invialid CSS, continue to parsing + ; // Invalid CSS, continue parsing } else if ( !memcmp(pbyOUI, abyOUICCMP, 4)) { pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_CCMP; } else if ( !memcmp(pbyOUI, abyOUIWEP104, 4)) { - // Invialid CSS, continue to parsing + // Invalid CSS, continue parsing } else { // any vendor checks here pBSSNode->abyCSSPK[j++] = WLAN_11i_CSS_UNKNOWN; diff --git a/drivers/staging/vt6656/wpactl.c b/drivers/staging/vt6656/wpactl.c index 5435e8205b2c..3e65aa132011 100644 --- a/drivers/staging/vt6656/wpactl.c +++ b/drivers/staging/vt6656/wpactl.c @@ -74,7 +74,7 @@ static void wpadev_setup(struct net_device *dev) /* * Description: - * register netdev for wpa supplicant deamon + * register netdev for wpa supplicant daemon * * Parameters: * In: @@ -154,7 +154,7 @@ static int wpa_release_wpadev(PSDevice pDevice) /* * Description: - * Set enable/disable dev for wpa supplicant deamon + * Set enable/disable dev for wpa supplicant daemon * * Parameters: * In: @@ -326,7 +326,7 @@ int wpa_set_wpadev(PSDevice pDevice, int val) if ((byKeyDecMode == KEY_CTL_TKIP) && (param->u.wpa_key.key_len != MAX_KEY_LEN)) { // TKIP Key must be 256 bits - DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "return- TKIP Key must be 256 bits!\n"); + DBG_PRT(MSG_LEVEL_DEBUG, KERN_INFO "return - TKIP Key must be 256 bits!\n"); return -EINVAL; } // Check AES key length diff --git a/drivers/staging/winbond/Kconfig b/drivers/staging/winbond/Kconfig index 132671d96d0d..a29f60836b77 100644 --- a/drivers/staging/winbond/Kconfig +++ b/drivers/staging/winbond/Kconfig @@ -1,6 +1,6 @@ config W35UND tristate "IS89C35 WLAN USB driver" - depends on MAC80211 && WLAN && USB && EXPERIMENTAL + depends on MAC80211 && WLAN && USB default n ---help--- This is highly experimental driver for Winbond WIFI card. diff --git a/drivers/staging/winbond/localpara.h b/drivers/staging/winbond/localpara.h index d7980575bed1..84effc47d79d 100644 --- a/drivers/staging/winbond/localpara.h +++ b/drivers/staging/winbond/localpara.h @@ -137,7 +137,7 @@ struct wb_local_para { u8 iPowerSaveMode; /* 0 indicates on, 1 indicates off */ u8 ATIMmode; u8 ExcludeUnencrypted; - /* Unit ime count for the decision to enter PS mode */ + /* Unit time count for the decision to enter PS mode */ u16 CheckCountForPS; u8 boHasTxActivity;/* tx activity has occurred */ u8 boMacPsValid; /* Power save mode obtained from H/W is valid or not */ @@ -187,7 +187,7 @@ struct wb_local_para { u8 reserved7[3]; struct chan_info CurrentChan; /* Current channel no. and channel band. It may be changed by scanning. */ - u8 boHandover; /* Roaming, Hnadover to other AP. */ + u8 boHandover; /* Roaming, Handover to other AP. */ u8 boCCAbusy; u16 CWMax; /* It may not be the real value that H/W used */ diff --git a/drivers/staging/winbond/mds.c b/drivers/staging/winbond/mds.c index c9f0e8f856a0..1b8b8ace39e0 100644 --- a/drivers/staging/winbond/mds.c +++ b/drivers/staging/winbond/mds.c @@ -569,7 +569,7 @@ Mds_SendComplete(struct wbsoft_priv *adapter, struct T02_descriptor *pT02) unsigned char SendOK = true; u8 RetryCount, TxRate; - if (pT02->T02_IgnoreResult) /* Don't care the result */ + if (pT02->T02_IgnoreResult) /* Don't care about the result */ return; if (pT02->T02_IsLastMpdu) { /* TODO: DTO -- get the retry count and fragment count */ diff --git a/drivers/staging/winbond/mto.c b/drivers/staging/winbond/mto.c index 1b52ebd4b011..560c0ab617d1 100644 --- a/drivers/staging/winbond/mto.c +++ b/drivers/staging/winbond/mto.c @@ -23,7 +23,7 @@ #include "core.h" /* Declare SQ3 to rate and fragmentation threshold table */ -/* Declare fragmentation thresholds table */ +/* Declare fragmentation threshold table */ #define MTO_MAX_FRAG_TH_LEVELS 5 #define MTO_MAX_DATA_RATE_LEVELS 12 diff --git a/drivers/staging/winbond/phy_calibration.c b/drivers/staging/winbond/phy_calibration.c index 77a3fff708c6..cabae3466704 100644 --- a/drivers/staging/winbond/phy_calibration.c +++ b/drivers/staging/winbond/phy_calibration.c @@ -399,7 +399,7 @@ void _rxadc_dc_offset_cancellation_winbond(struct hw_data *phw_data, u32 frequen val |= MASK_ADC_DC_CAL_STR; hw_set_dxx_reg(phw_data, REG_MODE_CTRL, val); - /* e. The result are shown in "adc_dc_cal_i[8:0] and adc_dc_cal_q[8:0]" */ + /* e. The results are shown in "adc_dc_cal_i[8:0] and adc_dc_cal_q[8:0]" */ #ifdef _DEBUG hw_get_dxx_reg(phw_data, REG_OFFSET_READ, &val); PHY_DEBUG(("[CAL] REG_OFFSET_READ = 0x%08X\n", val)); @@ -720,7 +720,7 @@ u8 _tx_iq_calibration_loop_winbond(struct hw_data *phw_data, for (capture_time = 0; capture_time < 10; capture_time++) { /* * a. Set iqcal_mode[1:0] to 0x2 and set "calib_start" to 0x1 to - * enable "IQ alibration Mode II" + * enable "IQ calibration Mode II" */ reg_mode_ctrl &= ~(MASK_IQCAL_TONE_SEL|MASK_IQCAL_MODE); reg_mode_ctrl &= ~MASK_IQCAL_MODE; @@ -750,7 +750,7 @@ u8 _tx_iq_calibration_loop_winbond(struct hw_data *phw_data, /* * d. Set iqcal_mode[1:0] to 0x3 and set "calib_start" to 0x1 to - * enable "IQ alibration Mode II" + * enable "IQ calibration Mode II" */ /* hw_get_dxx_reg(phw_data, REG_MODE_CTRL, &val); */ hw_get_dxx_reg(phw_data, REG_MODE_CTRL, ®_mode_ctrl); @@ -980,7 +980,7 @@ void _tx_iq_calibration_winbond(struct hw_data *phw_data) phy_set_rf_data(phw_data, 0, (0<<24)|0xFDF1C0); /* ; [BB-chip]: Calibration (6f).Send test pattern */ /* ; [BB-chip]: Calibration (6g). Search RXGCL optimal value */ - /* ; [BB-chip]: Calibration (6h). Caculate TX-path IQ imbalance and setting TX path IQ compensation table */ + /* ; [BB-chip]: Calibration (6h). Calculate TX-path IQ imbalance and setting TX path IQ compensation table */ /* phy_set_rf_data(phw_data, 3, (3<<24)|0x025586); */ msleep(30); /* 20060612.1.a 30ms delay. Add the follow 2 lines */ @@ -1373,7 +1373,7 @@ u8 _rx_iq_calibration_loop_winbond(struct hw_data *phw_data, u16 factor, u32 fre /***************************************************************/ void _rx_iq_calibration_winbond(struct hw_data *phw_data, u32 frequency) { -/* figo 20050523 marked this flag for can't compile for relesase */ +/* figo 20050523 marked this flag for can't compile for release */ #ifdef _DEBUG s32 rx_cal_reg[4]; u32 val; @@ -1397,7 +1397,7 @@ void _rx_iq_calibration_winbond(struct hw_data *phw_data, u32 frequency) /* ; [BB-chip]: Calibration (7f). Send test pattern */ /* ; [BB-chip]: Calibration (7g). Search RXGCL optimal value */ - /* ; [BB-chip]: Calibration (7h). Caculate RX-path IQ imbalance and setting RX path IQ compensation table */ + /* ; [BB-chip]: Calibration (7h). Calculate RX-path IQ imbalance and setting RX path IQ compensation table */ result = _rx_iq_calibration_loop_winbond(phw_data, 12589, frequency); @@ -1454,7 +1454,7 @@ void phy_calibration_winbond(struct hw_data *phw_data, u32 frequency) _rxadc_dc_offset_cancellation_winbond(phw_data, frequency); /* _txidac_dc_offset_cancellation_winbond(phw_data); */ - /* _txqdac_dc_offset_cacellation_winbond(phw_data); */ + /* _txqdac_dc_offset_cancellation_winbond(phw_data); */ _tx_iq_calibration_winbond(phw_data); _rx_iq_calibration_winbond(phw_data, frequency); diff --git a/drivers/staging/winbond/reg.c b/drivers/staging/winbond/reg.c index 1b38d6d225c9..5ecf9a121e78 100644 --- a/drivers/staging/winbond/reg.c +++ b/drivers/staging/winbond/reg.c @@ -693,7 +693,7 @@ u32 w89rf242_rf_data[] = { (0x0E << 24) | 0x5557DC, /* 1555F ; IBSC (0x0E) -- IRLNA & IRLNB (PTAT & Const current)=01/01; FA5976B_1.3F */ (0x10 << 24) | 0x000C20, /* 00030 ; TMODA (0x10) -- LNA_gain_step=0011 ; LNA=15/16dB */ (0x11 << 24) | 0x0C0022, /* 03000 ; TMODB (0x11) -- Turn ON RX-Q path Test Switch; To improve IQ path group delay (FA5976A_1.3C) */ - (0x12 << 24) | 0x000024 /* TMODC (0x12) -- Turn OFF Tempearure sensor */ + (0x12 << 24) | 0x000024 /* TMODC (0x12) -- Turn OFF Temperature sensor */ }; u32 w89rf242_channel_data_24[][2] = { diff --git a/drivers/staging/winbond/sme_api.h b/drivers/staging/winbond/sme_api.h index 8f4596c9e9b3..652ae7085a5f 100644 --- a/drivers/staging/winbond/sme_api.h +++ b/drivers/staging/winbond/sme_api.h @@ -12,7 +12,6 @@ #include "localpara.h" /****************** CONSTANT AND MACRO SECTION ******************************/ -#define _INLINE __inline #define MEDIA_STATE_DISCONNECTED 0 #define MEDIA_STATE_CONNECTED 1 @@ -26,17 +25,17 @@ /* OID_802_11_BSSID */ s8 sme_get_bssid(void *pcore_data, u8 *pbssid); -s8 sme_get_desired_bssid(void *pcore_data, u8 *pbssid); /* Not use */ +s8 sme_get_desired_bssid(void *pcore_data, u8 *pbssid); /* Unused */ s8 sme_set_desired_bssid(void *pcore_data, u8 *pbssid); /* OID_802_11_SSID */ s8 sme_get_ssid(void *pcore_data, u8 *pssid, u8 *pssid_len); -s8 sme_get_desired_ssid(void *pcore_data, u8 *pssid, u8 *pssid_len);/* Not use */ +s8 sme_get_desired_ssid(void *pcore_data, u8 *pssid, u8 *pssid_len);/* Unused */ s8 sme_set_desired_ssid(void *pcore_data, u8 *pssid, u8 ssid_len); /* OID_802_11_INFRASTRUCTURE_MODE */ s8 sme_get_bss_type(void *pcore_data, u8 *pbss_type); -s8 sme_get_desired_bss_type(void *pcore_data, u8 *pbss_type); /* Not use */ +s8 sme_get_desired_bss_type(void *pcore_data, u8 *pbss_type); /* Unused */ s8 sme_set_desired_bss_type(void *pcore_data, u8 bss_type); /* OID_802_11_FRAGMENTATION_THRESHOLD */ @@ -107,7 +106,7 @@ s8 sme_set_bssid_list_scan(void *pcore_data, void *pscan_para); s8 sme_set_reload_defaults(void *pcore_data, u8 reload_type); -/*------------------------- none-standard ----------------------------------*/ +/*------------------------- non-standard ----------------------------------*/ s8 sme_get_connect_status(void *pcore_data, u8 *pstatus); /*--------------------------------------------------------------------------*/ @@ -138,7 +137,7 @@ s8 sme_set_txrate_policy(void *pcore_data, u8 policy); s8 sme_get_txrate_policy(void *pcore_data, u8 *policy); s8 sme_get_cwmin_value(void *pcore_data, u8 *cwmin); s8 sme_get_cwmax_value(void *pcore_data, u16 *cwmax); -s8 sme_get_ms_radio_mode(void *pcore_data, u8 * pMsRadioOff); +s8 sme_get_ms_radio_mode(void *pcore_data, u8 *pMsRadioOff); s8 sme_set_ms_radio_mode(void *pcore_data, u8 boMsRadioOff); void sme_get_tx_power_level(void *pcore_data, u32 *TxPower); diff --git a/drivers/staging/winbond/wb35reg.c b/drivers/staging/winbond/wb35reg.c index da595f16f634..1bff7d1c9a77 100644 --- a/drivers/staging/winbond/wb35reg.c +++ b/drivers/staging/winbond/wb35reg.c @@ -217,7 +217,7 @@ unsigned char Wb35Reg_Write(struct hw_data *pHwData, u16 RegisterNo, u32 Registe * This command will be executed with a user defined value. When it completes, * this value is useful. For example, hal_set_current_channel will use it. * true : read command process successfully - * false : register not support + * false : register not supported */ unsigned char Wb35Reg_WriteWithCallbackValue(struct hw_data *pHwData, u16 RegisterNo, @@ -631,7 +631,7 @@ unsigned char Wb35Reg_initial(struct hw_data *pHwData) * CardComputeCrc -- * * Description: - * Runs the AUTODIN II CRC algorithm on buffer Buffer of length, Length. + * Runs the AUTODIN II CRC algorithm on the buffers Buffer length. * * Arguments: * Buffer - the input buffer diff --git a/drivers/staging/winbond/wb35tx.c b/drivers/staging/winbond/wb35tx.c index 5df39d46cda4..30a77ccfe480 100644 --- a/drivers/staging/winbond/wb35tx.c +++ b/drivers/staging/winbond/wb35tx.c @@ -1,13 +1,13 @@ -//============================================================================ -// Copyright (c) 1996-2002 Winbond Electronic Corporation -// -// Module Name: -// Wb35Tx.c -// -// Abstract: -// Processing the Tx message and put into down layer -// -//============================================================================ +/* + * Copyright (c) 1996-2002 Winbond Electronic Corporation + * + * Module Name: + * Wb35Tx.c + * + * Abstract: + * Processing the Tx message and put into down layer + * + */ #include <linux/usb.h> #include <linux/gfp.h> @@ -15,7 +15,7 @@ #include "mds_f.h" unsigned char -Wb35Tx_get_tx_buffer(struct hw_data * pHwData, u8 **pBuffer) +Wb35Tx_get_tx_buffer(struct hw_data *pHwData, u8 **pBuffer) { struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; @@ -25,28 +25,29 @@ Wb35Tx_get_tx_buffer(struct hw_data * pHwData, u8 **pBuffer) static void Wb35Tx(struct wbsoft_priv *adapter); -static void Wb35Tx_complete(struct urb * pUrb) +static void Wb35Tx_complete(struct urb *pUrb) { struct wbsoft_priv *adapter = pUrb->context; - struct hw_data * pHwData = &adapter->sHwData; + struct hw_data *pHwData = &adapter->sHwData; struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; struct wb35_mds *pMds = &adapter->Mds; printk("wb35: tx complete\n"); - // Variable setting + /* Variable setting */ pWb35Tx->EP4vm_state = VM_COMPLETED; - pWb35Tx->EP4VM_status = pUrb->status; //Store the last result of Irp - pMds->TxOwner[ pWb35Tx->TxSendIndex ] = 0;// Set the owner. Free the owner bit always. + pWb35Tx->EP4VM_status = pUrb->status; /* Store the last result of Irp */ + /* Set the owner. Free the owner bit always. */ + pMds->TxOwner[pWb35Tx->TxSendIndex] = 0; pWb35Tx->TxSendIndex++; pWb35Tx->TxSendIndex %= MAX_USB_TX_BUFFER_NUMBER; - if (pHwData->SurpriseRemove) // Let WbWlanHalt to handle surprise remove + if (pHwData->SurpriseRemove) /* Let WbWlanHalt handle surprise remove */ goto error; if (pWb35Tx->tx_halt) goto error; - // The URB is completed, check the result + /* The URB is completed, check the result */ if (pWb35Tx->EP4VM_status != 0) { printk("URB submission failed\n"); pWb35Tx->EP4vm_state = VM_STOP; @@ -64,43 +65,42 @@ error: static void Wb35Tx(struct wbsoft_priv *adapter) { - struct hw_data * pHwData = &adapter->sHwData; + struct hw_data *pHwData = &adapter->sHwData; struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; u8 *pTxBufferAddress; struct wb35_mds *pMds = &adapter->Mds; - struct urb * pUrb = (struct urb *)pWb35Tx->Tx4Urb; - int retv; + struct urb *pUrb = (struct urb *)pWb35Tx->Tx4Urb; + int retv; u32 SendIndex; - if (pHwData->SurpriseRemove) goto cleanup; if (pWb35Tx->tx_halt) goto cleanup; - // Ownership checking + /* Ownership checking */ SendIndex = pWb35Tx->TxSendIndex; - if (!pMds->TxOwner[SendIndex]) //No more data need to be sent, return immediately + /* No more data need to be sent, return immediately */ + if (!pMds->TxOwner[SendIndex]) goto cleanup; pTxBufferAddress = pWb35Tx->TxBuffer[SendIndex]; - // - // Issuing URB - // + + /* Issuing URB */ usb_fill_bulk_urb(pUrb, pHwData->udev, usb_sndbulkpipe(pHwData->udev, 4), - pTxBufferAddress, pMds->TxBufferSize[ SendIndex ], + pTxBufferAddress, pMds->TxBufferSize[SendIndex], Wb35Tx_complete, adapter); pWb35Tx->EP4vm_state = VM_RUNNING; retv = usb_submit_urb(pUrb, GFP_ATOMIC); - if (retv<0) { + if (retv < 0) { printk("EP4 Tx Irp sending error\n"); goto cleanup; } - // Check if driver needs issue Irp for EP2 + /* Check if driver needs issue Irp for EP2 */ pWb35Tx->TxFillCount += pMds->TxCountInBuffer[SendIndex]; if (pWb35Tx->TxFillCount > 12) Wb35Tx_EP2VM_start(adapter); @@ -115,10 +115,10 @@ static void Wb35Tx(struct wbsoft_priv *adapter) void Wb35Tx_start(struct wbsoft_priv *adapter) { - struct hw_data * pHwData = &adapter->sHwData; + struct hw_data *pHwData = &adapter->sHwData; struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; - // Allow only one thread to run into function + /* Allow only one thread to run into function */ if (atomic_inc_return(&pWb35Tx->TxFireCounter) == 1) { pWb35Tx->EP4vm_state = VM_RUNNING; Wb35Tx(adapter); @@ -126,7 +126,7 @@ void Wb35Tx_start(struct wbsoft_priv *adapter) atomic_dec(&pWb35Tx->TxFireCounter); } -unsigned char Wb35Tx_initial(struct hw_data * pHwData) +unsigned char Wb35Tx_initial(struct hw_data *pHwData) { struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; @@ -135,54 +135,50 @@ unsigned char Wb35Tx_initial(struct hw_data * pHwData) return false; pWb35Tx->Tx2Urb = usb_alloc_urb(0, GFP_ATOMIC); - if (!pWb35Tx->Tx2Urb) - { - usb_free_urb( pWb35Tx->Tx4Urb ); + if (!pWb35Tx->Tx2Urb) { + usb_free_urb(pWb35Tx->Tx4Urb); return false; } return true; } -//====================================================== -void Wb35Tx_stop(struct hw_data * pHwData) +void Wb35Tx_stop(struct hw_data *pHwData) { struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; - // Trying to canceling the Trp of EP2 + /* Try to cancel the Trp of EP2 */ if (pWb35Tx->EP2vm_state == VM_RUNNING) - usb_unlink_urb( pWb35Tx->Tx2Urb ); // Only use unlink, let Wb35Tx_destrot to free them + /* Only use unlink, let Wb35Tx_destroy free them */ + usb_unlink_urb(pWb35Tx->Tx2Urb); pr_debug("EP2 Tx stop\n"); - // Trying to canceling the Irp of EP4 + /* Try to cancel the Irp of EP4 */ if (pWb35Tx->EP4vm_state == VM_RUNNING) - usb_unlink_urb( pWb35Tx->Tx4Urb ); // Only use unlink, let Wb35Tx_destrot to free them + /* Only use unlink, let Wb35Tx_destroy free them */ + usb_unlink_urb(pWb35Tx->Tx4Urb); pr_debug("EP4 Tx stop\n"); } -//====================================================== -void Wb35Tx_destroy(struct hw_data * pHwData) +void Wb35Tx_destroy(struct hw_data *pHwData) { struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; - // Wait for VM stop + /* Wait for VM stop */ do { - msleep(10); // Delay for waiting function enter 940623.1.a - } while( (pWb35Tx->EP2vm_state != VM_STOP) && (pWb35Tx->EP4vm_state != VM_STOP) ); - msleep(10); // Delay for waiting function enter 940623.1.b - - if (pWb35Tx->Tx4Urb) - usb_free_urb( pWb35Tx->Tx4Urb ); + msleep(10); /* Delay for waiting function enter 940623.1.a */ + } while ((pWb35Tx->EP2vm_state != VM_STOP) && (pWb35Tx->EP4vm_state != VM_STOP)); + msleep(10); /* Delay for waiting function enter 940623.1.b */ - if (pWb35Tx->Tx2Urb) - usb_free_urb( pWb35Tx->Tx2Urb ); + usb_free_urb(pWb35Tx->Tx4Urb); + usb_free_urb(pWb35Tx->Tx2Urb); pr_debug("Wb35Tx_destroy OK\n"); } void Wb35Tx_CurrentTime(struct wbsoft_priv *adapter, u32 TimeCount) { - struct hw_data * pHwData = &adapter->sHwData; + struct hw_data *pHwData = &adapter->sHwData; struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; unsigned char Trigger = false; @@ -199,46 +195,45 @@ void Wb35Tx_CurrentTime(struct wbsoft_priv *adapter, u32 TimeCount) static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter); -static void Wb35Tx_EP2VM_complete(struct urb * pUrb) +static void Wb35Tx_EP2VM_complete(struct urb *pUrb) { struct wbsoft_priv *adapter = pUrb->context; - struct hw_data * pHwData = &adapter->sHwData; + struct hw_data *pHwData = &adapter->sHwData; struct T02_descriptor T02, TSTATUS; struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; - u32 * pltmp = (u32 *)pWb35Tx->EP2_buf; + u32 *pltmp = (u32 *)pWb35Tx->EP2_buf; u32 i; u16 InterruptInLength; - - // Variable setting + /* Variable setting */ pWb35Tx->EP2vm_state = VM_COMPLETED; pWb35Tx->EP2VM_status = pUrb->status; - // For Linux 2.4. Interrupt will always trigger - if (pHwData->SurpriseRemove) // Let WbWlanHalt to handle surprise remove + /* For Linux 2.4. Interrupt will always trigger */ + if (pHwData->SurpriseRemove) /* Let WbWlanHalt handle surprise remove */ goto error; if (pWb35Tx->tx_halt) goto error; - //The Urb is completed, check the result + /* The Urb is completed, check the result */ if (pWb35Tx->EP2VM_status != 0) { printk("EP2 IoCompleteRoutine return error\n"); - pWb35Tx->EP2vm_state= VM_STOP; + pWb35Tx->EP2vm_state = VM_STOP; goto error; } - // Update the Tx result + /* Update the Tx result */ InterruptInLength = pUrb->actual_length; - // Modify for minimum memory access and DWORD alignment. - T02.value = cpu_to_le32(pltmp[0]) >> 8; // [31:8] -> [24:0] - InterruptInLength -= 1;// 20051221.1.c Modify the follow for more stable - InterruptInLength >>= 2; // InterruptInLength/4 + /* Modify for minimum memory access and DWORD alignment. */ + T02.value = cpu_to_le32(pltmp[0]) >> 8; /* [31:8] -> [24:0] */ + InterruptInLength -= 1; /* 20051221.1.c Modify the follow for more stable */ + InterruptInLength >>= 2; /* InterruptInLength/4 */ for (i = 1; i <= InterruptInLength; i++) { T02.value |= ((cpu_to_le32(pltmp[i]) & 0xff) << 24); - TSTATUS.value = T02.value; //20061009 anson's endian - Mds_SendComplete( adapter, &TSTATUS ); + TSTATUS.value = T02.value; /* 20061009 anson's endian */ + Mds_SendComplete(adapter, &TSTATUS); T02.value = cpu_to_le32(pltmp[i]) >> 8; } @@ -250,10 +245,10 @@ error: static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter) { - struct hw_data * pHwData = &adapter->sHwData; + struct hw_data *pHwData = &adapter->sHwData; struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; - struct urb * pUrb = (struct urb *)pWb35Tx->Tx2Urb; - u32 * pltmp = (u32 *)pWb35Tx->EP2_buf; + struct urb *pUrb = (struct urb *)pWb35Tx->Tx2Urb; + u32 *pltmp = (u32 *)pWb35Tx->EP2_buf; int retv; if (pHwData->SurpriseRemove) @@ -262,11 +257,10 @@ static void Wb35Tx_EP2VM(struct wbsoft_priv *adapter) if (pWb35Tx->tx_halt) goto error; - // - // Issuing URB - // - usb_fill_int_urb( pUrb, pHwData->udev, usb_rcvintpipe(pHwData->udev,2), - pltmp, MAX_INTERRUPT_LENGTH, Wb35Tx_EP2VM_complete, adapter, 32); + /* Issuing URB */ + usb_fill_int_urb(pUrb, pHwData->udev, usb_rcvintpipe(pHwData->udev, 2), + pltmp, MAX_INTERRUPT_LENGTH, Wb35Tx_EP2VM_complete, + adapter, 32); pWb35Tx->EP2vm_state = VM_RUNNING; retv = usb_submit_urb(pUrb, GFP_ATOMIC); @@ -284,10 +278,10 @@ error: void Wb35Tx_EP2VM_start(struct wbsoft_priv *adapter) { - struct hw_data * pHwData = &adapter->sHwData; + struct hw_data *pHwData = &adapter->sHwData; struct wb35_tx *pWb35Tx = &pHwData->Wb35Tx; - // Allow only one thread to run into function + /* Allow only one thread to run into function */ if (atomic_inc_return(&pWb35Tx->TxResultCount) == 1) { pWb35Tx->EP2vm_state = VM_RUNNING; Wb35Tx_EP2VM(adapter); diff --git a/drivers/staging/winbond/wb35tx_s.h b/drivers/staging/winbond/wb35tx_s.h index f70f43395591..715f87d6ac5b 100644 --- a/drivers/staging/winbond/wb35tx_s.h +++ b/drivers/staging/winbond/wb35tx_s.h @@ -3,45 +3,37 @@ #include "mds_s.h" -//==================================== -// IS89C35 Tx related definition -//==================================== -#define TX_INTERFACE 0 // Interface 1 -#define TX_PIPE 3 // endpoint 4 -#define TX_INTERRUPT 1 // endpoint 2 -#define MAX_INTERRUPT_LENGTH 64 // It must be 64 for EP2 hardware - - - -//==================================== -// Internal variable for module -//==================================== - +/* IS89C35 Tx related definition */ +#define TX_INTERFACE 0 /* Interface 1 */ +#define TX_PIPE 3 /* Endpoint 4 */ +#define TX_INTERRUPT 1 /* Endpoint 2 */ +#define MAX_INTERRUPT_LENGTH 64 /* It must be 64 for EP2 hardware */ +/* Internal variable for module */ struct wb35_tx { - // For Tx buffer + /* For Tx buffer */ u8 TxBuffer[ MAX_USB_TX_BUFFER_NUMBER ][ MAX_USB_TX_BUFFER ]; - // For Interrupt pipe + /* For Interrupt pipe */ u8 EP2_buf[MAX_INTERRUPT_LENGTH]; - atomic_t TxResultCount;// For thread control of EP2 931130.4.m - atomic_t TxFireCounter;// For thread control of EP4 931130.4.n - u32 ByteTransfer; + atomic_t TxResultCount; /* For thread control of EP2 931130.4.m */ + atomic_t TxFireCounter; /* For thread control of EP4 931130.4.n */ + u32 ByteTransfer; - u32 TxSendIndex;// The next index of Mds array to be sent - u32 EP2vm_state; // for EP2vm state - u32 EP4vm_state; // for EP4vm state - u32 tx_halt; // Stopping VM + u32 TxSendIndex; /* The next index of Mds array to be sent */ + u32 EP2vm_state; /* for EP2vm state */ + u32 EP4vm_state; /* for EP4vm state */ + u32 tx_halt; /* Stopping VM */ - struct urb * Tx4Urb; - struct urb * Tx2Urb; + struct urb *Tx4Urb; + struct urb *Tx2Urb; int EP2VM_status; int EP4VM_status; - u32 TxFillCount; // 20060928 - u32 TxTimer; // 20060928 Add if sending packet not great than 13 + u32 TxFillCount; /* 20060928 */ + u32 TxTimer; /* 20060928 Add if sending packet is greater than 13 */ }; #endif diff --git a/drivers/staging/wlags49_h2/README.ubuntu b/drivers/staging/wlags49_h2/README.ubuntu index 5f1cfb8fd427..bfad7dc7725f 100644 --- a/drivers/staging/wlags49_h2/README.ubuntu +++ b/drivers/staging/wlags49_h2/README.ubuntu @@ -46,12 +46,12 @@ If you have a card using the HERMES II.5 chip you have to make changes to the Makefile and uncomment -DHERMES25. This will build driver wlags49_h25_cs. -Note: You can detemine the type with command "pccardctrl info" +Note: You can determine the type with command "pccardctrl info" MANIFID: 0156,0002 = HERMES - not supported by this driver MANIFID: 0156,0003 = HERMES II (Wireless B) MANIFID: 0156,0004 = HERMES II.5 (Wireless B/G) -After succesfull compile type command +After successful compile type command sudo make install @@ -81,7 +81,7 @@ The linux driver files (wl_xxxx.c) are changed in the following ways: - Addaptations of Andrey Borzenkov applied to 7.22 source - Alterations to avoid most HCF_ASSERTs -- Switching interrupts off and on in the HCF --- Bugfixes, things that were aparently wrong like reporting link status +-- Bugfixes, things that were apparently wrong like reporting link status change which checked a variable that was not changed in HCF anymore. -- Used on WEP but setting keys via SIOCSIWENCODEEXT was not supported -- Recovery actions added @@ -93,7 +93,7 @@ have to "open" the device first to get a handle and after "close" no changed; the former ioctl functions are now called before "open" and after "close", which was not expected. One of the problems was enable/ disable of interrupts in the HCF. Interrupt handling starts at "open" -so if a former "ioctl" routinge is called before "open" or after "close" +so if a former "ioctl" routine is called before "open" or after "close" then nothing should be done with interrupt switching in the HCF. Once this was solved most HCF_ASSERTS went away. @@ -120,8 +120,8 @@ include the man page. Even though setting parameters on the module does not work anymore but it provides some information about all the settings. -I have not have personal contact with Agere, but others have. Agere -agreed to make their software available under the BSD licence. +I have no personal contact with Agere, but others have. Agere +agreed to make their software available under the BSD license. This driver is based on the 7.22 version. The following was mailed by Agere to Andrey Borzenkov about this: diff --git a/drivers/staging/wlags49_h2/TODO b/drivers/staging/wlags49_h2/TODO index 94032b6ac2b5..f1a45611b236 100644 --- a/drivers/staging/wlags49_h2/TODO +++ b/drivers/staging/wlags49_h2/TODO @@ -1,4 +1,4 @@ -First of all, the best thing would be that this driver becomes obsolte by +First of all, the best thing would be that this driver becomes obsolete by adding support for Hermes II and Hermes II.5 cards to the existing orinoco driver. The orinoco driver currently only supports Hermes I based cards. Since this will not happen by magic and has not happened until now this @@ -10,11 +10,11 @@ list. TODO: - verify against a Hermes II.5 card - - verify with WPA encription (both with H2 and H2.5 cards) + - verify with WPA encryption (both with H2 and H2.5 cards) - sometimes the card does not initialize correctly, retry mechanisms - are build in to catch most cases but not all + are built in to catch most cases but not all - once the driver runs it is very stable, but I have the impression - some the crittical sections take to long + that some of the critical sections take some time. - the driver is split into a Hermes II and a Hermes II.5 part, it would be nice to handle both with one module instead of two - review by the wireless developer community @@ -25,7 +25,7 @@ TODO: DONE: - verified against a Hermes II card (Thomson Speedtouch 110 PCMCIA card) - - verified with WEP encription + - verified with WEP encryption Please send any patches or complaints about this driver to Greg Kroah-Hartman <greg@kroah.com> and Cc: Henk de Groot <pe1dnn@amsat.org> diff --git a/drivers/staging/wlags49_h2/hcf.c b/drivers/staging/wlags49_h2/hcf.c index 423544634ae5..4aac26d486f1 100644 --- a/drivers/staging/wlags49_h2/hcf.c +++ b/drivers/staging/wlags49_h2/hcf.c @@ -508,7 +508,7 @@ HCF_STATIC hcf_16* BASED xxxx[ ] = { * - HCF_ACT_INT_FORCE_ON enable interrupt generation by WaveLAN NIC * - HCF_ACT_INT_OFF disable interrupt generation by WaveLAN NIC * - HCF_ACT_INT_ON compensate 1 HCF_ACT_INT_OFF, enable interrupt generation if balance reached - * - HCF_ACT_PRS_SCAN Hermes Probe Respons Scan (F102) command + * - HCF_ACT_PRS_SCAN Hermes Probe Response Scan (F102) command * - HCF_ACT_RX_ACK acknowledge non-DMA receiver to Hermes * - HCF_ACT_SCAN Hermes Inquire Scan (F101) command (non-WARP only) * - HCF_ACT_SLEEP DDS Sleep request @@ -571,7 +571,7 @@ HCF_STATIC hcf_16* BASED xxxx[ ] = { * The F/W is wokenup by the HCF when the NIC Interrupts mode are disabled, i.e. at the first HCF_ACT_INT_OFF * after going into sleep. * - * The following Miscellanuous actions are defined: + * The following Miscellaneous actions are defined: * * o HCF_ACT_RX_ACK: Receiver Acknowledgement (non-DMA, non-USB mode only) * Acking the receiver, frees the NIC memory used to hold the Rx frame and allows the F/W to @@ -579,7 +579,7 @@ HCF_STATIC hcf_16* BASED xxxx[ ] = { * If the MSF does not need access (any longer) to the current frame, e.g. because it is rejected based on the * look ahead or copied to another buffer, the receiver may be acked. Acking earlier is assumed to have the * potential of improving the performance. - * If the MSF does not explitly ack te receiver, the acking is done implicitly if: + * If the MSF does not explicitly ack the receiver, the acking is done implicitly if: * - the received frame fits in the look ahead buffer, by the hcf_service_nic call that reported the Rx frame * - if not in the above step, by hcf_rcv_msg (assuming hcf_rcv_msg is called) * - if neither of the above implicit acks nor an explicit ack by the MSF, by the first hcf_service_nic after @@ -591,9 +591,9 @@ HCF_STATIC hcf_16* BASED xxxx[ ] = { * The Inquire Tallies command requests the F/W to provide its current set of tallies. * See also hcf_get_info with CFG_TALLIES as parameter. * - * o HCF_ACT_PRS_SCAN: Inquire Probe Respons Scan command + * o HCF_ACT_PRS_SCAN: Inquire Probe Response Scan command * This command is only operational if the F/W is enabled. - * The Probe Respons Scan command starts a scan sequence. + * The Probe Response Scan command starts a scan sequence. * The HCF puts the result of this action in an MSF defined buffer (see CFG_RID_LOG_STRCT). * * o HCF_ACT_SCAN: Inquire Scan command @@ -606,7 +606,7 @@ HCF_STATIC hcf_16* BASED xxxx[ ] = { * - NIC interrupts are not disabled while required by parameter action. * - an invalid code is specified in parameter action. * - HCF_ACT_INT_ON commands outnumber the HCF_ACT_INT_OFF commands. - * - reentrancy, may be caused by calling hcf_functions without adequate protection against NIC interrupts or + * - reentrancy, may be caused by calling hcf_functions without adequate protection against NIC interrupts or * multi-threading * * - Since the HCF does not maintain status information relative to the F/W enabled state, it is not asserted @@ -625,7 +625,7 @@ HCF_STATIC hcf_16* BASED xxxx[ ] = { * change in HREG_EV_STAT matching a bit in HREG_INT_EN, i.e. not if invoked as result of another device * generating an interrupt on the shared interrupt line. * Note 1: it has been observed that under certain adverse conditions on certain platforms the writing of - * HREG_INT_EN can apparently fail, therefor it is paramount that HREG_INT_EN is written again with 0 for + * HREG_INT_EN can apparently fail, therefore it is paramount that HREG_INT_EN is written again with 0 for * each and every call to HCF_ACT_INT_OFF. * Note 2: it has been observed that under certain H/W & S/W architectures this logic is called when there is * no NIC at all. To cater for this, the value of HREG_INT_EN is validated. If the unused bit 0x0100 is set, @@ -902,7 +902,7 @@ hcf_action( IFBP ifbp, hcf_16 action ) * - A command other than Continue, Enable, Disable, Connect or Disconnect is given. * - An invalid combination of the subfields is given or a bit outside the subfields is given. * - any return code besides HCF_SUCCESS. - * - reentrancy, may be caused by calling a hcf_function without adequate protection against NIC interrupts or + * - reentrancy, may be caused by calling a hcf_function without adequate protection against NIC interrupts or * multi-threading * *.DIAGRAM @@ -1030,7 +1030,7 @@ hcf_cntl( IFBP ifbp, hcf_16 cmd ) * hcf_connect passes the MSF-defined location of the IFB to the HCF and grants or revokes access right for the * HCF to the IFB. Revoking is done by specifying HCF_DISCONNECT rather than an I/O address for the parameter * io_base. Every call of hcf_connect in "connect" mode, must eventually be followed by a call of hcf_connect - * in "disconnect" mode. Clalling hcf_connect in "connect"/"disconnect" mode can not be nested. + * in "disconnect" mode. Calling hcf_connect in "connect"/"disconnect" mode can not be nested. * The IFB address must be used as a handle with all subsequent HCF-function calls and the HCF uses the IFB * address as a handle when it performs a call(back) of an MSF-function (i.e. msf_assert). * @@ -1058,7 +1058,7 @@ hcf_cntl( IFBP ifbp, hcf_16 cmd ) * specification for S/W reset * Note 2: it turns out that on some H/W constellations, the clock to access the EEProm is not lowered * to an appropriate frequency by HREG_IO_SRESET. By giving an HCMD_INI first, this problem is worked around. - *2b: Experimentally it is determined over a wide range of F/W versions that waiting for the for Cmd bit in + *2b: Experimentally it is determined over a wide range of F/W versions that are waiting for the for Cmd bit in * Ev register gives a workable strategy. The available documentation does not give much clues. *4: clear and initialize the IFB * The HCF house keeping info is designed such that zero is the appropriate initial value for as much as diff --git a/drivers/staging/wlags49_h2/hcfcfg.h b/drivers/staging/wlags49_h2/hcfcfg.h index 39fb4d326f65..869b5c343a86 100644 --- a/drivers/staging/wlags49_h2/hcfcfg.h +++ b/drivers/staging/wlags49_h2/hcfcfg.h @@ -21,7 +21,7 @@ * hcfcfg.tpl list all #defines which must be specified to: * adjust the HCF functions defined in HCF.C to the characteristics of a specific environment * o maximum sizes for messages -* o Endianess +* o Endianness * Compiler specific macros * o port I/O macros * o type definitions diff --git a/drivers/staging/wlags49_h2/hcfdef.h b/drivers/staging/wlags49_h2/hcfdef.h index 30744e194a23..74c0f713c57e 100644 --- a/drivers/staging/wlags49_h2/hcfdef.h +++ b/drivers/staging/wlags49_h2/hcfdef.h @@ -652,15 +652,15 @@ err: you used an invalid bitmask; #if 0 //get compiler going #if HCF_EX_INT_TICK != HREG_EV_TICK ;? out dated checking -err: someone redefined these macros while the implemenation assumes they are equal; +err: someone redefined these macros while the implementation assumes they are equal; #endif #if HCF_EX_INT_TX_OK != HFS_TX_CNTL_TX_OK || HFS_TX_CNTL_TX_OK != HREG_EV_TX_OK ;? out dated checking -err: someone redefined these macros while the implemenation assumes they are equal; +err: someone redefined these macros while the implementation assumes they are equal; #endif #if HCF_EX_INT_TX_EX != HFS_TX_CNTL_TX_EX || HFS_TX_CNTL_TX_EX != HREG_EV_TX_EX ;? out dated checking -err: someone redefined these macros while the implemenation assumes they are equal; +err: someone redefined these macros while the implementation assumes they are equal; #endif #endif // 0 get compiler going diff --git a/drivers/staging/wlags49_h2/mdd.h b/drivers/staging/wlags49_h2/mdd.h index 5c3515f31a16..0c914971c1ef 100644 --- a/drivers/staging/wlags49_h2/mdd.h +++ b/drivers/staging/wlags49_h2/mdd.h @@ -652,7 +652,7 @@ XX1( CFG_SCAN, SCAN_RS_STRCT, scan_result[32] ) /*Scan results * #define CFG_CNF_WDS_ADDR6 0xFC16 //[AP] Port 6 MAC Adrs of corresponding WDS Link node #define CFG_CNF_PM_MCAST_BUF 0xFC17 //[AP] Switch for PM buffereing of Multicast Messages #define CFG_CNF_MCAST_PM_BUF CFG_CNF_PM_MCAST_BUF //name does not match H-II spec -#define CFG_CNF_REJECT_ANY 0xFC18 //[AP] Switch for PM buffereing of Multicast Messages +#define CFG_CNF_REJECT_ANY 0xFC18 //[AP] Switch for PM buffering of Multicast Messages #define CFG_CNF_ENCRYPTION 0xFC20 //select en/de-cryption of Tx/Rx messages #define CFG_CNF_AUTHENTICATION 0xFC21 //[STA] selects Authentication algorithm @@ -844,13 +844,13 @@ XX1( CFG_SCAN, SCAN_RS_STRCT, scan_result[32] ) /*Scan results * #define HCF_SUCCESS 0x00 // OK -#define HCF_ERR_TIME_OUT 0x04 // Expected Hermes event did not occure in expected time +#define HCF_ERR_TIME_OUT 0x04 // Expected Hermes event did not occur in expected time #define HCF_ERR_NO_NIC 0x05 /* card not found (usually yanked away during hcfio_in_string * Also: card is either absent or disabled while it should be neither */ #define HCF_ERR_LEN 0x08 /* buffer size insufficient * - IFB_ConfigTable too small * - hcf_get_info buffer has a size of 0 or 1 or less than needed - * to accomodate all data + * to accommodate all data * - hcf_put_info: CFG_DLNV_DATA exceeds intermediate * buffer size */ #define HCF_ERR_INCOMP_PRI 0x09 // primary functions are not compatible @@ -1004,7 +1004,7 @@ XX1( CFG_SCAN, SCAN_RS_STRCT, scan_result[32] ) /*Scan results * #define CFG_CURRENT_LINK_STATUS 0x090B //Latest link status got through 0xF200 LinkEvent /*============================================================ INFORMATION FRAMES =========================*/ -#define CFG_INFO_FRAME_MIN 0xF000 //lowest value representing an Informatio Frame +#define CFG_INFO_FRAME_MIN 0xF000 //lowest value representing an Information Frame #define CFG_TALLIES 0xF100 //Communications Tallies #define CFG_SCAN 0xF101 //Scan results diff --git a/drivers/staging/wlags49_h2/sta_h2.c b/drivers/staging/wlags49_h2/sta_h2.c index f9a38523724c..00dffe2ed8f1 100644 --- a/drivers/staging/wlags49_h2/sta_h2.c +++ b/drivers/staging/wlags49_h2/sta_h2.c @@ -26,7 +26,7 @@ #include "hcfcfg.h" // to get hcf_16 etc defined as well as - // possible settings which inluence mdd.h or dhf.h + // possible settings which influence mdd.h or dhf.h #include "mdd.h" //to get COMP_ID_STA etc defined #include "dhf.h" //used to be "fhfmem.h", to get memblock,plugrecord, diff --git a/drivers/staging/wlags49_h2/sta_h25.c b/drivers/staging/wlags49_h2/sta_h25.c index 86ca1cdd8497..5b6f670d8ef2 100644 --- a/drivers/staging/wlags49_h2/sta_h25.c +++ b/drivers/staging/wlags49_h2/sta_h25.c @@ -25,7 +25,7 @@ #include "hcfcfg.h" // to get hcf_16 etc defined as well as - // possible settings which inluence mdd.h or dhf.h + // possible settings which influence mdd.h or dhf.h #include "mdd.h" //to get COMP_ID_STA etc defined #include "dhf.h" //used to be "fhfmem.h", to get memblock,plugrecord, diff --git a/drivers/staging/wlags49_h2/wl_enc.h b/drivers/staging/wlags49_h2/wl_enc.h index 46629f3b112b..1804611276b8 100644 --- a/drivers/staging/wlags49_h2/wl_enc.h +++ b/drivers/staging/wlags49_h2/wl_enc.h @@ -106,7 +106,7 @@ ENCSTRCT, *PENCSTRCT; /******************************************************************************* - * function prrottypes + * function prototypes ******************************************************************************/ int wl_wep_code( char *szCrypt, char *szDest, void *Data, int nLen ); diff --git a/drivers/staging/wlags49_h2/wl_if.h b/drivers/staging/wlags49_h2/wl_if.h index 6a26130f5a3a..6d66dabf032c 100644 --- a/drivers/staging/wlags49_h2/wl_if.h +++ b/drivers/staging/wlags49_h2/wl_if.h @@ -95,7 +95,7 @@ // Manufacture ID: 0156,0003 // Lowest measurment for noise floor seen is value 54 // Highest signal strength in close proximity to the AP seen is value 118 -// Very good must be arround 100 (otherwise its never "full scale" +// Very good must be around 100 (otherwise its never "full scale" // All other constants are derrived from these. This makes the signal gauge // work for me... #define HCF_MIN_SIGNAL_LEVEL 54 diff --git a/drivers/staging/wlags49_h2/wl_internal.h b/drivers/staging/wlags49_h2/wl_internal.h index 553601f48873..b23078164149 100644 --- a/drivers/staging/wlags49_h2/wl_internal.h +++ b/drivers/staging/wlags49_h2/wl_internal.h @@ -11,7 +11,7 @@ * *------------------------------------------------------------------------------ * - * Header for defintions and macros internal to the drvier. + * Header for definitions and macros internal to the drvier. * *------------------------------------------------------------------------------ * @@ -838,7 +838,7 @@ typedef struct dma_strct DESC_STRCT *rx_packet[NUM_RX_DESC]; DESC_STRCT *rx_reclaim_desc, *tx_reclaim_desc; // Descriptors for host-reclaim purposes (see HCF) int tx_rsc_ind; // DMA Tx resource indicator is maintained in the MSF, not in the HCF - int rx_rsc_ind; // Also added rx rsource indicator so that cleanup can be performed if alloc fails + int rx_rsc_ind; // Also added rx resource indicator so that cleanup can be performed if alloc fails int status; } DMA_STRCT; diff --git a/drivers/staging/wlags49_h2/wl_main.c b/drivers/staging/wlags49_h2/wl_main.c index 204107829577..f5f120a62460 100644 --- a/drivers/staging/wlags49_h2/wl_main.c +++ b/drivers/staging/wlags49_h2/wl_main.c @@ -63,7 +63,7 @@ * constant definitions ******************************************************************************/ -/* Allow support for calling system fcns to access F/W iamge file */ +/* Allow support for calling system fcns to access F/W image file */ #define __KERNEL_SYSCALLS__ /******************************************************************************* @@ -128,7 +128,7 @@ #include <wl_pci.h> #endif /* BUS_PCI */ /******************************************************************************* - * macro defintions + * macro definitions ******************************************************************************/ #define VALID_PARAM(C) \ { \ @@ -1163,7 +1163,7 @@ int rc; CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.version_major ), CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.version_minor )); - /* now we wil get the MAC address of the card */ + /* now we will get the MAC address of the card */ lp->ltvRecord.len = 4; if ( CNV_INT_TO_LITTLE( lp->hcfCtx.IFB_FWIdentity.comp_id ) == COMP_ID_FW_AP ) { lp->ltvRecord.typ = CFG_NIC_MAC_ADDR; @@ -1374,7 +1374,7 @@ int wl_put_ltv_init( struct wl_private *lp ) lp->ltvRecord.len = 2; lp->ltvRecord.typ = CFG_CNTL_OPT; - /* The Card Services build must ALWAYS configure for 16-bit I/O. PCI or + /* The Card Services build must ALWAYS be configured for 16-bit I/O. PCI or CardBus can be set to either 16/32 bit I/O, or Bus Master DMA, but only for Hermes-2.5 */ #ifdef BUS_PCMCIA @@ -1627,7 +1627,7 @@ int wl_put_ltv( struct wl_private *lp ) lp->ltvRecord.u.u16[0] = CNV_INT_TO_LITTLE( lp->TxRateControl[0] ); #endif // WARP -//;?skip temporarily to see whether the RID or something else is the probelm hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord )); +//;?skip temporarily to see whether the RID or something else is the problem hcf_status = hcf_put_info( &lp->hcfCtx, (LTVP)&( lp->ltvRecord )); DBG_TRACE( DbgInfo, "CFG_TX_RATE_CNTL 2.4GHz : 0x%04x\n", lp->TxRateControl[0] ); @@ -2474,7 +2474,7 @@ void wl_resume(struct net_device *dev) * * DESCRIPTION: * - * This function perfroms a check on the device and calls wl_remove() if + * This function performs a check on the device and calls wl_remove() if * necessary. This function can be used for all bus types, but exists mostly * for the benefit of the Card Services driver, as there are times when * wl_remove() does not get called. @@ -2596,7 +2596,7 @@ int wl_enable( struct wl_private *lp ) lp->portState = WVLAN_PORT_STATE_ENABLED; //;?bad mnemonic, NIC iso PORT #ifdef ENABLE_DMA if ( lp->use_dma ) { - wl_pci_dma_hcf_supply( lp ); //;?always succes? + wl_pci_dma_hcf_supply( lp ); //;?always successful? } #endif } @@ -2874,7 +2874,7 @@ int wl_mbx( struct wl_private *lp ) * DESCRIPTION: * * This function will perform the tedious task of endian translating all - * fields withtin a mailbox message which need translating. + * fields within a mailbox message which need translating. * * PARAMETERS: * @@ -2989,7 +2989,7 @@ void wl_endian_translate_mailbox( ltv_t *ltv ) * * DESCRIPTION: * - * This function will process the mailbox data. + * This function processes the mailbox data. * * PARAMETERS: * diff --git a/drivers/staging/wlags49_h2/wl_netdev.c b/drivers/staging/wlags49_h2/wl_netdev.c index 824b85232353..fb421407e106 100644 --- a/drivers/staging/wlags49_h2/wl_netdev.c +++ b/drivers/staging/wlags49_h2/wl_netdev.c @@ -652,7 +652,6 @@ void wl_tx_timeout( struct net_device *dev ) wl_unlock( lp, &flags ); DBG_LEAVE( DbgInfo ); - return; } // wl_tx_timeout /*============================================================================*/ @@ -836,8 +835,7 @@ int wl_tx( struct sk_buff *skb, struct net_device *dev, int port ) txF->frame.port = port; /* Move the frame to the txQ */ /* NOTE: Here's where we would do priority queueing */ - list_del( &( txF->node )); - list_add( &( txF->node ), &( lp->txQ[0] )); + list_move(&(txF->node), &(lp->txQ[0])); lp->txQ_count++; if( lp->txQ_count >= DEFAULT_NUM_TX_FRAMES ) { @@ -1252,7 +1250,7 @@ struct net_device * wl_device_alloc( void ) netif_stop_queue( dev ); - /* Allocate virutal devices for WDS support if needed */ + /* Allocate virtual devices for WDS support if needed */ WL_WDS_DEVICE_ALLOC( lp ); DBG_LEAVE( DbgInfo ); @@ -1292,7 +1290,6 @@ void wl_device_dealloc( struct net_device *dev ) free_netdev( dev ); DBG_LEAVE( DbgInfo ); - return; } // wl_device_dealloc /*============================================================================*/ @@ -1547,7 +1544,6 @@ void wl_wds_device_alloc( struct wl_private *lp ) WL_WDS_NETIF_STOP_QUEUE( lp ); DBG_LEAVE( DbgInfo ); - return; } // wl_wds_device_alloc /*============================================================================*/ @@ -1593,7 +1589,6 @@ void wl_wds_device_dealloc( struct wl_private *lp ) } DBG_LEAVE( DbgInfo ); - return; } // wl_wds_device_dealloc /*============================================================================*/ @@ -1604,7 +1599,7 @@ void wl_wds_device_dealloc( struct wl_private *lp ) * DESCRIPTION: * * Used to start the netif queues of all the "virtual" network devices - * which repesent the WDS ports. + * which represent the WDS ports. * * PARAMETERS: * @@ -1629,8 +1624,6 @@ void wl_wds_netif_start_queue( struct wl_private *lp ) } } } - - return; } // wl_wds_netif_start_queue /*============================================================================*/ @@ -1641,7 +1634,7 @@ void wl_wds_netif_start_queue( struct wl_private *lp ) * DESCRIPTION: * * Used to stop the netif queues of all the "virtual" network devices - * which repesent the WDS ports. + * which represent the WDS ports. * * PARAMETERS: * @@ -1666,8 +1659,6 @@ void wl_wds_netif_stop_queue( struct wl_private *lp ) } } } - - return; } // wl_wds_netif_stop_queue /*============================================================================*/ @@ -1678,7 +1669,7 @@ void wl_wds_netif_stop_queue( struct wl_private *lp ) * DESCRIPTION: * * Used to wake the netif queues of all the "virtual" network devices - * which repesent the WDS ports. + * which represent the WDS ports. * * PARAMETERS: * @@ -1703,8 +1694,6 @@ void wl_wds_netif_wake_queue( struct wl_private *lp ) } } } - - return; } // wl_wds_netif_wake_queue /*============================================================================*/ @@ -1715,7 +1704,7 @@ void wl_wds_netif_wake_queue( struct wl_private *lp ) * DESCRIPTION: * * Used to signal the network layer that carrier is present on all of the - * "virtual" network devices which repesent the WDS ports. + * "virtual" network devices which represent the WDS ports. * * PARAMETERS: * @@ -1738,8 +1727,6 @@ void wl_wds_netif_carrier_on( struct wl_private *lp ) } } } - - return; } // wl_wds_netif_carrier_on /*============================================================================*/ @@ -1750,7 +1737,7 @@ void wl_wds_netif_carrier_on( struct wl_private *lp ) * DESCRIPTION: * * Used to signal the network layer that carrier is NOT present on all of - * the "virtual" network devices which repesent the WDS ports. + * the "virtual" network devices which represent the WDS ports. * * PARAMETERS: * @@ -1763,18 +1750,15 @@ void wl_wds_netif_carrier_on( struct wl_private *lp ) ******************************************************************************/ void wl_wds_netif_carrier_off( struct wl_private *lp ) { - int count; - /*------------------------------------------------------------------------*/ + int count; - if( lp != NULL ) { - for( count = 0; count < NUM_WDS_PORTS; count++ ) { - if( lp->wds_port[count].is_registered ) { - netif_carrier_off( lp->wds_port[count].dev ); - } - } - } + if(lp != NULL) { + for(count = 0; count < NUM_WDS_PORTS; count++) { + if(lp->wds_port[count].is_registered) + netif_carrier_off(lp->wds_port[count].dev); + } + } - return; } // wl_wds_netif_carrier_off /*============================================================================*/ @@ -1810,22 +1794,19 @@ int wl_send_dma( struct wl_private *lp, struct sk_buff *skb, int port ) DBG_FUNC( "wl_send_dma" ); - if( lp == NULL ) - { + if( lp == NULL ) { DBG_ERROR( DbgInfo, "Private adapter struct is NULL\n" ); return FALSE; } - if( lp->dev == NULL ) - { + if( lp->dev == NULL ) { DBG_ERROR( DbgInfo, "net_device struct in wl_private is NULL\n" ); return FALSE; } /* AGAIN, ALL THE QUEUEING DONE HERE IN I/O MODE IS NOT PERFORMED */ - if( skb == NULL ) - { + if( skb == NULL ) { DBG_WARNING (DbgInfo, "Nothing to send.\n"); return FALSE; } @@ -1835,8 +1816,7 @@ int wl_send_dma( struct wl_private *lp, struct sk_buff *skb, int port ) /* Get a free descriptor */ desc = wl_pci_dma_get_tx_packet( lp ); - if( desc == NULL ) - { + if( desc == NULL ) { if( lp->netif_queue_on == TRUE ) { netif_stop_queue( lp->dev ); WL_WDS_NETIF_STOP_QUEUE( lp ); @@ -1852,8 +1832,7 @@ int wl_send_dma( struct wl_private *lp, struct sk_buff *skb, int port ) desc_next = desc->next_desc_addr; - if( desc_next->buf_addr == NULL ) - { + if( desc_next->buf_addr == NULL ) { DBG_ERROR( DbgInfo, "DMA descriptor buf_addr is NULL\n" ); return FALSE; } diff --git a/drivers/staging/wlags49_h2/wl_pci.c b/drivers/staging/wlags49_h2/wl_pci.c index 0b31b01bd490..a09c3ac793a2 100644 --- a/drivers/staging/wlags49_h2/wl_pci.c +++ b/drivers/staging/wlags49_h2/wl_pci.c @@ -223,7 +223,7 @@ int wl_adapter_init_module( void ) ******************************************************************************/ void wl_adapter_cleanup_module( void ) { - //;?how comes wl_adapter_cleanup_module is located in a seemingly pci specific module + //;?how come wl_adapter_cleanup_module is located in a seemingly pci specific module DBG_FUNC( "wl_adapter_cleanup_module" ); DBG_ENTER( DbgInfo ); @@ -385,7 +385,7 @@ int wl_adapter_is_open( struct net_device *dev ) * DESCRIPTION: * * Registered in the pci_driver structure, this function is called when the - * PCI subsystem finds a new PCI device which matches the infomation contained + * PCI subsystem finds a new PCI device which matches the information contained * in the pci_device_id table. * * PARAMETERS: @@ -424,7 +424,7 @@ int __devinit wl_pci_probe( struct pci_dev *pdev, * DESCRIPTION: * * Registered in the pci_driver structure, this function is called when the - * PCI subsystem detects that a PCI device which matches the infomation + * PCI subsystem detects that a PCI device which matches the information * contained in the pci_device_id table has been removed. * * PARAMETERS: @@ -899,7 +899,7 @@ int wl_pci_dma_free_tx_packet( struct pci_dev *pdev, struct wl_private *lp, * DESCRIPTION: * * Allocates a single Rx packet, consisting of two descriptors and one - * contiguous buffer. THe buffer starts with the hermes-specific header. + * contiguous buffer. The buffer starts with the hermes-specific header. * One descriptor points at the start, the other at offset 0x3a of the * buffer. * diff --git a/drivers/staging/wlags49_h2/wl_priv.c b/drivers/staging/wlags49_h2/wl_priv.c index f30e5ee4bca3..87e1e4123126 100644 --- a/drivers/staging/wlags49_h2/wl_priv.c +++ b/drivers/staging/wlags49_h2/wl_priv.c @@ -225,7 +225,7 @@ int wvlan_uil_connect( struct uilreq *urq, struct wl_private *lp ) * * DESCRIPTION: * - * Disonnect from the UIL after a request has been completed. + * Disconnect from the UIL after a request has been completed. * * PARAMETERS: * diff --git a/drivers/staging/wlags49_h2/wl_profile.c b/drivers/staging/wlags49_h2/wl_profile.c index 0e49272bc7a8..beabf5916df7 100644 --- a/drivers/staging/wlags49_h2/wl_profile.c +++ b/drivers/staging/wlags49_h2/wl_profile.c @@ -910,7 +910,7 @@ int parse_mac_address(char *value, u_char *byte_array) memset(byte_field, '\0', 3); while (value[value_offset] != '\0') { - /* Skip over the colon chars seperating the bytes, if they exist */ + /* Skip over the colon chars separating the bytes, if they exist */ if (value[value_offset] == ':') { value_offset++; continue; diff --git a/drivers/staging/wlags49_h2/wl_version.h b/drivers/staging/wlags49_h2/wl_version.h index 3deacfac9d25..037b5266428c 100644 --- a/drivers/staging/wlags49_h2/wl_version.h +++ b/drivers/staging/wlags49_h2/wl_version.h @@ -152,7 +152,7 @@ err: define bus type; /******************************************************************************* - * bus architechture specific defines, includes, etc. + * bus architecture specific defines, includes, etc. ******************************************************************************/ /* * There doesn't seem to be a difference for PCMCIA and PCI anymore, at least diff --git a/drivers/staging/wlags49_h2/wl_wext.c b/drivers/staging/wlags49_h2/wl_wext.c index 7ff0a108da13..f553366cccc5 100644 --- a/drivers/staging/wlags49_h2/wl_wext.c +++ b/drivers/staging/wlags49_h2/wl_wext.c @@ -62,6 +62,7 @@ #include <linux/if_arp.h> #include <linux/ioport.h> #include <linux/delay.h> +#include <linux/etherdevice.h> #include <asm/uaccess.h> #include <debug.h> @@ -173,7 +174,7 @@ static int hermes_clear_tkip_keys(ltv_t *ltv, u16 key_idx, u8 *addr) switch (key_idx) { case 0: - if (memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0) { + if (!is_broadcast_ether_addr(addr)) { ltv->len = 7; ltv->typ = CFG_REMOVE_TKIP_MAPPED_KEY; memcpy(<v->u.u8[0], addr, ETH_ALEN); @@ -605,7 +606,7 @@ retry: if (retries < 10) { retries++; - /* Holding the lock too long, make a gap to allow other processes */ + /* Holding the lock too long, makes a gap to allow other processes */ wl_unlock(lp, &flags); wl_lock( lp, &flags ); @@ -617,7 +618,7 @@ retry: goto out_unlock; } - /* Holding the lock too long, make a gap to allow other processes */ + /* Holding the lock too long, makes a gap to allow other processes */ wl_unlock(lp, &flags); wl_lock( lp, &flags ); @@ -630,7 +631,7 @@ retry: } } - /* Holding the lock too long, make a gap to allow other processes */ + /* Holding the lock too long, makes a gap to allow other processes */ wl_unlock(lp, &flags); wl_lock( lp, &flags ); @@ -693,7 +694,7 @@ retry: /* Encryption */ - /* Holding the lock too long, make a gap to allow other processes */ + /* Holding the lock too long, makes a gap to allow other processes */ wl_unlock(lp, &flags); wl_lock( lp, &flags ); @@ -720,7 +721,7 @@ retry: // Retry Limits and Lifetime - NOT SUPPORTED - /* Holding the lock too long, make a gap to allow other processes */ + /* Holding the lock too long, makes a gap to allow other processes */ wl_unlock(lp, &flags); wl_lock( lp, &flags ); @@ -2595,7 +2596,7 @@ static int wireless_set_scan(struct net_device *dev, struct iw_request_info *inf int retries = 0; /*------------------------------------------------------------------------*/ - //;? Note: shows results as trace, retruns always 0 unless BUSY + //;? Note: shows results as trace, returns always 0 unless BUSY DBG_FUNC( "wireless_set_scan" ); DBG_ENTER( DbgInfo ); @@ -2645,7 +2646,7 @@ retry: DBG_TRACE( DbgInfo, "CFG_SCAN_CHANNEL result : 0x%x\n", status ); - // Holding the lock too long, make a gap to allow other processes + // Holding the lock too long, makes a gap to allow other processes wl_unlock(lp, &flags); wl_lock( lp, &flags ); @@ -2656,7 +2657,7 @@ retry: DBG_TRACE( DbgInfo, "Reset card to recover, attempt: %d\n", retries ); wl_reset( dev ); - // Holding the lock too long, make a gap to allow other processes + // Holding the lock too long, makes a gap to allow other processes wl_unlock(lp, &flags); wl_lock( lp, &flags ); @@ -2673,7 +2674,7 @@ retry: status = hcf_put_info( &( lp->hcfCtx ), (LTVP)&( lp->ltvRecord )); - // Holding the lock too long, make a gap to allow other processes + // Holding the lock too long, makes a gap to allow other processes wl_unlock(lp, &flags); wl_lock( lp, &flags ); @@ -2681,7 +2682,7 @@ retry: /* Initiate the scan */ /* NOTE: Using HCF_ACT_SCAN has been removed, as using HCF_ACT_ACS_SCAN to - retrieve probe responses must always be used to support WPA */ + retrieve probe response must always be used to support WPA */ status = hcf_action( &( lp->hcfCtx ), HCF_ACT_ACS_SCAN ); if( status == HCF_SUCCESS ) { @@ -3054,7 +3055,7 @@ static void flush_tx(struct wl_private *lp) * Make sure that there is no data queued up in the firmware * before setting the TKIP keys. If this check is not * performed, some data may be sent out with incorrect MIC - * and cause synchronizarion errors with the AP + * and cause synchronization errors with the AP */ /* Check every 1ms for 100ms */ for (count = 0; count < 100; count++) { @@ -3654,7 +3655,7 @@ void wl_wext_event_ap( struct net_device *dev ) this event BEFORE sending the association event, as there are timing issues with the hostap supplicant. The supplicant will attempt to process an EAPOL-Key frame from an AP before receiving this information, which - is required properly process the said frame. */ + is required for a proper processed frame. */ wl_wext_event_assoc_ie( dev ); /* Get the BSSID */ diff --git a/drivers/staging/wlags49_h25/Kconfig b/drivers/staging/wlags49_h25/Kconfig index bf5664a51cd4..dd8dc4d62c64 100644 --- a/drivers/staging/wlags49_h25/Kconfig +++ b/drivers/staging/wlags49_h25/Kconfig @@ -8,4 +8,4 @@ config WLAGS49_H25 Driver for wireless cards using Agere's HERMES II.5 chipset which are identified with Manufacture ID: 0156,0004 The software is a modified version of wl_lkm_722_abg.tar.gz - from the Agere Systems website, addapted for Ubuntu 9.04. + from the Agere Systems website, adapted for Ubuntu 9.04. diff --git a/drivers/staging/wlags49_h25/TODO b/drivers/staging/wlags49_h25/TODO index 94032b6ac2b5..ec71ad3245e4 100644 --- a/drivers/staging/wlags49_h25/TODO +++ b/drivers/staging/wlags49_h25/TODO @@ -1,4 +1,4 @@ -First of all, the best thing would be that this driver becomes obsolte by +First of all, the best thing would be that this driver becomes obsolete by adding support for Hermes II and Hermes II.5 cards to the existing orinoco driver. The orinoco driver currently only supports Hermes I based cards. Since this will not happen by magic and has not happened until now this @@ -10,11 +10,11 @@ list. TODO: - verify against a Hermes II.5 card - - verify with WPA encription (both with H2 and H2.5 cards) + - verify with WPA encryption (both with H2 and H2.5 cards) - sometimes the card does not initialize correctly, retry mechanisms are build in to catch most cases but not all - once the driver runs it is very stable, but I have the impression - some the crittical sections take to long + some the critical sections take to long - the driver is split into a Hermes II and a Hermes II.5 part, it would be nice to handle both with one module instead of two - review by the wireless developer community @@ -25,7 +25,7 @@ TODO: DONE: - verified against a Hermes II card (Thomson Speedtouch 110 PCMCIA card) - - verified with WEP encription + - verified with WEP encryption Please send any patches or complaints about this driver to Greg Kroah-Hartman <greg@kroah.com> and Cc: Henk de Groot <pe1dnn@amsat.org> diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c index 0970127344e6..18c06a59c091 100644 --- a/drivers/staging/wlan-ng/cfg80211.c +++ b/drivers/staging/wlan-ng/cfg80211.c @@ -1,7 +1,7 @@ /* cfg80211 Interface for prism2_usb module */ -/* Prism2 channell/frequency/bitrate declarations */ +/* Prism2 channel/frequency/bitrate declarations */ static const struct ieee80211_channel prism2_channels[] = { { .center_freq = 2412 }, { .center_freq = 2417 }, @@ -329,9 +329,9 @@ int prism2_get_station(struct wiphy *wiphy, struct net_device *dev, int prism2_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) { - struct net_device *dev = request->wdev->netdev; + struct net_device *dev; struct prism2_wiphy_private *priv = wiphy_priv(wiphy); - wlandevice_t *wlandev = dev->ml_priv; + wlandevice_t *wlandev; struct p80211msg_dot11req_scan msg1; struct p80211msg_dot11req_scan_results msg2; struct cfg80211_bss *bss; @@ -345,6 +345,9 @@ int prism2_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request) if (!request) return -EINVAL; + dev = request->wdev->netdev; + wlandev = dev->ml_priv; + if (priv->scan_request && priv->scan_request != request) return -EBUSY; @@ -499,7 +502,7 @@ int prism2_connect(struct wiphy *wiphy, struct net_device *dev, goto exit; } - /* Set the authorisation */ + /* Set the authorization */ if ((sme->auth_type == NL80211_AUTHTYPE_OPEN_SYSTEM) || ((sme->auth_type == NL80211_AUTHTYPE_AUTOMATIC) && !is_wep)) msg_join.authtype.data = P80211ENUM_authalg_opensystem; diff --git a/drivers/staging/wlan-ng/hfa384x_usb.c b/drivers/staging/wlan-ng/hfa384x_usb.c index 7843dfdaa3cf..f180c3d8b012 100644 --- a/drivers/staging/wlan-ng/hfa384x_usb.c +++ b/drivers/staging/wlan-ng/hfa384x_usb.c @@ -2140,11 +2140,7 @@ exit_proc: ----------------------------------------------------------------*/ int hfa384x_drvr_getconfig(hfa384x_t *hw, u16 rid, void *buf, u16 len) { - int result; - - result = hfa384x_dorrid_wait(hw, rid, buf, len); - - return result; + return hfa384x_dorrid_wait(hw, rid, buf, len); } /*---------------------------------------------------------------- @@ -3790,7 +3786,7 @@ static void hfa384x_ctlxout_callback(struct urb *urb) #endif if ((urb->status == -ESHUTDOWN) || (urb->status == -ENODEV) || (hw == NULL)) - goto done; + return; retry: spin_lock_irqsave(&hw->ctlxq.lock, flags); @@ -3803,7 +3799,7 @@ retry: */ if (list_empty(&hw->ctlxq.active)) { spin_unlock_irqrestore(&hw->ctlxq.lock, flags); - goto done; + return; } /* @@ -3886,9 +3882,6 @@ delresp: if (run_queue) hfa384x_usbctlxq_run(hw); - -done: - ; } /*---------------------------------------------------------------- @@ -3985,15 +3978,10 @@ static void hfa384x_usbctlx_resptimerfn(unsigned long data) if (unlocked_usbctlx_cancel_async(hw, ctlx) == 0) { spin_unlock_irqrestore(&hw->ctlxq.lock, flags); hfa384x_usbctlxq_run(hw); - goto done; + return; } } - spin_unlock_irqrestore(&hw->ctlxq.lock, flags); - -done: - ; - } /*---------------------------------------------------------------- @@ -4057,23 +4045,20 @@ static void hfa384x_usb_throttlefn(unsigned long data) static int hfa384x_usbctlx_submit(hfa384x_t *hw, hfa384x_usbctlx_t *ctlx) { unsigned long flags; - int ret; spin_lock_irqsave(&hw->ctlxq.lock, flags); if (hw->wlandev->hwremoved) { spin_unlock_irqrestore(&hw->ctlxq.lock, flags); - ret = -ENODEV; - } else { - ctlx->state = CTLX_PENDING; - list_add_tail(&ctlx->list, &hw->ctlxq.pending); - - spin_unlock_irqrestore(&hw->ctlxq.lock, flags); - hfa384x_usbctlxq_run(hw); - ret = 0; + return -ENODEV; } - return ret; + ctlx->state = CTLX_PENDING; + list_add_tail(&ctlx->list, &hw->ctlxq.pending); + spin_unlock_irqrestore(&hw->ctlxq.lock, flags); + hfa384x_usbctlxq_run(hw); + + return 0; } /*---------------------------------------------------------------- diff --git a/drivers/staging/wlan-ng/p80211conv.c b/drivers/staging/wlan-ng/p80211conv.c index f53a27a2e3fe..3df753b51e89 100644 --- a/drivers/staging/wlan-ng/p80211conv.c +++ b/drivers/staging/wlan-ng/p80211conv.c @@ -559,17 +559,17 @@ void p80211skb_rxmeta_detach(struct sk_buff *skb) /* Sanity checks */ if (skb == NULL) { /* bad skb */ pr_debug("Called w/ null skb.\n"); - goto exit; + return; } frmmeta = P80211SKB_FRMMETA(skb); if (frmmeta == NULL) { /* no magic */ pr_debug("Called w/ bad frmmeta magic.\n"); - goto exit; + return; } rxmeta = frmmeta->rx; if (rxmeta == NULL) { /* bad meta ptr */ pr_debug("Called w/ bad rxmeta ptr.\n"); - goto exit; + return; } /* Free rxmeta */ @@ -577,8 +577,6 @@ void p80211skb_rxmeta_detach(struct sk_buff *skb) /* Clear skb->cb */ memset(skb->cb, 0, sizeof(skb->cb)); -exit: - return; } /*---------------------------------------------------------------- @@ -660,5 +658,4 @@ void p80211skb_free(struct wlandevice *wlandev, struct sk_buff *skb) else printk(KERN_ERR "Freeing an skb (%p) w/ no frmmeta.\n", skb); dev_kfree_skb(skb); - return; } diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c index 0f51b4ab3631..750330f064f9 100644 --- a/drivers/staging/wlan-ng/p80211netdev.c +++ b/drivers/staging/wlan-ng/p80211netdev.c @@ -240,10 +240,7 @@ void p80211netdev_rx(wlandevice_t *wlandev, struct sk_buff *skb) { /* Enqueue for post-irq processing */ skb_queue_tail(&wlandev->nsd_rxq, skb); - tasklet_schedule(&wlandev->rx_bh); - - return; } /*---------------------------------------------------------------- @@ -464,7 +461,7 @@ failed: /*---------------------------------------------------------------- * p80211knetdev_set_multicast_list * -* Called from higher lavers whenever there's a need to set/clear +* Called from higher layers whenever there's a need to set/clear * promiscuous mode or rewrite the multicast list. * * Arguments: @@ -644,7 +641,7 @@ static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr) p80211item_unk392_t *mibattr; p80211item_pstr6_t *macaddr; p80211item_uint32_t *resultcode; - int result = 0; + int result; /* If we're running, we don't allow MAC address changes */ if (netif_running(dev)) @@ -806,15 +803,13 @@ int wlan_setup(wlandevice_t *wlandev, struct device *physdev) * Arguments: * wlandev ptr to the wlandev structure for the * interface. -* Returns: -* zero on success, non-zero otherwise. * Call Context: * Should be process thread. We'll assume it might be * interrupt though. When we add support for statically * compiled drivers, this function will be called in the * context of the kernel startup code. ----------------------------------------------------------------*/ -int wlan_unsetup(wlandevice_t *wlandev) +void wlan_unsetup(wlandevice_t *wlandev) { struct wireless_dev *wdev; @@ -827,8 +822,6 @@ int wlan_unsetup(wlandevice_t *wlandev) free_netdev(wlandev->netdev); wlandev->netdev = NULL; } - - return 0; } /*---------------------------------------------------------------- @@ -852,13 +845,7 @@ int wlan_unsetup(wlandevice_t *wlandev) ----------------------------------------------------------------*/ int register_wlandev(wlandevice_t *wlandev) { - int i = 0; - - i = register_netdev(wlandev->netdev); - if (i) - return i; - - return 0; + return register_netdev(wlandev->netdev); } /*---------------------------------------------------------------- diff --git a/drivers/staging/wlan-ng/p80211netdev.h b/drivers/staging/wlan-ng/p80211netdev.h index 85884176b661..2fecca2302f4 100644 --- a/drivers/staging/wlan-ng/p80211netdev.h +++ b/drivers/staging/wlan-ng/p80211netdev.h @@ -235,7 +235,7 @@ int wep_encrypt(wlandevice_t *wlandev, u8 *buf, u8 *dst, u32 len, int keynum, u8 *iv, u8 *icv); int wlan_setup(wlandevice_t *wlandev, struct device *physdev); -int wlan_unsetup(wlandevice_t *wlandev); +void wlan_unsetup(wlandevice_t *wlandev); int register_wlandev(wlandevice_t *wlandev); int unregister_wlandev(wlandevice_t *wlandev); void p80211netdev_rx(wlandevice_t *wlandev, struct sk_buff *skb); diff --git a/drivers/staging/wlan-ng/p80211req.c b/drivers/staging/wlan-ng/p80211req.c index 179194e7d2aa..cdfd808d6854 100644 --- a/drivers/staging/wlan-ng/p80211req.c +++ b/drivers/staging/wlan-ng/p80211req.c @@ -73,7 +73,7 @@ #include "p80211req.h" static void p80211req_handlemsg(wlandevice_t *wlandev, struct p80211msg *msg); -static int p80211req_mibset_mibget(wlandevice_t *wlandev, +static void p80211req_mibset_mibget(wlandevice_t *wlandev, struct p80211msg_dot11req_mibget *mib_msg, int isget); @@ -155,32 +155,29 @@ static void p80211req_handlemsg(wlandevice_t *wlandev, struct p80211msg *msg) switch (msg->msgcode) { case DIDmsg_lnxreq_hostwep:{ - struct p80211msg_lnxreq_hostwep *req = - (struct p80211msg_lnxreq_hostwep *) msg; - wlandev->hostwep &= - ~(HOSTWEP_DECRYPT | HOSTWEP_ENCRYPT); - if (req->decrypt.data == P80211ENUM_truth_true) - wlandev->hostwep |= HOSTWEP_DECRYPT; - if (req->encrypt.data == P80211ENUM_truth_true) - wlandev->hostwep |= HOSTWEP_ENCRYPT; - - break; - } + struct p80211msg_lnxreq_hostwep *req = + (struct p80211msg_lnxreq_hostwep *) msg; + wlandev->hostwep &= + ~(HOSTWEP_DECRYPT | HOSTWEP_ENCRYPT); + if (req->decrypt.data == P80211ENUM_truth_true) + wlandev->hostwep |= HOSTWEP_DECRYPT; + if (req->encrypt.data == P80211ENUM_truth_true) + wlandev->hostwep |= HOSTWEP_ENCRYPT; + + break; + } case DIDmsg_dot11req_mibget: case DIDmsg_dot11req_mibset:{ - int isget = (msg->msgcode == DIDmsg_dot11req_mibget); - struct p80211msg_dot11req_mibget *mib_msg = - (struct p80211msg_dot11req_mibget *) msg; - p80211req_mibset_mibget(wlandev, mib_msg, isget); - } - default: - ; + int isget = (msg->msgcode == DIDmsg_dot11req_mibget); + struct p80211msg_dot11req_mibget *mib_msg = + (struct p80211msg_dot11req_mibget *) msg; + p80211req_mibset_mibget(wlandev, mib_msg, isget); + break; + } } /* switch msg->msgcode */ - - return; } -static int p80211req_mibset_mibget(wlandevice_t *wlandev, +static void p80211req_mibset_mibget(wlandevice_t *wlandev, struct p80211msg_dot11req_mibget *mib_msg, int isget) { @@ -190,76 +187,65 @@ static int p80211req_mibset_mibget(wlandevice_t *wlandev, switch (mibitem->did) { case DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey0:{ - if (!isget) - wep_change_key(wlandev, 0, key, pstr->len); - break; - } + if (!isget) + wep_change_key(wlandev, 0, key, pstr->len); + break; + } case DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey1:{ - if (!isget) - wep_change_key(wlandev, 1, key, pstr->len); - break; - } + if (!isget) + wep_change_key(wlandev, 1, key, pstr->len); + break; + } case DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey2:{ - if (!isget) - wep_change_key(wlandev, 2, key, pstr->len); - break; - } + if (!isget) + wep_change_key(wlandev, 2, key, pstr->len); + break; + } case DIDmib_dot11smt_dot11WEPDefaultKeysTable_dot11WEPDefaultKey3:{ - if (!isget) - wep_change_key(wlandev, 3, key, pstr->len); - break; - } + if (!isget) + wep_change_key(wlandev, 3, key, pstr->len); + break; + } case DIDmib_dot11smt_dot11PrivacyTable_dot11WEPDefaultKeyID:{ - u32 *data = (u32 *) mibitem->data; + u32 *data = (u32 *) mibitem->data; - if (isget) { - *data = - wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK; - } else { - wlandev->hostwep &= ~(HOSTWEP_DEFAULTKEY_MASK); - - wlandev->hostwep |= - (*data & HOSTWEP_DEFAULTKEY_MASK); - } - break; + if (isget) { + *data = wlandev->hostwep & HOSTWEP_DEFAULTKEY_MASK; + } else { + wlandev->hostwep &= ~(HOSTWEP_DEFAULTKEY_MASK); + wlandev->hostwep |= (*data & HOSTWEP_DEFAULTKEY_MASK); } + break; + } case DIDmib_dot11smt_dot11PrivacyTable_dot11PrivacyInvoked:{ - u32 *data = (u32 *) mibitem->data; - - if (isget) { - if (wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) - *data = P80211ENUM_truth_true; - else - *data = P80211ENUM_truth_false; - } else { - wlandev->hostwep &= ~(HOSTWEP_PRIVACYINVOKED); - if (*data == P80211ENUM_truth_true) - wlandev->hostwep |= - HOSTWEP_PRIVACYINVOKED; - } - break; + u32 *data = (u32 *) mibitem->data; + + if (isget) { + if (wlandev->hostwep & HOSTWEP_PRIVACYINVOKED) + *data = P80211ENUM_truth_true; + else + *data = P80211ENUM_truth_false; + } else { + wlandev->hostwep &= ~(HOSTWEP_PRIVACYINVOKED); + if (*data == P80211ENUM_truth_true) + wlandev->hostwep |= HOSTWEP_PRIVACYINVOKED; } + break; + } case DIDmib_dot11smt_dot11PrivacyTable_dot11ExcludeUnencrypted:{ - u32 *data = (u32 *) mibitem->data; - - if (isget) { - if (wlandev->hostwep & - HOSTWEP_EXCLUDEUNENCRYPTED) - *data = P80211ENUM_truth_true; - else - *data = P80211ENUM_truth_false; - } else { - wlandev->hostwep &= - ~(HOSTWEP_EXCLUDEUNENCRYPTED); - if (*data == P80211ENUM_truth_true) - wlandev->hostwep |= - HOSTWEP_EXCLUDEUNENCRYPTED; - } - break; + u32 *data = (u32 *) mibitem->data; + + if (isget) { + if (wlandev->hostwep & HOSTWEP_EXCLUDEUNENCRYPTED) + *data = P80211ENUM_truth_true; + else + *data = P80211ENUM_truth_false; + } else { + wlandev->hostwep &= ~(HOSTWEP_EXCLUDEUNENCRYPTED); + if (*data == P80211ENUM_truth_true) + wlandev->hostwep |= HOSTWEP_EXCLUDEUNENCRYPTED; } - default: - ; + break; + } } - - return 0; } diff --git a/drivers/staging/wlan-ng/p80211types.h b/drivers/staging/wlan-ng/p80211types.h index f043090ef86d..8cb4fc6448a0 100644 --- a/drivers/staging/wlan-ng/p80211types.h +++ b/drivers/staging/wlan-ng/p80211types.h @@ -197,7 +197,7 @@ P80211DID_LSB_ACCESS) /*----------------------------------------------------------------*/ -/* The following structure types are used for the represenation */ +/* The following structure types are used for the representation */ /* of ENUMint type metadata. */ typedef struct p80211enumpair { diff --git a/drivers/staging/wlan-ng/p80211wep.c b/drivers/staging/wlan-ng/p80211wep.c index 80c2d3b672bb..77e50a4aa7e9 100644 --- a/drivers/staging/wlan-ng/p80211wep.c +++ b/drivers/staging/wlan-ng/p80211wep.c @@ -134,10 +134,8 @@ int wep_change_key(wlandevice_t *wlandev, int keynum, u8 *key, int keylen) return -1; #ifdef WEP_DEBUG - printk(KERN_DEBUG - "WEP key %d len %d = %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", - keynum, keylen, key[0], key[1], key[2], key[3], key[4], key[5], - key[6], key[7]); + printk(KERN_DEBUG "WEP key %d len %d = %*phC\n", keynum, keylen, + 8, key); #endif wlandev->wep_keylens[keynum] = keylen; @@ -184,10 +182,8 @@ int wep_decrypt(wlandevice_t *wlandev, u8 *buf, u32 len, int key_override, keylen += 3; /* add in IV bytes */ #ifdef WEP_DEBUG - printk(KERN_DEBUG - "D %d: %02x %02x %02x (%d %d) %02x:%02x:%02x:%02x:%02x\n", len, - key[0], key[1], key[2], keyidx, keylen, key[3], key[4], key[5], - key[6], key[7]); + printk(KERN_DEBUG "D %d: %*ph (%d %d) %*phC\n", len, 3, key, + keyidx, keylen, 5, key + 3); #endif /* set up the RC4 state */ @@ -263,10 +259,8 @@ int wep_encrypt(wlandevice_t *wlandev, u8 *buf, u8 *dst, u32 len, int keynum, keylen += 3; /* add in IV bytes */ #ifdef WEP_DEBUG - printk(KERN_DEBUG - "E %d (%d/%d %d) %02x %02x %02x %02x:%02x:%02x:%02x:%02x\n", len, - iv[3], keynum, keylen, key[0], key[1], key[2], key[3], key[4], - key[5], key[6], key[7]); + printk(KERN_DEBUG "E %d (%d/%d %d) %*ph %*phC\n", len, + iv[3], keynum, keylen, 3, key, 5, key + 3); #endif /* set up the RC4 state */ diff --git a/drivers/staging/wlan-ng/prism2fw.c b/drivers/staging/wlan-ng/prism2fw.c index 66c9aa972310..0dfd2a4933ef 100644 --- a/drivers/staging/wlan-ng/prism2fw.c +++ b/drivers/staging/wlan-ng/prism2fw.c @@ -123,27 +123,27 @@ struct imgchunk { /* s-record image processing */ /* Data records */ -unsigned int ns3data; -struct s3datarec s3data[S3DATA_MAX]; +static unsigned int ns3data; +static struct s3datarec s3data[S3DATA_MAX]; /* Plug records */ -unsigned int ns3plug; -struct s3plugrec s3plug[S3PLUG_MAX]; +static unsigned int ns3plug; +static struct s3plugrec s3plug[S3PLUG_MAX]; /* CRC records */ -unsigned int ns3crc; -struct s3crcrec s3crc[S3CRC_MAX]; +static unsigned int ns3crc; +static struct s3crcrec s3crc[S3CRC_MAX]; /* Info records */ -unsigned int ns3info; -struct s3inforec s3info[S3INFO_MAX]; +static unsigned int ns3info; +static struct s3inforec s3info[S3INFO_MAX]; /* S7 record (there _better_ be only one) */ -u32 startaddr; +static u32 startaddr; /* Load image chunks */ -unsigned int nfchunks; -struct imgchunk fchunk[CHUNKS_MAX]; +static unsigned int nfchunks; +static struct imgchunk fchunk[CHUNKS_MAX]; /* Note that for the following pdrec_t arrays, the len and code */ /* fields are stored in HOST byte order. The mkpdrlist() function */ @@ -151,11 +151,11 @@ struct imgchunk fchunk[CHUNKS_MAX]; /*----------------------------------------------------------------*/ /* PDA, built from [card|newfile]+[addfile1+addfile2...] */ -struct pda pda; -hfa384x_compident_t nicid; -hfa384x_caplevel_t rfid; -hfa384x_caplevel_t macid; -hfa384x_caplevel_t priid; +static struct pda pda; +static hfa384x_compident_t nicid; +static hfa384x_caplevel_t rfid; +static hfa384x_caplevel_t macid; +static hfa384x_caplevel_t priid; /*================================================================*/ /* Local Function Declarations */ @@ -237,7 +237,7 @@ int prism2_fwtry(struct usb_device *udev, wlandevice_t *wlandev) * 0 - success * ~0 - failure ----------------------------------------------------------------*/ -int prism2_fwapply(const struct ihex_binrec *rfptr, wlandevice_t *wlandev) +static int prism2_fwapply(const struct ihex_binrec *rfptr, wlandevice_t *wlandev) { signed int result = 0; struct p80211msg_dot11req_mibget getmsg; @@ -376,7 +376,7 @@ int prism2_fwapply(const struct ihex_binrec *rfptr, wlandevice_t *wlandev) * 0 success * ~0 failure ----------------------------------------------------------------*/ -int crcimage(struct imgchunk *fchunk, unsigned int nfchunks, +static int crcimage(struct imgchunk *fchunk, unsigned int nfchunks, struct s3crcrec *s3crc, unsigned int ns3crc) { int result = 0; @@ -440,7 +440,7 @@ int crcimage(struct imgchunk *fchunk, unsigned int nfchunks, * Returns: * nothing ----------------------------------------------------------------*/ -void free_chunks(struct imgchunk *fchunk, unsigned int *nfchunks) +static void free_chunks(struct imgchunk *fchunk, unsigned int *nfchunks) { int i; for (i = 0; i < *nfchunks; i++) @@ -462,7 +462,7 @@ void free_chunks(struct imgchunk *fchunk, unsigned int *nfchunks) * Returns: * nothing ----------------------------------------------------------------*/ -void free_srecs(void) +static void free_srecs(void) { ns3data = 0; memset(s3data, 0, sizeof(s3data)); @@ -489,7 +489,7 @@ void free_srecs(void) * 0 - success * ~0 - failure (probably an errno) ----------------------------------------------------------------*/ -int mkimage(struct imgchunk *clist, unsigned int *ccnt) +static int mkimage(struct imgchunk *clist, unsigned int *ccnt) { int result = 0; int i; @@ -582,7 +582,7 @@ int mkimage(struct imgchunk *clist, unsigned int *ccnt) * 0 - success * ~0 - failure (probably an errno) ----------------------------------------------------------------*/ -int mkpdrlist(struct pda *pda) +static int mkpdrlist(struct pda *pda) { int result = 0; u16 *pda16 = (u16 *) pda->buf; @@ -656,7 +656,7 @@ int mkpdrlist(struct pda *pda) * 0 success * ~0 failure ----------------------------------------------------------------*/ -int plugimage(struct imgchunk *fchunk, unsigned int nfchunks, +static int plugimage(struct imgchunk *fchunk, unsigned int nfchunks, struct s3plugrec *s3plug, unsigned int ns3plug, struct pda *pda) { int result = 0; @@ -764,7 +764,7 @@ int plugimage(struct imgchunk *fchunk, unsigned int nfchunks, * 0 - success * ~0 - failure (probably an errno) ----------------------------------------------------------------*/ -int read_cardpda(struct pda *pda, wlandevice_t *wlandev) +static int read_cardpda(struct pda *pda, wlandevice_t *wlandev) { int result = 0; struct p80211msg_p2req_readpda msg; @@ -806,7 +806,7 @@ int read_cardpda(struct pda *pda, wlandevice_t *wlandev) * * Note also that the start address record, originally an S7 record in * the srec file, is expected in the fw file to be like a data record but -* with a certain address to make it identiable. +* with a certain address to make it identifiable. * * Here's the SREC format that the fw should have come from: * S[37]nnaaaaaaaaddd...dddcc @@ -854,7 +854,7 @@ int read_cardpda(struct pda *pda, wlandevice_t *wlandev) * 0 - success * ~0 - failure (probably an errno) ----------------------------------------------------------------*/ -int read_fwfile(const struct ihex_binrec *record) +static int read_fwfile(const struct ihex_binrec *record) { int i; int rcnt = 0; @@ -978,7 +978,7 @@ int read_fwfile(const struct ihex_binrec *record) * 0 success * ~0 failure ----------------------------------------------------------------*/ -int writeimage(wlandevice_t *wlandev, struct imgchunk *fchunk, +static int writeimage(wlandevice_t *wlandev, struct imgchunk *fchunk, unsigned int nfchunks) { int result = 0; @@ -1130,7 +1130,7 @@ free_result: return result; } -int validate_identity(void) +static int validate_identity(void) { int i; int result = 1; diff --git a/drivers/staging/wlan-ng/prism2sta.c b/drivers/staging/wlan-ng/prism2sta.c index 1dfd9aa5e9fe..8d2277bb898f 100644 --- a/drivers/staging/wlan-ng/prism2sta.c +++ b/drivers/staging/wlan-ng/prism2sta.c @@ -242,7 +242,6 @@ static int prism2sta_close(wlandevice_t *wlandev) ----------------------------------------------------------------*/ static void prism2sta_reset(wlandevice_t *wlandev) { - return; } /*---------------------------------------------------------------- @@ -988,7 +987,6 @@ static void prism2sta_inf_handover(wlandevice_t *wlandev, hfa384x_InfFrame_t *inf) { pr_debug("received infoframe:HANDOVER (unhandled)\n"); - return; } /*---------------------------------------------------------------- @@ -1035,8 +1033,6 @@ static void prism2sta_inf_tallies(wlandevice_t *wlandev, for (i = 0; i < cnt; i++, dst++, src16++) *dst += le16_to_cpu(*src16); } - - return; } /*---------------------------------------------------------------- @@ -1093,8 +1089,6 @@ static void prism2sta_inf_scanresults(wlandevice_t *wlandev, printk(KERN_ERR "setconfig(joinreq) failed, result=%d\n", result); } - - return; } /*---------------------------------------------------------------- @@ -1194,7 +1188,6 @@ static void prism2sta_inf_chinforesults(wlandevice_t *wlandev, atomic_set(&hw->channel_info.done, 2); hw->channel_info.count = n; - return; } void prism2sta_processing_defer(struct work_struct *data) @@ -1218,7 +1211,7 @@ void prism2sta_processing_defer(struct work_struct *data) /* Now let's handle the linkstatus stuff */ if (hw->link_status == hw->link_status_new) - goto failed; + return; hw->link_status = hw->link_status_new; @@ -1272,7 +1265,7 @@ void prism2sta_processing_defer(struct work_struct *data) pr_debug ("getconfig(0x%02x) failed, result = %d\n", HFA384x_RID_CURRENTBSSID, result); - goto failed; + return; } result = hfa384x_drvr_getconfig(hw, @@ -1282,7 +1275,7 @@ void prism2sta_processing_defer(struct work_struct *data) pr_debug ("getconfig(0x%02x) failed, result = %d\n", HFA384x_RID_CURRENTSSID, result); - goto failed; + return; } prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *) &ssid, (p80211pstrd_t *) & @@ -1296,7 +1289,7 @@ void prism2sta_processing_defer(struct work_struct *data) pr_debug ("getconfig(0x%02x) failed, result = %d\n", HFA384x_RID_PORTSTATUS, result); - goto failed; + return; } wlandev->macmode = (portstatus == HFA384x_PSTATUS_CONN_IBSS) ? @@ -1355,7 +1348,7 @@ void prism2sta_processing_defer(struct work_struct *data) if (result) { pr_debug("getconfig(0x%02x) failed, result = %d\n", HFA384x_RID_CURRENTBSSID, result); - goto failed; + return; } result = hfa384x_drvr_getconfig(hw, @@ -1364,7 +1357,7 @@ void prism2sta_processing_defer(struct work_struct *data) if (result) { pr_debug("getconfig(0x%02x) failed, result = %d\n", HFA384x_RID_CURRENTSSID, result); - goto failed; + return; } prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *) &ssid, (p80211pstrd_t *) &wlandev->ssid); @@ -1443,14 +1436,10 @@ void prism2sta_processing_defer(struct work_struct *data) /* This is bad, IO port problems? */ printk(KERN_WARNING "unknown linkstatus=0x%02x\n", hw->link_status); - goto failed; - break; + return; } wlandev->linkstatus = (hw->link_status == HFA384x_LINK_CONNECTED); - -failed: - return; } /*---------------------------------------------------------------- @@ -1478,8 +1467,6 @@ static void prism2sta_inf_linkstatus(wlandevice_t *wlandev, hw->link_status_new = le16_to_cpu(inf->info.linkstatus.linkstatus); schedule_work(&hw->link_bh); - - return; } /*---------------------------------------------------------------- @@ -1540,8 +1527,6 @@ static void prism2sta_inf_assocstatus(wlandevice_t *wlandev, printk(KERN_WARNING "authfail assocstatus info frame received for authenticated station.\n"); } - - return; } /*---------------------------------------------------------------- @@ -1731,7 +1716,6 @@ static void prism2sta_inf_authreq_defer(wlandevice_t *wlandev, "setconfig(authenticatestation) failed, result=%d\n", result); } - return; } /*---------------------------------------------------------------- @@ -1758,8 +1742,6 @@ static void prism2sta_inf_psusercnt(wlandevice_t *wlandev, hfa384x_t *hw = (hfa384x_t *) wlandev->priv; hw->psusercount = le16_to_cpu(inf->info.psusercnt.usercnt); - - return; } /*---------------------------------------------------------------- @@ -1825,7 +1807,6 @@ void prism2sta_ev_info(wlandevice_t *wlandev, hfa384x_InfFrame_t *inf) "Unknown info type=0x%02x\n", inf->infotype); break; } - return; } /*---------------------------------------------------------------- @@ -1850,8 +1831,6 @@ void prism2sta_ev_info(wlandevice_t *wlandev, hfa384x_InfFrame_t *inf) void prism2sta_ev_txexc(wlandevice_t *wlandev, u16 status) { pr_debug("TxExc status=0x%x.\n", status); - - return; } /*---------------------------------------------------------------- @@ -1875,7 +1854,6 @@ void prism2sta_ev_tx(wlandevice_t *wlandev, u16 status) pr_debug("Tx Complete, status=0x%04x\n", status); /* update linux network stats */ wlandev->linux_stats.tx_packets++; - return; } /*---------------------------------------------------------------- @@ -1897,7 +1875,6 @@ void prism2sta_ev_tx(wlandevice_t *wlandev, u16 status) void prism2sta_ev_rx(wlandevice_t *wlandev, struct sk_buff *skb) { p80211netdev_rx(wlandev, skb); - return; } /*---------------------------------------------------------------- @@ -1919,7 +1896,6 @@ void prism2sta_ev_rx(wlandevice_t *wlandev, struct sk_buff *skb) void prism2sta_ev_alloc(wlandevice_t *wlandev) { netif_wake_queue(wlandev->netdev); - return; } /*---------------------------------------------------------------- @@ -1988,12 +1964,12 @@ void prism2sta_commsqual_defer(struct work_struct *data) int result = 0; if (hw->wlandev->hwremoved) - goto done; + return; /* we don't care if we're in AP mode */ if ((wlandev->macmode == WLAN_MACMODE_NONE) || (wlandev->macmode == WLAN_MACMODE_ESS_AP)) { - goto done; + return; } /* It only makes sense to poll these in non-IBSS */ @@ -2004,7 +1980,7 @@ void prism2sta_commsqual_defer(struct work_struct *data) if (result) { printk(KERN_ERR "error fetching commsqual\n"); - goto done; + return; } pr_debug("commsqual %d %d %d\n", @@ -2021,7 +1997,7 @@ void prism2sta_commsqual_defer(struct work_struct *data) if (result) { pr_debug("get signal rate failed, result = %d\n", result); - goto done; + return; } switch (mibitem->data) { @@ -2048,7 +2024,7 @@ void prism2sta_commsqual_defer(struct work_struct *data) if (result) { pr_debug("getconfig(0x%02x) failed, result = %d\n", HFA384x_RID_CURRENTBSSID, result); - goto done; + return; } result = hfa384x_drvr_getconfig(hw, @@ -2057,16 +2033,13 @@ void prism2sta_commsqual_defer(struct work_struct *data) if (result) { pr_debug("getconfig(0x%02x) failed, result = %d\n", HFA384x_RID_CURRENTSSID, result); - goto done; + return; } prism2mgmt_bytestr2pstr((hfa384x_bytestr_t *) &ssid, (p80211pstrd_t *) &wlandev->ssid); /* Reschedule timer */ mod_timer(&hw->commsqual_timer, jiffies + HZ); - -done: - ; } void prism2sta_commsqual_timer(unsigned long data) diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c index 64ffd70eb7dc..f775c5453845 100644 --- a/drivers/staging/xgifb/XGI_main_26.c +++ b/drivers/staging/xgifb/XGI_main_26.c @@ -6,6 +6,7 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +#include <linux/sizes.h> #include <linux/module.h> #ifdef CONFIG_MTRR @@ -329,6 +330,7 @@ static int XGIfb_validate_mode(struct xgifb_video_info *xgifb_info, int myindex) { u16 xres, yres; struct xgi_hw_device_info *hw_info = &xgifb_info->hw_info; + unsigned long required_mem; if (xgifb_info->chip == XG21) { if (xgifb_info->display2 == XGIFB_DISP_LCD) { @@ -345,13 +347,13 @@ static int XGIfb_validate_mode(struct xgifb_video_info *xgifb_info, int myindex) } } - return myindex; + goto check_memory; } /* FIXME: for now, all is valid on XG27 */ if (xgifb_info->chip == XG27) - return myindex; + goto check_memory; if (!(XGIbios_mode[myindex].chipset & MD_XGI315)) return -1; @@ -539,6 +541,12 @@ static int XGIfb_validate_mode(struct xgifb_video_info *xgifb_info, int myindex) case XGIFB_DISP_NONE: break; } + +check_memory: + required_mem = XGIbios_mode[myindex].xres * XGIbios_mode[myindex].yres * + XGIbios_mode[myindex].bpp / 8; + if (required_mem > xgifb_info->video_size) + return -1; return myindex; } @@ -913,17 +921,10 @@ static void XGIfb_post_setmode(struct xgifb_video_info *xgifb_info) } if ((filter >= 0) && (filter <= 7)) { - pr_debug("FilterTable[%d]-%d: %02x %02x %02x %02x\n", + pr_debug("FilterTable[%d]-%d: %*ph\n", filter_tb, filter, - XGI_TV_filter[filter_tb]. - filter[filter][0], - XGI_TV_filter[filter_tb]. - filter[filter][1], - XGI_TV_filter[filter_tb]. - filter[filter][2], - XGI_TV_filter[filter_tb]. - filter[filter][3] - ); + 4, XGI_TV_filter[filter_tb]. + filter[filter]); xgifb_reg_set( XGIPART2, 0x35, @@ -1404,11 +1405,10 @@ static int XGIfb_pan_display(struct fb_var_screeninfo *var, if (var->yoffset < 0 || var->yoffset >= info->var.yres_virtual || var->xoffset) return -EINVAL; - } else { - if (var->xoffset + info->var.xres > info->var.xres_virtual + } else if (var->xoffset + info->var.xres > info->var.xres_virtual || var->yoffset + info->var.yres - > info->var.yres_virtual) - return -EINVAL; + > info->var.yres_virtual) { + return -EINVAL; } err = XGIfb_pan_var(var, info); if (err < 0) @@ -1471,6 +1471,9 @@ static int XGIfb_get_dram_size(struct xgifb_video_info *xgifb_info) xgifb_reg_set(XGISR, IND_SIS_DRAM_SIZE, 0x51); reg = xgifb_reg_get(XGISR, IND_SIS_DRAM_SIZE); + if (!reg) + return -1; + switch ((reg & XGI_DRAM_SIZE_MASK) >> 4) { case XGI_DRAM_SIZE_1MB: xgifb_info->video_size = 0x100000; @@ -1701,6 +1704,7 @@ static int __devinit xgifb_probe(struct pci_dev *pdev, struct fb_info *fb_info; struct xgifb_video_info *xgifb_info; struct xgi_hw_device_info *hw_info; + unsigned long video_size_max; fb_info = framebuffer_alloc(sizeof(*xgifb_info), &pdev->dev); if (!fb_info) @@ -1721,6 +1725,7 @@ static int __devinit xgifb_probe(struct pci_dev *pdev, xgifb_info->subsysvendor = pdev->subsystem_vendor; xgifb_info->subsysdevice = pdev->subsystem_device; + video_size_max = pci_resource_len(pdev, 0); xgifb_info->video_base = pci_resource_start(pdev, 0); xgifb_info->mmio_base = pci_resource_start(pdev, 1); xgifb_info->mmio_size = pci_resource_len(pdev, 1); @@ -1777,10 +1782,10 @@ static int __devinit xgifb_probe(struct pci_dev *pdev, hw_info->jChipType = xgifb_info->chip; if (XGIfb_get_dram_size(xgifb_info)) { - dev_err(&pdev->dev, - "Fatal error: Unable to determine RAM size.\n"); - ret = -ENODEV; - goto error_disable; + xgifb_info->video_size = min_t(unsigned long, video_size_max, + SZ_16M); + } else if (xgifb_info->video_size > video_size_max) { + xgifb_info->video_size = video_size_max; } /* Enable PCI_LINEAR_ADDRESSING and MMIO_ENABLE */ diff --git a/drivers/staging/xgifb/vb_def.h b/drivers/staging/xgifb/vb_def.h index 69078d933a47..77137e4452a0 100644 --- a/drivers/staging/xgifb/vb_def.h +++ b/drivers/staging/xgifb/vb_def.h @@ -3,9 +3,7 @@ #include "../../video/sis/initdef.h" #define VB_XGI301C 0x0020 /* for 301C */ -#define VB_YPbPr1080i 0x03 -#define LVDSCRT1Len 15 #define SupportCRT2in301C 0x0100 /* for 301C */ #define SetCHTVOverScan 0x8000 @@ -22,15 +20,6 @@ #define XGI_CRT2_PORT_00 (0x00 - 0x030) -/* ============================================================= - for 310 -============================================================== */ -#define ModeSoftSetting 0x04 - -/* ---------------- SetMode Stack */ -#define CRT1Len 15 -#define VCLKLen 4 - #define SupportAllCRT2 0x0078 #define NoSupportTV 0x0070 #define NoSupportHiVisionTV 0x0060 @@ -115,16 +104,6 @@ #define ActiveHiTV 0x08 #define ActiveYPbPr 0x10 -/* --------------------------------------------------------- */ -/* translated from asm code 301def.h */ -/* */ -/* --------------------------------------------------------- */ -#define LVDSCRT1Len_H 8 -#define LVDSCRT1Len_V 7 -#define LCDDesDataLen 6 -#define LVDSDesDataLen2 8 -#define LCDDesDataLen2 8 - #define NTSC1024x768HT 1908 #define YPbPrTV525iHT 1716 /* YPbPr */ diff --git a/drivers/staging/xgifb/vb_init.c b/drivers/staging/xgifb/vb_init.c index 80dba6a425ba..7739dbd9f029 100644 --- a/drivers/staging/xgifb/vb_init.c +++ b/drivers/staging/xgifb/vb_init.c @@ -1269,7 +1269,7 @@ static unsigned char GetXG27FPBits(struct vb_device_info *pVBInfo) if (temp <= 2) temp &= 0x03; else - temp = ((temp & 0x04) >> 1) || ((~temp) & 0x01); + temp = ((temp & 0x04) >> 1) | ((~temp) & 0x01); xgifb_reg_set(pVBInfo->P3d4, 0x4A, CR4A); @@ -1299,8 +1299,6 @@ unsigned char XGIInitNew(struct pci_dev *pdev) outb(0x67, (pVBInfo->BaseAddr + 0x12)); /* 3c2 <- 67 ,ynlai */ - pVBInfo->ISXPDOS = 0; - pVBInfo->P3c4 = pVBInfo->BaseAddr + 0x14; pVBInfo->P3d4 = pVBInfo->BaseAddr + 0x24; pVBInfo->P3c0 = pVBInfo->BaseAddr + 0x10; @@ -1494,7 +1492,6 @@ unsigned char XGIInitNew(struct pci_dev *pdev) XGINew_SetModeScratch(HwDeviceExtension, pVBInfo); xgifb_reg_set(pVBInfo->P3d4, 0x8c, 0x87); - xgifb_reg_set(pVBInfo->P3c4, 0x14, 0x31); return 1; } /* end of init */ diff --git a/drivers/staging/xgifb/vb_setmode.c b/drivers/staging/xgifb/vb_setmode.c index e81149fc66e3..e95a1655a6ce 100644 --- a/drivers/staging/xgifb/vb_setmode.c +++ b/drivers/staging/xgifb/vb_setmode.c @@ -23,20 +23,18 @@ static const unsigned short XGINew_VGA_DAC[] = { void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo) { - pVBInfo->StandTable = (struct SiS_StandTable_S *) &XGI330_StandTable; - pVBInfo->EModeIDTable = (struct XGI_ExtStruct *) XGI330_EModeIDTable; - pVBInfo->RefIndex = (struct XGI_Ext2Struct *) XGI330_RefIndex; - pVBInfo->XGINEWUB_CRT1Table - = (struct XGI_CRT1TableStruct *) XGI_CRT1Table; - - pVBInfo->MCLKData = (struct SiS_MCLKData *) XGI340New_MCLKData; - pVBInfo->ECLKData = (struct XGI_ECLKDataStruct *) XGI340_ECLKData; - pVBInfo->VCLKData = (struct SiS_VCLKData *) XGI_VCLKData; - pVBInfo->VBVCLKData = (struct SiS_VBVCLKData *) XGI_VBVCLKData; + pVBInfo->StandTable = &XGI330_StandTable; + pVBInfo->EModeIDTable = XGI330_EModeIDTable; + pVBInfo->RefIndex = XGI330_RefIndex; + pVBInfo->XGINEWUB_CRT1Table = XGI_CRT1Table; + + pVBInfo->MCLKData = XGI340New_MCLKData; + pVBInfo->ECLKData = XGI340_ECLKData; + pVBInfo->VCLKData = XGI_VCLKData; + pVBInfo->VBVCLKData = XGI_VBVCLKData; pVBInfo->ScreenOffset = XGI330_ScreenOffset; - pVBInfo->StResInfo = (struct SiS_StResInfo_S *) XGI330_StResInfo; - pVBInfo->ModeResInfo - = (struct SiS_ModeResInfo_S *) XGI330_ModeResInfo; + pVBInfo->StResInfo = XGI330_StResInfo; + pVBInfo->ModeResInfo = XGI330_ModeResInfo; pVBInfo->LCDResInfo = 0; pVBInfo->LCDTypeInfo = 0; @@ -56,24 +54,9 @@ void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo) pVBInfo->SR21 = 0xa3; pVBInfo->SR22 = 0xfb; - pVBInfo->NTSCTiming = XGI330_NTSCTiming; - pVBInfo->PALTiming = XGI330_PALTiming; - pVBInfo->HiTVExtTiming = XGI330_HiTVExtTiming; - pVBInfo->HiTVSt1Timing = XGI330_HiTVSt1Timing; - pVBInfo->HiTVSt2Timing = XGI330_HiTVSt2Timing; - pVBInfo->HiTVTextTiming = XGI330_HiTVTextTiming; - pVBInfo->YPbPr750pTiming = XGI330_YPbPr750pTiming; - pVBInfo->YPbPr525pTiming = XGI330_YPbPr525pTiming; - pVBInfo->YPbPr525iTiming = XGI330_YPbPr525iTiming; - pVBInfo->HiTVGroup3Data = XGI330_HiTVGroup3Data; - pVBInfo->HiTVGroup3Simu = XGI330_HiTVGroup3Simu; - pVBInfo->HiTVGroup3Text = XGI330_HiTVGroup3Text; - pVBInfo->Ren525pGroup3 = XGI330_Ren525pGroup3; - pVBInfo->Ren750pGroup3 = XGI330_Ren750pGroup3; - - pVBInfo->TimingH = (struct XGI_TimingHStruct *) XGI_TimingH; - pVBInfo->TimingV = (struct XGI_TimingVStruct *) XGI_TimingV; - pVBInfo->UpdateCRT1 = (struct XGI_XG21CRT1Struct *) XGI_UpdateCRT1Table; + pVBInfo->TimingH = XGI_TimingH; + pVBInfo->TimingV = XGI_TimingV; + pVBInfo->UpdateCRT1 = XGI_UpdateCRT1Table; /* 310 customization related */ if ((pVBInfo->VBType & VB_SIS301LV) || (pVBInfo->VBType & VB_SIS302LV)) @@ -86,8 +69,7 @@ void InitTo330Pointer(unsigned char ChipType, struct vb_device_info *pVBInfo) if (ChipType == XG27) { unsigned char temp; - pVBInfo->MCLKData - = (struct SiS_MCLKData *) XGI27New_MCLKData; + pVBInfo->MCLKData = XGI27New_MCLKData; pVBInfo->CR40 = XGI27_cr41; pVBInfo->XGINew_CR97 = 0xc1; pVBInfo->SR15 = XG27_SR13; @@ -116,11 +98,9 @@ static void XGI_SetSeqRegs(unsigned short ModeNo, i = XGI_SetCRT2ToLCDA; if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) { tempah |= 0x01; - } else { - if (pVBInfo->VBInfo & (SetCRT2ToTV | SetCRT2ToLCD)) { - if (pVBInfo->VBInfo & SetInSlaveMode) - tempah |= 0x01; - } + } else if (pVBInfo->VBInfo & (SetCRT2ToTV | SetCRT2ToLCD)) { + if (pVBInfo->VBInfo & SetInSlaveMode) + tempah |= 0x01; } tempah |= 0x20; /* screen off */ @@ -165,10 +145,9 @@ static void XGI_SetATTRegs(unsigned short ModeNo, if ((modeflag & Charx8Dot) && i == 0x13) { /* ifndef Dot9 */ if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) { ARdata = 0; - } else { - if ((pVBInfo->VBInfo & + } else if ((pVBInfo->VBInfo & (SetCRT2ToTV | SetCRT2ToLCD)) && - (pVBInfo->VBInfo & SetInSlaveMode)) + (pVBInfo->VBInfo & SetInSlaveMode)) { ARdata = 0; } } @@ -258,59 +237,45 @@ static unsigned char XGI_AjustCRT2Rate(unsigned short ModeNo, } if (pVBInfo->VBInfo & SetCRT2ToHiVision) { /* for HiTV */ - if ((pVBInfo->VBType & VB_SIS301LV) && - (pVBInfo->VBExtInfo == VB_YPbPr1080i)) { - tempax |= SupportYPbPr750p; - if ((pVBInfo->VBInfo & SetInSlaveMode) && - ((resinfo == 3) || - (resinfo == 4) || - (resinfo > 7))) + tempax |= SupportHiVision; + if ((pVBInfo->VBInfo & SetInSlaveMode) && + ((resinfo == 4) || + (resinfo == 3 && + (pVBInfo->SetFlag & TVSimuMode)) || + (resinfo > 7))) return 0; - } else { - tempax |= SupportHiVision; - if ((pVBInfo->VBInfo & SetInSlaveMode) && - ((resinfo == 4) || - (resinfo == 3 && - (pVBInfo->SetFlag & TVSimuMode)) || - (resinfo > 7))) - return 0; - } - } else { - if (pVBInfo->VBInfo & (SetCRT2ToAVIDEO | + } else if (pVBInfo->VBInfo & (SetCRT2ToAVIDEO | SetCRT2ToSVIDEO | SetCRT2ToSCART | SetCRT2ToYPbPr525750 | SetCRT2ToHiVision)) { - tempax |= SupportTV; - - if (pVBInfo->VBType & (VB_SIS301B | - VB_SIS302B | - VB_SIS301LV | - VB_SIS302LV | - VB_XGI301C)) - tempax |= SupportTV1024; - - if (!(pVBInfo->VBInfo & TVSetPAL) && - (modeflag & NoSupportSimuTV) && - (pVBInfo->VBInfo & SetInSlaveMode) && - (!(pVBInfo->VBInfo & SetNotSimuMode))) - return 0; - } + tempax |= SupportTV; + + if (pVBInfo->VBType & (VB_SIS301B | + VB_SIS302B | + VB_SIS301LV | + VB_SIS302LV | + VB_XGI301C)) + tempax |= SupportTV1024; + + if (!(pVBInfo->VBInfo & TVSetPAL) && + (modeflag & NoSupportSimuTV) && + (pVBInfo->VBInfo & SetInSlaveMode) && + (!(pVBInfo->VBInfo & SetNotSimuMode))) + return 0; } - } else { /* for LVDS */ - if (pVBInfo->VBInfo & SetCRT2ToLCD) { - tempax |= SupportLCD; + } else if (pVBInfo->VBInfo & SetCRT2ToLCD) { /* for LVDS */ + tempax |= SupportLCD; - if (resinfo > 0x08) - return 0; /* 1024x768 */ + if (resinfo > 0x08) + return 0; /* 1024x768 */ - if (pVBInfo->LCDResInfo < Panel_1024x768) { - if (resinfo > 0x07) - return 0; /* 800x600 */ + if (pVBInfo->LCDResInfo < Panel_1024x768) { + if (resinfo > 0x07) + return 0; /* 800x600 */ - if (resinfo == 0x04) - return 0; /* 512x384 */ - } + if (resinfo == 0x04) + return 0; /* 512x384 */ } } @@ -969,13 +934,8 @@ static unsigned short XGI_GetVCLK2Ptr(unsigned short ModeNo, } /* 301lv */ - if ((pVBInfo->VBType & VB_SIS301LV) && - !(pVBInfo->VBExtInfo == VB_YPbPr1080i)) { - if (pVBInfo->VBExtInfo == YPbPr750p) - VCLKIndex = XGI_YPbPr750pVCLK; - else if (pVBInfo->VBExtInfo == YPbPr525p) - VCLKIndex = YPbPr525pVCLK; - else if (pVBInfo->SetFlag & RPLLDIV2XO) + if (pVBInfo->VBType & VB_SIS301LV) { + if (pVBInfo->SetFlag & RPLLDIV2XO) VCLKIndex = YPbPr525iVCLK_2; else VCLKIndex = YPbPr525iVCLK; @@ -991,13 +951,11 @@ static unsigned short XGI_GetVCLK2Ptr(unsigned short ModeNo, Ext_CRTVCLK; VCLKIndex &= IndexMask; } - } else { /* LVDS */ - if ((pVBInfo->LCDResInfo == Panel_800x600) || - (pVBInfo->LCDResInfo == Panel_320x480)) - VCLKIndex = VCLK40; /* LVDSXlat1VCLK */ - else - VCLKIndex = VCLK65_315 + 2; /* LVDSXlat2VCLK, - LVDSXlat3VCLK */ + } else if ((pVBInfo->LCDResInfo == Panel_800x600) || + (pVBInfo->LCDResInfo == Panel_320x480)) { /* LVDS */ + VCLKIndex = VCLK40; /* LVDSXlat1VCLK */ + } else { + VCLKIndex = VCLK65_315 + 2; /* LVDSXlat2VCLK, LVDSXlat3VCLK */ } return VCLKIndex; @@ -1352,7 +1310,7 @@ static void *XGI_GetLcdPtr(unsigned short BX, unsigned short ModeNo, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo) { - unsigned short i, tempdx, tempcx, tempbx, tempal, modeflag, table; + unsigned short i, tempdx, tempbx, tempal, modeflag, table; struct XGI330_LCDDataTablStruct *tempdi = NULL; @@ -1377,15 +1335,6 @@ static void *XGI_GetLcdPtr(unsigned short BX, unsigned short ModeNo, tempal = (tempal & 0x0f); } - tempcx = LCDLenList[tempbx]; - - if (pVBInfo->LCDInfo & EnableScalingLCD) { /* ScaleLCD */ - if ((tempbx == 5) || (tempbx) == 7) - tempcx = LCDDesDataLen2; - else if ((tempbx == 3) || (tempbx == 8)) - tempcx = LVDSDesDataLen2; - } - switch (tempbx) { case 0: case 1: @@ -1403,14 +1352,6 @@ static void *XGI_GetLcdPtr(unsigned short BX, unsigned short ModeNo, case 5: tempdi = XGI_LCDDesDataTable; break; - case 6: - tempdi = XGI_EPLCHLCDRegPtr; - break; - case 7: - case 8: - case 9: - tempdi = NULL; - break; default: break; } @@ -1764,62 +1705,20 @@ static void *XGI_GetLcdPtr(unsigned short BX, unsigned short ModeNo, default: break; } - } else if (table == 6) { - switch (tempdi[i].DATAPTR) { - case 0: - return &XGI_CH7017LV1024x768[tempal]; - break; - case 1: - return &XGI_CH7017LV1400x1050[tempal]; - break; - default: - break; - } } return NULL; } -static void *XGI_GetTVPtr(unsigned short BX, unsigned short ModeNo, +static struct SiS_TVData const *XGI_GetTVPtr(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short RefreshRateTableIndex, struct vb_device_info *pVBInfo) { - unsigned short i, tempdx, tempbx, tempal, modeflag, table; - struct XGI330_TVDataTablStruct *tempdi = NULL; + unsigned short i, tempdx, tempal, modeflag; - tempbx = BX; modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; tempal = pVBInfo->RefIndex[RefreshRateTableIndex].Ext_CRT2CRTC; tempal = tempal & 0x3f; - table = tempbx; - - switch (tempbx) { - case 0: - tempdi = NULL; - break; - case 1: - tempdi = NULL; - break; - case 2: - case 6: - tempdi = xgifb_chrontel_tv; - break; - case 3: - tempdi = NULL; - break; - case 4: - tempdi = XGI_TVDataTable; - break; - case 5: - tempdi = NULL; - break; - default: - break; - } - - if (tempdi == NULL) /* OEMUtil */ - return NULL; - tempdx = pVBInfo->TVInfo; if (pVBInfo->VBInfo & SetInSlaveMode) @@ -1830,78 +1729,14 @@ static void *XGI_GetTVPtr(unsigned short BX, unsigned short ModeNo, i = 0; - while (tempdi[i].MASK != 0xffff) { - if ((tempdx & tempdi[i].MASK) == tempdi[i].CAP) + while (XGI_TVDataTable[i].MASK != 0xffff) { + if ((tempdx & XGI_TVDataTable[i].MASK) == + XGI_TVDataTable[i].CAP) break; i++; } - if (table == 0x04) { - switch (tempdi[i].DATAPTR) { - case 0: - return &XGI_ExtPALData[tempal]; - break; - case 1: - return &XGI_ExtNTSCData[tempal]; - break; - case 2: - return &XGI_StPALData[tempal]; - break; - case 3: - return &XGI_StNTSCData[tempal]; - break; - case 4: - return &XGI_ExtHiTVData[tempal]; - break; - case 5: - return &XGI_St2HiTVData[tempal]; - break; - case 6: - return &XGI_ExtYPbPr525iData[tempal]; - break; - case 7: - return &XGI_ExtYPbPr525pData[tempal]; - break; - case 8: - return &XGI_ExtYPbPr750pData[tempal]; - break; - case 9: - return &XGI_StYPbPr525iData[tempal]; - break; - case 10: - return &XGI_StYPbPr525pData[tempal]; - break; - case 11: - return &XGI_StYPbPr750pData[tempal]; - break; - case 12: /* avoid system hang */ - return &XGI_ExtNTSCData[tempal]; - break; - case 13: - return &XGI_St1HiTVData[tempal]; - break; - default: - break; - } - } else if (table == 0x02) { - switch (tempdi[i].DATAPTR) { - case 0: - return &XGI_CHTVUNTSCData[tempal]; - break; - case 1: - return &XGI_CHTVONTSCData[tempal]; - break; - case 2: - return &XGI_CHTVUPALData[tempal]; - break; - case 3: - return &XGI_CHTVOPALData[tempal]; - break; - default: - break; - } - } - return NULL; + return &XGI_TVDataTable[i].DATAPTR[tempal]; } static void XGI_GetLVDSData(unsigned short ModeNo, unsigned short ModeIdIndex, @@ -1914,9 +1749,8 @@ static void XGI_GetLVDSData(unsigned short ModeNo, unsigned short ModeIdIndex, tempbx = 2; if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) { - LCDPtr = (struct SiS_LVDSData *)XGI_GetLcdPtr(tempbx, - ModeNo, ModeIdIndex, RefreshRateTableIndex, - pVBInfo); + LCDPtr = XGI_GetLcdPtr(tempbx, ModeNo, ModeIdIndex, + RefreshRateTableIndex, pVBInfo); pVBInfo->VGAHT = LCDPtr->VGAHT; pVBInfo->VGAVT = LCDPtr->VGAVT; pVBInfo->HT = LCDPtr->LCDHT; @@ -1962,11 +1796,8 @@ static void XGI_ModCRT1Regs(unsigned short ModeNo, unsigned short ModeIdIndex, tempbx = 0; if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) { - LCDPtr = (struct XGI_LVDSCRT1HDataStruct *) - XGI_GetLcdPtr(tempbx, ModeNo, - ModeIdIndex, - RefreshRateTableIndex, - pVBInfo); + LCDPtr = XGI_GetLcdPtr(tempbx, ModeNo, ModeIdIndex, + RefreshRateTableIndex, pVBInfo); for (i = 0; i < 8; i++) pVBInfo->TimingH[0].data[i] = LCDPtr[0].Reg[i]; @@ -1977,13 +1808,8 @@ static void XGI_ModCRT1Regs(unsigned short ModeNo, unsigned short ModeIdIndex, tempbx = 1; if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) { - LCDPtr1 = (struct XGI_LVDSCRT1VDataStruct *) - XGI_GetLcdPtr( - tempbx, - ModeNo, - ModeIdIndex, - RefreshRateTableIndex, - pVBInfo); + LCDPtr1 = XGI_GetLcdPtr(tempbx, ModeNo, ModeIdIndex, + RefreshRateTableIndex, pVBInfo); for (i = 0; i < 7; i++) pVBInfo->TimingV[0].data[i] = LCDPtr1[0].Reg[i]; } @@ -2075,23 +1901,11 @@ static void XGI_SetLVDSRegs(unsigned short ModeNo, unsigned short ModeIdIndex, modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; tempbx = 3; if (pVBInfo->LCDInfo & EnableScalingLCD) - LCDPtr1 = - (struct XGI330_LCDDataDesStruct2 *) - XGI_GetLcdPtr( - tempbx, - ModeNo, - ModeIdIndex, - RefreshRateTableIndex, - pVBInfo); + LCDPtr1 = XGI_GetLcdPtr(tempbx, ModeNo, ModeIdIndex, + RefreshRateTableIndex, pVBInfo); else - LCDPtr = - (struct XGI_LCDDesStruct *) - XGI_GetLcdPtr( - tempbx, - ModeNo, - ModeIdIndex, - RefreshRateTableIndex, - pVBInfo); + LCDPtr = XGI_GetLcdPtr(tempbx, ModeNo, ModeIdIndex, + RefreshRateTableIndex, pVBInfo); XGI_GetLCDSync(&tempax, &tempbx, pVBInfo); push1 = tempbx; @@ -2438,8 +2252,8 @@ static void XGI_GetVCLKLen(unsigned char tempal, unsigned char *di_0, | VB_SIS301LV | VB_SIS302LV | VB_XGI301C)) { if ((!(pVBInfo->VBInfo & XGI_SetCRT2ToLCDA)) && (pVBInfo->SetFlag & ProgrammingCRT2)) { - *di_0 = (unsigned char) XGI_VBVCLKData[tempal].SR2B; - *di_1 = XGI_VBVCLKData[tempal].SR2C; + *di_0 = XGI_VBVCLKData[tempal].Part4_A; + *di_1 = XGI_VBVCLKData[tempal].Part4_B; } } else { *di_0 = XGI_VCLKData[tempal].SR2B; @@ -2634,21 +2448,16 @@ static void XGI_GetVBInfo(unsigned short ModeNo, unsigned short ModeIdIndex, temp = xgifb_reg_get(pVBInfo->P3d4, 0x38); - if (pVBInfo->IF_DEF_LCDA == 1) { - - if (((HwDeviceExtension->jChipType >= XG20) || - (HwDeviceExtension->jChipType >= XG40)) && - (pVBInfo->IF_DEF_LVDS == 0)) { - if (pVBInfo->VBType & - (VB_SIS302B | - VB_SIS301LV | - VB_SIS302LV | - VB_XGI301C)) { - if (temp & EnableDualEdge) { - tempbx |= SetCRT2ToDualEdge; - if (temp & SetToLCDA) - tempbx |= XGI_SetCRT2ToLCDA; - } + if (pVBInfo->IF_DEF_LVDS == 0) { + if (pVBInfo->VBType & + (VB_SIS302B | + VB_SIS301LV | + VB_SIS302LV | + VB_XGI301C)) { + if (temp & EnableDualEdge) { + tempbx |= SetCRT2ToDualEdge; + if (temp & SetToLCDA) + tempbx |= XGI_SetCRT2ToLCDA; } } } @@ -2687,11 +2496,10 @@ static void XGI_GetVBInfo(unsigned short ModeNo, unsigned short ModeIdIndex, temp = 0x09FC; else temp = 0x097C; + } else if (pVBInfo->IF_DEF_HiVision == 1) { + temp = 0x01FC; } else { - if (pVBInfo->IF_DEF_HiVision == 1) - temp = 0x01FC; - else - temp = 0x017C; + temp = 0x017C; } } else { /* 3nd party chip */ temp = SetCRT2ToLCD; @@ -2702,19 +2510,17 @@ static void XGI_GetVBInfo(unsigned short ModeNo, unsigned short ModeIdIndex, tempbx = 0; } - if (pVBInfo->IF_DEF_LCDA == 1) { /* Select Display Device */ - if (!(pVBInfo->VBType & VB_NoLCD)) { - if (tempbx & XGI_SetCRT2ToLCDA) { - if (tempbx & SetSimuScanMode) - tempbx &= (~(SetCRT2ToLCD | - SetCRT2ToRAMDAC | - SwitchCRT2)); - else - tempbx &= (~(SetCRT2ToLCD | - SetCRT2ToRAMDAC | - SetCRT2ToTV | - SwitchCRT2)); - } + if (!(pVBInfo->VBType & VB_NoLCD)) { + if (tempbx & XGI_SetCRT2ToLCDA) { + if (tempbx & SetSimuScanMode) + tempbx &= (~(SetCRT2ToLCD | + SetCRT2ToRAMDAC | + SwitchCRT2)); + else + tempbx &= (~(SetCRT2ToLCD | + SetCRT2ToRAMDAC | + SetCRT2ToTV | + SwitchCRT2)); } } @@ -2777,11 +2583,9 @@ static void XGI_GetVBInfo(unsigned short ModeNo, unsigned short ModeIdIndex, if (!(tempbx & DisableCRT2Display)) { if ((!(tempbx & DriverMode)) || (!(modeflag & CRT2Mode))) { - if (pVBInfo->IF_DEF_LCDA == 1) { - if (!(tempbx & XGI_SetCRT2ToLCDA)) - tempbx |= (SetInSlaveMode | - SetSimuScanMode); - } + if (!(tempbx & XGI_SetCRT2ToLCDA)) + tempbx |= (SetInSlaveMode | + SetSimuScanMode); } /* LCD+TV can't support in slave mode @@ -2867,19 +2671,17 @@ static void XGI_GetTVInfo(unsigned short ModeNo, unsigned short ModeIdIndex, if (pVBInfo->VBInfo & SetCRT2ToHiVision) { if (pVBInfo->VBInfo & SetInSlaveMode) tempbx &= (~RPLLDIV2XO); - } else { - if (tempbx & - (TVSetYPbPr525p | TVSetYPbPr750p)) + } else if (tempbx & + (TVSetYPbPr525p | TVSetYPbPr750p)) { tempbx &= (~RPLLDIV2XO); - else if (!(pVBInfo->VBType & + } else if (!(pVBInfo->VBType & (VB_SIS301B | VB_SIS302B | VB_SIS301LV | VB_SIS302LV | VB_XGI301C))) { - if (tempbx & TVSimuMode) - tempbx &= (~RPLLDIV2XO); - } + if (tempbx & TVSimuMode) + tempbx &= (~RPLLDIV2XO); } } } @@ -2960,20 +2762,6 @@ static unsigned char XGI_GetLCDInfo(unsigned short ModeNo, tempbx |= SetLCDtoNonExpanding; } - if (pVBInfo->IF_DEF_ExpLink == 1) { - if (modeflag & HalfDCLK) { - if (!(tempbx & SetLCDtoNonExpanding)) { - tempbx |= XGI_EnableLVDSDDA; - } else { - if (pVBInfo->LCDResInfo == Panel_1024x768) { - if (resinfo == 4) {/* 512x384 */ - tempbx |= XGI_EnableLVDSDDA; - } - } - } - } - } - if (pVBInfo->VBInfo & SetInSlaveMode) { if (pVBInfo->VBInfo & SetNotSimuMode) tempbx |= XGI_LCDVESATiming; @@ -3122,33 +2910,6 @@ static void XGI_XG27BLSignalVDD(unsigned short tempbh, unsigned short tempbl, xgifb_reg_and_or(pVBInfo->P3d4, 0x48, ~tempbh, tempbl); } -/* --------------------------------------------------------------------- */ -/* Function : XGI_XG21SetPanelDelay */ -/* Input : */ -/* Output : */ -/* Description : */ -/* I/P : bl : 1 ; T1 : the duration between CPL on and signal on */ -/* : bl : 2 ; T2 : the duration signal on and Vdd on */ -/* : bl : 3 ; T3 : the duration between CPL off and signal off */ -/* : bl : 4 ; T4 : the duration signal off and Vdd off */ -/* --------------------------------------------------------------------- */ -static void XGI_XG21SetPanelDelay(struct xgifb_video_info *xgifb_info, - unsigned short tempbl, - struct vb_device_info *pVBInfo) -{ - if (tempbl == 1) - mdelay(xgifb_info->lvds_data.PSC_S1); - - if (tempbl == 2) - mdelay(xgifb_info->lvds_data.PSC_S2); - - if (tempbl == 3) - mdelay(xgifb_info->lvds_data.PSC_S3); - - if (tempbl == 4) - mdelay(xgifb_info->lvds_data.PSC_S4); -} - static void XGI_DisplayOn(struct xgifb_video_info *xgifb_info, struct xgi_hw_device_info *pXGIHWDE, struct vb_device_info *pVBInfo) @@ -3160,12 +2921,12 @@ static void XGI_DisplayOn(struct xgifb_video_info *xgifb_info, if (!(XGI_XG21GetPSCValue(pVBInfo) & 0x1)) { /* LVDS VDD on */ XGI_XG21BLSignalVDD(0x01, 0x01, pVBInfo); - XGI_XG21SetPanelDelay(xgifb_info, 2, pVBInfo); + mdelay(xgifb_info->lvds_data.PSC_S2); } if (!(XGI_XG21GetPSCValue(pVBInfo) & 0x20)) /* LVDS signal on */ XGI_XG21BLSignalVDD(0x20, 0x20, pVBInfo); - XGI_XG21SetPanelDelay(xgifb_info, 3, pVBInfo); + mdelay(xgifb_info->lvds_data.PSC_S3); /* LVDS backlight on */ XGI_XG21BLSignalVDD(0x02, 0x02, pVBInfo); } else { @@ -3180,12 +2941,12 @@ static void XGI_DisplayOn(struct xgifb_video_info *xgifb_info, if (!(XGI_XG27GetPSCValue(pVBInfo) & 0x1)) { /* LVDS VDD on */ XGI_XG27BLSignalVDD(0x01, 0x01, pVBInfo); - XGI_XG21SetPanelDelay(xgifb_info, 2, pVBInfo); + mdelay(xgifb_info->lvds_data.PSC_S2); } if (!(XGI_XG27GetPSCValue(pVBInfo) & 0x20)) /* LVDS signal on */ XGI_XG27BLSignalVDD(0x20, 0x20, pVBInfo); - XGI_XG21SetPanelDelay(xgifb_info, 3, pVBInfo); + mdelay(xgifb_info->lvds_data.PSC_S3); /* LVDS backlight on */ XGI_XG27BLSignalVDD(0x02, 0x02, pVBInfo); } else { @@ -3205,7 +2966,7 @@ void XGI_DisplayOff(struct xgifb_video_info *xgifb_info, if (pVBInfo->IF_DEF_LVDS == 1) { /* LVDS backlight off */ XGI_XG21BLSignalVDD(0x02, 0x00, pVBInfo); - XGI_XG21SetPanelDelay(xgifb_info, 3, pVBInfo); + mdelay(xgifb_info->lvds_data.PSC_S3); } else { /* DVO/DVI signal off */ XGI_XG21BLSignalVDD(0x20, 0x00, pVBInfo); @@ -3216,7 +2977,7 @@ void XGI_DisplayOff(struct xgifb_video_info *xgifb_info, if ((XGI_XG27GetPSCValue(pVBInfo) & 0x2)) { /* LVDS backlight off */ XGI_XG27BLSignalVDD(0x02, 0x00, pVBInfo); - XGI_XG21SetPanelDelay(xgifb_info, 3, pVBInfo); + mdelay(xgifb_info->lvds_data.PSC_S3); } if (pVBInfo->IF_DEF_LVDS == 0) @@ -3378,7 +3139,6 @@ static void XGI_GetCRT2Data(unsigned short ModeNo, unsigned short ModeIdIndex, unsigned short tempax = 0, tempbx, modeflag, resinfo; struct SiS_LCDData *LCDPtr = NULL; - struct SiS_TVData *TVPtr = NULL; /* si+Ext_ResInfo */ modeflag = pVBInfo->EModeIDTable[ModeIdIndex].Ext_ModeFlag; @@ -3395,9 +3155,8 @@ static void XGI_GetCRT2Data(unsigned short ModeNo, unsigned short ModeIdIndex, tempbx = 4; if (pVBInfo->VBInfo & (SetCRT2ToLCD | XGI_SetCRT2ToLCDA)) { - LCDPtr = (struct SiS_LCDData *) XGI_GetLcdPtr(tempbx, - ModeNo, ModeIdIndex, RefreshRateTableIndex, - pVBInfo); + LCDPtr = XGI_GetLcdPtr(tempbx, ModeNo, ModeIdIndex, + RefreshRateTableIndex, pVBInfo); pVBInfo->RVBHCMAX = LCDPtr->RVBHCMAX; pVBInfo->RVBHCFACT = LCDPtr->RVBHCFACT; @@ -3479,10 +3238,10 @@ static void XGI_GetCRT2Data(unsigned short ModeNo, unsigned short ModeIdIndex, } if (pVBInfo->VBInfo & (SetCRT2ToTV)) { - tempbx = 4; - TVPtr = (struct SiS_TVData *) XGI_GetTVPtr(tempbx, - ModeNo, ModeIdIndex, RefreshRateTableIndex, - pVBInfo); + struct SiS_TVData const *TVPtr; + + TVPtr = XGI_GetTVPtr(ModeNo, ModeIdIndex, RefreshRateTableIndex, + pVBInfo); pVBInfo->RVBHCMAX = TVPtr->RVBHCMAX; pVBInfo->RVBHCFACT = TVPtr->RVBHCFACT; @@ -3882,16 +3641,9 @@ static void XGI_SetLockRegs(unsigned short ModeNo, unsigned short ModeIdIndex, | VB_SIS302LV | VB_XGI301C))) temp += 2; - if (pVBInfo->VBInfo & SetCRT2ToHiVision) { - if (pVBInfo->VBType & VB_SIS301LV) { - if (pVBInfo->VBExtInfo == VB_YPbPr1080i) { - if (resinfo == 7) - temp -= 2; - } - } else if (resinfo == 7) { + if ((pVBInfo->VBInfo & SetCRT2ToHiVision) && + !(pVBInfo->VBType & VB_SIS301LV) && (resinfo == 7)) temp -= 2; - } - } } /* 0x05 Horizontal Display Start */ @@ -4061,18 +3813,16 @@ static void XGI_SetLockRegs(unsigned short ModeNo, unsigned short ModeIdIndex, } else { tempbx -= 10; } - } else { - if (pVBInfo->TVInfo & TVSimuMode) { - if (pVBInfo->TVInfo & TVSetPAL) { - if (pVBInfo->VBType & VB_SIS301LV) { - if (!(pVBInfo->TVInfo & - (TVSetYPbPr525p | - TVSetYPbPr750p | - TVSetHiVision))) - tempbx += 40; - } else { + } else if (pVBInfo->TVInfo & TVSimuMode) { + if (pVBInfo->TVInfo & TVSetPAL) { + if (pVBInfo->VBType & VB_SIS301LV) { + if (!(pVBInfo->TVInfo & + (TVSetYPbPr525p | + TVSetYPbPr750p | + TVSetHiVision))) tempbx += 40; - } + } else { + tempbx += 40; } } } @@ -4154,7 +3904,7 @@ static void XGI_SetGroup2(unsigned short ModeNo, unsigned short ModeIdIndex, { unsigned short i, j, tempax, tempbx, tempcx, temp, push1, push2, modeflag, resinfo, crt2crtc; - unsigned char *TimingPoint; + unsigned char const *TimingPoint; unsigned long longtemp, tempeax, tempebx, temp2, tempecx; @@ -4186,33 +3936,33 @@ static void XGI_SetGroup2(unsigned short ModeNo, unsigned short ModeIdIndex, tempax = (tempax & 0xff00) >> 8; xgifb_reg_set(pVBInfo->Part2Port, 0x0, tempax); - TimingPoint = pVBInfo->NTSCTiming; + TimingPoint = XGI330_NTSCTiming; if (pVBInfo->TVInfo & TVSetPAL) - TimingPoint = pVBInfo->PALTiming; + TimingPoint = XGI330_PALTiming; if (pVBInfo->VBInfo & SetCRT2ToHiVision) { - TimingPoint = pVBInfo->HiTVExtTiming; + TimingPoint = XGI330_HiTVExtTiming; if (pVBInfo->VBInfo & SetInSlaveMode) - TimingPoint = pVBInfo->HiTVSt2Timing; + TimingPoint = XGI330_HiTVSt2Timing; if (pVBInfo->SetFlag & TVSimuMode) - TimingPoint = pVBInfo->HiTVSt1Timing; + TimingPoint = XGI330_HiTVSt1Timing; if (!(modeflag & Charx8Dot)) - TimingPoint = pVBInfo->HiTVTextTiming; + TimingPoint = XGI330_HiTVTextTiming; } if (pVBInfo->VBInfo & SetCRT2ToYPbPr525750) { if (pVBInfo->TVInfo & TVSetYPbPr525i) - TimingPoint = pVBInfo->YPbPr525iTiming; + TimingPoint = XGI330_YPbPr525iTiming; if (pVBInfo->TVInfo & TVSetYPbPr525p) - TimingPoint = pVBInfo->YPbPr525pTiming; + TimingPoint = XGI330_YPbPr525pTiming; if (pVBInfo->TVInfo & TVSetYPbPr750p) - TimingPoint = pVBInfo->YPbPr750pTiming; + TimingPoint = XGI330_YPbPr750pTiming; } for (i = 0x01, j = 0; i <= 0x2D; i++, j++) @@ -4385,11 +4135,9 @@ static void XGI_SetGroup2(unsigned short ModeNo, unsigned short ModeIdIndex, temp += 1; } } - } else { - if (pVBInfo->VBInfo & SetInSlaveMode) { - if (ModeNo == 0x2f) - temp += 1; - } + } else if (pVBInfo->VBInfo & SetInSlaveMode) { + if (ModeNo == 0x2f) + temp += 1; } } @@ -4644,8 +4392,8 @@ static void XGI_SetLCDRegs(unsigned short ModeNo, unsigned short ModeIdIndex, /* Customized LCDB Des no add */ tempbx = 5; - LCDBDesPtr = (struct XGI_LCDDesStruct *) XGI_GetLcdPtr(tempbx, ModeNo, - ModeIdIndex, RefreshRateTableIndex, pVBInfo); + LCDBDesPtr = XGI_GetLcdPtr(tempbx, ModeNo, ModeIdIndex, + RefreshRateTableIndex, pVBInfo); tempah = pVBInfo->LCDResInfo; tempah &= PanelResInfo; @@ -4876,7 +4624,7 @@ static void XGI_SetGroup3(unsigned short ModeNo, unsigned short ModeIdIndex, struct vb_device_info *pVBInfo) { unsigned short i; - unsigned char *tempdi; + unsigned char const *tempdi; unsigned short modeflag; /* si+Ext_ResInfo */ @@ -4905,18 +4653,18 @@ static void XGI_SetGroup3(unsigned short ModeNo, unsigned short ModeIdIndex, if (pVBInfo->TVInfo & TVSetYPbPr525i) return; - tempdi = pVBInfo->HiTVGroup3Data; + tempdi = XGI330_HiTVGroup3Data; if (pVBInfo->SetFlag & TVSimuMode) { - tempdi = pVBInfo->HiTVGroup3Simu; + tempdi = XGI330_HiTVGroup3Simu; if (!(modeflag & Charx8Dot)) - tempdi = pVBInfo->HiTVGroup3Text; + tempdi = XGI330_HiTVGroup3Text; } if (pVBInfo->TVInfo & TVSetYPbPr525p) - tempdi = pVBInfo->Ren525pGroup3; + tempdi = XGI330_Ren525pGroup3; if (pVBInfo->TVInfo & TVSetYPbPr750p) - tempdi = pVBInfo->Ren750pGroup3; + tempdi = XGI330_Ren750pGroup3; for (i = 0; i <= 0x3E; i++) xgifb_reg_set(pVBInfo->Part3Port, i, tempdi[i]); @@ -5054,13 +4802,11 @@ static void XGI_SetGroup4(unsigned short ModeNo, unsigned short ModeIdIndex, if (pVBInfo->VBInfo & SetCRT2ToLCD) { if (tempax > 800) tempax -= 800; - } else { - if (pVBInfo->VGAHDE > 800) { - if (pVBInfo->VGAHDE == 1024) - tempax = (tempax * 25 / 32) - 1; - else - tempax = (tempax * 20 / 32) - 1; - } + } else if (pVBInfo->VGAHDE > 800) { + if (pVBInfo->VGAHDE == 1024) + tempax = (tempax * 25 / 32) - 1; + else + tempax = (tempax * 20 / 32) - 1; } tempax -= 1; @@ -5101,9 +4847,7 @@ static void XGI_SetGroup4(unsigned short ModeNo, unsigned short ModeIdIndex, } /* end 301b */ - if (pVBInfo->ISXPDOS == 0) - XGI_SetCRT2VCLK(ModeNo, ModeIdIndex, RefreshRateTableIndex, - pVBInfo); + XGI_SetCRT2VCLK(ModeNo, ModeIdIndex, RefreshRateTableIndex, pVBInfo); } static void XGINew_EnableCRT2(struct vb_device_info *pVBInfo) @@ -6414,12 +6158,10 @@ static void XGI_EnableBridge(struct xgifb_video_info *xgifb_info, if (pVBInfo->SetFlag & EnableChA) { /* Power on */ xgifb_reg_set(pVBInfo->Part1Port, 0x1E, 0x20); - } else { - if (pVBInfo->VBInfo & SetCRT2ToDualEdge) { - /* Power on */ - xgifb_reg_set(pVBInfo->Part1Port, - 0x1E, 0x20); - } + } else if (pVBInfo->VBInfo & SetCRT2ToDualEdge) { + /* Power on */ + xgifb_reg_set(pVBInfo->Part1Port, + 0x1E, 0x20); } } @@ -6607,7 +6349,6 @@ unsigned char XGISetModeNew(struct xgifb_video_info *xgifb_info, struct vb_device_info *pVBInfo = &VBINF; pVBInfo->BaseAddr = xgifb_info->vga_base; pVBInfo->IF_DEF_LVDS = 0; - pVBInfo->IF_DEF_LCDA = 1; if (HwDeviceExtension->jChipType >= XG20) { pVBInfo->IF_DEF_YPbPr = 0; @@ -6678,16 +6419,14 @@ unsigned char XGISetModeNew(struct xgifb_video_info *xgifb_info, XGI_SetLCDAGroup(ModeNo, ModeIdIndex, HwDeviceExtension, pVBInfo); } - } else { - if (!(pVBInfo->VBInfo & SwitchCRT2)) { - XGI_SetCRT1Group(xgifb_info, - HwDeviceExtension, ModeNo, - ModeIdIndex, pVBInfo); - if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) { - XGI_SetLCDAGroup(ModeNo, ModeIdIndex, - HwDeviceExtension, - pVBInfo); - } + } else if (!(pVBInfo->VBInfo & SwitchCRT2)) { + XGI_SetCRT1Group(xgifb_info, + HwDeviceExtension, ModeNo, + ModeIdIndex, pVBInfo); + if (pVBInfo->VBInfo & XGI_SetCRT2ToLCDA) { + XGI_SetLCDAGroup(ModeNo, ModeIdIndex, + HwDeviceExtension, + pVBInfo); } } diff --git a/drivers/staging/xgifb/vb_struct.h b/drivers/staging/xgifb/vb_struct.h index 22c8eb9810d6..70158c2c68af 100644 --- a/drivers/staging/xgifb/vb_struct.h +++ b/drivers/staging/xgifb/vb_struct.h @@ -43,13 +43,6 @@ struct XGI_LCDDesStruct { unsigned short LCDVRS; }; -struct XGI_LCDDataTablStruct { - unsigned char PANELID; - unsigned short MASK; - unsigned short CAP; - unsigned short DATAPTR; -}; - struct XGI330_LCDDataDesStruct2 { unsigned short LCDHDES; unsigned short LCDHRS; @@ -59,19 +52,6 @@ struct XGI330_LCDDataDesStruct2 { unsigned short LCDVSync; }; - -struct XGI330_TVDataStruct { - unsigned short RVBHCMAX; - unsigned short RVBHCFACT; - unsigned short VGAHT; - unsigned short VGAVT; - unsigned short TVHDE; - unsigned short TVVDE; - unsigned short RVBHRS; - unsigned char FlickerMode; - unsigned short HALFRVBHRS; -}; - struct XGI330_LCDDataTablStruct { unsigned char PANELID; unsigned short MASK; @@ -82,7 +62,7 @@ struct XGI330_LCDDataTablStruct { struct XGI330_TVDataTablStruct { unsigned short MASK; unsigned short CAP; - unsigned short DATAPTR; + struct SiS_TVData const *DATAPTR; }; @@ -137,10 +117,10 @@ struct XGI21_LVDSCapStruct { unsigned short LVDSVSYNC; unsigned char VCLKData1; unsigned char VCLKData2; - unsigned char PSC_S1; - unsigned char PSC_S2; - unsigned char PSC_S3; - unsigned char PSC_S4; + unsigned char PSC_S1; /* Duration between CPL on and signal on */ + unsigned char PSC_S2; /* Duration signal on and Vdd on */ + unsigned char PSC_S3; /* Duration between CPL off and signal off */ + unsigned char PSC_S4; /* Duration signal off and Vdd off */ unsigned char PSC_S5; }; @@ -155,7 +135,6 @@ struct XGI301C_Tap4TimingStruct { }; struct vb_device_info { - unsigned char ISXPDOS; unsigned long P3c4, P3d4, P3c0, P3ce, P3c2, P3cc; unsigned long P3ca, P3c6, P3c7, P3c8, P3c9, P3da; unsigned long Part0Port, Part1Port, Part2Port; @@ -168,12 +147,10 @@ struct vb_device_info { unsigned short ModeType; unsigned short IF_DEF_LVDS, IF_DEF_TRUMPION, IF_DEF_DSTN; unsigned short IF_DEF_CRT2Monitor; - unsigned short IF_DEF_LCDA, IF_DEF_YPbPr; - unsigned short IF_DEF_ExpLink; + unsigned short IF_DEF_YPbPr; unsigned short IF_DEF_HiVision; unsigned short LCDResInfo, LCDTypeInfo, VBType;/*301b*/ unsigned short VBInfo, TVInfo, LCDInfo; - unsigned short VBExtInfo;/*301lv*/ unsigned short SetFlag; unsigned short NewFlickerMode; unsigned short SelectCRT2Rate; @@ -197,20 +174,6 @@ struct vb_device_info { struct SiS_MCLKData *MCLKData; struct XGI_ECLKDataStruct *ECLKData; - unsigned char *NTSCTiming; - unsigned char *PALTiming; - unsigned char *HiTVExtTiming; - unsigned char *HiTVSt1Timing; - unsigned char *HiTVSt2Timing; - unsigned char *HiTVTextTiming; - unsigned char *YPbPr750pTiming; - unsigned char *YPbPr525pTiming; - unsigned char *YPbPr525iTiming; - unsigned char *HiTVGroup3Data; - unsigned char *HiTVGroup3Simu; - unsigned char *HiTVGroup3Text; - unsigned char *Ren525pGroup3; - unsigned char *Ren750pGroup3; unsigned char *ScreenOffset; unsigned char *pXGINew_DRAMTypeDefinition; unsigned char XGINew_CR97; diff --git a/drivers/staging/xgifb/vb_table.h b/drivers/staging/xgifb/vb_table.h index 1c168461411d..180aae042cea 100644 --- a/drivers/staging/xgifb/vb_table.h +++ b/drivers/staging/xgifb/vb_table.h @@ -403,13 +403,6 @@ static struct XGI_CRT1TableStruct XGI_CRT1Table[] = { 0x03, 0xDE, 0xC0, 0x84, 0xBF, 0x04, 0x90} } /* 0x47 */ }; -static unsigned char XGI_CH7017LV1024x768[] = { - 0x60, 0x02, 0x00, 0x07, 0x40, 0xED, - 0xA3, 0xC8, 0xC7, 0xAC, 0xE0, 0x02}; -static unsigned char XGI_CH7017LV1400x1050[] = { - 0x60, 0x03, 0x11, 0x00, 0x40, 0xE3, - 0xAD, 0xDB, 0xF6, 0xAC, 0xE0, 0x02}; - /*add for new UNIVGABIOS*/ static struct SiS_LCDData XGI_StLCD1024x768Data[] = { {62, 25, 800, 546, 1344, 806}, @@ -525,18 +518,7 @@ static struct SiS_LCDData XGI_StLCD1600x1200Data[] = { {1, 1, 2160, 1250, 2160, 1250} /* 09 (1600x1200) */ }; -static struct SiS_LCDData XGI_CetLCD1400x1050Data[] = { - {1, 1, 1688, 1066, 1688, 1066}, /* 00 (320x200,320x400, - 640x200,640x400) */ - {1, 1, 1688, 1066, 1688, 1066}, /* 01 (320x350,640x350) */ - {1, 1, 1688, 1066, 1688, 1066}, /* 02 (360x400,720x400) */ - {1, 1, 1688, 1066, 1688, 1066}, /* 03 (720x350) */ - {1, 1, 1688, 1066, 1688, 1066}, /* 04 (640x480x60Hz) */ - {1, 1, 1688, 1066, 1688, 1066}, /* 05 (800x600x60Hz) */ - {1, 1, 1688, 1066, 1688, 1066}, /* 06 (1024x768x60Hz) */ - {1, 1, 1688, 1066, 1688, 1066}, /* 07 (1280x1024x60Hz) */ - {1, 1, 1688, 1066, 1688, 1066} /* 08 (1400x1050x60Hz) */ -}; +#define XGI_CetLCD1400x1050Data XGI_CetLCD1280x1024Data static struct SiS_LCDData XGI_NoScalingData[] = { {1, 1, 800, 449, 800, 449}, @@ -583,17 +565,7 @@ static struct SiS_LCDData xgifb_lcd_1280x1024x75[] = { {1, 1, 1688, 1066, 1688, 1066} /* ; 07 (1280x1024x75Hz) */ }; -static struct SiS_LCDData XGI_CetLCD1280x1024x75Data[] = { - {1, 1, 1688, 1066, 1688, 1066}, /* ; 00 (320x200,320x400, - 640x200,640x400) */ - {1, 1, 1688, 1066, 1688, 1066}, /* ; 01 (320x350,640x350) */ - {1, 1, 1688, 1066, 1688, 1066}, /* ; 02 (360x400,720x400) */ - {1, 1, 1688, 1066, 1688, 1066}, /* ; 03 (720x350) */ - {1, 1, 1688, 1066, 1688, 1066}, /* ; 04 (640x480x75Hz) */ - {1, 1, 1688, 1066, 1688, 1066}, /* ; 05 (800x600x75Hz) */ - {1, 1, 1688, 1066, 1688, 1066}, /* ; 06 (1024x768x75Hz) */ - {1, 1, 1688, 1066, 1688, 1066} /* ; 07 (1280x1024x75Hz) */ -}; +#define XGI_CetLCD1280x1024x75Data XGI_CetLCD1280x1024Data static struct SiS_LCDData XGI_NoScalingDatax75[] = { {1, 1, 800, 449, 800, 449}, /* ; 00 (320x200, 320x400, @@ -903,7 +875,7 @@ static struct XGI330_LCDDataDesStruct2 XGI_NoScalingDesDatax75[] = { {9, 1337, 0, 771, 112, 6} /* ; 0A (1280x768x60Hz) */ }; -static struct XGI330_TVDataStruct XGI_StPALData[] = { +static const struct SiS_TVData XGI_StPALData[] = { {1, 1, 864, 525, 1270, 400, 100, 0, 760}, {1, 1, 864, 525, 1270, 350, 100, 0, 760}, {1, 1, 864, 525, 1270, 400, 0, 0, 720}, @@ -912,7 +884,7 @@ static struct XGI330_TVDataStruct XGI_StPALData[] = { {1, 1, 864, 525, 1270, 600, 50, 0, 0} }; -static struct XGI330_TVDataStruct XGI_ExtPALData[] = { +static const struct SiS_TVData XGI_ExtPALData[] = { {2, 1, 1080, 463, 1270, 500, 50, 0, 50}, {15, 7, 1152, 413, 1270, 500, 50, 0, 50}, {2, 1, 1080, 463, 1270, 500, 50, 0, 50}, @@ -923,7 +895,7 @@ static struct XGI330_TVDataStruct XGI_ExtPALData[] = { {3, 2, 1080, 619, 1270, 540, 438, 0, 438} }; -static struct XGI330_TVDataStruct XGI_StNTSCData[] = { +static const struct SiS_TVData XGI_StNTSCData[] = { {1, 1, 858, 525, 1270, 400, 50, 0, 760}, {1, 1, 858, 525, 1270, 350, 50, 0, 640}, {1, 1, 858, 525, 1270, 400, 0, 0, 720}, @@ -931,7 +903,7 @@ static struct XGI330_TVDataStruct XGI_StNTSCData[] = { {1, 1, 858, 525, 1270, 480, 0, 0, 760} }; -static struct XGI330_TVDataStruct XGI_ExtNTSCData[] = { +static const struct SiS_TVData XGI_ExtNTSCData[] = { {9, 5, 1001, 453, 1270, 420, 171, 0, 171}, {12, 5, 858, 403, 1270, 420, 171, 0, 171}, {9, 5, 1001, 453, 1270, 420, 171, 0, 171}, @@ -943,7 +915,7 @@ static struct XGI330_TVDataStruct XGI_ExtNTSCData[] = { {3, 2, 1001, 533, 1270, 420, 0, 0, 0} }; -static struct XGI330_TVDataStruct XGI_St1HiTVData[] = { +static const struct SiS_TVData XGI_St1HiTVData[] = { {1, 1, 892, 563, 690, 800, 0, 0, 0}, /* 00 (320x200,320x400, 640x200,640x400) */ {1, 1, 892, 563, 690, 700, 0, 0, 0}, /* 01 (320x350,640x350) */ @@ -953,7 +925,7 @@ static struct XGI330_TVDataStruct XGI_St1HiTVData[] = { {8, 5, 1050, 683, 1648, 960, 0x150, 1, 0} /* 05 (400x300,800x600) */ }; -static struct XGI330_TVDataStruct XGI_St2HiTVData[] = { +static const struct SiS_TVData XGI_St2HiTVData[] = { {3, 1, 840, 483, 1648, 960, 0x032, 0, 0}, /* 00 (320x200,320x400, 640x200,640x400) */ {1, 1, 892, 563, 690, 700, 0, 0, 0}, /* 01 (320x350,640x350) */ @@ -963,7 +935,7 @@ static struct XGI330_TVDataStruct XGI_St2HiTVData[] = { {8, 5, 1050, 683, 1648, 960, 0x17C, 1, 0} /* 05 (400x300,800x600) */ }; -static struct XGI330_TVDataStruct XGI_ExtHiTVData[] = { +static const struct SiS_TVData XGI_ExtHiTVData[] = { {6, 1, 840, 563, 1632, 960, 0, 0, 0}, /* 00 (320x200,320x400, 640x200,640x400) */ {3, 1, 960, 563, 1632, 960, 0, 0, 0}, /* 01 (320x350,640x350) */ @@ -978,7 +950,7 @@ static struct XGI330_TVDataStruct XGI_ExtHiTVData[] = { {8, 5, 1750, 803, 1648, 960, 0x128, 0, 0} /* 0A (1280x720) */ }; -static struct XGI330_TVDataStruct XGI_ExtYPbPr525iData[] = { +static const struct SiS_TVData XGI_ExtYPbPr525iData[] = { { 9, 5, 1001, 453, 1270, 420, 171, 0, 171}, { 12, 5, 858, 403, 1270, 420, 171, 0, 171}, { 9, 5, 1001, 453, 1270, 420, 171, 0, 171}, @@ -990,7 +962,7 @@ static struct XGI330_TVDataStruct XGI_ExtYPbPr525iData[] = { { 3, 2, 1001, 533, 1250, 420, 0, 0, 0} }; -static struct XGI330_TVDataStruct XGI_StYPbPr525iData[] = { +static const struct SiS_TVData XGI_StYPbPr525iData[] = { {1, 1, 858, 525, 1270, 400, 50, 0, 760}, {1, 1, 858, 525, 1270, 350, 50, 0, 640}, {1, 1, 858, 525, 1270, 400, 0, 0, 720}, @@ -998,7 +970,7 @@ static struct XGI330_TVDataStruct XGI_StYPbPr525iData[] = { {1, 1, 858, 525, 1270, 480, 0, 0, 760}, }; -static struct XGI330_TVDataStruct XGI_ExtYPbPr525pData[] = { +static const struct SiS_TVData XGI_ExtYPbPr525pData[] = { { 9, 5, 1001, 453, 1270, 420, 171, 0, 171}, { 12, 5, 858, 403, 1270, 420, 171, 0, 171}, { 9, 5, 1001, 453, 1270, 420, 171, 0, 171}, @@ -1010,7 +982,7 @@ static struct XGI330_TVDataStruct XGI_ExtYPbPr525pData[] = { { 3, 2, 1001, 533, 1270, 420, 0, 0, 0} }; -static struct XGI330_TVDataStruct XGI_StYPbPr525pData[] = { +static const struct SiS_TVData XGI_StYPbPr525pData[] = { {1, 1, 1716, 525, 1270, 400, 50, 0, 760}, {1, 1, 1716, 525, 1270, 350, 50, 0, 640}, {1, 1, 1716, 525, 1270, 400, 0, 0, 720}, @@ -1018,7 +990,7 @@ static struct XGI330_TVDataStruct XGI_StYPbPr525pData[] = { {1, 1, 1716, 525, 1270, 480, 0, 0, 760}, }; -static struct XGI330_TVDataStruct XGI_ExtYPbPr750pData[] = { +static const struct SiS_TVData XGI_ExtYPbPr750pData[] = { { 3, 1, 935, 470, 1130, 680, 50, 0, 0}, /* 00 (320x200,320x400, 640x200,640x400) */ {24, 7, 935, 420, 1130, 680, 50, 0, 0}, /* 01 (320x350,640x350) */ @@ -1033,7 +1005,7 @@ static struct XGI330_TVDataStruct XGI_ExtYPbPr750pData[] = { {10, 9, 1320, 830, 1130, 640, 50, 0, 0} }; -static struct XGI330_TVDataStruct XGI_StYPbPr750pData[] = { +static const struct SiS_TVData XGI_StYPbPr750pData[] = { {1, 1, 1650, 750, 1280, 400, 50, 0, 760}, {1, 1, 1650, 750, 1280, 350, 50, 0, 640}, {1, 1, 1650, 750, 1280, 400, 0, 0, 720}, @@ -1041,7 +1013,7 @@ static struct XGI330_TVDataStruct XGI_StYPbPr750pData[] = { {1, 1, 1650, 750, 1280, 480, 0, 0, 760}, }; -static unsigned char XGI330_NTSCTiming[] = { +static const unsigned char XGI330_NTSCTiming[] = { 0x17, 0x1d, 0x03, 0x09, 0x05, 0x06, 0x0c, 0x0c, 0x94, 0x49, 0x01, 0x0a, 0x06, 0x0d, 0x04, 0x0a, 0x06, 0x14, 0x0d, 0x04, 0x0a, 0x00, 0x85, 0x1b, @@ -1052,7 +1024,7 @@ static unsigned char XGI330_NTSCTiming[] = { 0x00, 0x40, 0x44, 0x00, 0xdb, 0x02, 0x3b, 0x00 }; -static unsigned char XGI330_PALTiming[] = { +static const unsigned char XGI330_PALTiming[] = { 0x21, 0x5A, 0x35, 0x6e, 0x04, 0x38, 0x3d, 0x70, 0x94, 0x49, 0x01, 0x12, 0x06, 0x3e, 0x35, 0x6d, 0x06, 0x14, 0x3e, 0x35, 0x6d, 0x00, 0x45, 0x2b, @@ -1063,7 +1035,7 @@ static unsigned char XGI330_PALTiming[] = { 0x00, 0x40, 0x3e, 0x00, 0xe1, 0x02, 0x28, 0x00 }; -static unsigned char XGI330_HiTVExtTiming[] = { +static const unsigned char XGI330_HiTVExtTiming[] = { 0x2D, 0x60, 0x2C, 0x5F, 0x08, 0x31, 0x3A, 0x64, 0x28, 0x02, 0x01, 0x3D, 0x06, 0x3E, 0x35, 0x6D, 0x06, 0x14, 0x3E, 0x35, 0x6D, 0x00, 0xC5, 0x3F, @@ -1075,7 +1047,7 @@ static unsigned char XGI330_HiTVExtTiming[] = { 0x27, 0x00, 0xfc, 0xff, 0x6a, 0x00 }; -static unsigned char XGI330_HiTVSt1Timing[] = { +static const unsigned char XGI330_HiTVSt1Timing[] = { 0x32, 0x65, 0x2C, 0x5F, 0x08, 0x31, 0x3A, 0x65, 0x28, 0x02, 0x01, 0x3D, 0x06, 0x3E, 0x35, 0x6D, 0x06, 0x14, 0x3E, 0x35, 0x6D, 0x00, 0xC5, 0x3F, @@ -1087,7 +1059,7 @@ static unsigned char XGI330_HiTVSt1Timing[] = { 0x0E, 0x00, 0xfc, 0xff, 0x2d, 0x00 }; -static unsigned char XGI330_HiTVSt2Timing[] = { +static const unsigned char XGI330_HiTVSt2Timing[] = { 0x32, 0x65, 0x2C, 0x5F, 0x08, 0x31, 0x3A, 0x64, 0x28, 0x02, 0x01, 0x3D, 0x06, 0x3E, 0x35, 0x6D, 0x06, 0x14, 0x3E, 0x35, 0x6D, 0x00, 0xC5, 0x3F, @@ -1099,7 +1071,7 @@ static unsigned char XGI330_HiTVSt2Timing[] = { 0x27, 0x00, 0xFC, 0xff, 0x6a, 0x00 }; -static unsigned char XGI330_HiTVTextTiming[] = { +static const unsigned char XGI330_HiTVTextTiming[] = { 0x32, 0x65, 0x2C, 0x5F, 0x08, 0x31, 0x3A, 0x65, 0x28, 0x02, 0x01, 0x3D, 0x06, 0x3E, 0x35, 0x6D, 0x06, 0x14, 0x3E, 0x35, 0x6D, 0x00, 0xC5, 0x3F, @@ -1111,7 +1083,7 @@ static unsigned char XGI330_HiTVTextTiming[] = { 0x11, 0x00, 0xFC, 0xFF, 0x32, 0x00 }; -static unsigned char XGI330_YPbPr750pTiming[] = { +static const unsigned char XGI330_YPbPr750pTiming[] = { 0x30, 0x1d, 0xe8, 0x09, 0x09, 0xed, 0x0c, 0x0c, 0x98, 0x0a, 0x01, 0x0c, 0x06, 0x0d, 0x04, 0x0a, 0x06, 0x14, 0x0d, 0x04, 0x0a, 0x00, 0x85, 0x3f, @@ -1123,7 +1095,7 @@ static unsigned char XGI330_YPbPr750pTiming[] = { 0x11, 0x00, 0xfc, 0xff, 0x32, 0x00 }; -static unsigned char XGI330_YPbPr525pTiming[] = { +static const unsigned char XGI330_YPbPr525pTiming[] = { 0x3E, 0x11, 0x06, 0x09, 0x0b, 0x0c, 0x0c, 0x0c, 0x98, 0x0a, 0x01, 0x0d, 0x06, 0x0d, 0x04, 0x0a, 0x06, 0x14, 0x0d, 0x04, 0x0a, 0x00, 0x85, 0x3f, @@ -1135,7 +1107,7 @@ static unsigned char XGI330_YPbPr525pTiming[] = { 0x11, 0x00, 0xFC, 0xFF, 0x32, 0x00 }; -static unsigned char XGI330_YPbPr525iTiming[] = { +static const unsigned char XGI330_YPbPr525iTiming[] = { 0x1B, 0x21, 0x03, 0x09, 0x05, 0x06, 0x0C, 0x0C, 0x94, 0x49, 0x01, 0x0A, 0x06, 0x0D, 0x04, 0x0A, 0x06, 0x14, 0x0D, 0x04, 0x0A, 0x00, 0x85, 0x1B, @@ -1147,7 +1119,7 @@ static unsigned char XGI330_YPbPr525iTiming[] = { 0x44, 0x00, 0xDB, 0x02, 0x3B, 0x00 }; -static unsigned char XGI330_HiTVGroup3Data[] = { +static const unsigned char XGI330_HiTVGroup3Data[] = { 0x00, 0x1A, 0x22, 0x63, 0x62, 0x22, 0x08, 0x5F, 0x05, 0x21, 0xB2, 0xB2, 0x55, 0x77, 0x2A, 0xA6, 0x25, 0x2F, 0x47, 0xFA, 0xC8, 0xFF, 0x8E, 0x20, @@ -1158,7 +1130,7 @@ static unsigned char XGI330_HiTVGroup3Data[] = { 0x18, 0x05, 0x18, 0x05, 0x4C, 0xA8, 0x01 }; -static unsigned char XGI330_HiTVGroup3Simu[] = { +static const unsigned char XGI330_HiTVGroup3Simu[] = { 0x00, 0x1A, 0x22, 0x63, 0x62, 0x22, 0x08, 0x95, 0xDB, 0x20, 0xB8, 0xB8, 0x55, 0x47, 0x2A, 0xA6, 0x25, 0x2F, 0x47, 0xFA, 0xC8, 0xFF, 0x8E, 0x20, @@ -1169,7 +1141,7 @@ static unsigned char XGI330_HiTVGroup3Simu[] = { 0x18, 0x05, 0x18, 0x05, 0x4C, 0xA8, 0x01 }; -static unsigned char XGI330_HiTVGroup3Text[] = { +static const unsigned char XGI330_HiTVGroup3Text[] = { 0x00, 0x1A, 0x22, 0x63, 0x62, 0x22, 0x08, 0xA7, 0xF5, 0x20, 0xCE, 0xCE, 0x55, 0x47, 0x2A, 0xA6, 0x25, 0x2F, 0x47, 0xFA, 0xC8, 0xFF, 0x8E, 0x20, @@ -1180,7 +1152,7 @@ static unsigned char XGI330_HiTVGroup3Text[] = { 0x18, 0x05, 0x18, 0x05, 0x4C, 0xA8, 0x01 }; -static unsigned char XGI330_Ren525pGroup3[] = { +static const unsigned char XGI330_Ren525pGroup3[] = { 0x00, 0x14, 0x15, 0x25, 0x55, 0x15, 0x0b, 0x13, 0xB1, 0x41, 0x62, 0x62, 0xFF, 0xF4, 0x45, 0xa6, 0x25, 0x2F, 0x67, 0xF6, 0xbf, 0xFF, 0x8E, 0x20, @@ -1191,7 +1163,7 @@ static unsigned char XGI330_Ren525pGroup3[] = { 0x1a, 0x1F, 0x25, 0x2a, 0x4C, 0xAA, 0x01 }; -static unsigned char XGI330_Ren750pGroup3[] = { +static const unsigned char XGI330_Ren750pGroup3[] = { 0x00, 0x14, 0x15, 0x25, 0x55, 0x15, 0x0b, 0x7a, 0x54, 0x41, 0xE7, 0xE7, 0xFF, 0xF4, 0x45, 0xa6, 0x25, 0x2F, 0x67, 0xF6, 0xbf, 0xFF, 0x8E, 0x20, @@ -1236,17 +1208,7 @@ static struct SiS_LVDSData XGI_LVDS1280x1024Data_1[] = { {1688, 1066, 1688, 1066} }; -static struct SiS_LVDSData XGI_LVDS1280x1024Data_2[] = { - {1344, 806, 1344, 806}, - {1344, 806, 1344, 806}, - {1344, 806, 1344, 806}, - {1344, 806, 1344, 806}, - {1344, 806, 1344, 806}, - {1344, 806, 1344, 806}, - {1344, 806, 1344, 806}, - {800, 449, 1280, 801}, - {800, 525, 1280, 813} -}; +#define XGI_LVDS1280x1024Data_2 XGI_LVDS1024x768Data_2 static struct SiS_LVDSData XGI_LVDS1400x1050Data_1[] = { {928, 416, 1688, 1066}, @@ -1532,42 +1494,6 @@ static struct XGI330_LCDDataDesStruct2 XGI_LVDSNoScalingDesDatax75[] = { {0, 1328, 0, 771, 112, 6} /* ; 0A (1280x768x75Hz) */ }; -static struct SiS_LVDSData XGI_CHTVUNTSCData[] = { - { 840, 600, 840, 600}, - { 840, 600, 840, 600}, - { 840, 600, 840, 600}, - { 840, 600, 840, 600}, - { 784, 600, 784, 600}, - {1064, 750, 1064, 750} -}; - -static struct SiS_LVDSData XGI_CHTVONTSCData[] = { - { 840, 525, 840, 525}, - { 840, 525, 840, 525}, - { 840, 525, 840, 525}, - { 840, 525, 840, 525}, - { 784, 525, 784, 525}, - {1040, 700, 1040, 700} -}; - -static struct SiS_LVDSData XGI_CHTVUPALData[] = { - {1008, 625, 1008, 625}, - {1008, 625, 1008, 625}, - {1008, 625, 1008, 625}, - {1008, 625, 1008, 625}, - { 840, 750, 840, 750}, - { 936, 836, 936, 836} -}; - -static struct SiS_LVDSData XGI_CHTVOPALData[] = { - {1008, 625, 1008, 625}, - {1008, 625, 1008, 625}, - {1008, 625, 1008, 625}, - {1008, 625, 1008, 625}, - {840, 625, 840, 625}, - {960, 750, 960, 750} -}; - /* CR00,CR02,CR03,CR04,CR05,SR0B,SR0C,SR0E */ static struct XGI_LVDSCRT1HDataStruct XGI_LVDSCRT11024x768_1_H[] = { { {0x4B, 0x27, 0x8F, 0x32, 0x1B, 0x00, 0x45, 0x00} }, /* 00 (320x) */ @@ -1933,49 +1859,21 @@ static struct XGI330_LCDDataTablStruct XGI_EPLLCDDesDataPtr[] = { {0xFF, 0x0000, 0x0000, 0} }; -static struct XGI330_LCDDataTablStruct XGI_EPLCHLCDRegPtr[] = { - {Panel_1024x768, 0x0000, 0x0000, 0}, /* XGI_CH7017LV1024x768 */ - {Panel_1400x1050, 0x0000, 0x0000, 1}, /* XGI_CH7017LV1400x1050 */ - {0xFF, 0x0000, 0x0000, 0} -}; - -static struct XGI330_TVDataTablStruct XGI_TVDataTable[] = { - {0x09E1, 0x0001, 0}, /* XGI_ExtPALData */ - {0x09E1, 0x0000, 1}, /* XGI_ExtNTSCData */ - {0x09E1, 0x0801, 2}, /* XGI_StPALData */ - {0x09E1, 0x0800, 3}, /* XGI_StNTSCData */ - {0x49E0, 0x0100, 4}, /* XGI_ExtHiTVData */ - {0x49E0, 0x4100, 5}, /* XGI_St2HiTVData */ - {0x49E0, 0x4900, 13}, /* XGI_St1HiTVData */ - {0x09E0, 0x0020, 6}, /* XGI_ExtYPbPr525iData */ - {0x09E0, 0x0040, 7}, /* XGI_ExtYPbPr525pData */ - {0x09E0, 0x0080, 8}, /* XGI_ExtYPbPr750pData */ - {0x09E0, 0x0820, 9}, /* XGI_StYPbPr525iData */ - {0x09E0, 0x0840, 10}, /* XGI_StYPbPr525pData */ - {0x09E0, 0x0880, 11}, /* XGI_StYPbPr750pData */ - {0xffff, 0x0000, 12} /* END */ -}; - -/* Chrontel 7017 TV List */ -static struct XGI330_TVDataTablStruct xgifb_chrontel_tv[] = { - {0x0011, 0x0000, 0}, /* UNTSC */ - {0x0011, 0x0010, 1}, /* ONTSC */ - {0x0011, 0x0001, 2}, /* UPAL */ - {0x0011, 0x0011, 3}, /* OPAL */ - {0xFFFF, 0x0000, 4} -}; - -static unsigned short LCDLenList[] = { - LVDSCRT1Len_H, - LVDSCRT1Len_V, - LVDSDataLen, - LCDDesDataLen, - LCDDataLen, - LCDDesDataLen, - 0, - LCDDesDataLen, - LCDDesDataLen, - 0 +static const struct XGI330_TVDataTablStruct XGI_TVDataTable[] = { + {0x09E1, 0x0001, XGI_ExtPALData}, + {0x09E1, 0x0000, XGI_ExtNTSCData}, + {0x09E1, 0x0801, XGI_StPALData}, + {0x09E1, 0x0800, XGI_StNTSCData}, + {0x49E0, 0x0100, XGI_ExtHiTVData}, + {0x49E0, 0x4100, XGI_St2HiTVData}, + {0x49E0, 0x4900, XGI_St1HiTVData}, + {0x09E0, 0x0020, XGI_ExtYPbPr525iData}, + {0x09E0, 0x0040, XGI_ExtYPbPr525pData}, + {0x09E0, 0x0080, XGI_ExtYPbPr750pData}, + {0x09E0, 0x0820, XGI_StYPbPr525iData}, + {0x09E0, 0x0840, XGI_StYPbPr525pData}, + {0x09E0, 0x0880, XGI_StYPbPr750pData}, + {0xffff, 0x0000, XGI_ExtNTSCData}, }; /* Dual link only */ @@ -2336,7 +2234,7 @@ static struct SiS_VCLKData XGI_VCLKData[] = { {0xFF, 0x00, 0} /* End mark */ }; -static struct SiS_VCLKData XGI_VBVCLKData[] = { +static struct SiS_VBVCLKData XGI_VBVCLKData[] = { {0x1B, 0xE1, 25}, /* 00 (25.175MHz) */ {0x4E, 0xE4, 28}, /* 01 (28.322MHz) */ {0x57, 0xE4, 31}, /* 02 (31.500MHz) */ diff --git a/drivers/staging/zcache/tmem.c b/drivers/staging/zcache/tmem.c index eaa90213457b..56c8e606ad1c 100644 --- a/drivers/staging/zcache/tmem.c +++ b/drivers/staging/zcache/tmem.c @@ -3,7 +3,7 @@ * * Copyright (c) 2009-2011, Dan Magenheimer, Oracle Corp. * - * The primary purpose of Transcedent Memory ("tmem") is to map object-oriented + * The primary purpose of Transcendent Memory ("tmem") is to map object-oriented * "handles" (triples containing a pool id, and object id, and an index), to * pages in a page-accessible memory (PAM). Tmem references the PAM pages via * an abstract "pampd" (PAM page-descriptor), which can be operated on by a diff --git a/drivers/staging/zsmalloc/zsmalloc-main.c b/drivers/staging/zsmalloc/zsmalloc-main.c index 8b0bcb626a7f..09a9d35d436f 100644 --- a/drivers/staging/zsmalloc/zsmalloc-main.c +++ b/drivers/staging/zsmalloc/zsmalloc-main.c @@ -75,9 +75,140 @@ #include <linux/cpumask.h> #include <linux/cpu.h> #include <linux/vmalloc.h> +#include <linux/hardirq.h> +#include <linux/spinlock.h> +#include <linux/types.h> #include "zsmalloc.h" -#include "zsmalloc_int.h" + +/* + * This must be power of 2 and greater than of equal to sizeof(link_free). + * These two conditions ensure that any 'struct link_free' itself doesn't + * span more than 1 page which avoids complex case of mapping 2 pages simply + * to restore link_free pointer values. + */ +#define ZS_ALIGN 8 + +/* + * A single 'zspage' is composed of up to 2^N discontiguous 0-order (single) + * pages. ZS_MAX_ZSPAGE_ORDER defines upper limit on N. + */ +#define ZS_MAX_ZSPAGE_ORDER 2 +#define ZS_MAX_PAGES_PER_ZSPAGE (_AC(1, UL) << ZS_MAX_ZSPAGE_ORDER) + +/* + * Object location (<PFN>, <obj_idx>) is encoded as + * as single (void *) handle value. + * + * Note that object index <obj_idx> is relative to system + * page <PFN> it is stored in, so for each sub-page belonging + * to a zspage, obj_idx starts with 0. + * + * This is made more complicated by various memory models and PAE. + */ + +#ifndef MAX_PHYSMEM_BITS +#ifdef CONFIG_HIGHMEM64G +#define MAX_PHYSMEM_BITS 36 +#else /* !CONFIG_HIGHMEM64G */ +/* + * If this definition of MAX_PHYSMEM_BITS is used, OBJ_INDEX_BITS will just + * be PAGE_SHIFT + */ +#define MAX_PHYSMEM_BITS BITS_PER_LONG +#endif +#endif +#define _PFN_BITS (MAX_PHYSMEM_BITS - PAGE_SHIFT) +#define OBJ_INDEX_BITS (BITS_PER_LONG - _PFN_BITS) +#define OBJ_INDEX_MASK ((_AC(1, UL) << OBJ_INDEX_BITS) - 1) + +#define MAX(a, b) ((a) >= (b) ? (a) : (b)) +/* ZS_MIN_ALLOC_SIZE must be multiple of ZS_ALIGN */ +#define ZS_MIN_ALLOC_SIZE \ + MAX(32, (ZS_MAX_PAGES_PER_ZSPAGE << PAGE_SHIFT >> OBJ_INDEX_BITS)) +#define ZS_MAX_ALLOC_SIZE PAGE_SIZE + +/* + * On systems with 4K page size, this gives 254 size classes! There is a + * trader-off here: + * - Large number of size classes is potentially wasteful as free page are + * spread across these classes + * - Small number of size classes causes large internal fragmentation + * - Probably its better to use specific size classes (empirically + * determined). NOTE: all those class sizes must be set as multiple of + * ZS_ALIGN to make sure link_free itself never has to span 2 pages. + * + * ZS_MIN_ALLOC_SIZE and ZS_SIZE_CLASS_DELTA must be multiple of ZS_ALIGN + * (reason above) + */ +#define ZS_SIZE_CLASS_DELTA 16 +#define ZS_SIZE_CLASSES ((ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) / \ + ZS_SIZE_CLASS_DELTA + 1) + +/* + * We do not maintain any list for completely empty or full pages + */ +enum fullness_group { + ZS_ALMOST_FULL, + ZS_ALMOST_EMPTY, + _ZS_NR_FULLNESS_GROUPS, + + ZS_EMPTY, + ZS_FULL +}; + +/* + * We assign a page to ZS_ALMOST_EMPTY fullness group when: + * n <= N / f, where + * n = number of allocated objects + * N = total number of objects zspage can store + * f = 1/fullness_threshold_frac + * + * Similarly, we assign zspage to: + * ZS_ALMOST_FULL when n > N / f + * ZS_EMPTY when n == 0 + * ZS_FULL when n == N + * + * (see: fix_fullness_group()) + */ +static const int fullness_threshold_frac = 4; + +struct size_class { + /* + * Size of objects stored in this class. Must be multiple + * of ZS_ALIGN. + */ + int size; + unsigned int index; + + /* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */ + int pages_per_zspage; + + spinlock_t lock; + + /* stats */ + u64 pages_allocated; + + struct page *fullness_list[_ZS_NR_FULLNESS_GROUPS]; +}; + +/* + * Placed within free objects to form a singly linked list. + * For every zspage, first_page->freelist gives head of this list. + * + * This must be power of 2 and less than or equal to ZS_ALIGN + */ +struct link_free { + /* Handle of next free chunk (encodes <PFN, obj_idx>) */ + void *next; +}; + +struct zs_pool { + struct size_class size_class[ZS_SIZE_CLASSES]; + + gfp_t flags; /* allocation flags used when growing pool */ + const char *name; +}; /* * A zspage's class index and fullness group @@ -88,6 +219,30 @@ #define CLASS_IDX_MASK ((1 << CLASS_IDX_BITS) - 1) #define FULLNESS_MASK ((1 << FULLNESS_BITS) - 1) +/* + * By default, zsmalloc uses a copy-based object mapping method to access + * allocations that span two pages. However, if a particular architecture + * 1) Implements local_flush_tlb_kernel_range() and 2) Performs VM mapping + * faster than copying, then it should be added here so that + * USE_PGTABLE_MAPPING is defined. This causes zsmalloc to use page table + * mapping rather than copying + * for object mapping. +*/ +#if defined(CONFIG_ARM) +#define USE_PGTABLE_MAPPING +#endif + +struct mapping_area { +#ifdef USE_PGTABLE_MAPPING + struct vm_struct *vm; /* vm area for mapping object that span pages */ +#else + char *vm_buf; /* copy buffer for objects that span pages */ +#endif + char *vm_addr; /* address of kmap_atomic()'ed pages */ + enum zs_mapmode vm_mm; /* mapping mode */ +}; + + /* per-cpu VM mapping areas for zspage accesses that cross page boundaries */ static DEFINE_PER_CPU(struct mapping_area, zs_map_area); @@ -470,16 +625,83 @@ static struct page *find_get_zspage(struct size_class *class) return page; } -static void zs_copy_map_object(char *buf, struct page *firstpage, - int off, int size) +#ifdef USE_PGTABLE_MAPPING +static inline int __zs_cpu_up(struct mapping_area *area) +{ + /* + * Make sure we don't leak memory if a cpu UP notification + * and zs_init() race and both call zs_cpu_up() on the same cpu + */ + if (area->vm) + return 0; + area->vm = alloc_vm_area(PAGE_SIZE * 2, NULL); + if (!area->vm) + return -ENOMEM; + return 0; +} + +static inline void __zs_cpu_down(struct mapping_area *area) +{ + if (area->vm) + free_vm_area(area->vm); + area->vm = NULL; +} + +static inline void *__zs_map_object(struct mapping_area *area, + struct page *pages[2], int off, int size) +{ + BUG_ON(map_vm_area(area->vm, PAGE_KERNEL, &pages)); + area->vm_addr = area->vm->addr; + return area->vm_addr + off; +} + +static inline void __zs_unmap_object(struct mapping_area *area, + struct page *pages[2], int off, int size) +{ + unsigned long addr = (unsigned long)area->vm_addr; + unsigned long end = addr + (PAGE_SIZE * 2); + + flush_cache_vunmap(addr, end); + unmap_kernel_range_noflush(addr, PAGE_SIZE * 2); + local_flush_tlb_kernel_range(addr, end); +} + +#else /* USE_PGTABLE_MAPPING */ + +static inline int __zs_cpu_up(struct mapping_area *area) +{ + /* + * Make sure we don't leak memory if a cpu UP notification + * and zs_init() race and both call zs_cpu_up() on the same cpu + */ + if (area->vm_buf) + return 0; + area->vm_buf = (char *)__get_free_page(GFP_KERNEL); + if (!area->vm_buf) + return -ENOMEM; + return 0; +} + +static inline void __zs_cpu_down(struct mapping_area *area) +{ + if (area->vm_buf) + free_page((unsigned long)area->vm_buf); + area->vm_buf = NULL; +} + +static void *__zs_map_object(struct mapping_area *area, + struct page *pages[2], int off, int size) { - struct page *pages[2]; int sizes[2]; void *addr; + char *buf = area->vm_buf; - pages[0] = firstpage; - pages[1] = get_next_page(firstpage); - BUG_ON(!pages[1]); + /* disable page faults to match kmap_atomic() return conditions */ + pagefault_disable(); + + /* no read fastpath */ + if (area->vm_mm == ZS_MM_WO) + goto out; sizes[0] = PAGE_SIZE - off; sizes[1] = size - sizes[0]; @@ -491,18 +713,20 @@ static void zs_copy_map_object(char *buf, struct page *firstpage, addr = kmap_atomic(pages[1]); memcpy(buf + sizes[0], addr, sizes[1]); kunmap_atomic(addr); +out: + return area->vm_buf; } -static void zs_copy_unmap_object(char *buf, struct page *firstpage, - int off, int size) +static void __zs_unmap_object(struct mapping_area *area, + struct page *pages[2], int off, int size) { - struct page *pages[2]; int sizes[2]; void *addr; + char *buf = area->vm_buf; - pages[0] = firstpage; - pages[1] = get_next_page(firstpage); - BUG_ON(!pages[1]); + /* no write fastpath */ + if (area->vm_mm == ZS_MM_RO) + goto out; sizes[0] = PAGE_SIZE - off; sizes[1] = size - sizes[0]; @@ -514,34 +738,31 @@ static void zs_copy_unmap_object(char *buf, struct page *firstpage, addr = kmap_atomic(pages[1]); memcpy(addr, buf + sizes[0], sizes[1]); kunmap_atomic(addr); + +out: + /* enable page faults to match kunmap_atomic() return conditions */ + pagefault_enable(); } +#endif /* USE_PGTABLE_MAPPING */ + static int zs_cpu_notifier(struct notifier_block *nb, unsigned long action, void *pcpu) { - int cpu = (long)pcpu; + int ret, cpu = (long)pcpu; struct mapping_area *area; switch (action) { case CPU_UP_PREPARE: area = &per_cpu(zs_map_area, cpu); - /* - * Make sure we don't leak memory if a cpu UP notification - * and zs_init() race and both call zs_cpu_up() on the same cpu - */ - if (area->vm_buf) - return 0; - area->vm_buf = (char *)__get_free_page(GFP_KERNEL); - if (!area->vm_buf) - return -ENOMEM; - return 0; + ret = __zs_cpu_up(area); + if (ret) + return notifier_from_errno(ret); break; case CPU_DEAD: case CPU_UP_CANCELED: area = &per_cpu(zs_map_area, cpu); - if (area->vm_buf) - free_page((unsigned long)area->vm_buf); - area->vm_buf = NULL; + __zs_cpu_down(area); break; } @@ -758,28 +979,36 @@ void *zs_map_object(struct zs_pool *pool, unsigned long handle, enum fullness_group fg; struct size_class *class; struct mapping_area *area; + struct page *pages[2]; BUG_ON(!handle); + /* + * Because we use per-cpu mapping areas shared among the + * pools/users, we can't allow mapping in interrupt context + * because it can corrupt another users mappings. + */ + BUG_ON(in_interrupt()); + obj_handle_to_location(handle, &page, &obj_idx); get_zspage_mapping(get_first_page(page), &class_idx, &fg); class = &pool->size_class[class_idx]; off = obj_idx_to_offset(page, obj_idx, class->size); area = &get_cpu_var(zs_map_area); + area->vm_mm = mm; if (off + class->size <= PAGE_SIZE) { /* this object is contained entirely within a page */ area->vm_addr = kmap_atomic(page); return area->vm_addr + off; } - /* disable page faults to match kmap_atomic() return conditions */ - pagefault_disable(); + /* this object spans two pages */ + pages[0] = page; + pages[1] = get_next_page(page); + BUG_ON(!pages[1]); - if (mm != ZS_MM_WO) - zs_copy_map_object(area->vm_buf, page, off, class->size); - area->vm_addr = NULL; - return area->vm_buf; + return __zs_map_object(area, pages, off, class->size); } EXPORT_SYMBOL_GPL(zs_map_object); @@ -793,17 +1022,6 @@ void zs_unmap_object(struct zs_pool *pool, unsigned long handle) struct size_class *class; struct mapping_area *area; - area = &__get_cpu_var(zs_map_area); - /* single-page object fastpath */ - if (area->vm_addr) { - kunmap_atomic(area->vm_addr); - goto out; - } - - /* no write fastpath */ - if (area->vm_mm == ZS_MM_RO) - goto pfenable; - BUG_ON(!handle); obj_handle_to_location(handle, &page, &obj_idx); @@ -811,12 +1029,18 @@ void zs_unmap_object(struct zs_pool *pool, unsigned long handle) class = &pool->size_class[class_idx]; off = obj_idx_to_offset(page, obj_idx, class->size); - zs_copy_unmap_object(area->vm_buf, page, off, class->size); + area = &__get_cpu_var(zs_map_area); + if (off + class->size <= PAGE_SIZE) + kunmap_atomic(area->vm_addr); + else { + struct page *pages[2]; -pfenable: - /* enable page faults to match kunmap_atomic() return conditions */ - pagefault_enable(); -out: + pages[0] = page; + pages[1] = get_next_page(page); + BUG_ON(!pages[1]); + + __zs_unmap_object(area, pages, off, class->size); + } put_cpu_var(zs_map_area); } EXPORT_SYMBOL_GPL(zs_unmap_object); diff --git a/drivers/staging/zsmalloc/zsmalloc_int.h b/drivers/staging/zsmalloc/zsmalloc_int.h deleted file mode 100644 index 528051767733..000000000000 --- a/drivers/staging/zsmalloc/zsmalloc_int.h +++ /dev/null @@ -1,155 +0,0 @@ -/* - * zsmalloc memory allocator - * - * Copyright (C) 2011 Nitin Gupta - * - * This code is released using a dual license strategy: BSD/GPL - * You can choose the license that better fits your requirements. - * - * Released under the terms of 3-clause BSD License - * Released under the terms of GNU General Public License Version 2.0 - */ - -#ifndef _ZS_MALLOC_INT_H_ -#define _ZS_MALLOC_INT_H_ - -#include <linux/kernel.h> -#include <linux/spinlock.h> -#include <linux/types.h> - -/* - * This must be power of 2 and greater than of equal to sizeof(link_free). - * These two conditions ensure that any 'struct link_free' itself doesn't - * span more than 1 page which avoids complex case of mapping 2 pages simply - * to restore link_free pointer values. - */ -#define ZS_ALIGN 8 - -/* - * A single 'zspage' is composed of up to 2^N discontiguous 0-order (single) - * pages. ZS_MAX_ZSPAGE_ORDER defines upper limit on N. - */ -#define ZS_MAX_ZSPAGE_ORDER 2 -#define ZS_MAX_PAGES_PER_ZSPAGE (_AC(1, UL) << ZS_MAX_ZSPAGE_ORDER) - -/* - * Object location (<PFN>, <obj_idx>) is encoded as - * as single (void *) handle value. - * - * Note that object index <obj_idx> is relative to system - * page <PFN> it is stored in, so for each sub-page belonging - * to a zspage, obj_idx starts with 0. - * - * This is made more complicated by various memory models and PAE. - */ - -#ifndef MAX_PHYSMEM_BITS -#ifdef CONFIG_HIGHMEM64G -#define MAX_PHYSMEM_BITS 36 -#else /* !CONFIG_HIGHMEM64G */ -/* - * If this definition of MAX_PHYSMEM_BITS is used, OBJ_INDEX_BITS will just - * be PAGE_SHIFT - */ -#define MAX_PHYSMEM_BITS BITS_PER_LONG -#endif -#endif -#define _PFN_BITS (MAX_PHYSMEM_BITS - PAGE_SHIFT) -#define OBJ_INDEX_BITS (BITS_PER_LONG - _PFN_BITS) -#define OBJ_INDEX_MASK ((_AC(1, UL) << OBJ_INDEX_BITS) - 1) - -#define MAX(a, b) ((a) >= (b) ? (a) : (b)) -/* ZS_MIN_ALLOC_SIZE must be multiple of ZS_ALIGN */ -#define ZS_MIN_ALLOC_SIZE \ - MAX(32, (ZS_MAX_PAGES_PER_ZSPAGE << PAGE_SHIFT >> OBJ_INDEX_BITS)) -#define ZS_MAX_ALLOC_SIZE PAGE_SIZE - -/* - * On systems with 4K page size, this gives 254 size classes! There is a - * trader-off here: - * - Large number of size classes is potentially wasteful as free page are - * spread across these classes - * - Small number of size classes causes large internal fragmentation - * - Probably its better to use specific size classes (empirically - * determined). NOTE: all those class sizes must be set as multiple of - * ZS_ALIGN to make sure link_free itself never has to span 2 pages. - * - * ZS_MIN_ALLOC_SIZE and ZS_SIZE_CLASS_DELTA must be multiple of ZS_ALIGN - * (reason above) - */ -#define ZS_SIZE_CLASS_DELTA 16 -#define ZS_SIZE_CLASSES ((ZS_MAX_ALLOC_SIZE - ZS_MIN_ALLOC_SIZE) / \ - ZS_SIZE_CLASS_DELTA + 1) - -/* - * We do not maintain any list for completely empty or full pages - */ -enum fullness_group { - ZS_ALMOST_FULL, - ZS_ALMOST_EMPTY, - _ZS_NR_FULLNESS_GROUPS, - - ZS_EMPTY, - ZS_FULL -}; - -/* - * We assign a page to ZS_ALMOST_EMPTY fullness group when: - * n <= N / f, where - * n = number of allocated objects - * N = total number of objects zspage can store - * f = 1/fullness_threshold_frac - * - * Similarly, we assign zspage to: - * ZS_ALMOST_FULL when n > N / f - * ZS_EMPTY when n == 0 - * ZS_FULL when n == N - * - * (see: fix_fullness_group()) - */ -static const int fullness_threshold_frac = 4; - -struct mapping_area { - char *vm_buf; /* copy buffer for objects that span pages */ - char *vm_addr; /* address of kmap_atomic()'ed pages */ - enum zs_mapmode vm_mm; /* mapping mode */ -}; - -struct size_class { - /* - * Size of objects stored in this class. Must be multiple - * of ZS_ALIGN. - */ - int size; - unsigned int index; - - /* Number of PAGE_SIZE sized pages to combine to form a 'zspage' */ - int pages_per_zspage; - - spinlock_t lock; - - /* stats */ - u64 pages_allocated; - - struct page *fullness_list[_ZS_NR_FULLNESS_GROUPS]; -}; - -/* - * Placed within free objects to form a singly linked list. - * For every zspage, first_page->freelist gives head of this list. - * - * This must be power of 2 and less than or equal to ZS_ALIGN - */ -struct link_free { - /* Handle of next free chunk (encodes <PFN, obj_idx>) */ - void *next; -}; - -struct zs_pool { - struct size_class size_class[ZS_SIZE_CLASSES]; - - gfp_t flags; /* allocation flags used when growing pool */ - const char *name; -}; - -#endif diff --git a/include/linux/hid-sensor-hub.h b/include/linux/hid-sensor-hub.h new file mode 100644 index 000000000000..0aa5f4c42ae6 --- /dev/null +++ b/include/linux/hid-sensor-hub.h @@ -0,0 +1,160 @@ +/* + * HID Sensors Driver + * Copyright (c) 2012, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#ifndef _HID_SENSORS_HUB_H +#define _HID_SENSORS_HUB_H + +#include <linux/hid.h> +#include <linux/hid-sensor-ids.h> + +/** + * struct hid_sensor_hub_attribute_info - Attribute info + * @usage_id: Parent usage id of a physical device. + * @attrib_id: Attribute id for this attribute. + * @report_id: Report id in which this information resides. + * @index: Field index in the report. + * @units: Measurment unit for this attribute. + * @unit_expo: Exponent used in the data. + * @size: Size in bytes for data size. + */ +struct hid_sensor_hub_attribute_info { + u32 usage_id; + u32 attrib_id; + s32 report_id; + s32 index; + s32 units; + s32 unit_expo; + s32 size; +}; + +/** + * struct hid_sensor_hub_device - Stores the hub instance data + * @hdev: Stores the hid instance. + * @vendor_id: Vendor id of hub device. + * @product_id: Product id of hub device. + */ +struct hid_sensor_hub_device { + struct hid_device *hdev; + u32 vendor_id; + u32 product_id; +}; + +/** + * struct hid_sensor_hub_callbacks - Client callback functions + * @pdev: Platform device instance of the client driver. + * @suspend: Suspend callback. + * @resume: Resume callback. + * @capture_sample: Callback to get a sample. + * @send_event: Send notification to indicate all samples are + * captured, process and send event + */ +struct hid_sensor_hub_callbacks { + struct platform_device *pdev; + int (*suspend)(struct hid_sensor_hub_device *hsdev, void *priv); + int (*resume)(struct hid_sensor_hub_device *hsdev, void *priv); + int (*capture_sample)(struct hid_sensor_hub_device *hsdev, + u32 usage_id, size_t raw_len, char *raw_data, + void *priv); + int (*send_event)(struct hid_sensor_hub_device *hsdev, u32 usage_id, + void *priv); +}; + +/* Registration functions */ + +/** +* sensor_hub_register_callback() - Register client callbacks +* @hsdev: Hub device instance. +* @usage_id: Usage id of the client (E.g. 0x200076 for Gyro). +* @usage_callback: Callback function storage +* +* Used to register callbacks by client processing drivers. Sensor +* hub core driver will call these callbacks to offload processing +* of data streams and notifications. +*/ +int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev, + u32 usage_id, + struct hid_sensor_hub_callbacks *usage_callback); + +/** +* sensor_hub_remove_callback() - Remove client callbacks +* @hsdev: Hub device instance. +* @usage_id: Usage id of the client (E.g. 0x200076 for Gyro). +* +* If there is a callback registred, this call will remove that +* callbacks, so that it will stop data and event notifications. +*/ +int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev, + u32 usage_id); + + +/* Hid sensor hub core interfaces */ + +/** +* sensor_hub_input_get_attribute_info() - Get an attribute information +* @hsdev: Hub device instance. +* @type: Type of this attribute, input/output/feature +* @usage_id: Attribute usage id of parent physical device as per spec +* @attr_usage_id: Attribute usage id as per spec +* @info: return information about attribute after parsing report +* +* Parses report and returns the attribute information such as report id, +* field index, units and exponet etc. +*/ +int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev, + u8 type, + u32 usage_id, u32 attr_usage_id, + struct hid_sensor_hub_attribute_info *info); + +/** +* sensor_hub_input_attr_get_raw_value() - Synchronous read request +* @usage_id: Attribute usage id of parent physical device as per spec +* @attr_usage_id: Attribute usage id as per spec +* @report_id: Report id to look for +* +* Issues a synchronous read request for an input attribute. Returns +* data upto 32 bits. Since client can get events, so this call should +* not be used for data paths, this will impact performance. +*/ + +int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev, + u32 usage_id, + u32 attr_usage_id, u32 report_id); +/** +* sensor_hub_set_feature() - Feature set request +* @report_id: Report id to look for +* @field_index: Field index inside a report +* @value: Value to set +* +* Used to set a field in feature report. For example this can set polling +* interval, sensitivity, activate/deactivate state. +*/ +int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, + u32 field_index, s32 value); + +/** +* sensor_hub_get_feature() - Feature get request +* @report_id: Report id to look for +* @field_index: Field index inside a report +* @value: Place holder for return value +* +* Used to get a field in feature report. For example this can get polling +* interval, sensitivity, activate/deactivate state. +*/ +int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id, + u32 field_index, s32 *value); +#endif diff --git a/include/linux/hid-sensor-ids.h b/include/linux/hid-sensor-ids.h new file mode 100644 index 000000000000..ca8d7e94eb3c --- /dev/null +++ b/include/linux/hid-sensor-ids.h @@ -0,0 +1,112 @@ +/* + * HID Sensors Driver + * Copyright (c) 2012, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. + * + */ +#ifndef _HID_SENSORS_IDS_H +#define _HID_SENSORS_IDS_H + +#define HID_UP_SENSOR 0x00200000 +#define HID_MAX_PHY_DEVICES 0xFF + +/* Accel 3D (200073) */ +#define HID_USAGE_SENSOR_ACCEL_3D 0x200073 +#define HID_USAGE_SENSOR_ACCEL_X_AXIS 0x200453 +#define HID_USAGE_SENSOR_ACCEL_Y_AXIS 0x200454 +#define HID_USAGE_SENSOR_ACCEL_Z_AXIS 0x200455 + +/* ALS (200041) */ +#define HID_USAGE_SENSOR_ALS 0x200041 +#define HID_USAGE_SENSOR_LIGHT_ILLUM 0x2004d1 + +/* Gyro 3D: (200076) */ +#define HID_USAGE_SENSOR_GYRO_3D 0x200076 +#define HID_USAGE_SENSOR_ANGL_VELOCITY_X_AXIS 0x200457 +#define HID_USAGE_SENSOR_ANGL_VELOCITY_Y_AXIS 0x200458 +#define HID_USAGE_SENSOR_ANGL_VELOCITY_Z_AXIS 0x200459 + +/*ORIENTATION: Compass 3D: (200083) */ +#define HID_USAGE_SENSOR_COMPASS_3D 0x200083 +#define HID_USAGE_SENSOR_ORIENT_MAGN_HEADING 0x200471 +#define HID_USAGE_SENSOR_ORIENT_MAGN_HEADING_X 0x200472 +#define HID_USAGE_SENSOR_ORIENT_MAGN_HEADING_Y 0x200473 +#define HID_USAGE_SENSOR_ORIENT_MAGN_HEADING_Z 0x200474 + +#define HID_USAGE_SENSOR_ORIENT_COMP_MAGN_NORTH 0x200475 +#define HID_USAGE_SENSOR_ORIENT_COMP_TRUE_NORTH 0x200476 +#define HID_USAGE_SENSOR_ORIENT_MAGN_NORTH 0x200477 +#define HID_USAGE_SENSOR_ORIENT_TRUE_NORTH 0x200478 + +#define HID_USAGE_SENSOR_ORIENT_DISTANCE 0x200479 +#define HID_USAGE_SENSOR_ORIENT_DISTANCE_X 0x20047A +#define HID_USAGE_SENSOR_ORIENT_DISTANCE_Y 0x20047B +#define HID_USAGE_SENSOR_ORIENT_DISTANCE_Z 0x20047C +#define HID_USAGE_SENSOR_ORIENT_DISTANCE_OUT_OF_RANGE 0x20047D +#define HID_USAGE_SENSOR_ORIENT_TILT 0x20047E +#define HID_USAGE_SENSOR_ORIENT_TILT_X 0x20047F +#define HID_USAGE_SENSOR_ORIENT_TILT_Y 0x200480 +#define HID_USAGE_SENSOR_ORIENT_TILT_Z 0x200481 +#define HID_USAGE_SENSOR_ORIENT_ROTATION_MATRIX 0x200482 +#define HID_USAGE_SENSOR_ORIENT_QUATERNION 0x200483 +#define HID_USAGE_SENSOR_ORIENT_MAGN_FLUX 0x200484 + +#define HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_X_AXIS 0x200485 +#define HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Y_AXIS 0x200486 +#define HID_USAGE_SENSOR_ORIENT_MAGN_FLUX_Z_AXIS 0x200487 + +/* Units */ +#define HID_USAGE_SENSOR_UNITS_NOT_SPECIFIED 0x00 +#define HID_USAGE_SENSOR_UNITS_LUX 0x01 +#define HID_USAGE_SENSOR_UNITS_KELVIN 0x01000100 +#define HID_USAGE_SENSOR_UNITS_FAHRENHEIT 0x03000100 +#define HID_USAGE_SENSOR_UNITS_PASCAL 0xF1E1 +#define HID_USAGE_SENSOR_UNITS_NEWTON 0x11E1 +#define HID_USAGE_SENSOR_UNITS_METERS_PER_SECOND 0x11F0 +#define HID_USAGE_SENSOR_UNITS_METERS_PER_SEC_SQRD 0x11E0 +#define HID_USAGE_SENSOR_UNITS_FARAD 0xE14F2000 +#define HID_USAGE_SENSOR_UNITS_AMPERE 0x01001000 +#define HID_USAGE_SENSOR_UNITS_WATT 0x21d1 +#define HID_USAGE_SENSOR_UNITS_HENRY 0x21E1E000 +#define HID_USAGE_SENSOR_UNITS_OHM 0x21D1E000 +#define HID_USAGE_SENSOR_UNITS_VOLT 0x21D1F000 +#define HID_USAGE_SENSOR_UNITS_HERTZ 0x01F0 +#define HID_USAGE_SENSOR_UNITS_DEGREES_PER_SEC_SQRD 0x14E0 +#define HID_USAGE_SENSOR_UNITS_RADIANS 0x12 +#define HID_USAGE_SENSOR_UNITS_RADIANS_PER_SECOND 0x12F0 +#define HID_USAGE_SENSOR_UNITS_RADIANS_PER_SEC_SQRD 0x12E0 +#define HID_USAGE_SENSOR_UNITS_SECOND 0x0110 +#define HID_USAGE_SENSOR_UNITS_GAUSS 0x01E1F000 +#define HID_USAGE_SENSOR_UNITS_GRAM 0x0101 +#define HID_USAGE_SENSOR_UNITS_CENTIMETER 0x11 +#define HID_USAGE_SENSOR_UNITS_G 0x1A +#define HID_USAGE_SENSOR_UNITS_MILLISECOND 0x19 +#define HID_USAGE_SENSOR_UNITS_PERCENT 0x17 +#define HID_USAGE_SENSOR_UNITS_DEGREES 0x14 +#define HID_USAGE_SENSOR_UNITS_DEGREES_PER_SECOND 0x15 + +/* Common selectors */ +#define HID_USAGE_SENSOR_PROP_REPORT_INTERVAL 0x20030E +#define HID_USAGE_SENSOR_PROP_SENSITIVITY_ABS 0x20030F +#define HID_USAGE_SENSOR_PROP_SENSITIVITY_RANGE_PCT 0x200310 +#define HID_USAGE_SENSOR_PROP_SENSITIVITY_REL_PCT 0x200311 +#define HID_USAGE_SENSOR_PROP_ACCURACY 0x200312 +#define HID_USAGE_SENSOR_PROP_RESOLUTION 0x200313 +#define HID_USAGE_SENSOR_PROP_RANGE_MAXIMUM 0x200314 +#define HID_USAGE_SENSOR_PROP_RANGE_MINIMUM 0x200315 +#define HID_USAGE_SENSOR_PROP_REPORT_STATE 0x200316 +#define HID_USAGE_SENSOR_PROY_POWER_STATE 0x200319 + +#endif diff --git a/include/linux/iio/adc/ad_sigma_delta.h b/include/linux/iio/adc/ad_sigma_delta.h new file mode 100644 index 000000000000..2e4eab9868a3 --- /dev/null +++ b/include/linux/iio/adc/ad_sigma_delta.h @@ -0,0 +1,173 @@ +/* + * Support code for Analog Devices Sigma-Delta ADCs + * + * Copyright 2012 Analog Devices Inc. + * Author: Lars-Peter Clausen <lars@metafoo.de> + * + * Licensed under the GPL-2. + */ +#ifndef __AD_SIGMA_DELTA_H__ +#define __AD_SIGMA_DELTA_H__ + +enum ad_sigma_delta_mode { + AD_SD_MODE_CONTINUOUS = 0, + AD_SD_MODE_SINGLE = 1, + AD_SD_MODE_IDLE = 2, + AD_SD_MODE_POWERDOWN = 3, +}; + +/** + * struct ad_sigma_delta_calib_data - Calibration data for Sigma Delta devices + * @mode: Calibration mode. + * @channel: Calibration channel. + */ +struct ad_sd_calib_data { + unsigned int mode; + unsigned int channel; +}; + +struct ad_sigma_delta; +struct iio_dev; + +/** + * struct ad_sigma_delta_info - Sigma Delta driver specific callbacks and options + * @set_channel: Will be called to select the current channel, may be NULL. + * @set_mode: Will be called to select the current mode, may be NULL. + * @postprocess_sample: Is called for each sampled data word, can be used to + * modify or drop the sample data, it, may be NULL. + * @has_registers: true if the device has writable and readable registers, false + * if there is just one read-only sample data shift register. + * @addr_shift: Shift of the register address in the communications register. + * @read_mask: Mask for the communications register having the read bit set. + */ +struct ad_sigma_delta_info { + int (*set_channel)(struct ad_sigma_delta *, unsigned int channel); + int (*set_mode)(struct ad_sigma_delta *, enum ad_sigma_delta_mode mode); + int (*postprocess_sample)(struct ad_sigma_delta *, unsigned int raw_sample); + bool has_registers; + unsigned int addr_shift; + unsigned int read_mask; +}; + +/** + * struct ad_sigma_delta - Sigma Delta device struct + * @spi: The spi device associated with the Sigma Delta device. + * @trig: The IIO trigger associated with the Sigma Delta device. + * + * Most of the fields are private to the sigma delta library code and should not + * be accessed by individual drivers. + */ +struct ad_sigma_delta { + struct spi_device *spi; + struct iio_trigger *trig; + +/* private: */ + struct completion completion; + bool irq_dis; + + bool bus_locked; + + uint8_t comm; + + const struct ad_sigma_delta_info *info; + + /* + * DMA (thus cache coherency maintenance) requires the + * transfer buffers to live in their own cache lines. + */ + uint8_t data[4] ____cacheline_aligned; +}; + +static inline int ad_sigma_delta_set_channel(struct ad_sigma_delta *sd, + unsigned int channel) +{ + if (sd->info->set_channel) + return sd->info->set_channel(sd, channel); + + return 0; +} + +static inline int ad_sigma_delta_set_mode(struct ad_sigma_delta *sd, + unsigned int mode) +{ + if (sd->info->set_mode) + return sd->info->set_mode(sd, mode); + + return 0; +} + +static inline int ad_sigma_delta_postprocess_sample(struct ad_sigma_delta *sd, + unsigned int raw_sample) +{ + if (sd->info->postprocess_sample) + return sd->info->postprocess_sample(sd, raw_sample); + + return 0; +} + +void ad_sd_set_comm(struct ad_sigma_delta *sigma_delta, uint8_t comm); +int ad_sd_write_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg, + unsigned int size, unsigned int val); +int ad_sd_read_reg(struct ad_sigma_delta *sigma_delta, unsigned int reg, + unsigned int size, unsigned int *val); + +int ad_sigma_delta_single_conversion(struct iio_dev *indio_dev, + const struct iio_chan_spec *chan, int *val); +int ad_sd_calibrate_all(struct ad_sigma_delta *sigma_delta, + const struct ad_sd_calib_data *cd, unsigned int n); +int ad_sd_init(struct ad_sigma_delta *sigma_delta, struct iio_dev *indio_dev, + struct spi_device *spi, const struct ad_sigma_delta_info *info); + +int ad_sd_setup_buffer_and_trigger(struct iio_dev *indio_dev); +void ad_sd_cleanup_buffer_and_trigger(struct iio_dev *indio_dev); + +int ad_sd_validate_trigger(struct iio_dev *indio_dev, struct iio_trigger *trig); + +#define __AD_SD_CHANNEL(_si, _channel1, _channel2, _address, _bits, \ + _storagebits, _shift, _extend_name, _type) \ + { \ + .type = (_type), \ + .differential = (_channel2 == -1 ? 0 : 1), \ + .indexed = 1, \ + .channel = (_channel1), \ + .channel2 = (_channel2), \ + .address = (_address), \ + .extend_name = (_extend_name), \ + .info_mask = IIO_CHAN_INFO_RAW_SEPARATE_BIT | \ + IIO_CHAN_INFO_SCALE_SHARED_BIT | \ + IIO_CHAN_INFO_OFFSET_SEPARATE_BIT, \ + .scan_index = (_si), \ + .scan_type = { \ + .sign = 'u', \ + .realbits = (_bits), \ + .storagebits = (_storagebits), \ + .shift = (_shift), \ + .endianness = IIO_BE, \ + }, \ + } + +#define AD_SD_DIFF_CHANNEL(_si, _channel1, _channel2, _address, _bits, \ + _storagebits, _shift) \ + __AD_SD_CHANNEL(_si, _channel1, _channel2, _address, _bits, \ + _storagebits, _shift, NULL, IIO_VOLTAGE) + +#define AD_SD_SHORTED_CHANNEL(_si, _channel, _address, _bits, \ + _storagebits, _shift) \ + __AD_SD_CHANNEL(_si, _channel, _channel, _address, _bits, \ + _storagebits, _shift, "shorted", IIO_VOLTAGE) + +#define AD_SD_CHANNEL(_si, _channel, _address, _bits, \ + _storagebits, _shift) \ + __AD_SD_CHANNEL(_si, _channel, -1, _address, _bits, \ + _storagebits, _shift, NULL, IIO_VOLTAGE) + +#define AD_SD_TEMP_CHANNEL(_si, _address, _bits, _storagebits, _shift) \ + __AD_SD_CHANNEL(_si, 0, -1, _address, _bits, \ + _storagebits, _shift, NULL, IIO_TEMP) + +#define AD_SD_SUPPLY_CHANNEL(_si, _channel, _address, _bits, _storagebits, \ + _shift) \ + __AD_SD_CHANNEL(_si, _channel, -1, _address, _bits, \ + _storagebits, _shift, "supply", IIO_VOLTAGE) + +#endif diff --git a/include/linux/iio/buffer.h b/include/linux/iio/buffer.h index 8ba516fc2ec6..c629b3a1d9a9 100644 --- a/include/linux/iio/buffer.h +++ b/include/linux/iio/buffer.h @@ -36,7 +36,7 @@ struct iio_buffer; * any of them not existing. **/ struct iio_buffer_access_funcs { - int (*store_to)(struct iio_buffer *buffer, u8 *data, s64 timestamp); + int (*store_to)(struct iio_buffer *buffer, u8 *data); int (*read_first_n)(struct iio_buffer *buffer, size_t n, char __user *buf); @@ -118,10 +118,8 @@ int iio_scan_mask_set(struct iio_dev *indio_dev, * iio_push_to_buffer() - push to a registered buffer. * @buffer: IIO buffer structure for device * @data: the data to push to the buffer - * @timestamp: timestamp to associate with the data */ -int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data, - s64 timestamp); +int iio_push_to_buffer(struct iio_buffer *buffer, unsigned char *data); int iio_update_demux(struct iio_dev *indio_dev); diff --git a/include/linux/iio/consumer.h b/include/linux/iio/consumer.h index e2657e6d4d26..e875bcf0478f 100644 --- a/include/linux/iio/consumer.h +++ b/include/linux/iio/consumer.h @@ -8,7 +8,7 @@ * the Free Software Foundation. */ #ifndef _IIO_INKERN_CONSUMER_H_ -#define _IIO_INKERN_CONSUMER_H +#define _IIO_INKERN_CONSUMER_H_ #include <linux/iio/types.h> struct iio_dev; @@ -61,7 +61,7 @@ void iio_channel_release_all(struct iio_channel *chan); /** * iio_read_channel_raw() - read from a given channel - * @channel: The channel being queried. + * @chan: The channel being queried. * @val: Value read back. * * Note raw reads from iio channels are in adc counts and hence @@ -71,6 +71,21 @@ int iio_read_channel_raw(struct iio_channel *chan, int *val); /** + * iio_read_channel_processed() - read processed value from a given channel + * @chan: The channel being queried. + * @val: Value read back. + * + * Returns an error code or 0. + * + * This function will read a processed value from a channel. A processed value + * means that this value will have the correct unit and not some device internal + * representation. If the device does not support reporting a processed value + * the function will query the raw value and the channels scale and offset and + * do the appropriate transformation. + */ +int iio_read_channel_processed(struct iio_channel *chan, int *val); + +/** * iio_get_channel_type() - get the type of a channel * @channel: The channel being queried. * @type: The type of the channel. @@ -82,7 +97,7 @@ int iio_get_channel_type(struct iio_channel *channel, /** * iio_read_channel_scale() - read the scale value for a channel - * @channel: The channel being queried. + * @chan: The channel being queried. * @val: First part of value read back. * @val2: Second part of value read back. * @@ -93,4 +108,27 @@ int iio_get_channel_type(struct iio_channel *channel, int iio_read_channel_scale(struct iio_channel *chan, int *val, int *val2); +/** + * iio_convert_raw_to_processed() - Converts a raw value to a processed value + * @chan: The channel being queried + * @raw: The raw IIO to convert + * @processed: The result of the conversion + * @scale: Scale factor to apply during the conversion + * + * Returns an error code or 0. + * + * This function converts a raw value to processed value for a specific channel. + * A raw value is the device internal representation of a sample and the value + * returned by iio_read_channel_raw, so the unit of that value is device + * depended. A processed value on the other hand is value has a normed unit + * according with the IIO specification. + * + * The scale factor allows to increase the precession of the returned value. For + * a scale factor of 1 the function will return the result in the normal IIO + * unit for the channel type. E.g. millivolt for voltage channels, if you want + * nanovolts instead pass 1000 as the scale factor. + */ +int iio_convert_raw_to_processed(struct iio_channel *chan, int raw, + int *processed, unsigned int scale); + #endif diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h index be82936c4089..c0ae76ac4e0b 100644 --- a/include/linux/iio/iio.h +++ b/include/linux/iio/iio.h @@ -35,10 +35,13 @@ enum iio_chan_info_enum { IIO_CHAN_INFO_FREQUENCY, IIO_CHAN_INFO_PHASE, IIO_CHAN_INFO_HARDWAREGAIN, + IIO_CHAN_INFO_HYSTERESIS, }; #define IIO_CHAN_INFO_SHARED_BIT(type) BIT(type*2) #define IIO_CHAN_INFO_SEPARATE_BIT(type) BIT(type*2 + 1) +#define IIO_CHAN_INFO_BITS(type) (IIO_CHAN_INFO_SHARED_BIT(type) | \ + IIO_CHAN_INFO_SEPARATE_BIT(type)) #define IIO_CHAN_INFO_RAW_SEPARATE_BIT \ IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_RAW) @@ -100,6 +103,10 @@ enum iio_chan_info_enum { IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_HARDWAREGAIN) #define IIO_CHAN_INFO_HARDWAREGAIN_SHARED_BIT \ IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_HARDWAREGAIN) +#define IIO_CHAN_INFO_HYSTERESIS_SEPARATE_BIT \ + IIO_CHAN_INFO_SEPARATE_BIT(IIO_CHAN_INFO_HYSTERESIS) +#define IIO_CHAN_INFO_HYSTERESIS_SHARED_BIT \ + IIO_CHAN_INFO_SHARED_BIT(IIO_CHAN_INFO_HYSTERESIS) enum iio_endian { IIO_CPU, @@ -164,7 +171,7 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev, * IIO_ENUM() - Initialize enum extended channel attribute * @_name: Attribute name * @_shared: Whether the attribute is shared between all channels - * @_e: Pointer to a iio_enum struct + * @_e: Pointer to an iio_enum struct * * This should usually be used together with IIO_ENUM_AVAILABLE() */ @@ -180,9 +187,9 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev, /** * IIO_ENUM_AVAILABLE() - Initialize enum available extended channel attribute * @_name: Attribute name ("_available" will be appended to the name) - * @_e: Pointer to a iio_enum struct + * @_e: Pointer to an iio_enum struct * - * Creates a read only attribute which list all the available enum items in a + * Creates a read only attribute which lists all the available enum items in a * space separated list. This should usually be used together with IIO_ENUM() */ #define IIO_ENUM_AVAILABLE(_name, _e) \ @@ -229,6 +236,7 @@ ssize_t iio_enum_write(struct iio_dev *indio_dev, * @indexed: Specify the channel has a numerical index. If not, * the channel index number will be suppressed for sysfs * attributes but not for event codes. + * @output: Channel is output. * @differential: Channel is differential. */ struct iio_chan_spec { @@ -255,6 +263,21 @@ struct iio_chan_spec { unsigned differential:1; }; + +/** + * iio_channel_has_info() - Checks whether a channel supports a info attribute + * @chan: The channel to be queried + * @type: Type of the info attribute to be checked + * + * Returns true if the channels supports reporting values for the given info + * attribute type, false otherwise. + */ +static inline bool iio_channel_has_info(const struct iio_chan_spec *chan, + enum iio_chan_info_enum type) +{ + return chan->info_mask & IIO_CHAN_INFO_BITS(type); +} + #define IIO_ST(si, rb, sb, sh) \ { .sign = si, .realbits = rb, .storagebits = sb, .shift = sh } @@ -312,6 +335,9 @@ struct iio_dev; * Meaning is event dependent. * @validate_trigger: function to validate the trigger when the * current trigger gets changed. + * @update_scan_mode: function to configure device and scan buffer when + * channels have changed + * @debugfs_reg_access: function to read or write register value of device **/ struct iio_info { struct module *driver_module; @@ -367,10 +393,10 @@ struct iio_info { * scan mask is valid for the device. */ struct iio_buffer_setup_ops { - int (*preenable)(struct iio_dev *); - int (*postenable)(struct iio_dev *); - int (*predisable)(struct iio_dev *); - int (*postdisable)(struct iio_dev *); + int (*preenable)(struct iio_dev *); + int (*postenable)(struct iio_dev *); + int (*predisable)(struct iio_dev *); + int (*postdisable)(struct iio_dev *); bool (*validate_scan_mask)(struct iio_dev *indio_dev, const unsigned long *scan_mask); }; @@ -516,6 +542,31 @@ static inline struct iio_dev *iio_device_get(struct iio_dev *indio_dev) return indio_dev ? dev_to_iio_dev(get_device(&indio_dev->dev)) : NULL; } + +/** + * iio_device_set_drvdata() - Set device driver data + * @indio_dev: IIO device structure + * @data: Driver specific data + * + * Allows to attach an arbitrary pointer to an IIO device, which can later be + * retrieved by iio_device_get_drvdata(). + */ +static inline void iio_device_set_drvdata(struct iio_dev *indio_dev, void *data) +{ + dev_set_drvdata(&indio_dev->dev, data); +} + +/** + * iio_device_get_drvdata() - Get device driver data + * @indio_dev: IIO device structure + * + * Returns the data previously set with iio_device_set_drvdata() + */ +static inline void *iio_device_get_drvdata(struct iio_dev *indio_dev) +{ + return dev_get_drvdata(&indio_dev->dev); +} + /* Can we make this smaller? */ #define IIO_ALIGN L1_CACHE_BYTES /** diff --git a/include/linux/iio/kfifo_buf.h b/include/linux/iio/kfifo_buf.h index 014d5a13b32b..25eeac762e84 100644 --- a/include/linux/iio/kfifo_buf.h +++ b/include/linux/iio/kfifo_buf.h @@ -1,3 +1,5 @@ +#ifndef __LINUX_IIO_KFIFO_BUF_H__ +#define __LINUX_IIO_KFIFO_BUF_H__ #include <linux/kfifo.h> #include <linux/iio/iio.h> @@ -6,3 +8,4 @@ struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev); void iio_kfifo_free(struct iio_buffer *r); +#endif diff --git a/include/linux/iio/machine.h b/include/linux/iio/machine.h index 400a453ff67b..809a3f08d5a5 100644 --- a/include/linux/iio/machine.h +++ b/include/linux/iio/machine.h @@ -8,6 +8,9 @@ * the Free Software Foundation. */ +#ifndef __LINUX_IIO_MACHINE_H__ +#define __LINUX_IIO_MACHINE_H__ + /** * struct iio_map - description of link between consumer and device channels * @adc_channel_label: Label used to identify the channel on the provider. @@ -22,3 +25,5 @@ struct iio_map { const char *consumer_dev_name; const char *consumer_channel; }; + +#endif diff --git a/include/linux/iio/trigger.h b/include/linux/iio/trigger.h index a9819940a84c..20239da1d0f7 100644 --- a/include/linux/iio/trigger.h +++ b/include/linux/iio/trigger.h @@ -29,7 +29,7 @@ struct iio_subirq { * instances of a given device. **/ struct iio_trigger_ops { - struct module *owner; + struct module *owner; int (*set_trigger_state)(struct iio_trigger *trig, bool state); int (*try_reenable)(struct iio_trigger *trig); int (*validate_device)(struct iio_trigger *trig, @@ -39,7 +39,7 @@ struct iio_trigger_ops { /** * struct iio_trigger - industrial I/O trigger device - * + * @ops: [DRIVER] operations structure * @id: [INTERN] unique id number * @name: [DRIVER] unique name * @dev: [DRIVER] associated device (if relevant) @@ -76,19 +76,19 @@ struct iio_trigger { static inline struct iio_trigger *to_iio_trigger(struct device *d) { return container_of(d, struct iio_trigger, dev); -}; +} static inline void iio_trigger_put(struct iio_trigger *trig) { module_put(trig->ops->owner); put_device(&trig->dev); -}; +} static inline void iio_trigger_get(struct iio_trigger *trig) { get_device(&trig->dev); __module_get(trig->ops->owner); -}; +} /** * iio_trigger_register() - register a trigger with the IIO core @@ -104,7 +104,8 @@ void iio_trigger_unregister(struct iio_trigger *trig_info); /** * iio_trigger_poll() - called on a trigger occurring - * @trig: trigger which occurred + * @trig: trigger which occurred + * @time: timestamp when trigger occurred * * Typically called in relevant hardware interrupt handler. **/ diff --git a/include/linux/iio/trigger_consumer.h b/include/linux/iio/trigger_consumer.h index 60d64b356945..c4f8c7409666 100644 --- a/include/linux/iio/trigger_consumer.h +++ b/include/linux/iio/trigger_consumer.h @@ -7,6 +7,15 @@ * the Free Software Foundation. */ +#ifndef __LINUX_IIO_TRIGGER_CONSUMER_H__ +#define __LINUX_IIO_TRIGGER_CONSUMER_H__ + +#include <linux/interrupt.h> +#include <linux/types.h> + +struct iio_dev; +struct iio_trigger; + /** * struct iio_poll_func - poll function pair * @@ -50,3 +59,5 @@ void iio_trigger_notify_done(struct iio_trigger *trig); */ int iio_triggered_buffer_postenable(struct iio_dev *indio_dev); int iio_triggered_buffer_predisable(struct iio_dev *indio_dev); + +#endif diff --git a/include/linux/iio/types.h b/include/linux/iio/types.h index 44e397705d7f..5c647ecfd5ba 100644 --- a/include/linux/iio/types.h +++ b/include/linux/iio/types.h @@ -57,5 +57,6 @@ enum iio_modifier { #define IIO_VAL_INT_PLUS_MICRO 2 #define IIO_VAL_INT_PLUS_NANO 3 #define IIO_VAL_INT_PLUS_MICRO_DB 4 +#define IIO_VAL_FRACTIONAL 10 #endif /* _IIO_TYPES_H_ */ diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 6955045199b0..70c6a359b2f4 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -600,4 +600,12 @@ struct x86_cpu_id { #define X86_MODEL_ANY 0 #define X86_FEATURE_ANY 0 /* Same as FPU, you can't test for that */ +#define IPACK_ANY_FORMAT 0xff +#define IPACK_ANY_ID (~0) +struct ipack_device_id { + __u8 format; /* Format version or IPACK_ANY_ID */ + __u32 vendor; /* Vendor ID or IPACK_ANY_ID */ + __u32 device; /* Device ID or IPACK_ANY_ID */ +}; + #endif /* LINUX_MOD_DEVICETABLE_H */ diff --git a/include/linux/platform_data/ad5755.h b/include/linux/platform_data/ad5755.h new file mode 100644 index 000000000000..a5a1cb751874 --- /dev/null +++ b/include/linux/platform_data/ad5755.h @@ -0,0 +1,103 @@ +/* + * Copyright 2012 Analog Devices Inc. + * + * Licensed under the GPL-2. + */ +#ifndef __LINUX_PLATFORM_DATA_AD5755_H__ +#define __LINUX_PLATFORM_DATA_AD5755_H__ + +enum ad5755_mode { + AD5755_MODE_VOLTAGE_0V_5V = 0, + AD5755_MODE_VOLTAGE_0V_10V = 1, + AD5755_MODE_VOLTAGE_PLUSMINUS_5V = 2, + AD5755_MODE_VOLTAGE_PLUSMINUS_10V = 3, + AD5755_MODE_CURRENT_4mA_20mA = 4, + AD5755_MODE_CURRENT_0mA_20mA = 5, + AD5755_MODE_CURRENT_0mA_24mA = 6, +}; + +enum ad5755_dc_dc_phase { + AD5755_DC_DC_PHASE_ALL_SAME_EDGE = 0, + AD5755_DC_DC_PHASE_A_B_SAME_EDGE_C_D_OPP_EDGE = 1, + AD5755_DC_DC_PHASE_A_C_SAME_EDGE_B_D_OPP_EDGE = 2, + AD5755_DC_DC_PHASE_90_DEGREE = 3, +}; + +enum ad5755_dc_dc_freq { + AD5755_DC_DC_FREQ_250kHZ = 0, + AD5755_DC_DC_FREQ_410kHZ = 1, + AD5755_DC_DC_FREQ_650kHZ = 2, +}; + +enum ad5755_dc_dc_maxv { + AD5755_DC_DC_MAXV_23V = 0, + AD5755_DC_DC_MAXV_24V5 = 1, + AD5755_DC_DC_MAXV_27V = 2, + AD5755_DC_DC_MAXV_29V5 = 3, +}; + +enum ad5755_slew_rate { + AD5755_SLEW_RATE_64k = 0, + AD5755_SLEW_RATE_32k = 1, + AD5755_SLEW_RATE_16k = 2, + AD5755_SLEW_RATE_8k = 3, + AD5755_SLEW_RATE_4k = 4, + AD5755_SLEW_RATE_2k = 5, + AD5755_SLEW_RATE_1k = 6, + AD5755_SLEW_RATE_500 = 7, + AD5755_SLEW_RATE_250 = 8, + AD5755_SLEW_RATE_125 = 9, + AD5755_SLEW_RATE_64 = 10, + AD5755_SLEW_RATE_32 = 11, + AD5755_SLEW_RATE_16 = 12, + AD5755_SLEW_RATE_8 = 13, + AD5755_SLEW_RATE_4 = 14, + AD5755_SLEW_RATE_0_5 = 15, +}; + +enum ad5755_slew_step_size { + AD5755_SLEW_STEP_SIZE_1 = 0, + AD5755_SLEW_STEP_SIZE_2 = 1, + AD5755_SLEW_STEP_SIZE_4 = 2, + AD5755_SLEW_STEP_SIZE_8 = 3, + AD5755_SLEW_STEP_SIZE_16 = 4, + AD5755_SLEW_STEP_SIZE_32 = 5, + AD5755_SLEW_STEP_SIZE_64 = 6, + AD5755_SLEW_STEP_SIZE_128 = 7, + AD5755_SLEW_STEP_SIZE_256 = 8, +}; + +/** + * struct ad5755_platform_data - AD5755 DAC driver platform data + * @ext_dc_dc_compenstation_resistor: Whether an external DC-DC converter + * compensation register is used. + * @dc_dc_phase: DC-DC converter phase. + * @dc_dc_freq: DC-DC converter frequency. + * @dc_dc_maxv: DC-DC maximum allowed boost voltage. + * @dac.mode: The mode to be used for the DAC output. + * @dac.ext_current_sense_resistor: Whether an external current sense resistor + * is used. + * @dac.enable_voltage_overrange: Whether to enable 20% voltage output overrange. + * @dac.slew.enable: Whether to enable digital slew. + * @dac.slew.rate: Slew rate of the digital slew. + * @dac.slew.step_size: Slew step size of the digital slew. + **/ +struct ad5755_platform_data { + bool ext_dc_dc_compenstation_resistor; + enum ad5755_dc_dc_phase dc_dc_phase; + enum ad5755_dc_dc_freq dc_dc_freq; + enum ad5755_dc_dc_maxv dc_dc_maxv; + + struct { + enum ad5755_mode mode; + bool ext_current_sense_resistor; + bool enable_voltage_overrange; + struct { + bool enable; + enum ad5755_slew_rate rate; + enum ad5755_slew_step_size step_size; + } slew; + } dac[4]; +}; + +#endif diff --git a/include/linux/platform_data/ad7791.h b/include/linux/platform_data/ad7791.h new file mode 100644 index 000000000000..f9e4db1b82ae --- /dev/null +++ b/include/linux/platform_data/ad7791.h @@ -0,0 +1,17 @@ +#ifndef __LINUX_PLATFORM_DATA_AD7791__ +#define __LINUX_PLATFORM_DATA_AD7791__ + +/** + * struct ad7791_platform_data - AD7791 device platform data + * @buffered: If set to true configure the device for buffered input mode. + * @burnout_current: If set to true the 100mA burnout current is enabled. + * @unipolar: If set to true sample in unipolar mode, if set to false sample in + * bipolar mode. + */ +struct ad7791_platform_data { + bool buffered; + bool burnout_current; + bool unipolar; +}; + +#endif diff --git a/include/linux/power/generic-adc-battery.h b/include/linux/power/generic-adc-battery.h new file mode 100644 index 000000000000..b1ebe08533b6 --- /dev/null +++ b/include/linux/power/generic-adc-battery.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2012, Anish Kumar <anish198519851985@gmail.com> + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +#ifndef GENERIC_ADC_BATTERY_H +#define GENERIC_ADC_BATTERY_H + +/** + * struct gab_platform_data - platform_data for generic adc iio battery driver. + * @battery_info: recommended structure to specify static power supply + * parameters + * @cal_charge: calculate charge level. + * @gpio_charge_finished: gpio for the charger. + * @gpio_inverted: Should be 1 if the GPIO is active low otherwise 0 + * @jitter_delay: delay required after the interrupt to check battery + * status.Default set is 10ms. + */ +struct gab_platform_data { + struct power_supply_info battery_info; + int (*cal_charge)(long value); + int gpio_charge_finished; + bool gpio_inverted; + int jitter_delay; +}; + +#endif /* GENERIC_ADC_BATTERY_H */ diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c index 7ed6864ef65b..df4fc23dd836 100644 --- a/scripts/mod/file2alias.c +++ b/scripts/mod/file2alias.c @@ -966,6 +966,21 @@ static int do_isapnp_entry(const char *filename, } ADD_TO_DEVTABLE("isapnp", struct isapnp_device_id, do_isapnp_entry); +/* Looks like: "ipack:fNvNdN". */ +static int do_ipack_entry(const char *filename, + struct ipack_device_id *id, char *alias) +{ + id->vendor = TO_NATIVE(id->vendor); + id->device = TO_NATIVE(id->device); + strcpy(alias, "ipack:"); + ADD(alias, "f", id->format != IPACK_ANY_FORMAT, id->format); + ADD(alias, "v", id->vendor != IPACK_ANY_ID, id->vendor); + ADD(alias, "d", id->device != IPACK_ANY_ID, id->device); + add_wildcard(alias); + return 1; +} +ADD_TO_DEVTABLE("ipack", struct ipack_device_id, do_ipack_entry); + /* * Append a match expression for a single masked hex digit. * outp points to a pointer to the character at which to append. |