Merge tag 'staging-3.3-rc3' into staging-next
This was done to resolve some merge issues with the following files that had changed in both branches: drivers/staging/rtl8712/rtl871x_sta_mgt.c drivers/staging/tidspbridge/rmgr/drv_interface.c drivers/staging/zcache/zcache-main.c Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
commit
b91867f2ee
|
@ -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"
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -88,6 +88,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 +130,6 @@ source "drivers/staging/omapdrm/Kconfig"
|
|||
|
||||
source "drivers/staging/android/Kconfig"
|
||||
|
||||
source "drivers/staging/telephony/Kconfig"
|
||||
|
||||
endif # STAGING
|
||||
|
|
|
@ -34,8 +34,8 @@ 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 +55,4 @@ obj-$(CONFIG_INTEL_MEI) += mei/
|
|||
obj-$(CONFIG_MFD_NVEC) += nvec/
|
||||
obj-$(CONFIG_DRM_OMAP) += omapdrm/
|
||||
obj-$(CONFIG_ANDROID) += android/
|
||||
obj-$(CONFIG_PHONE) += telephony/
|
||||
|
|
|
@ -102,6 +102,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
|
||||
|
|
|
@ -6,3 +6,5 @@ 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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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);
|
||||
|
|
@ -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);
|
||||
|
|
@ -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
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -34,6 +34,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>
|
||||
|
||||
|
@ -82,7 +83,7 @@ task_notify_func(struct notifier_block *self, unsigned long val, void *data)
|
|||
|
||||
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;
|
||||
|
@ -134,25 +135,24 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
|
|||
}
|
||||
selected_oom_adj = min_adj;
|
||||
|
||||
read_lock(&tasklist_lock);
|
||||
for_each_process(p) {
|
||||
struct mm_struct *mm;
|
||||
struct signal_struct *sig;
|
||||
rcu_read_lock();
|
||||
for_each_process(tsk) {
|
||||
struct task_struct *p;
|
||||
int oom_adj;
|
||||
|
||||
task_lock(p);
|
||||
mm = p->mm;
|
||||
sig = p->signal;
|
||||
if (!mm || !sig) {
|
||||
task_unlock(p);
|
||||
if (tsk->flags & PF_KTHREAD)
|
||||
continue;
|
||||
}
|
||||
oom_adj = sig->oom_adj;
|
||||
|
||||
p = find_lock_task_mm(tsk);
|
||||
if (!p)
|
||||
continue;
|
||||
|
||||
oom_adj = p->signal->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;
|
||||
|
@ -183,12 +183,12 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -351,7 +351,7 @@ static int ram_console_driver_probe(struct platform_device *pdev)
|
|||
"%lx\n", res, pdev->num_resources, res ? res->flags : 0);
|
||||
return -ENXIO;
|
||||
}
|
||||
buffer_size = res->end - res->start + 1;
|
||||
buffer_size = resource_size(res);
|
||||
start = res->start;
|
||||
printk(KERN_INFO "ram_console: got buffer at %zx, size %zx\n",
|
||||
start, buffer_size);
|
||||
|
@ -411,15 +411,14 @@ static int __init ram_console_late_init(void)
|
|||
if (ram_console_old_log == NULL)
|
||||
return 0;
|
||||
#ifdef CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT
|
||||
ram_console_old_log = kmalloc(ram_console_old_log_size, GFP_KERNEL);
|
||||
ram_console_old_log = kmemdup(ram_console_old_log_init_buffer,
|
||||
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;
|
||||
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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
@ -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,41 @@ 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. */
|
||||
} 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*/
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 |
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -868,8 +868,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;
|
||||
}
|
||||
|
|
|
@ -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++) \
|
||||
{ \
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -3,7 +3,7 @@
|
|||
#
|
||||
|
||||
obj-$(CONFIG_IIO) += industrialio.o
|
||||
industrialio-y := industrialio-core.o
|
||||
industrialio-y := industrialio-core.o industrialio-event.o
|
||||
industrialio-$(CONFIG_IIO_BUFFER) += industrialio-buffer.o
|
||||
industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 <<
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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,
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -353,7 +337,10 @@ static int __devinit ad5446_probe(struct spi_device *spi)
|
|||
/* Estabilish 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;
|
||||
|
|
|
@ -281,29 +281,27 @@ static struct attribute *ad9834_attributes[] = {
|
|||
NULL,
|
||||
};
|
||||
|
||||
static umode_t ad9834_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 ad9834_state *st = iio_priv(indio_dev);
|
||||
|
||||
umode_t mode = attr->mode;
|
||||
|
||||
if (((st->devid == ID_AD9833) || (st->devid == ID_AD9837)) &&
|
||||
((attr == &iio_dev_attr_dds0_out1_enable.dev_attr.attr) ||
|
||||
(attr == &iio_dev_attr_dds0_out1_wavetype.dev_attr.attr) ||
|
||||
(attr ==
|
||||
&iio_dev_attr_dds0_out1_wavetype_available.dev_attr.attr) ||
|
||||
(attr == &iio_dev_attr_dds0_pincontrol_en.dev_attr.attr)))
|
||||
mode = 0;
|
||||
|
||||
return mode;
|
||||
}
|
||||
static struct attribute *ad9833_attributes[] = {
|
||||
&iio_dev_attr_dds0_freq0.dev_attr.attr,
|
||||
&iio_dev_attr_dds0_freq1.dev_attr.attr,
|
||||
&iio_const_attr_dds0_freq_scale.dev_attr.attr,
|
||||
&iio_dev_attr_dds0_phase0.dev_attr.attr,
|
||||
&iio_dev_attr_dds0_phase1.dev_attr.attr,
|
||||
&iio_const_attr_dds0_phase_scale.dev_attr.attr,
|
||||
&iio_dev_attr_dds0_freqsymbol.dev_attr.attr,
|
||||
&iio_dev_attr_dds0_phasesymbol.dev_attr.attr,
|
||||
&iio_dev_attr_dds0_out_enable.dev_attr.attr,
|
||||
&iio_dev_attr_dds0_out0_wavetype.dev_attr.attr,
|
||||
&iio_dev_attr_dds0_out0_wavetype_available.dev_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group ad9834_attribute_group = {
|
||||
.attrs = ad9834_attributes,
|
||||
.is_visible = ad9834_attr_is_visible,
|
||||
};
|
||||
|
||||
static const struct attribute_group ad9833_attribute_group = {
|
||||
.attrs = ad9833_attributes,
|
||||
};
|
||||
|
||||
static const struct iio_info ad9834_info = {
|
||||
|
@ -311,6 +309,11 @@ static const struct iio_info ad9834_info = {
|
|||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static const struct iio_info ad9833_info = {
|
||||
.attrs = &ad9833_attribute_group,
|
||||
.driver_module = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __devinit ad9834_probe(struct spi_device *spi)
|
||||
{
|
||||
struct ad9834_platform_data *pdata = spi->dev.platform_data;
|
||||
|
@ -344,7 +347,15 @@ static int __devinit ad9834_probe(struct spi_device *spi)
|
|||
st->reg = reg;
|
||||
indio_dev->dev.parent = &spi->dev;
|
||||
indio_dev->name = spi_get_device_id(spi)->name;
|
||||
indio_dev->info = &ad9834_info;
|
||||
switch (st->devid) {
|
||||
case ID_AD9833:
|
||||
case ID_AD9837:
|
||||
indio_dev->info = &ad9833_info;
|
||||
break;
|
||||
default:
|
||||
indio_dev->info = &ad9834_info;
|
||||
break;
|
||||
}
|
||||
indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
|
||||
/* Setup default messages */
|
||||
|
|
|
@ -115,8 +115,6 @@ int adis16260_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 = &adis16260_ring_setup_ops;
|
||||
|
||||
|
|
|
@ -49,4 +49,8 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
|
|||
|
||||
#endif
|
||||
|
||||
int iio_device_register_eventset(struct iio_dev *indio_dev);
|
||||
void iio_device_unregister_eventset(struct iio_dev *indio_dev);
|
||||
int iio_event_getfd(struct iio_dev *indio_dev);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -142,8 +142,6 @@ int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev)
|
|||
}
|
||||
|
||||
indio_dev->buffer = buffer;
|
||||
/* Tell the core how to access the buffer */
|
||||
buffer->access = &kfifo_access_funcs;
|
||||
|
||||
/* Enable timestamps by default */
|
||||
buffer->scan_timestamp = true;
|
||||
|
|
|
@ -607,9 +607,6 @@ static int ad5933_register_ring_funcs_and_init(struct iio_dev *indio_dev)
|
|||
if (!indio_dev->buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
/* 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 = &ad5933_ring_setup_ops;
|
||||
|
||||
|
|
|
@ -187,8 +187,6 @@ int adis16400_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 = &adis16400_ring_setup_ops;
|
||||
|
||||
|
|
|
@ -100,71 +100,6 @@ const struct iio_chan_spec
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* struct iio_detected_event_list - list element for events that have occurred
|
||||
* @list: linked list header
|
||||
* @ev: the event itself
|
||||
*/
|
||||
struct iio_detected_event_list {
|
||||
struct list_head list;
|
||||
struct iio_event_data ev;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct iio_event_interface - chrdev interface for an event line
|
||||
* @dev: device assocated with event interface
|
||||
* @wait: wait queue to allow blocking reads of events
|
||||
* @event_list_lock: mutex to protect the list of detected events
|
||||
* @det_events: list of detected events
|
||||
* @max_events: maximum number of events before new ones are dropped
|
||||
* @current_events: number of events in detected list
|
||||
* @flags: file operations related flags including busy flag.
|
||||
*/
|
||||
struct iio_event_interface {
|
||||
wait_queue_head_t wait;
|
||||
struct mutex event_list_lock;
|
||||
struct list_head det_events;
|
||||
int max_events;
|
||||
int current_events;
|
||||
struct list_head dev_attr_list;
|
||||
unsigned long flags;
|
||||
struct attribute_group group;
|
||||
};
|
||||
|
||||
int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp)
|
||||
{
|
||||
struct iio_event_interface *ev_int = indio_dev->event_interface;
|
||||
struct iio_detected_event_list *ev;
|
||||
int ret = 0;
|
||||
|
||||
/* Does anyone care? */
|
||||
mutex_lock(&ev_int->event_list_lock);
|
||||
if (test_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
|
||||
if (ev_int->current_events == ev_int->max_events) {
|
||||
mutex_unlock(&ev_int->event_list_lock);
|
||||
return 0;
|
||||
}
|
||||
ev = kmalloc(sizeof(*ev), GFP_KERNEL);
|
||||
if (ev == NULL) {
|
||||
ret = -ENOMEM;
|
||||
mutex_unlock(&ev_int->event_list_lock);
|
||||
goto error_ret;
|
||||
}
|
||||
ev->ev.id = ev_code;
|
||||
ev->ev.timestamp = timestamp;
|
||||
|
||||
list_add_tail(&ev->list, &ev_int->det_events);
|
||||
ev_int->current_events++;
|
||||
mutex_unlock(&ev_int->event_list_lock);
|
||||
wake_up_interruptible(&ev_int->wait);
|
||||
} else
|
||||
mutex_unlock(&ev_int->event_list_lock);
|
||||
|
||||
error_ret:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(iio_push_event);
|
||||
|
||||
/* This turns up an awful lot */
|
||||
ssize_t iio_read_const_attr(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
|
@ -174,110 +109,6 @@ ssize_t iio_read_const_attr(struct device *dev,
|
|||
}
|
||||
EXPORT_SYMBOL(iio_read_const_attr);
|
||||
|
||||
static ssize_t iio_event_chrdev_read(struct file *filep,
|
||||
char __user *buf,
|
||||
size_t count,
|
||||
loff_t *f_ps)
|
||||
{
|
||||
struct iio_event_interface *ev_int = filep->private_data;
|
||||
struct iio_detected_event_list *el;
|
||||
size_t len = sizeof(el->ev);
|
||||
int ret;
|
||||
|
||||
if (count < len)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&ev_int->event_list_lock);
|
||||
if (list_empty(&ev_int->det_events)) {
|
||||
if (filep->f_flags & O_NONBLOCK) {
|
||||
ret = -EAGAIN;
|
||||
goto error_mutex_unlock;
|
||||
}
|
||||
mutex_unlock(&ev_int->event_list_lock);
|
||||
/* Blocking on device; waiting for something to be there */
|
||||
ret = wait_event_interruptible(ev_int->wait,
|
||||
!list_empty(&ev_int
|
||||
->det_events));
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
/* Single access device so no one else can get the data */
|
||||
mutex_lock(&ev_int->event_list_lock);
|
||||
}
|
||||
|
||||
el = list_first_entry(&ev_int->det_events,
|
||||
struct iio_detected_event_list,
|
||||
list);
|
||||
if (copy_to_user(buf, &(el->ev), len)) {
|
||||
ret = -EFAULT;
|
||||
goto error_mutex_unlock;
|
||||
}
|
||||
list_del(&el->list);
|
||||
ev_int->current_events--;
|
||||
mutex_unlock(&ev_int->event_list_lock);
|
||||
kfree(el);
|
||||
|
||||
return len;
|
||||
|
||||
error_mutex_unlock:
|
||||
mutex_unlock(&ev_int->event_list_lock);
|
||||
error_ret:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int iio_event_chrdev_release(struct inode *inode, struct file *filep)
|
||||
{
|
||||
struct iio_event_interface *ev_int = filep->private_data;
|
||||
struct iio_detected_event_list *el, *t;
|
||||
|
||||
mutex_lock(&ev_int->event_list_lock);
|
||||
clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
|
||||
/*
|
||||
* In order to maintain a clean state for reopening,
|
||||
* clear out any awaiting events. The mask will prevent
|
||||
* any new __iio_push_event calls running.
|
||||
*/
|
||||
list_for_each_entry_safe(el, t, &ev_int->det_events, list) {
|
||||
list_del(&el->list);
|
||||
kfree(el);
|
||||
}
|
||||
ev_int->current_events = 0;
|
||||
mutex_unlock(&ev_int->event_list_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations iio_event_chrdev_fileops = {
|
||||
.read = iio_event_chrdev_read,
|
||||
.release = iio_event_chrdev_release,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
static int iio_event_getfd(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct iio_event_interface *ev_int = indio_dev->event_interface;
|
||||
int fd;
|
||||
|
||||
if (ev_int == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&ev_int->event_list_lock);
|
||||
if (test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
|
||||
mutex_unlock(&ev_int->event_list_lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
mutex_unlock(&ev_int->event_list_lock);
|
||||
fd = anon_inode_getfd("iio:event",
|
||||
&iio_event_chrdev_fileops, ev_int, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
mutex_lock(&ev_int->event_list_lock);
|
||||
clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
|
||||
mutex_unlock(&ev_int->event_list_lock);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
static int __init iio_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
@ -726,295 +557,6 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
|
|||
kfree(indio_dev->chan_attr_group.attrs);
|
||||
}
|
||||
|
||||
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 ssize_t iio_ev_state_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
int ret;
|
||||
bool val;
|
||||
|
||||
ret = strtobool(buf, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = indio_dev->info->write_event_config(indio_dev,
|
||||
this_attr->address,
|
||||
val);
|
||||
return (ret < 0) ? ret : len;
|
||||
}
|
||||
|
||||
static ssize_t iio_ev_state_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
int val = indio_dev->info->read_event_config(indio_dev,
|
||||
this_attr->address);
|
||||
|
||||
if (val < 0)
|
||||
return val;
|
||||
else
|
||||
return sprintf(buf, "%d\n", val);
|
||||
}
|
||||
|
||||
static ssize_t iio_ev_value_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
int val, ret;
|
||||
|
||||
ret = indio_dev->info->read_event_value(indio_dev,
|
||||
this_attr->address, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", val);
|
||||
}
|
||||
|
||||
static ssize_t iio_ev_value_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
unsigned long val;
|
||||
int ret;
|
||||
|
||||
if (!indio_dev->info->write_event_value)
|
||||
return -EINVAL;
|
||||
|
||||
ret = strict_strtoul(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = indio_dev->info->write_event_value(indio_dev, this_attr->address,
|
||||
val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int iio_device_add_event_sysfs(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan)
|
||||
{
|
||||
int ret = 0, i, attrcount = 0;
|
||||
u64 mask = 0;
|
||||
char *postfix;
|
||||
if (!chan->event_mask)
|
||||
return 0;
|
||||
|
||||
for_each_set_bit(i, &chan->event_mask, sizeof(chan->event_mask)*8) {
|
||||
postfix = kasprintf(GFP_KERNEL, "%s_%s_en",
|
||||
iio_ev_type_text[i/IIO_EV_DIR_MAX],
|
||||
iio_ev_dir_text[i%IIO_EV_DIR_MAX]);
|
||||
if (postfix == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto error_ret;
|
||||
}
|
||||
if (chan->modified)
|
||||
mask = IIO_MOD_EVENT_CODE(chan->type, 0, chan->channel,
|
||||
i/IIO_EV_DIR_MAX,
|
||||
i%IIO_EV_DIR_MAX);
|
||||
else if (chan->differential)
|
||||
mask = IIO_EVENT_CODE(chan->type,
|
||||
0, 0,
|
||||
i%IIO_EV_DIR_MAX,
|
||||
i/IIO_EV_DIR_MAX,
|
||||
0,
|
||||
chan->channel,
|
||||
chan->channel2);
|
||||
else
|
||||
mask = IIO_UNMOD_EVENT_CODE(chan->type,
|
||||
chan->channel,
|
||||
i/IIO_EV_DIR_MAX,
|
||||
i%IIO_EV_DIR_MAX);
|
||||
|
||||
ret = __iio_add_chan_devattr(postfix,
|
||||
chan,
|
||||
&iio_ev_state_show,
|
||||
iio_ev_state_store,
|
||||
mask,
|
||||
0,
|
||||
&indio_dev->dev,
|
||||
&indio_dev->event_interface->
|
||||
dev_attr_list);
|
||||
kfree(postfix);
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
attrcount++;
|
||||
postfix = kasprintf(GFP_KERNEL, "%s_%s_value",
|
||||
iio_ev_type_text[i/IIO_EV_DIR_MAX],
|
||||
iio_ev_dir_text[i%IIO_EV_DIR_MAX]);
|
||||
if (postfix == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto error_ret;
|
||||
}
|
||||
ret = __iio_add_chan_devattr(postfix, chan,
|
||||
iio_ev_value_show,
|
||||
iio_ev_value_store,
|
||||
mask,
|
||||
0,
|
||||
&indio_dev->dev,
|
||||
&indio_dev->event_interface->
|
||||
dev_attr_list);
|
||||
kfree(postfix);
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
attrcount++;
|
||||
}
|
||||
ret = attrcount;
|
||||
error_ret:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void __iio_remove_event_config_attrs(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct iio_dev_attr *p, *n;
|
||||
list_for_each_entry_safe(p, n,
|
||||
&indio_dev->event_interface->
|
||||
dev_attr_list, l) {
|
||||
kfree(p->dev_attr.attr.name);
|
||||
kfree(p);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int __iio_add_event_config_attrs(struct iio_dev *indio_dev)
|
||||
{
|
||||
int j, ret, attrcount = 0;
|
||||
|
||||
INIT_LIST_HEAD(&indio_dev->event_interface->dev_attr_list);
|
||||
/* Dynically created from the channels array */
|
||||
for (j = 0; j < indio_dev->num_channels; j++) {
|
||||
ret = iio_device_add_event_sysfs(indio_dev,
|
||||
&indio_dev->channels[j]);
|
||||
if (ret < 0)
|
||||
goto error_clear_attrs;
|
||||
attrcount += ret;
|
||||
}
|
||||
return attrcount;
|
||||
|
||||
error_clear_attrs:
|
||||
__iio_remove_event_config_attrs(indio_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool iio_check_for_dynamic_events(struct iio_dev *indio_dev)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 0; j < indio_dev->num_channels; j++)
|
||||
if (indio_dev->channels[j].event_mask != 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void iio_setup_ev_int(struct iio_event_interface *ev_int)
|
||||
{
|
||||
mutex_init(&ev_int->event_list_lock);
|
||||
/* discussion point - make this variable? */
|
||||
ev_int->max_events = 10;
|
||||
ev_int->current_events = 0;
|
||||
INIT_LIST_HEAD(&ev_int->det_events);
|
||||
init_waitqueue_head(&ev_int->wait);
|
||||
}
|
||||
|
||||
static const char *iio_event_group_name = "events";
|
||||
static int iio_device_register_eventset(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct iio_dev_attr *p;
|
||||
int ret = 0, attrcount_orig = 0, attrcount, attrn;
|
||||
struct attribute **attr;
|
||||
|
||||
if (!(indio_dev->info->event_attrs ||
|
||||
iio_check_for_dynamic_events(indio_dev)))
|
||||
return 0;
|
||||
|
||||
indio_dev->event_interface =
|
||||
kzalloc(sizeof(struct iio_event_interface), GFP_KERNEL);
|
||||
if (indio_dev->event_interface == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto error_ret;
|
||||
}
|
||||
|
||||
iio_setup_ev_int(indio_dev->event_interface);
|
||||
if (indio_dev->info->event_attrs != NULL) {
|
||||
attr = indio_dev->info->event_attrs->attrs;
|
||||
while (*attr++ != NULL)
|
||||
attrcount_orig++;
|
||||
}
|
||||
attrcount = attrcount_orig;
|
||||
if (indio_dev->channels) {
|
||||
ret = __iio_add_event_config_attrs(indio_dev);
|
||||
if (ret < 0)
|
||||
goto error_free_setup_event_lines;
|
||||
attrcount += ret;
|
||||
}
|
||||
|
||||
indio_dev->event_interface->group.name = iio_event_group_name;
|
||||
indio_dev->event_interface->group.attrs = kcalloc(attrcount + 1,
|
||||
sizeof(indio_dev->event_interface->group.attrs[0]),
|
||||
GFP_KERNEL);
|
||||
if (indio_dev->event_interface->group.attrs == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto error_free_setup_event_lines;
|
||||
}
|
||||
if (indio_dev->info->event_attrs)
|
||||
memcpy(indio_dev->event_interface->group.attrs,
|
||||
indio_dev->info->event_attrs->attrs,
|
||||
sizeof(indio_dev->event_interface->group.attrs[0])
|
||||
*attrcount_orig);
|
||||
attrn = attrcount_orig;
|
||||
/* Add all elements from the list. */
|
||||
list_for_each_entry(p,
|
||||
&indio_dev->event_interface->dev_attr_list,
|
||||
l)
|
||||
indio_dev->event_interface->group.attrs[attrn++] =
|
||||
&p->dev_attr.attr;
|
||||
indio_dev->groups[indio_dev->groupcounter++] =
|
||||
&indio_dev->event_interface->group;
|
||||
|
||||
return 0;
|
||||
|
||||
error_free_setup_event_lines:
|
||||
__iio_remove_event_config_attrs(indio_dev);
|
||||
kfree(indio_dev->event_interface);
|
||||
error_ret:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void iio_device_unregister_eventset(struct iio_dev *indio_dev)
|
||||
{
|
||||
if (indio_dev->event_interface == NULL)
|
||||
return;
|
||||
__iio_remove_event_config_attrs(indio_dev);
|
||||
kfree(indio_dev->event_interface->group.attrs);
|
||||
kfree(indio_dev->event_interface);
|
||||
}
|
||||
|
||||
static void iio_dev_release(struct device *device)
|
||||
{
|
||||
struct iio_dev *indio_dev = container_of(device, struct iio_dev, dev);
|
||||
|
|
|
@ -0,0 +1,454 @@
|
|||
/* Industrial I/O event handling
|
||||
*
|
||||
* Copyright (c) 2008 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.
|
||||
*
|
||||
* Based on elements of hwmon and input subsystems.
|
||||
*/
|
||||
|
||||
#include <linux/anon_inodes.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kfifo.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/wait.h>
|
||||
#include "iio.h"
|
||||
#include "iio_core.h"
|
||||
#include "sysfs.h"
|
||||
#include "events.h"
|
||||
|
||||
/**
|
||||
* struct iio_event_interface - chrdev interface for an event line
|
||||
* @wait: wait queue to allow blocking reads of events
|
||||
* @event_list_lock: mutex to protect the list of detected events
|
||||
* @det_events: list of detected events
|
||||
* @dev_attr_list: list of event interface sysfs attribute
|
||||
* @flags: file operations related flags including busy flag.
|
||||
* @group: event interface sysfs attribute group
|
||||
*/
|
||||
struct iio_event_interface {
|
||||
wait_queue_head_t wait;
|
||||
DECLARE_KFIFO(det_events, struct iio_event_data, 16);
|
||||
|
||||
struct list_head dev_attr_list;
|
||||
unsigned long flags;
|
||||
struct attribute_group group;
|
||||
};
|
||||
|
||||
int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp)
|
||||
{
|
||||
struct iio_event_interface *ev_int = indio_dev->event_interface;
|
||||
struct iio_event_data ev;
|
||||
int copied;
|
||||
|
||||
/* Does anyone care? */
|
||||
spin_lock(&ev_int->wait.lock);
|
||||
if (test_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
|
||||
|
||||
ev.id = ev_code;
|
||||
ev.timestamp = timestamp;
|
||||
|
||||
copied = kfifo_put(&ev_int->det_events, &ev);
|
||||
if (copied != 0)
|
||||
wake_up_locked_poll(&ev_int->wait, POLLIN);
|
||||
}
|
||||
spin_unlock(&ev_int->wait.lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(iio_push_event);
|
||||
|
||||
/**
|
||||
* iio_event_poll() - poll the event queue to find out if it has data
|
||||
*/
|
||||
static unsigned int iio_event_poll(struct file *filep,
|
||||
struct poll_table_struct *wait)
|
||||
{
|
||||
struct iio_event_interface *ev_int = filep->private_data;
|
||||
unsigned int events = 0;
|
||||
|
||||
poll_wait(filep, &ev_int->wait, wait);
|
||||
|
||||
spin_lock(&ev_int->wait.lock);
|
||||
if (!kfifo_is_empty(&ev_int->det_events))
|
||||
events = POLLIN | POLLRDNORM;
|
||||
spin_unlock(&ev_int->wait.lock);
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
static ssize_t iio_event_chrdev_read(struct file *filep,
|
||||
char __user *buf,
|
||||
size_t count,
|
||||
loff_t *f_ps)
|
||||
{
|
||||
struct iio_event_interface *ev_int = filep->private_data;
|
||||
unsigned int copied;
|
||||
int ret;
|
||||
|
||||
if (count < sizeof(struct iio_event_data))
|
||||
return -EINVAL;
|
||||
|
||||
spin_lock(&ev_int->wait.lock);
|
||||
if (kfifo_is_empty(&ev_int->det_events)) {
|
||||
if (filep->f_flags & O_NONBLOCK) {
|
||||
ret = -EAGAIN;
|
||||
goto error_unlock;
|
||||
}
|
||||
/* Blocking on device; waiting for something to be there */
|
||||
ret = wait_event_interruptible_locked(ev_int->wait,
|
||||
!kfifo_is_empty(&ev_int->det_events));
|
||||
if (ret)
|
||||
goto error_unlock;
|
||||
/* Single access device so no one else can get the data */
|
||||
}
|
||||
|
||||
ret = kfifo_to_user(&ev_int->det_events, buf, count, &copied);
|
||||
|
||||
error_unlock:
|
||||
spin_unlock(&ev_int->wait.lock);
|
||||
|
||||
return ret ? ret : copied;
|
||||
}
|
||||
|
||||
static int iio_event_chrdev_release(struct inode *inode, struct file *filep)
|
||||
{
|
||||
struct iio_event_interface *ev_int = filep->private_data;
|
||||
|
||||
spin_lock(&ev_int->wait.lock);
|
||||
__clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
|
||||
/*
|
||||
* In order to maintain a clean state for reopening,
|
||||
* clear out any awaiting events. The mask will prevent
|
||||
* any new __iio_push_event calls running.
|
||||
*/
|
||||
kfifo_reset_out(&ev_int->det_events);
|
||||
spin_unlock(&ev_int->wait.lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations iio_event_chrdev_fileops = {
|
||||
.read = iio_event_chrdev_read,
|
||||
.poll = iio_event_poll,
|
||||
.release = iio_event_chrdev_release,
|
||||
.owner = THIS_MODULE,
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
int iio_event_getfd(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct iio_event_interface *ev_int = indio_dev->event_interface;
|
||||
int fd;
|
||||
|
||||
if (ev_int == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
spin_lock(&ev_int->wait.lock);
|
||||
if (__test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
|
||||
spin_unlock(&ev_int->wait.lock);
|
||||
return -EBUSY;
|
||||
}
|
||||
spin_unlock(&ev_int->wait.lock);
|
||||
fd = anon_inode_getfd("iio:event",
|
||||
&iio_event_chrdev_fileops, ev_int, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
spin_lock(&ev_int->wait.lock);
|
||||
__clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
|
||||
spin_unlock(&ev_int->wait.lock);
|
||||
}
|
||||
return fd;
|
||||
}
|
||||
|
||||
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 ssize_t iio_ev_state_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
int ret;
|
||||
bool val;
|
||||
|
||||
ret = strtobool(buf, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = indio_dev->info->write_event_config(indio_dev,
|
||||
this_attr->address,
|
||||
val);
|
||||
return (ret < 0) ? ret : len;
|
||||
}
|
||||
|
||||
static ssize_t iio_ev_state_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
int val = indio_dev->info->read_event_config(indio_dev,
|
||||
this_attr->address);
|
||||
|
||||
if (val < 0)
|
||||
return val;
|
||||
else
|
||||
return sprintf(buf, "%d\n", val);
|
||||
}
|
||||
|
||||
static ssize_t iio_ev_value_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
int val, ret;
|
||||
|
||||
ret = indio_dev->info->read_event_value(indio_dev,
|
||||
this_attr->address, &val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return sprintf(buf, "%d\n", val);
|
||||
}
|
||||
|
||||
static ssize_t iio_ev_value_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||
unsigned long val;
|
||||
int ret;
|
||||
|
||||
if (!indio_dev->info->write_event_value)
|
||||
return -EINVAL;
|
||||
|
||||
ret = strict_strtoul(buf, 10, &val);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = indio_dev->info->write_event_value(indio_dev, this_attr->address,
|
||||
val);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static int iio_device_add_event_sysfs(struct iio_dev *indio_dev,
|
||||
struct iio_chan_spec const *chan)
|
||||
{
|
||||
int ret = 0, i, attrcount = 0;
|
||||
u64 mask = 0;
|
||||
char *postfix;
|
||||
if (!chan->event_mask)
|
||||
return 0;
|
||||
|
||||
for_each_set_bit(i, &chan->event_mask, sizeof(chan->event_mask)*8) {
|
||||
postfix = kasprintf(GFP_KERNEL, "%s_%s_en",
|
||||
iio_ev_type_text[i/IIO_EV_DIR_MAX],
|
||||
iio_ev_dir_text[i%IIO_EV_DIR_MAX]);
|
||||
if (postfix == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto error_ret;
|
||||
}
|
||||
if (chan->modified)
|
||||
mask = IIO_MOD_EVENT_CODE(chan->type, 0, chan->channel,
|
||||
i/IIO_EV_DIR_MAX,
|
||||
i%IIO_EV_DIR_MAX);
|
||||
else if (chan->differential)
|
||||
mask = IIO_EVENT_CODE(chan->type,
|
||||
0, 0,
|
||||
i%IIO_EV_DIR_MAX,
|
||||
i/IIO_EV_DIR_MAX,
|
||||
0,
|
||||
chan->channel,
|
||||
chan->channel2);
|
||||
else
|
||||
mask = IIO_UNMOD_EVENT_CODE(chan->type,
|
||||
chan->channel,
|
||||
i/IIO_EV_DIR_MAX,
|
||||
i%IIO_EV_DIR_MAX);
|
||||
|
||||
ret = __iio_add_chan_devattr(postfix,
|
||||
chan,
|
||||
&iio_ev_state_show,
|
||||
iio_ev_state_store,
|
||||
mask,
|
||||
0,
|
||||
&indio_dev->dev,
|
||||
&indio_dev->event_interface->
|
||||
dev_attr_list);
|
||||
kfree(postfix);
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
attrcount++;
|
||||
postfix = kasprintf(GFP_KERNEL, "%s_%s_value",
|
||||
iio_ev_type_text[i/IIO_EV_DIR_MAX],
|
||||
iio_ev_dir_text[i%IIO_EV_DIR_MAX]);
|
||||
if (postfix == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto error_ret;
|
||||
}
|
||||
ret = __iio_add_chan_devattr(postfix, chan,
|
||||
iio_ev_value_show,
|
||||
iio_ev_value_store,
|
||||
mask,
|
||||
0,
|
||||
&indio_dev->dev,
|
||||
&indio_dev->event_interface->
|
||||
dev_attr_list);
|
||||
kfree(postfix);
|
||||
if (ret)
|
||||
goto error_ret;
|
||||
attrcount++;
|
||||
}
|
||||
ret = attrcount;
|
||||
error_ret:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void __iio_remove_event_config_attrs(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct iio_dev_attr *p, *n;
|
||||
list_for_each_entry_safe(p, n,
|
||||
&indio_dev->event_interface->
|
||||
dev_attr_list, l) {
|
||||
kfree(p->dev_attr.attr.name);
|
||||
kfree(p);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int __iio_add_event_config_attrs(struct iio_dev *indio_dev)
|
||||
{
|
||||
int j, ret, attrcount = 0;
|
||||
|
||||
INIT_LIST_HEAD(&indio_dev->event_interface->dev_attr_list);
|
||||
/* Dynically created from the channels array */
|
||||
for (j = 0; j < indio_dev->num_channels; j++) {
|
||||
ret = iio_device_add_event_sysfs(indio_dev,
|
||||
&indio_dev->channels[j]);
|
||||
if (ret < 0)
|
||||
goto error_clear_attrs;
|
||||
attrcount += ret;
|
||||
}
|
||||
return attrcount;
|
||||
|
||||
error_clear_attrs:
|
||||
__iio_remove_event_config_attrs(indio_dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool iio_check_for_dynamic_events(struct iio_dev *indio_dev)
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 0; j < indio_dev->num_channels; j++)
|
||||
if (indio_dev->channels[j].event_mask != 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void iio_setup_ev_int(struct iio_event_interface *ev_int)
|
||||
{
|
||||
INIT_KFIFO(ev_int->det_events);
|
||||
init_waitqueue_head(&ev_int->wait);
|
||||
}
|
||||
|
||||
static const char *iio_event_group_name = "events";
|
||||
int iio_device_register_eventset(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct iio_dev_attr *p;
|
||||
int ret = 0, attrcount_orig = 0, attrcount, attrn;
|
||||
struct attribute **attr;
|
||||
|
||||
if (!(indio_dev->info->event_attrs ||
|
||||
iio_check_for_dynamic_events(indio_dev)))
|
||||
return 0;
|
||||
|
||||
indio_dev->event_interface =
|
||||
kzalloc(sizeof(struct iio_event_interface), GFP_KERNEL);
|
||||
if (indio_dev->event_interface == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto error_ret;
|
||||
}
|
||||
|
||||
iio_setup_ev_int(indio_dev->event_interface);
|
||||
if (indio_dev->info->event_attrs != NULL) {
|
||||
attr = indio_dev->info->event_attrs->attrs;
|
||||
while (*attr++ != NULL)
|
||||
attrcount_orig++;
|
||||
}
|
||||
attrcount = attrcount_orig;
|
||||
if (indio_dev->channels) {
|
||||
ret = __iio_add_event_config_attrs(indio_dev);
|
||||
if (ret < 0)
|
||||
goto error_free_setup_event_lines;
|
||||
attrcount += ret;
|
||||
}
|
||||
|
||||
indio_dev->event_interface->group.name = iio_event_group_name;
|
||||
indio_dev->event_interface->group.attrs = kcalloc(attrcount + 1,
|
||||
sizeof(indio_dev->event_interface->group.attrs[0]),
|
||||
GFP_KERNEL);
|
||||
if (indio_dev->event_interface->group.attrs == NULL) {
|
||||
ret = -ENOMEM;
|
||||
goto error_free_setup_event_lines;
|
||||
}
|
||||
if (indio_dev->info->event_attrs)
|
||||
memcpy(indio_dev->event_interface->group.attrs,
|
||||
indio_dev->info->event_attrs->attrs,
|
||||
sizeof(indio_dev->event_interface->group.attrs[0])
|
||||
*attrcount_orig);
|
||||
attrn = attrcount_orig;
|
||||
/* Add all elements from the list. */
|
||||
list_for_each_entry(p,
|
||||
&indio_dev->event_interface->dev_attr_list,
|
||||
l)
|
||||
indio_dev->event_interface->group.attrs[attrn++] =
|
||||
&p->dev_attr.attr;
|
||||
indio_dev->groups[indio_dev->groupcounter++] =
|
||||
&indio_dev->event_interface->group;
|
||||
|
||||
return 0;
|
||||
|
||||
error_free_setup_event_lines:
|
||||
__iio_remove_event_config_attrs(indio_dev);
|
||||
kfree(indio_dev->event_interface);
|
||||
error_ret:
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void iio_device_unregister_eventset(struct iio_dev *indio_dev)
|
||||
{
|
||||
if (indio_dev->event_interface == NULL)
|
||||
return;
|
||||
__iio_remove_event_config_attrs(indio_dev);
|
||||
kfree(indio_dev->event_interface->group.attrs);
|
||||
kfree(indio_dev->event_interface);
|
||||
}
|
|
@ -59,21 +59,6 @@ static struct attribute_group iio_kfifo_attribute_group = {
|
|||
.name = "buffer",
|
||||
};
|
||||
|
||||
struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct iio_kfifo *kf;
|
||||
|
||||
kf = kzalloc(sizeof *kf, GFP_KERNEL);
|
||||
if (!kf)
|
||||
return NULL;
|
||||
kf->update_needed = true;
|
||||
iio_buffer_init(&kf->buffer);
|
||||
kf->buffer.attrs = &iio_kfifo_attribute_group;
|
||||
|
||||
return &kf->buffer;
|
||||
}
|
||||
EXPORT_SYMBOL(iio_kfifo_allocate);
|
||||
|
||||
static int iio_get_bytes_per_datum_kfifo(struct iio_buffer *r)
|
||||
{
|
||||
return r->bytes_per_datum;
|
||||
|
@ -104,12 +89,6 @@ static int iio_set_length_kfifo(struct iio_buffer *r, int length)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void iio_kfifo_free(struct iio_buffer *r)
|
||||
{
|
||||
kfree(iio_to_kfifo(r));
|
||||
}
|
||||
EXPORT_SYMBOL(iio_kfifo_free);
|
||||
|
||||
static int iio_store_to_kfifo(struct iio_buffer *r,
|
||||
u8 *data,
|
||||
s64 timestamp)
|
||||
|
@ -137,7 +116,7 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r,
|
|||
return copied;
|
||||
}
|
||||
|
||||
const struct iio_buffer_access_funcs kfifo_access_funcs = {
|
||||
static const struct iio_buffer_access_funcs kfifo_access_funcs = {
|
||||
.store_to = &iio_store_to_kfifo,
|
||||
.read_first_n = &iio_read_first_n_kfifo,
|
||||
.request_update = &iio_request_update_kfifo,
|
||||
|
@ -146,6 +125,27 @@ const struct iio_buffer_access_funcs kfifo_access_funcs = {
|
|||
.get_length = &iio_get_length_kfifo,
|
||||
.set_length = &iio_set_length_kfifo,
|
||||
};
|
||||
EXPORT_SYMBOL(kfifo_access_funcs);
|
||||
|
||||
struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct iio_kfifo *kf;
|
||||
|
||||
kf = kzalloc(sizeof *kf, GFP_KERNEL);
|
||||
if (!kf)
|
||||
return NULL;
|
||||
kf->update_needed = true;
|
||||
iio_buffer_init(&kf->buffer);
|
||||
kf->buffer.attrs = &iio_kfifo_attribute_group;
|
||||
kf->buffer.access = &kfifo_access_funcs;
|
||||
|
||||
return &kf->buffer;
|
||||
}
|
||||
EXPORT_SYMBOL(iio_kfifo_allocate);
|
||||
|
||||
void iio_kfifo_free(struct iio_buffer *r)
|
||||
{
|
||||
kfree(iio_to_kfifo(r));
|
||||
}
|
||||
EXPORT_SYMBOL(iio_kfifo_free);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
#include "iio.h"
|
||||
#include "buffer.h"
|
||||
|
||||
extern const struct iio_buffer_access_funcs kfifo_access_funcs;
|
||||
|
||||
struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev);
|
||||
void iio_kfifo_free(struct iio_buffer *r);
|
||||
|
||||
|
|
|
@ -592,11 +592,18 @@ static const struct i2c_device_id isl29018_id[] = {
|
|||
|
||||
MODULE_DEVICE_TABLE(i2c, isl29018_id);
|
||||
|
||||
static const struct of_device_id isl29018_of_match[] = {
|
||||
{ .compatible = "invn,isl29018", },
|
||||
{ },
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, isl29018_of_match);
|
||||
|
||||
static struct i2c_driver isl29018_driver = {
|
||||
.class = I2C_CLASS_HWMON,
|
||||
.driver = {
|
||||
.name = "isl29018",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = isl29018_of_match,
|
||||
},
|
||||
.probe = isl29018_probe,
|
||||
.remove = __devexit_p(isl29018_remove),
|
||||
|
|
|
@ -564,9 +564,17 @@ static const struct i2c_device_id ak8975_id[] = {
|
|||
|
||||
MODULE_DEVICE_TABLE(i2c, ak8975_id);
|
||||
|
||||
static const struct of_device_id ak8975_of_match[] = {
|
||||
{ .compatible = "asahi-kasei,ak8975", },
|
||||
{ .compatible = "ak8975", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, ak8975_of_match);
|
||||
|
||||
static struct i2c_driver ak8975_driver = {
|
||||
.driver = {
|
||||
.name = "ak8975",
|
||||
.of_match_table = ak8975_of_match,
|
||||
},
|
||||
.probe = ak8975_probe,
|
||||
.remove = __devexit_p(ak8975_remove),
|
||||
|
|
|
@ -144,8 +144,6 @@ int ade7758_configure_ring(struct iio_dev *indio_dev)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Effectively select the ring buffer implementation */
|
||||
indio_dev->buffer->access = &ring_sw_access_funcs;
|
||||
indio_dev->setup_ops = &ade7758_ring_setup_ops;
|
||||
|
||||
indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
|
||||
|
|
|
@ -329,6 +329,16 @@ static struct attribute_group iio_ring_attribute_group = {
|
|||
.name = "buffer",
|
||||
};
|
||||
|
||||
static const struct iio_buffer_access_funcs ring_sw_access_funcs = {
|
||||
.store_to = &iio_store_to_sw_rb,
|
||||
.read_first_n = &iio_read_first_n_sw_rb,
|
||||
.request_update = &iio_request_update_sw_rb,
|
||||
.get_bytes_per_datum = &iio_get_bytes_per_datum_sw_rb,
|
||||
.set_bytes_per_datum = &iio_set_bytes_per_datum_sw_rb,
|
||||
.get_length = &iio_get_length_sw_rb,
|
||||
.set_length = &iio_set_length_sw_rb,
|
||||
};
|
||||
|
||||
struct iio_buffer *iio_sw_rb_allocate(struct iio_dev *indio_dev)
|
||||
{
|
||||
struct iio_buffer *buf;
|
||||
|
@ -341,6 +351,7 @@ struct iio_buffer *iio_sw_rb_allocate(struct iio_dev *indio_dev)
|
|||
buf = &ring->buf;
|
||||
iio_buffer_init(buf);
|
||||
buf->attrs = &iio_ring_attribute_group;
|
||||
buf->access = &ring_sw_access_funcs;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
@ -352,16 +363,5 @@ void iio_sw_rb_free(struct iio_buffer *r)
|
|||
}
|
||||
EXPORT_SYMBOL(iio_sw_rb_free);
|
||||
|
||||
const struct iio_buffer_access_funcs ring_sw_access_funcs = {
|
||||
.store_to = &iio_store_to_sw_rb,
|
||||
.read_first_n = &iio_read_first_n_sw_rb,
|
||||
.request_update = &iio_request_update_sw_rb,
|
||||
.get_bytes_per_datum = &iio_get_bytes_per_datum_sw_rb,
|
||||
.set_bytes_per_datum = &iio_set_bytes_per_datum_sw_rb,
|
||||
.get_length = &iio_get_length_sw_rb,
|
||||
.set_length = &iio_set_length_sw_rb,
|
||||
};
|
||||
EXPORT_SYMBOL(ring_sw_access_funcs);
|
||||
|
||||
MODULE_DESCRIPTION("Industrialio I/O software ring buffer");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
|
|
@ -25,11 +25,6 @@
|
|||
#define _IIO_RING_SW_H_
|
||||
#include "buffer.h"
|
||||
|
||||
/**
|
||||
* ring_sw_access_funcs - access functions for a software ring buffer
|
||||
**/
|
||||
extern const struct iio_buffer_access_funcs ring_sw_access_funcs;
|
||||
|
||||
struct iio_buffer *iio_sw_rb_allocate(struct iio_dev *indio_dev);
|
||||
void iio_sw_rb_free(struct iio_buffer *ring);
|
||||
#endif /* _IIO_RING_SW_H_ */
|
||||
|
|
|
@ -107,7 +107,7 @@ void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm)
|
|||
Wait until unlinking of all currently active capture URBs has been
|
||||
finished.
|
||||
*/
|
||||
static void wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
|
||||
void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
|
||||
{
|
||||
int timeout = HZ;
|
||||
unsigned int i;
|
||||
|
@ -134,7 +134,7 @@ static void wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
|
|||
void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
|
||||
{
|
||||
line6_unlink_audio_in_urbs(line6pcm);
|
||||
wait_clear_audio_in_urbs(line6pcm);
|
||||
line6_wait_clear_audio_in_urbs(line6pcm);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -193,25 +193,6 @@ void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length)
|
|||
}
|
||||
}
|
||||
|
||||
int line6_alloc_capture_buffer(struct snd_line6_pcm *line6pcm)
|
||||
{
|
||||
/* We may be invoked multiple times in a row so allocate once only */
|
||||
if (line6pcm->buffer_in)
|
||||
return 0;
|
||||
|
||||
line6pcm->buffer_in =
|
||||
kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
|
||||
line6pcm->max_packet_size, GFP_KERNEL);
|
||||
|
||||
if (!line6pcm->buffer_in) {
|
||||
dev_err(line6pcm->line6->ifcdev,
|
||||
"cannot malloc capture buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm)
|
||||
{
|
||||
kfree(line6pcm->buffer_in);
|
||||
|
@ -273,9 +254,9 @@ static void audio_in_callback(struct urb *urb)
|
|||
line6pcm->prev_fsize = fsize;
|
||||
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
if (!(line6pcm->flags & MASK_PCM_IMPULSE))
|
||||
if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
|
||||
#endif
|
||||
if (test_bit(BIT_PCM_ALSA_CAPTURE, &line6pcm->flags)
|
||||
if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, &line6pcm->flags)
|
||||
&& (fsize > 0))
|
||||
line6_capture_copy(line6pcm, fbuf, fsize);
|
||||
}
|
||||
|
@ -291,9 +272,9 @@ static void audio_in_callback(struct urb *urb)
|
|||
submit_audio_in_urb(line6pcm);
|
||||
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
if (!(line6pcm->flags & MASK_PCM_IMPULSE))
|
||||
if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
|
||||
#endif
|
||||
if (test_bit(BIT_PCM_ALSA_CAPTURE, &line6pcm->flags))
|
||||
if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, &line6pcm->flags))
|
||||
line6_capture_check_period(line6pcm, length);
|
||||
}
|
||||
}
|
||||
|
@ -341,17 +322,17 @@ static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream,
|
|||
}
|
||||
/* -- [FD] end */
|
||||
|
||||
if ((line6pcm->flags & MASK_CAPTURE) == 0) {
|
||||
ret = line6_alloc_capture_buffer(line6pcm);
|
||||
ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_pcm_lib_malloc_pages(substream,
|
||||
params_buffer_bytes(hw_params));
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
|
||||
return ret;
|
||||
}
|
||||
|
||||
line6pcm->period_in = params_period_bytes(hw_params);
|
||||
return 0;
|
||||
|
@ -361,12 +342,7 @@ static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream,
|
|||
static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
|
||||
|
||||
if ((line6pcm->flags & MASK_CAPTURE) == 0) {
|
||||
line6_unlink_wait_clear_audio_in_urbs(line6pcm);
|
||||
line6_free_capture_buffer(line6pcm);
|
||||
}
|
||||
|
||||
line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
|
||||
return snd_pcm_lib_free_pages(substream);
|
||||
}
|
||||
|
||||
|
@ -380,7 +356,7 @@ int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd)
|
|||
#ifdef CONFIG_PM
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
#endif
|
||||
err = line6_pcm_start(line6pcm, MASK_PCM_ALSA_CAPTURE);
|
||||
err = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
@ -391,7 +367,7 @@ int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd)
|
|||
#ifdef CONFIG_PM
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
#endif
|
||||
err = line6_pcm_stop(line6pcm, MASK_PCM_ALSA_CAPTURE);
|
||||
err = line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
extern struct snd_pcm_ops snd_line6_capture_ops;
|
||||
|
||||
extern int line6_alloc_capture_buffer(struct snd_line6_pcm *line6pcm);
|
||||
extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf,
|
||||
int fsize);
|
||||
extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm,
|
||||
|
@ -30,6 +29,7 @@ extern int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm);
|
|||
extern void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm);
|
||||
extern void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm
|
||||
*line6pcm);
|
||||
extern void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm);
|
||||
extern int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1346,7 +1346,7 @@ static void __exit line6_exit(void)
|
|||
if (line6pcm == NULL)
|
||||
continue;
|
||||
|
||||
line6_pcm_stop(line6pcm, ~0);
|
||||
line6_pcm_release(line6pcm, ~0);
|
||||
}
|
||||
|
||||
usb_deregister(&line6_driver);
|
||||
|
|
|
@ -52,9 +52,9 @@ static ssize_t pcm_set_impulse_volume(struct device *dev,
|
|||
line6pcm->impulse_volume = value;
|
||||
|
||||
if (value > 0)
|
||||
line6_pcm_start(line6pcm, MASK_PCM_IMPULSE);
|
||||
line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_IMPULSE);
|
||||
else
|
||||
line6_pcm_stop(line6pcm, MASK_PCM_IMPULSE);
|
||||
line6_pcm_release(line6pcm, LINE6_BITS_PCM_IMPULSE);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
@ -92,29 +92,43 @@ static bool test_flags(unsigned long flags0, unsigned long flags1,
|
|||
return ((flags0 & mask) == 0) && ((flags1 & mask) != 0);
|
||||
}
|
||||
|
||||
int line6_pcm_start(struct snd_line6_pcm *line6pcm, int channels)
|
||||
int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels)
|
||||
{
|
||||
unsigned long flags_old =
|
||||
__sync_fetch_and_or(&line6pcm->flags, channels);
|
||||
unsigned long flags_new = flags_old | channels;
|
||||
unsigned long flags_final = flags_old;
|
||||
int err = 0;
|
||||
|
||||
line6pcm->prev_fbuf = NULL;
|
||||
|
||||
if (test_flags(flags_old, flags_new, MASK_CAPTURE)) {
|
||||
if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) {
|
||||
/* We may be invoked multiple times in a row so allocate once only */
|
||||
if (!line6pcm->buffer_in) {
|
||||
line6pcm->buffer_in =
|
||||
kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
|
||||
line6pcm->max_packet_size, GFP_KERNEL);
|
||||
|
||||
if (!line6pcm->buffer_in) {
|
||||
dev_err(line6pcm->line6->ifcdev,
|
||||
"cannot malloc capture buffer\n");
|
||||
err = -ENOMEM;
|
||||
goto pcm_acquire_error;
|
||||
}
|
||||
|
||||
flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER;
|
||||
}
|
||||
}
|
||||
|
||||
if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_STREAM)) {
|
||||
/*
|
||||
Waiting for completion of active URBs in the stop handler is
|
||||
a bug, we therefore report an error if capturing is restarted
|
||||
too soon.
|
||||
*/
|
||||
if (line6pcm->active_urb_in | line6pcm->unlink_urb_in)
|
||||
if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) {
|
||||
dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
|
||||
return -EBUSY;
|
||||
|
||||
if (!(flags_new & MASK_PCM_ALSA_CAPTURE)) {
|
||||
err = line6_alloc_capture_buffer(line6pcm);
|
||||
|
||||
if (err < 0)
|
||||
goto pcm_start_error;
|
||||
}
|
||||
|
||||
line6pcm->count_in = 0;
|
||||
|
@ -122,55 +136,78 @@ int line6_pcm_start(struct snd_line6_pcm *line6pcm, int channels)
|
|||
err = line6_submit_audio_in_all_urbs(line6pcm);
|
||||
|
||||
if (err < 0)
|
||||
goto pcm_start_error;
|
||||
goto pcm_acquire_error;
|
||||
|
||||
flags_final |= channels & LINE6_BITS_CAPTURE_STREAM;
|
||||
}
|
||||
|
||||
if (test_flags(flags_old, flags_new, MASK_PLAYBACK)) {
|
||||
if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) {
|
||||
/* We may be invoked multiple times in a row so allocate once only */
|
||||
if (!line6pcm->buffer_out) {
|
||||
line6pcm->buffer_out =
|
||||
kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
|
||||
line6pcm->max_packet_size, GFP_KERNEL);
|
||||
|
||||
if (!line6pcm->buffer_out) {
|
||||
dev_err(line6pcm->line6->ifcdev,
|
||||
"cannot malloc playback buffer\n");
|
||||
err = -ENOMEM;
|
||||
goto pcm_acquire_error;
|
||||
}
|
||||
|
||||
flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER;
|
||||
}
|
||||
}
|
||||
|
||||
if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_STREAM)) {
|
||||
/*
|
||||
See comment above regarding PCM restart.
|
||||
*/
|
||||
if (line6pcm->active_urb_out | line6pcm->unlink_urb_out)
|
||||
See comment above regarding PCM restart.
|
||||
*/
|
||||
if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) {
|
||||
dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
|
||||
return -EBUSY;
|
||||
|
||||
if (!(flags_new & MASK_PCM_ALSA_PLAYBACK)) {
|
||||
err = line6_alloc_playback_buffer(line6pcm);
|
||||
|
||||
if (err < 0)
|
||||
goto pcm_start_error;
|
||||
}
|
||||
|
||||
line6pcm->count_out = 0;
|
||||
err = line6_submit_audio_out_all_urbs(line6pcm);
|
||||
|
||||
if (err < 0)
|
||||
goto pcm_start_error;
|
||||
goto pcm_acquire_error;
|
||||
|
||||
flags_final |= channels & LINE6_BITS_PLAYBACK_STREAM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
pcm_start_error:
|
||||
__sync_fetch_and_and(&line6pcm->flags, ~channels);
|
||||
pcm_acquire_error:
|
||||
/*
|
||||
If not all requested resources/streams could be obtained, release
|
||||
those which were successfully obtained (if any).
|
||||
*/
|
||||
line6_pcm_release(line6pcm, flags_final & channels);
|
||||
return err;
|
||||
}
|
||||
|
||||
int line6_pcm_stop(struct snd_line6_pcm *line6pcm, int channels)
|
||||
int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels)
|
||||
{
|
||||
unsigned long flags_old =
|
||||
__sync_fetch_and_and(&line6pcm->flags, ~channels);
|
||||
unsigned long flags_new = flags_old & ~channels;
|
||||
|
||||
if (test_flags(flags_new, flags_old, MASK_CAPTURE)) {
|
||||
if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_STREAM))
|
||||
line6_unlink_audio_in_urbs(line6pcm);
|
||||
|
||||
if (!(flags_old & MASK_PCM_ALSA_CAPTURE))
|
||||
line6_free_capture_buffer(line6pcm);
|
||||
if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) {
|
||||
line6_wait_clear_audio_in_urbs(line6pcm);
|
||||
line6_free_capture_buffer(line6pcm);
|
||||
}
|
||||
|
||||
if (test_flags(flags_new, flags_old, MASK_PLAYBACK)) {
|
||||
if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_STREAM))
|
||||
line6_unlink_audio_out_urbs(line6pcm);
|
||||
|
||||
if (!(flags_old & MASK_PCM_ALSA_PLAYBACK))
|
||||
line6_free_playback_buffer(line6pcm);
|
||||
if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_BUFFER)) {
|
||||
line6_wait_clear_audio_out_urbs(line6pcm);
|
||||
line6_free_playback_buffer(line6pcm);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -185,7 +222,7 @@ int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&line6pcm->lock_trigger, flags);
|
||||
clear_bit(BIT_PREPARED, &line6pcm->flags);
|
||||
clear_bit(LINE6_INDEX_PREPARED, &line6pcm->flags);
|
||||
|
||||
snd_pcm_group_for_each_entry(s, substream) {
|
||||
switch (s->stream) {
|
||||
|
@ -498,13 +535,13 @@ int snd_line6_prepare(struct snd_pcm_substream *substream)
|
|||
|
||||
switch (substream->stream) {
|
||||
case SNDRV_PCM_STREAM_PLAYBACK:
|
||||
if ((line6pcm->flags & MASK_PLAYBACK) == 0)
|
||||
if ((line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) == 0)
|
||||
line6_unlink_wait_clear_audio_out_urbs(line6pcm);
|
||||
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_STREAM_CAPTURE:
|
||||
if ((line6pcm->flags & MASK_CAPTURE) == 0)
|
||||
if ((line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) == 0)
|
||||
line6_unlink_wait_clear_audio_in_urbs(line6pcm);
|
||||
|
||||
break;
|
||||
|
@ -513,7 +550,7 @@ int snd_line6_prepare(struct snd_pcm_substream *substream)
|
|||
MISSING_CASE;
|
||||
}
|
||||
|
||||
if (!test_and_set_bit(BIT_PREPARED, &line6pcm->flags)) {
|
||||
if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) {
|
||||
line6pcm->count_out = 0;
|
||||
line6pcm->pos_out = 0;
|
||||
line6pcm->pos_out_done = 0;
|
||||
|
|
|
@ -46,57 +46,131 @@
|
|||
(line6pcm->pcm->streams[stream].substream)
|
||||
|
||||
/*
|
||||
PCM mode bits and masks.
|
||||
"ALSA": operations triggered by applications via ALSA
|
||||
"MONITOR": software monitoring
|
||||
"IMPULSE": optional impulse response operation
|
||||
PCM mode bits.
|
||||
|
||||
There are several features of the Line6 USB driver which require PCM
|
||||
data to be exchanged with the device:
|
||||
*) PCM playback and capture via ALSA
|
||||
*) software monitoring (for devices without hardware monitoring)
|
||||
*) optional impulse response measurement
|
||||
However, from the device's point of view, there is just a single
|
||||
capture and playback stream, which must be shared between these
|
||||
subsystems. It is therefore necessary to maintain the state of the
|
||||
subsystems with respect to PCM usage. We define several constants of
|
||||
the form LINE6_BIT_PCM_<subsystem>_<direction>_<resource> with the
|
||||
following meanings:
|
||||
*) <subsystem> is one of
|
||||
-) ALSA: PCM playback and capture via ALSA
|
||||
-) MONITOR: software monitoring
|
||||
-) IMPULSE: optional impulse response measurement
|
||||
*) <direction> is one of
|
||||
-) PLAYBACK: audio output (from host to device)
|
||||
-) CAPTURE: audio input (from device to host)
|
||||
*) <resource> is one of
|
||||
-) BUFFER: buffer required by PCM data stream
|
||||
-) STREAM: actual PCM data stream
|
||||
|
||||
The subsystems call line6_pcm_acquire() to acquire the (shared)
|
||||
resources needed for a particular operation (e.g., allocate the buffer
|
||||
for ALSA playback or start the capture stream for software monitoring).
|
||||
When a resource is no longer needed, it is released by calling
|
||||
line6_pcm_release(). Buffer allocation and stream startup are handled
|
||||
separately to allow the ALSA kernel driver to perform them at
|
||||
appropriate places (since the callback which starts a PCM stream is not
|
||||
allowed to sleep).
|
||||
*/
|
||||
enum {
|
||||
/* individual bits: */
|
||||
BIT_PCM_ALSA_PLAYBACK,
|
||||
BIT_PCM_ALSA_CAPTURE,
|
||||
BIT_PCM_MONITOR_PLAYBACK,
|
||||
BIT_PCM_MONITOR_CAPTURE,
|
||||
/* individual bit indices: */
|
||||
LINE6_INDEX_PCM_ALSA_PLAYBACK_BUFFER,
|
||||
LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM,
|
||||
LINE6_INDEX_PCM_ALSA_CAPTURE_BUFFER,
|
||||
LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
|
||||
LINE6_INDEX_PCM_MONITOR_PLAYBACK_BUFFER,
|
||||
LINE6_INDEX_PCM_MONITOR_PLAYBACK_STREAM,
|
||||
LINE6_INDEX_PCM_MONITOR_CAPTURE_BUFFER,
|
||||
LINE6_INDEX_PCM_MONITOR_CAPTURE_STREAM,
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
BIT_PCM_IMPULSE_PLAYBACK,
|
||||
BIT_PCM_IMPULSE_CAPTURE,
|
||||
LINE6_INDEX_PCM_IMPULSE_PLAYBACK_BUFFER,
|
||||
LINE6_INDEX_PCM_IMPULSE_PLAYBACK_STREAM,
|
||||
LINE6_INDEX_PCM_IMPULSE_CAPTURE_BUFFER,
|
||||
LINE6_INDEX_PCM_IMPULSE_CAPTURE_STREAM,
|
||||
#endif
|
||||
BIT_PAUSE_PLAYBACK,
|
||||
BIT_PREPARED,
|
||||
LINE6_INDEX_PAUSE_PLAYBACK,
|
||||
LINE6_INDEX_PREPARED,
|
||||
|
||||
/* individual masks: */
|
||||
/* *INDENT-OFF* */
|
||||
MASK_PCM_ALSA_PLAYBACK = 1 << BIT_PCM_ALSA_PLAYBACK,
|
||||
MASK_PCM_ALSA_CAPTURE = 1 << BIT_PCM_ALSA_CAPTURE,
|
||||
MASK_PCM_MONITOR_PLAYBACK = 1 << BIT_PCM_MONITOR_PLAYBACK,
|
||||
MASK_PCM_MONITOR_CAPTURE = 1 << BIT_PCM_MONITOR_CAPTURE,
|
||||
/* individual bit masks: */
|
||||
LINE6_BIT(PCM_ALSA_PLAYBACK_BUFFER),
|
||||
LINE6_BIT(PCM_ALSA_PLAYBACK_STREAM),
|
||||
LINE6_BIT(PCM_ALSA_CAPTURE_BUFFER),
|
||||
LINE6_BIT(PCM_ALSA_CAPTURE_STREAM),
|
||||
LINE6_BIT(PCM_MONITOR_PLAYBACK_BUFFER),
|
||||
LINE6_BIT(PCM_MONITOR_PLAYBACK_STREAM),
|
||||
LINE6_BIT(PCM_MONITOR_CAPTURE_BUFFER),
|
||||
LINE6_BIT(PCM_MONITOR_CAPTURE_STREAM),
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
MASK_PCM_IMPULSE_PLAYBACK = 1 << BIT_PCM_IMPULSE_PLAYBACK,
|
||||
MASK_PCM_IMPULSE_CAPTURE = 1 << BIT_PCM_IMPULSE_CAPTURE,
|
||||
LINE6_BIT(PCM_IMPULSE_PLAYBACK_BUFFER),
|
||||
LINE6_BIT(PCM_IMPULSE_PLAYBACK_STREAM),
|
||||
LINE6_BIT(PCM_IMPULSE_CAPTURE_BUFFER),
|
||||
LINE6_BIT(PCM_IMPULSE_CAPTURE_STREAM),
|
||||
#endif
|
||||
MASK_PAUSE_PLAYBACK = 1 << BIT_PAUSE_PLAYBACK,
|
||||
MASK_PREPARED = 1 << BIT_PREPARED,
|
||||
/* *INDENT-ON* */
|
||||
LINE6_BIT(PAUSE_PLAYBACK),
|
||||
LINE6_BIT(PREPARED),
|
||||
|
||||
/* combined bit masks (by operation): */
|
||||
LINE6_BITS_PCM_ALSA_BUFFER =
|
||||
LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER |
|
||||
LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER,
|
||||
|
||||
LINE6_BITS_PCM_ALSA_STREAM =
|
||||
LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM |
|
||||
LINE6_BIT_PCM_ALSA_CAPTURE_STREAM,
|
||||
|
||||
LINE6_BITS_PCM_MONITOR =
|
||||
LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER |
|
||||
LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM |
|
||||
LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER |
|
||||
LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM,
|
||||
|
||||
/* combined masks (by operation): */
|
||||
MASK_PCM_ALSA = MASK_PCM_ALSA_PLAYBACK | MASK_PCM_ALSA_CAPTURE,
|
||||
MASK_PCM_MONITOR = MASK_PCM_MONITOR_PLAYBACK | MASK_PCM_MONITOR_CAPTURE,
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
MASK_PCM_IMPULSE = MASK_PCM_IMPULSE_PLAYBACK | MASK_PCM_IMPULSE_CAPTURE,
|
||||
LINE6_BITS_PCM_IMPULSE =
|
||||
LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER |
|
||||
LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM |
|
||||
LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER |
|
||||
LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM,
|
||||
#endif
|
||||
|
||||
/* combined masks (by direction): */
|
||||
/* combined bit masks (by direction): */
|
||||
LINE6_BITS_PLAYBACK_BUFFER =
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
MASK_PLAYBACK =
|
||||
MASK_PCM_ALSA_PLAYBACK | MASK_PCM_MONITOR_PLAYBACK |
|
||||
MASK_PCM_IMPULSE_PLAYBACK,
|
||||
MASK_CAPTURE =
|
||||
MASK_PCM_ALSA_CAPTURE | MASK_PCM_MONITOR_CAPTURE |
|
||||
MASK_PCM_IMPULSE_CAPTURE
|
||||
#else
|
||||
MASK_PLAYBACK = MASK_PCM_ALSA_PLAYBACK | MASK_PCM_MONITOR_PLAYBACK,
|
||||
MASK_CAPTURE = MASK_PCM_ALSA_CAPTURE | MASK_PCM_MONITOR_CAPTURE
|
||||
LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER |
|
||||
#endif
|
||||
LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER |
|
||||
LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER ,
|
||||
|
||||
LINE6_BITS_PLAYBACK_STREAM =
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM |
|
||||
#endif
|
||||
LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM |
|
||||
LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM ,
|
||||
|
||||
LINE6_BITS_CAPTURE_BUFFER =
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER |
|
||||
#endif
|
||||
LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER |
|
||||
LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER ,
|
||||
|
||||
LINE6_BITS_CAPTURE_STREAM =
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM |
|
||||
#endif
|
||||
LINE6_BIT_PCM_ALSA_CAPTURE_STREAM |
|
||||
LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM,
|
||||
|
||||
LINE6_BITS_STREAM =
|
||||
LINE6_BITS_PLAYBACK_STREAM |
|
||||
LINE6_BITS_CAPTURE_STREAM
|
||||
};
|
||||
|
||||
struct line6_pcm_properties {
|
||||
|
@ -290,7 +364,7 @@ struct snd_line6_pcm {
|
|||
#endif
|
||||
|
||||
/**
|
||||
Several status bits (see BIT_*).
|
||||
Several status bits (see LINE6_BIT_*).
|
||||
*/
|
||||
unsigned long flags;
|
||||
|
||||
|
@ -302,16 +376,7 @@ extern int line6_init_pcm(struct usb_line6 *line6,
|
|||
extern int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd);
|
||||
extern int snd_line6_prepare(struct snd_pcm_substream *substream);
|
||||
extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm);
|
||||
extern int line6_pcm_start(struct snd_line6_pcm *line6pcm, int channels);
|
||||
extern int line6_pcm_stop(struct snd_line6_pcm *line6pcm, int channels);
|
||||
|
||||
#define PRINT_FRAME_DIFF(op) { \
|
||||
static int diff_prev = 1000; \
|
||||
int diff = line6pcm->last_frame_out - line6pcm->last_frame_in; \
|
||||
if ((diff != diff_prev) && (abs(diff) < 100)) { \
|
||||
printk(KERN_INFO "%s frame diff = %d\n", op, diff); \
|
||||
diff_prev = diff; \
|
||||
} \
|
||||
}
|
||||
extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels);
|
||||
extern int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -166,7 +166,7 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
|
|||
struct usb_iso_packet_descriptor *fout =
|
||||
&urb_out->iso_frame_desc[i];
|
||||
|
||||
if (line6pcm->flags & MASK_CAPTURE)
|
||||
if (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM)
|
||||
fsize = line6pcm->prev_fsize;
|
||||
|
||||
if (fsize == 0) {
|
||||
|
@ -196,8 +196,8 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
|
|||
urb_out->transfer_buffer_length = urb_size;
|
||||
urb_out->context = line6pcm;
|
||||
|
||||
if (test_bit(BIT_PCM_ALSA_PLAYBACK, &line6pcm->flags) &&
|
||||
!test_bit(BIT_PAUSE_PLAYBACK, &line6pcm->flags)) {
|
||||
if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags) &&
|
||||
!test_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags)) {
|
||||
struct snd_pcm_runtime *runtime =
|
||||
get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK)->runtime;
|
||||
|
||||
|
@ -238,10 +238,10 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
|
|||
|
||||
if (line6pcm->prev_fbuf != NULL) {
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
if (line6pcm->flags & MASK_PCM_IMPULSE) {
|
||||
if (line6pcm->flags & LINE6_BITS_PCM_IMPULSE) {
|
||||
create_impulse_test_signal(line6pcm, urb_out,
|
||||
bytes_per_frame);
|
||||
if (line6pcm->flags & MASK_PCM_ALSA_CAPTURE) {
|
||||
if (line6pcm->flags & LINE6_BIT_PCM_ALSA_CAPTURE_STREAM) {
|
||||
line6_capture_copy(line6pcm,
|
||||
urb_out->transfer_buffer,
|
||||
urb_out->
|
||||
|
@ -254,8 +254,8 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
|
|||
if (!
|
||||
(line6pcm->line6->
|
||||
properties->capabilities & LINE6_BIT_HWMON)
|
||||
&& (line6pcm->flags & MASK_PLAYBACK)
|
||||
&& (line6pcm->flags & MASK_CAPTURE))
|
||||
&& (line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM)
|
||||
&& (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM))
|
||||
add_monitor_signal(urb_out, line6pcm->prev_fbuf,
|
||||
line6pcm->volume_monitor,
|
||||
bytes_per_frame);
|
||||
|
@ -321,7 +321,7 @@ void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm)
|
|||
/*
|
||||
Wait until unlinking of all currently active playback URBs has been finished.
|
||||
*/
|
||||
static void wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
|
||||
void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
|
||||
{
|
||||
int timeout = HZ;
|
||||
unsigned int i;
|
||||
|
@ -348,26 +348,7 @@ static void wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
|
|||
void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
|
||||
{
|
||||
line6_unlink_audio_out_urbs(line6pcm);
|
||||
wait_clear_audio_out_urbs(line6pcm);
|
||||
}
|
||||
|
||||
int line6_alloc_playback_buffer(struct snd_line6_pcm *line6pcm)
|
||||
{
|
||||
/* We may be invoked multiple times in a row so allocate once only */
|
||||
if (line6pcm->buffer_out)
|
||||
return 0;
|
||||
|
||||
line6pcm->buffer_out =
|
||||
kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
|
||||
line6pcm->max_packet_size, GFP_KERNEL);
|
||||
|
||||
if (!line6pcm->buffer_out) {
|
||||
dev_err(line6pcm->line6->ifcdev,
|
||||
"cannot malloc playback buffer\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
line6_wait_clear_audio_out_urbs(line6pcm);
|
||||
}
|
||||
|
||||
void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm)
|
||||
|
@ -407,7 +388,7 @@ static void audio_out_callback(struct urb *urb)
|
|||
|
||||
spin_lock_irqsave(&line6pcm->lock_audio_out, flags);
|
||||
|
||||
if (test_bit(BIT_PCM_ALSA_PLAYBACK, &line6pcm->flags)) {
|
||||
if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags)) {
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
line6pcm->pos_out_done +=
|
||||
length / line6pcm->properties->bytes_per_frame;
|
||||
|
@ -432,7 +413,7 @@ static void audio_out_callback(struct urb *urb)
|
|||
if (!shutdown) {
|
||||
submit_audio_out_urb(line6pcm);
|
||||
|
||||
if (test_bit(BIT_PCM_ALSA_PLAYBACK, &line6pcm->flags)) {
|
||||
if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags)) {
|
||||
line6pcm->bytes_out += length;
|
||||
if (line6pcm->bytes_out >= line6pcm->period_out) {
|
||||
line6pcm->bytes_out %= line6pcm->period_out;
|
||||
|
@ -484,17 +465,17 @@ static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream,
|
|||
}
|
||||
/* -- [FD] end */
|
||||
|
||||
if ((line6pcm->flags & MASK_PLAYBACK) == 0) {
|
||||
ret = line6_alloc_playback_buffer(line6pcm);
|
||||
ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
}
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_pcm_lib_malloc_pages(substream,
|
||||
params_buffer_bytes(hw_params));
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
|
||||
return ret;
|
||||
}
|
||||
|
||||
line6pcm->period_out = params_period_bytes(hw_params);
|
||||
return 0;
|
||||
|
@ -504,12 +485,7 @@ static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream,
|
|||
static int snd_line6_playback_hw_free(struct snd_pcm_substream *substream)
|
||||
{
|
||||
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
|
||||
|
||||
if ((line6pcm->flags & MASK_PLAYBACK) == 0) {
|
||||
line6_unlink_wait_clear_audio_out_urbs(line6pcm);
|
||||
line6_free_playback_buffer(line6pcm);
|
||||
}
|
||||
|
||||
line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
|
||||
return snd_pcm_lib_free_pages(substream);
|
||||
}
|
||||
|
||||
|
@ -523,7 +499,7 @@ int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd)
|
|||
#ifdef CONFIG_PM
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
#endif
|
||||
err = line6_pcm_start(line6pcm, MASK_PCM_ALSA_PLAYBACK);
|
||||
err = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
@ -534,7 +510,7 @@ int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd)
|
|||
#ifdef CONFIG_PM
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
#endif
|
||||
err = line6_pcm_stop(line6pcm, MASK_PCM_ALSA_PLAYBACK);
|
||||
err = line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM);
|
||||
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
@ -542,11 +518,11 @@ int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd)
|
|||
break;
|
||||
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
set_bit(BIT_PAUSE_PLAYBACK, &line6pcm->flags);
|
||||
set_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags);
|
||||
break;
|
||||
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
clear_bit(BIT_PAUSE_PLAYBACK, &line6pcm->flags);
|
||||
clear_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags);
|
||||
break;
|
||||
|
||||
default:
|
||||
|
|
|
@ -29,13 +29,13 @@
|
|||
|
||||
extern struct snd_pcm_ops snd_line6_playback_ops;
|
||||
|
||||
extern int line6_alloc_playback_buffer(struct snd_line6_pcm *line6pcm);
|
||||
extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm);
|
||||
extern void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm);
|
||||
extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm);
|
||||
extern void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm);
|
||||
extern void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm
|
||||
*line6pcm);
|
||||
extern void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm);
|
||||
extern int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -207,9 +207,9 @@ static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol,
|
|||
line6pcm->volume_monitor = ucontrol->value.integer.value[0];
|
||||
|
||||
if (line6pcm->volume_monitor > 0)
|
||||
line6_pcm_start(line6pcm, MASK_PCM_MONITOR);
|
||||
line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_MONITOR);
|
||||
else
|
||||
line6_pcm_stop(line6pcm, MASK_PCM_MONITOR);
|
||||
line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -264,7 +264,7 @@ static void toneport_start_pcm(unsigned long arg)
|
|||
{
|
||||
struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg;
|
||||
struct usb_line6 *line6 = &toneport->line6;
|
||||
line6_pcm_start(line6->line6pcm, MASK_PCM_MONITOR);
|
||||
line6_pcm_acquire(line6->line6pcm, LINE6_BITS_PCM_MONITOR);
|
||||
}
|
||||
|
||||
/* control definition */
|
||||
|
@ -320,7 +320,9 @@ static void toneport_setup(struct usb_line6_toneport *toneport)
|
|||
/* initialize source select: */
|
||||
switch (usbdev->descriptor.idProduct) {
|
||||
case LINE6_DEVID_TONEPORT_UX1:
|
||||
case LINE6_DEVID_TONEPORT_UX2:
|
||||
case LINE6_DEVID_PODSTUDIO_UX1:
|
||||
case LINE6_DEVID_PODSTUDIO_UX2:
|
||||
toneport_send_cmd(usbdev,
|
||||
toneport_source_info[toneport->source].code,
|
||||
0x0000);
|
||||
|
@ -363,7 +365,9 @@ static int toneport_try_init(struct usb_interface *interface,
|
|||
/* register source select control: */
|
||||
switch (usbdev->descriptor.idProduct) {
|
||||
case LINE6_DEVID_TONEPORT_UX1:
|
||||
case LINE6_DEVID_TONEPORT_UX2:
|
||||
case LINE6_DEVID_PODSTUDIO_UX1:
|
||||
case LINE6_DEVID_PODSTUDIO_UX2:
|
||||
err =
|
||||
snd_ctl_add(line6->card,
|
||||
snd_ctl_new1(&toneport_control_source,
|
||||
|
@ -442,7 +446,7 @@ void line6_toneport_disconnect(struct usb_interface *interface)
|
|||
struct snd_line6_pcm *line6pcm = toneport->line6.line6pcm;
|
||||
|
||||
if (line6pcm != NULL) {
|
||||
line6_pcm_stop(line6pcm, MASK_PCM_MONITOR);
|
||||
line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
|
||||
line6_pcm_disconnect(line6pcm);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,31 +39,29 @@
|
|||
#define LINE6_DEVID_TONEPORT_UX2 0x4142
|
||||
#define LINE6_DEVID_VARIAX 0x534d
|
||||
|
||||
enum {
|
||||
LINE6_ID_BASSPODXT,
|
||||
LINE6_ID_BASSPODXTLIVE,
|
||||
LINE6_ID_BASSPODXTPRO,
|
||||
LINE6_ID_GUITARPORT,
|
||||
LINE6_ID_POCKETPOD,
|
||||
LINE6_ID_PODHD300,
|
||||
LINE6_ID_PODHD500,
|
||||
LINE6_ID_PODSTUDIO_GX,
|
||||
LINE6_ID_PODSTUDIO_UX1,
|
||||
LINE6_ID_PODSTUDIO_UX2,
|
||||
LINE6_ID_PODX3,
|
||||
LINE6_ID_PODX3LIVE,
|
||||
LINE6_ID_PODXT,
|
||||
LINE6_ID_PODXTLIVE,
|
||||
LINE6_ID_PODXTPRO,
|
||||
LINE6_ID_TONEPORT_GX,
|
||||
LINE6_ID_TONEPORT_UX1,
|
||||
LINE6_ID_TONEPORT_UX2,
|
||||
LINE6_ID_VARIAX
|
||||
};
|
||||
|
||||
#define LINE6_BIT(x) LINE6_BIT_ ## x = 1 << LINE6_ID_ ## x
|
||||
#define LINE6_BIT(x) LINE6_BIT_ ## x = 1 << LINE6_INDEX_ ## x
|
||||
|
||||
enum {
|
||||
LINE6_INDEX_BASSPODXT,
|
||||
LINE6_INDEX_BASSPODXTLIVE,
|
||||
LINE6_INDEX_BASSPODXTPRO,
|
||||
LINE6_INDEX_GUITARPORT,
|
||||
LINE6_INDEX_POCKETPOD,
|
||||
LINE6_INDEX_PODHD300,
|
||||
LINE6_INDEX_PODHD500,
|
||||
LINE6_INDEX_PODSTUDIO_GX,
|
||||
LINE6_INDEX_PODSTUDIO_UX1,
|
||||
LINE6_INDEX_PODSTUDIO_UX2,
|
||||
LINE6_INDEX_PODX3,
|
||||
LINE6_INDEX_PODX3LIVE,
|
||||
LINE6_INDEX_PODXT,
|
||||
LINE6_INDEX_PODXTLIVE,
|
||||
LINE6_INDEX_PODXTPRO,
|
||||
LINE6_INDEX_TONEPORT_GX,
|
||||
LINE6_INDEX_TONEPORT_UX1,
|
||||
LINE6_INDEX_TONEPORT_UX2,
|
||||
LINE6_INDEX_VARIAX,
|
||||
|
||||
LINE6_BIT(BASSPODXT),
|
||||
LINE6_BIT(BASSPODXTLIVE),
|
||||
LINE6_BIT(BASSPODXTPRO),
|
||||
|
|
|
@ -3825,6 +3825,7 @@ static int easycap_usb_probe(struct usb_interface *intf,
|
|||
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||||
pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
|
||||
if (!pdata_urb) {
|
||||
usb_free_urb(purb);
|
||||
SAM("ERROR: Could not allocate struct data_urb.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
|
|
@ -3,5 +3,8 @@ TODO:
|
|||
Upon Unstaging:
|
||||
- move mei.h to include/linux/mei.h
|
||||
- Documentation/ioctl/ioctl-number.txt
|
||||
- move mei.txt under Documentation/mei/
|
||||
- move mei-amt-version.c under Documentation/mei
|
||||
- add hostprogs-y for mei-amt-version.c
|
||||
- drop mei_version.h
|
||||
- Updated MAINTAINERS
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
*
|
||||
* Intel Management Engine Interface (Intel MEI) Linux driver
|
||||
* Copyright (c) 2003-2011, Intel Corporation.
|
||||
* Copyright (c) 2003-2012, Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
*
|
||||
* Intel Management Engine Interface (Intel MEI) Linux driver
|
||||
* Copyright (c) 2003-2011, Intel Corporation.
|
||||
* Copyright (c) 2003-2012, Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
*
|
||||
* Intel Management Engine Interface (Intel MEI) Linux driver
|
||||
* Copyright (c) 2003-2011, Intel Corporation.
|
||||
* Copyright (c) 2003-2012, Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
@ -215,26 +215,17 @@ int mei_count_full_read_slots(struct mei_device *dev)
|
|||
* @buffer: message buffer will be written
|
||||
* @buffer_length: message size will be read
|
||||
*/
|
||||
void mei_read_slots(struct mei_device *dev,
|
||||
unsigned char *buffer, unsigned long buffer_length)
|
||||
void mei_read_slots(struct mei_device *dev, unsigned char *buffer,
|
||||
unsigned long buffer_length)
|
||||
{
|
||||
u32 i = 0;
|
||||
unsigned char temp_buf[sizeof(u32)];
|
||||
u32 *reg_buf = (u32 *)buffer;
|
||||
|
||||
while (buffer_length >= sizeof(u32)) {
|
||||
((u32 *) buffer)[i] = mei_mecbrw_read(dev);
|
||||
|
||||
dev_dbg(&dev->pdev->dev,
|
||||
"buffer[%d]= %d\n",
|
||||
i, ((u32 *) buffer)[i]);
|
||||
|
||||
i++;
|
||||
buffer_length -= sizeof(u32);
|
||||
}
|
||||
for (; buffer_length >= sizeof(u32); buffer_length -= sizeof(u32))
|
||||
*reg_buf++ = mei_mecbrw_read(dev);
|
||||
|
||||
if (buffer_length > 0) {
|
||||
*((u32 *) &temp_buf) = mei_mecbrw_read(dev);
|
||||
memcpy(&buffer[i * 4], temp_buf, buffer_length);
|
||||
u32 reg = mei_mecbrw_read(dev);
|
||||
memcpy(reg_buf, ®, buffer_length);
|
||||
}
|
||||
|
||||
dev->host_hw_state |= H_IG;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
*
|
||||
* Intel Management Engine Interface (Intel MEI) Linux driver
|
||||
* Copyright (c) 2003-2011, Intel Corporation.
|
||||
* Copyright (c) 2003-2012, Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
@ -33,7 +33,8 @@
|
|||
|
||||
|
||||
void mei_read_slots(struct mei_device *dev,
|
||||
unsigned char *buffer, unsigned long buffer_length);
|
||||
unsigned char *buffer,
|
||||
unsigned long buffer_length);
|
||||
|
||||
int mei_write_message(struct mei_device *dev,
|
||||
struct mei_msg_hdr *header,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
*
|
||||
* Intel Management Engine Interface (Intel MEI) Linux driver
|
||||
* Copyright (c) 2003-2011, Intel Corporation.
|
||||
* Copyright (c) 2003-2012, Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
@ -123,8 +123,7 @@ static int mei_irq_thread_read_amthi_message(struct mei_io_list *complete_list,
|
|||
BUG_ON(mei_hdr->me_addr != dev->iamthif_cl.me_client_id);
|
||||
BUG_ON(dev->iamthif_state != MEI_IAMTHIF_READING);
|
||||
|
||||
buffer = (unsigned char *) (dev->iamthif_msg_buf +
|
||||
dev->iamthif_msg_buf_index);
|
||||
buffer = dev->iamthif_msg_buf + dev->iamthif_msg_buf_index;
|
||||
BUG_ON(dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length);
|
||||
|
||||
mei_read_slots(dev, buffer, mei_hdr->length);
|
||||
|
@ -206,9 +205,7 @@ static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list,
|
|||
cl = (struct mei_cl *)cb_pos->file_private;
|
||||
if (cl && _mei_irq_thread_state_ok(cl, mei_hdr)) {
|
||||
cl->reading_state = MEI_READING;
|
||||
buffer = (unsigned char *)
|
||||
(cb_pos->response_buffer.data +
|
||||
cb_pos->information);
|
||||
buffer = cb_pos->response_buffer.data + cb_pos->information;
|
||||
|
||||
if (cb_pos->response_buffer.size <
|
||||
mei_hdr->length + cb_pos->information) {
|
||||
|
@ -247,8 +244,7 @@ static int mei_irq_thread_read_client_message(struct mei_io_list *complete_list,
|
|||
quit:
|
||||
dev_dbg(&dev->pdev->dev, "message read\n");
|
||||
if (!buffer) {
|
||||
mei_read_slots(dev, (unsigned char *) dev->rd_msg_buf,
|
||||
mei_hdr->length);
|
||||
mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
|
||||
dev_dbg(&dev->pdev->dev, "discarding message, header =%08x.\n",
|
||||
*(u32 *) dev->rd_msg_buf);
|
||||
}
|
||||
|
@ -632,13 +628,11 @@ static void mei_irq_thread_read_bus_message(struct mei_device *dev,
|
|||
struct hbm_host_stop_request *host_stop_req;
|
||||
int res;
|
||||
|
||||
unsigned char *buffer;
|
||||
|
||||
/* read the message to our buffer */
|
||||
buffer = (unsigned char *) dev->rd_msg_buf;
|
||||
BUG_ON(mei_hdr->length >= sizeof(dev->rd_msg_buf));
|
||||
mei_read_slots(dev, buffer, mei_hdr->length);
|
||||
mei_msg = (struct mei_bus_message *) buffer;
|
||||
mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
|
||||
mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
|
||||
|
||||
switch (*(u8 *) mei_msg) {
|
||||
case HOST_START_RES_CMD:
|
||||
|
@ -1423,7 +1417,7 @@ void mei_timer(struct work_struct *work)
|
|||
|
||||
if (dev->iamthif_stall_timer) {
|
||||
if (--dev->iamthif_stall_timer == 0) {
|
||||
dev_dbg(&dev->pdev->dev, "reseting because of hang to amthi.\n");
|
||||
dev_dbg(&dev->pdev->dev, "resetting because of hang to amthi.\n");
|
||||
mei_reset(dev, 1);
|
||||
dev->iamthif_msg_buf_size = 0;
|
||||
dev->iamthif_msg_buf_index = 0;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
*
|
||||
* Intel Management Engine Interface (Intel MEI) Linux driver
|
||||
* Copyright (c) 2003-2011, Intel Corporation.
|
||||
* Copyright (c) 2003-2012, Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
*
|
||||
* Intel Management Engine Interface (Intel MEI) Linux driver
|
||||
* Copyright (c) 2003-2011, Intel Corporation.
|
||||
* Copyright (c) 2003-2012, Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
|
|
@ -0,0 +1,479 @@
|
|||
/******************************************************************************
|
||||
* Intel Management Engine Interface (Intel MEI) Linux driver
|
||||
* Intel MEI Interface Header
|
||||
*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2012 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
|
||||
* USA
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution
|
||||
* in the file called LICENSE.GPL.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Corporation.
|
||||
* linux-mei@linux.intel.com
|
||||
* http://www.intel.com
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <bits/wordsize.h>
|
||||
#include "mei.h"
|
||||
|
||||
/*****************************************************************************
|
||||
* Intel Management Enginin Interface
|
||||
*****************************************************************************/
|
||||
|
||||
#define mei_msg(_me, fmt, ARGS...) do { \
|
||||
if (_me->verbose) \
|
||||
fprintf(stderr, fmt, ##ARGS); \
|
||||
} while (0)
|
||||
|
||||
#define mei_err(_me, fmt, ARGS...) do { \
|
||||
fprintf(stderr, "Error: " fmt, ##ARGS); \
|
||||
} while (0)
|
||||
|
||||
struct mei {
|
||||
uuid_le guid;
|
||||
bool initialized;
|
||||
bool verbose;
|
||||
unsigned int buf_size;
|
||||
unsigned char prot_ver;
|
||||
int fd;
|
||||
};
|
||||
|
||||
static void mei_deinit(struct mei *cl)
|
||||
{
|
||||
if (cl->fd != -1)
|
||||
close(cl->fd);
|
||||
cl->fd = -1;
|
||||
cl->buf_size = 0;
|
||||
cl->prot_ver = 0;
|
||||
cl->initialized = false;
|
||||
}
|
||||
|
||||
static bool mei_init(struct mei *me, const uuid_le *guid,
|
||||
unsigned char req_protocol_version, bool verbose)
|
||||
{
|
||||
int result;
|
||||
struct mei_client *cl;
|
||||
struct mei_connect_client_data data;
|
||||
|
||||
mei_deinit(me);
|
||||
|
||||
me->verbose = verbose;
|
||||
|
||||
me->fd = open("/dev/mei", O_RDWR);
|
||||
if (me->fd == -1) {
|
||||
mei_err(me, "Cannot establish a handle to the Intel MEI driver\n");
|
||||
goto err;
|
||||
}
|
||||
memcpy(&me->guid, guid, sizeof(*guid));
|
||||
memset(&data, 0, sizeof(data));
|
||||
me->initialized = true;
|
||||
|
||||
memcpy(&data.in_client_uuid, &me->guid, sizeof(me->guid));
|
||||
result = ioctl(me->fd, IOCTL_MEI_CONNECT_CLIENT, &data);
|
||||
if (result) {
|
||||
mei_err(me, "IOCTL_MEI_CONNECT_CLIENT receive message. err=%d\n", result);
|
||||
goto err;
|
||||
}
|
||||
cl = &data.out_client_properties;
|
||||
mei_msg(me, "max_message_length %d\n", cl->max_msg_length);
|
||||
mei_msg(me, "protocol_version %d\n", cl->protocol_version);
|
||||
|
||||
if ((req_protocol_version > 0) &&
|
||||
(cl->protocol_version != req_protocol_version)) {
|
||||
mei_err(me, "Intel MEI protocol version not supported\n");
|
||||
goto err;
|
||||
}
|
||||
|
||||
me->buf_size = cl->max_msg_length;
|
||||
me->prot_ver = cl->protocol_version;
|
||||
|
||||
return true;
|
||||
err:
|
||||
mei_deinit(me);
|
||||
return false;
|
||||
}
|
||||
|
||||
static ssize_t mei_recv_msg(struct mei *me, unsigned char *buffer,
|
||||
ssize_t len, unsigned long timeout)
|
||||
{
|
||||
ssize_t rc;
|
||||
|
||||
mei_msg(me, "call read length = %zd\n", len);
|
||||
|
||||
rc = read(me->fd, buffer, len);
|
||||
if (rc < 0) {
|
||||
mei_err(me, "read failed with status %zd %s\n",
|
||||
rc, strerror(errno));
|
||||
mei_deinit(me);
|
||||
} else {
|
||||
mei_msg(me, "read succeeded with result %zd\n", rc);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
static ssize_t mei_send_msg(struct mei *me, const unsigned char *buffer,
|
||||
ssize_t len, unsigned long timeout)
|
||||
{
|
||||
struct timeval tv;
|
||||
ssize_t written;
|
||||
ssize_t rc;
|
||||
fd_set set;
|
||||
|
||||
tv.tv_sec = timeout / 1000;
|
||||
tv.tv_usec = (timeout % 1000) * 1000000;
|
||||
|
||||
mei_msg(me, "call write length = %zd\n", len);
|
||||
|
||||
written = write(me->fd, buffer, len);
|
||||
if (written < 0) {
|
||||
rc = -errno;
|
||||
mei_err(me, "write failed with status %zd %s\n",
|
||||
written, strerror(errno));
|
||||
goto out;
|
||||
}
|
||||
|
||||
FD_ZERO(&set);
|
||||
FD_SET(me->fd, &set);
|
||||
rc = select(me->fd + 1 , &set, NULL, NULL, &tv);
|
||||
if (rc > 0 && FD_ISSET(me->fd, &set)) {
|
||||
mei_msg(me, "write success\n");
|
||||
} else if (rc == 0) {
|
||||
mei_err(me, "write failed on timeout with status\n");
|
||||
goto out;
|
||||
} else { /* rc < 0 */
|
||||
mei_err(me, "write failed on select with status %zd\n", rc);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = written;
|
||||
out:
|
||||
if (rc < 0)
|
||||
mei_deinit(me);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Intel Advanced Management Technolgy ME Client
|
||||
***************************************************************************/
|
||||
|
||||
#define AMT_MAJOR_VERSION 1
|
||||
#define AMT_MINOR_VERSION 1
|
||||
|
||||
#define AMT_STATUS_SUCCESS 0x0
|
||||
#define AMT_STATUS_INTERNAL_ERROR 0x1
|
||||
#define AMT_STATUS_NOT_READY 0x2
|
||||
#define AMT_STATUS_INVALID_AMT_MODE 0x3
|
||||
#define AMT_STATUS_INVALID_MESSAGE_LENGTH 0x4
|
||||
|
||||
#define AMT_STATUS_HOST_IF_EMPTY_RESPONSE 0x4000
|
||||
#define AMT_STATUS_SDK_RESOURCES 0x1004
|
||||
|
||||
|
||||
#define AMT_BIOS_VERSION_LEN 65
|
||||
#define AMT_VERSIONS_NUMBER 50
|
||||
#define AMT_UNICODE_STRING_LEN 20
|
||||
|
||||
struct amt_unicode_string {
|
||||
uint16_t length;
|
||||
char string[AMT_UNICODE_STRING_LEN];
|
||||
} __attribute__((packed));
|
||||
|
||||
struct amt_version_type {
|
||||
struct amt_unicode_string description;
|
||||
struct amt_unicode_string version;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct amt_version {
|
||||
uint8_t major;
|
||||
uint8_t minor;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct amt_code_versions {
|
||||
uint8_t bios[AMT_BIOS_VERSION_LEN];
|
||||
uint32_t count;
|
||||
struct amt_version_type versions[AMT_VERSIONS_NUMBER];
|
||||
} __attribute__((packed));
|
||||
|
||||
/***************************************************************************
|
||||
* Intel Advanced Management Technolgy Host Interface
|
||||
***************************************************************************/
|
||||
|
||||
struct amt_host_if_msg_header {
|
||||
struct amt_version version;
|
||||
uint16_t _reserved;
|
||||
uint32_t command;
|
||||
uint32_t length;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct amt_host_if_resp_header {
|
||||
struct amt_host_if_msg_header header;
|
||||
uint32_t status;
|
||||
unsigned char data[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
const uuid_le MEI_IAMTHIF = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, \
|
||||
0xac, 0xa8, 0x46, 0xe0, 0xff, 0x65, 0x81, 0x4c);
|
||||
|
||||
#define AMT_HOST_IF_CODE_VERSIONS_REQUEST 0x0400001A
|
||||
#define AMT_HOST_IF_CODE_VERSIONS_RESPONSE 0x0480001A
|
||||
|
||||
const struct amt_host_if_msg_header CODE_VERSION_REQ = {
|
||||
.version = {AMT_MAJOR_VERSION, AMT_MINOR_VERSION},
|
||||
._reserved = 0,
|
||||
.command = AMT_HOST_IF_CODE_VERSIONS_REQUEST,
|
||||
.length = 0
|
||||
};
|
||||
|
||||
|
||||
struct amt_host_if {
|
||||
struct mei mei_cl;
|
||||
unsigned long send_timeout;
|
||||
bool initialized;
|
||||
};
|
||||
|
||||
|
||||
bool amt_host_if_init(struct amt_host_if *acmd,
|
||||
unsigned long send_timeout, bool verbose)
|
||||
{
|
||||
acmd->send_timeout = (send_timeout) ? send_timeout : 20000;
|
||||
acmd->initialized = mei_init(&acmd->mei_cl, &MEI_IAMTHIF, 0, verbose);
|
||||
return acmd->initialized;
|
||||
}
|
||||
|
||||
void amt_host_if_deinit(struct amt_host_if *acmd)
|
||||
{
|
||||
mei_deinit(&acmd->mei_cl);
|
||||
acmd->initialized = false;
|
||||
}
|
||||
|
||||
uint32_t amt_verify_code_versions(const struct amt_host_if_resp_header *resp)
|
||||
{
|
||||
uint32_t status = AMT_STATUS_SUCCESS;
|
||||
struct amt_code_versions *code_ver;
|
||||
size_t code_ver_len;
|
||||
uint32_t ver_type_cnt;
|
||||
uint32_t len;
|
||||
uint32_t i;
|
||||
|
||||
code_ver = (struct amt_code_versions *)resp->data;
|
||||
/* length - sizeof(status) */
|
||||
code_ver_len = resp->header.length - sizeof(uint32_t);
|
||||
ver_type_cnt = code_ver_len -
|
||||
sizeof(code_ver->bios) -
|
||||
sizeof(code_ver->count);
|
||||
if (code_ver->count != ver_type_cnt / sizeof(struct amt_version_type)) {
|
||||
status = AMT_STATUS_INTERNAL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
for (i = 0; i < code_ver->count; i++) {
|
||||
len = code_ver->versions[i].description.length;
|
||||
|
||||
if (len > AMT_UNICODE_STRING_LEN) {
|
||||
status = AMT_STATUS_INTERNAL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
|
||||
len = code_ver->versions[i].version.length;
|
||||
if (code_ver->versions[i].version.string[len] != '\0' ||
|
||||
len != strlen(code_ver->versions[i].version.string)) {
|
||||
status = AMT_STATUS_INTERNAL_ERROR;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
uint32_t amt_verify_response_header(uint32_t command,
|
||||
const struct amt_host_if_msg_header *resp_hdr,
|
||||
uint32_t response_size)
|
||||
{
|
||||
if (response_size < sizeof(struct amt_host_if_resp_header)) {
|
||||
return AMT_STATUS_INTERNAL_ERROR;
|
||||
} else if (response_size != (resp_hdr->length +
|
||||
sizeof(struct amt_host_if_msg_header))) {
|
||||
return AMT_STATUS_INTERNAL_ERROR;
|
||||
} else if (resp_hdr->command != command) {
|
||||
return AMT_STATUS_INTERNAL_ERROR;
|
||||
} else if (resp_hdr->_reserved != 0) {
|
||||
return AMT_STATUS_INTERNAL_ERROR;
|
||||
} else if (resp_hdr->version.major != AMT_MAJOR_VERSION ||
|
||||
resp_hdr->version.minor < AMT_MINOR_VERSION) {
|
||||
return AMT_STATUS_INTERNAL_ERROR;
|
||||
}
|
||||
return AMT_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static uint32_t amt_host_if_call(struct amt_host_if *acmd,
|
||||
const unsigned char *command, ssize_t command_sz,
|
||||
uint8_t **read_buf, uint32_t rcmd,
|
||||
unsigned int expected_sz)
|
||||
{
|
||||
uint32_t in_buf_sz;
|
||||
uint32_t out_buf_sz;
|
||||
ssize_t written;
|
||||
uint32_t status;
|
||||
struct amt_host_if_resp_header *msg_hdr;
|
||||
|
||||
in_buf_sz = acmd->mei_cl.buf_size;
|
||||
*read_buf = (uint8_t *)malloc(sizeof(uint8_t) * in_buf_sz);
|
||||
if (*read_buf == NULL)
|
||||
return AMT_STATUS_SDK_RESOURCES;
|
||||
memset(*read_buf, 0, in_buf_sz);
|
||||
msg_hdr = (struct amt_host_if_resp_header *)*read_buf;
|
||||
|
||||
written = mei_send_msg(&acmd->mei_cl,
|
||||
command, command_sz, acmd->send_timeout);
|
||||
if (written != command_sz)
|
||||
return AMT_STATUS_INTERNAL_ERROR;
|
||||
|
||||
out_buf_sz = mei_recv_msg(&acmd->mei_cl, *read_buf, in_buf_sz, 2000);
|
||||
if (out_buf_sz <= 0)
|
||||
return AMT_STATUS_HOST_IF_EMPTY_RESPONSE;
|
||||
|
||||
status = msg_hdr->status;
|
||||
if (status != AMT_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
status = amt_verify_response_header(rcmd,
|
||||
&msg_hdr->header, out_buf_sz);
|
||||
if (status != AMT_STATUS_SUCCESS)
|
||||
return status;
|
||||
|
||||
if (expected_sz && expected_sz != out_buf_sz)
|
||||
return AMT_STATUS_INTERNAL_ERROR;
|
||||
|
||||
return AMT_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
uint32_t amt_get_code_versions(struct amt_host_if *cmd,
|
||||
struct amt_code_versions *versions)
|
||||
{
|
||||
struct amt_host_if_resp_header *response = NULL;
|
||||
uint32_t status;
|
||||
|
||||
status = amt_host_if_call(cmd,
|
||||
(const unsigned char *)&CODE_VERSION_REQ,
|
||||
sizeof(CODE_VERSION_REQ),
|
||||
(uint8_t **)&response,
|
||||
AMT_HOST_IF_CODE_VERSIONS_RESPONSE, 0);
|
||||
|
||||
if (status != AMT_STATUS_SUCCESS)
|
||||
goto out;
|
||||
|
||||
status = amt_verify_code_versions(response);
|
||||
if (status != AMT_STATUS_SUCCESS)
|
||||
goto out;
|
||||
|
||||
memcpy(versions, response->data, sizeof(struct amt_code_versions));
|
||||
out:
|
||||
if (response != NULL)
|
||||
free(response);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/************************** end of amt_host_if_command ***********************/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct amt_code_versions ver;
|
||||
struct amt_host_if acmd;
|
||||
unsigned int i;
|
||||
uint32_t status;
|
||||
int ret;
|
||||
bool verbose;
|
||||
|
||||
verbose = (argc > 1 && strcmp(argv[1], "-v") == 0);
|
||||
|
||||
if (!amt_host_if_init(&acmd, 5000, verbose)) {
|
||||
ret = 1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = amt_get_code_versions(&acmd, &ver);
|
||||
|
||||
switch (status) {
|
||||
case AMT_STATUS_HOST_IF_EMPTY_RESPONSE:
|
||||
printf("Intel AMT: DISABLED\n");
|
||||
ret = 0;
|
||||
break;
|
||||
case AMT_STATUS_SUCCESS:
|
||||
printf("Intel AMT: ENABLED\n");
|
||||
for (i = 0; i < ver.count; i++) {
|
||||
printf("%s:\t%s\n", ver.versions[i].description.string,
|
||||
ver.versions[i].version.string);
|
||||
}
|
||||
ret = 0;
|
||||
break;
|
||||
default:
|
||||
printf("An error has occurred\n");
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
|
@ -1,63 +1,68 @@
|
|||
/*
|
||||
|
||||
Intel Management Engine Interface (Intel MEI) Linux driver
|
||||
Intel MEI Interface Header
|
||||
|
||||
This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
redistributing this file, you may do so under either license.
|
||||
|
||||
GPL LICENSE SUMMARY
|
||||
|
||||
Copyright(c) 2003-2011 Intel Corporation. All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of version 2 of the GNU General Public License as
|
||||
published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
Contact Information:
|
||||
Intel Corporation.
|
||||
linux-mei@linux.intel.com
|
||||
http://www.intel.com
|
||||
|
||||
|
||||
BSD LICENSE
|
||||
|
||||
Copyright(c) 2003-2011 Intel Corporation. All rights reserved.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
* Neither the name of Intel Corporation nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
/******************************************************************************
|
||||
* Intel Management Engine Interface (Intel MEI) Linux driver
|
||||
* Intel MEI Interface Header
|
||||
*
|
||||
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||
* redistributing this file, you may do so under either license.
|
||||
*
|
||||
* GPL LICENSE SUMMARY
|
||||
*
|
||||
* Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of version 2 of the GNU General Public License as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but
|
||||
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
|
||||
* USA
|
||||
*
|
||||
* The full GNU General Public License is included in this distribution
|
||||
* in the file called LICENSE.GPL.
|
||||
*
|
||||
* Contact Information:
|
||||
* Intel Corporation.
|
||||
* linux-mei@linux.intel.com
|
||||
* http://www.intel.com
|
||||
*
|
||||
* BSD LICENSE
|
||||
*
|
||||
* Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
* * Neither the name Intel Corporation nor the names of its
|
||||
* contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef _LINUX_MEI_H
|
||||
#define _LINUX_MEI_H
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
*
|
||||
* Intel Management Engine Interface (Intel MEI) Linux driver
|
||||
* Copyright (c) 2003-2011, Intel Corporation.
|
||||
* Copyright (c) 2003-2012, Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
@ -30,6 +30,8 @@
|
|||
#define MEI_WD_PARAMS_SIZE 4
|
||||
#define MEI_WD_STATE_INDEPENDENCE_MSG_SENT (1 << 0)
|
||||
|
||||
#define MEI_RD_MSG_BUF_SIZE (128 * sizeof(u32))
|
||||
|
||||
/*
|
||||
* MEI PCI Device object
|
||||
*/
|
||||
|
@ -125,7 +127,7 @@ enum mei_cb_major_types {
|
|||
*/
|
||||
struct mei_message_data {
|
||||
u32 size;
|
||||
char *data;
|
||||
unsigned char *data;
|
||||
} __packed;
|
||||
|
||||
|
||||
|
@ -219,7 +221,7 @@ struct mei_device {
|
|||
bool need_reset;
|
||||
|
||||
u32 extra_write_index;
|
||||
u32 rd_msg_buf[128]; /* used for control messages */
|
||||
unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE]; /* control messages */
|
||||
u32 wr_msg_buf[128]; /* used for control messages */
|
||||
u32 ext_msg_buf[8]; /* for control responses */
|
||||
u32 rd_msg_hdr;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
*
|
||||
* Intel Management Engine Interface (Intel MEI) Linux driver
|
||||
* Copyright (c) 2003-2011, Intel Corporation.
|
||||
* Copyright (c) 2003-2012, Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
*
|
||||
* Intel Management Engine Interface (Intel MEI) Linux driver
|
||||
* Copyright (c) 2003-2011, Intel Corporation.
|
||||
* Copyright (c) 2003-2012, Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
|
|
|
@ -7,21 +7,21 @@ config MFD_NVEC
|
|||
|
||||
config KEYBOARD_NVEC
|
||||
bool "Keyboard on nVidia compliant EC"
|
||||
depends on MFD_NVEC && INPUT=y
|
||||
depends on MFD_NVEC && INPUT
|
||||
help
|
||||
Say Y here to enable support for a keyboard connected to
|
||||
a nVidia compliant embedded controller.
|
||||
|
||||
config SERIO_NVEC_PS2
|
||||
bool "PS2 on nVidia EC"
|
||||
depends on MFD_NVEC && MOUSE_PS2
|
||||
depends on MFD_NVEC && SERIO
|
||||
help
|
||||
Say Y here to enable support for a Touchpad / Mouse connected
|
||||
to a nVidia compliant embedded controller.
|
||||
|
||||
config NVEC_POWER
|
||||
bool "NVEC charger and battery"
|
||||
depends on MFD_NVEC && POWER_SUPPLY=y
|
||||
depends on MFD_NVEC && POWER_SUPPLY
|
||||
help
|
||||
Say Y to enable support for battery and charger interface for
|
||||
nVidia compliant embedded controllers.
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
#define I2C_CNFG_DEBOUNCE_CNT_SHIFT 12
|
||||
|
||||
#define I2C_SL_CNFG 0x20
|
||||
#define I2C_SL_NEWL (1<<2)
|
||||
#define I2C_SL_NEWSL (1<<2)
|
||||
#define I2C_SL_NACK (1<<1)
|
||||
#define I2C_SL_RESP (1<<0)
|
||||
#define I2C_SL_IRQ (1<<3)
|
||||
|
@ -687,7 +687,7 @@ static void tegra_init_i2c_slave(struct nvec_chip *nvec)
|
|||
|
||||
clk_set_rate(nvec->i2c_clk, 8 * 80000);
|
||||
|
||||
writel(I2C_SL_NEWL, nvec->base + I2C_SL_CNFG);
|
||||
writel(I2C_SL_NEWSL, nvec->base + I2C_SL_CNFG);
|
||||
writel(0x1E, nvec->base + I2C_SL_DELAY_COUNT);
|
||||
|
||||
writel(nvec->i2c_addr>>1, nvec->base + I2C_SL_ADDR1);
|
||||
|
@ -701,7 +701,7 @@ static void tegra_init_i2c_slave(struct nvec_chip *nvec)
|
|||
static void nvec_disable_i2c_slave(struct nvec_chip *nvec)
|
||||
{
|
||||
disable_irq(nvec->irq);
|
||||
writel(I2C_SL_NEWL | I2C_SL_NACK, nvec->base + I2C_SL_CNFG);
|
||||
writel(I2C_SL_NEWSL | I2C_SL_NACK, nvec->base + I2C_SL_CNFG);
|
||||
clk_disable(nvec->i2c_clk);
|
||||
}
|
||||
|
||||
|
@ -784,11 +784,6 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
|
|||
nvec->i2c_clk = i2c_clk;
|
||||
nvec->rx = &nvec->msg_pool[0];
|
||||
|
||||
/* Set the gpio to low when we've got something to say */
|
||||
err = gpio_request(nvec->gpio, "nvec gpio");
|
||||
if (err < 0)
|
||||
dev_err(nvec->dev, "couldn't request gpio\n");
|
||||
|
||||
ATOMIC_INIT_NOTIFIER_HEAD(&nvec->notifier_list);
|
||||
|
||||
init_completion(&nvec->sync_write);
|
||||
|
@ -802,6 +797,12 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
|
|||
INIT_WORK(&nvec->tx_work, nvec_request_master);
|
||||
nvec->wq = alloc_workqueue("nvec", WQ_NON_REENTRANT, 2);
|
||||
|
||||
err = gpio_request_one(nvec->gpio, GPIOF_OUT_INIT_HIGH, "nvec gpio");
|
||||
if (err < 0) {
|
||||
dev_err(nvec->dev, "couldn't request gpio\n");
|
||||
goto failed;
|
||||
}
|
||||
|
||||
err = request_irq(nvec->irq, nvec_interrupt, 0, "nvec", nvec);
|
||||
if (err) {
|
||||
dev_err(nvec->dev, "couldn't request irq\n");
|
||||
|
@ -813,8 +814,6 @@ static int __devinit tegra_nvec_probe(struct platform_device *pdev)
|
|||
|
||||
clk_enable(i2c_clk);
|
||||
|
||||
gpio_direction_output(nvec->gpio, 1);
|
||||
gpio_set_value(nvec->gpio, 1);
|
||||
|
||||
/* enable event reporting */
|
||||
nvec_write_async(nvec, EC_ENABLE_EVENT_REPORTING,
|
||||
|
|
|
@ -21,10 +21,18 @@
|
|||
|
||||
#include "nvec.h"
|
||||
|
||||
#define START_STREAMING {'\x06', '\x03', '\x04'}
|
||||
#define START_STREAMING {'\x06', '\x03', '\x06'}
|
||||
#define STOP_STREAMING {'\x06', '\x04'}
|
||||
#define SEND_COMMAND {'\x06', '\x01', '\xf4', '\x01'}
|
||||
|
||||
#ifdef NVEC_PS2_DEBUG
|
||||
#define NVEC_PHD(str, buf, len) \
|
||||
print_hex_dump(KERN_DEBUG, str, DUMP_PREFIX_NONE, \
|
||||
16, 1, buf, len, false)
|
||||
#else
|
||||
#define NVEC_PHD(str, buf, len)
|
||||
#endif
|
||||
|
||||
static const unsigned char MOUSE_RESET[] = {'\x06', '\x01', '\xff', '\x03'};
|
||||
|
||||
struct nvec_ps2 {
|
||||
|
@ -67,18 +75,18 @@ static int nvec_ps2_notifier(struct notifier_block *nb,
|
|||
case NVEC_PS2_EVT:
|
||||
for (i = 0; i < msg[1]; i++)
|
||||
serio_interrupt(ps2_dev.ser_dev, msg[2 + i], 0);
|
||||
NVEC_PHD("ps/2 mouse event: ", &msg[2], msg[1]);
|
||||
return NOTIFY_STOP;
|
||||
|
||||
case NVEC_PS2:
|
||||
if (msg[2] == 1)
|
||||
if (msg[2] == 1) {
|
||||
for (i = 0; i < (msg[1] - 2); i++)
|
||||
serio_interrupt(ps2_dev.ser_dev, msg[i + 4], 0);
|
||||
else if (msg[1] != 2) { /* !ack */
|
||||
print_hex_dump(KERN_WARNING, "unhandled mouse event: ",
|
||||
DUMP_PREFIX_NONE, 16, 1,
|
||||
msg, msg[1] + 2, true);
|
||||
NVEC_PHD("ps/2 mouse reply: ", &msg[4], msg[1] - 2);
|
||||
}
|
||||
|
||||
else if (msg[1] != 2) /* !ack */
|
||||
NVEC_PHD("unhandled mouse event: ", msg, msg[1] + 2);
|
||||
return NOTIFY_STOP;
|
||||
}
|
||||
|
||||
|
@ -90,10 +98,10 @@ static int __devinit nvec_mouse_probe(struct platform_device *pdev)
|
|||
struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
|
||||
struct serio *ser_dev = kzalloc(sizeof(struct serio), GFP_KERNEL);
|
||||
|
||||
ser_dev->id.type = SERIO_8042;
|
||||
ser_dev->id.type = SERIO_PS_PSTHRU;
|
||||
ser_dev->write = ps2_sendcommand;
|
||||
ser_dev->open = ps2_startstreaming;
|
||||
ser_dev->close = ps2_stopstreaming;
|
||||
ser_dev->start = ps2_startstreaming;
|
||||
ser_dev->stop = ps2_stopstreaming;
|
||||
|
||||
strlcpy(ser_dev->name, "nvec mouse", sizeof(ser_dev->name));
|
||||
strlcpy(ser_dev->phys, "nvec", sizeof(ser_dev->phys));
|
||||
|
@ -111,8 +119,35 @@ static int __devinit nvec_mouse_probe(struct platform_device *pdev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int nvec_mouse_suspend(struct platform_device *pdev, pm_message_t state)
|
||||
{
|
||||
struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
|
||||
|
||||
/* disable mouse */
|
||||
nvec_write_async(nvec, "\x06\xf4", 2);
|
||||
|
||||
/* send cancel autoreceive */
|
||||
nvec_write_async(nvec, "\x06\x04", 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int nvec_mouse_resume(struct platform_device *pdev)
|
||||
{
|
||||
struct nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
|
||||
|
||||
ps2_startstreaming(ps2_dev.ser_dev);
|
||||
|
||||
/* enable mouse */
|
||||
nvec_write_async(nvec, "\x06\xf5", 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver nvec_mouse_driver = {
|
||||
.probe = nvec_mouse_probe,
|
||||
.suspend = nvec_mouse_suspend,
|
||||
.resume = nvec_mouse_resume,
|
||||
.driver = {
|
||||
.name = "nvec-mouse",
|
||||
.owner = THIS_MODULE,
|
||||
|
|
|
@ -84,7 +84,7 @@ fail:
|
|||
page_cache_release(pages[i]);
|
||||
}
|
||||
drm_free_large(pages);
|
||||
return ERR_PTR(PTR_ERR(p));
|
||||
return ERR_CAST(p);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* Copyright (C) 2007-2010 Angelo Arrifano <miknix@gmail.com>
|
||||
*
|
||||
* Information gathered from disassebled dsdt and from here:
|
||||
* Information gathered from disassembled dsdt and from here:
|
||||
* <http://www.microsoft.com/whdc/system/platform/firmware/DirAppLaunch.mspx>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
|
@ -25,6 +25,8 @@
|
|||
|
||||
#define QUICKSTART_VERSION "1.03"
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
|
@ -37,41 +39,297 @@ MODULE_AUTHOR("Angelo Arrifano");
|
|||
MODULE_DESCRIPTION("ACPI Direct App Launch driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define QUICKSTART_ACPI_DEVICE_NAME "quickstart"
|
||||
#define QUICKSTART_ACPI_CLASS "quickstart"
|
||||
#define QUICKSTART_ACPI_HID "PNP0C32"
|
||||
#define QUICKSTART_ACPI_DEVICE_NAME "quickstart"
|
||||
#define QUICKSTART_ACPI_CLASS "quickstart"
|
||||
#define QUICKSTART_ACPI_HID "PNP0C32"
|
||||
|
||||
#define QUICKSTART_PF_DRIVER_NAME "quickstart"
|
||||
#define QUICKSTART_PF_DEVICE_NAME "quickstart"
|
||||
#define QUICKSTART_PF_DEVATTR_NAME "pressed_button"
|
||||
#define QUICKSTART_PF_DRIVER_NAME "quickstart"
|
||||
#define QUICKSTART_PF_DEVICE_NAME "quickstart"
|
||||
|
||||
#define QUICKSTART_MAX_BTN_NAME_LEN 16
|
||||
/*
|
||||
* There will be two events:
|
||||
* 0x02 - A hot button was pressed while device was off/sleeping.
|
||||
* 0x80 - A hot button was pressed while device was up.
|
||||
*/
|
||||
#define QUICKSTART_EVENT_WAKE 0x02
|
||||
#define QUICKSTART_EVENT_RUNTIME 0x80
|
||||
|
||||
/* There will be two events:
|
||||
* 0x02 - A hot button was pressed while device was off/sleeping.
|
||||
* 0x80 - A hot button was pressed while device was up. */
|
||||
#define QUICKSTART_EVENT_WAKE 0x02
|
||||
#define QUICKSTART_EVENT_RUNTIME 0x80
|
||||
|
||||
struct quickstart_btn {
|
||||
struct quickstart_button {
|
||||
char *name;
|
||||
unsigned int id;
|
||||
struct quickstart_btn *next;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
static struct quickstart_driver_data {
|
||||
struct quickstart_btn *btn_lst;
|
||||
struct quickstart_btn *pressed;
|
||||
} quickstart_data;
|
||||
|
||||
/* ACPI driver Structs */
|
||||
struct quickstart_acpi {
|
||||
struct acpi_device *device;
|
||||
struct quickstart_btn *btn;
|
||||
struct quickstart_button *button;
|
||||
};
|
||||
static int quickstart_acpi_add(struct acpi_device *device);
|
||||
static int quickstart_acpi_remove(struct acpi_device *device, int type);
|
||||
static const struct acpi_device_id quickstart_device_ids[] = {
|
||||
|
||||
static LIST_HEAD(buttons);
|
||||
static struct quickstart_button *pressed;
|
||||
|
||||
static struct input_dev *quickstart_input;
|
||||
|
||||
/* Platform driver functions */
|
||||
static ssize_t quickstart_buttons_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int count = 0;
|
||||
struct quickstart_button *b;
|
||||
|
||||
if (list_empty(&buttons))
|
||||
return snprintf(buf, PAGE_SIZE, "none");
|
||||
|
||||
list_for_each_entry(b, &buttons, list) {
|
||||
count += snprintf(buf + count, PAGE_SIZE - count, "%u\t%s\n",
|
||||
b->id, b->name);
|
||||
|
||||
if (count >= PAGE_SIZE) {
|
||||
count = PAGE_SIZE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t quickstart_pressed_button_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||
(pressed ? pressed->name : "none"));
|
||||
}
|
||||
|
||||
|
||||
static ssize_t quickstart_pressed_button_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
if (count < 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (strncasecmp(buf, "none", 4) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
pressed = NULL;
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Helper functions */
|
||||
static struct quickstart_button *quickstart_buttons_add(void)
|
||||
{
|
||||
struct quickstart_button *b;
|
||||
|
||||
b = kzalloc(sizeof(*b), GFP_KERNEL);
|
||||
if (!b)
|
||||
return NULL;
|
||||
|
||||
list_add_tail(&b->list, &buttons);
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
static void quickstart_button_del(struct quickstart_button *data)
|
||||
{
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
list_del(&data->list);
|
||||
kfree(data->name);
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
static void quickstart_buttons_free(void)
|
||||
{
|
||||
struct quickstart_button *b, *n;
|
||||
|
||||
list_for_each_entry_safe(b, n, &buttons, list)
|
||||
quickstart_button_del(b);
|
||||
}
|
||||
|
||||
/* ACPI Driver functions */
|
||||
static void quickstart_acpi_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct quickstart_acpi *quickstart = data;
|
||||
|
||||
if (!quickstart)
|
||||
return;
|
||||
|
||||
switch (event) {
|
||||
case QUICKSTART_EVENT_WAKE:
|
||||
pressed = quickstart->button;
|
||||
break;
|
||||
case QUICKSTART_EVENT_RUNTIME:
|
||||
input_report_key(quickstart_input, quickstart->button->id, 1);
|
||||
input_sync(quickstart_input);
|
||||
input_report_key(quickstart_input, quickstart->button->id, 0);
|
||||
input_sync(quickstart_input);
|
||||
break;
|
||||
default:
|
||||
pr_err("Unexpected ACPI event notify (%u)\n", event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static int quickstart_acpi_ghid(struct quickstart_acpi *quickstart)
|
||||
{
|
||||
acpi_status status;
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
int ret = 0;
|
||||
|
||||
/*
|
||||
* This returns a buffer telling the button usage ID,
|
||||
* and triggers pending notify events (The ones before booting).
|
||||
*/
|
||||
status = acpi_evaluate_object(quickstart->device->handle, "GHID", NULL,
|
||||
&buffer);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
pr_err("%s GHID method failed\n", quickstart->button->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/*
|
||||
* <<The GHID method can return a BYTE, WORD, or DWORD.
|
||||
* The value must be encoded in little-endian byte
|
||||
* order (least significant byte first).>>
|
||||
*/
|
||||
switch (buffer.length) {
|
||||
case 1:
|
||||
quickstart->button->id = *(uint8_t *)buffer.pointer;
|
||||
break;
|
||||
case 2:
|
||||
quickstart->button->id = *(uint16_t *)buffer.pointer;
|
||||
break;
|
||||
case 4:
|
||||
quickstart->button->id = *(uint32_t *)buffer.pointer;
|
||||
break;
|
||||
case 8:
|
||||
quickstart->button->id = *(uint64_t *)buffer.pointer;
|
||||
break;
|
||||
default:
|
||||
pr_err("%s GHID method returned buffer of unexpected length %u\n",
|
||||
quickstart->button->name, buffer.length);
|
||||
ret = -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
kfree(buffer.pointer);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int quickstart_acpi_config(struct quickstart_acpi *quickstart)
|
||||
{
|
||||
char *bid = acpi_device_bid(quickstart->device);
|
||||
char *name;
|
||||
|
||||
name = kmalloc(strlen(bid) + 1, GFP_KERNEL);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Add new button to list */
|
||||
quickstart->button = quickstart_buttons_add();
|
||||
if (!quickstart->button) {
|
||||
kfree(name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
quickstart->button->name = name;
|
||||
strcpy(quickstart->button->name, bid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int quickstart_acpi_add(struct acpi_device *device)
|
||||
{
|
||||
int ret;
|
||||
acpi_status status;
|
||||
struct quickstart_acpi *quickstart;
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
quickstart = kzalloc(sizeof(*quickstart), GFP_KERNEL);
|
||||
if (!quickstart)
|
||||
return -ENOMEM;
|
||||
|
||||
quickstart->device = device;
|
||||
|
||||
strcpy(acpi_device_name(device), QUICKSTART_ACPI_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), QUICKSTART_ACPI_CLASS);
|
||||
device->driver_data = quickstart;
|
||||
|
||||
/* Add button to list and initialize some stuff */
|
||||
ret = quickstart_acpi_config(quickstart);
|
||||
if (ret < 0)
|
||||
goto fail_config;
|
||||
|
||||
status = acpi_install_notify_handler(device->handle, ACPI_ALL_NOTIFY,
|
||||
quickstart_acpi_notify,
|
||||
quickstart);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
pr_err("Notify handler install error\n");
|
||||
ret = -ENODEV;
|
||||
goto fail_installnotify;
|
||||
}
|
||||
|
||||
ret = quickstart_acpi_ghid(quickstart);
|
||||
if (ret < 0)
|
||||
goto fail_ghid;
|
||||
|
||||
return 0;
|
||||
|
||||
fail_ghid:
|
||||
acpi_remove_notify_handler(device->handle, ACPI_ALL_NOTIFY,
|
||||
quickstart_acpi_notify);
|
||||
|
||||
fail_installnotify:
|
||||
quickstart_button_del(quickstart->button);
|
||||
|
||||
fail_config:
|
||||
|
||||
kfree(quickstart);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int quickstart_acpi_remove(struct acpi_device *device, int type)
|
||||
{
|
||||
acpi_status status;
|
||||
struct quickstart_acpi *quickstart;
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
quickstart = acpi_driver_data(device);
|
||||
if (!quickstart)
|
||||
return -EINVAL;
|
||||
|
||||
status = acpi_remove_notify_handler(device->handle, ACPI_ALL_NOTIFY,
|
||||
quickstart_acpi_notify);
|
||||
if (ACPI_FAILURE(status))
|
||||
pr_err("Error removing notify handler\n");
|
||||
|
||||
kfree(quickstart);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Platform driver structs */
|
||||
static DEVICE_ATTR(pressed_button, 0666, quickstart_pressed_button_show,
|
||||
quickstart_pressed_button_store);
|
||||
static DEVICE_ATTR(buttons, 0444, quickstart_buttons_show, NULL);
|
||||
static struct platform_device *pf_device;
|
||||
static struct platform_driver pf_driver = {
|
||||
.driver = {
|
||||
.name = QUICKSTART_PF_DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct acpi_device_id quickstart_device_ids[] = {
|
||||
{QUICKSTART_ACPI_HID, 0},
|
||||
{"", 0},
|
||||
};
|
||||
|
@ -86,273 +344,7 @@ static struct acpi_driver quickstart_acpi_driver = {
|
|||
},
|
||||
};
|
||||
|
||||
/* Input device structs */
|
||||
struct input_dev *quickstart_input;
|
||||
|
||||
/* Platform driver structs */
|
||||
static ssize_t buttons_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf);
|
||||
static ssize_t pressed_button_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf);
|
||||
static ssize_t pressed_button_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf,
|
||||
size_t count);
|
||||
static DEVICE_ATTR(pressed_button, 0666, pressed_button_show,
|
||||
pressed_button_store);
|
||||
static DEVICE_ATTR(buttons, 0444, buttons_show, NULL);
|
||||
static struct platform_device *pf_device;
|
||||
static struct platform_driver pf_driver = {
|
||||
.driver = {
|
||||
.name = QUICKSTART_PF_DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Platform driver functions
|
||||
*/
|
||||
static ssize_t buttons_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
int count = 0;
|
||||
struct quickstart_btn *ptr = quickstart_data.btn_lst;
|
||||
|
||||
if (!ptr)
|
||||
return snprintf(buf, PAGE_SIZE, "none");
|
||||
|
||||
while (ptr && (count < PAGE_SIZE)) {
|
||||
if (ptr->name) {
|
||||
count += snprintf(buf + count,
|
||||
PAGE_SIZE - count,
|
||||
"%d\t%s\n", ptr->id, ptr->name);
|
||||
}
|
||||
ptr = ptr->next;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t pressed_button_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return snprintf(buf, PAGE_SIZE, "%s\n",
|
||||
(quickstart_data.pressed ?
|
||||
quickstart_data.pressed->name : "none"));
|
||||
}
|
||||
|
||||
|
||||
static ssize_t pressed_button_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
if (count < 2)
|
||||
return -EINVAL;
|
||||
|
||||
if (strncasecmp(buf, "none", 4) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
quickstart_data.pressed = NULL;
|
||||
return count;
|
||||
}
|
||||
|
||||
/* Hotstart Helper functions */
|
||||
static int quickstart_btnlst_add(struct quickstart_btn **data)
|
||||
{
|
||||
struct quickstart_btn **ptr = &quickstart_data.btn_lst;
|
||||
|
||||
while (*ptr)
|
||||
ptr = &((*ptr)->next);
|
||||
|
||||
*ptr = kzalloc(sizeof(struct quickstart_btn), GFP_KERNEL);
|
||||
if (!*ptr) {
|
||||
*data = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
*data = *ptr;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void quickstart_btnlst_del(struct quickstart_btn *data)
|
||||
{
|
||||
struct quickstart_btn **ptr = &quickstart_data.btn_lst;
|
||||
|
||||
if (!data)
|
||||
return;
|
||||
|
||||
while (*ptr) {
|
||||
if (*ptr == data) {
|
||||
*ptr = (*ptr)->next;
|
||||
kfree(data);
|
||||
return;
|
||||
}
|
||||
ptr = &((*ptr)->next);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void quickstart_btnlst_free(void)
|
||||
{
|
||||
struct quickstart_btn *ptr = quickstart_data.btn_lst;
|
||||
struct quickstart_btn *lptr = NULL;
|
||||
|
||||
while (ptr) {
|
||||
lptr = ptr;
|
||||
ptr = ptr->next;
|
||||
kfree(lptr->name);
|
||||
kfree(lptr);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* ACPI Driver functions */
|
||||
static void quickstart_acpi_notify(acpi_handle handle, u32 event, void *data)
|
||||
{
|
||||
struct quickstart_acpi *quickstart = data;
|
||||
|
||||
if (!quickstart)
|
||||
return;
|
||||
|
||||
if (event == QUICKSTART_EVENT_WAKE)
|
||||
quickstart_data.pressed = quickstart->btn;
|
||||
else if (event == QUICKSTART_EVENT_RUNTIME) {
|
||||
input_report_key(quickstart_input, quickstart->btn->id, 1);
|
||||
input_sync(quickstart_input);
|
||||
input_report_key(quickstart_input, quickstart->btn->id, 0);
|
||||
input_sync(quickstart_input);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void quickstart_acpi_ghid(struct quickstart_acpi *quickstart)
|
||||
{
|
||||
acpi_status status;
|
||||
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
|
||||
uint32_t usageid = 0;
|
||||
|
||||
if (!quickstart)
|
||||
return;
|
||||
|
||||
/* This returns a buffer telling the button usage ID,
|
||||
* and triggers pending notify events (The ones before booting). */
|
||||
status = acpi_evaluate_object(quickstart->device->handle,
|
||||
"GHID", NULL, &buffer);
|
||||
if (ACPI_FAILURE(status) || !buffer.pointer) {
|
||||
printk(KERN_ERR "quickstart: %s GHID method failed.\n",
|
||||
quickstart->btn->name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (buffer.length < 8)
|
||||
return;
|
||||
|
||||
/* <<The GHID method can return a BYTE, WORD, or DWORD.
|
||||
* The value must be encoded in little-endian byte
|
||||
* order (least significant byte first).>> */
|
||||
usageid = *((uint32_t *)(buffer.pointer + (buffer.length - 8)));
|
||||
quickstart->btn->id = usageid;
|
||||
|
||||
kfree(buffer.pointer);
|
||||
}
|
||||
|
||||
static int quickstart_acpi_config(struct quickstart_acpi *quickstart, char *bid)
|
||||
{
|
||||
int len = strlen(bid);
|
||||
int ret;
|
||||
|
||||
/* Add button to list */
|
||||
ret = quickstart_btnlst_add(&quickstart->btn);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
quickstart->btn->name = kzalloc(len + 1, GFP_KERNEL);
|
||||
if (!quickstart->btn->name) {
|
||||
quickstart_btnlst_free();
|
||||
return -ENOMEM;
|
||||
}
|
||||
strcpy(quickstart->btn->name, bid);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int quickstart_acpi_add(struct acpi_device *device)
|
||||
{
|
||||
int ret = 0;
|
||||
acpi_status status = AE_OK;
|
||||
struct quickstart_acpi *quickstart = NULL;
|
||||
|
||||
if (!device)
|
||||
return -EINVAL;
|
||||
|
||||
quickstart = kzalloc(sizeof(struct quickstart_acpi), GFP_KERNEL);
|
||||
if (!quickstart)
|
||||
return -ENOMEM;
|
||||
|
||||
quickstart->device = device;
|
||||
strcpy(acpi_device_name(device), QUICKSTART_ACPI_DEVICE_NAME);
|
||||
strcpy(acpi_device_class(device), QUICKSTART_ACPI_CLASS);
|
||||
device->driver_data = quickstart;
|
||||
|
||||
/* Add button to list and initialize some stuff */
|
||||
ret = quickstart_acpi_config(quickstart, acpi_device_bid(device));
|
||||
if (ret)
|
||||
goto fail_config;
|
||||
|
||||
status = acpi_install_notify_handler(device->handle,
|
||||
ACPI_ALL_NOTIFY,
|
||||
quickstart_acpi_notify,
|
||||
quickstart);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
printk(KERN_ERR "quickstart: Notify handler install error\n");
|
||||
ret = -ENODEV;
|
||||
goto fail_installnotify;
|
||||
}
|
||||
|
||||
quickstart_acpi_ghid(quickstart);
|
||||
|
||||
return 0;
|
||||
|
||||
fail_installnotify:
|
||||
quickstart_btnlst_del(quickstart->btn);
|
||||
|
||||
fail_config:
|
||||
|
||||
kfree(quickstart);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int quickstart_acpi_remove(struct acpi_device *device, int type)
|
||||
{
|
||||
acpi_status status = 0;
|
||||
struct quickstart_acpi *quickstart = NULL;
|
||||
|
||||
if (!device || !acpi_driver_data(device))
|
||||
return -EINVAL;
|
||||
|
||||
quickstart = acpi_driver_data(device);
|
||||
|
||||
status = acpi_remove_notify_handler(device->handle,
|
||||
ACPI_ALL_NOTIFY,
|
||||
quickstart_acpi_notify);
|
||||
if (ACPI_FAILURE(status))
|
||||
printk(KERN_ERR "quickstart: Error removing notify handler\n");
|
||||
|
||||
|
||||
kfree(quickstart);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Module functions */
|
||||
|
||||
static void quickstart_exit(void)
|
||||
{
|
||||
input_unregister_device(quickstart_input);
|
||||
|
@ -366,15 +358,12 @@ static void quickstart_exit(void)
|
|||
|
||||
acpi_bus_unregister_driver(&quickstart_acpi_driver);
|
||||
|
||||
quickstart_btnlst_free();
|
||||
|
||||
return;
|
||||
quickstart_buttons_free();
|
||||
}
|
||||
|
||||
static int __init quickstart_init_input(void)
|
||||
{
|
||||
struct quickstart_btn **ptr = &quickstart_data.btn_lst;
|
||||
int count;
|
||||
struct quickstart_button *b;
|
||||
int ret;
|
||||
|
||||
quickstart_input = input_allocate_device();
|
||||
|
@ -385,11 +374,9 @@ static int __init quickstart_init_input(void)
|
|||
quickstart_input->name = "Quickstart ACPI Buttons";
|
||||
quickstart_input->id.bustype = BUS_HOST;
|
||||
|
||||
while (*ptr) {
|
||||
count++;
|
||||
list_for_each_entry(b, &buttons, list) {
|
||||
set_bit(EV_KEY, quickstart_input->evbit);
|
||||
set_bit((*ptr)->id, quickstart_input->keybit);
|
||||
ptr = &((*ptr)->next);
|
||||
set_bit(b->id, quickstart_input->keybit);
|
||||
}
|
||||
|
||||
ret = input_register_device(quickstart_input);
|
||||
|
@ -415,7 +402,7 @@ static int __init quickstart_init(void)
|
|||
return ret;
|
||||
|
||||
/* If existing bus with no devices */
|
||||
if (!quickstart_data.btn_lst) {
|
||||
if (list_empty(&buttons)) {
|
||||
ret = -ENODEV;
|
||||
goto fail_pfdrv_reg;
|
||||
}
|
||||
|
@ -444,14 +431,12 @@ static int __init quickstart_init(void)
|
|||
if (ret)
|
||||
goto fail_dev_file2;
|
||||
|
||||
|
||||
/* Input device */
|
||||
ret = quickstart_init_input();
|
||||
if (ret)
|
||||
goto fail_input;
|
||||
|
||||
printk(KERN_INFO "quickstart: ACPI Direct App Launch ver %s\n",
|
||||
QUICKSTART_VERSION);
|
||||
pr_info("ACPI Direct App Launch ver %s\n", QUICKSTART_VERSION);
|
||||
|
||||
return 0;
|
||||
fail_input:
|
||||
|
|
|
@ -2453,7 +2453,7 @@ static inline void update_network(struct rtllib_network *dst,
|
|||
if (src->wmm_param[0].ac_aci_acm_aifsn ||
|
||||
src->wmm_param[1].ac_aci_acm_aifsn ||
|
||||
src->wmm_param[2].ac_aci_acm_aifsn ||
|
||||
src->wmm_param[1].ac_aci_acm_aifsn)
|
||||
src->wmm_param[3].ac_aci_acm_aifsn)
|
||||
memcpy(dst->wmm_param, src->wmm_param, WME_AC_PRAM_LEN);
|
||||
|
||||
dst->SignalStrength = src->SignalStrength;
|
||||
|
|
|
@ -237,7 +237,7 @@ ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb,
|
|||
|
||||
#ifdef NOT_YET
|
||||
if (ieee->iw_mode == IW_MODE_MASTER) {
|
||||
printk(KERN_DEBUG "%s: Master mode not yet suppported.\n",
|
||||
printk(KERN_DEBUG "%s: Master mode not yet supported.\n",
|
||||
ieee->dev->name);
|
||||
return 0;
|
||||
/*
|
||||
|
|
|
@ -9,13 +9,6 @@ config R8712U
|
|||
This option adds the Realtek RTL8712 USB device such as the D-Link DWA-130.
|
||||
If built as a module, it will be called r8712u.
|
||||
|
||||
config R8712_AP
|
||||
bool "Realtek RTL8712U AP code"
|
||||
depends on R8712U
|
||||
default N
|
||||
---help---
|
||||
This option allows the Realtek RTL8712 USB device to be an Access Point.
|
||||
|
||||
config R8712_TX_AGGR
|
||||
bool "Realtek RTL8712U Transmit Aggregation code"
|
||||
depends on R8712U && BROKEN
|
||||
|
|
|
@ -140,7 +140,6 @@ struct dvobj_priv {
|
|||
u8 ishighspeed;
|
||||
uint(*inirp_init)(struct _adapter *adapter);
|
||||
uint(*inirp_deinit)(struct _adapter *adapter);
|
||||
struct semaphore usb_suspend_sema;
|
||||
struct usb_device *pusbdev;
|
||||
};
|
||||
|
||||
|
|
|
@ -330,7 +330,6 @@ u8 r8712_init_drv_sw(struct _adapter *padapter)
|
|||
padapter->stapriv.padapter = padapter;
|
||||
r8712_init_bcmc_stainfo(padapter);
|
||||
r8712_init_pwrctrl_priv(padapter);
|
||||
sema_init(&(padapter->pwrctrlpriv.pnp_pwr_mgnt_sema), 0);
|
||||
mp871xinit(padapter);
|
||||
if (init_default_value(padapter) != _SUCCESS)
|
||||
return _FAIL;
|
||||
|
|
|
@ -72,18 +72,6 @@ static inline struct list_head *get_list_head(struct __queue *queue)
|
|||
#define LIST_CONTAINOR(ptr, type, member) \
|
||||
((type *)((char *)(ptr)-(SIZE_T)(&((type *)0)->member)))
|
||||
|
||||
static inline void _enter_hwio_critical(struct semaphore *prwlock,
|
||||
unsigned long *pirqL)
|
||||
{
|
||||
down(prwlock);
|
||||
}
|
||||
|
||||
static inline void _exit_hwio_critical(struct semaphore *prwlock,
|
||||
unsigned long *pirqL)
|
||||
{
|
||||
up(prwlock);
|
||||
}
|
||||
|
||||
static inline void list_delete(struct list_head *plist)
|
||||
{
|
||||
list_del_init(plist);
|
||||
|
@ -152,11 +140,6 @@ static inline u32 _down_sema(struct semaphore *sema)
|
|||
return _SUCCESS;
|
||||
}
|
||||
|
||||
static inline void _rtl_rwlock_init(struct semaphore *prwlock)
|
||||
{
|
||||
sema_init(prwlock, 1);
|
||||
}
|
||||
|
||||
static inline void _init_listhead(struct list_head *list)
|
||||
{
|
||||
INIT_LIST_HEAD(list);
|
||||
|
|
|
@ -55,8 +55,6 @@ int r8712_init_recv_priv(struct recv_priv *precvpriv, struct _adapter *padapter)
|
|||
int alignment = 0;
|
||||
struct sk_buff *pskb = NULL;
|
||||
|
||||
sema_init(&precvpriv->recv_sema, 0);
|
||||
sema_init(&precvpriv->terminate_recvthread_sema, 0);
|
||||
/*init recv_buf*/
|
||||
_init_queue(&precvpriv->free_recv_buf_queue);
|
||||
precvpriv->pallocated_recv_buf = _malloc(NR_RECVBUFF *
|
||||
|
|
|
@ -131,7 +131,6 @@ uint r8712_alloc_io_queue(struct _adapter *adapter)
|
|||
pio_req = (struct io_req *)(pio_queue->free_ioreqs_buf);
|
||||
for (i = 0; i < NUM_IOREQ; i++) {
|
||||
_init_listhead(&pio_req->list);
|
||||
sema_init(&pio_req->sema, 0);
|
||||
list_insert_tail(&pio_req->list, &pio_queue->free_ioreqs);
|
||||
pio_req++;
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue