staging driver merge for 3.4-rc1

Here is the big drivers/staging/ merge for 3.4-rc1
 
 Lots of new driver updates here, with the addition of a few new ones, and only
 one moving out of the staging tree to the "real" part of the kernel (the hyperv
 scsi driver, acked by the scsi maintainer).
 
 There are also loads of cleanups, fixes, and other minor things in here, all
 self-contained in the drivers/staging/ tree.
 
 Overall we reversed the recent trend by adding more lines than we removed:
  379 files changed, 37952 insertions(+), 14153 deletions(-)
 
 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v2.0.18 (GNU/Linux)
 
 iEYEABECAAYFAk9necMACgkQMUfUDdst+ykn0gCgvUcAu8khJuLXKArhcyrIb7XH
 qVgAoIp4/Ntb+zNSI3UGX03VLx15VSdi
 =z2fR
 -----END PGP SIGNATURE-----

Merge tag 'staging-3.3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging

Pull big staging driver updates from Greg KH:
 "Here is the big drivers/staging/ merge for 3.4-rc1

  Lots of new driver updates here, with the addition of a few new ones,
  and only one moving out of the staging tree to the "real" part of the
  kernel (the hyperv scsi driver, acked by the scsi maintainer).

  There are also loads of cleanups, fixes, and other minor things in
  here, all self-contained in the drivers/staging/ tree.

  Overall we reversed the recent trend by adding more lines than we
  removed:
   379 files changed, 37952 insertions(+), 14153 deletions(-)"

* tag 'staging-3.3' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging: (360 commits)
  staging/zmem: Use lockdep_assert_held instead of spin_is_locked
  Staging: rtl8187se: r8180_wx.c: Cleaned up comments
  Staging: rtl8187se: r8180_wx.c: Removed old comments
  Staging: rtl8187se: r8180_dm.c: Removed old comments
  Staging: android: ram_console.c:
  Staging: rtl8187se: r8180_dm.c: Fix comments
  Staging: rtl8187se: r8180_dm.c: Fix spacing issues
  Staging: rtl8187se: r8180_dm.c Fixed indentation issues
  Staging: rtl8187se: r8180_dm.c: Fix brackets
  Staging: rtl8187se: r8180_dm.c: Removed spaces before tab stop
  staging: vme: fix section mismatches in linux-next 20120314
  Staging: rtl8187se: r8180_core.c: Fix some long line issues
  Staging: rtl8187se: r8180_core.c: Fix some spacing issues
  Staging: rtl8187se: r8180_core.c: Removed trailing spaces
  staging: mei: remove driver internal versioning
  Staging: rtl8187se: r8180_core.c: Cleaned up if statement
  staging: ozwpan depends on NET
  staging: ozwpan: added maintainer for ozwpan driver
  staging/mei: propagate error codes up in the write flow
  drivers:staging:mei Fix some typos in staging/mei
  ...
This commit is contained in:
Linus Torvalds 2012-03-20 11:23:18 -07:00
commit 71e7ff2578
379 changed files with 38023 additions and 14224 deletions

View File

@ -6395,6 +6395,11 @@ W: http://wiki.laptop.org/go/DCON
S: Odd Fixes
F: drivers/staging/olpc_dcon/
STAGING - OZMO DEVICES USB OVER WIFI DRIVER
M: Chris Kelly <ckelly@ozmodevices.com>
S: Maintained
F: drivers/staging/ozwpan/
STAGING - PARALLEL LCD/KEYPAD PANEL DRIVER
M: Willy Tarreau <willy@meta-x.org>
S: Odd Fixes

View File

@ -40,8 +40,6 @@ source "drivers/net/Kconfig"
source "drivers/isdn/Kconfig"
source "drivers/telephony/Kconfig"
# input before char - char/joystick depends on it. As does USB.
source "drivers/input/Kconfig"

View File

@ -86,7 +86,6 @@ obj-$(CONFIG_POWER_SUPPLY) += power/
obj-$(CONFIG_HWMON) += hwmon/
obj-$(CONFIG_THERMAL) += thermal/
obj-$(CONFIG_WATCHDOG) += watchdog/
obj-$(CONFIG_PHONE) += telephony/
obj-$(CONFIG_MD) += md/
obj-$(CONFIG_BT) += bluetooth/
obj-$(CONFIG_ACCESSIBILITY) += accessibility/

View File

@ -662,6 +662,13 @@ config VMWARE_PVSCSI
To compile this driver as a module, choose M here: the
module will be called vmw_pvscsi.
config HYPERV_STORAGE
tristate "Microsoft Hyper-V virtual storage driver"
depends on SCSI && HYPERV
default HYPERV
help
Select this option to enable the Hyper-V virtual storage driver.
config LIBFC
tristate "LibFC module"
select SCSI_FC_ATTRS

View File

@ -142,6 +142,7 @@ obj-$(CONFIG_SCSI_BNX2_ISCSI) += libiscsi.o bnx2i/
obj-$(CONFIG_BE2ISCSI) += libiscsi.o be2iscsi/
obj-$(CONFIG_SCSI_PMCRAID) += pmcraid.o
obj-$(CONFIG_VMWARE_PVSCSI) += vmw_pvscsi.o
obj-$(CONFIG_HYPERV_STORAGE) += hv_storvsc.o
obj-$(CONFIG_ARM) += arm/
@ -170,6 +171,8 @@ scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o
scsi_mod-y += scsi_trace.o
scsi_mod-$(CONFIG_PM) += scsi_pm.o
hv_storvsc-y := storvsc_drv.o
scsi_tgt-y += scsi_tgt_lib.o scsi_tgt_if.o
sd_mod-objs := sd.o

File diff suppressed because it is too large Load Diff

View File

@ -76,8 +76,6 @@ source "drivers/staging/vt6655/Kconfig"
source "drivers/staging/vt6656/Kconfig"
source "drivers/staging/hv/Kconfig"
source "drivers/staging/vme/Kconfig"
source "drivers/staging/sep/Kconfig"
@ -88,6 +86,8 @@ source "drivers/staging/zram/Kconfig"
source "drivers/staging/zcache/Kconfig"
source "drivers/staging/zsmalloc/Kconfig"
source "drivers/staging/wlags49_h2/Kconfig"
source "drivers/staging/wlags49_h25/Kconfig"
@ -128,4 +128,10 @@ source "drivers/staging/omapdrm/Kconfig"
source "drivers/staging/android/Kconfig"
source "drivers/staging/telephony/Kconfig"
source "drivers/staging/ramster/Kconfig"
source "drivers/staging/ozwpan/Kconfig"
endif # STAGING

View File

@ -29,13 +29,12 @@ obj-$(CONFIG_USB_SERIAL_QUATECH_USB2) += quatech_usb2/
obj-$(CONFIG_OCTEON_ETHERNET) += octeon/
obj-$(CONFIG_VT6655) += vt6655/
obj-$(CONFIG_VT6656) += vt6656/
obj-$(CONFIG_HYPERV) += hv/
obj-$(CONFIG_VME_BUS) += vme/
obj-$(CONFIG_DX_SEP) += sep/
obj-$(CONFIG_IIO) += iio/
obj-$(CONFIG_ZRAM) += zram/
obj-$(CONFIG_XVMALLOC) += zram/
obj-$(CONFIG_ZCACHE) += zcache/
obj-$(CONFIG_ZSMALLOC) += zsmalloc/
obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/
obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/
obj-$(CONFIG_FB_SM7XX) += sm7xx/
@ -55,3 +54,6 @@ obj-$(CONFIG_INTEL_MEI) += mei/
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/

View File

@ -25,65 +25,17 @@ config ANDROID_LOGGER
tristate "Android log driver"
default n
config ANDROID_RAM_CONSOLE
bool "Android RAM buffer console"
depends on !S390 && !UML
default n
config ANDROID_RAM_CONSOLE_ENABLE_VERBOSE
bool "Enable verbose console messages on Android RAM console"
default y
depends on ANDROID_RAM_CONSOLE
menuconfig ANDROID_RAM_CONSOLE_ERROR_CORRECTION
bool "Android RAM Console Enable error correction"
default n
depends on ANDROID_RAM_CONSOLE
depends on !ANDROID_RAM_CONSOLE_EARLY_INIT
config ANDROID_PERSISTENT_RAM
bool
select REED_SOLOMON
select REED_SOLOMON_ENC8
select REED_SOLOMON_DEC8
if ANDROID_RAM_CONSOLE_ERROR_CORRECTION
config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_DATA_SIZE
int "Android RAM Console Data data size"
default 128
help
Must be a power of 2.
config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_ECC_SIZE
int "Android RAM Console ECC size"
default 16
config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE
int "Android RAM Console Symbol size"
default 8
config ANDROID_RAM_CONSOLE_ERROR_CORRECTION_POLYNOMIAL
hex "Android RAM Console Polynomial"
default 0x19 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 4)
default 0x29 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 5)
default 0x61 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 6)
default 0x89 if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 7)
default 0x11d if (ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE = 8)
endif # ANDROID_RAM_CONSOLE_ERROR_CORRECTION
config ANDROID_RAM_CONSOLE_EARLY_INIT
bool "Start Android RAM console early"
config ANDROID_RAM_CONSOLE
bool "Android RAM buffer console"
depends on !S390 && !UML
select ANDROID_PERSISTENT_RAM
default n
depends on ANDROID_RAM_CONSOLE
config ANDROID_RAM_CONSOLE_EARLY_ADDR
hex "Android RAM console virtual address"
default 0
depends on ANDROID_RAM_CONSOLE_EARLY_INIT
config ANDROID_RAM_CONSOLE_EARLY_SIZE
hex "Android RAM console buffer size"
default 0
depends on ANDROID_RAM_CONSOLE_EARLY_INIT
config ANDROID_TIMED_OUTPUT
bool "Timed output class driver"
@ -102,6 +54,32 @@ config ANDROID_LOW_MEMORY_KILLER
source "drivers/staging/android/switch/Kconfig"
config ANDROID_INTF_ALARM
bool "Android alarm driver"
depends on RTC_CLASS
default n
help
Provides non-wakeup and rtc backed wakeup alarms based on rtc or
elapsed realtime, and a non-wakeup alarm on the monotonic clock.
Also provides an interface to set the wall time which must be used
for elapsed realtime to work.
config ANDROID_INTF_ALARM_DEV
bool "Android alarm device"
depends on ANDROID_INTF_ALARM
default y
help
Exports the alarm interface to user-space.
config ANDROID_ALARM_OLDDRV_COMPAT
bool "Android Alarm compatability with old drivers"
depends on ANDROID_INTF_ALARM
default n
help
Provides preprocessor alias to aid compatability with
older out-of-tree drivers that use the Android Alarm
in-kernel API. This will be removed eventually.
endif # if ANDROID
endmenu

View File

@ -1,8 +1,11 @@
obj-$(CONFIG_ANDROID_BINDER_IPC) += binder.o
obj-$(CONFIG_ASHMEM) += ashmem.o
obj-$(CONFIG_ANDROID_LOGGER) += logger.o
obj-$(CONFIG_ANDROID_PERSISTENT_RAM) += persistent_ram.o
obj-$(CONFIG_ANDROID_RAM_CONSOLE) += ram_console.o
obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o
obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o
obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o
obj-$(CONFIG_ANDROID_SWITCH) += switch/
obj-$(CONFIG_ANDROID_INTF_ALARM) += alarm.o
obj-$(CONFIG_ANDROID_INTF_ALARM_DEV) += alarm-dev.o

View File

@ -3,7 +3,7 @@ TODO:
- sparse fixes
- rename files to be not so "generic"
- make sure things build as modules properly
- add proper arch dependancies as needed
- add proper arch dependencies as needed
- audit userspace interfaces to make sure they are sane
Please send patches to Greg Kroah-Hartman <greg@kroah.com> and Cc:

View File

@ -0,0 +1,297 @@
/* drivers/rtc/alarm-dev.c
*
* Copyright (C) 2007-2009 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/time.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/uaccess.h>
#include "android_alarm.h"
/* XXX - Hack out wakelocks, while they are out of tree */
struct wake_lock {
int i;
};
#define wake_lock(x)
#define wake_lock_timeout(x, y)
#define wake_unlock(x)
#define WAKE_LOCK_SUSPEND 0
#define wake_lock_init(x, y, z) ((x)->i = 1)
#define wake_lock_destroy(x)
#define ANDROID_ALARM_PRINT_INFO (1U << 0)
#define ANDROID_ALARM_PRINT_IO (1U << 1)
#define ANDROID_ALARM_PRINT_INT (1U << 2)
static int debug_mask = ANDROID_ALARM_PRINT_INFO;
module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
#define pr_alarm(debug_level_mask, args...) \
do { \
if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask) { \
pr_info(args); \
} \
} while (0)
#define ANDROID_ALARM_WAKEUP_MASK ( \
ANDROID_ALARM_RTC_WAKEUP_MASK | \
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK)
/* support old usespace code */
#define ANDROID_ALARM_SET_OLD _IOW('a', 2, time_t) /* set alarm */
#define ANDROID_ALARM_SET_AND_WAIT_OLD _IOW('a', 3, time_t)
static int alarm_opened;
static DEFINE_SPINLOCK(alarm_slock);
static struct wake_lock alarm_wake_lock;
static DECLARE_WAIT_QUEUE_HEAD(alarm_wait_queue);
static uint32_t alarm_pending;
static uint32_t alarm_enabled;
static uint32_t wait_pending;
static struct android_alarm alarms[ANDROID_ALARM_TYPE_COUNT];
static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int rv = 0;
unsigned long flags;
struct timespec new_alarm_time;
struct timespec new_rtc_time;
struct timespec tmp_time;
enum android_alarm_type alarm_type = ANDROID_ALARM_IOCTL_TO_TYPE(cmd);
uint32_t alarm_type_mask = 1U << alarm_type;
if (alarm_type >= ANDROID_ALARM_TYPE_COUNT)
return -EINVAL;
if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_GET_TIME(0)) {
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
return -EPERM;
if (file->private_data == NULL &&
cmd != ANDROID_ALARM_SET_RTC) {
spin_lock_irqsave(&alarm_slock, flags);
if (alarm_opened) {
spin_unlock_irqrestore(&alarm_slock, flags);
return -EBUSY;
}
alarm_opened = 1;
file->private_data = (void *)1;
spin_unlock_irqrestore(&alarm_slock, flags);
}
}
switch (ANDROID_ALARM_BASE_CMD(cmd)) {
case ANDROID_ALARM_CLEAR(0):
spin_lock_irqsave(&alarm_slock, flags);
pr_alarm(IO, "alarm %d clear\n", alarm_type);
android_alarm_try_to_cancel(&alarms[alarm_type]);
if (alarm_pending) {
alarm_pending &= ~alarm_type_mask;
if (!alarm_pending && !wait_pending)
wake_unlock(&alarm_wake_lock);
}
alarm_enabled &= ~alarm_type_mask;
spin_unlock_irqrestore(&alarm_slock, flags);
break;
case ANDROID_ALARM_SET_OLD:
case ANDROID_ALARM_SET_AND_WAIT_OLD:
if (get_user(new_alarm_time.tv_sec, (int __user *)arg)) {
rv = -EFAULT;
goto err1;
}
new_alarm_time.tv_nsec = 0;
goto from_old_alarm_set;
case ANDROID_ALARM_SET_AND_WAIT(0):
case ANDROID_ALARM_SET(0):
if (copy_from_user(&new_alarm_time, (void __user *)arg,
sizeof(new_alarm_time))) {
rv = -EFAULT;
goto err1;
}
from_old_alarm_set:
spin_lock_irqsave(&alarm_slock, flags);
pr_alarm(IO, "alarm %d set %ld.%09ld\n", alarm_type,
new_alarm_time.tv_sec, new_alarm_time.tv_nsec);
alarm_enabled |= alarm_type_mask;
android_alarm_start_range(&alarms[alarm_type],
timespec_to_ktime(new_alarm_time),
timespec_to_ktime(new_alarm_time));
spin_unlock_irqrestore(&alarm_slock, flags);
if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0)
&& cmd != ANDROID_ALARM_SET_AND_WAIT_OLD)
break;
/* fall though */
case ANDROID_ALARM_WAIT:
spin_lock_irqsave(&alarm_slock, flags);
pr_alarm(IO, "alarm wait\n");
if (!alarm_pending && wait_pending) {
wake_unlock(&alarm_wake_lock);
wait_pending = 0;
}
spin_unlock_irqrestore(&alarm_slock, flags);
rv = wait_event_interruptible(alarm_wait_queue, alarm_pending);
if (rv)
goto err1;
spin_lock_irqsave(&alarm_slock, flags);
rv = alarm_pending;
wait_pending = 1;
alarm_pending = 0;
spin_unlock_irqrestore(&alarm_slock, flags);
break;
case ANDROID_ALARM_SET_RTC:
if (copy_from_user(&new_rtc_time, (void __user *)arg,
sizeof(new_rtc_time))) {
rv = -EFAULT;
goto err1;
}
rv = android_alarm_set_rtc(new_rtc_time);
spin_lock_irqsave(&alarm_slock, flags);
alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK;
wake_up(&alarm_wait_queue);
spin_unlock_irqrestore(&alarm_slock, flags);
if (rv < 0)
goto err1;
break;
case ANDROID_ALARM_GET_TIME(0):
switch (alarm_type) {
case ANDROID_ALARM_RTC_WAKEUP:
case ANDROID_ALARM_RTC:
getnstimeofday(&tmp_time);
break;
case ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP:
case ANDROID_ALARM_ELAPSED_REALTIME:
tmp_time =
ktime_to_timespec(alarm_get_elapsed_realtime());
break;
case ANDROID_ALARM_TYPE_COUNT:
case ANDROID_ALARM_SYSTEMTIME:
ktime_get_ts(&tmp_time);
break;
}
if (copy_to_user((void __user *)arg, &tmp_time,
sizeof(tmp_time))) {
rv = -EFAULT;
goto err1;
}
break;
default:
rv = -EINVAL;
goto err1;
}
err1:
return rv;
}
static int alarm_open(struct inode *inode, struct file *file)
{
file->private_data = NULL;
return 0;
}
static int alarm_release(struct inode *inode, struct file *file)
{
int i;
unsigned long flags;
spin_lock_irqsave(&alarm_slock, flags);
if (file->private_data != 0) {
for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {
uint32_t alarm_type_mask = 1U << i;
if (alarm_enabled & alarm_type_mask) {
pr_alarm(INFO, "alarm_release: clear alarm, "
"pending %d\n",
!!(alarm_pending & alarm_type_mask));
alarm_enabled &= ~alarm_type_mask;
}
spin_unlock_irqrestore(&alarm_slock, flags);
android_alarm_cancel(&alarms[i]);
spin_lock_irqsave(&alarm_slock, flags);
}
if (alarm_pending | wait_pending) {
if (alarm_pending)
pr_alarm(INFO, "alarm_release: clear "
"pending alarms %x\n", alarm_pending);
wake_unlock(&alarm_wake_lock);
wait_pending = 0;
alarm_pending = 0;
}
alarm_opened = 0;
}
spin_unlock_irqrestore(&alarm_slock, flags);
return 0;
}
static void alarm_triggered(struct android_alarm *alarm)
{
unsigned long flags;
uint32_t alarm_type_mask = 1U << alarm->type;
pr_alarm(INT, "alarm_triggered type %d\n", alarm->type);
spin_lock_irqsave(&alarm_slock, flags);
if (alarm_enabled & alarm_type_mask) {
wake_lock_timeout(&alarm_wake_lock, 5 * HZ);
alarm_enabled &= ~alarm_type_mask;
alarm_pending |= alarm_type_mask;
wake_up(&alarm_wait_queue);
}
spin_unlock_irqrestore(&alarm_slock, flags);
}
static const struct file_operations alarm_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = alarm_ioctl,
.open = alarm_open,
.release = alarm_release,
};
static struct miscdevice alarm_device = {
.minor = MISC_DYNAMIC_MINOR,
.name = "alarm",
.fops = &alarm_fops,
};
static int __init alarm_dev_init(void)
{
int err;
int i;
err = misc_register(&alarm_device);
if (err)
return err;
for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++)
android_alarm_init(&alarms[i], i, alarm_triggered);
wake_lock_init(&alarm_wake_lock, WAKE_LOCK_SUSPEND, "alarm");
return 0;
}
static void __exit alarm_dev_exit(void)
{
misc_deregister(&alarm_device);
wake_lock_destroy(&alarm_wake_lock);
}
module_init(alarm_dev_init);
module_exit(alarm_dev_exit);

View File

@ -0,0 +1,601 @@
/* drivers/rtc/alarm.c
*
* Copyright (C) 2007-2009 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/time.h>
#include <linux/module.h>
#include <linux/device.h>
#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include "android_alarm.h"
/* XXX - Hack out wakelocks, while they are out of tree */
struct wake_lock {
int i;
};
#define wake_lock(x)
#define wake_lock_timeout(x, y)
#define wake_unlock(x)
#define WAKE_LOCK_SUSPEND 0
#define wake_lock_init(x, y, z) ((x)->i = 1)
#define wake_lock_destroy(x)
#define ANDROID_ALARM_PRINT_ERROR (1U << 0)
#define ANDROID_ALARM_PRINT_INIT_STATUS (1U << 1)
#define ANDROID_ALARM_PRINT_TSET (1U << 2)
#define ANDROID_ALARM_PRINT_CALL (1U << 3)
#define ANDROID_ALARM_PRINT_SUSPEND (1U << 4)
#define ANDROID_ALARM_PRINT_INT (1U << 5)
#define ANDROID_ALARM_PRINT_FLOW (1U << 6)
static int debug_mask = ANDROID_ALARM_PRINT_ERROR | \
ANDROID_ALARM_PRINT_INIT_STATUS;
module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
#define pr_alarm(debug_level_mask, args...) \
do { \
if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask) { \
pr_info(args); \
} \
} while (0)
#define ANDROID_ALARM_WAKEUP_MASK ( \
ANDROID_ALARM_RTC_WAKEUP_MASK | \
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK)
/* support old usespace code */
#define ANDROID_ALARM_SET_OLD _IOW('a', 2, time_t) /* set alarm */
#define ANDROID_ALARM_SET_AND_WAIT_OLD _IOW('a', 3, time_t)
struct alarm_queue {
struct rb_root alarms;
struct rb_node *first;
struct hrtimer timer;
ktime_t delta;
bool stopped;
ktime_t stopped_time;
};
static struct rtc_device *alarm_rtc_dev;
static DEFINE_SPINLOCK(alarm_slock);
static DEFINE_MUTEX(alarm_setrtc_mutex);
static struct wake_lock alarm_rtc_wake_lock;
static struct platform_device *alarm_platform_dev;
struct alarm_queue alarms[ANDROID_ALARM_TYPE_COUNT];
static bool suspended;
static void update_timer_locked(struct alarm_queue *base, bool head_removed)
{
struct android_alarm *alarm;
bool is_wakeup = base == &alarms[ANDROID_ALARM_RTC_WAKEUP] ||
base == &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP];
if (base->stopped) {
pr_alarm(FLOW, "changed alarm while setting the wall time\n");
return;
}
if (is_wakeup && !suspended && head_removed)
wake_unlock(&alarm_rtc_wake_lock);
if (!base->first)
return;
alarm = container_of(base->first, struct android_alarm, node);
pr_alarm(FLOW, "selected alarm, type %d, func %pF at %lld\n",
alarm->type, alarm->function, ktime_to_ns(alarm->expires));
if (is_wakeup && suspended) {
pr_alarm(FLOW, "changed alarm while suspened\n");
wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ);
return;
}
hrtimer_try_to_cancel(&base->timer);
base->timer.node.expires = ktime_add(base->delta, alarm->expires);
base->timer._softexpires = ktime_add(base->delta, alarm->softexpires);
hrtimer_start_expires(&base->timer, HRTIMER_MODE_ABS);
}
static void alarm_enqueue_locked(struct android_alarm *alarm)
{
struct alarm_queue *base = &alarms[alarm->type];
struct rb_node **link = &base->alarms.rb_node;
struct rb_node *parent = NULL;
struct android_alarm *entry;
int leftmost = 1;
bool was_first = false;
pr_alarm(FLOW, "added alarm, type %d, func %pF at %lld\n",
alarm->type, alarm->function, ktime_to_ns(alarm->expires));
if (base->first == &alarm->node) {
base->first = rb_next(&alarm->node);
was_first = true;
}
if (!RB_EMPTY_NODE(&alarm->node)) {
rb_erase(&alarm->node, &base->alarms);
RB_CLEAR_NODE(&alarm->node);
}
while (*link) {
parent = *link;
entry = rb_entry(parent, struct android_alarm, node);
/*
* We dont care about collisions. Nodes with
* the same expiry time stay together.
*/
if (alarm->expires.tv64 < entry->expires.tv64) {
link = &(*link)->rb_left;
} else {
link = &(*link)->rb_right;
leftmost = 0;
}
}
if (leftmost)
base->first = &alarm->node;
if (leftmost || was_first)
update_timer_locked(base, was_first);
rb_link_node(&alarm->node, parent, link);
rb_insert_color(&alarm->node, &base->alarms);
}
/**
* android_alarm_init - initialize an alarm
* @alarm: the alarm to be initialized
* @type: the alarm type to be used
* @function: alarm callback function
*/
void android_alarm_init(struct android_alarm *alarm,
enum android_alarm_type type, void (*function)(struct android_alarm *))
{
RB_CLEAR_NODE(&alarm->node);
alarm->type = type;
alarm->function = function;
pr_alarm(FLOW, "created alarm, type %d, func %pF\n", type, function);
}
/**
* android_alarm_start_range - (re)start an alarm
* @alarm: the alarm to be added
* @start: earliest expiry time
* @end: expiry time
*/
void android_alarm_start_range(struct android_alarm *alarm, ktime_t start,
ktime_t end)
{
unsigned long flags;
spin_lock_irqsave(&alarm_slock, flags);
alarm->softexpires = start;
alarm->expires = end;
alarm_enqueue_locked(alarm);
spin_unlock_irqrestore(&alarm_slock, flags);
}
/**
* android_alarm_try_to_cancel - try to deactivate an alarm
* @alarm: alarm to stop
*
* Returns:
* 0 when the alarm was not active
* 1 when the alarm was active
* -1 when the alarm may currently be excuting the callback function and
* cannot be stopped (it may also be inactive)
*/
int android_alarm_try_to_cancel(struct android_alarm *alarm)
{
struct alarm_queue *base = &alarms[alarm->type];
unsigned long flags;
bool first = false;
int ret = 0;
spin_lock_irqsave(&alarm_slock, flags);
if (!RB_EMPTY_NODE(&alarm->node)) {
pr_alarm(FLOW, "canceled alarm, type %d, func %pF at %lld\n",
alarm->type, alarm->function,
ktime_to_ns(alarm->expires));
ret = 1;
if (base->first == &alarm->node) {
base->first = rb_next(&alarm->node);
first = true;
}
rb_erase(&alarm->node, &base->alarms);
RB_CLEAR_NODE(&alarm->node);
if (first)
update_timer_locked(base, true);
} else
pr_alarm(FLOW, "tried to cancel alarm, type %d, func %pF\n",
alarm->type, alarm->function);
spin_unlock_irqrestore(&alarm_slock, flags);
if (!ret && hrtimer_callback_running(&base->timer))
ret = -1;
return ret;
}
/**
* android_alarm_cancel - cancel an alarm and wait for the handler to finish.
* @alarm: the alarm to be cancelled
*
* Returns:
* 0 when the alarm was not active
* 1 when the alarm was active
*/
int android_alarm_cancel(struct android_alarm *alarm)
{
for (;;) {
int ret = android_alarm_try_to_cancel(alarm);
if (ret >= 0)
return ret;
cpu_relax();
}
}
/**
* alarm_set_rtc - set the kernel and rtc walltime
* @new_time: timespec value containing the new time
*/
int android_alarm_set_rtc(struct timespec new_time)
{
int i;
int ret;
unsigned long flags;
struct rtc_time rtc_new_rtc_time;
struct timespec tmp_time;
rtc_time_to_tm(new_time.tv_sec, &rtc_new_rtc_time);
pr_alarm(TSET, "set rtc %ld %ld - rtc %02d:%02d:%02d %02d/%02d/%04d\n",
new_time.tv_sec, new_time.tv_nsec,
rtc_new_rtc_time.tm_hour, rtc_new_rtc_time.tm_min,
rtc_new_rtc_time.tm_sec, rtc_new_rtc_time.tm_mon + 1,
rtc_new_rtc_time.tm_mday,
rtc_new_rtc_time.tm_year + 1900);
mutex_lock(&alarm_setrtc_mutex);
spin_lock_irqsave(&alarm_slock, flags);
wake_lock(&alarm_rtc_wake_lock);
getnstimeofday(&tmp_time);
for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
hrtimer_try_to_cancel(&alarms[i].timer);
alarms[i].stopped = true;
alarms[i].stopped_time = timespec_to_ktime(tmp_time);
}
alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta =
alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta =
ktime_sub(alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta,
timespec_to_ktime(timespec_sub(tmp_time, new_time)));
spin_unlock_irqrestore(&alarm_slock, flags);
ret = do_settimeofday(&new_time);
spin_lock_irqsave(&alarm_slock, flags);
for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
alarms[i].stopped = false;
update_timer_locked(&alarms[i], false);
}
spin_unlock_irqrestore(&alarm_slock, flags);
if (ret < 0) {
pr_alarm(ERROR, "alarm_set_rtc: Failed to set time\n");
goto err;
}
if (!alarm_rtc_dev) {
pr_alarm(ERROR,
"alarm_set_rtc: no RTC, time will be lost on reboot\n");
goto err;
}
ret = rtc_set_time(alarm_rtc_dev, &rtc_new_rtc_time);
if (ret < 0)
pr_alarm(ERROR, "alarm_set_rtc: "
"Failed to set RTC, time will be lost on reboot\n");
err:
wake_unlock(&alarm_rtc_wake_lock);
mutex_unlock(&alarm_setrtc_mutex);
return ret;
}
/**
* alarm_get_elapsed_realtime - get the elapsed real time in ktime_t format
*
* returns the time in ktime_t format
*/
ktime_t alarm_get_elapsed_realtime(void)
{
ktime_t now;
unsigned long flags;
struct alarm_queue *base = &alarms[ANDROID_ALARM_ELAPSED_REALTIME];
spin_lock_irqsave(&alarm_slock, flags);
now = base->stopped ? base->stopped_time : ktime_get_real();
now = ktime_sub(now, base->delta);
spin_unlock_irqrestore(&alarm_slock, flags);
return now;
}
static enum hrtimer_restart alarm_timer_triggered(struct hrtimer *timer)
{
struct alarm_queue *base;
struct android_alarm *alarm;
unsigned long flags;
ktime_t now;
spin_lock_irqsave(&alarm_slock, flags);
base = container_of(timer, struct alarm_queue, timer);
now = base->stopped ? base->stopped_time : hrtimer_cb_get_time(timer);
now = ktime_sub(now, base->delta);
pr_alarm(INT, "alarm_timer_triggered type %ld at %lld\n",
base - alarms, ktime_to_ns(now));
while (base->first) {
alarm = container_of(base->first, struct android_alarm, node);
if (alarm->softexpires.tv64 > now.tv64) {
pr_alarm(FLOW, "don't call alarm, %pF, %lld (s %lld)\n",
alarm->function, ktime_to_ns(alarm->expires),
ktime_to_ns(alarm->softexpires));
break;
}
base->first = rb_next(&alarm->node);
rb_erase(&alarm->node, &base->alarms);
RB_CLEAR_NODE(&alarm->node);
pr_alarm(CALL, "call alarm, type %d, func %pF, %lld (s %lld)\n",
alarm->type, alarm->function,
ktime_to_ns(alarm->expires),
ktime_to_ns(alarm->softexpires));
spin_unlock_irqrestore(&alarm_slock, flags);
alarm->function(alarm);
spin_lock_irqsave(&alarm_slock, flags);
}
if (!base->first)
pr_alarm(FLOW, "no more alarms of type %ld\n", base - alarms);
update_timer_locked(base, true);
spin_unlock_irqrestore(&alarm_slock, flags);
return HRTIMER_NORESTART;
}
static void alarm_triggered_func(void *p)
{
struct rtc_device *rtc = alarm_rtc_dev;
if (!(rtc->irq_data & RTC_AF))
return;
pr_alarm(INT, "rtc alarm triggered\n");
wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ);
}
static int alarm_suspend(struct platform_device *pdev, pm_message_t state)
{
int err = 0;
unsigned long flags;
struct rtc_wkalrm rtc_alarm;
struct rtc_time rtc_current_rtc_time;
unsigned long rtc_current_time;
unsigned long rtc_alarm_time;
struct timespec rtc_delta;
struct timespec wall_time;
struct alarm_queue *wakeup_queue = NULL;
struct alarm_queue *tmp_queue = NULL;
pr_alarm(SUSPEND, "alarm_suspend(%p, %d)\n", pdev, state.event);
spin_lock_irqsave(&alarm_slock, flags);
suspended = true;
spin_unlock_irqrestore(&alarm_slock, flags);
hrtimer_cancel(&alarms[ANDROID_ALARM_RTC_WAKEUP].timer);
hrtimer_cancel(&alarms[
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].timer);
tmp_queue = &alarms[ANDROID_ALARM_RTC_WAKEUP];
if (tmp_queue->first)
wakeup_queue = tmp_queue;
tmp_queue = &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP];
if (tmp_queue->first && (!wakeup_queue ||
hrtimer_get_expires(&tmp_queue->timer).tv64 <
hrtimer_get_expires(&wakeup_queue->timer).tv64))
wakeup_queue = tmp_queue;
if (wakeup_queue) {
rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time);
getnstimeofday(&wall_time);
rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time);
set_normalized_timespec(&rtc_delta,
wall_time.tv_sec - rtc_current_time,
wall_time.tv_nsec);
rtc_alarm_time = timespec_sub(ktime_to_timespec(
hrtimer_get_expires(&wakeup_queue->timer)),
rtc_delta).tv_sec;
rtc_time_to_tm(rtc_alarm_time, &rtc_alarm.time);
rtc_alarm.enabled = 1;
rtc_set_alarm(alarm_rtc_dev, &rtc_alarm);
rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time);
rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time);
pr_alarm(SUSPEND,
"rtc alarm set at %ld, now %ld, rtc delta %ld.%09ld\n",
rtc_alarm_time, rtc_current_time,
rtc_delta.tv_sec, rtc_delta.tv_nsec);
if (rtc_current_time + 1 >= rtc_alarm_time) {
pr_alarm(SUSPEND, "alarm about to go off\n");
memset(&rtc_alarm, 0, sizeof(rtc_alarm));
rtc_alarm.enabled = 0;
rtc_set_alarm(alarm_rtc_dev, &rtc_alarm);
spin_lock_irqsave(&alarm_slock, flags);
suspended = false;
wake_lock_timeout(&alarm_rtc_wake_lock, 2 * HZ);
update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP],
false);
update_timer_locked(&alarms[
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP], false);
err = -EBUSY;
spin_unlock_irqrestore(&alarm_slock, flags);
}
}
return err;
}
static int alarm_resume(struct platform_device *pdev)
{
struct rtc_wkalrm alarm;
unsigned long flags;
pr_alarm(SUSPEND, "alarm_resume(%p)\n", pdev);
memset(&alarm, 0, sizeof(alarm));
alarm.enabled = 0;
rtc_set_alarm(alarm_rtc_dev, &alarm);
spin_lock_irqsave(&alarm_slock, flags);
suspended = false;
update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP], false);
update_timer_locked(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP],
false);
spin_unlock_irqrestore(&alarm_slock, flags);
return 0;
}
static struct rtc_task alarm_rtc_task = {
.func = alarm_triggered_func
};
static int rtc_alarm_add_device(struct device *dev,
struct class_interface *class_intf)
{
int err;
struct rtc_device *rtc = to_rtc_device(dev);
mutex_lock(&alarm_setrtc_mutex);
if (alarm_rtc_dev) {
err = -EBUSY;
goto err1;
}
alarm_platform_dev =
platform_device_register_simple("alarm", -1, NULL, 0);
if (IS_ERR(alarm_platform_dev)) {
err = PTR_ERR(alarm_platform_dev);
goto err2;
}
err = rtc_irq_register(rtc, &alarm_rtc_task);
if (err)
goto err3;
alarm_rtc_dev = rtc;
pr_alarm(INIT_STATUS, "using rtc device, %s, for alarms", rtc->name);
mutex_unlock(&alarm_setrtc_mutex);
return 0;
err3:
platform_device_unregister(alarm_platform_dev);
err2:
err1:
mutex_unlock(&alarm_setrtc_mutex);
return err;
}
static void rtc_alarm_remove_device(struct device *dev,
struct class_interface *class_intf)
{
if (dev == &alarm_rtc_dev->dev) {
pr_alarm(INIT_STATUS, "lost rtc device for alarms");
rtc_irq_unregister(alarm_rtc_dev, &alarm_rtc_task);
platform_device_unregister(alarm_platform_dev);
alarm_rtc_dev = NULL;
}
}
static struct class_interface rtc_alarm_interface = {
.add_dev = &rtc_alarm_add_device,
.remove_dev = &rtc_alarm_remove_device,
};
static struct platform_driver alarm_driver = {
.suspend = alarm_suspend,
.resume = alarm_resume,
.driver = {
.name = "alarm"
}
};
static int __init alarm_late_init(void)
{
unsigned long flags;
struct timespec tmp_time, system_time;
/* this needs to run after the rtc is read at boot */
spin_lock_irqsave(&alarm_slock, flags);
/* We read the current rtc and system time so we can later calulate
* elasped realtime to be (boot_systemtime + rtc - boot_rtc) ==
* (rtc - (boot_rtc - boot_systemtime))
*/
getnstimeofday(&tmp_time);
ktime_get_ts(&system_time);
alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta =
alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta =
timespec_to_ktime(timespec_sub(tmp_time, system_time));
spin_unlock_irqrestore(&alarm_slock, flags);
return 0;
}
static int __init alarm_driver_init(void)
{
int err;
int i;
for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
hrtimer_init(&alarms[i].timer,
CLOCK_REALTIME, HRTIMER_MODE_ABS);
alarms[i].timer.function = alarm_timer_triggered;
}
hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].timer,
CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
alarms[ANDROID_ALARM_SYSTEMTIME].timer.function = alarm_timer_triggered;
err = platform_driver_register(&alarm_driver);
if (err < 0)
goto err1;
wake_lock_init(&alarm_rtc_wake_lock, WAKE_LOCK_SUSPEND, "alarm_rtc");
rtc_alarm_interface.class = rtc_class;
err = class_interface_register(&rtc_alarm_interface);
if (err < 0)
goto err2;
return 0;
err2:
wake_lock_destroy(&alarm_rtc_wake_lock);
platform_driver_unregister(&alarm_driver);
err1:
return err;
}
static void __exit alarm_exit(void)
{
class_interface_unregister(&rtc_alarm_interface);
wake_lock_destroy(&alarm_rtc_wake_lock);
platform_driver_unregister(&alarm_driver);
}
late_initcall(alarm_late_init);
module_init(alarm_driver_init);
module_exit(alarm_exit);

View File

@ -0,0 +1,121 @@
/* include/linux/android_alarm.h
*
* Copyright (C) 2006-2007 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _LINUX_ANDROID_ALARM_H
#define _LINUX_ANDROID_ALARM_H
#include <linux/ioctl.h>
#include <linux/time.h>
enum android_alarm_type {
/* return code bit numbers or set alarm arg */
ANDROID_ALARM_RTC_WAKEUP,
ANDROID_ALARM_RTC,
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
ANDROID_ALARM_ELAPSED_REALTIME,
ANDROID_ALARM_SYSTEMTIME,
ANDROID_ALARM_TYPE_COUNT,
/* return code bit numbers */
/* ANDROID_ALARM_TIME_CHANGE = 16 */
};
#ifdef __KERNEL__
#include <linux/ktime.h>
#include <linux/rbtree.h>
/*
* The alarm interface is similar to the hrtimer interface but adds support
* for wakeup from suspend. It also adds an elapsed realtime clock that can
* be used for periodic timers that need to keep runing while the system is
* suspended and not be disrupted when the wall time is set.
*/
/**
* struct alarm - the basic alarm structure
* @node: red black tree node for time ordered insertion
* @type: alarm type. rtc/elapsed-realtime/systemtime, wakeup/non-wakeup.
* @softexpires: the absolute earliest expiry time of the alarm.
* @expires: the absolute expiry time.
* @function: alarm expiry callback function
*
* The alarm structure must be initialized by alarm_init()
*
*/
struct android_alarm {
struct rb_node node;
enum android_alarm_type type;
ktime_t softexpires;
ktime_t expires;
void (*function)(struct android_alarm *);
};
void android_alarm_init(struct android_alarm *alarm,
enum android_alarm_type type, void (*function)(struct android_alarm *));
void android_alarm_start_range(struct android_alarm *alarm, ktime_t start,
ktime_t end);
int android_alarm_try_to_cancel(struct android_alarm *alarm);
int android_alarm_cancel(struct android_alarm *alarm);
ktime_t alarm_get_elapsed_realtime(void);
/* set rtc while preserving elapsed realtime */
int android_alarm_set_rtc(const struct timespec ts);
#ifdef CONFIG_ANDROID_ALARM_OLDDRV_COMPAT
/*
* Some older drivers depend on the old API,
* so provide compatability macros for now.
*/
#define alarm android_alarm
#define alarm_init(x, y, z) android_alarm_init(x, y, z)
#define alarm_start_range(x, y, z) android_alarm_start_range(x, y, z)
#define alarm_try_to_cancel(x) android_alarm_try_to_cancel(x)
#define alarm_cancel(x) android_alarm_cancel(x)
#define alarm_set_rtc(x) android_alarm_set_rtc(x)
#endif
#endif
enum android_alarm_return_flags {
ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP,
ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC,
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK =
1U << ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
ANDROID_ALARM_ELAPSED_REALTIME_MASK =
1U << ANDROID_ALARM_ELAPSED_REALTIME,
ANDROID_ALARM_SYSTEMTIME_MASK = 1U << ANDROID_ALARM_SYSTEMTIME,
ANDROID_ALARM_TIME_CHANGE_MASK = 1U << 16
};
/* Disable alarm */
#define ANDROID_ALARM_CLEAR(type) _IO('a', 0 | ((type) << 4))
/* Ack last alarm and wait for next */
#define ANDROID_ALARM_WAIT _IO('a', 1)
#define ALARM_IOW(c, type, size) _IOW('a', (c) | ((type) << 4), size)
/* Set alarm */
#define ANDROID_ALARM_SET(type) ALARM_IOW(2, type, struct timespec)
#define ANDROID_ALARM_SET_AND_WAIT(type) ALARM_IOW(3, type, struct timespec)
#define ANDROID_ALARM_GET_TIME(type) ALARM_IOW(4, type, struct timespec)
#define ANDROID_ALARM_SET_RTC _IOW('a', 5, struct timespec)
#define ANDROID_ALARM_BASE_CMD(cmd) (cmd & ~(_IOC(0, 0, 0xf0, 0)))
#define ANDROID_ALARM_IOCTL_TO_TYPE(cmd) (_IOC_NR(cmd) >> 4)
#endif

View File

@ -315,7 +315,7 @@ static int ashmem_mmap(struct file *file, struct vm_area_struct *vma)
get_file(asma->file);
/*
* XXX - Reworked to use shmem_zero_setup() instead of
* XXX - Reworked to use shmem_zero_setup() instead of
* shmem_set_file while we're in staging. -jstultz
*/
if (vma->vm_flags & VM_SHARED) {
@ -680,7 +680,7 @@ static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return ret;
}
static struct file_operations ashmem_fops = {
static const struct file_operations ashmem_fops = {
.owner = THIS_MODULE,
.open = ashmem_open,
.release = ashmem_release,

View File

@ -103,7 +103,7 @@ static uint32_t binder_debug_mask = BINDER_DEBUG_USER_ERROR |
BINDER_DEBUG_FAILED_TRANSACTION | BINDER_DEBUG_DEAD_TRANSACTION;
module_param_named(debug_mask, binder_debug_mask, uint, S_IWUSR | S_IRUGO);
static int binder_debug_no_lock;
static bool binder_debug_no_lock;
module_param_named(proc_no_lock, binder_debug_no_lock, bool, S_IWUSR | S_IRUGO);
static DECLARE_WAIT_QUEUE_HEAD(binder_user_error_wait);
@ -258,7 +258,7 @@ struct binder_ref {
};
struct binder_buffer {
struct list_head entry; /* free and allocated entries by addesss */
struct list_head entry; /* free and allocated entries by address */
struct rb_node rb_node; /* free entry by size or allocated entry */
/* by address */
unsigned free:1;
@ -288,6 +288,7 @@ struct binder_proc {
struct rb_root refs_by_node;
int pid;
struct vm_area_struct *vma;
struct mm_struct *vma_vm_mm;
struct task_struct *tsk;
struct files_struct *files;
struct hlist_node deferred_work_node;
@ -633,7 +634,7 @@ static int binder_update_page_range(struct binder_proc *proc, int allocate,
if (mm) {
down_write(&mm->mmap_sem);
vma = proc->vma;
if (vma && mm != vma->vm_mm) {
if (vma && mm != proc->vma_vm_mm) {
pr_err("binder: %d: vma mm and task mm mismatch\n",
proc->pid);
vma = NULL;
@ -2776,6 +2777,7 @@ static void binder_vma_close(struct vm_area_struct *vma)
(vma->vm_end - vma->vm_start) / SZ_1K, vma->vm_flags,
(unsigned long)pgprot_val(vma->vm_page_prot));
proc->vma = NULL;
proc->vma_vm_mm = NULL;
binder_defer_work(proc, BINDER_DEFERRED_PUT_FILES);
}
@ -2858,6 +2860,7 @@ static int binder_mmap(struct file *filp, struct vm_area_struct *vma)
barrier();
proc->files = get_files_struct(proc->tsk);
proc->vma = vma;
proc->vma_vm_mm = vma->vm_mm;
/*printk(KERN_INFO "binder_mmap: %d %lx-%lx maps %p\n",
proc->pid, vma->vm_start, vma->vm_end, proc->buffer);*/

View File

@ -60,7 +60,11 @@ struct logger_reader {
};
/* logger_offset - returns index 'n' into the log via (optimized) modulus */
#define logger_offset(n) ((n) & (log->size - 1))
size_t logger_offset(struct logger_log *log, size_t n)
{
return n & (log->size-1);
}
/*
* file_get_log - Given a file structure, return the associated log
@ -89,20 +93,24 @@ static inline struct logger_log *file_get_log(struct file *file)
* get_entry_len - Grabs the length of the payload of the next entry starting
* from 'off'.
*
* An entry length is 2 bytes (16 bits) in host endian order.
* In the log, the length does not include the size of the log entry structure.
* This function returns the size including the log entry structure.
*
* Caller needs to hold log->mutex.
*/
static __u32 get_entry_len(struct logger_log *log, size_t off)
{
__u16 val;
switch (log->size - off) {
case 1:
memcpy(&val, log->buffer + off, 1);
memcpy(((char *) &val) + 1, log->buffer, 1);
break;
default:
memcpy(&val, log->buffer + off, 2);
}
/* copy 2 bytes from buffer, in memcpy order, */
/* handling possible wrap at end of buffer */
((__u8 *)&val)[0] = log->buffer[off];
if (likely(off+1 < log->size))
((__u8 *)&val)[1] = log->buffer[off+1];
else
((__u8 *)&val)[1] = log->buffer[0];
return sizeof(struct logger_entry) + val;
}
@ -137,7 +145,7 @@ static ssize_t do_read_log_to_user(struct logger_log *log,
if (copy_to_user(buf + len, log->buffer, count - len))
return -EFAULT;
reader->r_off = logger_offset(reader->r_off + count);
reader->r_off = logger_offset(log, reader->r_off + count);
return count;
}
@ -164,9 +172,10 @@ static ssize_t logger_read(struct file *file, char __user *buf,
start:
while (1) {
mutex_lock(&log->mutex);
prepare_to_wait(&log->wq, &wait, TASK_INTERRUPTIBLE);
mutex_lock(&log->mutex);
ret = (log->w_off == reader->r_off);
mutex_unlock(&log->mutex);
if (!ret)
@ -225,7 +234,7 @@ static size_t get_next_entry(struct logger_log *log, size_t off, size_t len)
do {
size_t nr = get_entry_len(log, off);
off = logger_offset(off + nr);
off = logger_offset(log, off + nr);
count += nr;
} while (count < len);
@ -233,16 +242,28 @@ static size_t get_next_entry(struct logger_log *log, size_t off, size_t len)
}
/*
* clock_interval - is a < c < b in mod-space? Put another way, does the line
* from a to b cross c?
* is_between - is a < c < b, accounting for wrapping of a, b, and c
* positions in the buffer
*
* That is, if a<b, check for c between a and b
* and if a>b, check for c outside (not between) a and b
*
* |------- a xxxxxxxx b --------|
* c^
*
* |xxxxx b --------- a xxxxxxxxx|
* c^
* or c^
*/
static inline int clock_interval(size_t a, size_t b, size_t c)
static inline int is_between(size_t a, size_t b, size_t c)
{
if (b < a) {
if (a < c || b >= c)
if (a < b) {
/* is c between a and b? */
if (a < c && c <= b)
return 1;
} else {
if (a < c && b >= c)
/* is c outside of b through a? */
if (c <= b || a < c)
return 1;
}
@ -260,14 +281,14 @@ static inline int clock_interval(size_t a, size_t b, size_t c)
static void fix_up_readers(struct logger_log *log, size_t len)
{
size_t old = log->w_off;
size_t new = logger_offset(old + len);
size_t new = logger_offset(log, old + len);
struct logger_reader *reader;
if (clock_interval(old, new, log->head))
if (is_between(old, new, log->head))
log->head = get_next_entry(log, log->head, len);
list_for_each_entry(reader, &log->readers, list)
if (clock_interval(old, new, reader->r_off))
if (is_between(old, new, reader->r_off))
reader->r_off = get_next_entry(log, reader->r_off, len);
}
@ -286,7 +307,7 @@ static void do_write_log(struct logger_log *log, const void *buf, size_t count)
if (count != len)
memcpy(log->buffer, buf + len, count - len);
log->w_off = logger_offset(log->w_off + count);
log->w_off = logger_offset(log, log->w_off + count);
}
@ -309,9 +330,15 @@ static ssize_t do_write_log_from_user(struct logger_log *log,
if (count != len)
if (copy_from_user(log->buffer, buf + len, count - len))
/*
* Note that by not updating w_off, this abandons the
* portion of the new entry that *was* successfully
* copied, just above. This is intentional to avoid
* message corruption from missing fragments.
*/
return -EFAULT;
log->w_off = logger_offset(log->w_off + count);
log->w_off = logger_offset(log, log->w_off + count);
return count;
}
@ -432,7 +459,12 @@ static int logger_release(struct inode *ignored, struct file *file)
{
if (file->f_mode & FMODE_READ) {
struct logger_reader *reader = file->private_data;
struct logger_log *log = reader->log;
mutex_lock(&log->mutex);
list_del(&reader->list);
mutex_unlock(&log->mutex);
kfree(reader);
}

View File

@ -1,16 +1,17 @@
/* drivers/misc/lowmemorykiller.c
*
* The lowmemorykiller driver lets user-space specify a set of memory thresholds
* where processes with a range of oom_adj values will get killed. Specify the
* minimum oom_adj values in /sys/module/lowmemorykiller/parameters/adj and the
* number of free pages in /sys/module/lowmemorykiller/parameters/minfree. Both
* files take a comma separated list of numbers in ascending order.
* where processes with a range of oom_score_adj values will get killed. Specify
* the minimum oom_score_adj values in
* /sys/module/lowmemorykiller/parameters/adj and the number of free pages in
* /sys/module/lowmemorykiller/parameters/minfree. Both files take a comma
* separated list of numbers in ascending order.
*
* For example, write "0,8" to /sys/module/lowmemorykiller/parameters/adj and
* "1024,4096" to /sys/module/lowmemorykiller/parameters/minfree to kill
* processes with a oom_adj value of 8 or higher when the free memory drops
* below 4096 pages and kill processes with a oom_adj value of 0 or higher
* when the free memory drops below 1024 pages.
* processes with a oom_score_adj value of 8 or higher when the free memory
* drops below 4096 pages and kill processes with a oom_score_adj value of 0 or
* higher when the free memory drops below 1024 pages.
*
* The driver considers memory used for caches to be free, but if a large
* percentage of the cached memory is locked this can be very inaccurate
@ -34,6 +35,7 @@
#include <linux/mm.h>
#include <linux/oom.h>
#include <linux/sched.h>
#include <linux/rcupdate.h>
#include <linux/profile.h>
#include <linux/notifier.h>
@ -45,7 +47,7 @@ static int lowmem_adj[6] = {
12,
};
static int lowmem_adj_size = 4;
static size_t lowmem_minfree[6] = {
static int lowmem_minfree[6] = {
3 * 512, /* 6MB */
2 * 1024, /* 8MB */
4 * 1024, /* 16MB */
@ -73,23 +75,23 @@ static int
task_notify_func(struct notifier_block *self, unsigned long val, void *data)
{
struct task_struct *task = data;
if (task == lowmem_deathpending) {
if (task == lowmem_deathpending)
lowmem_deathpending = NULL;
task_handoff_unregister(&task_nb);
}
return NOTIFY_OK;
}
static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
{
struct task_struct *p;
struct task_struct *tsk;
struct task_struct *selected = NULL;
int rem = 0;
int tasksize;
int i;
int min_adj = OOM_ADJUST_MAX + 1;
int min_score_adj = OOM_SCORE_ADJ_MAX + 1;
int selected_tasksize = 0;
int selected_oom_adj;
int selected_oom_score_adj;
int array_size = ARRAY_SIZE(lowmem_adj);
int other_free = global_page_state(NR_FREE_PAGES);
int other_file = global_page_state(NR_FILE_PAGES) -
@ -115,80 +117,77 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
for (i = 0; i < array_size; i++) {
if (other_free < lowmem_minfree[i] &&
other_file < lowmem_minfree[i]) {
min_adj = lowmem_adj[i];
min_score_adj = lowmem_adj[i];
break;
}
}
if (sc->nr_to_scan > 0)
lowmem_print(3, "lowmem_shrink %lu, %x, ofree %d %d, ma %d\n",
sc->nr_to_scan, sc->gfp_mask, other_free,
other_file, min_adj);
other_file, min_score_adj);
rem = global_page_state(NR_ACTIVE_ANON) +
global_page_state(NR_ACTIVE_FILE) +
global_page_state(NR_INACTIVE_ANON) +
global_page_state(NR_INACTIVE_FILE);
if (sc->nr_to_scan <= 0 || min_adj == OOM_ADJUST_MAX + 1) {
if (sc->nr_to_scan <= 0 || min_score_adj == OOM_SCORE_ADJ_MAX + 1) {
lowmem_print(5, "lowmem_shrink %lu, %x, return %d\n",
sc->nr_to_scan, sc->gfp_mask, rem);
return rem;
}
selected_oom_adj = min_adj;
selected_oom_score_adj = min_score_adj;
read_lock(&tasklist_lock);
for_each_process(p) {
struct mm_struct *mm;
struct signal_struct *sig;
int oom_adj;
rcu_read_lock();
for_each_process(tsk) {
struct task_struct *p;
int oom_score_adj;
task_lock(p);
mm = p->mm;
sig = p->signal;
if (!mm || !sig) {
if (tsk->flags & PF_KTHREAD)
continue;
p = find_lock_task_mm(tsk);
if (!p)
continue;
oom_score_adj = p->signal->oom_score_adj;
if (oom_score_adj < min_score_adj) {
task_unlock(p);
continue;
}
oom_adj = sig->oom_adj;
if (oom_adj < min_adj) {
task_unlock(p);
continue;
}
tasksize = get_mm_rss(mm);
tasksize = get_mm_rss(p->mm);
task_unlock(p);
if (tasksize <= 0)
continue;
if (selected) {
if (oom_adj < selected_oom_adj)
if (oom_score_adj < selected_oom_score_adj)
continue;
if (oom_adj == selected_oom_adj &&
if (oom_score_adj == selected_oom_score_adj &&
tasksize <= selected_tasksize)
continue;
}
selected = p;
selected_tasksize = tasksize;
selected_oom_adj = oom_adj;
selected_oom_score_adj = oom_score_adj;
lowmem_print(2, "select %d (%s), adj %d, size %d, to kill\n",
p->pid, p->comm, oom_adj, tasksize);
p->pid, p->comm, oom_score_adj, tasksize);
}
if (selected) {
lowmem_print(1, "send sigkill to %d (%s), adj %d, size %d\n",
selected->pid, selected->comm,
selected_oom_adj, selected_tasksize);
selected_oom_score_adj, selected_tasksize);
/*
* If CONFIG_PROFILING is off, then task_handoff_register()
* is a nop. In that case we don't want to stall the killer
* by setting lowmem_deathpending.
* If CONFIG_PROFILING is off, then we don't want to stall
* the killer by setting lowmem_deathpending.
*/
#ifdef CONFIG_PROFILING
lowmem_deathpending = selected;
lowmem_deathpending_timeout = jiffies + HZ;
task_handoff_register(&task_nb);
#endif
force_sig(SIGKILL, selected);
send_sig(SIGKILL, selected, 0);
rem -= selected_tasksize;
}
lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n",
sc->nr_to_scan, sc->gfp_mask, rem);
read_unlock(&tasklist_lock);
rcu_read_unlock();
return rem;
}
@ -199,6 +198,7 @@ static struct shrinker lowmem_shrinker = {
static int __init lowmem_init(void)
{
task_handoff_register(&task_nb);
register_shrinker(&lowmem_shrinker);
return 0;
}
@ -206,6 +206,7 @@ static int __init lowmem_init(void)
static void __exit lowmem_exit(void)
{
unregister_shrinker(&lowmem_shrinker);
task_handoff_unregister(&task_nb);
}
module_param_named(cost, lowmem_shrinker.seeks, int, S_IRUGO | S_IWUSR);

View File

@ -0,0 +1,470 @@
/*
* Copyright (C) 2012 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/device.h>
#include <linux/err.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/io.h>
#include <linux/list.h>
#include <linux/memblock.h>
#include <linux/rslib.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include "persistent_ram.h"
struct persistent_ram_buffer {
uint32_t sig;
atomic_t start;
atomic_t size;
uint8_t data[0];
};
#define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */
static __initdata LIST_HEAD(persistent_ram_list);
static inline size_t buffer_size(struct persistent_ram_zone *prz)
{
return atomic_read(&prz->buffer->size);
}
static inline size_t buffer_start(struct persistent_ram_zone *prz)
{
return atomic_read(&prz->buffer->start);
}
/* increase and wrap the start pointer, returning the old value */
static inline size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a)
{
int old;
int new;
do {
old = atomic_read(&prz->buffer->start);
new = old + a;
while (unlikely(new > prz->buffer_size))
new -= prz->buffer_size;
} while (atomic_cmpxchg(&prz->buffer->start, old, new) != old);
return old;
}
/* increase the size counter until it hits the max size */
static inline void buffer_size_add(struct persistent_ram_zone *prz, size_t a)
{
size_t old;
size_t new;
if (atomic_read(&prz->buffer->size) == prz->buffer_size)
return;
do {
old = atomic_read(&prz->buffer->size);
new = old + a;
if (new > prz->buffer_size)
new = prz->buffer_size;
} while (atomic_cmpxchg(&prz->buffer->size, old, new) != old);
}
/* increase the size counter, retuning an error if it hits the max size */
static inline ssize_t buffer_size_add_clamp(struct persistent_ram_zone *prz,
size_t a)
{
size_t old;
size_t new;
do {
old = atomic_read(&prz->buffer->size);
new = old + a;
if (new > prz->buffer_size)
return -ENOMEM;
} while (atomic_cmpxchg(&prz->buffer->size, old, new) != old);
return 0;
}
static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz,
uint8_t *data, size_t len, uint8_t *ecc)
{
int i;
uint16_t par[prz->ecc_size];
/* Initialize the parity buffer */
memset(par, 0, sizeof(par));
encode_rs8(prz->rs_decoder, data, len, par, 0);
for (i = 0; i < prz->ecc_size; i++)
ecc[i] = par[i];
}
static int persistent_ram_decode_rs8(struct persistent_ram_zone *prz,
void *data, size_t len, uint8_t *ecc)
{
int i;
uint16_t par[prz->ecc_size];
for (i = 0; i < prz->ecc_size; i++)
par[i] = ecc[i];
return decode_rs8(prz->rs_decoder, data, par, len,
NULL, 0, NULL, 0, NULL);
}
static void notrace persistent_ram_update_ecc(struct persistent_ram_zone *prz,
unsigned int start, unsigned int count)
{
struct persistent_ram_buffer *buffer = prz->buffer;
uint8_t *buffer_end = buffer->data + prz->buffer_size;
uint8_t *block;
uint8_t *par;
int ecc_block_size = prz->ecc_block_size;
int ecc_size = prz->ecc_size;
int size = prz->ecc_block_size;
if (!prz->ecc)
return;
block = buffer->data + (start & ~(ecc_block_size - 1));
par = prz->par_buffer + (start / ecc_block_size) * prz->ecc_size;
do {
if (block + ecc_block_size > buffer_end)
size = buffer_end - block;
persistent_ram_encode_rs8(prz, block, size, par);
block += ecc_block_size;
par += ecc_size;
} while (block < buffer->data + start + count);
}
static void persistent_ram_update_header_ecc(struct persistent_ram_zone *prz)
{
struct persistent_ram_buffer *buffer = prz->buffer;
if (!prz->ecc)
return;
persistent_ram_encode_rs8(prz, (uint8_t *)buffer, sizeof(*buffer),
prz->par_header);
}
static void persistent_ram_ecc_old(struct persistent_ram_zone *prz)
{
struct persistent_ram_buffer *buffer = prz->buffer;
uint8_t *block;
uint8_t *par;
if (!prz->ecc)
return;
block = buffer->data;
par = prz->par_buffer;
while (block < buffer->data + buffer_size(prz)) {
int numerr;
int size = prz->ecc_block_size;
if (block + size > buffer->data + prz->buffer_size)
size = buffer->data + prz->buffer_size - block;
numerr = persistent_ram_decode_rs8(prz, block, size, par);
if (numerr > 0) {
pr_devel("persistent_ram: error in block %p, %d\n",
block, numerr);
prz->corrected_bytes += numerr;
} else if (numerr < 0) {
pr_devel("persistent_ram: uncorrectable error in block %p\n",
block);
prz->bad_blocks++;
}
block += prz->ecc_block_size;
par += prz->ecc_size;
}
}
static int persistent_ram_init_ecc(struct persistent_ram_zone *prz,
size_t buffer_size)
{
int numerr;
struct persistent_ram_buffer *buffer = prz->buffer;
int ecc_blocks;
if (!prz->ecc)
return 0;
prz->ecc_block_size = 128;
prz->ecc_size = 16;
prz->ecc_symsize = 8;
prz->ecc_poly = 0x11d;
ecc_blocks = DIV_ROUND_UP(prz->buffer_size, prz->ecc_block_size);
prz->buffer_size -= (ecc_blocks + 1) * prz->ecc_size;
if (prz->buffer_size > buffer_size) {
pr_err("persistent_ram: invalid size %zu, non-ecc datasize %zu\n",
buffer_size, prz->buffer_size);
return -EINVAL;
}
prz->par_buffer = buffer->data + prz->buffer_size;
prz->par_header = prz->par_buffer + ecc_blocks * prz->ecc_size;
/*
* first consecutive root is 0
* primitive element to generate roots = 1
*/
prz->rs_decoder = init_rs(prz->ecc_symsize, prz->ecc_poly, 0, 1,
prz->ecc_size);
if (prz->rs_decoder == NULL) {
pr_info("persistent_ram: init_rs failed\n");
return -EINVAL;
}
prz->corrected_bytes = 0;
prz->bad_blocks = 0;
numerr = persistent_ram_decode_rs8(prz, buffer, sizeof(*buffer),
prz->par_header);
if (numerr > 0) {
pr_info("persistent_ram: error in header, %d\n", numerr);
prz->corrected_bytes += numerr;
} else if (numerr < 0) {
pr_info("persistent_ram: uncorrectable error in header\n");
prz->bad_blocks++;
}
return 0;
}
ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
char *str, size_t len)
{
ssize_t ret;
if (prz->corrected_bytes || prz->bad_blocks)
ret = snprintf(str, len, ""
"\n%d Corrected bytes, %d unrecoverable blocks\n",
prz->corrected_bytes, prz->bad_blocks);
else
ret = snprintf(str, len, "\nNo errors detected\n");
return ret;
}
static void notrace persistent_ram_update(struct persistent_ram_zone *prz,
const void *s, unsigned int start, unsigned int count)
{
struct persistent_ram_buffer *buffer = prz->buffer;
memcpy(buffer->data + start, s, count);
persistent_ram_update_ecc(prz, start, count);
}
static void __init
persistent_ram_save_old(struct persistent_ram_zone *prz)
{
struct persistent_ram_buffer *buffer = prz->buffer;
size_t size = buffer_size(prz);
size_t start = buffer_start(prz);
char *dest;
persistent_ram_ecc_old(prz);
dest = kmalloc(size, GFP_KERNEL);
if (dest == NULL) {
pr_err("persistent_ram: failed to allocate buffer\n");
return;
}
prz->old_log = dest;
prz->old_log_size = size;
memcpy(prz->old_log, &buffer->data[start], size - start);
memcpy(prz->old_log + size - start, &buffer->data[0], start);
}
int notrace persistent_ram_write(struct persistent_ram_zone *prz,
const void *s, unsigned int count)
{
int rem;
int c = count;
size_t start;
if (unlikely(c > prz->buffer_size)) {
s += c - prz->buffer_size;
c = prz->buffer_size;
}
buffer_size_add_clamp(prz, c);
start = buffer_start_add(prz, c);
rem = prz->buffer_size - start;
if (unlikely(rem < c)) {
persistent_ram_update(prz, s, start, rem);
s += rem;
c -= rem;
start = 0;
}
persistent_ram_update(prz, s, start, c);
persistent_ram_update_header_ecc(prz);
return count;
}
size_t persistent_ram_old_size(struct persistent_ram_zone *prz)
{
return prz->old_log_size;
}
void *persistent_ram_old(struct persistent_ram_zone *prz)
{
return prz->old_log;
}
void persistent_ram_free_old(struct persistent_ram_zone *prz)
{
kfree(prz->old_log);
prz->old_log = NULL;
prz->old_log_size = 0;
}
static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
struct persistent_ram_zone *prz)
{
struct page **pages;
phys_addr_t page_start;
unsigned int page_count;
pgprot_t prot;
unsigned int i;
page_start = start - offset_in_page(start);
page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE);
prot = pgprot_noncached(PAGE_KERNEL);
pages = kmalloc(sizeof(struct page *) * page_count, GFP_KERNEL);
if (!pages) {
pr_err("%s: Failed to allocate array for %u pages\n", __func__,
page_count);
return -ENOMEM;
}
for (i = 0; i < page_count; i++) {
phys_addr_t addr = page_start + i * PAGE_SIZE;
pages[i] = pfn_to_page(addr >> PAGE_SHIFT);
}
prz->vaddr = vmap(pages, page_count, VM_MAP, prot);
kfree(pages);
if (!prz->vaddr) {
pr_err("%s: Failed to map %u pages\n", __func__, page_count);
return -ENOMEM;
}
prz->buffer = prz->vaddr + offset_in_page(start);
prz->buffer_size = size - sizeof(struct persistent_ram_buffer);
return 0;
}
static int __init persistent_ram_buffer_init(const char *name,
struct persistent_ram_zone *prz)
{
int i;
struct persistent_ram *ram;
struct persistent_ram_descriptor *desc;
phys_addr_t start;
list_for_each_entry(ram, &persistent_ram_list, node) {
start = ram->start;
for (i = 0; i < ram->num_descs; i++) {
desc = &ram->descs[i];
if (!strcmp(desc->name, name))
return persistent_ram_buffer_map(start,
desc->size, prz);
start += desc->size;
}
}
return -EINVAL;
}
static __init
struct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc)
{
struct persistent_ram_zone *prz;
int ret;
prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL);
if (!prz) {
pr_err("persistent_ram: failed to allocate persistent ram zone\n");
return ERR_PTR(-ENOMEM);
}
INIT_LIST_HEAD(&prz->node);
ret = persistent_ram_buffer_init(dev_name(dev), prz);
if (ret) {
pr_err("persistent_ram: failed to initialize buffer\n");
return ERR_PTR(ret);
}
prz->ecc = ecc;
ret = persistent_ram_init_ecc(prz, prz->buffer_size);
if (ret)
return ERR_PTR(ret);
if (prz->buffer->sig == PERSISTENT_RAM_SIG) {
if (buffer_size(prz) > prz->buffer_size ||
buffer_start(prz) > buffer_size(prz))
pr_info("persistent_ram: found existing invalid buffer,"
" size %ld, start %ld\n",
buffer_size(prz), buffer_start(prz));
else {
pr_info("persistent_ram: found existing buffer,"
" size %ld, start %ld\n",
buffer_size(prz), buffer_start(prz));
persistent_ram_save_old(prz);
}
} else {
pr_info("persistent_ram: no valid data in buffer"
" (sig = 0x%08x)\n", prz->buffer->sig);
}
prz->buffer->sig = PERSISTENT_RAM_SIG;
atomic_set(&prz->buffer->start, 0);
atomic_set(&prz->buffer->size, 0);
return prz;
}
struct persistent_ram_zone * __init
persistent_ram_init_ringbuffer(struct device *dev, bool ecc)
{
return __persistent_ram_init(dev, ecc);
}
int __init persistent_ram_early_init(struct persistent_ram *ram)
{
int ret;
ret = memblock_reserve(ram->start, ram->size);
if (ret) {
pr_err("Failed to reserve persistent memory from %08lx-%08lx\n",
(long)ram->start, (long)(ram->start + ram->size - 1));
return ret;
}
list_add_tail(&ram->node, &persistent_ram_list);
pr_info("Initialized persistent memory from %08lx-%08lx\n",
(long)ram->start, (long)(ram->start + ram->size - 1));
return 0;
}

View File

@ -0,0 +1,78 @@
/*
* Copyright (C) 2011 Google, Inc.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef __LINUX_PERSISTENT_RAM_H__
#define __LINUX_PERSISTENT_RAM_H__
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/types.h>
struct persistent_ram_buffer;
struct persistent_ram_descriptor {
const char *name;
phys_addr_t size;
};
struct persistent_ram {
phys_addr_t start;
phys_addr_t size;
int num_descs;
struct persistent_ram_descriptor *descs;
struct list_head node;
};
struct persistent_ram_zone {
struct list_head node;
void *vaddr;
struct persistent_ram_buffer *buffer;
size_t buffer_size;
/* ECC correction */
bool ecc;
char *par_buffer;
char *par_header;
struct rs_control *rs_decoder;
int corrected_bytes;
int bad_blocks;
int ecc_block_size;
int ecc_size;
int ecc_symsize;
int ecc_poly;
char *old_log;
size_t old_log_size;
size_t old_log_footer_size;
bool early;
};
int persistent_ram_early_init(struct persistent_ram *ram);
struct persistent_ram_zone *persistent_ram_init_ringbuffer(struct device *dev,
bool ecc);
int persistent_ram_write(struct persistent_ram_zone *prz, const void *s,
unsigned int count);
size_t persistent_ram_old_size(struct persistent_ram_zone *prz);
void *persistent_ram_old(struct persistent_ram_zone *prz);
void persistent_ram_free_old(struct persistent_ram_zone *prz);
ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
char *str, size_t len);
#endif

View File

@ -21,129 +21,24 @@
#include <linux/string.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include "persistent_ram.h"
#include "ram_console.h"
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
#include <linux/rslib.h>
#endif
struct ram_console_buffer {
uint32_t sig;
uint32_t start;
uint32_t size;
uint8_t data[0];
};
#define RAM_CONSOLE_SIG (0x43474244) /* DBGC */
#ifdef CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT
static char __initdata
ram_console_old_log_init_buffer[CONFIG_ANDROID_RAM_CONSOLE_EARLY_SIZE];
#endif
static char *ram_console_old_log;
static size_t ram_console_old_log_size;
static struct ram_console_buffer *ram_console_buffer;
static size_t ram_console_buffer_size;
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
static char *ram_console_par_buffer;
static struct rs_control *ram_console_rs_decoder;
static int ram_console_corrected_bytes;
static int ram_console_bad_blocks;
#define ECC_BLOCK_SIZE CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_DATA_SIZE
#define ECC_SIZE CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_ECC_SIZE
#define ECC_SYMSIZE CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_SYMBOL_SIZE
#define ECC_POLY CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION_POLYNOMIAL
#endif
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
static void ram_console_encode_rs8(uint8_t *data, size_t len, uint8_t *ecc)
{
int i;
uint16_t par[ECC_SIZE];
/* Initialize the parity buffer */
memset(par, 0, sizeof(par));
encode_rs8(ram_console_rs_decoder, data, len, par, 0);
for (i = 0; i < ECC_SIZE; i++)
ecc[i] = par[i];
}
static int ram_console_decode_rs8(void *data, size_t len, uint8_t *ecc)
{
int i;
uint16_t par[ECC_SIZE];
for (i = 0; i < ECC_SIZE; i++)
par[i] = ecc[i];
return decode_rs8(ram_console_rs_decoder, data, par, len,
NULL, 0, NULL, 0, NULL);
}
#endif
static void ram_console_update(const char *s, unsigned int count)
{
struct ram_console_buffer *buffer = ram_console_buffer;
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
uint8_t *buffer_end = buffer->data + ram_console_buffer_size;
uint8_t *block;
uint8_t *par;
int size = ECC_BLOCK_SIZE;
#endif
memcpy(buffer->data + buffer->start, s, count);
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
block = buffer->data + (buffer->start & ~(ECC_BLOCK_SIZE - 1));
par = ram_console_par_buffer +
(buffer->start / ECC_BLOCK_SIZE) * ECC_SIZE;
do {
if (block + ECC_BLOCK_SIZE > buffer_end)
size = buffer_end - block;
ram_console_encode_rs8(block, size, par);
block += ECC_BLOCK_SIZE;
par += ECC_SIZE;
} while (block < buffer->data + buffer->start + count);
#endif
}
static void ram_console_update_header(void)
{
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
struct ram_console_buffer *buffer = ram_console_buffer;
uint8_t *par;
par = ram_console_par_buffer +
DIV_ROUND_UP(ram_console_buffer_size, ECC_BLOCK_SIZE) * ECC_SIZE;
ram_console_encode_rs8((uint8_t *)buffer, sizeof(*buffer), par);
#endif
}
static struct persistent_ram_zone *ram_console_zone;
static const char *bootinfo;
static size_t bootinfo_size;
static void
ram_console_write(struct console *console, const char *s, unsigned int count)
{
int rem;
struct ram_console_buffer *buffer = ram_console_buffer;
if (count > ram_console_buffer_size) {
s += count - ram_console_buffer_size;
count = ram_console_buffer_size;
}
rem = ram_console_buffer_size - buffer->start;
if (rem < count) {
ram_console_update(s, rem);
s += rem;
count -= rem;
buffer->start = 0;
buffer->size = ram_console_buffer_size;
}
ram_console_update(s, count);
buffer->start += count;
if (buffer->size < ram_console_buffer_size)
buffer->size += count;
ram_console_update_header();
struct persistent_ram_zone *prz = console->data;
persistent_ram_write(prz, s, count);
}
static struct console ram_console = {
.name = "ram",
.write = ram_console_write,
.flags = CON_PRINTBUFFER | CON_ENABLED,
.flags = CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME,
.index = -1,
};
@ -155,220 +50,31 @@ void ram_console_enable_console(int enabled)
ram_console.flags &= ~CON_ENABLED;
}
static void __init
ram_console_save_old(struct ram_console_buffer *buffer, const char *bootinfo,
char *dest)
static int __init ram_console_probe(struct platform_device *pdev)
{
size_t old_log_size = buffer->size;
size_t bootinfo_size = 0;
size_t total_size = old_log_size;
char *ptr;
const char *bootinfo_label = "Boot info:\n";
struct ram_console_platform_data *pdata = pdev->dev.platform_data;
struct persistent_ram_zone *prz;
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
uint8_t *block;
uint8_t *par;
char strbuf[80];
int strbuf_len = 0;
prz = persistent_ram_init_ringbuffer(&pdev->dev, true);
if (IS_ERR(prz))
return PTR_ERR(prz);
block = buffer->data;
par = ram_console_par_buffer;
while (block < buffer->data + buffer->size) {
int numerr;
int size = ECC_BLOCK_SIZE;
if (block + size > buffer->data + ram_console_buffer_size)
size = buffer->data + ram_console_buffer_size - block;
numerr = ram_console_decode_rs8(block, size, par);
if (numerr > 0) {
#if 0
printk(KERN_INFO "ram_console: error in block %p, %d\n",
block, numerr);
#endif
ram_console_corrected_bytes += numerr;
} else if (numerr < 0) {
#if 0
printk(KERN_INFO "ram_console: uncorrectable error in "
"block %p\n", block);
#endif
ram_console_bad_blocks++;
}
block += ECC_BLOCK_SIZE;
par += ECC_SIZE;
}
if (ram_console_corrected_bytes || ram_console_bad_blocks)
strbuf_len = snprintf(strbuf, sizeof(strbuf),
"\n%d Corrected bytes, %d unrecoverable blocks\n",
ram_console_corrected_bytes, ram_console_bad_blocks);
else
strbuf_len = snprintf(strbuf, sizeof(strbuf),
"\nNo errors detected\n");
if (strbuf_len >= sizeof(strbuf))
strbuf_len = sizeof(strbuf) - 1;
total_size += strbuf_len;
#endif
if (bootinfo)
bootinfo_size = strlen(bootinfo) + strlen(bootinfo_label);
total_size += bootinfo_size;
if (dest == NULL) {
dest = kmalloc(total_size, GFP_KERNEL);
if (dest == NULL) {
printk(KERN_ERR
"ram_console: failed to allocate buffer\n");
return;
}
if (pdata) {
bootinfo = kstrdup(pdata->bootinfo, GFP_KERNEL);
if (bootinfo)
bootinfo_size = strlen(bootinfo);
}
ram_console_old_log = dest;
ram_console_old_log_size = total_size;
memcpy(ram_console_old_log,
&buffer->data[buffer->start], buffer->size - buffer->start);
memcpy(ram_console_old_log + buffer->size - buffer->start,
&buffer->data[0], buffer->start);
ptr = ram_console_old_log + old_log_size;
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
memcpy(ptr, strbuf, strbuf_len);
ptr += strbuf_len;
#endif
if (bootinfo) {
memcpy(ptr, bootinfo_label, strlen(bootinfo_label));
ptr += strlen(bootinfo_label);
memcpy(ptr, bootinfo, bootinfo_size);
ptr += bootinfo_size;
}
}
static int __init ram_console_init(struct ram_console_buffer *buffer,
size_t buffer_size, const char *bootinfo,
char *old_buf)
{
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
int numerr;
uint8_t *par;
#endif
ram_console_buffer = buffer;
ram_console_buffer_size =
buffer_size - sizeof(struct ram_console_buffer);
if (ram_console_buffer_size > buffer_size) {
pr_err("ram_console: buffer %p, invalid size %zu, "
"datasize %zu\n", buffer, buffer_size,
ram_console_buffer_size);
return 0;
}
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ERROR_CORRECTION
ram_console_buffer_size -= (DIV_ROUND_UP(ram_console_buffer_size,
ECC_BLOCK_SIZE) + 1) * ECC_SIZE;
if (ram_console_buffer_size > buffer_size) {
pr_err("ram_console: buffer %p, invalid size %zu, "
"non-ecc datasize %zu\n",
buffer, buffer_size, ram_console_buffer_size);
return 0;
}
ram_console_par_buffer = buffer->data + ram_console_buffer_size;
/* first consecutive root is 0
* primitive element to generate roots = 1
*/
ram_console_rs_decoder = init_rs(ECC_SYMSIZE, ECC_POLY, 0, 1, ECC_SIZE);
if (ram_console_rs_decoder == NULL) {
printk(KERN_INFO "ram_console: init_rs failed\n");
return 0;
}
ram_console_corrected_bytes = 0;
ram_console_bad_blocks = 0;
par = ram_console_par_buffer +
DIV_ROUND_UP(ram_console_buffer_size, ECC_BLOCK_SIZE) * ECC_SIZE;
numerr = ram_console_decode_rs8(buffer, sizeof(*buffer), par);
if (numerr > 0) {
printk(KERN_INFO "ram_console: error in header, %d\n", numerr);
ram_console_corrected_bytes += numerr;
} else if (numerr < 0) {
printk(KERN_INFO
"ram_console: uncorrectable error in header\n");
ram_console_bad_blocks++;
}
#endif
if (buffer->sig == RAM_CONSOLE_SIG) {
if (buffer->size > ram_console_buffer_size
|| buffer->start > buffer->size)
printk(KERN_INFO "ram_console: found existing invalid "
"buffer, size %d, start %d\n",
buffer->size, buffer->start);
else {
printk(KERN_INFO "ram_console: found existing buffer, "
"size %d, start %d\n",
buffer->size, buffer->start);
ram_console_save_old(buffer, bootinfo, old_buf);
}
} else {
printk(KERN_INFO "ram_console: no valid data in buffer "
"(sig = 0x%08x)\n", buffer->sig);
}
buffer->sig = RAM_CONSOLE_SIG;
buffer->start = 0;
buffer->size = 0;
ram_console_zone = prz;
ram_console.data = prz;
register_console(&ram_console);
#ifdef CONFIG_ANDROID_RAM_CONSOLE_ENABLE_VERBOSE
console_verbose();
#endif
return 0;
}
#ifdef CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT
static int __init ram_console_early_init(void)
{
return ram_console_init((struct ram_console_buffer *)
CONFIG_ANDROID_RAM_CONSOLE_EARLY_ADDR,
CONFIG_ANDROID_RAM_CONSOLE_EARLY_SIZE,
NULL,
ram_console_old_log_init_buffer);
}
#else
static int ram_console_driver_probe(struct platform_device *pdev)
{
struct resource *res = pdev->resource;
size_t start;
size_t buffer_size;
void *buffer;
const char *bootinfo = NULL;
struct ram_console_platform_data *pdata = pdev->dev.platform_data;
if (res == NULL || pdev->num_resources != 1 ||
!(res->flags & IORESOURCE_MEM)) {
printk(KERN_ERR "ram_console: invalid resource, %p %d flags "
"%lx\n", res, pdev->num_resources, res ? res->flags : 0);
return -ENXIO;
}
buffer_size = res->end - res->start + 1;
start = res->start;
printk(KERN_INFO "ram_console: got buffer at %zx, size %zx\n",
start, buffer_size);
buffer = ioremap(res->start, buffer_size);
if (buffer == NULL) {
printk(KERN_ERR "ram_console: failed to map memory\n");
return -ENOMEM;
}
if (pdata)
bootinfo = pdata->bootinfo;
return ram_console_init(buffer, buffer_size, bootinfo, NULL/* allocate */);
}
static struct platform_driver ram_console_driver = {
.probe = ram_console_driver_probe,
.driver = {
.name = "ram_console",
},
@ -376,10 +82,11 @@ static struct platform_driver ram_console_driver = {
static int __init ram_console_module_init(void)
{
int err;
err = platform_driver_register(&ram_console_driver);
return err;
return platform_driver_probe(&ram_console_driver, ram_console_probe);
}
#ifndef CONFIG_PRINTK
#define dmesg_restrict 0
#endif
static ssize_t ram_console_read_old(struct file *file, char __user *buf,
@ -387,14 +94,52 @@ static ssize_t ram_console_read_old(struct file *file, char __user *buf,
{
loff_t pos = *offset;
ssize_t count;
struct persistent_ram_zone *prz = ram_console_zone;
size_t old_log_size = persistent_ram_old_size(prz);
const char *old_log = persistent_ram_old(prz);
char *str;
int ret;
if (pos >= ram_console_old_log_size)
return 0;
if (dmesg_restrict && !capable(CAP_SYSLOG))
return -EPERM;
count = min(len, (size_t)(ram_console_old_log_size - pos));
if (copy_to_user(buf, ram_console_old_log + pos, count))
return -EFAULT;
/* Main last_kmsg log */
if (pos < old_log_size) {
count = min(len, (size_t)(old_log_size - pos));
if (copy_to_user(buf, old_log + pos, count))
return -EFAULT;
goto out;
}
/* ECC correction notice */
pos -= old_log_size;
count = persistent_ram_ecc_string(prz, NULL, 0);
if (pos < count) {
str = kmalloc(count, GFP_KERNEL);
if (!str)
return -ENOMEM;
persistent_ram_ecc_string(prz, str, count + 1);
count = min(len, (size_t)(count - pos));
ret = copy_to_user(buf, str + pos, count);
kfree(str);
if (ret)
return -EFAULT;
goto out;
}
/* Boot info passed through pdata */
pos -= count;
if (pos < bootinfo_size) {
count = min(len, (size_t)(bootinfo_size - pos));
if (copy_to_user(buf, bootinfo + pos, count))
return -EFAULT;
goto out;
}
/* EOF */
return 0;
out:
*offset += count;
return count;
}
@ -407,37 +152,28 @@ static const struct file_operations ram_console_file_ops = {
static int __init ram_console_late_init(void)
{
struct proc_dir_entry *entry;
struct persistent_ram_zone *prz = ram_console_zone;
if (ram_console_old_log == NULL)
if (!prz)
return 0;
#ifdef CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT
ram_console_old_log = kmalloc(ram_console_old_log_size, GFP_KERNEL);
if (ram_console_old_log == NULL) {
printk(KERN_ERR
"ram_console: failed to allocate buffer for old log\n");
ram_console_old_log_size = 0;
if (persistent_ram_old_size(prz) == 0)
return 0;
}
memcpy(ram_console_old_log,
ram_console_old_log_init_buffer, ram_console_old_log_size);
#endif
entry = create_proc_entry("last_kmsg", S_IFREG | S_IRUGO, NULL);
if (!entry) {
printk(KERN_ERR "ram_console: failed to create proc entry\n");
kfree(ram_console_old_log);
ram_console_old_log = NULL;
persistent_ram_free_old(prz);
return 0;
}
entry->proc_fops = &ram_console_file_ops;
entry->size = ram_console_old_log_size;
entry->size = persistent_ram_old_size(prz) +
persistent_ram_ecc_string(prz, NULL, 0) +
bootinfo_size;
return 0;
}
#ifdef CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT
console_initcall(ram_console_early_init);
#else
postcore_initcall(ram_console_module_init);
#endif
late_initcall(ram_console_late_init);
postcore_initcall(ram_console_module_init);

View File

@ -29,9 +29,9 @@ struct timed_gpio_data {
struct timed_output_dev dev;
struct hrtimer timer;
spinlock_t lock;
unsigned gpio;
int max_timeout;
u8 active_low;
unsigned gpio;
int max_timeout;
u8 active_low;
};
static enum hrtimer_restart gpio_timer_func(struct hrtimer *timer)

View File

@ -20,13 +20,13 @@
struct timed_gpio {
const char *name;
unsigned gpio;
unsigned gpio;
int max_timeout;
u8 active_low;
u8 active_low;
};
struct timed_gpio_platform_data {
int num_gpios;
int num_gpios;
struct timed_gpio *gpios;
};

View File

@ -159,7 +159,6 @@ static void setup_packet_header(struct asus_oled_packet *packet, char flags,
static void enable_oled(struct asus_oled_dev *odev, uint8_t enabl)
{
int a;
int retval;
int act_len;
struct asus_oled_packet *packet;
@ -178,17 +177,15 @@ static void enable_oled(struct asus_oled_dev *odev, uint8_t enabl)
else
packet->bitmap[0] = 0xae;
for (a = 0; a < 1; a++) {
retval = usb_bulk_msg(odev->udev,
usb_sndbulkpipe(odev->udev, 2),
packet,
sizeof(struct asus_oled_header) + 1,
&act_len,
-1);
retval = usb_bulk_msg(odev->udev,
usb_sndbulkpipe(odev->udev, 2),
packet,
sizeof(struct asus_oled_header) + 1,
&act_len,
-1);
if (retval)
dev_dbg(&odev->udev->dev, "retval = %d\n", retval);
}
if (retval)
dev_dbg(&odev->udev->dev, "retval = %d\n", retval);
odev->enabled = enabl;

View File

@ -728,14 +728,10 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
if (IoBuffer.InputLength > MAX_CNTL_PKT_SIZE)
return -EINVAL;
pvBuffer = kmalloc(IoBuffer.InputLength, GFP_KERNEL);
if (!pvBuffer)
return -ENOMEM;
if (copy_from_user(pvBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength)) {
kfree(pvBuffer);
return -EFAULT;
}
pvBuffer = memdup_user(IoBuffer.InputBuffer,
IoBuffer.InputLength);
if (IS_ERR(pvBuffer))
return PTR_ERR(pvBuffer);
down(&Adapter->LowPowerModeSync);
Status = wait_event_interruptible_timeout(Adapter->lowpower_mode_wait_queue,
@ -1140,15 +1136,10 @@ cntrlEnd:
if (IoBuffer.InputLength < sizeof(ULONG) * 2)
return -EINVAL;
pvBuffer = kmalloc(IoBuffer.InputLength, GFP_KERNEL);
if (!pvBuffer)
return -ENOMEM;
/* Get WrmBuffer structure */
if (copy_from_user(pvBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength)) {
kfree(pvBuffer);
return -EFAULT;
}
pvBuffer = memdup_user(IoBuffer.InputBuffer,
IoBuffer.InputLength);
if (IS_ERR(pvBuffer))
return PTR_ERR(pvBuffer);
pBulkBuffer = (PBULKWRM_BUFFER)pvBuffer;
@ -1302,20 +1293,18 @@ cntrlEnd:
/*
* Deny the access if the offset crosses the cal area limit.
*/
if (stNVMReadWrite.uiNumBytes > Adapter->uiNVMDSDSize)
return STATUS_FAILURE;
if ((stNVMReadWrite.uiOffset + stNVMReadWrite.uiNumBytes) > Adapter->uiNVMDSDSize) {
if (stNVMReadWrite.uiOffset > Adapter->uiNVMDSDSize - stNVMReadWrite.uiNumBytes) {
/* BCM_DEBUG_PRINT(Adapter,DBG_TYPE_PRINTK, 0, 0,"Can't allow access beyond NVM Size: 0x%x 0x%x\n", stNVMReadWrite.uiOffset, stNVMReadWrite.uiNumBytes); */
return STATUS_FAILURE;
}
pReadData = kzalloc(stNVMReadWrite.uiNumBytes, GFP_KERNEL);
if (!pReadData)
return -ENOMEM;
if (copy_from_user(pReadData, stNVMReadWrite.pBuffer, stNVMReadWrite.uiNumBytes)) {
kfree(pReadData);
return -EFAULT;
}
pReadData = memdup_user(stNVMReadWrite.pBuffer,
stNVMReadWrite.uiNumBytes);
if (IS_ERR(pReadData))
return PTR_ERR(pReadData);
do_gettimeofday(&tv0);
if (IOCTL_BCM_NVM_READ == cmd) {

File diff suppressed because it is too large Load Diff

View File

@ -4,11 +4,11 @@
/*************************TYPE DEF**********************/
#define NUM_OF_LEDS 4
#define DSD_START_OFFSET 0x0200
#define EEPROM_VERSION_OFFSET 0x020E
#define EEPROM_HW_PARAM_POINTER_ADDRESS 0x0218
#define EEPROM_HW_PARAM_POINTER_ADDRRES_MAP5 0x0220
#define GPIO_SECTION_START_OFFSET 0x03
#define DSD_START_OFFSET 0x0200
#define EEPROM_VERSION_OFFSET 0x020E
#define EEPROM_HW_PARAM_POINTER_ADDRESS 0x0218
#define EEPROM_HW_PARAM_POINTER_ADDRRES_MAP5 0x0220
#define GPIO_SECTION_START_OFFSET 0x03
#define COMPATIBILITY_SECTION_LENGTH 42
#define COMPATIBILITY_SECTION_LENGTH_MAP5 84
@ -18,27 +18,27 @@
#define EEPROM_MAP5_MINORVERSION 0
#define MAX_NUM_OF_BLINKS 10
#define NUM_OF_GPIO_PINS 16
#define MAX_NUM_OF_BLINKS 10
#define NUM_OF_GPIO_PINS 16
#define DISABLE_GPIO_NUM 0xFF
#define EVENT_SIGNALED 1
#define DISABLE_GPIO_NUM 0xFF
#define EVENT_SIGNALED 1
#define MAX_FILE_NAME_BUFFER_SIZE 100
#define MAX_FILE_NAME_BUFFER_SIZE 100
#define TURN_ON_LED(GPIO, index) do{ \
#define TURN_ON_LED(GPIO, index) do { \
UINT gpio_val = GPIO; \
(Adapter->LEDInfo.LEDState[index].BitPolarity == 1) ? \
wrmaltWithLock(Adapter,BCM_GPIO_OUTPUT_SET_REG, &gpio_val ,sizeof(gpio_val)) : \
wrmaltWithLock(Adapter,BCM_GPIO_OUTPUT_CLR_REG, &gpio_val, sizeof(gpio_val)); \
}while(0);
wrmaltWithLock(Adapter, BCM_GPIO_OUTPUT_SET_REG, &gpio_val, sizeof(gpio_val)) : \
wrmaltWithLock(Adapter, BCM_GPIO_OUTPUT_CLR_REG, &gpio_val, sizeof(gpio_val)); \
} while (0);
#define TURN_OFF_LED(GPIO, index) do { \
UINT gpio_val = GPIO; \
(Adapter->LEDInfo.LEDState[index].BitPolarity == 1) ? \
wrmaltWithLock(Adapter,BCM_GPIO_OUTPUT_CLR_REG,&gpio_val ,sizeof(gpio_val)) : \
wrmaltWithLock(Adapter,BCM_GPIO_OUTPUT_SET_REG,&gpio_val ,sizeof(gpio_val)); \
}while(0);
wrmaltWithLock(Adapter, BCM_GPIO_OUTPUT_CLR_REG, &gpio_val, sizeof(gpio_val)) : \
wrmaltWithLock(Adapter, BCM_GPIO_OUTPUT_SET_REG, &gpio_val, sizeof(gpio_val)); \
} while (0);
#define B_ULONG32 unsigned long
@ -50,7 +50,7 @@ typedef enum _LEDColors{
BLUE_LED = 2,
YELLOW_LED = 3,
GREEN_LED = 4
} LEDColors; /*Enumerated values of different LED types*/
} LEDColors; /*Enumerated values of different LED types*/
typedef enum LedEvents {
SHUTDOWN_EXIT = 0x00,
@ -62,43 +62,39 @@ typedef enum LedEvents {
LOWPOWER_MODE_ENTER = 0x20,
IDLEMODE_CONTINUE = 0x40,
IDLEMODE_EXIT = 0x80,
LED_THREAD_INACTIVE = 0x100, //Makes the LED thread Inactivce. It wil be equivallent to putting the thread on hold.
LED_THREAD_ACTIVE = 0x200 //Makes the LED Thread Active back.
} LedEventInfo_t; /*Enumerated values of different driver states*/
LED_THREAD_INACTIVE = 0x100, /* Makes the LED thread Inactivce. It wil be equivallent to putting the thread on hold. */
LED_THREAD_ACTIVE = 0x200, /* Makes the LED Thread Active back. */
DRIVER_HALT = 0xff
} LedEventInfo_t; /* Enumerated values of different driver states */
#define DRIVER_HALT 0xff
/*Structure which stores the information of different LED types
* and corresponding LED state information of driver states*/
typedef struct LedStateInfo_t
{
/*
* Structure which stores the information of different LED types
* and corresponding LED state information of driver states
*/
typedef struct LedStateInfo_t {
UCHAR LED_Type; /* specify GPIO number - use 0xFF if not used */
UCHAR LED_On_State; /* Bits set or reset for different states */
UCHAR LED_Blink_State; /* Bits set or reset for blinking LEDs for different states */
UCHAR GPIO_Num;
UCHAR BitPolarity; /*To represent whether H/W is normal polarity or reverse
polarity*/
}LEDStateInfo, *pLEDStateInfo;
UCHAR BitPolarity; /* To represent whether H/W is normal polarity or reverse polarity */
} LEDStateInfo, *pLEDStateInfo;
typedef struct _LED_INFO_STRUCT
{
typedef struct _LED_INFO_STRUCT {
LEDStateInfo LEDState[NUM_OF_LEDS];
BOOLEAN bIdleMode_tx_from_host; /*Variable to notify whether driver came out
from idlemode due to Host or target*/
BOOLEAN bIdleMode_tx_from_host; /* Variable to notify whether driver came out from idlemode due to Host or target*/
BOOLEAN bIdle_led_off;
wait_queue_head_t notify_led_event;
wait_queue_head_t idleModeSyncEvent;
struct task_struct *led_cntrl_threadid;
int led_thread_running;
struct task_struct *led_cntrl_threadid;
int led_thread_running;
BOOLEAN bLedInitDone;
} LED_INFO_STRUCT, *PLED_INFO_STRUCT;
//LED Thread state.
#define BCM_LED_THREAD_DISABLED 0 //LED Thread is not running.
#define BCM_LED_THREAD_RUNNING_ACTIVELY 1 //LED thread is running.
#define BCM_LED_THREAD_RUNNING_INACTIVELY 2 //LED thread has been put on hold
/* LED Thread state. */
#define BCM_LED_THREAD_DISABLED 0 /* LED Thread is not running. */
#define BCM_LED_THREAD_RUNNING_ACTIVELY 1 /* LED thread is running. */
#define BCM_LED_THREAD_RUNNING_INACTIVELY 2 /*LED thread has been put on hold*/

View File

@ -765,8 +765,9 @@ config COMEDI_ADV_PCI_DIO
default N
---help---
Enable support for Advantech PCI DIO cards
PCI-1730, PCI-1733, PCI-1734, PCI-1736UP, PCI-1750, PCI-1751,
PCI-1752, PCI-1753/E, PCI-1754, PCI-1756 and PCI-1762
PCI-1730, PCI-1733, PCI-1734, PCI-1735U, PCI-1736UP, PCI-1739U,
PCI-1750, PCI-1751, PCI-1752, PCI-1753/E, PCI-1754, PCI-1756,
PCI-1760 and PCI-1762
To compile this driver as a module, choose M here: the module will be
called adv_pci_dio.

View File

@ -8,16 +8,16 @@
/*
Driver: adv_pci_dio
Description: Advantech PCI-1730, PCI-1733, PCI-1734, PCI-1735U,
PCI-1736UP, PCI-1750, PCI-1751, PCI-1752, PCI-1753/E,
PCI-1754, PCI-1756, PCI-1762
PCI-1736UP, PCI-1739U, PCI-1750, PCI-1751, PCI-1752,
PCI-1753/E, PCI-1754, PCI-1756, PCI-1760, PCI-1762
Author: Michal Dobes <dobes@tesnet.cz>
Devices: [Advantech] PCI-1730 (adv_pci_dio), PCI-1733,
PCI-1734, PCI-1735U, PCI-1736UP, PCI-1750,
PCI-1734, PCI-1735U, PCI-1736UP, PCI-1739U, PCI-1750,
PCI-1751, PCI-1752, PCI-1753,
PCI-1753+PCI-1753E, PCI-1754, PCI-1756,
PCI-1760, PCI-1762
Status: untested
Updated: Tue, 04 May 2010 13:00:00 +0000
Updated: Mon, 09 Jan 2012 12:40:46 +0000
This driver supports now only insn interface for DI/DO/DIO.
@ -51,6 +51,7 @@ Configuration options:
/* hardware types of the cards */
enum hw_cards_id {
TYPE_PCI1730, TYPE_PCI1733, TYPE_PCI1734, TYPE_PCI1735, TYPE_PCI1736,
TYPE_PCI1739,
TYPE_PCI1750,
TYPE_PCI1751,
TYPE_PCI1752,
@ -109,6 +110,12 @@ enum hw_io_access {
#define PCI1736_BOARDID 4 /* R: Board I/D switch for 1736UP */
#define PCI1736_MAINREG 0 /* Normal register (2) doesn't work */
/* Advantech PCI-1739U */
#define PCI1739_DIO 0 /* R/W: begin of 8255 registers block */
#define PCI1739_ICR 32 /* W: Interrupt control register */
#define PCI1739_ISR 32 /* R: Interrupt status register */
#define PCI1739_BOARDID 8 /* R: Board I/D switch for 1739U */
/* Advantech PCI-1750 */
#define PCI1750_IDI 0 /* R: Isolated digital input 0-15 */
#define PCI1750_IDO 0 /* W: Isolated digital output 0-15 */
@ -262,6 +269,7 @@ static DEFINE_PCI_DEVICE_TABLE(pci_dio_pci_table) = {
{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1734) },
{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1735) },
{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1736) },
{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1739) },
{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1750) },
{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1751) },
{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1752) },
@ -316,6 +324,14 @@ static const struct dio_boardtype boardtypes[] = {
{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} },
@ -883,6 +899,11 @@ static int pci_dio_reset(struct comedi_device *dev)
outb(0, dev->iobase + PCI1736_3_INT_RF);
break;
case TYPE_PCI1739:
/* disable & clear interrupts */
outb(0x88, dev->iobase + PCI1739_ICR);
break;
case TYPE_PCI1750:
case TYPE_PCI1751:
/* disable & clear interrupts */

View File

@ -720,12 +720,20 @@ static int dt2801_dio_insn_config(struct comedi_device *dev,
which = 1;
/* configure */
if (data[0]) {
switch (data[0]) {
case INSN_CONFIG_DIO_OUTPUT:
s->io_bits = 0xff;
dt2801_writecmd(dev, DT_C_SET_DIGOUT);
} else {
break;
case INSN_CONFIG_DIO_INPUT:
s->io_bits = 0;
dt2801_writecmd(dev, DT_C_SET_DIGIN);
break;
case INSN_CONFIG_DIO_QUERY:
data[1] = s->io_bits ? COMEDI_OUTPUT : COMEDI_INPUT;
return insn->n;
default:
return -EINVAL;
}
dt2801_writedata(dev, which);

View File

@ -527,7 +527,7 @@ static void dt9812_configure_gain(struct usb_dt9812 *dev,
* 11x -> Gain = 0.5
*/
case DT9812_GAIN_0PT5:
rmw->or_value = F020_MASK_ADC0CF_AMP0GN2 ||
rmw->or_value = F020_MASK_ADC0CF_AMP0GN2 |
F020_MASK_ADC0CF_AMP0GN1;
break;
case DT9812_GAIN_1:
@ -540,7 +540,7 @@ static void dt9812_configure_gain(struct usb_dt9812 *dev,
rmw->or_value = F020_MASK_ADC0CF_AMP0GN1;
break;
case DT9812_GAIN_8:
rmw->or_value = F020_MASK_ADC0CF_AMP0GN1 ||
rmw->or_value = F020_MASK_ADC0CF_AMP0GN1 |
F020_MASK_ADC0CF_AMP0GN0;
break;
case DT9812_GAIN_16:

View File

@ -2098,23 +2098,29 @@ static int me4000_dio_insn_config(struct comedi_device *dev,
CALL_PDEBUG("In me4000_dio_insn_config()\n");
if (data[0] == INSN_CONFIG_DIO_QUERY) {
switch (data[0]) {
default:
return -EINVAL;
case INSN_CONFIG_DIO_QUERY:
data[1] =
(s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
return insn->n;
case INSN_CONFIG_DIO_INPUT:
case INSN_CONFIG_DIO_OUTPUT:
break;
}
/*
* 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.
* value INSN_CONFIG_DIO_INPUT or INSN_CONFIG_DIO_OUTPUT.
* On the ME-4000 it is only possible to switch port wise (8 bit)
*/
tmp = me4000_inl(dev, info->dio_context.ctrl_reg);
if (data[0] == COMEDI_OUTPUT) {
if (data[0] == INSN_CONFIG_DIO_OUTPUT) {
if (chan < 8) {
s->io_bits |= 0xFF;
tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 |

View File

@ -30,7 +30,7 @@ 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
Updated: Sun, 21 Apr 2002 21:03:38 -0700
Updated: Mon, 09 Jan 2012 14:27:23 +0000
The DIO-96 appears as four 8255 subdevices. See the 8255
driver notes for details.
@ -42,6 +42,11 @@ supports simple digital I/O; no handshaking is supported.
DMA mostly works for the PCI-DIO32HS, but only in timed input mode.
The PCI-DIO-32HS/PCI-6533 has a configurable external trigger. Setting
scan_begin_arg to 0 or CR_EDGE triggers on the leading edge. Setting
scan_begin_arg to CR_INVERT or (CR_EDGE | CR_INVERT) triggers on the
trailing edge.
This driver could be easily modified to support AT-MIO32HS and
AT-MIO96.
@ -436,6 +441,7 @@ static int ni_pcidio_request_di_mite_channel(struct comedi_device *dev)
comedi_error(dev, "failed to reserve mite dma channel.");
return -EBUSY;
}
devpriv->di_mite_chan->dir = COMEDI_INPUT;
writeb(primary_DMAChannel_bits(devpriv->di_mite_chan->channel) |
secondary_DMAChannel_bits(devpriv->di_mite_chan->channel),
devpriv->mite->daq_io_addr + DMA_Line_Control_Group1);
@ -482,6 +488,21 @@ void ni_pcidio_event(struct comedi_device *dev, struct comedi_subdevice *s)
comedi_event(dev, s);
}
static int ni_pcidio_poll(struct comedi_device *dev, struct comedi_subdevice *s)
{
unsigned long irq_flags;
int count;
spin_lock_irqsave(&dev->spinlock, irq_flags);
spin_lock(&devpriv->mite_channel_lock);
if (devpriv->di_mite_chan)
mite_sync_input_dma(devpriv->di_mite_chan, s->async);
spin_unlock(&devpriv->mite_channel_lock);
count = s->async->buf_write_count - s->async->buf_read_count;
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
return count;
}
static irqreturn_t nidio_interrupt(int irq, void *d)
{
struct comedi_device *dev = d;
@ -497,7 +518,6 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
int status;
int work = 0;
unsigned int m_status = 0;
unsigned long irq_flags;
/* interrupcions parasites */
if (dev->attached == 0) {
@ -505,6 +525,9 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
return IRQ_NONE;
}
/* Lock to avoid race with comedi_poll */
spin_lock(&dev->spinlock);
status = readb(devpriv->mite->daq_io_addr +
Interrupt_And_Window_Status);
flags = readb(devpriv->mite->daq_io_addr + Group_1_Flags);
@ -518,7 +541,7 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
/* printk("buf[4096]=%08x\n",
*(unsigned int *)(async->prealloc_buf+4096)); */
spin_lock_irqsave(&devpriv->mite_channel_lock, irq_flags);
spin_lock(&devpriv->mite_channel_lock);
if (devpriv->di_mite_chan)
m_status = mite_get_status(devpriv->di_mite_chan);
#ifdef MITE_DEBUG
@ -543,7 +566,7 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
disable_irq(dev->irq);
}
}
spin_unlock_irqrestore(&devpriv->mite_channel_lock, irq_flags);
spin_unlock(&devpriv->mite_channel_lock);
while (status & DataLeft) {
work++;
@ -645,6 +668,8 @@ out:
Master_DMA_And_Interrupt_Control);
}
#endif
spin_unlock(&dev->spinlock);
return IRQ_HANDLED;
}
@ -825,8 +850,8 @@ static int ni_pcidio_cmdtest(struct comedi_device *dev,
} else {
/* TRIG_EXT */
/* should be level/edge, hi/lo specification here */
if (cmd->scan_begin_arg != 0) {
cmd->scan_begin_arg = 0;
if ((cmd->scan_begin_arg & ~(CR_EDGE | CR_INVERT)) != 0) {
cmd->scan_begin_arg &= (CR_EDGE | CR_INVERT);
err++;
}
}
@ -941,7 +966,13 @@ static int ni_pcidio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
writeb(0, devpriv->mite->daq_io_addr + Sequence);
writeb(0x00, devpriv->mite->daq_io_addr + ReqReg);
writeb(4, devpriv->mite->daq_io_addr + BlockMode);
writeb(0, devpriv->mite->daq_io_addr + LinePolarities);
if (!(cmd->scan_begin_arg & CR_INVERT)) {
/* Leading Edge pulse mode */
writeb(0, devpriv->mite->daq_io_addr + LinePolarities);
} else {
/* Trailing Edge pulse mode */
writeb(2, devpriv->mite->daq_io_addr + LinePolarities);
}
writeb(0x00, devpriv->mite->daq_io_addr + AckSer);
writel(1, devpriv->mite->daq_io_addr + StartDelay);
writeb(1, devpriv->mite->daq_io_addr + ReqDelay);
@ -1005,17 +1036,24 @@ static int ni_pcidio_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
static int setup_mite_dma(struct comedi_device *dev, struct comedi_subdevice *s)
{
int retval;
unsigned long flags;
retval = ni_pcidio_request_di_mite_channel(dev);
if (retval)
return retval;
devpriv->di_mite_chan->dir = COMEDI_INPUT;
/* write alloc the entire buffer */
comedi_buf_write_alloc(s->async, s->async->prealloc_bufsz);
mite_prep_dma(devpriv->di_mite_chan, 32, 32);
spin_lock_irqsave(&devpriv->mite_channel_lock, flags);
if (devpriv->di_mite_chan) {
mite_prep_dma(devpriv->di_mite_chan, 32, 32);
mite_dma_arm(devpriv->di_mite_chan);
} else
retval = -EIO;
spin_unlock_irqrestore(&devpriv->mite_channel_lock, flags);
mite_dma_arm(devpriv->di_mite_chan);
return 0;
return retval;
}
static int ni_pcidio_inttrig(struct comedi_device *dev,
@ -1244,6 +1282,7 @@ static int nidio_attach(struct comedi_device *dev, struct comedi_devconfig *it)
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));

View File

@ -29,14 +29,15 @@ Devices: [National Instruments] PCI-MIO-16XE-50 (ni_pcimio),
PCI-MIO-16XE-10, PXI-6030E, PCI-MIO-16E-1, PCI-MIO-16E-4, PCI-6014, PCI-6040E,
PXI-6040E, PCI-6030E, PCI-6031E, PCI-6032E, PCI-6033E, PCI-6071E, PCI-6023E,
PCI-6024E, PCI-6025E, PXI-6025E, PCI-6034E, PCI-6035E, PCI-6052E,
PCI-6110, PCI-6111, PCI-6220, PCI-6221, PCI-6224, PXI-6224, PCI-6225, PXI-6225,
PCI-6229, PCI-6250, PCI-6251, PCIe-6251, PCI-6254, PCI-6259, PCIe-6259,
PCI-6110, PCI-6111, PCI-6220, PCI-6221, PCI-6224, PXI-6224,
PCI-6225, PXI-6225, PCI-6229, PCI-6250, PCI-6251, PCIe-6251, PXIe-6251,
PCI-6254, PCI-6259, PCIe-6259,
PCI-6280, PCI-6281, PXI-6281, PCI-6284, PCI-6289,
PCI-6711, PXI-6711, PCI-6713, PXI-6713,
PXI-6071E, PCI-6070E, PXI-6070E,
PXI-6052E, PCI-6036E, PCI-6731, PCI-6733, PXI-6733,
PCI-6143, PXI-6143
Updated: Wed, 03 Dec 2008 10:51:47 +0000
Updated: Mon, 09 Jan 2012 14:52:48 +0000
These boards are almost identical to the AT-MIO E series, except that
they use the PCI bus instead of ISA (i.e., AT). See the notes for
@ -182,6 +183,7 @@ static DEFINE_PCI_DEVICE_TABLE(ni_pci_table) = {
{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717f)},
{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x71bc)},
{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717d)},
{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x72e8)},
{0}
};
@ -1045,6 +1047,25 @@ static const struct ni_board_struct ni_boards[] = {
.caldac = {caldac_none},
.has_8255 = 0,
},
{
.device_id = 0x72e8,
.name = "pxie-6251",
.n_adchan = 16,
.adbits = 16,
.ai_fifo_depth = 4095,
.gainlkup = ai_gain_628x,
.ai_speed = 800,
.n_aochan = 2,
.aobits = 16,
.ao_fifo_depth = 8191,
.ao_range_table = &range_ni_M_625x_ao,
.reg_type = ni_reg_625x,
.ao_unipolar = 0,
.ao_speed = 357,
.num_p0_dio_channels = 8,
.caldac = {caldac_none},
.has_8255 = 0,
},
{
.device_id = 0x70b7,
.name = "pci-6254",

View File

@ -306,7 +306,7 @@ static int __unioxx5_subdev_init(struct comedi_subdevice *subdev,
usp = kzalloc(sizeof(*usp), GFP_KERNEL);
if (usp == NULL) {
printk(KERN_ERR "comedi%d: erorr! --> out of memory!\n", minor);
printk(KERN_ERR "comedi%d: error! --> out of memory!\n", minor);
return -1;
}

View File

@ -39,7 +39,7 @@ Status: testing
*
*
* Revision history:
* 0.1: inital version
* 0.1: initial version
* 0.2: all basic functions implemented, digital I/O only for one port
* 0.3: proper vendor ID and driver name
* 0.4: fixed D/A voltage range
@ -235,16 +235,16 @@ struct usbduxsub {
short int ao_cmd_running;
/* pwm is running */
short int pwm_cmd_running;
/* continous aquisition */
short int ai_continous;
short int ao_continous;
/* continuous acquisition */
short int ai_continuous;
short int ao_continuous;
/* number of samples to acquire */
int ai_sample_count;
int ao_sample_count;
/* time between samples in units of the timer */
unsigned int ai_timer;
unsigned int ao_timer;
/* counter between aquisitions */
/* counter between acquisitions */
unsigned int ai_counter;
unsigned int ao_counter;
/* interval in frames/uframes */
@ -455,8 +455,8 @@ static void usbduxsub_ai_IsocIrq(struct urb *urb)
this_usbduxsub->ai_counter = this_usbduxsub->ai_timer;
/* test, if we transmit only a fixed number of samples */
if (!(this_usbduxsub->ai_continous)) {
/* not continous, fixed number of samples */
if (!(this_usbduxsub->ai_continuous)) {
/* not continuous, fixed number of samples */
this_usbduxsub->ai_sample_count--;
/* all samples received? */
if (this_usbduxsub->ai_sample_count < 0) {
@ -607,8 +607,8 @@ static void usbduxsub_ao_IsocIrq(struct urb *urb)
/* timer zero */
this_usbduxsub->ao_counter = this_usbduxsub->ao_timer;
/* handle non continous aquisition */
if (!(this_usbduxsub->ao_continous)) {
/* handle non continuous acquisition */
if (!(this_usbduxsub->ao_continuous)) {
/* fixed number of samples */
this_usbduxsub->ao_sample_count--;
if (this_usbduxsub->ao_sample_count < 0) {
@ -925,7 +925,7 @@ static int usbdux_ai_cmdtest(struct comedi_device *dev,
if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
err++;
/* scanning is continous */
/* scanning is continuous */
tmp = cmd->convert_src;
cmd->convert_src &= TRIG_NOW;
if (!cmd->convert_src || tmp != cmd->convert_src)
@ -1193,7 +1193,7 @@ static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
up(&this_usbduxsub->sem);
return -EBUSY;
}
/* set current channel of the running aquisition to zero */
/* set current channel of the running acquisition to zero */
s->async->cur_chan = 0;
/* first the number of channels per time step */
@ -1261,10 +1261,10 @@ static int usbdux_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
if (cmd->stop_src == TRIG_COUNT) {
/* data arrives as one packet */
this_usbduxsub->ai_sample_count = cmd->stop_arg;
this_usbduxsub->ai_continous = 0;
this_usbduxsub->ai_continuous = 0;
} else {
/* continous aquisition */
this_usbduxsub->ai_continous = 1;
/* continuous acquisition */
this_usbduxsub->ai_continuous = 1;
this_usbduxsub->ai_sample_count = 0;
}
@ -1586,7 +1586,7 @@ static int usbdux_ao_cmdtest(struct comedi_device *dev,
/* 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 immidiately a new scan */
/* start immediately a new scan */
/* the sampling rate is set by the coversion rate */
cmd->scan_begin_src &= TRIG_FOLLOW;
} else {
@ -1596,7 +1596,7 @@ static int usbdux_ao_cmdtest(struct comedi_device *dev,
if (!cmd->scan_begin_src || tmp != cmd->scan_begin_src)
err++;
/* scanning is continous */
/* scanning is continuous */
tmp = cmd->convert_src;
/* all conversion events happen simultaneously */
@ -1710,7 +1710,7 @@ static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
dev_dbg(&this_usbduxsub->interface->dev,
"comedi%d: %s\n", dev->minor, __func__);
/* set current channel of the running aquisition to zero */
/* set current channel of the running acquisition to zero */
s->async->cur_chan = 0;
for (i = 0; i < cmd->chanlist_len; ++i) {
chan = CR_CHAN(cmd->chanlist[i]);
@ -1759,7 +1759,7 @@ static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
this_usbduxsub->ao_counter = this_usbduxsub->ao_timer;
if (cmd->stop_src == TRIG_COUNT) {
/* not continous */
/* not continuous */
/* counter */
/* high speed also scans everything at once */
if (0) { /* (this_usbduxsub->high_speed) */
@ -1771,10 +1771,10 @@ static int usbdux_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
/* data arrives as one packet */
this_usbduxsub->ao_sample_count = cmd->stop_arg;
}
this_usbduxsub->ao_continous = 0;
this_usbduxsub->ao_continuous = 0;
} else {
/* continous aquisition */
this_usbduxsub->ao_continous = 1;
/* continuous acquisition */
this_usbduxsub->ao_continuous = 1;
this_usbduxsub->ao_sample_count = 0;
}

View File

@ -48,8 +48,7 @@
#endif
#include "bc_dts_defs.h"
#include "bcm_70012_regs.h" /* Link Register defs */
#include "crystalhd.h"
#define CRYSTALHD_API_NAME "crystalhd"
#define CRYSTALHD_API_DEV_NAME "/dev/crystalhd"

View File

@ -1,40 +0,0 @@
/********************************************************************
* Copyright(c) 2006-2009 Broadcom Corporation.
*
* Name: bc_dts_types.h
*
* Description: Data types
*
* AU
*
* HISTORY:
*
********************************************************************
* This header is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation, either version 2.1 of the License.
*
* This header 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 Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License
* along with this header. If not, see <http://www.gnu.org/licenses/>.
*******************************************************************/
#ifndef _BC_DTS_TYPES_H_
#define _BC_DTS_TYPES_H_
#include <stdint.h>
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#define TEXT
#endif

View File

@ -0,0 +1,14 @@
#ifndef _CRYSTALHD_H_
#define _CRYSTALHD_H_
#include <asm/system.h>
#include "bc_dts_defs.h"
#include "crystalhd_misc.h"
#include "bc_dts_glob_lnx.h"
#include "crystalhd_hw.h"
#include "crystalhd_cmds.h"
#include "crystalhd_lnx.h"
#include "bcm_70012_regs.h"
#include "crystalhd_fw_if.h"
#endif

View File

@ -24,8 +24,7 @@
* along with this driver. If not, see <http://www.gnu.org/licenses/>.
**********************************************************************/
#include "crystalhd_cmds.h"
#include "crystalhd_hw.h"
#include "crystalhd.h"
static struct crystalhd_user *bc_cproc_get_uid(struct crystalhd_cmd *ctx)
{

View File

@ -33,8 +33,8 @@
* from _dts_glob and dts_defs etc.. which are defined for
* windows.
*/
#include "crystalhd_misc.h"
#include "crystalhd_hw.h"
#include "crystalhd.h"
enum crystalhd_state {
BC_LINK_INVALID = 0x00,

View File

@ -22,10 +22,11 @@
* along with this driver. If not, see <http://www.gnu.org/licenses/>.
**********************************************************************/
#include "crystalhd.h"
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include "crystalhd_hw.h"
/* Functions internal to this file */
@ -766,7 +767,7 @@ static enum BC_STATUS crystalhd_hw_fill_desc(struct crystalhd_dio_req *ioreq,
crystalhd_hw_dump_desc(desc, last_desc_ix, 1);
if (count != xfr_sz) {
BCMLOG_ERR("interal error sz curr:%x exp:%x\n", count, xfr_sz);
BCMLOG_ERR("internal error sz curr:%x exp:%x\n", count, xfr_sz);
return BC_STS_ERROR;
}
@ -868,8 +869,7 @@ static enum BC_STATUS crystalhd_stop_tx_dma_engine(struct crystalhd_hw *hw)
BCMLOG(BCMLOG_DBG, "Stopping TX DMA Engine..\n");
/* FIXME: jarod: invert dma_ctrl and check bit? or are there missing parens? */
if (!dma_cntrl & DMA_START_BIT) {
if (!(dma_cntrl & DMA_START_BIT)) {
BCMLOG(BCMLOG_DBG, "Already Stopped\n");
return BC_STS_SUCCESS;
}
@ -1628,7 +1628,6 @@ enum BC_STATUS crystalhd_download_fw(struct crystalhd_adp *adp, void *buffer, ui
uint32_t fw_sig_len = 36;
uint32_t dram_offset = BC_FWIMG_ST_ADDR, sig_reg;
BCMLOG_ENTER;
if (!adp || !buffer || !sz) {
BCMLOG_ERR("Invalid Params.\n");
@ -1725,8 +1724,6 @@ enum BC_STATUS crystalhd_do_fw_cmd(struct crystalhd_hw *hw,
crystalhd_create_event(&fw_cmd_event);
BCMLOG_ENTER;
if (!hw || !fw_cmd) {
BCMLOG_ERR("Invalid Arguments\n");
return BC_STS_INV_ARG;

View File

@ -27,8 +27,7 @@
#ifndef _CRYSTALHD_HW_H_
#define _CRYSTALHD_HW_H_
#include "crystalhd_misc.h"
#include "crystalhd_fw_if.h"
#include "crystalhd.h"
/* HW constants..*/
#define DMA_ENGINE_CNT 2

View File

@ -15,10 +15,11 @@
along with this driver. If not, see <http://www.gnu.org/licenses/>.
***************************************************************************/
#include "crystalhd.h"
#include <linux/mutex.h>
#include <linux/slab.h>
#include "crystalhd_lnx.h"
static DEFINE_MUTEX(chd_dec_mutex);
static struct class *crystalhd_class;
@ -298,7 +299,6 @@ static int chd_dec_open(struct inode *in, struct file *fd)
enum BC_STATUS sts = BC_STS_SUCCESS;
struct crystalhd_user *uc = NULL;
BCMLOG_ENTER;
if (!adp) {
BCMLOG_ERR("Invalid adp\n");
return -EINVAL;
@ -327,7 +327,6 @@ static int chd_dec_close(struct inode *in, struct file *fd)
struct crystalhd_adp *adp = chd_get_adp();
struct crystalhd_user *uc;
BCMLOG_ENTER;
if (!adp) {
BCMLOG_ERR("Invalid adp\n");
return -EINVAL;
@ -513,8 +512,6 @@ static void __devexit chd_dec_pci_remove(struct pci_dev *pdev)
struct crystalhd_adp *pinfo;
enum BC_STATUS sts = BC_STS_SUCCESS;
BCMLOG_ENTER;
pinfo = pci_get_drvdata(pdev);
if (!pinfo) {
BCMLOG_ERR("could not get adp\n");

View File

@ -1,7 +1,7 @@
/***************************************************************************
* Copyright (c) 2005-2009, Broadcom Corporation.
*
* Name: crystalhd_lnx . c
* Name: crystalhd_lnx . h
*
* Description:
* BCM70012 Linux driver
@ -48,11 +48,10 @@
#include <asm/system.h>
#include <linux/uaccess.h>
#include "crystalhd_cmds.h"
#include "crystalhd.h"
#define CRYSTAL_HD_NAME "Broadcom Crystal HD Decoder (BCM70012) Driver"
/* OS specific PCI information structure and adapter information. */
struct crystalhd_adp {
/* Hardware borad/PCI specifics */

View File

@ -24,10 +24,9 @@
* along with this driver. If not, see <http://www.gnu.org/licenses/>.
**********************************************************************/
#include <linux/slab.h>
#include "crystalhd.h"
#include "crystalhd_misc.h"
#include "crystalhd_lnx.h"
#include <linux/slab.h>
uint32_t g_linklog_level;

View File

@ -28,6 +28,8 @@
#ifndef _CRYSTALHD_MISC_H_
#define _CRYSTALHD_MISC_H_
#include "crystalhd.h"
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
@ -35,8 +37,6 @@
#include <linux/ioctl.h>
#include <linux/dma-mapping.h>
#include <linux/sched.h>
#include <asm/system.h>
#include "bc_dts_glob_lnx.h"
/* Global log level variable defined in crystal_misc.c file */
extern uint32_t g_linklog_level;
@ -200,29 +200,21 @@ enum _chd_log_levels {
BCMLOG_INFO = 0x00000001, /* Generic informational */
BCMLOG_DBG = 0x00000002, /* First level Debug info */
BCMLOG_SSTEP = 0x00000004, /* Stepping information */
BCMLOG_ENTER_LEAVE = 0x00000008, /* stack tracking */
};
#define BCMLOG_ENTER \
if (g_linklog_level & BCMLOG_ENTER_LEAVE) { \
printk(KERN_DEBUG "Entered %s\n", __func__); \
}
#define BCMLOG_LEAVE \
if (g_linklog_level & BCMLOG_ENTER_LEAVE) { \
printk(KERN_DEBUG "Leaving %s\n", __func__); \
}
#define BCMLOG(trace, fmt, args...) \
do { \
if (g_linklog_level & trace) \
printk(fmt, ##args); \
} while (0)
#define BCMLOG(trace, fmt, args...) \
if (g_linklog_level & trace) { \
printk(fmt, ##args); \
}
#define BCMLOG_ERR(fmt, args...) \
do { \
if (g_linklog_level & BCMLOG_ERROR) { \
printk(KERN_ERR "*ERR*:%s:%d: "fmt, __FILE__, __LINE__, ##args); \
} \
} while (0);
#define BCMLOG_ERR(fmt, args...) \
do { \
if (g_linklog_level & BCMLOG_ERROR) \
printk(KERN_ERR "*ERR*:%s:%d: "fmt, \
__FILE__, __LINE__, ##args); \
} while (0)
#endif

View File

@ -11,6 +11,6 @@ TODO:
- Use of kmem_cache seems a bit unusual
Please send patches to:
Greg Kroah-Hartman <gregkh@suse.de>
Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Mark Einon <mark.einon@gmail.com>

View File

@ -802,7 +802,7 @@ static int et131x_init_eeprom(struct et131x_adapter *adapter)
/* THIS IS A WORKAROUND:
* I need to call this function twice to get my card in a
* LG M1 Express Dual running. I tried also a msleep before this
* function, because I thougth there could be some time condidions
* function, because I thought there could be some time condidions
* but it didn't work. Call the whole function twice also work.
*/
if (pci_read_config_byte(pdev, ET1310_PCI_EEPROM_STATUS, &eestatus)) {
@ -987,7 +987,7 @@ static void et1310_config_mac_regs1(struct et131x_adapter *adapter)
writel(station1, &macregs->station_addr_1);
writel(station2, &macregs->station_addr_2);
/* Max ethernet packet in bytes that will passed by the mac without
/* Max ethernet packet in bytes that will be passed by the mac without
* being truncated. Allow the MAC to pass 4 more than our max packet
* size. This is 4 for the Ethernet CRC.
*
@ -3109,7 +3109,7 @@ static struct rfd *nic_rx_pkts(struct et131x_adapter *adapter)
skb->protocol = eth_type_trans(skb, adapter->netdev);
skb->ip_summed = CHECKSUM_NONE;
netif_rx(skb);
netif_rx_ni(skb);
} else {
rfd->len = 0;
}
@ -4413,7 +4413,7 @@ static void et131x_up(struct net_device *netdev)
/**
* et131x_down - Bring down the device
* @netdev: device to be broght down
* @netdev: device to be brought down
*/
static void et131x_down(struct net_device *netdev)
{
@ -5177,7 +5177,7 @@ static int et131x_set_mac_addr(struct net_device *netdev, void *new_mac)
/* Make sure the requested MAC is valid */
if (!is_valid_ether_addr(address->sa_data))
return -EINVAL;
return -EADDRNOTAVAIL;
et131x_disable_txrx(netdev);
et131x_handle_send_interrupt(adapter);

View File

@ -596,7 +596,7 @@ struct rxdma_regs { /* Location: */
* structure for tx test reg in txmac address map
* located at address 0x3014
* 31-17: unused
* 16: reserved1
* 16: reserved
* 15: txtest_en
* 14-11: unused
* 10-0: txq test pointer
@ -1485,7 +1485,7 @@ struct address_map {
* 3: reserved
* 2: ignore_10g_fr
* 1: reserved
* 0: preamble_supress_en
* 0: preamble_suppress_en
*/
/* MI Register 22: PHY Configuration Reg(0x16)

View File

@ -450,7 +450,7 @@ exit:
/**
* usb_alphatrack_poll
*/
static unsigned int usb_alphatrack_poll(struct file *file, poll_table * wait)
static unsigned int usb_alphatrack_poll(struct file *file, poll_table *wait)
{
struct usb_alphatrack *dev;
unsigned int mask = 0;

View File

@ -471,7 +471,7 @@ exit:
/**
* usb_tranzport_poll
*/
static unsigned int usb_tranzport_poll(struct file *file, poll_table * wait)
static unsigned int usb_tranzport_poll(struct file *file, poll_table *wait)
{
struct usb_tranzport *dev;
unsigned int mask = 0;

View File

@ -29,10 +29,10 @@
#define FT1000_PROC "ft1000"
#define MAX_FILE_LEN 255
#define PUTM_TO_PAGE(len,page,args...) \
#define PUTM_TO_PAGE(len, page, args...) \
len += snprintf(page+len, PAGE_SIZE - len, args)
#define PUTX_TO_PAGE(len,page,message,size,var) \
#define PUTX_TO_PAGE(len, page, message, size, var) \
len += snprintf(page+len, PAGE_SIZE - len, message); \
for(i = 0; i < (size - 1); i++) \
{ \
@ -40,7 +40,7 @@
} \
len += snprintf(page+len, PAGE_SIZE - len, "%02x\n", var[i])
#define PUTD_TO_PAGE(len,page,message,size,var) \
#define PUTD_TO_PAGE(len, page, message, size, var) \
len += snprintf(page+len, PAGE_SIZE - len, message); \
for(i = 0; i < (size - 1); i++) \
{ \

View File

@ -1,5 +0,0 @@
config HYPERV_STORAGE
tristate "Microsoft Hyper-V virtual storage driver"
depends on HYPERV && SCSI
help
Select this option to enable the Hyper-V virtual storage driver.

View File

@ -1,3 +0,0 @@
obj-$(CONFIG_HYPERV_STORAGE) += hv_storvsc.o
hv_storvsc-y := storvsc_drv.o

View File

@ -1,5 +0,0 @@
TODO:
- audit the scsi driver
Please send patches for this code to Greg Kroah-Hartman <gregkh@suse.de>,
Haiyang Zhang <haiyangz@microsoft.com>, and K. Y. Srinivasan <kys@microsoft.com>

View File

@ -62,7 +62,7 @@ Then fill in the following:
An optional associated buffer.
- indio_dev->pollfunc:
Poll function related elements. This controls what occurs when a trigger
to which this device is attached sends and event.
to which this device is attached sends an event.
- indio_dev->channels:
Specification of device channels. Most attributes etc are built
form this spec.

View File

@ -0,0 +1,241 @@
/* Industrialio event test code.
*
* Copyright (c) 2011-2012 Lars-Peter Clausen <lars@metafoo.de>
*
* 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.
*
* This program is primarily intended as an example application.
* Reads the current buffer setup from sysfs and starts a short capture
* from the specified device, pretty printing the result after appropriate
* conversion.
*
* Usage:
* iio_event_monitor <device_name>
*
*/
#define _GNU_SOURCE
#include <unistd.h>
#include <stdbool.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <poll.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include "iio_utils.h"
#include "../events.h"
static const char * const iio_chan_type_name_spec[] = {
[IIO_VOLTAGE] = "voltage",
[IIO_CURRENT] = "current",
[IIO_POWER] = "power",
[IIO_ACCEL] = "accel",
[IIO_ANGL_VEL] = "anglvel",
[IIO_MAGN] = "magn",
[IIO_LIGHT] = "illuminance",
[IIO_INTENSITY] = "intensity",
[IIO_PROXIMITY] = "proximity",
[IIO_TEMP] = "temp",
[IIO_INCLI] = "incli",
[IIO_ROT] = "rot",
[IIO_ANGL] = "angl",
[IIO_TIMESTAMP] = "timestamp",
[IIO_CAPACITANCE] = "capacitance",
};
static const char * const iio_ev_type_text[] = {
[IIO_EV_TYPE_THRESH] = "thresh",
[IIO_EV_TYPE_MAG] = "mag",
[IIO_EV_TYPE_ROC] = "roc",
[IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive",
[IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive",
};
static const char * const iio_ev_dir_text[] = {
[IIO_EV_DIR_EITHER] = "either",
[IIO_EV_DIR_RISING] = "rising",
[IIO_EV_DIR_FALLING] = "falling"
};
static const char * const iio_modifier_names[] = {
[IIO_MOD_X] = "x",
[IIO_MOD_Y] = "y",
[IIO_MOD_Z] = "z",
[IIO_MOD_LIGHT_BOTH] = "both",
[IIO_MOD_LIGHT_IR] = "ir",
};
static bool event_is_known(struct iio_event_data *event)
{
enum iio_chan_type type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event->id);
enum iio_modifier mod = IIO_EVENT_CODE_EXTRACT_MODIFIER(event->id);
enum iio_event_type ev_type = IIO_EVENT_CODE_EXTRACT_TYPE(event->id);
enum iio_event_direction dir = IIO_EVENT_CODE_EXTRACT_DIR(event->id);
switch (type) {
case IIO_VOLTAGE:
case IIO_CURRENT:
case IIO_POWER:
case IIO_ACCEL:
case IIO_ANGL_VEL:
case IIO_MAGN:
case IIO_LIGHT:
case IIO_INTENSITY:
case IIO_PROXIMITY:
case IIO_TEMP:
case IIO_INCLI:
case IIO_ROT:
case IIO_ANGL:
case IIO_TIMESTAMP:
case IIO_CAPACITANCE:
break;
default:
return false;
}
switch (mod) {
case IIO_NO_MOD:
case IIO_MOD_X:
case IIO_MOD_Y:
case IIO_MOD_Z:
case IIO_MOD_LIGHT_BOTH:
case IIO_MOD_LIGHT_IR:
break;
default:
return false;
}
switch (ev_type) {
case IIO_EV_TYPE_THRESH:
case IIO_EV_TYPE_MAG:
case IIO_EV_TYPE_ROC:
case IIO_EV_TYPE_THRESH_ADAPTIVE:
case IIO_EV_TYPE_MAG_ADAPTIVE:
break;
default:
return false;
}
switch (dir) {
case IIO_EV_DIR_EITHER:
case IIO_EV_DIR_RISING:
case IIO_EV_DIR_FALLING:
break;
default:
return false;
}
return true;
}
static void print_event(struct iio_event_data *event)
{
enum iio_chan_type type = IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event->id);
enum iio_modifier mod = IIO_EVENT_CODE_EXTRACT_MODIFIER(event->id);
enum iio_event_type ev_type = IIO_EVENT_CODE_EXTRACT_TYPE(event->id);
enum iio_event_direction dir = IIO_EVENT_CODE_EXTRACT_DIR(event->id);
int chan = IIO_EVENT_CODE_EXTRACT_CHAN(event->id);
int chan2 = IIO_EVENT_CODE_EXTRACT_CHAN2(event->id);
bool diff = IIO_EVENT_CODE_EXTRACT_DIFF(event->id);
if (!event_is_known(event)) {
printf("Unknown event: time: %lld, id: %llx\n",
event->timestamp, event->id);
return;
}
printf("Event: time: %lld, ", event->timestamp);
if (mod != IIO_NO_MOD) {
printf("type: %s(%s), ",
iio_chan_type_name_spec[type],
iio_modifier_names[mod]);
} else {
printf("type: %s, ",
iio_chan_type_name_spec[type]);
}
if (diff && chan >= 0 && chan2 >= 0)
printf("channel: %d-%d, ", chan, chan2);
else if (chan >= 0)
printf("channel: %d, ", chan);
printf("evtype: %s, direction: %s\n",
iio_ev_type_text[ev_type],
iio_ev_dir_text[dir]);
}
int main(int argc, char **argv)
{
struct iio_event_data event;
const char *device_name;
char *chrdev_name;
int ret;
int dev_num;
int fd, event_fd;
if (argc <= 1) {
printf("Usage: %s <device_name>\n", argv[0]);
return -1;
}
device_name = argv[1];
dev_num = find_type_by_name(device_name, "iio:device");
if (dev_num >= 0) {
printf("Found IIO device with name %s with device number %d\n",
device_name, dev_num);
ret = asprintf(&chrdev_name, "/dev/iio:device%d", dev_num);
if (ret < 0) {
ret = -ENOMEM;
goto error_ret;
}
} else {
/* If we can't find a IIO device by name assume device_name is a
IIO chrdev */
chrdev_name = strdup(device_name);
}
fd = open(chrdev_name, 0);
if (fd == -1) {
fprintf(stdout, "Failed to open %s\n", chrdev_name);
ret = -errno;
goto error_free_chrdev_name;
}
ret = ioctl(fd, IIO_GET_EVENT_FD_IOCTL, &event_fd);
close(fd);
if (ret == -1 || event_fd == -1) {
fprintf(stdout, "Failed to retrieve event fd\n");
ret = -errno;
goto error_free_chrdev_name;
}
while (true) {
ret = read(event_fd, &event, sizeof(event));
if (ret == -1) {
if (errno == EAGAIN) {
printf("nothing available\n");
continue;
} else {
perror("Failed to read event from device");
ret = -errno;
break;
}
}
print_event(&event);
}
close(event_fd);
error_free_chrdev_name:
free(chrdev_name);
error_ret:
return ret;
}

View File

@ -0,0 +1,58 @@
Industrial I/O Subsystem in kernel consumers.
The IIO subsystem can act as a layer under other elements of the kernel
providing a means of obtaining ADC type readings or of driving DAC type
signals. The functionality supported will grow as use cases arise.
Describing the channel mapping (iio/machine.h)
Channel associations are described using:
struct iio_map {
const char *adc_channel_label;
const char *consumer_dev_name;
const char *consumer_channel;
};
adc_channel_label identifies the channel on the IIO device by being
matched against the datasheet_name field of the iio_chan_spec.
consumer_dev_name allows identification of the consumer device.
This are then used to find the channel mapping from the consumer device (see
below).
Finally consumer_channel is a string identifying the channel to the consumer.
(Perhaps 'battery_voltage' or similar).
An array of these structures is then passed to the IIO driver.
Supporting in kernel interfaces in the driver (driver.h)
The driver must provide datasheet_name values for its channels and
must pass the iio_map structures and a pointer to its own iio_dev structure
on to the core via a call to iio_map_array_register. On removal,
iio_map_array_unregister reverses this process.
The result of this is that the IIO core now has all the information needed
to associate a given channel with the consumer requesting it.
Acting as an IIO consumer (consumer.h)
The consumer first has to obtain an iio_channel structure from the core
by calling iio_channel_get(). The correct channel is identified by:
* matching dev or dev_name against consumer_dev and consumer_dev_name
* matching consumer_channel against consumer_channel in the map
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
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.

View File

@ -11,6 +11,13 @@ menuconfig IIO
number of different physical interfaces (i2c, spi, etc). See
drivers/staging/iio/Documentation for more information.
if IIO
config IIO_ST_HWMON
tristate "Hwmon driver that uses channels specified via iio maps"
depends on HWMON
help
This is a platform driver that in combination with a suitable
map allows IIO devices to provide basic hwmon functionality
for those channels specified in the map.
config IIO_BUFFER
bool "Enable buffer support within IIO"
@ -79,7 +86,7 @@ config IIO_SIMPLE_DUMMY
help
Driver intended mainly as documentation for how to write
a driver. May also be useful for testing userspace code
without hardward.
without hardware.
if IIO_SIMPLE_DUMMY

View File

@ -3,7 +3,7 @@
#
obj-$(CONFIG_IIO) += industrialio.o
industrialio-y := industrialio-core.o
industrialio-y := industrialio-core.o industrialio-event.o inkern.o
industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
@ -17,6 +17,8 @@ iio_dummy-$(CONFIG_IIO_SIMPLE_DUMMY_BUFFER) += iio_simple_dummy_buffer.o
obj-$(CONFIG_IIO_DUMMY_EVGEN) += iio_dummy_evgen.o
obj-$(CONFIG_IIO_ST_HWMON) += iio_hwmon.o
obj-y += accel/
obj-y += adc/
obj-y += addac/

View File

@ -115,9 +115,7 @@ int adis16201_configure_ring(struct iio_dev *indio_dev)
return ret;
}
indio_dev->buffer = ring;
/* Effectively select the ring buffer implementation */
ring->scan_timestamp = true;
ring->access = &ring_sw_access_funcs;
indio_dev->setup_ops = &adis16201_ring_setup_ops;
indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,

View File

@ -117,9 +117,7 @@ int adis16203_configure_ring(struct iio_dev *indio_dev)
return ret;
}
indio_dev->buffer = ring;
/* Effectively select the ring buffer implementation */
ring->scan_timestamp = true;
ring->access = &ring_sw_access_funcs;
indio_dev->setup_ops = &adis16203_ring_setup_ops;
indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,

View File

@ -112,8 +112,6 @@ int adis16204_configure_ring(struct iio_dev *indio_dev)
return ret;
}
indio_dev->buffer = ring;
/* Effectively select the ring buffer implementation */
ring->access = &ring_sw_access_funcs;
ring->scan_timestamp = true;
indio_dev->setup_ops = &adis16204_ring_setup_ops;

View File

@ -113,8 +113,6 @@ int adis16209_configure_ring(struct iio_dev *indio_dev)
return ret;
}
indio_dev->buffer = ring;
/* Effectively select the ring buffer implementation */
ring->access = &ring_sw_access_funcs;
ring->scan_timestamp = true;
indio_dev->setup_ops = &adis16209_ring_setup_ops;

View File

@ -110,8 +110,6 @@ int adis16240_configure_ring(struct iio_dev *indio_dev)
return ret;
}
indio_dev->buffer = ring;
/* Effectively select the ring buffer implementation */
ring->access = &ring_sw_access_funcs;
ring->scan_timestamp = true;
indio_dev->setup_ops = &adis16240_ring_setup_ops;

View File

@ -187,12 +187,10 @@ void lis3l02dq_unconfigure_buffer(struct iio_dev *indio_dev);
#ifdef CONFIG_LIS3L02DQ_BUF_RING_SW
#define lis3l02dq_free_buf iio_sw_rb_free
#define lis3l02dq_alloc_buf iio_sw_rb_allocate
#define lis3l02dq_access_funcs ring_sw_access_funcs
#endif
#ifdef CONFIG_LIS3L02DQ_BUF_KFIFO
#define lis3l02dq_free_buf iio_kfifo_free
#define lis3l02dq_alloc_buf iio_kfifo_allocate
#define lis3l02dq_access_funcs kfifo_access_funcs
#endif
irqreturn_t lis3l02dq_data_rdy_trig_poll(int irq, void *private);
#define lis3l02dq_th lis3l02dq_data_rdy_trig_poll

View File

@ -239,7 +239,7 @@ static int lis3l02dq_data_rdy_trigger_set_state(struct iio_trigger *trig,
__lis3l02dq_write_data_ready_config(&indio_dev->dev, state);
if (state == false) {
/*
* A possible quirk with teh handler is currently worked around
* A possible quirk with the handler is currently worked around
* by ensuring outstanding read events are cleared.
*/
ret = lis3l02dq_read_all(indio_dev, NULL);
@ -406,8 +406,6 @@ int lis3l02dq_configure_buffer(struct iio_dev *indio_dev)
return -ENOMEM;
indio_dev->buffer = buffer;
/* Effectively select the buffer implementation */
indio_dev->buffer->access = &lis3l02dq_access_funcs;
buffer->scan_timestamp = true;
indio_dev->setup_ops = &lis3l02dq_buffer_setup_ops;

View File

@ -136,7 +136,7 @@
#define SCA3000_INT_MASK_ACTIVE_HIGH 0x01
#define SCA3000_INT_MASK_ACTIVE_LOW 0x00
/* Values of mulipexed registers (write to ctrl_data after select) */
/* Values of multiplexed registers (write to ctrl_data after select) */
#define SCA3000_REG_ADDR_CTRL_DATA 0x22
/* Measurement modes available on some sca3000 series chips. Code assumes others

View File

@ -193,4 +193,13 @@ config MAX1363_RING_BUFFER
Say yes here to include ring buffer support in the MAX1363
ADC driver.
config LPC32XX_ADC
tristate "NXP LPC32XX ADC"
depends on ARCH_LPC32XX && !TOUCHSCREEN_LPC32XX
help
Say yes here to build support for the integrated ADC inside the
LPC32XX SoC. Note that this feature uses the same hardware as the
touchscreen driver, so you can only select one of the two drivers
(lpc32xx_adc or lpc32xx_ts). Provides direct access via sysfs.
endmenu

View File

@ -37,3 +37,4 @@ obj-$(CONFIG_AD7192) += ad7192.o
obj-$(CONFIG_ADT7310) += adt7310.o
obj-$(CONFIG_ADT7410) += adt7410.o
obj-$(CONFIG_AD7280) += ad7280a.o
obj-$(CONFIG_LPC32XX_ADC) += lpc32xx_adc.o

View File

@ -561,8 +561,6 @@ static int ad7192_register_ring_funcs_and_init(struct iio_dev *indio_dev)
ret = -ENOMEM;
goto error_ret;
}
/* Effectively select the ring buffer implementation */
indio_dev->buffer->access = &ring_sw_access_funcs;
indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
&ad7192_trigger_handler,
IRQF_ONESHOT,
@ -824,25 +822,20 @@ static struct attribute *ad7192_attributes[] = {
NULL
};
static umode_t ad7192_attr_is_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad7192_state *st = iio_priv(indio_dev);
umode_t mode = attr->mode;
if ((st->devid != ID_AD7195) &&
(attr == &iio_dev_attr_ac_excitation_en.dev_attr.attr))
mode = 0;
return mode;
}
static const struct attribute_group ad7192_attribute_group = {
.attrs = ad7192_attributes,
.is_visible = ad7192_attr_is_visible,
};
static struct attribute *ad7195_attributes[] = {
&iio_dev_attr_sampling_frequency.dev_attr.attr,
&iio_dev_attr_in_v_m_v_scale_available.dev_attr.attr,
&iio_dev_attr_in_voltage_scale_available.dev_attr.attr,
&iio_dev_attr_bridge_switch_en.dev_attr.attr,
NULL
};
static const struct attribute_group ad7195_attribute_group = {
.attrs = ad7195_attributes,
};
static int ad7192_read_raw(struct iio_dev *indio_dev,
@ -972,6 +965,15 @@ static const struct iio_info ad7192_info = {
.driver_module = THIS_MODULE,
};
static const struct iio_info ad7195_info = {
.read_raw = &ad7192_read_raw,
.write_raw = &ad7192_write_raw,
.write_raw_get_fmt = &ad7192_write_raw_get_fmt,
.attrs = &ad7195_attribute_group,
.validate_trigger = ad7192_validate_trigger,
.driver_module = THIS_MODULE,
};
#define AD7192_CHAN_DIFF(_chan, _chan2, _name, _address, _si) \
{ .type = IIO_VOLTAGE, \
.differential = 1, \
@ -1064,7 +1066,10 @@ static int __devinit ad7192_probe(struct spi_device *spi)
indio_dev->channels = ad7192_channels;
indio_dev->num_channels = ARRAY_SIZE(ad7192_channels);
indio_dev->available_scan_masks = st->available_scan_masks;
indio_dev->info = &ad7192_info;
if (st->devid == ID_AD7195)
indio_dev->info = &ad7195_info;
else
indio_dev->info = &ad7192_info;
for (i = 0; i < indio_dev->num_channels; i++)
st->available_scan_masks[i] = (1 << i) | (1 <<

View File

@ -321,7 +321,7 @@ static int ad7291_read_event_value(struct iio_dev *indio_dev,
switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
case IIO_VOLTAGE:
reg = ad7291_limit_regs[IIO_EVENT_CODE_EXTRACT_NUM(event_code)]
reg = ad7291_limit_regs[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)]
[!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
IIO_EV_DIR_RISING)];
@ -359,7 +359,7 @@ static int ad7291_write_event_value(struct iio_dev *indio_dev,
case IIO_VOLTAGE:
if (val > AD7291_VALUE_MASK || val < 0)
return -EINVAL;
reg = ad7291_limit_regs[IIO_EVENT_CODE_EXTRACT_NUM(event_code)]
reg = ad7291_limit_regs[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)]
[!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
IIO_EV_DIR_RISING)];
return ad7291_i2c_write(chip, reg, val);
@ -386,7 +386,7 @@ static int ad7291_read_event_config(struct iio_dev *indio_dev,
switch (IIO_EVENT_CODE_EXTRACT_CHAN_TYPE(event_code)) {
case IIO_VOLTAGE:
if (chip->c_mask &
(1 << (15 - IIO_EVENT_CODE_EXTRACT_NUM(event_code))))
(1 << (15 - IIO_EVENT_CODE_EXTRACT_CHAN(event_code))))
return 1;
else
return 0;
@ -418,12 +418,12 @@ static int ad7291_write_event_config(struct iio_dev *indio_dev,
switch (IIO_EVENT_CODE_EXTRACT_TYPE(event_code)) {
case IIO_VOLTAGE:
if ((!state) && (chip->c_mask & (1 << (15 -
IIO_EVENT_CODE_EXTRACT_NUM(event_code)))))
chip->c_mask &= ~(1 << (15 - IIO_EVENT_CODE_EXTRACT_NUM
IIO_EVENT_CODE_EXTRACT_CHAN(event_code)))))
chip->c_mask &= ~(1 << (15 - IIO_EVENT_CODE_EXTRACT_CHAN
(event_code)));
else if (state && (!(chip->c_mask & (1 << (15 -
IIO_EVENT_CODE_EXTRACT_NUM(event_code))))))
chip->c_mask |= (1 << (15 - IIO_EVENT_CODE_EXTRACT_NUM
IIO_EVENT_CODE_EXTRACT_CHAN(event_code))))))
chip->c_mask |= (1 << (15 - IIO_EVENT_CODE_EXTRACT_CHAN
(event_code)));
else
break;

View File

@ -131,9 +131,6 @@ int ad7298_register_ring_funcs_and_init(struct iio_dev *indio_dev)
ret = -ENOMEM;
goto error_ret;
}
/* Effectively select the ring buffer implementation */
indio_dev->buffer->access = &ring_sw_access_funcs;
indio_dev->pollfunc = iio_alloc_pollfunc(NULL,
&ad7298_trigger_handler,
IRQF_ONESHOT,

View File

@ -23,7 +23,7 @@
/**
* ad7476_ring_preenable() setup the parameters of the ring before enabling
*
* The complex nature of the setting of the nuber of bytes per datum is due
* The complex nature of the setting of the number of bytes per datum is due
* to this driver currently ensuring that the timestamp is stored at an 8
* byte boundary.
**/
@ -98,8 +98,6 @@ int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev)
ret = -ENOMEM;
goto error_ret;
}
/* Effectively select the ring buffer implementation */
indio_dev->buffer->access = &ring_sw_access_funcs;
indio_dev->pollfunc
= iio_alloc_pollfunc(NULL,
&ad7476_trigger_handler,

View File

@ -197,7 +197,7 @@ static IIO_DEVICE_ATTR(oversampling_ratio, S_IRUGO | S_IWUSR,
ad7606_store_oversampling_ratio, 0);
static IIO_CONST_ATTR(oversampling_ratio_available, "0 2 4 8 16 32 64");
static struct attribute *ad7606_attributes[] = {
static struct attribute *ad7606_attributes_os_and_range[] = {
&iio_dev_attr_in_voltage_range.dev_attr.attr,
&iio_const_attr_in_voltage_range_available.dev_attr.attr,
&iio_dev_attr_oversampling_ratio.dev_attr.attr,
@ -205,34 +205,28 @@ static struct attribute *ad7606_attributes[] = {
NULL,
};
static umode_t ad7606_attr_is_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad7606_state *st = iio_priv(indio_dev);
static const struct attribute_group ad7606_attribute_group_os_and_range = {
.attrs = ad7606_attributes_os_and_range,
};
umode_t mode = attr->mode;
static struct attribute *ad7606_attributes_os[] = {
&iio_dev_attr_oversampling_ratio.dev_attr.attr,
&iio_const_attr_oversampling_ratio_available.dev_attr.attr,
NULL,
};
if (!(gpio_is_valid(st->pdata->gpio_os0) &&
gpio_is_valid(st->pdata->gpio_os1) &&
gpio_is_valid(st->pdata->gpio_os2)) &&
(attr == &iio_dev_attr_oversampling_ratio.dev_attr.attr ||
attr ==
&iio_const_attr_oversampling_ratio_available.dev_attr.attr))
mode = 0;
else if (!gpio_is_valid(st->pdata->gpio_range) &&
(attr == &iio_dev_attr_in_voltage_range.dev_attr.attr ||
attr ==
&iio_const_attr_in_voltage_range_available.dev_attr.attr))
mode = 0;
static const struct attribute_group ad7606_attribute_group_os = {
.attrs = ad7606_attributes_os,
};
return mode;
}
static struct attribute *ad7606_attributes_range[] = {
&iio_dev_attr_in_voltage_range.dev_attr.attr,
&iio_const_attr_in_voltage_range_available.dev_attr.attr,
NULL,
};
static const struct attribute_group ad7606_attribute_group = {
.attrs = ad7606_attributes,
.is_visible = ad7606_attr_is_visible,
static const struct attribute_group ad7606_attribute_group_range = {
.attrs = ad7606_attributes_range,
};
#define AD7606_CHANNEL(num) \
@ -435,10 +429,27 @@ static irqreturn_t ad7606_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
};
static const struct iio_info ad7606_info = {
static const struct iio_info ad7606_info_no_os_or_range = {
.driver_module = THIS_MODULE,
.read_raw = &ad7606_read_raw,
.attrs = &ad7606_attribute_group,
};
static const struct iio_info ad7606_info_os_and_range = {
.driver_module = THIS_MODULE,
.read_raw = &ad7606_read_raw,
.attrs = &ad7606_attribute_group_os_and_range,
};
static const struct iio_info ad7606_info_os = {
.driver_module = THIS_MODULE,
.read_raw = &ad7606_read_raw,
.attrs = &ad7606_attribute_group_os,
};
static const struct iio_info ad7606_info_range = {
.driver_module = THIS_MODULE,
.read_raw = &ad7606_read_raw,
.attrs = &ad7606_attribute_group_range,
};
struct iio_dev *ad7606_probe(struct device *dev, int irq,
@ -483,7 +494,19 @@ struct iio_dev *ad7606_probe(struct device *dev, int irq,
st->chip_info = &ad7606_chip_info_tbl[id];
indio_dev->dev.parent = dev;
indio_dev->info = &ad7606_info;
if (gpio_is_valid(st->pdata->gpio_os0) &&
gpio_is_valid(st->pdata->gpio_os1) &&
gpio_is_valid(st->pdata->gpio_os2)) {
if (gpio_is_valid(st->pdata->gpio_range))
indio_dev->info = &ad7606_info_os_and_range;
else
indio_dev->info = &ad7606_info_os;
} else {
if (gpio_is_valid(st->pdata->gpio_range))
indio_dev->info = &ad7606_info_range;
else
indio_dev->info = &ad7606_info_no_os_or_range;
}
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->name = st->chip_info->name;
indio_dev->channels = st->chip_info->channels;

View File

@ -173,18 +173,7 @@ static struct platform_driver ad7606_driver = {
},
};
static int __init ad7606_init(void)
{
return platform_driver_register(&ad7606_driver);
}
static void __exit ad7606_cleanup(void)
{
platform_driver_unregister(&ad7606_driver);
}
module_init(ad7606_init);
module_exit(ad7606_cleanup);
module_platform_driver(ad7606_driver);
MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>");
MODULE_DESCRIPTION("Analog Devices AD7606 ADC");

View File

@ -110,8 +110,6 @@ int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev)
goto error_ret;
}
/* Effectively select the ring buffer implementation */
indio_dev->buffer->access = &ring_sw_access_funcs;
indio_dev->pollfunc = iio_alloc_pollfunc(&ad7606_trigger_handler_th_bh,
&ad7606_trigger_handler_th_bh,
0,

View File

@ -427,8 +427,6 @@ static int ad7793_register_ring_funcs_and_init(struct iio_dev *indio_dev)
ret = -ENOMEM;
goto error_ret;
}
/* Effectively select the ring buffer implementation */
indio_dev->buffer->access = &ring_sw_access_funcs;
indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
&ad7793_trigger_handler,
IRQF_ONESHOT,

View File

@ -131,8 +131,6 @@ int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev)
ret = -ENOMEM;
goto error_ret;
}
/* Effectively select the ring buffer implementation */
indio_dev->buffer->access = &ring_sw_access_funcs;
indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
&ad7887_trigger_handler,
IRQF_ONESHOT,

View File

@ -256,7 +256,7 @@ static int ad799x_write_event_value(struct iio_dev *indio_dev,
struct ad799x_state *st = iio_priv(indio_dev);
int direction = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
IIO_EV_DIR_FALLING);
int number = IIO_EVENT_CODE_EXTRACT_NUM(event_code);
int number = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
mutex_lock(&indio_dev->mlock);
ret = ad799x_i2c_write16(st,
@ -275,7 +275,7 @@ static int ad799x_read_event_value(struct iio_dev *indio_dev,
struct ad799x_state *st = iio_priv(indio_dev);
int direction = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
IIO_EV_DIR_FALLING);
int number = IIO_EVENT_CODE_EXTRACT_NUM(event_code);
int number = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
u16 valin;
mutex_lock(&indio_dev->mlock);

View File

@ -26,7 +26,7 @@
/**
* ad799x_ring_preenable() setup the parameters of the ring before enabling
*
* The complex nature of the setting of the nuber of bytes per datum is due
* The complex nature of the setting of the number of bytes per datum is due
* to this driver currently ensuring that the timestamp is stored at an 8
* byte boundary.
**/
@ -141,8 +141,6 @@ int ad799x_register_ring_funcs_and_init(struct iio_dev *indio_dev)
ret = -ENOMEM;
goto error_ret;
}
/* Effectively select the ring buffer implementation */
indio_dev->buffer->access = &ring_sw_access_funcs;
indio_dev->pollfunc = iio_alloc_pollfunc(NULL,
&ad799x_trigger_handler,
IRQF_ONESHOT,

View File

@ -725,32 +725,19 @@ static struct attribute *adt7310_event_int_attributes[] = {
&iio_dev_attr_fault_queue.dev_attr.attr,
&iio_dev_attr_t_alarm_high.dev_attr.attr,
&iio_dev_attr_t_alarm_low.dev_attr.attr,
&iio_dev_attr_t_hyst.dev_attr.attr,
NULL,
};
static struct attribute *adt7310_event_ct_attributes[] = {
&iio_dev_attr_event_mode.dev_attr.attr,
&iio_dev_attr_available_event_modes.dev_attr.attr,
&iio_dev_attr_fault_queue.dev_attr.attr,
&iio_dev_attr_t_crit.dev_attr.attr,
&iio_dev_attr_t_hyst.dev_attr.attr,
NULL,
};
static struct attribute_group adt7310_event_attribute_group[ADT7310_IRQS] = {
{
.attrs = adt7310_event_int_attributes,
.name = "events",
}, {
.attrs = adt7310_event_ct_attributes,
.name = "events",
}
static struct attribute_group adt7310_event_attribute_group = {
.attrs = adt7310_event_int_attributes,
.name = "events",
};
static const struct iio_info adt7310_info = {
.attrs = &adt7310_attribute_group,
.event_attrs = adt7310_event_attribute_group,
.event_attrs = &adt7310_event_attribute_group,
.driver_module = THIS_MODULE,
};

View File

@ -693,32 +693,19 @@ static struct attribute *adt7410_event_int_attributes[] = {
&iio_dev_attr_fault_queue.dev_attr.attr,
&iio_dev_attr_t_alarm_high.dev_attr.attr,
&iio_dev_attr_t_alarm_low.dev_attr.attr,
&iio_dev_attr_t_hyst.dev_attr.attr,
NULL,
};
static struct attribute *adt7410_event_ct_attributes[] = {
&iio_dev_attr_event_mode.dev_attr.attr,
&iio_dev_attr_available_event_modes.dev_attr.attr,
&iio_dev_attr_fault_queue.dev_attr.attr,
&iio_dev_attr_t_crit.dev_attr.attr,
&iio_dev_attr_t_hyst.dev_attr.attr,
NULL,
};
static struct attribute_group adt7410_event_attribute_group[ADT7410_IRQS] = {
{
.attrs = adt7410_event_int_attributes,
.name = "events",
}, {
.attrs = adt7410_event_ct_attributes,
.name = "events",
}
static struct attribute_group adt7410_event_attribute_group = {
.attrs = adt7410_event_int_attributes,
.name = "events",
};
static const struct iio_info adt7410_info = {
.attrs = &adt7410_attribute_group,
.event_attrs = adt7410_event_attribute_group,
.event_attrs = &adt7410_event_attribute_group,
.driver_module = THIS_MODULE,
};

View File

@ -0,0 +1,237 @@
/*
* lpc32xx_adc.c - Support for ADC in LPC32XX
*
* 3-channel, 10-bit ADC
*
* Copyright (C) 2011, 2012 Roland Stigge <stigge@antcom.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.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/completion.h>
#include "../iio.h"
#include "../sysfs.h"
/*
* LPC32XX registers definitions
*/
#define LPC32XX_ADC_SELECT(x) ((x) + 0x04)
#define LPC32XX_ADC_CTRL(x) ((x) + 0x08)
#define LPC32XX_ADC_VALUE(x) ((x) + 0x48)
/* Bit definitions for LPC32XX_ADC_SELECT: */
#define AD_REFm 0x00000200 /* constant, always write this value! */
#define AD_REFp 0x00000080 /* constant, always write this value! */
#define AD_IN 0x00000010 /* multiple of this is the */
/* channel number: 0, 1, 2 */
#define AD_INTERNAL 0x00000004 /* constant, always write this value! */
/* Bit definitions for LPC32XX_ADC_CTRL: */
#define AD_STROBE 0x00000002
#define AD_PDN_CTRL 0x00000004
/* Bit definitions for LPC32XX_ADC_VALUE: */
#define ADC_VALUE_MASK 0x000003FF
#define MOD_NAME "lpc32xx-adc"
struct lpc32xx_adc_info {
void __iomem *adc_base;
struct clk *clk;
struct completion completion;
u32 value;
};
static int lpc32xx_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int *val,
int *val2,
long mask)
{
struct lpc32xx_adc_info *info = iio_priv(indio_dev);
if (mask == 0) {
mutex_lock(&indio_dev->mlock);
clk_enable(info->clk);
/* Measurement setup */
__raw_writel(AD_INTERNAL | (chan->address) | AD_REFp | AD_REFm,
LPC32XX_ADC_SELECT(info->adc_base));
/* Trigger conversion */
__raw_writel(AD_PDN_CTRL | AD_STROBE,
LPC32XX_ADC_CTRL(info->adc_base));
wait_for_completion(&info->completion); /* set by ISR */
clk_disable(info->clk);
*val = info->value;
mutex_unlock(&indio_dev->mlock);
return IIO_VAL_INT;
}
return -EINVAL;
}
static const struct iio_info lpc32xx_adc_iio_info = {
.read_raw = &lpc32xx_read_raw,
.driver_module = THIS_MODULE,
};
#define LPC32XX_ADC_CHANNEL(_index) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.channel = _index, \
.address = AD_IN * _index, \
.scan_index = _index, \
}
static struct iio_chan_spec lpc32xx_adc_iio_channels[] = {
LPC32XX_ADC_CHANNEL(0),
LPC32XX_ADC_CHANNEL(1),
LPC32XX_ADC_CHANNEL(2),
};
static irqreturn_t lpc32xx_adc_isr(int irq, void *dev_id)
{
struct lpc32xx_adc_info *info = (struct lpc32xx_adc_info *) dev_id;
/* Read value and clear irq */
info->value = __raw_readl(LPC32XX_ADC_VALUE(info->adc_base)) &
ADC_VALUE_MASK;
complete(&info->completion);
return IRQ_HANDLED;
}
static int __devinit lpc32xx_adc_probe(struct platform_device *pdev)
{
struct lpc32xx_adc_info *info = NULL;
struct resource *res;
int retval = -ENODEV;
struct iio_dev *iodev = NULL;
int irq;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
dev_err(&pdev->dev, "failed to get platform I/O memory\n");
retval = -EBUSY;
goto errout1;
}
iodev = iio_allocate_device(sizeof(struct lpc32xx_adc_info));
if (!iodev) {
dev_err(&pdev->dev, "failed allocating iio device\n");
retval = -ENOMEM;
goto errout1;
}
info = iio_priv(iodev);
info->adc_base = ioremap(res->start, res->end - res->start + 1);
if (!info->adc_base) {
dev_err(&pdev->dev, "failed mapping memory\n");
retval = -EBUSY;
goto errout2;
}
info->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(info->clk)) {
dev_err(&pdev->dev, "failed getting clock\n");
goto errout3;
}
irq = platform_get_irq(pdev, 0);
if ((irq < 0) || (irq >= NR_IRQS)) {
dev_err(&pdev->dev, "failed getting interrupt resource\n");
retval = -EINVAL;
goto errout4;
}
retval = request_irq(irq, lpc32xx_adc_isr, 0, MOD_NAME, info);
if (retval < 0) {
dev_err(&pdev->dev, "failed requesting interrupt\n");
goto errout4;
}
platform_set_drvdata(pdev, iodev);
init_completion(&info->completion);
iodev->name = MOD_NAME;
iodev->dev.parent = &pdev->dev;
iodev->info = &lpc32xx_adc_iio_info;
iodev->modes = INDIO_DIRECT_MODE;
iodev->channels = lpc32xx_adc_iio_channels;
iodev->num_channels = ARRAY_SIZE(lpc32xx_adc_iio_channels);
retval = iio_device_register(iodev);
if (retval)
goto errout5;
dev_info(&pdev->dev, "LPC32XX ADC driver loaded, IRQ %d\n", irq);
return 0;
errout5:
free_irq(irq, iodev);
errout4:
clk_put(info->clk);
errout3:
iounmap(info->adc_base);
errout2:
iio_free_device(iodev);
errout1:
return retval;
}
static int __devexit lpc32xx_adc_remove(struct platform_device *pdev)
{
struct iio_dev *iodev = platform_get_drvdata(pdev);
struct lpc32xx_adc_info *info = iio_priv(iodev);
int irq = platform_get_irq(pdev, 0);
iio_device_unregister(iodev);
free_irq(irq, iodev);
platform_set_drvdata(pdev, NULL);
clk_put(info->clk);
iounmap(info->adc_base);
iio_free_device(iodev);
return 0;
}
static struct platform_driver lpc32xx_adc_driver = {
.probe = lpc32xx_adc_probe,
.remove = __devexit_p(lpc32xx_adc_remove),
.driver = {
.name = MOD_NAME,
.owner = THIS_MODULE,
},
};
module_platform_driver(lpc32xx_adc_driver);
MODULE_AUTHOR("Roland Stigge <stigge@antcom.de>");
MODULE_DESCRIPTION("LPC32XX ADC driver");
MODULE_LICENSE("GPL");

View File

@ -341,7 +341,7 @@ static struct iio_chan_spec max1361_channels[] =
static struct iio_chan_spec max1363_channels[] =
MAX1363_4X_CHANS(12, MAX1363_EV_M);
/* Appies to max1236, max1237 */
/* Applies to max1236, max1237 */
static const enum max1363_modes max1236_mode_list[] = {
_s0, _s1, _s2, _s3,
s0to1, s0to2, s0to3,
@ -543,9 +543,9 @@ static int max1363_read_thresh(struct iio_dev *indio_dev,
{
struct max1363_state *st = iio_priv(indio_dev);
if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING)
*val = st->thresh_low[IIO_EVENT_CODE_EXTRACT_NUM(event_code)];
*val = st->thresh_low[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)];
else
*val = st->thresh_high[IIO_EVENT_CODE_EXTRACT_NUM(event_code)];
*val = st->thresh_high[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)];
return 0;
}
@ -568,10 +568,10 @@ static int max1363_write_thresh(struct iio_dev *indio_dev,
switch (IIO_EVENT_CODE_EXTRACT_DIR(event_code)) {
case IIO_EV_DIR_FALLING:
st->thresh_low[IIO_EVENT_CODE_EXTRACT_NUM(event_code)] = val;
st->thresh_low[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)] = val;
break;
case IIO_EV_DIR_RISING:
st->thresh_high[IIO_EVENT_CODE_EXTRACT_NUM(event_code)] = val;
st->thresh_high[IIO_EVENT_CODE_EXTRACT_CHAN(event_code)] = val;
break;
}
@ -622,7 +622,7 @@ static int max1363_read_event_config(struct iio_dev *indio_dev,
struct max1363_state *st = iio_priv(indio_dev);
int val;
int number = IIO_EVENT_CODE_EXTRACT_NUM(event_code);
int number = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
mutex_lock(&indio_dev->mlock);
if (IIO_EVENT_CODE_EXTRACT_DIR(event_code) == IIO_EV_DIR_FALLING)
val = (1 << number) & st->mask_low;
@ -775,7 +775,7 @@ static int max1363_write_event_config(struct iio_dev *indio_dev,
int ret = 0;
struct max1363_state *st = iio_priv(indio_dev);
u16 unifiedmask;
int number = IIO_EVENT_CODE_EXTRACT_NUM(event_code);
int number = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
mutex_lock(&indio_dev->mlock);
unifiedmask = st->mask_low | st->mask_high;
@ -1245,10 +1245,31 @@ static int max1363_initial_setup(struct max1363_state *st)
return max1363_set_scan_mode(st);
}
static int __devinit max1363_alloc_scan_masks(struct iio_dev *indio_dev)
{
struct max1363_state *st = iio_priv(indio_dev);
unsigned long *masks;
int i;
masks = kzalloc(BITS_TO_LONGS(MAX1363_MAX_CHANNELS)*sizeof(long)*
(st->chip_info->num_modes + 1), GFP_KERNEL);
if (!masks)
return -ENOMEM;
for (i = 0; i < st->chip_info->num_modes; i++)
bitmap_copy(masks + BITS_TO_LONGS(MAX1363_MAX_CHANNELS)*i,
max1363_mode_table[st->chip_info->mode_list[i]]
.modemask, MAX1363_MAX_CHANNELS);
indio_dev->available_scan_masks = masks;
return 0;
}
static int __devinit max1363_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int ret, i;
int ret;
struct max1363_state *st;
struct iio_dev *indio_dev;
struct regulator *reg;
@ -1276,19 +1297,10 @@ static int __devinit max1363_probe(struct i2c_client *client,
st->chip_info = &max1363_chip_info_tbl[id->driver_data];
st->client = client;
indio_dev->available_scan_masks
= kzalloc(BITS_TO_LONGS(MAX1363_MAX_CHANNELS)*sizeof(long)*
(st->chip_info->num_modes + 1), GFP_KERNEL);
if (!indio_dev->available_scan_masks) {
ret = -ENOMEM;
ret = max1363_alloc_scan_masks(indio_dev);
if (ret)
goto error_free_device;
}
for (i = 0; i < st->chip_info->num_modes; i++)
bitmap_copy(indio_dev->available_scan_masks +
BITS_TO_LONGS(MAX1363_MAX_CHANNELS)*i,
max1363_mode_table[st->chip_info->mode_list[i]]
.modemask, MAX1363_MAX_CHANNELS);
/* Estabilish that the iio_dev is a child of the i2c device */
indio_dev->dev.parent = &client->dev;
indio_dev->name = id->name;

View File

@ -116,8 +116,6 @@ int max1363_register_ring_funcs_and_init(struct iio_dev *indio_dev)
ret = -ENOMEM;
goto error_deallocate_sw_rb;
}
/* Effectively select the ring buffer implementation */
indio_dev->buffer->access = &ring_sw_access_funcs;
/* Ring buffer functions - here trigger setup related */
indio_dev->setup_ops = &max1363_ring_setup_ops;

View File

@ -125,30 +125,14 @@ static const struct i2c_device_id adt7316_i2c_id[] = {
MODULE_DEVICE_TABLE(i2c, adt7316_i2c_id);
#ifdef CONFIG_PM
static int adt7316_i2c_suspend(struct i2c_client *client, pm_message_t message)
{
return adt7316_disable(&client->dev);
}
static int adt7316_i2c_resume(struct i2c_client *client)
{
return adt7316_enable(&client->dev);
}
#else
# define adt7316_i2c_suspend NULL
# define adt7316_i2c_resume NULL
#endif
static struct i2c_driver adt7316_driver = {
.driver = {
.name = "adt7316",
.pm = ADT7316_PM_OPS,
.owner = THIS_MODULE,
},
.probe = adt7316_i2c_probe,
.remove = __devexit_p(adt7316_i2c_remove),
.suspend = adt7316_i2c_suspend,
.resume = adt7316_i2c_resume,
.id_table = adt7316_i2c_id,
};
module_i2c_driver(adt7316_driver);

View File

@ -133,30 +133,14 @@ static const struct spi_device_id adt7316_spi_id[] = {
MODULE_DEVICE_TABLE(spi, adt7316_spi_id);
#ifdef CONFIG_PM
static int adt7316_spi_suspend(struct spi_device *spi_dev, pm_message_t message)
{
return adt7316_disable(&spi_dev->dev);
}
static int adt7316_spi_resume(struct spi_device *spi_dev)
{
return adt7316_enable(&spi_dev->dev);
}
#else
# define adt7316_spi_suspend NULL
# define adt7316_spi_resume NULL
#endif
static struct spi_driver adt7316_driver = {
.driver = {
.name = "adt7316",
.pm = ADT7316_PM_OPS,
.owner = THIS_MODULE,
},
.probe = adt7316_spi_probe,
.remove = __devexit_p(adt7316_spi_remove),
.suspend = adt7316_spi_suspend,
.resume = adt7316_spi_resume,
.id_table = adt7316_spi_id,
};
module_spi_driver(adt7316_driver);

View File

@ -2089,24 +2089,25 @@ static struct attribute_group adt7516_event_attribute_group = {
.name = "events",
};
#ifdef CONFIG_PM
int adt7316_disable(struct device *dev)
#ifdef CONFIG_PM_SLEEP
static int adt7316_disable(struct device *dev)
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return _adt7316_store_enabled(chip, 0);
}
EXPORT_SYMBOL(adt7316_disable);
int adt7316_enable(struct device *dev)
static int adt7316_enable(struct device *dev)
{
struct iio_dev *dev_info = dev_get_drvdata(dev);
struct adt7316_chip_info *chip = iio_priv(dev_info);
return _adt7316_store_enabled(chip, 1);
}
EXPORT_SYMBOL(adt7316_enable);
SIMPLE_DEV_PM_OPS(adt7316_pm_ops, adt7316_disable, adt7316_enable);
EXPORT_SYMBOL_GPL(adt7316_pm_ops);
#endif
static const struct iio_info adt7316_info = {

View File

@ -10,6 +10,7 @@
#define _ADT7316_H_
#include <linux/types.h>
#include <linux/pm.h>
#define ADT7316_REG_MAX_ADDR 0x3F
@ -23,9 +24,11 @@ struct adt7316_bus {
int (*multi_write) (void *client, u8 first_reg, u8 count, u8 *data);
};
#ifdef CONFIG_PM
int adt7316_disable(struct device *dev);
int adt7316_enable(struct device *dev);
#ifdef CONFIG_PM_SLEEP
extern const struct dev_pm_ops adt7316_pm_ops;
#define ADT7316_PM_OPS (&adt7316_pm_ops)
#else
#define ADT7316_PM_OPS NULL
#endif
int adt7316_probe(struct device *dev, struct adt7316_bus *bus, const char *name);
int adt7316_remove(struct device *dev);

View File

@ -91,8 +91,6 @@ struct iio_buffer {
**/
void iio_buffer_init(struct iio_buffer *buffer);
void iio_buffer_deinit(struct iio_buffer *buffer);
/**
* __iio_update_buffer() - update common elements of buffers
* @buffer: buffer that is the event source

View File

@ -167,7 +167,7 @@ static int ad7150_write_event_params(struct iio_dev *indio_dev, u64 event_code)
u16 value;
u8 sens, timeout;
struct ad7150_chip_info *chip = iio_priv(indio_dev);
int chan = IIO_EVENT_CODE_EXTRACT_NUM(event_code);
int chan = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
IIO_EV_DIR_RISING);
@ -279,7 +279,7 @@ static int ad7150_read_event_value(struct iio_dev *indio_dev,
u64 event_code,
int *val)
{
int chan = IIO_EVENT_CODE_EXTRACT_NUM(event_code);
int chan = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
struct ad7150_chip_info *chip = iio_priv(indio_dev);
int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
IIO_EV_DIR_RISING);
@ -309,7 +309,7 @@ static int ad7150_write_event_value(struct iio_dev *indio_dev,
{
int ret;
struct ad7150_chip_info *chip = iio_priv(indio_dev);
int chan = IIO_EVENT_CODE_EXTRACT_NUM(event_code);
int chan = IIO_EVENT_CODE_EXTRACT_CHAN(event_code);
int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(event_code) ==
IIO_EV_DIR_RISING);
@ -347,7 +347,7 @@ static ssize_t ad7150_show_timeout(struct device *dev,
u8 value;
/* use the event code for consistency reasons */
int chan = IIO_EVENT_CODE_EXTRACT_NUM(this_attr->address);
int chan = IIO_EVENT_CODE_EXTRACT_CHAN(this_attr->address);
int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(this_attr->address)
== IIO_EV_DIR_RISING);
@ -373,7 +373,7 @@ static ssize_t ad7150_store_timeout(struct device *dev,
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad7150_chip_info *chip = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
int chan = IIO_EVENT_CODE_EXTRACT_NUM(this_attr->address);
int chan = IIO_EVENT_CODE_EXTRACT_CHAN(this_attr->address);
int rising = !!(IIO_EVENT_CODE_EXTRACT_DIR(this_attr->address) ==
IIO_EV_DIR_RISING);
u8 data;

View File

@ -0,0 +1,96 @@
/*
* Industrial I/O in kernel consumer interface
*
* Copyright (c) 2011 Jonathan Cameron
*
* 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 _IIO_INKERN_CONSUMER_H_
#define _IIO_INKERN_CONSUMER_H
#include "types.h"
struct iio_dev;
struct iio_chan_spec;
/**
* struct iio_channel - everything needed for a consumer to use a channel
* @indio_dev: Device on which the channel exists.
* @channel: Full description of the channel.
*/
struct iio_channel {
struct iio_dev *indio_dev;
const struct iio_chan_spec *channel;
};
/**
* iio_channel_get() - get description of all that is needed to access channel.
* @name: Unique name of the device as provided in the iio_map
* with which the desired provider to consumer mapping
* was registered.
* @consumer_channel: Unique name to identify the channel on the consumer
* side. This typically describes the channels use within
* the consumer. E.g. 'battery_voltage'
*/
struct iio_channel *iio_st_channel_get(const char *name,
const char *consumer_channel);
/**
* iio_st_channel_release() - release channels obtained via iio_st_channel_get
* @chan: The channel to be released.
*/
void iio_st_channel_release(struct iio_channel *chan);
/**
* iio_st_channel_get_all() - get all channels associated with a client
* @name: name of consumer device.
*
* Returns an array of iio_channel structures terminated with one with
* null iio_dev pointer.
* This function is used by fairly generic consumers to get all the
* channels registered as having this consumer.
*/
struct iio_channel *iio_st_channel_get_all(const char *name);
/**
* iio_st_channel_release_all() - reverse iio_st_get_all
* @chan: Array of channels to be released.
*/
void iio_st_channel_release_all(struct iio_channel *chan);
/**
* iio_st_read_channel_raw() - read from a given channel
* @channel: The channel being queried.
* @val: Value read back.
*
* Note raw reads from iio channels are in adc counts and hence
* scale will need to be applied if standard units required.
*/
int iio_st_read_channel_raw(struct iio_channel *chan,
int *val);
/**
* iio_st_get_channel_type() - get the type of a channel
* @channel: The channel being queried.
* @type: The type of the channel.
*
* returns the enum iio_chan_type of the channel
*/
int iio_st_get_channel_type(struct iio_channel *channel,
enum iio_chan_type *type);
/**
* iio_st_read_channel_scale() - read the scale value for a channel
* @channel: The channel being queried.
* @val: First part of value read back.
* @val2: Second part of value read back.
*
* Note returns a description of what is in val and val2, such
* as IIO_VAL_INT_PLUS_MICRO telling us we have a value of val
* + val2/1e6
*/
int iio_st_read_channel_scale(struct iio_channel *chan, int *val,
int *val2);
#endif

View File

@ -4,11 +4,12 @@
menu "Digital to analog converters"
config AD5064
tristate "Analog Devices AD5064/64-1/44/24 DAC driver"
tristate "Analog Devices AD5064/64-1/65/44/45/24/25, AD5628/48/66/68 DAC driver"
depends on SPI
help
Say yes here to build support for Analog Devices AD5064, AD5064-1,
AD5044, AD5024 Digital to Analog Converter.
Say yes here to build support for Analog Devices AD5024, AD5025, AD5044,
AD5045, AD5064, AD5064-1, AD5065, AD5628, AD5648, AD5666, AD5668 Digital
to Analog Converter.
To compile this driver as a module, choose M here: the
module will be called ad5064.

View File

@ -1,5 +1,6 @@
/*
* AD5064, AD5064-1, AD5044, AD5024 Digital to analog converters driver
* AD5024, AD5025, AD5044, AD5045, AD5064, AD5064-1, AD5065, AD5628, AD5648,
* AD5666, AD5668 Digital to analog converters driver
*
* Copyright 2011 Analog Devices Inc.
*
@ -19,7 +20,8 @@
#include "../sysfs.h"
#include "dac.h"
#define AD5064_DAC_CHANNELS 4
#define AD5064_MAX_DAC_CHANNELS 8
#define AD5064_MAX_VREFS 4
#define AD5064_ADDR(x) ((x) << 20)
#define AD5064_CMD(x) ((x) << 24)
@ -35,7 +37,10 @@
#define AD5064_CMD_CLEAR 0x5
#define AD5064_CMD_LDAC_MASK 0x6
#define AD5064_CMD_RESET 0x7
#define AD5064_CMD_DAISY_CHAIN_ENABLE 0x8
#define AD5064_CMD_CONFIG 0x8
#define AD5064_CONFIG_DAISY_CHAIN_ENABLE BIT(1)
#define AD5064_CONFIG_INT_VREF_ENABLE BIT(0)
#define AD5064_LDAC_PWRDN_NONE 0x0
#define AD5064_LDAC_PWRDN_1K 0x1
@ -45,12 +50,17 @@
/**
* struct ad5064_chip_info - chip specific information
* @shared_vref: whether the vref supply is shared between channels
* @internal_vref: internal reference voltage. 0 if the chip has no internal
* vref.
* @channel: channel specification
*/
* @num_channels: number of channels
*/
struct ad5064_chip_info {
bool shared_vref;
struct iio_chan_spec channel[AD5064_DAC_CHANNELS];
unsigned long internal_vref;
const struct iio_chan_spec *channels;
unsigned int num_channels;
};
/**
@ -61,16 +71,19 @@ struct ad5064_chip_info {
* @pwr_down: whether channel is powered down
* @pwr_down_mode: channel's current power down mode
* @dac_cache: current DAC raw value (chip does not support readback)
* @use_internal_vref: set to true if the internal reference voltage should be
* used.
* @data: spi transfer buffers
*/
struct ad5064_state {
struct spi_device *spi;
const struct ad5064_chip_info *chip_info;
struct regulator_bulk_data vref_reg[AD5064_DAC_CHANNELS];
bool pwr_down[AD5064_DAC_CHANNELS];
u8 pwr_down_mode[AD5064_DAC_CHANNELS];
unsigned int dac_cache[AD5064_DAC_CHANNELS];
struct regulator_bulk_data vref_reg[AD5064_MAX_VREFS];
bool pwr_down[AD5064_MAX_DAC_CHANNELS];
u8 pwr_down_mode[AD5064_MAX_DAC_CHANNELS];
unsigned int dac_cache[AD5064_MAX_DAC_CHANNELS];
bool use_internal_vref;
/*
* DMA (thus cache coherency maintenance) requires the
@ -81,50 +94,20 @@ struct ad5064_state {
enum ad5064_type {
ID_AD5024,
ID_AD5025,
ID_AD5044,
ID_AD5045,
ID_AD5064,
ID_AD5064_1,
};
#define AD5064_CHANNEL(chan, bits) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.channel = (chan), \
.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
.address = AD5064_ADDR_DAC(chan), \
.scan_type = IIO_ST('u', (bits), 16, 20 - (bits)) \
}
static const struct ad5064_chip_info ad5064_chip_info_tbl[] = {
[ID_AD5024] = {
.shared_vref = false,
.channel[0] = AD5064_CHANNEL(0, 12),
.channel[1] = AD5064_CHANNEL(1, 12),
.channel[2] = AD5064_CHANNEL(2, 12),
.channel[3] = AD5064_CHANNEL(3, 12),
},
[ID_AD5044] = {
.shared_vref = false,
.channel[0] = AD5064_CHANNEL(0, 14),
.channel[1] = AD5064_CHANNEL(1, 14),
.channel[2] = AD5064_CHANNEL(2, 14),
.channel[3] = AD5064_CHANNEL(3, 14),
},
[ID_AD5064] = {
.shared_vref = false,
.channel[0] = AD5064_CHANNEL(0, 16),
.channel[1] = AD5064_CHANNEL(1, 16),
.channel[2] = AD5064_CHANNEL(2, 16),
.channel[3] = AD5064_CHANNEL(3, 16),
},
[ID_AD5064_1] = {
.shared_vref = true,
.channel[0] = AD5064_CHANNEL(0, 16),
.channel[1] = AD5064_CHANNEL(1, 16),
.channel[2] = AD5064_CHANNEL(2, 16),
.channel[3] = AD5064_CHANNEL(3, 16),
},
ID_AD5065,
ID_AD5628_1,
ID_AD5628_2,
ID_AD5648_1,
ID_AD5648_2,
ID_AD5666_1,
ID_AD5666_2,
ID_AD5668_1,
ID_AD5668_2,
};
static int ad5064_spi_write(struct ad5064_state *st, unsigned int cmd,
@ -160,22 +143,25 @@ static const char ad5064_powerdown_modes[][15] = {
[AD5064_LDAC_PWRDN_3STATE] = "three_state",
};
static ssize_t ad5064_read_powerdown_mode(struct device *dev,
struct device_attribute *attr, char *buf)
static ssize_t ad5064_read_powerdown_mode_available(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, char *buf)
{
return sprintf(buf, "%s %s %s\n", ad5064_powerdown_modes[1],
ad5064_powerdown_modes[2], ad5064_powerdown_modes[3]);
}
static ssize_t ad5064_read_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, char *buf)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad5064_state *st = iio_priv(indio_dev);
return sprintf(buf, "%s\n",
ad5064_powerdown_modes[st->pwr_down_mode[this_attr->address]]);
ad5064_powerdown_modes[st->pwr_down_mode[chan->channel]]);
}
static ssize_t ad5064_write_powerdown_mode(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
static ssize_t ad5064_write_powerdown_mode(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, const char *buf, size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad5064_state *st = iio_priv(indio_dev);
unsigned int mode, i;
int ret;
@ -192,31 +178,26 @@ static ssize_t ad5064_write_powerdown_mode(struct device *dev,
return -EINVAL;
mutex_lock(&indio_dev->mlock);
st->pwr_down_mode[this_attr->address] = mode;
st->pwr_down_mode[chan->channel] = mode;
ret = ad5064_sync_powerdown_mode(st, this_attr->address);
ret = ad5064_sync_powerdown_mode(st, chan->channel);
mutex_unlock(&indio_dev->mlock);
return ret ? ret : len;
}
static ssize_t ad5064_read_dac_powerdown(struct device *dev,
struct device_attribute *attr,
char *buf)
static ssize_t ad5064_read_dac_powerdown(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, char *buf)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad5064_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
return sprintf(buf, "%d\n", st->pwr_down[this_attr->address]);
return sprintf(buf, "%d\n", st->pwr_down[chan->channel]);
}
static ssize_t ad5064_write_dac_powerdown(struct device *dev,
struct device_attribute *attr, const char *buf, size_t len)
static ssize_t ad5064_write_dac_powerdown(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan, const char *buf, size_t len)
{
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad5064_state *st = iio_priv(indio_dev);
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
bool pwr_down;
int ret;
@ -225,53 +206,24 @@ static ssize_t ad5064_write_dac_powerdown(struct device *dev,
return ret;
mutex_lock(&indio_dev->mlock);
st->pwr_down[this_attr->address] = pwr_down;
st->pwr_down[chan->channel] = pwr_down;
ret = ad5064_sync_powerdown_mode(st, this_attr->address);
ret = ad5064_sync_powerdown_mode(st, chan->channel);
mutex_unlock(&indio_dev->mlock);
return ret ? ret : len;
}
static IIO_CONST_ATTR(out_voltage_powerdown_mode_available,
"1kohm_to_gnd 100kohm_to_gnd three_state");
static int ad5064_get_vref(struct ad5064_state *st,
struct iio_chan_spec const *chan)
{
unsigned int i;
#define IIO_DEV_ATTR_DAC_POWERDOWN_MODE(_chan) \
IIO_DEVICE_ATTR(out_voltage##_chan##_powerdown_mode, \
S_IRUGO | S_IWUSR, \
ad5064_read_powerdown_mode, \
ad5064_write_powerdown_mode, _chan);
if (st->use_internal_vref)
return st->chip_info->internal_vref;
#define IIO_DEV_ATTR_DAC_POWERDOWN(_chan) \
IIO_DEVICE_ATTR(out_voltage##_chan##_powerdown, \
S_IRUGO | S_IWUSR, \
ad5064_read_dac_powerdown, \
ad5064_write_dac_powerdown, _chan)
static IIO_DEV_ATTR_DAC_POWERDOWN(0);
static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(0);
static IIO_DEV_ATTR_DAC_POWERDOWN(1);
static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(1);
static IIO_DEV_ATTR_DAC_POWERDOWN(2);
static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(2);
static IIO_DEV_ATTR_DAC_POWERDOWN(3);
static IIO_DEV_ATTR_DAC_POWERDOWN_MODE(3);
static struct attribute *ad5064_attributes[] = {
&iio_dev_attr_out_voltage0_powerdown.dev_attr.attr,
&iio_dev_attr_out_voltage1_powerdown.dev_attr.attr,
&iio_dev_attr_out_voltage2_powerdown.dev_attr.attr,
&iio_dev_attr_out_voltage3_powerdown.dev_attr.attr,
&iio_dev_attr_out_voltage0_powerdown_mode.dev_attr.attr,
&iio_dev_attr_out_voltage1_powerdown_mode.dev_attr.attr,
&iio_dev_attr_out_voltage2_powerdown_mode.dev_attr.attr,
&iio_dev_attr_out_voltage3_powerdown_mode.dev_attr.attr,
&iio_const_attr_out_voltage_powerdown_mode_available.dev_attr.attr,
NULL,
};
static const struct attribute_group ad5064_attribute_group = {
.attrs = ad5064_attributes,
};
i = st->chip_info->shared_vref ? 0 : chan->channel;
return regulator_get_voltage(st->vref_reg[i].consumer);
}
static int ad5064_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
@ -280,7 +232,6 @@ static int ad5064_read_raw(struct iio_dev *indio_dev,
long m)
{
struct ad5064_state *st = iio_priv(indio_dev);
unsigned int vref;
int scale_uv;
switch (m) {
@ -288,8 +239,7 @@ static int ad5064_read_raw(struct iio_dev *indio_dev,
*val = st->dac_cache[chan->channel];
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
vref = st->chip_info->shared_vref ? 0 : chan->channel;
scale_uv = regulator_get_voltage(st->vref_reg[vref].consumer);
scale_uv = ad5064_get_vref(st, chan);
if (scale_uv < 0)
return scale_uv;
@ -331,13 +281,144 @@ static int ad5064_write_raw(struct iio_dev *indio_dev,
static const struct iio_info ad5064_info = {
.read_raw = ad5064_read_raw,
.write_raw = ad5064_write_raw,
.attrs = &ad5064_attribute_group,
.driver_module = THIS_MODULE,
};
static struct iio_chan_spec_ext_info ad5064_ext_info[] = {
{
.name = "powerdown",
.read = ad5064_read_dac_powerdown,
.write = ad5064_write_dac_powerdown,
},
{
.name = "powerdown_mode",
.read = ad5064_read_powerdown_mode,
.write = ad5064_write_powerdown_mode,
},
{
.name = "powerdown_mode_available",
.shared = true,
.read = ad5064_read_powerdown_mode_available,
},
{ },
};
#define AD5064_CHANNEL(chan, bits) { \
.type = IIO_VOLTAGE, \
.indexed = 1, \
.output = 1, \
.channel = (chan), \
.info_mask = IIO_CHAN_INFO_SCALE_SEPARATE_BIT, \
.address = AD5064_ADDR_DAC(chan), \
.scan_type = IIO_ST('u', (bits), 16, 20 - (bits)), \
.ext_info = ad5064_ext_info, \
}
#define DECLARE_AD5064_CHANNELS(name, bits) \
const struct iio_chan_spec name[] = { \
AD5064_CHANNEL(0, bits), \
AD5064_CHANNEL(1, bits), \
AD5064_CHANNEL(2, bits), \
AD5064_CHANNEL(3, bits), \
AD5064_CHANNEL(4, bits), \
AD5064_CHANNEL(5, bits), \
AD5064_CHANNEL(6, bits), \
AD5064_CHANNEL(7, bits), \
}
static DECLARE_AD5064_CHANNELS(ad5024_channels, 12);
static DECLARE_AD5064_CHANNELS(ad5044_channels, 14);
static DECLARE_AD5064_CHANNELS(ad5064_channels, 16);
static const struct ad5064_chip_info ad5064_chip_info_tbl[] = {
[ID_AD5024] = {
.shared_vref = false,
.channels = ad5024_channels,
.num_channels = 4,
},
[ID_AD5025] = {
.shared_vref = false,
.channels = ad5024_channels,
.num_channels = 2,
},
[ID_AD5044] = {
.shared_vref = false,
.channels = ad5044_channels,
.num_channels = 4,
},
[ID_AD5045] = {
.shared_vref = false,
.channels = ad5044_channels,
.num_channels = 2,
},
[ID_AD5064] = {
.shared_vref = false,
.channels = ad5064_channels,
.num_channels = 4,
},
[ID_AD5064_1] = {
.shared_vref = true,
.channels = ad5064_channels,
.num_channels = 4,
},
[ID_AD5065] = {
.shared_vref = false,
.channels = ad5064_channels,
.num_channels = 2,
},
[ID_AD5628_1] = {
.shared_vref = true,
.internal_vref = 2500000,
.channels = ad5024_channels,
.num_channels = 8,
},
[ID_AD5628_2] = {
.shared_vref = true,
.internal_vref = 5000000,
.channels = ad5024_channels,
.num_channels = 8,
},
[ID_AD5648_1] = {
.shared_vref = true,
.internal_vref = 2500000,
.channels = ad5044_channels,
.num_channels = 8,
},
[ID_AD5648_2] = {
.shared_vref = true,
.internal_vref = 5000000,
.channels = ad5044_channels,
.num_channels = 8,
},
[ID_AD5666_1] = {
.shared_vref = true,
.internal_vref = 2500000,
.channels = ad5064_channels,
.num_channels = 4,
},
[ID_AD5666_2] = {
.shared_vref = true,
.internal_vref = 5000000,
.channels = ad5064_channels,
.num_channels = 4,
},
[ID_AD5668_1] = {
.shared_vref = true,
.internal_vref = 2500000,
.channels = ad5064_channels,
.num_channels = 8,
},
[ID_AD5668_2] = {
.shared_vref = true,
.internal_vref = 5000000,
.channels = ad5064_channels,
.num_channels = 8,
},
};
static inline unsigned int ad5064_num_vref(struct ad5064_state *st)
{
return st->chip_info->shared_vref ? 1 : AD5064_DAC_CHANNELS;
return st->chip_info->shared_vref ? 1 : st->chip_info->num_channels;
}
static const char * const ad5064_vref_names[] = {
@ -376,14 +457,24 @@ static int __devinit ad5064_probe(struct spi_device *spi)
ret = regulator_bulk_get(&st->spi->dev, ad5064_num_vref(st),
st->vref_reg);
if (ret)
goto error_free;
if (ret) {
if (!st->chip_info->internal_vref)
goto error_free;
st->use_internal_vref = true;
ret = ad5064_spi_write(st, AD5064_CMD_CONFIG, 0,
AD5064_CONFIG_INT_VREF_ENABLE, 0);
if (ret) {
dev_err(&spi->dev, "Failed to enable internal vref: %d\n",
ret);
goto error_free;
}
} else {
ret = regulator_bulk_enable(ad5064_num_vref(st), st->vref_reg);
if (ret)
goto error_free_reg;
}
ret = regulator_bulk_enable(ad5064_num_vref(st), st->vref_reg);
if (ret)
goto error_free_reg;
for (i = 0; i < AD5064_DAC_CHANNELS; ++i) {
for (i = 0; i < st->chip_info->num_channels; ++i) {
st->pwr_down_mode[i] = AD5064_LDAC_PWRDN_1K;
st->dac_cache[i] = 0x8000;
}
@ -392,8 +483,8 @@ static int __devinit ad5064_probe(struct spi_device *spi)
indio_dev->name = spi_get_device_id(spi)->name;
indio_dev->info = &ad5064_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = st->chip_info->channel;
indio_dev->num_channels = AD5064_DAC_CHANNELS;
indio_dev->channels = st->chip_info->channels;
indio_dev->num_channels = st->chip_info->num_channels;
ret = iio_device_register(indio_dev);
if (ret)
@ -402,9 +493,11 @@ static int __devinit ad5064_probe(struct spi_device *spi)
return 0;
error_disable_reg:
regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg);
if (!st->use_internal_vref)
regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg);
error_free_reg:
regulator_bulk_free(ad5064_num_vref(st), st->vref_reg);
if (!st->use_internal_vref)
regulator_bulk_free(ad5064_num_vref(st), st->vref_reg);
error_free:
iio_free_device(indio_dev);
@ -419,8 +512,10 @@ static int __devexit ad5064_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg);
regulator_bulk_free(ad5064_num_vref(st), st->vref_reg);
if (!st->use_internal_vref) {
regulator_bulk_disable(ad5064_num_vref(st), st->vref_reg);
regulator_bulk_free(ad5064_num_vref(st), st->vref_reg);
}
iio_free_device(indio_dev);
@ -429,9 +524,21 @@ static int __devexit ad5064_remove(struct spi_device *spi)
static const struct spi_device_id ad5064_id[] = {
{"ad5024", ID_AD5024},
{"ad5025", ID_AD5025},
{"ad5044", ID_AD5044},
{"ad5045", ID_AD5045},
{"ad5064", ID_AD5064},
{"ad5064-1", ID_AD5064_1},
{"ad5065", ID_AD5065},
{"ad5628-1", ID_AD5628_1},
{"ad5628-2", ID_AD5628_2},
{"ad5648-1", ID_AD5648_1},
{"ad5648-2", ID_AD5648_2},
{"ad5666-1", ID_AD5666_1},
{"ad5666-2", ID_AD5666_2},
{"ad5668-1", ID_AD5668_1},
{"ad5668-2", ID_AD5668_2},
{"ad5668-3", ID_AD5668_2}, /* similar enough to ad5668-2 */
{}
};
MODULE_DEVICE_TABLE(spi, ad5064_id);
@ -448,5 +555,5 @@ static struct spi_driver ad5064_driver = {
module_spi_driver(ad5064_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Analog Devices AD5064/64-1/44/24 DAC");
MODULE_DESCRIPTION("Analog Devices AD5024/25/44/45/64/64-1/65, AD5628/48/66/68 DAC");
MODULE_LICENSE("GPL v2");

View File

@ -439,8 +439,8 @@ static int __devinit ad5360_alloc_channels(struct iio_dev *indio_dev)
struct iio_chan_spec *channels;
unsigned int i;
channels = kcalloc(sizeof(struct iio_chan_spec),
st->chip_info->num_channels, GFP_KERNEL);
channels = kcalloc(st->chip_info->num_channels,
sizeof(struct iio_chan_spec), GFP_KERNEL);
if (!channels)
return -ENOMEM;

View File

@ -363,8 +363,8 @@ static int __devinit ad5380_alloc_channels(struct iio_dev *indio_dev)
struct iio_chan_spec *channels;
unsigned int i;
channels = kcalloc(sizeof(struct iio_chan_spec),
st->chip_info->num_channels, GFP_KERNEL);
channels = kcalloc(st->chip_info->num_channels,
sizeof(struct iio_chan_spec), GFP_KERNEL);
if (!channels)
return -ENOMEM;

View File

@ -536,18 +536,7 @@ static struct spi_driver ad5421_driver = {
.probe = ad5421_probe,
.remove = __devexit_p(ad5421_remove),
};
static __init int ad5421_init(void)
{
return spi_register_driver(&ad5421_driver);
}
module_init(ad5421_init);
static __exit void ad5421_exit(void)
{
spi_unregister_driver(&ad5421_driver);
}
module_exit(ad5421_exit);
module_spi_driver(ad5421_driver);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("Analog Devices AD5421 DAC");

View File

@ -149,30 +149,8 @@ static struct attribute *ad5446_attributes[] = {
NULL,
};
static umode_t ad5446_attr_is_visible(struct kobject *kobj,
struct attribute *attr, int n)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct ad5446_state *st = iio_priv(indio_dev);
umode_t mode = attr->mode;
if (!st->chip_info->store_pwr_down &&
(attr == &iio_dev_attr_out_voltage0_powerdown.dev_attr.attr ||
attr == &iio_dev_attr_out_voltage_powerdown_mode.
dev_attr.attr ||
attr ==
&iio_const_attr_out_voltage_powerdown_mode_available.
dev_attr.attr))
mode = 0;
return mode;
}
static const struct attribute_group ad5446_attribute_group = {
.attrs = ad5446_attributes,
.is_visible = ad5446_attr_is_visible,
};
#define AD5446_CHANNEL(bits, storage, shift) { \
@ -321,6 +299,12 @@ static const struct iio_info ad5446_info = {
.driver_module = THIS_MODULE,
};
static const struct iio_info ad5446_info_no_pwr_down = {
.read_raw = ad5446_read_raw,
.write_raw = ad5446_write_raw,
.driver_module = THIS_MODULE,
};
static int __devinit ad5446_probe(struct spi_device *spi)
{
struct ad5446_state *st;
@ -350,10 +334,13 @@ static int __devinit ad5446_probe(struct spi_device *spi)
st->reg = reg;
st->spi = spi;
/* Estabilish that the iio_dev is a child of the spi device */
/* 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;
indio_dev->info = &ad5446_info;
if (st->chip_info->store_pwr_down)
indio_dev->info = &ad5446_info;
else
indio_dev->info = &ad5446_info_no_pwr_down;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->channels = &st->chip_info->channel;
indio_dev->num_channels = 1;

Some files were not shown because too many files have changed in this diff Show More