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:
Greg Kroah-Hartman 2012-02-10 10:58:25 -08:00
commit b91867f2ee
208 changed files with 17150 additions and 11186 deletions

View File

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

View File

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

View File

@ -88,6 +88,8 @@ source "drivers/staging/zram/Kconfig"
source "drivers/staging/zcache/Kconfig" source "drivers/staging/zcache/Kconfig"
source "drivers/staging/zsmalloc/Kconfig"
source "drivers/staging/wlags49_h2/Kconfig" source "drivers/staging/wlags49_h2/Kconfig"
source "drivers/staging/wlags49_h25/Kconfig" source "drivers/staging/wlags49_h25/Kconfig"
@ -128,4 +130,6 @@ source "drivers/staging/omapdrm/Kconfig"
source "drivers/staging/android/Kconfig" source "drivers/staging/android/Kconfig"
source "drivers/staging/telephony/Kconfig"
endif # STAGING endif # STAGING

View File

@ -34,8 +34,8 @@ obj-$(CONFIG_VME_BUS) += vme/
obj-$(CONFIG_DX_SEP) += sep/ obj-$(CONFIG_DX_SEP) += sep/
obj-$(CONFIG_IIO) += iio/ obj-$(CONFIG_IIO) += iio/
obj-$(CONFIG_ZRAM) += zram/ obj-$(CONFIG_ZRAM) += zram/
obj-$(CONFIG_XVMALLOC) += zram/
obj-$(CONFIG_ZCACHE) += zcache/ obj-$(CONFIG_ZCACHE) += zcache/
obj-$(CONFIG_ZSMALLOC) += zsmalloc/
obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/ obj-$(CONFIG_WLAGS49_H2) += wlags49_h2/
obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/ obj-$(CONFIG_WLAGS49_H25) += wlags49_h25/
obj-$(CONFIG_FB_SM7XX) += sm7xx/ obj-$(CONFIG_FB_SM7XX) += sm7xx/
@ -55,3 +55,4 @@ obj-$(CONFIG_INTEL_MEI) += mei/
obj-$(CONFIG_MFD_NVEC) += nvec/ obj-$(CONFIG_MFD_NVEC) += nvec/
obj-$(CONFIG_DRM_OMAP) += omapdrm/ obj-$(CONFIG_DRM_OMAP) += omapdrm/
obj-$(CONFIG_ANDROID) += android/ obj-$(CONFIG_ANDROID) += android/
obj-$(CONFIG_PHONE) += telephony/

View File

@ -102,6 +102,32 @@ config ANDROID_LOW_MEMORY_KILLER
source "drivers/staging/android/switch/Kconfig" 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 endif # if ANDROID
endmenu endmenu

View File

@ -6,3 +6,5 @@ obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o
obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o
obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o
obj-$(CONFIG_ANDROID_SWITCH) += switch/ obj-$(CONFIG_ANDROID_SWITCH) += switch/
obj-$(CONFIG_ANDROID_INTF_ALARM) += alarm.o
obj-$(CONFIG_ANDROID_INTF_ALARM_DEV) += alarm-dev.o

View File

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

View File

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

View File

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

View File

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

View File

@ -315,7 +315,7 @@ static int ashmem_mmap(struct file *file, struct vm_area_struct *vma)
get_file(asma->file); 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 * shmem_set_file while we're in staging. -jstultz
*/ */
if (vma->vm_flags & VM_SHARED) { 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; return ret;
} }
static struct file_operations ashmem_fops = { static const struct file_operations ashmem_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = ashmem_open, .open = ashmem_open,
.release = ashmem_release, .release = ashmem_release,

View File

@ -258,7 +258,7 @@ struct binder_ref {
}; };
struct binder_buffer { 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 */ struct rb_node rb_node; /* free entry by size or allocated entry */
/* by address */ /* by address */
unsigned free:1; unsigned free:1;

View File

@ -60,7 +60,11 @@ struct logger_reader {
}; };
/* logger_offset - returns index 'n' into the log via (optimized) modulus */ /* 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 * 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 * get_entry_len - Grabs the length of the payload of the next entry starting
* from 'off'. * 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. * Caller needs to hold log->mutex.
*/ */
static __u32 get_entry_len(struct logger_log *log, size_t off) static __u32 get_entry_len(struct logger_log *log, size_t off)
{ {
__u16 val; __u16 val;
switch (log->size - off) { /* copy 2 bytes from buffer, in memcpy order, */
case 1: /* handling possible wrap at end of buffer */
memcpy(&val, log->buffer + off, 1);
memcpy(((char *) &val) + 1, log->buffer, 1); ((__u8 *)&val)[0] = log->buffer[off];
break; if (likely(off+1 < log->size))
default: ((__u8 *)&val)[1] = log->buffer[off+1];
memcpy(&val, log->buffer + off, 2); else
} ((__u8 *)&val)[1] = log->buffer[0];
return sizeof(struct logger_entry) + val; 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)) if (copy_to_user(buf + len, log->buffer, count - len))
return -EFAULT; return -EFAULT;
reader->r_off = logger_offset(reader->r_off + count); reader->r_off = logger_offset(log, reader->r_off + count);
return count; return count;
} }
@ -164,9 +172,10 @@ static ssize_t logger_read(struct file *file, char __user *buf,
start: start:
while (1) { while (1) {
mutex_lock(&log->mutex);
prepare_to_wait(&log->wq, &wait, TASK_INTERRUPTIBLE); prepare_to_wait(&log->wq, &wait, TASK_INTERRUPTIBLE);
mutex_lock(&log->mutex);
ret = (log->w_off == reader->r_off); ret = (log->w_off == reader->r_off);
mutex_unlock(&log->mutex); mutex_unlock(&log->mutex);
if (!ret) if (!ret)
@ -225,7 +234,7 @@ static size_t get_next_entry(struct logger_log *log, size_t off, size_t len)
do { do {
size_t nr = get_entry_len(log, off); size_t nr = get_entry_len(log, off);
off = logger_offset(off + nr); off = logger_offset(log, off + nr);
count += nr; count += nr;
} while (count < len); } 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 * is_between - is a < c < b, accounting for wrapping of a, b, and c
* from a to b cross 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 < b) {
if (a < c || b >= c) /* is c between a and b? */
if (a < c && c <= b)
return 1; return 1;
} else { } else {
if (a < c && b >= c) /* is c outside of b through a? */
if (c <= b || a < c)
return 1; 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) static void fix_up_readers(struct logger_log *log, size_t len)
{ {
size_t old = log->w_off; 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; 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); log->head = get_next_entry(log, log->head, len);
list_for_each_entry(reader, &log->readers, list) 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); 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) if (count != len)
memcpy(log->buffer, buf + len, 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 (count != len)
if (copy_from_user(log->buffer, buf + len, 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; return -EFAULT;
log->w_off = logger_offset(log->w_off + count); log->w_off = logger_offset(log, log->w_off + count);
return count; return count;
} }

View File

@ -34,6 +34,7 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/oom.h> #include <linux/oom.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/rcupdate.h>
#include <linux/profile.h> #include <linux/profile.h>
#include <linux/notifier.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) static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
{ {
struct task_struct *p; struct task_struct *tsk;
struct task_struct *selected = NULL; struct task_struct *selected = NULL;
int rem = 0; int rem = 0;
int tasksize; int tasksize;
@ -134,25 +135,24 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
} }
selected_oom_adj = min_adj; selected_oom_adj = min_adj;
read_lock(&tasklist_lock); rcu_read_lock();
for_each_process(p) { for_each_process(tsk) {
struct mm_struct *mm; struct task_struct *p;
struct signal_struct *sig;
int oom_adj; int oom_adj;
task_lock(p); if (tsk->flags & PF_KTHREAD)
mm = p->mm;
sig = p->signal;
if (!mm || !sig) {
task_unlock(p);
continue; 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) { if (oom_adj < min_adj) {
task_unlock(p); task_unlock(p);
continue; continue;
} }
tasksize = get_mm_rss(mm); tasksize = get_mm_rss(p->mm);
task_unlock(p); task_unlock(p);
if (tasksize <= 0) if (tasksize <= 0)
continue; continue;
@ -183,12 +183,12 @@ static int lowmem_shrink(struct shrinker *s, struct shrink_control *sc)
lowmem_deathpending_timeout = jiffies + HZ; lowmem_deathpending_timeout = jiffies + HZ;
task_handoff_register(&task_nb); task_handoff_register(&task_nb);
#endif #endif
force_sig(SIGKILL, selected); send_sig(SIGKILL, selected, 0);
rem -= selected_tasksize; rem -= selected_tasksize;
} }
lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n", lowmem_print(4, "lowmem_shrink %lu, %x, return %d\n",
sc->nr_to_scan, sc->gfp_mask, rem); sc->nr_to_scan, sc->gfp_mask, rem);
read_unlock(&tasklist_lock); rcu_read_unlock();
return rem; return rem;
} }

View File

@ -351,7 +351,7 @@ static int ram_console_driver_probe(struct platform_device *pdev)
"%lx\n", res, pdev->num_resources, res ? res->flags : 0); "%lx\n", res, pdev->num_resources, res ? res->flags : 0);
return -ENXIO; return -ENXIO;
} }
buffer_size = res->end - res->start + 1; buffer_size = resource_size(res);
start = res->start; start = res->start;
printk(KERN_INFO "ram_console: got buffer at %zx, size %zx\n", printk(KERN_INFO "ram_console: got buffer at %zx, size %zx\n",
start, buffer_size); start, buffer_size);
@ -411,15 +411,14 @@ static int __init ram_console_late_init(void)
if (ram_console_old_log == NULL) if (ram_console_old_log == NULL)
return 0; return 0;
#ifdef CONFIG_ANDROID_RAM_CONSOLE_EARLY_INIT #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) { if (ram_console_old_log == NULL) {
printk(KERN_ERR printk(KERN_ERR
"ram_console: failed to allocate buffer for old log\n"); "ram_console: failed to allocate buffer for old log\n");
ram_console_old_log_size = 0; ram_console_old_log_size = 0;
return 0; return 0;
} }
memcpy(ram_console_old_log,
ram_console_old_log_init_buffer, ram_console_old_log_size);
#endif #endif
entry = create_proc_entry("last_kmsg", S_IFREG | S_IRUGO, NULL); entry = create_proc_entry("last_kmsg", S_IFREG | S_IRUGO, NULL);
if (!entry) { if (!entry) {

View File

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

View File

@ -728,14 +728,10 @@ static long bcm_char_ioctl(struct file *filp, UINT cmd, ULONG arg)
if (IoBuffer.InputLength > MAX_CNTL_PKT_SIZE) if (IoBuffer.InputLength > MAX_CNTL_PKT_SIZE)
return -EINVAL; return -EINVAL;
pvBuffer = kmalloc(IoBuffer.InputLength, GFP_KERNEL); pvBuffer = memdup_user(IoBuffer.InputBuffer,
if (!pvBuffer) IoBuffer.InputLength);
return -ENOMEM; if (IS_ERR(pvBuffer))
return PTR_ERR(pvBuffer);
if (copy_from_user(pvBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength)) {
kfree(pvBuffer);
return -EFAULT;
}
down(&Adapter->LowPowerModeSync); down(&Adapter->LowPowerModeSync);
Status = wait_event_interruptible_timeout(Adapter->lowpower_mode_wait_queue, Status = wait_event_interruptible_timeout(Adapter->lowpower_mode_wait_queue,
@ -1140,15 +1136,10 @@ cntrlEnd:
if (IoBuffer.InputLength < sizeof(ULONG) * 2) if (IoBuffer.InputLength < sizeof(ULONG) * 2)
return -EINVAL; return -EINVAL;
pvBuffer = kmalloc(IoBuffer.InputLength, GFP_KERNEL); pvBuffer = memdup_user(IoBuffer.InputBuffer,
if (!pvBuffer) IoBuffer.InputLength);
return -ENOMEM; if (IS_ERR(pvBuffer))
return PTR_ERR(pvBuffer);
/* Get WrmBuffer structure */
if (copy_from_user(pvBuffer, IoBuffer.InputBuffer, IoBuffer.InputLength)) {
kfree(pvBuffer);
return -EFAULT;
}
pBulkBuffer = (PBULKWRM_BUFFER)pvBuffer; pBulkBuffer = (PBULKWRM_BUFFER)pvBuffer;
@ -1302,20 +1293,18 @@ cntrlEnd:
/* /*
* Deny the access if the offset crosses the cal area limit. * 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); */ /* 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; return STATUS_FAILURE;
} }
pReadData = kzalloc(stNVMReadWrite.uiNumBytes, GFP_KERNEL); pReadData = memdup_user(stNVMReadWrite.pBuffer,
if (!pReadData) stNVMReadWrite.uiNumBytes);
return -ENOMEM; if (IS_ERR(pReadData))
return PTR_ERR(pReadData);
if (copy_from_user(pReadData, stNVMReadWrite.pBuffer, stNVMReadWrite.uiNumBytes)) {
kfree(pReadData);
return -EFAULT;
}
do_gettimeofday(&tv0); do_gettimeofday(&tv0);
if (IOCTL_BCM_NVM_READ == cmd) { if (IOCTL_BCM_NVM_READ == cmd) {

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -8,16 +8,16 @@
/* /*
Driver: adv_pci_dio Driver: adv_pci_dio
Description: Advantech PCI-1730, PCI-1733, PCI-1734, PCI-1735U, Description: Advantech PCI-1730, PCI-1733, PCI-1734, PCI-1735U,
PCI-1736UP, PCI-1750, PCI-1751, PCI-1752, PCI-1753/E, PCI-1736UP, PCI-1739U, PCI-1750, PCI-1751, PCI-1752,
PCI-1754, PCI-1756, PCI-1762 PCI-1753/E, PCI-1754, PCI-1756, PCI-1760, PCI-1762
Author: Michal Dobes <dobes@tesnet.cz> Author: Michal Dobes <dobes@tesnet.cz>
Devices: [Advantech] PCI-1730 (adv_pci_dio), PCI-1733, 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-1751, PCI-1752, PCI-1753,
PCI-1753+PCI-1753E, PCI-1754, PCI-1756, PCI-1753+PCI-1753E, PCI-1754, PCI-1756,
PCI-1760, PCI-1762 PCI-1760, PCI-1762
Status: untested 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. This driver supports now only insn interface for DI/DO/DIO.
@ -51,6 +51,7 @@ Configuration options:
/* hardware types of the cards */ /* hardware types of the cards */
enum hw_cards_id { enum hw_cards_id {
TYPE_PCI1730, TYPE_PCI1733, TYPE_PCI1734, TYPE_PCI1735, TYPE_PCI1736, TYPE_PCI1730, TYPE_PCI1733, TYPE_PCI1734, TYPE_PCI1735, TYPE_PCI1736,
TYPE_PCI1739,
TYPE_PCI1750, TYPE_PCI1750,
TYPE_PCI1751, TYPE_PCI1751,
TYPE_PCI1752, TYPE_PCI1752,
@ -109,6 +110,12 @@ enum hw_io_access {
#define PCI1736_BOARDID 4 /* R: Board I/D switch for 1736UP */ #define PCI1736_BOARDID 4 /* R: Board I/D switch for 1736UP */
#define PCI1736_MAINREG 0 /* Normal register (2) doesn't work */ #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 */ /* Advantech PCI-1750 */
#define PCI1750_IDI 0 /* R: Isolated digital input 0-15 */ #define PCI1750_IDI 0 /* R: Isolated digital input 0-15 */
#define PCI1750_IDO 0 /* W: Isolated digital output 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, 0x1734) },
{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1735) }, { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1735) },
{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1736) }, { 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, 0x1750) },
{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1751) }, { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1751) },
{ PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1752) }, { PCI_DEVICE(PCI_VENDOR_ID_ADVANTECH, 0x1752) },
@ -316,6 +324,14 @@ static const struct dio_boardtype boardtypes[] = {
{4, PCI1736_BOARDID, 1, SDF_INTERNAL}, {4, PCI1736_BOARDID, 1, SDF_INTERNAL},
{ {0, 0, 0, 0} }, { {0, 0, 0, 0} },
IO_8b}, 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, {"pci1750", PCI_VENDOR_ID_ADVANTECH, 0x1750, PCIDIO_MAINREG,
TYPE_PCI1750, TYPE_PCI1750,
{ {0, 0, 0, 0}, {16, PCI1750_IDI, 2, 0} }, { {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); outb(0, dev->iobase + PCI1736_3_INT_RF);
break; break;
case TYPE_PCI1739:
/* disable & clear interrupts */
outb(0x88, dev->iobase + PCI1739_ICR);
break;
case TYPE_PCI1750: case TYPE_PCI1750:
case TYPE_PCI1751: case TYPE_PCI1751:
/* disable & clear interrupts */ /* disable & clear interrupts */

View File

@ -720,12 +720,20 @@ static int dt2801_dio_insn_config(struct comedi_device *dev,
which = 1; which = 1;
/* configure */ /* configure */
if (data[0]) { switch (data[0]) {
case INSN_CONFIG_DIO_OUTPUT:
s->io_bits = 0xff; s->io_bits = 0xff;
dt2801_writecmd(dev, DT_C_SET_DIGOUT); dt2801_writecmd(dev, DT_C_SET_DIGOUT);
} else { break;
case INSN_CONFIG_DIO_INPUT:
s->io_bits = 0; s->io_bits = 0;
dt2801_writecmd(dev, DT_C_SET_DIGIN); 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); dt2801_writedata(dev, which);

View File

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

View File

@ -2098,23 +2098,29 @@ static int me4000_dio_insn_config(struct comedi_device *dev,
CALL_PDEBUG("In me4000_dio_insn_config()\n"); 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] = data[1] =
(s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT; (s->io_bits & (1 << chan)) ? COMEDI_OUTPUT : COMEDI_INPUT;
return insn->n; return insn->n;
case INSN_CONFIG_DIO_INPUT:
case INSN_CONFIG_DIO_OUTPUT:
break;
} }
/* /*
* The input or output configuration of each digital line is * The input or output configuration of each digital line is
* configured by a special insn_config instruction. chanspec * configured by a special insn_config instruction. chanspec
* contains the channel to be changed, and data[0] contains the * 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) * On the ME-4000 it is only possible to switch port wise (8 bit)
*/ */
tmp = me4000_inl(dev, info->dio_context.ctrl_reg); tmp = me4000_inl(dev, info->dio_context.ctrl_reg);
if (data[0] == COMEDI_OUTPUT) { if (data[0] == INSN_CONFIG_DIO_OUTPUT) {
if (chan < 8) { if (chan < 8) {
s->io_bits |= 0xFF; s->io_bits |= 0xFF;
tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 | tmp &= ~(ME4000_DIO_CTRL_BIT_MODE_0 |

View File

@ -30,7 +30,7 @@ Status: works
Devices: [National Instruments] PCI-DIO-32HS (ni_pcidio), PXI-6533, Devices: [National Instruments] PCI-DIO-32HS (ni_pcidio), PXI-6533,
PCI-DIO-96, PCI-DIO-96B, PXI-6508, PCI-6503, PCI-6503B, PCI-6503X, PCI-DIO-96, PCI-DIO-96B, PXI-6508, PCI-6503, PCI-6503B, PCI-6503X,
PXI-6503, PCI-6533, PCI-6534 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 The DIO-96 appears as four 8255 subdevices. See the 8255
driver notes for details. 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. 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 This driver could be easily modified to support AT-MIO32HS and
AT-MIO96. 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."); comedi_error(dev, "failed to reserve mite dma channel.");
return -EBUSY; return -EBUSY;
} }
devpriv->di_mite_chan->dir = COMEDI_INPUT;
writeb(primary_DMAChannel_bits(devpriv->di_mite_chan->channel) | writeb(primary_DMAChannel_bits(devpriv->di_mite_chan->channel) |
secondary_DMAChannel_bits(devpriv->di_mite_chan->channel), secondary_DMAChannel_bits(devpriv->di_mite_chan->channel),
devpriv->mite->daq_io_addr + DMA_Line_Control_Group1); 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); 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) static irqreturn_t nidio_interrupt(int irq, void *d)
{ {
struct comedi_device *dev = d; struct comedi_device *dev = d;
@ -497,7 +518,6 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
int status; int status;
int work = 0; int work = 0;
unsigned int m_status = 0; unsigned int m_status = 0;
unsigned long irq_flags;
/* interrupcions parasites */ /* interrupcions parasites */
if (dev->attached == 0) { if (dev->attached == 0) {
@ -505,6 +525,9 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
return IRQ_NONE; return IRQ_NONE;
} }
/* Lock to avoid race with comedi_poll */
spin_lock(&dev->spinlock);
status = readb(devpriv->mite->daq_io_addr + status = readb(devpriv->mite->daq_io_addr +
Interrupt_And_Window_Status); Interrupt_And_Window_Status);
flags = readb(devpriv->mite->daq_io_addr + Group_1_Flags); 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", /* printk("buf[4096]=%08x\n",
*(unsigned int *)(async->prealloc_buf+4096)); */ *(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) if (devpriv->di_mite_chan)
m_status = mite_get_status(devpriv->di_mite_chan); m_status = mite_get_status(devpriv->di_mite_chan);
#ifdef MITE_DEBUG #ifdef MITE_DEBUG
@ -543,7 +566,7 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
disable_irq(dev->irq); disable_irq(dev->irq);
} }
} }
spin_unlock_irqrestore(&devpriv->mite_channel_lock, irq_flags); spin_unlock(&devpriv->mite_channel_lock);
while (status & DataLeft) { while (status & DataLeft) {
work++; work++;
@ -645,6 +668,8 @@ out:
Master_DMA_And_Interrupt_Control); Master_DMA_And_Interrupt_Control);
} }
#endif #endif
spin_unlock(&dev->spinlock);
return IRQ_HANDLED; return IRQ_HANDLED;
} }
@ -825,8 +850,8 @@ static int ni_pcidio_cmdtest(struct comedi_device *dev,
} else { } else {
/* TRIG_EXT */ /* TRIG_EXT */
/* should be level/edge, hi/lo specification here */ /* should be level/edge, hi/lo specification here */
if (cmd->scan_begin_arg != 0) { if ((cmd->scan_begin_arg & ~(CR_EDGE | CR_INVERT)) != 0) {
cmd->scan_begin_arg = 0; cmd->scan_begin_arg &= (CR_EDGE | CR_INVERT);
err++; 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(0, devpriv->mite->daq_io_addr + Sequence);
writeb(0x00, devpriv->mite->daq_io_addr + ReqReg); writeb(0x00, devpriv->mite->daq_io_addr + ReqReg);
writeb(4, devpriv->mite->daq_io_addr + BlockMode); 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); writeb(0x00, devpriv->mite->daq_io_addr + AckSer);
writel(1, devpriv->mite->daq_io_addr + StartDelay); writel(1, devpriv->mite->daq_io_addr + StartDelay);
writeb(1, devpriv->mite->daq_io_addr + ReqDelay); 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) static int setup_mite_dma(struct comedi_device *dev, struct comedi_subdevice *s)
{ {
int retval; int retval;
unsigned long flags;
retval = ni_pcidio_request_di_mite_channel(dev); retval = ni_pcidio_request_di_mite_channel(dev);
if (retval) if (retval)
return 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 retval;
return 0;
} }
static int ni_pcidio_inttrig(struct comedi_device *dev, 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->len_chanlist = 32; /* XXX */
s->buf_change = &ni_pcidio_change; s->buf_change = &ni_pcidio_change;
s->async_dma_dir = DMA_BIDIRECTIONAL; 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_IO(0));
writel(0, devpriv->mite->daq_io_addr + Port_Pin_Directions(0)); writel(0, devpriv->mite->daq_io_addr + Port_Pin_Directions(0));

View File

@ -29,14 +29,15 @@ Devices: [National Instruments] PCI-MIO-16XE-50 (ni_pcimio),
PCI-MIO-16XE-10, PXI-6030E, PCI-MIO-16E-1, PCI-MIO-16E-4, PCI-6014, PCI-6040E, 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, 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-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-6110, PCI-6111, PCI-6220, PCI-6221, PCI-6224, PXI-6224,
PCI-6229, PCI-6250, PCI-6251, PCIe-6251, PCI-6254, PCI-6259, PCIe-6259, 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-6280, PCI-6281, PXI-6281, PCI-6284, PCI-6289,
PCI-6711, PXI-6711, PCI-6713, PXI-6713, PCI-6711, PXI-6711, PCI-6713, PXI-6713,
PXI-6071E, PCI-6070E, PXI-6070E, PXI-6071E, PCI-6070E, PXI-6070E,
PXI-6052E, PCI-6036E, PCI-6731, PCI-6733, PXI-6733, PXI-6052E, PCI-6036E, PCI-6731, PCI-6733, PXI-6733,
PCI-6143, PXI-6143 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 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 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, 0x717f)},
{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x71bc)}, {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x71bc)},
{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717d)}, {PCI_DEVICE(PCI_VENDOR_ID_NI, 0x717d)},
{PCI_DEVICE(PCI_VENDOR_ID_NI, 0x72e8)},
{0} {0}
}; };
@ -1045,6 +1047,25 @@ static const struct ni_board_struct ni_boards[] = {
.caldac = {caldac_none}, .caldac = {caldac_none},
.has_8255 = 0, .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, .device_id = 0x70b7,
.name = "pci-6254", .name = "pci-6254",

View File

@ -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"); 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"); BCMLOG(BCMLOG_DBG, "Already Stopped\n");
return BC_STS_SUCCESS; return BC_STS_SUCCESS;
} }

View File

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

File diff suppressed because it is too large Load Diff

View File

@ -3,7 +3,7 @@
# #
obj-$(CONFIG_IIO) += industrialio.o 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_BUFFER) += industrialio-buffer.o
industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o industrialio-$(CONFIG_IIO_TRIGGER) += industrialio-trigger.o

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -406,8 +406,6 @@ int lis3l02dq_configure_buffer(struct iio_dev *indio_dev)
return -ENOMEM; return -ENOMEM;
indio_dev->buffer = buffer; indio_dev->buffer = buffer;
/* Effectively select the buffer implementation */
indio_dev->buffer->access = &lis3l02dq_access_funcs;
buffer->scan_timestamp = true; buffer->scan_timestamp = true;
indio_dev->setup_ops = &lis3l02dq_buffer_setup_ops; indio_dev->setup_ops = &lis3l02dq_buffer_setup_ops;

View File

@ -561,8 +561,6 @@ static int ad7192_register_ring_funcs_and_init(struct iio_dev *indio_dev)
ret = -ENOMEM; ret = -ENOMEM;
goto error_ret; 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, indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
&ad7192_trigger_handler, &ad7192_trigger_handler,
IRQF_ONESHOT, IRQF_ONESHOT,
@ -824,25 +822,20 @@ static struct attribute *ad7192_attributes[] = {
NULL 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 = { static const struct attribute_group ad7192_attribute_group = {
.attrs = ad7192_attributes, .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, 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, .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) \ #define AD7192_CHAN_DIFF(_chan, _chan2, _name, _address, _si) \
{ .type = IIO_VOLTAGE, \ { .type = IIO_VOLTAGE, \
.differential = 1, \ .differential = 1, \
@ -1064,7 +1066,10 @@ static int __devinit ad7192_probe(struct spi_device *spi)
indio_dev->channels = ad7192_channels; indio_dev->channels = ad7192_channels;
indio_dev->num_channels = ARRAY_SIZE(ad7192_channels); indio_dev->num_channels = ARRAY_SIZE(ad7192_channels);
indio_dev->available_scan_masks = st->available_scan_masks; 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++) for (i = 0; i < indio_dev->num_channels; i++)
st->available_scan_masks[i] = (1 << i) | (1 << st->available_scan_masks[i] = (1 << i) | (1 <<

View File

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

View File

@ -98,8 +98,6 @@ int ad7476_register_ring_funcs_and_init(struct iio_dev *indio_dev)
ret = -ENOMEM; ret = -ENOMEM;
goto error_ret; goto error_ret;
} }
/* Effectively select the ring buffer implementation */
indio_dev->buffer->access = &ring_sw_access_funcs;
indio_dev->pollfunc indio_dev->pollfunc
= iio_alloc_pollfunc(NULL, = iio_alloc_pollfunc(NULL,
&ad7476_trigger_handler, &ad7476_trigger_handler,

View File

@ -197,7 +197,7 @@ static IIO_DEVICE_ATTR(oversampling_ratio, S_IRUGO | S_IWUSR,
ad7606_store_oversampling_ratio, 0); ad7606_store_oversampling_ratio, 0);
static IIO_CONST_ATTR(oversampling_ratio_available, "0 2 4 8 16 32 64"); 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_dev_attr_in_voltage_range.dev_attr.attr,
&iio_const_attr_in_voltage_range_available.dev_attr.attr, &iio_const_attr_in_voltage_range_available.dev_attr.attr,
&iio_dev_attr_oversampling_ratio.dev_attr.attr, &iio_dev_attr_oversampling_ratio.dev_attr.attr,
@ -205,34 +205,28 @@ static struct attribute *ad7606_attributes[] = {
NULL, NULL,
}; };
static umode_t ad7606_attr_is_visible(struct kobject *kobj, static const struct attribute_group ad7606_attribute_group_os_and_range = {
struct attribute *attr, int n) .attrs = ad7606_attributes_os_and_range,
{ };
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);
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) && static const struct attribute_group ad7606_attribute_group_os = {
gpio_is_valid(st->pdata->gpio_os1) && .attrs = ad7606_attributes_os,
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;
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 = { static const struct attribute_group ad7606_attribute_group_range = {
.attrs = ad7606_attributes, .attrs = ad7606_attributes_range,
.is_visible = ad7606_attr_is_visible,
}; };
#define AD7606_CHANNEL(num) \ #define AD7606_CHANNEL(num) \
@ -435,10 +429,27 @@ static irqreturn_t ad7606_interrupt(int irq, void *dev_id)
return IRQ_HANDLED; 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, .driver_module = THIS_MODULE,
.read_raw = &ad7606_read_raw, .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, 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]; st->chip_info = &ad7606_chip_info_tbl[id];
indio_dev->dev.parent = dev; 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->modes = INDIO_DIRECT_MODE;
indio_dev->name = st->chip_info->name; indio_dev->name = st->chip_info->name;
indio_dev->channels = st->chip_info->channels; indio_dev->channels = st->chip_info->channels;

View File

@ -110,8 +110,6 @@ int ad7606_register_ring_funcs_and_init(struct iio_dev *indio_dev)
goto error_ret; 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, indio_dev->pollfunc = iio_alloc_pollfunc(&ad7606_trigger_handler_th_bh,
&ad7606_trigger_handler_th_bh, &ad7606_trigger_handler_th_bh,
0, 0,

View File

@ -427,8 +427,6 @@ static int ad7793_register_ring_funcs_and_init(struct iio_dev *indio_dev)
ret = -ENOMEM; ret = -ENOMEM;
goto error_ret; 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, indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
&ad7793_trigger_handler, &ad7793_trigger_handler,
IRQF_ONESHOT, IRQF_ONESHOT,

View File

@ -131,8 +131,6 @@ int ad7887_register_ring_funcs_and_init(struct iio_dev *indio_dev)
ret = -ENOMEM; ret = -ENOMEM;
goto error_ret; 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, indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,
&ad7887_trigger_handler, &ad7887_trigger_handler,
IRQF_ONESHOT, IRQF_ONESHOT,

View File

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

View File

@ -725,32 +725,19 @@ static struct attribute *adt7310_event_int_attributes[] = {
&iio_dev_attr_fault_queue.dev_attr.attr, &iio_dev_attr_fault_queue.dev_attr.attr,
&iio_dev_attr_t_alarm_high.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_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_crit.dev_attr.attr,
&iio_dev_attr_t_hyst.dev_attr.attr, &iio_dev_attr_t_hyst.dev_attr.attr,
NULL, NULL,
}; };
static struct attribute_group adt7310_event_attribute_group[ADT7310_IRQS] = { static struct attribute_group adt7310_event_attribute_group = {
{ .attrs = adt7310_event_int_attributes,
.attrs = adt7310_event_int_attributes, .name = "events",
.name = "events",
}, {
.attrs = adt7310_event_ct_attributes,
.name = "events",
}
}; };
static const struct iio_info adt7310_info = { static const struct iio_info adt7310_info = {
.attrs = &adt7310_attribute_group, .attrs = &adt7310_attribute_group,
.event_attrs = adt7310_event_attribute_group, .event_attrs = &adt7310_event_attribute_group,
.driver_module = THIS_MODULE, .driver_module = THIS_MODULE,
}; };

View File

@ -693,32 +693,19 @@ static struct attribute *adt7410_event_int_attributes[] = {
&iio_dev_attr_fault_queue.dev_attr.attr, &iio_dev_attr_fault_queue.dev_attr.attr,
&iio_dev_attr_t_alarm_high.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_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_crit.dev_attr.attr,
&iio_dev_attr_t_hyst.dev_attr.attr, &iio_dev_attr_t_hyst.dev_attr.attr,
NULL, NULL,
}; };
static struct attribute_group adt7410_event_attribute_group[ADT7410_IRQS] = { static struct attribute_group adt7410_event_attribute_group = {
{ .attrs = adt7410_event_int_attributes,
.attrs = adt7410_event_int_attributes, .name = "events",
.name = "events",
}, {
.attrs = adt7410_event_ct_attributes,
.name = "events",
}
}; };
static const struct iio_info adt7410_info = { static const struct iio_info adt7410_info = {
.attrs = &adt7410_attribute_group, .attrs = &adt7410_attribute_group,
.event_attrs = adt7410_event_attribute_group, .event_attrs = &adt7410_event_attribute_group,
.driver_module = THIS_MODULE, .driver_module = THIS_MODULE,
}; };

View File

@ -116,8 +116,6 @@ int max1363_register_ring_funcs_and_init(struct iio_dev *indio_dev)
ret = -ENOMEM; ret = -ENOMEM;
goto error_deallocate_sw_rb; 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 */ /* Ring buffer functions - here trigger setup related */
indio_dev->setup_ops = &max1363_ring_setup_ops; indio_dev->setup_ops = &max1363_ring_setup_ops;

View File

@ -149,30 +149,8 @@ static struct attribute *ad5446_attributes[] = {
NULL, 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 = { static const struct attribute_group ad5446_attribute_group = {
.attrs = ad5446_attributes, .attrs = ad5446_attributes,
.is_visible = ad5446_attr_is_visible,
}; };
#define AD5446_CHANNEL(bits, storage, shift) { \ #define AD5446_CHANNEL(bits, storage, shift) { \
@ -321,6 +299,12 @@ static const struct iio_info ad5446_info = {
.driver_module = THIS_MODULE, .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) static int __devinit ad5446_probe(struct spi_device *spi)
{ {
struct ad5446_state *st; 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 */ /* Estabilish that the iio_dev is a child of the spi device */
indio_dev->dev.parent = &spi->dev; indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name; 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->modes = INDIO_DIRECT_MODE;
indio_dev->channels = &st->chip_info->channel; indio_dev->channels = &st->chip_info->channel;
indio_dev->num_channels = 1; indio_dev->num_channels = 1;

View File

@ -281,29 +281,27 @@ static struct attribute *ad9834_attributes[] = {
NULL, NULL,
}; };
static umode_t ad9834_attr_is_visible(struct kobject *kobj, static struct attribute *ad9833_attributes[] = {
struct attribute *attr, int n) &iio_dev_attr_dds0_freq0.dev_attr.attr,
{ &iio_dev_attr_dds0_freq1.dev_attr.attr,
struct device *dev = container_of(kobj, struct device, kobj); &iio_const_attr_dds0_freq_scale.dev_attr.attr,
struct iio_dev *indio_dev = dev_get_drvdata(dev); &iio_dev_attr_dds0_phase0.dev_attr.attr,
struct ad9834_state *st = iio_priv(indio_dev); &iio_dev_attr_dds0_phase1.dev_attr.attr,
&iio_const_attr_dds0_phase_scale.dev_attr.attr,
umode_t mode = attr->mode; &iio_dev_attr_dds0_freqsymbol.dev_attr.attr,
&iio_dev_attr_dds0_phasesymbol.dev_attr.attr,
if (((st->devid == ID_AD9833) || (st->devid == ID_AD9837)) && &iio_dev_attr_dds0_out_enable.dev_attr.attr,
((attr == &iio_dev_attr_dds0_out1_enable.dev_attr.attr) || &iio_dev_attr_dds0_out0_wavetype.dev_attr.attr,
(attr == &iio_dev_attr_dds0_out1_wavetype.dev_attr.attr) || &iio_dev_attr_dds0_out0_wavetype_available.dev_attr.attr,
(attr == NULL,
&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 const struct attribute_group ad9834_attribute_group = { static const struct attribute_group ad9834_attribute_group = {
.attrs = ad9834_attributes, .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 = { static const struct iio_info ad9834_info = {
@ -311,6 +309,11 @@ static const struct iio_info ad9834_info = {
.driver_module = THIS_MODULE, .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) static int __devinit ad9834_probe(struct spi_device *spi)
{ {
struct ad9834_platform_data *pdata = spi->dev.platform_data; 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; st->reg = reg;
indio_dev->dev.parent = &spi->dev; indio_dev->dev.parent = &spi->dev;
indio_dev->name = spi_get_device_id(spi)->name; 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; indio_dev->modes = INDIO_DIRECT_MODE;
/* Setup default messages */ /* Setup default messages */

View File

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

View File

@ -49,4 +49,8 @@ ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
#endif #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 #endif

View File

@ -142,8 +142,6 @@ int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev)
} }
indio_dev->buffer = buffer; indio_dev->buffer = buffer;
/* Tell the core how to access the buffer */
buffer->access = &kfifo_access_funcs;
/* Enable timestamps by default */ /* Enable timestamps by default */
buffer->scan_timestamp = true; buffer->scan_timestamp = true;

View File

@ -607,9 +607,6 @@ static int ad5933_register_ring_funcs_and_init(struct iio_dev *indio_dev)
if (!indio_dev->buffer) if (!indio_dev->buffer)
return -ENOMEM; return -ENOMEM;
/* Effectively select the ring buffer implementation */
indio_dev->buffer->access = &ring_sw_access_funcs;
/* Ring buffer functions - here trigger setup related */ /* Ring buffer functions - here trigger setup related */
indio_dev->setup_ops = &ad5933_ring_setup_ops; indio_dev->setup_ops = &ad5933_ring_setup_ops;

View File

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

View File

@ -100,71 +100,6 @@ const struct iio_chan_spec
return NULL; 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 */ /* This turns up an awful lot */
ssize_t iio_read_const_attr(struct device *dev, ssize_t iio_read_const_attr(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
@ -174,110 +109,6 @@ ssize_t iio_read_const_attr(struct device *dev,
} }
EXPORT_SYMBOL(iio_read_const_attr); 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) static int __init iio_init(void)
{ {
int ret; int ret;
@ -726,295 +557,6 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
kfree(indio_dev->chan_attr_group.attrs); 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) static void iio_dev_release(struct device *device)
{ {
struct iio_dev *indio_dev = container_of(device, struct iio_dev, dev); struct iio_dev *indio_dev = container_of(device, struct iio_dev, dev);

View File

@ -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);
}

View File

@ -59,21 +59,6 @@ static struct attribute_group iio_kfifo_attribute_group = {
.name = "buffer", .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) static int iio_get_bytes_per_datum_kfifo(struct iio_buffer *r)
{ {
return r->bytes_per_datum; return r->bytes_per_datum;
@ -104,12 +89,6 @@ static int iio_set_length_kfifo(struct iio_buffer *r, int length)
return 0; 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, static int iio_store_to_kfifo(struct iio_buffer *r,
u8 *data, u8 *data,
s64 timestamp) s64 timestamp)
@ -137,7 +116,7 @@ static int iio_read_first_n_kfifo(struct iio_buffer *r,
return copied; 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, .store_to = &iio_store_to_kfifo,
.read_first_n = &iio_read_first_n_kfifo, .read_first_n = &iio_read_first_n_kfifo,
.request_update = &iio_request_update_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, .get_length = &iio_get_length_kfifo,
.set_length = &iio_set_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"); MODULE_LICENSE("GPL");

View File

@ -3,8 +3,6 @@
#include "iio.h" #include "iio.h"
#include "buffer.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); struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev);
void iio_kfifo_free(struct iio_buffer *r); void iio_kfifo_free(struct iio_buffer *r);

View File

@ -592,11 +592,18 @@ static const struct i2c_device_id isl29018_id[] = {
MODULE_DEVICE_TABLE(i2c, 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 = { static struct i2c_driver isl29018_driver = {
.class = I2C_CLASS_HWMON, .class = I2C_CLASS_HWMON,
.driver = { .driver = {
.name = "isl29018", .name = "isl29018",
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = isl29018_of_match,
}, },
.probe = isl29018_probe, .probe = isl29018_probe,
.remove = __devexit_p(isl29018_remove), .remove = __devexit_p(isl29018_remove),

View File

@ -564,9 +564,17 @@ static const struct i2c_device_id ak8975_id[] = {
MODULE_DEVICE_TABLE(i2c, 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 = { static struct i2c_driver ak8975_driver = {
.driver = { .driver = {
.name = "ak8975", .name = "ak8975",
.of_match_table = ak8975_of_match,
}, },
.probe = ak8975_probe, .probe = ak8975_probe,
.remove = __devexit_p(ak8975_remove), .remove = __devexit_p(ak8975_remove),

View File

@ -144,8 +144,6 @@ int ade7758_configure_ring(struct iio_dev *indio_dev)
return ret; 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->setup_ops = &ade7758_ring_setup_ops;
indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time, indio_dev->pollfunc = iio_alloc_pollfunc(&iio_pollfunc_store_time,

View File

@ -329,6 +329,16 @@ static struct attribute_group iio_ring_attribute_group = {
.name = "buffer", .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 *iio_sw_rb_allocate(struct iio_dev *indio_dev)
{ {
struct iio_buffer *buf; struct iio_buffer *buf;
@ -341,6 +351,7 @@ struct iio_buffer *iio_sw_rb_allocate(struct iio_dev *indio_dev)
buf = &ring->buf; buf = &ring->buf;
iio_buffer_init(buf); iio_buffer_init(buf);
buf->attrs = &iio_ring_attribute_group; buf->attrs = &iio_ring_attribute_group;
buf->access = &ring_sw_access_funcs;
return buf; return buf;
} }
@ -352,16 +363,5 @@ void iio_sw_rb_free(struct iio_buffer *r)
} }
EXPORT_SYMBOL(iio_sw_rb_free); 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_DESCRIPTION("Industrialio I/O software ring buffer");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

View File

@ -25,11 +25,6 @@
#define _IIO_RING_SW_H_ #define _IIO_RING_SW_H_
#include "buffer.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); struct iio_buffer *iio_sw_rb_allocate(struct iio_dev *indio_dev);
void iio_sw_rb_free(struct iio_buffer *ring); void iio_sw_rb_free(struct iio_buffer *ring);
#endif /* _IIO_RING_SW_H_ */ #endif /* _IIO_RING_SW_H_ */

View File

@ -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 Wait until unlinking of all currently active capture URBs has been
finished. 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; int timeout = HZ;
unsigned int i; 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) void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
{ {
line6_unlink_audio_in_urbs(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) void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm)
{ {
kfree(line6pcm->buffer_in); kfree(line6pcm->buffer_in);
@ -273,9 +254,9 @@ static void audio_in_callback(struct urb *urb)
line6pcm->prev_fsize = fsize; line6pcm->prev_fsize = fsize;
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
if (!(line6pcm->flags & MASK_PCM_IMPULSE)) if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
#endif #endif
if (test_bit(BIT_PCM_ALSA_CAPTURE, &line6pcm->flags) if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, &line6pcm->flags)
&& (fsize > 0)) && (fsize > 0))
line6_capture_copy(line6pcm, fbuf, fsize); line6_capture_copy(line6pcm, fbuf, fsize);
} }
@ -291,9 +272,9 @@ static void audio_in_callback(struct urb *urb)
submit_audio_in_urb(line6pcm); submit_audio_in_urb(line6pcm);
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
if (!(line6pcm->flags & MASK_PCM_IMPULSE)) if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
#endif #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); line6_capture_check_period(line6pcm, length);
} }
} }
@ -341,17 +322,17 @@ static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream,
} }
/* -- [FD] end */ /* -- [FD] end */
if ((line6pcm->flags & MASK_CAPTURE) == 0) { ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
ret = line6_alloc_capture_buffer(line6pcm);
if (ret < 0) if (ret < 0)
return ret; return ret;
}
ret = snd_pcm_lib_malloc_pages(substream, ret = snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params)); params_buffer_bytes(hw_params));
if (ret < 0) if (ret < 0) {
line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
return ret; return ret;
}
line6pcm->period_in = params_period_bytes(hw_params); line6pcm->period_in = params_period_bytes(hw_params);
return 0; 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) static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream)
{ {
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
if ((line6pcm->flags & MASK_CAPTURE) == 0) {
line6_unlink_wait_clear_audio_in_urbs(line6pcm);
line6_free_capture_buffer(line6pcm);
}
return snd_pcm_lib_free_pages(substream); 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 #ifdef CONFIG_PM
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
#endif #endif
err = line6_pcm_start(line6pcm, MASK_PCM_ALSA_CAPTURE); err = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);
if (err < 0) if (err < 0)
return err; return err;
@ -391,7 +367,7 @@ int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd)
#ifdef CONFIG_PM #ifdef CONFIG_PM
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
#endif #endif
err = line6_pcm_stop(line6pcm, MASK_PCM_ALSA_CAPTURE); err = line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);
if (err < 0) if (err < 0)
return err; return err;

View File

@ -19,7 +19,6 @@
extern struct snd_pcm_ops snd_line6_capture_ops; 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, extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf,
int fsize); int fsize);
extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm, 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_audio_in_urbs(struct snd_line6_pcm *line6pcm);
extern void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm extern void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm
*line6pcm); *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); extern int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd);
#endif #endif

View File

@ -1346,7 +1346,7 @@ static void __exit line6_exit(void)
if (line6pcm == NULL) if (line6pcm == NULL)
continue; continue;
line6_pcm_stop(line6pcm, ~0); line6_pcm_release(line6pcm, ~0);
} }
usb_deregister(&line6_driver); usb_deregister(&line6_driver);

View File

@ -52,9 +52,9 @@ static ssize_t pcm_set_impulse_volume(struct device *dev,
line6pcm->impulse_volume = value; line6pcm->impulse_volume = value;
if (value > 0) if (value > 0)
line6_pcm_start(line6pcm, MASK_PCM_IMPULSE); line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_IMPULSE);
else else
line6_pcm_stop(line6pcm, MASK_PCM_IMPULSE); line6_pcm_release(line6pcm, LINE6_BITS_PCM_IMPULSE);
return count; return count;
} }
@ -92,29 +92,43 @@ static bool test_flags(unsigned long flags0, unsigned long flags1,
return ((flags0 & mask) == 0) && ((flags1 & mask) != 0); 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 = unsigned long flags_old =
__sync_fetch_and_or(&line6pcm->flags, channels); __sync_fetch_and_or(&line6pcm->flags, channels);
unsigned long flags_new = flags_old | channels; unsigned long flags_new = flags_old | channels;
unsigned long flags_final = flags_old;
int err = 0; int err = 0;
line6pcm->prev_fbuf = NULL; 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 Waiting for completion of active URBs in the stop handler is
a bug, we therefore report an error if capturing is restarted a bug, we therefore report an error if capturing is restarted
too soon. 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; 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; 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); err = line6_submit_audio_in_all_urbs(line6pcm);
if (err < 0) 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. See comment above regarding PCM restart.
*/ */
if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) {
dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
return -EBUSY; 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; line6pcm->count_out = 0;
err = line6_submit_audio_out_all_urbs(line6pcm); err = line6_submit_audio_out_all_urbs(line6pcm);
if (err < 0) if (err < 0)
goto pcm_start_error; goto pcm_acquire_error;
flags_final |= channels & LINE6_BITS_PLAYBACK_STREAM;
} }
return 0; return 0;
pcm_start_error: pcm_acquire_error:
__sync_fetch_and_and(&line6pcm->flags, ~channels); /*
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; 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 = unsigned long flags_old =
__sync_fetch_and_and(&line6pcm->flags, ~channels); __sync_fetch_and_and(&line6pcm->flags, ~channels);
unsigned long flags_new = flags_old & ~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); line6_unlink_audio_in_urbs(line6pcm);
if (!(flags_old & MASK_PCM_ALSA_CAPTURE)) if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) {
line6_free_capture_buffer(line6pcm); 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); line6_unlink_audio_out_urbs(line6pcm);
if (!(flags_old & MASK_PCM_ALSA_PLAYBACK)) if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_BUFFER)) {
line6_free_playback_buffer(line6pcm); line6_wait_clear_audio_out_urbs(line6pcm);
line6_free_playback_buffer(line6pcm);
} }
return 0; return 0;
@ -185,7 +222,7 @@ int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&line6pcm->lock_trigger, 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) { snd_pcm_group_for_each_entry(s, substream) {
switch (s->stream) { switch (s->stream) {
@ -498,13 +535,13 @@ int snd_line6_prepare(struct snd_pcm_substream *substream)
switch (substream->stream) { switch (substream->stream) {
case SNDRV_PCM_STREAM_PLAYBACK: 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); line6_unlink_wait_clear_audio_out_urbs(line6pcm);
break; break;
case SNDRV_PCM_STREAM_CAPTURE: 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); line6_unlink_wait_clear_audio_in_urbs(line6pcm);
break; break;
@ -513,7 +550,7 @@ int snd_line6_prepare(struct snd_pcm_substream *substream)
MISSING_CASE; 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->count_out = 0;
line6pcm->pos_out = 0; line6pcm->pos_out = 0;
line6pcm->pos_out_done = 0; line6pcm->pos_out_done = 0;

View File

@ -46,57 +46,131 @@
(line6pcm->pcm->streams[stream].substream) (line6pcm->pcm->streams[stream].substream)
/* /*
PCM mode bits and masks. PCM mode bits.
"ALSA": operations triggered by applications via ALSA
"MONITOR": software monitoring There are several features of the Line6 USB driver which require PCM
"IMPULSE": optional impulse response operation 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 { enum {
/* individual bits: */ /* individual bit indices: */
BIT_PCM_ALSA_PLAYBACK, LINE6_INDEX_PCM_ALSA_PLAYBACK_BUFFER,
BIT_PCM_ALSA_CAPTURE, LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM,
BIT_PCM_MONITOR_PLAYBACK, LINE6_INDEX_PCM_ALSA_CAPTURE_BUFFER,
BIT_PCM_MONITOR_CAPTURE, 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 #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
BIT_PCM_IMPULSE_PLAYBACK, LINE6_INDEX_PCM_IMPULSE_PLAYBACK_BUFFER,
BIT_PCM_IMPULSE_CAPTURE, LINE6_INDEX_PCM_IMPULSE_PLAYBACK_STREAM,
LINE6_INDEX_PCM_IMPULSE_CAPTURE_BUFFER,
LINE6_INDEX_PCM_IMPULSE_CAPTURE_STREAM,
#endif #endif
BIT_PAUSE_PLAYBACK, LINE6_INDEX_PAUSE_PLAYBACK,
BIT_PREPARED, LINE6_INDEX_PREPARED,
/* individual masks: */ /* individual bit masks: */
/* *INDENT-OFF* */ LINE6_BIT(PCM_ALSA_PLAYBACK_BUFFER),
MASK_PCM_ALSA_PLAYBACK = 1 << BIT_PCM_ALSA_PLAYBACK, LINE6_BIT(PCM_ALSA_PLAYBACK_STREAM),
MASK_PCM_ALSA_CAPTURE = 1 << BIT_PCM_ALSA_CAPTURE, LINE6_BIT(PCM_ALSA_CAPTURE_BUFFER),
MASK_PCM_MONITOR_PLAYBACK = 1 << BIT_PCM_MONITOR_PLAYBACK, LINE6_BIT(PCM_ALSA_CAPTURE_STREAM),
MASK_PCM_MONITOR_CAPTURE = 1 << BIT_PCM_MONITOR_CAPTURE, 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 #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
MASK_PCM_IMPULSE_PLAYBACK = 1 << BIT_PCM_IMPULSE_PLAYBACK, LINE6_BIT(PCM_IMPULSE_PLAYBACK_BUFFER),
MASK_PCM_IMPULSE_CAPTURE = 1 << BIT_PCM_IMPULSE_CAPTURE, LINE6_BIT(PCM_IMPULSE_PLAYBACK_STREAM),
LINE6_BIT(PCM_IMPULSE_CAPTURE_BUFFER),
LINE6_BIT(PCM_IMPULSE_CAPTURE_STREAM),
#endif #endif
MASK_PAUSE_PLAYBACK = 1 << BIT_PAUSE_PLAYBACK, LINE6_BIT(PAUSE_PLAYBACK),
MASK_PREPARED = 1 << BIT_PREPARED, LINE6_BIT(PREPARED),
/* *INDENT-ON* */
/* 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 #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 #endif
/* combined masks (by direction): */ /* combined bit masks (by direction): */
LINE6_BITS_PLAYBACK_BUFFER =
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE #ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
MASK_PLAYBACK = LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER |
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
#endif #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 { struct line6_pcm_properties {
@ -290,7 +364,7 @@ struct snd_line6_pcm {
#endif #endif
/** /**
Several status bits (see BIT_*). Several status bits (see LINE6_BIT_*).
*/ */
unsigned long flags; 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_trigger(struct snd_pcm_substream *substream, int cmd);
extern int snd_line6_prepare(struct snd_pcm_substream *substream); extern int snd_line6_prepare(struct snd_pcm_substream *substream);
extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm); 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_acquire(struct snd_line6_pcm *line6pcm, int channels);
extern int line6_pcm_stop(struct snd_line6_pcm *line6pcm, int channels); extern int line6_pcm_release(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; \
} \
}
#endif #endif

View File

@ -166,7 +166,7 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
struct usb_iso_packet_descriptor *fout = struct usb_iso_packet_descriptor *fout =
&urb_out->iso_frame_desc[i]; &urb_out->iso_frame_desc[i];
if (line6pcm->flags & MASK_CAPTURE) if (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM)
fsize = line6pcm->prev_fsize; fsize = line6pcm->prev_fsize;
if (fsize == 0) { 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->transfer_buffer_length = urb_size;
urb_out->context = line6pcm; urb_out->context = line6pcm;
if (test_bit(BIT_PCM_ALSA_PLAYBACK, &line6pcm->flags) && if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags) &&
!test_bit(BIT_PAUSE_PLAYBACK, &line6pcm->flags)) { !test_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags)) {
struct snd_pcm_runtime *runtime = struct snd_pcm_runtime *runtime =
get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK)->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) { if (line6pcm->prev_fbuf != NULL) {
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE #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, create_impulse_test_signal(line6pcm, urb_out,
bytes_per_frame); bytes_per_frame);
if (line6pcm->flags & MASK_PCM_ALSA_CAPTURE) { if (line6pcm->flags & LINE6_BIT_PCM_ALSA_CAPTURE_STREAM) {
line6_capture_copy(line6pcm, line6_capture_copy(line6pcm,
urb_out->transfer_buffer, urb_out->transfer_buffer,
urb_out-> urb_out->
@ -254,8 +254,8 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
if (! if (!
(line6pcm->line6-> (line6pcm->line6->
properties->capabilities & LINE6_BIT_HWMON) properties->capabilities & LINE6_BIT_HWMON)
&& (line6pcm->flags & MASK_PLAYBACK) && (line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM)
&& (line6pcm->flags & MASK_CAPTURE)) && (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM))
add_monitor_signal(urb_out, line6pcm->prev_fbuf, add_monitor_signal(urb_out, line6pcm->prev_fbuf,
line6pcm->volume_monitor, line6pcm->volume_monitor,
bytes_per_frame); 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. 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; int timeout = HZ;
unsigned int i; 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) void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
{ {
line6_unlink_audio_out_urbs(line6pcm); line6_unlink_audio_out_urbs(line6pcm);
wait_clear_audio_out_urbs(line6pcm); line6_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;
} }
void line6_free_playback_buffer(struct snd_line6_pcm *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); 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; struct snd_pcm_runtime *runtime = substream->runtime;
line6pcm->pos_out_done += line6pcm->pos_out_done +=
length / line6pcm->properties->bytes_per_frame; length / line6pcm->properties->bytes_per_frame;
@ -432,7 +413,7 @@ static void audio_out_callback(struct urb *urb)
if (!shutdown) { if (!shutdown) {
submit_audio_out_urb(line6pcm); 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; line6pcm->bytes_out += length;
if (line6pcm->bytes_out >= line6pcm->period_out) { if (line6pcm->bytes_out >= line6pcm->period_out) {
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 */ /* -- [FD] end */
if ((line6pcm->flags & MASK_PLAYBACK) == 0) { ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
ret = line6_alloc_playback_buffer(line6pcm);
if (ret < 0) if (ret < 0)
return ret; return ret;
}
ret = snd_pcm_lib_malloc_pages(substream, ret = snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params)); params_buffer_bytes(hw_params));
if (ret < 0) if (ret < 0) {
line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
return ret; return ret;
}
line6pcm->period_out = params_period_bytes(hw_params); line6pcm->period_out = params_period_bytes(hw_params);
return 0; 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) static int snd_line6_playback_hw_free(struct snd_pcm_substream *substream)
{ {
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream); struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
if ((line6pcm->flags & MASK_PLAYBACK) == 0) {
line6_unlink_wait_clear_audio_out_urbs(line6pcm);
line6_free_playback_buffer(line6pcm);
}
return snd_pcm_lib_free_pages(substream); 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 #ifdef CONFIG_PM
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
#endif #endif
err = line6_pcm_start(line6pcm, MASK_PCM_ALSA_PLAYBACK); err = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM);
if (err < 0) if (err < 0)
return err; return err;
@ -534,7 +510,7 @@ int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd)
#ifdef CONFIG_PM #ifdef CONFIG_PM
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
#endif #endif
err = line6_pcm_stop(line6pcm, MASK_PCM_ALSA_PLAYBACK); err = line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM);
if (err < 0) if (err < 0)
return err; return err;
@ -542,11 +518,11 @@ int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd)
break; break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
set_bit(BIT_PAUSE_PLAYBACK, &line6pcm->flags); set_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags);
break; break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
clear_bit(BIT_PAUSE_PLAYBACK, &line6pcm->flags); clear_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags);
break; break;
default: default:

View File

@ -29,13 +29,13 @@
extern struct snd_pcm_ops snd_line6_playback_ops; 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 int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm);
extern void line6_free_playback_buffer(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 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_audio_out_urbs(struct snd_line6_pcm *line6pcm);
extern void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm extern void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm
*line6pcm); *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); extern int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd);
#endif #endif

View File

@ -207,9 +207,9 @@ static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol,
line6pcm->volume_monitor = ucontrol->value.integer.value[0]; line6pcm->volume_monitor = ucontrol->value.integer.value[0];
if (line6pcm->volume_monitor > 0) if (line6pcm->volume_monitor > 0)
line6_pcm_start(line6pcm, MASK_PCM_MONITOR); line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_MONITOR);
else else
line6_pcm_stop(line6pcm, MASK_PCM_MONITOR); line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
return 1; 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_toneport *toneport = (struct usb_line6_toneport *)arg;
struct usb_line6 *line6 = &toneport->line6; 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 */ /* control definition */
@ -320,7 +320,9 @@ static void toneport_setup(struct usb_line6_toneport *toneport)
/* initialize source select: */ /* initialize source select: */
switch (usbdev->descriptor.idProduct) { switch (usbdev->descriptor.idProduct) {
case LINE6_DEVID_TONEPORT_UX1: case LINE6_DEVID_TONEPORT_UX1:
case LINE6_DEVID_TONEPORT_UX2:
case LINE6_DEVID_PODSTUDIO_UX1: case LINE6_DEVID_PODSTUDIO_UX1:
case LINE6_DEVID_PODSTUDIO_UX2:
toneport_send_cmd(usbdev, toneport_send_cmd(usbdev,
toneport_source_info[toneport->source].code, toneport_source_info[toneport->source].code,
0x0000); 0x0000);
@ -363,7 +365,9 @@ static int toneport_try_init(struct usb_interface *interface,
/* register source select control: */ /* register source select control: */
switch (usbdev->descriptor.idProduct) { switch (usbdev->descriptor.idProduct) {
case LINE6_DEVID_TONEPORT_UX1: case LINE6_DEVID_TONEPORT_UX1:
case LINE6_DEVID_TONEPORT_UX2:
case LINE6_DEVID_PODSTUDIO_UX1: case LINE6_DEVID_PODSTUDIO_UX1:
case LINE6_DEVID_PODSTUDIO_UX2:
err = err =
snd_ctl_add(line6->card, snd_ctl_add(line6->card,
snd_ctl_new1(&toneport_control_source, 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; struct snd_line6_pcm *line6pcm = toneport->line6.line6pcm;
if (line6pcm != NULL) { if (line6pcm != NULL) {
line6_pcm_stop(line6pcm, MASK_PCM_MONITOR); line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
line6_pcm_disconnect(line6pcm); line6_pcm_disconnect(line6pcm);
} }
} }

View File

@ -39,31 +39,29 @@
#define LINE6_DEVID_TONEPORT_UX2 0x4142 #define LINE6_DEVID_TONEPORT_UX2 0x4142
#define LINE6_DEVID_VARIAX 0x534d #define LINE6_DEVID_VARIAX 0x534d
enum { #define LINE6_BIT(x) LINE6_BIT_ ## x = 1 << LINE6_INDEX_ ## x
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
enum { 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(BASSPODXT),
LINE6_BIT(BASSPODXTLIVE), LINE6_BIT(BASSPODXTLIVE),
LINE6_BIT(BASSPODXTPRO), LINE6_BIT(BASSPODXTPRO),

View File

@ -3825,6 +3825,7 @@ static int easycap_usb_probe(struct usb_interface *intf,
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL); pdata_urb = kzalloc(sizeof(struct data_urb), GFP_KERNEL);
if (!pdata_urb) { if (!pdata_urb) {
usb_free_urb(purb);
SAM("ERROR: Could not allocate struct data_urb.\n"); SAM("ERROR: Could not allocate struct data_urb.\n");
return -ENOMEM; return -ENOMEM;
} }

View File

@ -3,5 +3,8 @@ TODO:
Upon Unstaging: Upon Unstaging:
- move mei.h to include/linux/mei.h - move mei.h to include/linux/mei.h
- Documentation/ioctl/ioctl-number.txt - 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 - drop mei_version.h
- Updated MAINTAINERS - Updated MAINTAINERS

View File

@ -1,7 +1,7 @@
/* /*
* *
* Intel Management Engine Interface (Intel MEI) Linux driver * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,

View File

@ -1,7 +1,7 @@
/* /*
* *
* Intel Management Engine Interface (Intel MEI) Linux driver * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,

View File

@ -1,7 +1,7 @@
/* /*
* *
* Intel Management Engine Interface (Intel MEI) Linux driver * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * 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: message buffer will be written
* @buffer_length: message size will be read * @buffer_length: message size will be read
*/ */
void mei_read_slots(struct mei_device *dev, void mei_read_slots(struct mei_device *dev, unsigned char *buffer,
unsigned char *buffer, unsigned long buffer_length) unsigned long buffer_length)
{ {
u32 i = 0; u32 *reg_buf = (u32 *)buffer;
unsigned char temp_buf[sizeof(u32)];
while (buffer_length >= sizeof(u32)) { for (; buffer_length >= sizeof(u32); buffer_length -= sizeof(u32))
((u32 *) buffer)[i] = mei_mecbrw_read(dev); *reg_buf++ = mei_mecbrw_read(dev);
dev_dbg(&dev->pdev->dev,
"buffer[%d]= %d\n",
i, ((u32 *) buffer)[i]);
i++;
buffer_length -= sizeof(u32);
}
if (buffer_length > 0) { if (buffer_length > 0) {
*((u32 *) &temp_buf) = mei_mecbrw_read(dev); u32 reg = mei_mecbrw_read(dev);
memcpy(&buffer[i * 4], temp_buf, buffer_length); memcpy(reg_buf, &reg, buffer_length);
} }
dev->host_hw_state |= H_IG; dev->host_hw_state |= H_IG;

View File

@ -1,7 +1,7 @@
/* /*
* *
* Intel Management Engine Interface (Intel MEI) Linux driver * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@ -33,7 +33,8 @@
void mei_read_slots(struct mei_device *dev, 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, int mei_write_message(struct mei_device *dev,
struct mei_msg_hdr *header, struct mei_msg_hdr *header,

View File

@ -1,7 +1,7 @@
/* /*
* *
* Intel Management Engine Interface (Intel MEI) Linux driver * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * 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(mei_hdr->me_addr != dev->iamthif_cl.me_client_id);
BUG_ON(dev->iamthif_state != MEI_IAMTHIF_READING); BUG_ON(dev->iamthif_state != MEI_IAMTHIF_READING);
buffer = (unsigned char *) (dev->iamthif_msg_buf + buffer = dev->iamthif_msg_buf + dev->iamthif_msg_buf_index;
dev->iamthif_msg_buf_index);
BUG_ON(dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length); BUG_ON(dev->iamthif_mtu < dev->iamthif_msg_buf_index + mei_hdr->length);
mei_read_slots(dev, buffer, 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; cl = (struct mei_cl *)cb_pos->file_private;
if (cl && _mei_irq_thread_state_ok(cl, mei_hdr)) { if (cl && _mei_irq_thread_state_ok(cl, mei_hdr)) {
cl->reading_state = MEI_READING; cl->reading_state = MEI_READING;
buffer = (unsigned char *) buffer = cb_pos->response_buffer.data + cb_pos->information;
(cb_pos->response_buffer.data +
cb_pos->information);
if (cb_pos->response_buffer.size < if (cb_pos->response_buffer.size <
mei_hdr->length + cb_pos->information) { 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: quit:
dev_dbg(&dev->pdev->dev, "message read\n"); dev_dbg(&dev->pdev->dev, "message read\n");
if (!buffer) { if (!buffer) {
mei_read_slots(dev, (unsigned char *) dev->rd_msg_buf, mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
mei_hdr->length);
dev_dbg(&dev->pdev->dev, "discarding message, header =%08x.\n", dev_dbg(&dev->pdev->dev, "discarding message, header =%08x.\n",
*(u32 *) dev->rd_msg_buf); *(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; struct hbm_host_stop_request *host_stop_req;
int res; int res;
unsigned char *buffer;
/* read the message to our buffer */ /* read the message to our buffer */
buffer = (unsigned char *) dev->rd_msg_buf;
BUG_ON(mei_hdr->length >= sizeof(dev->rd_msg_buf)); BUG_ON(mei_hdr->length >= sizeof(dev->rd_msg_buf));
mei_read_slots(dev, buffer, mei_hdr->length); mei_read_slots(dev, dev->rd_msg_buf, mei_hdr->length);
mei_msg = (struct mei_bus_message *) buffer; mei_msg = (struct mei_bus_message *)dev->rd_msg_buf;
switch (*(u8 *) mei_msg) { switch (*(u8 *) mei_msg) {
case HOST_START_RES_CMD: 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) {
if (--dev->iamthif_stall_timer == 0) { 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); mei_reset(dev, 1);
dev->iamthif_msg_buf_size = 0; dev->iamthif_msg_buf_size = 0;
dev->iamthif_msg_buf_index = 0; dev->iamthif_msg_buf_index = 0;

View File

@ -1,7 +1,7 @@
/* /*
* *
* Intel Management Engine Interface (Intel MEI) Linux driver * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,

View File

@ -1,7 +1,7 @@
/* /*
* *
* Intel Management Engine Interface (Intel MEI) Linux driver * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,

View File

@ -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;
}

View File

@ -1,63 +1,68 @@
/* /******************************************************************************
* Intel Management Engine Interface (Intel MEI) Linux driver
Intel Management Engine Interface (Intel MEI) Linux driver * Intel MEI Interface Header
Intel MEI Interface Header *
* This file is provided under a dual BSD/GPLv2 license. When using or
This file is provided under a dual BSD/GPLv2 license. When using or * redistributing this file, you may do so under either license.
redistributing this file, you may do so under either license. *
* GPL LICENSE SUMMARY
GPL LICENSE SUMMARY *
* Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
Copyright(c) 2003-2011 Intel Corporation. All rights reserved. *
* This program is free software; you can redistribute it and/or modify
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
it under the terms of version 2 of the GNU General Public License as * published by the Free Software Foundation.
published by the Free Software Foundation. *
* This program is distributed in the hope that it will be useful, but
This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of
WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details.
General Public License for more details. *
* You should have received a copy of the GNU General Public License
Contact Information: * along with this program; if not, write to the Free Software
Intel Corporation. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
linux-mei@linux.intel.com * USA
http://www.intel.com *
* The full GNU General Public License is included in this distribution
* in the file called LICENSE.GPL.
BSD LICENSE *
* Contact Information:
Copyright(c) 2003-2011 Intel Corporation. All rights reserved. * Intel Corporation.
All rights reserved. * linux-mei@linux.intel.com
* http://www.intel.com
Redistribution and use in source and binary forms, with or without *
modification, are permitted provided that the following conditions * BSD LICENSE
are met: *
* Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
* Redistributions of source code must retain the above copyright * All rights reserved.
notice, this list of conditions and the following disclaimer. *
* Redistributions in binary form must reproduce the above copyright * Redistribution and use in source and binary forms, with or without
notice, this list of conditions and the following disclaimer in * modification, are permitted provided that the following conditions
the documentation and/or other materials provided with the * are met:
distribution. *
* Neither the name of Intel Corporation nor the names of its * * Redistributions of source code must retain the above copyright
contributors may be used to endorse or promote products derived * notice, this list of conditions and the following disclaimer.
from this software without specific prior written permission. * * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * the documentation and/or other materials provided with the
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * distribution.
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * * Neither the name Intel Corporation nor the names of its
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * contributors may be used to endorse or promote products derived
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * from this software without specific prior written permission.
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT *
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * 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 #ifndef _LINUX_MEI_H
#define _LINUX_MEI_H #define _LINUX_MEI_H

View File

@ -1,7 +1,7 @@
/* /*
* *
* Intel Management Engine Interface (Intel MEI) Linux driver * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@ -30,6 +30,8 @@
#define MEI_WD_PARAMS_SIZE 4 #define MEI_WD_PARAMS_SIZE 4
#define MEI_WD_STATE_INDEPENDENCE_MSG_SENT (1 << 0) #define MEI_WD_STATE_INDEPENDENCE_MSG_SENT (1 << 0)
#define MEI_RD_MSG_BUF_SIZE (128 * sizeof(u32))
/* /*
* MEI PCI Device object * MEI PCI Device object
*/ */
@ -125,7 +127,7 @@ enum mei_cb_major_types {
*/ */
struct mei_message_data { struct mei_message_data {
u32 size; u32 size;
char *data; unsigned char *data;
} __packed; } __packed;
@ -219,7 +221,7 @@ struct mei_device {
bool need_reset; bool need_reset;
u32 extra_write_index; 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 wr_msg_buf[128]; /* used for control messages */
u32 ext_msg_buf[8]; /* for control responses */ u32 ext_msg_buf[8]; /* for control responses */
u32 rd_msg_hdr; u32 rd_msg_hdr;

View File

@ -1,7 +1,7 @@
/* /*
* *
* Intel Management Engine Interface (Intel MEI) Linux driver * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,

View File

@ -1,7 +1,7 @@
/* /*
* *
* Intel Management Engine Interface (Intel MEI) Linux driver * 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 * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,

View File

@ -7,21 +7,21 @@ config MFD_NVEC
config KEYBOARD_NVEC config KEYBOARD_NVEC
bool "Keyboard on nVidia compliant EC" bool "Keyboard on nVidia compliant EC"
depends on MFD_NVEC && INPUT=y depends on MFD_NVEC && INPUT
help help
Say Y here to enable support for a keyboard connected to Say Y here to enable support for a keyboard connected to
a nVidia compliant embedded controller. a nVidia compliant embedded controller.
config SERIO_NVEC_PS2 config SERIO_NVEC_PS2
bool "PS2 on nVidia EC" bool "PS2 on nVidia EC"
depends on MFD_NVEC && MOUSE_PS2 depends on MFD_NVEC && SERIO
help help
Say Y here to enable support for a Touchpad / Mouse connected Say Y here to enable support for a Touchpad / Mouse connected
to a nVidia compliant embedded controller. to a nVidia compliant embedded controller.
config NVEC_POWER config NVEC_POWER
bool "NVEC charger and battery" bool "NVEC charger and battery"
depends on MFD_NVEC && POWER_SUPPLY=y depends on MFD_NVEC && POWER_SUPPLY
help help
Say Y to enable support for battery and charger interface for Say Y to enable support for battery and charger interface for
nVidia compliant embedded controllers. nVidia compliant embedded controllers.

View File

@ -49,7 +49,7 @@
#define I2C_CNFG_DEBOUNCE_CNT_SHIFT 12 #define I2C_CNFG_DEBOUNCE_CNT_SHIFT 12
#define I2C_SL_CNFG 0x20 #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_NACK (1<<1)
#define I2C_SL_RESP (1<<0) #define I2C_SL_RESP (1<<0)
#define I2C_SL_IRQ (1<<3) #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); 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(0x1E, nvec->base + I2C_SL_DELAY_COUNT);
writel(nvec->i2c_addr>>1, nvec->base + I2C_SL_ADDR1); 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) static void nvec_disable_i2c_slave(struct nvec_chip *nvec)
{ {
disable_irq(nvec->irq); 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); 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->i2c_clk = i2c_clk;
nvec->rx = &nvec->msg_pool[0]; 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); ATOMIC_INIT_NOTIFIER_HEAD(&nvec->notifier_list);
init_completion(&nvec->sync_write); 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); INIT_WORK(&nvec->tx_work, nvec_request_master);
nvec->wq = alloc_workqueue("nvec", WQ_NON_REENTRANT, 2); 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); err = request_irq(nvec->irq, nvec_interrupt, 0, "nvec", nvec);
if (err) { if (err) {
dev_err(nvec->dev, "couldn't request irq\n"); 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); clk_enable(i2c_clk);
gpio_direction_output(nvec->gpio, 1);
gpio_set_value(nvec->gpio, 1);
/* enable event reporting */ /* enable event reporting */
nvec_write_async(nvec, EC_ENABLE_EVENT_REPORTING, nvec_write_async(nvec, EC_ENABLE_EVENT_REPORTING,

View File

@ -21,10 +21,18 @@
#include "nvec.h" #include "nvec.h"
#define START_STREAMING {'\x06', '\x03', '\x04'} #define START_STREAMING {'\x06', '\x03', '\x06'}
#define STOP_STREAMING {'\x06', '\x04'} #define STOP_STREAMING {'\x06', '\x04'}
#define SEND_COMMAND {'\x06', '\x01', '\xf4', '\x01'} #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'}; static const unsigned char MOUSE_RESET[] = {'\x06', '\x01', '\xff', '\x03'};
struct nvec_ps2 { struct nvec_ps2 {
@ -67,18 +75,18 @@ static int nvec_ps2_notifier(struct notifier_block *nb,
case NVEC_PS2_EVT: case NVEC_PS2_EVT:
for (i = 0; i < msg[1]; i++) for (i = 0; i < msg[1]; i++)
serio_interrupt(ps2_dev.ser_dev, msg[2 + i], 0); serio_interrupt(ps2_dev.ser_dev, msg[2 + i], 0);
NVEC_PHD("ps/2 mouse event: ", &msg[2], msg[1]);
return NOTIFY_STOP; return NOTIFY_STOP;
case NVEC_PS2: case NVEC_PS2:
if (msg[2] == 1) if (msg[2] == 1) {
for (i = 0; i < (msg[1] - 2); i++) for (i = 0; i < (msg[1] - 2); i++)
serio_interrupt(ps2_dev.ser_dev, msg[i + 4], 0); serio_interrupt(ps2_dev.ser_dev, msg[i + 4], 0);
else if (msg[1] != 2) { /* !ack */ NVEC_PHD("ps/2 mouse reply: ", &msg[4], msg[1] - 2);
print_hex_dump(KERN_WARNING, "unhandled mouse event: ",
DUMP_PREFIX_NONE, 16, 1,
msg, msg[1] + 2, true);
} }
else if (msg[1] != 2) /* !ack */
NVEC_PHD("unhandled mouse event: ", msg, msg[1] + 2);
return NOTIFY_STOP; 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 nvec_chip *nvec = dev_get_drvdata(pdev->dev.parent);
struct serio *ser_dev = kzalloc(sizeof(struct serio), GFP_KERNEL); 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->write = ps2_sendcommand;
ser_dev->open = ps2_startstreaming; ser_dev->start = ps2_startstreaming;
ser_dev->close = ps2_stopstreaming; ser_dev->stop = ps2_stopstreaming;
strlcpy(ser_dev->name, "nvec mouse", sizeof(ser_dev->name)); strlcpy(ser_dev->name, "nvec mouse", sizeof(ser_dev->name));
strlcpy(ser_dev->phys, "nvec", sizeof(ser_dev->phys)); 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; 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 = { static struct platform_driver nvec_mouse_driver = {
.probe = nvec_mouse_probe, .probe = nvec_mouse_probe,
.suspend = nvec_mouse_suspend,
.resume = nvec_mouse_resume,
.driver = { .driver = {
.name = "nvec-mouse", .name = "nvec-mouse",
.owner = THIS_MODULE, .owner = THIS_MODULE,

View File

@ -84,7 +84,7 @@ fail:
page_cache_release(pages[i]); page_cache_release(pages[i]);
} }
drm_free_large(pages); drm_free_large(pages);
return ERR_PTR(PTR_ERR(p)); return ERR_CAST(p);
} }
/** /**

View File

@ -4,7 +4,7 @@
* *
* Copyright (C) 2007-2010 Angelo Arrifano <miknix@gmail.com> * 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> * <http://www.microsoft.com/whdc/system/platform/firmware/DirAppLaunch.mspx>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -25,6 +25,8 @@
#define QUICKSTART_VERSION "1.03" #define QUICKSTART_VERSION "1.03"
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
@ -37,41 +39,297 @@ MODULE_AUTHOR("Angelo Arrifano");
MODULE_DESCRIPTION("ACPI Direct App Launch driver"); MODULE_DESCRIPTION("ACPI Direct App Launch driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
#define QUICKSTART_ACPI_DEVICE_NAME "quickstart" #define QUICKSTART_ACPI_DEVICE_NAME "quickstart"
#define QUICKSTART_ACPI_CLASS "quickstart" #define QUICKSTART_ACPI_CLASS "quickstart"
#define QUICKSTART_ACPI_HID "PNP0C32" #define QUICKSTART_ACPI_HID "PNP0C32"
#define QUICKSTART_PF_DRIVER_NAME "quickstart" #define QUICKSTART_PF_DRIVER_NAME "quickstart"
#define QUICKSTART_PF_DEVICE_NAME "quickstart" #define QUICKSTART_PF_DEVICE_NAME "quickstart"
#define QUICKSTART_PF_DEVATTR_NAME "pressed_button"
#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: struct quickstart_button {
* 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 {
char *name; char *name;
unsigned int id; 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 quickstart_acpi {
struct acpi_device *device; 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 LIST_HEAD(buttons);
static const struct acpi_device_id quickstart_device_ids[] = { 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}, {QUICKSTART_ACPI_HID, 0},
{"", 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 */ /* Module functions */
static void quickstart_exit(void) static void quickstart_exit(void)
{ {
input_unregister_device(quickstart_input); input_unregister_device(quickstart_input);
@ -366,15 +358,12 @@ static void quickstart_exit(void)
acpi_bus_unregister_driver(&quickstart_acpi_driver); acpi_bus_unregister_driver(&quickstart_acpi_driver);
quickstart_btnlst_free(); quickstart_buttons_free();
return;
} }
static int __init quickstart_init_input(void) static int __init quickstart_init_input(void)
{ {
struct quickstart_btn **ptr = &quickstart_data.btn_lst; struct quickstart_button *b;
int count;
int ret; int ret;
quickstart_input = input_allocate_device(); quickstart_input = input_allocate_device();
@ -385,11 +374,9 @@ static int __init quickstart_init_input(void)
quickstart_input->name = "Quickstart ACPI Buttons"; quickstart_input->name = "Quickstart ACPI Buttons";
quickstart_input->id.bustype = BUS_HOST; quickstart_input->id.bustype = BUS_HOST;
while (*ptr) { list_for_each_entry(b, &buttons, list) {
count++;
set_bit(EV_KEY, quickstart_input->evbit); set_bit(EV_KEY, quickstart_input->evbit);
set_bit((*ptr)->id, quickstart_input->keybit); set_bit(b->id, quickstart_input->keybit);
ptr = &((*ptr)->next);
} }
ret = input_register_device(quickstart_input); ret = input_register_device(quickstart_input);
@ -415,7 +402,7 @@ static int __init quickstart_init(void)
return ret; return ret;
/* If existing bus with no devices */ /* If existing bus with no devices */
if (!quickstart_data.btn_lst) { if (list_empty(&buttons)) {
ret = -ENODEV; ret = -ENODEV;
goto fail_pfdrv_reg; goto fail_pfdrv_reg;
} }
@ -444,14 +431,12 @@ static int __init quickstart_init(void)
if (ret) if (ret)
goto fail_dev_file2; goto fail_dev_file2;
/* Input device */ /* Input device */
ret = quickstart_init_input(); ret = quickstart_init_input();
if (ret) if (ret)
goto fail_input; goto fail_input;
printk(KERN_INFO "quickstart: ACPI Direct App Launch ver %s\n", pr_info("ACPI Direct App Launch ver %s\n", QUICKSTART_VERSION);
QUICKSTART_VERSION);
return 0; return 0;
fail_input: fail_input:

View File

@ -2453,7 +2453,7 @@ static inline void update_network(struct rtllib_network *dst,
if (src->wmm_param[0].ac_aci_acm_aifsn || if (src->wmm_param[0].ac_aci_acm_aifsn ||
src->wmm_param[1].ac_aci_acm_aifsn || src->wmm_param[1].ac_aci_acm_aifsn ||
src->wmm_param[2].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); memcpy(dst->wmm_param, src->wmm_param, WME_AC_PRAM_LEN);
dst->SignalStrength = src->SignalStrength; dst->SignalStrength = src->SignalStrength;

View File

@ -237,7 +237,7 @@ ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb,
#ifdef NOT_YET #ifdef NOT_YET
if (ieee->iw_mode == IW_MODE_MASTER) { 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); ieee->dev->name);
return 0; return 0;
/* /*

View File

@ -9,13 +9,6 @@ config R8712U
This option adds the Realtek RTL8712 USB device such as the D-Link DWA-130. 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. 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 config R8712_TX_AGGR
bool "Realtek RTL8712U Transmit Aggregation code" bool "Realtek RTL8712U Transmit Aggregation code"
depends on R8712U && BROKEN depends on R8712U && BROKEN

View File

@ -140,7 +140,6 @@ struct dvobj_priv {
u8 ishighspeed; u8 ishighspeed;
uint(*inirp_init)(struct _adapter *adapter); uint(*inirp_init)(struct _adapter *adapter);
uint(*inirp_deinit)(struct _adapter *adapter); uint(*inirp_deinit)(struct _adapter *adapter);
struct semaphore usb_suspend_sema;
struct usb_device *pusbdev; struct usb_device *pusbdev;
}; };

View File

@ -330,7 +330,6 @@ u8 r8712_init_drv_sw(struct _adapter *padapter)
padapter->stapriv.padapter = padapter; padapter->stapriv.padapter = padapter;
r8712_init_bcmc_stainfo(padapter); r8712_init_bcmc_stainfo(padapter);
r8712_init_pwrctrl_priv(padapter); r8712_init_pwrctrl_priv(padapter);
sema_init(&(padapter->pwrctrlpriv.pnp_pwr_mgnt_sema), 0);
mp871xinit(padapter); mp871xinit(padapter);
if (init_default_value(padapter) != _SUCCESS) if (init_default_value(padapter) != _SUCCESS)
return _FAIL; return _FAIL;

View File

@ -72,18 +72,6 @@ static inline struct list_head *get_list_head(struct __queue *queue)
#define LIST_CONTAINOR(ptr, type, member) \ #define LIST_CONTAINOR(ptr, type, member) \
((type *)((char *)(ptr)-(SIZE_T)(&((type *)0)->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) static inline void list_delete(struct list_head *plist)
{ {
list_del_init(plist); list_del_init(plist);
@ -152,11 +140,6 @@ static inline u32 _down_sema(struct semaphore *sema)
return _SUCCESS; return _SUCCESS;
} }
static inline void _rtl_rwlock_init(struct semaphore *prwlock)
{
sema_init(prwlock, 1);
}
static inline void _init_listhead(struct list_head *list) static inline void _init_listhead(struct list_head *list)
{ {
INIT_LIST_HEAD(list); INIT_LIST_HEAD(list);

View File

@ -55,8 +55,6 @@ int r8712_init_recv_priv(struct recv_priv *precvpriv, struct _adapter *padapter)
int alignment = 0; int alignment = 0;
struct sk_buff *pskb = NULL; struct sk_buff *pskb = NULL;
sema_init(&precvpriv->recv_sema, 0);
sema_init(&precvpriv->terminate_recvthread_sema, 0);
/*init recv_buf*/ /*init recv_buf*/
_init_queue(&precvpriv->free_recv_buf_queue); _init_queue(&precvpriv->free_recv_buf_queue);
precvpriv->pallocated_recv_buf = _malloc(NR_RECVBUFF * precvpriv->pallocated_recv_buf = _malloc(NR_RECVBUFF *

View File

@ -131,7 +131,6 @@ uint r8712_alloc_io_queue(struct _adapter *adapter)
pio_req = (struct io_req *)(pio_queue->free_ioreqs_buf); pio_req = (struct io_req *)(pio_queue->free_ioreqs_buf);
for (i = 0; i < NUM_IOREQ; i++) { for (i = 0; i < NUM_IOREQ; i++) {
_init_listhead(&pio_req->list); _init_listhead(&pio_req->list);
sema_init(&pio_req->sema, 0);
list_insert_tail(&pio_req->list, &pio_queue->free_ioreqs); list_insert_tail(&pio_req->list, &pio_queue->free_ioreqs);
pio_req++; pio_req++;
} }

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