Merge tag 'staging-3.3-rc3' into staging-next
This was done to resolve some merge issues with the following files that had changed in both branches: drivers/staging/rtl8712/rtl871x_sta_mgt.c drivers/staging/tidspbridge/rmgr/drv_interface.c drivers/staging/zcache/zcache-main.c Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
commit
b91867f2ee
|
@ -40,8 +40,6 @@ source "drivers/net/Kconfig"
|
||||||
|
|
||||||
source "drivers/isdn/Kconfig"
|
source "drivers/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"
|
||||||
|
|
|
@ -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/
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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/
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -0,0 +1,297 @@
|
||||||
|
/* drivers/rtc/alarm-dev.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007-2009 Google, Inc.
|
||||||
|
*
|
||||||
|
* This software is licensed under the terms of the GNU General Public
|
||||||
|
* License version 2, as published by the Free Software Foundation, and
|
||||||
|
* may be copied, distributed, and modified under those terms.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/time.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/miscdevice.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
#include "android_alarm.h"
|
||||||
|
|
||||||
|
/* XXX - Hack out wakelocks, while they are out of tree */
|
||||||
|
struct wake_lock {
|
||||||
|
int i;
|
||||||
|
};
|
||||||
|
#define wake_lock(x)
|
||||||
|
#define wake_lock_timeout(x, y)
|
||||||
|
#define wake_unlock(x)
|
||||||
|
#define WAKE_LOCK_SUSPEND 0
|
||||||
|
#define wake_lock_init(x, y, z) ((x)->i = 1)
|
||||||
|
#define wake_lock_destroy(x)
|
||||||
|
|
||||||
|
#define ANDROID_ALARM_PRINT_INFO (1U << 0)
|
||||||
|
#define ANDROID_ALARM_PRINT_IO (1U << 1)
|
||||||
|
#define ANDROID_ALARM_PRINT_INT (1U << 2)
|
||||||
|
|
||||||
|
|
||||||
|
static int debug_mask = ANDROID_ALARM_PRINT_INFO;
|
||||||
|
module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
|
||||||
|
|
||||||
|
#define pr_alarm(debug_level_mask, args...) \
|
||||||
|
do { \
|
||||||
|
if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask) { \
|
||||||
|
pr_info(args); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define ANDROID_ALARM_WAKEUP_MASK ( \
|
||||||
|
ANDROID_ALARM_RTC_WAKEUP_MASK | \
|
||||||
|
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK)
|
||||||
|
|
||||||
|
/* support old usespace code */
|
||||||
|
#define ANDROID_ALARM_SET_OLD _IOW('a', 2, time_t) /* set alarm */
|
||||||
|
#define ANDROID_ALARM_SET_AND_WAIT_OLD _IOW('a', 3, time_t)
|
||||||
|
|
||||||
|
static int alarm_opened;
|
||||||
|
static DEFINE_SPINLOCK(alarm_slock);
|
||||||
|
static struct wake_lock alarm_wake_lock;
|
||||||
|
static DECLARE_WAIT_QUEUE_HEAD(alarm_wait_queue);
|
||||||
|
static uint32_t alarm_pending;
|
||||||
|
static uint32_t alarm_enabled;
|
||||||
|
static uint32_t wait_pending;
|
||||||
|
|
||||||
|
static struct android_alarm alarms[ANDROID_ALARM_TYPE_COUNT];
|
||||||
|
|
||||||
|
static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
|
||||||
|
{
|
||||||
|
int rv = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
struct timespec new_alarm_time;
|
||||||
|
struct timespec new_rtc_time;
|
||||||
|
struct timespec tmp_time;
|
||||||
|
enum android_alarm_type alarm_type = ANDROID_ALARM_IOCTL_TO_TYPE(cmd);
|
||||||
|
uint32_t alarm_type_mask = 1U << alarm_type;
|
||||||
|
|
||||||
|
if (alarm_type >= ANDROID_ALARM_TYPE_COUNT)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_GET_TIME(0)) {
|
||||||
|
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
|
||||||
|
return -EPERM;
|
||||||
|
if (file->private_data == NULL &&
|
||||||
|
cmd != ANDROID_ALARM_SET_RTC) {
|
||||||
|
spin_lock_irqsave(&alarm_slock, flags);
|
||||||
|
if (alarm_opened) {
|
||||||
|
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
alarm_opened = 1;
|
||||||
|
file->private_data = (void *)1;
|
||||||
|
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (ANDROID_ALARM_BASE_CMD(cmd)) {
|
||||||
|
case ANDROID_ALARM_CLEAR(0):
|
||||||
|
spin_lock_irqsave(&alarm_slock, flags);
|
||||||
|
pr_alarm(IO, "alarm %d clear\n", alarm_type);
|
||||||
|
android_alarm_try_to_cancel(&alarms[alarm_type]);
|
||||||
|
if (alarm_pending) {
|
||||||
|
alarm_pending &= ~alarm_type_mask;
|
||||||
|
if (!alarm_pending && !wait_pending)
|
||||||
|
wake_unlock(&alarm_wake_lock);
|
||||||
|
}
|
||||||
|
alarm_enabled &= ~alarm_type_mask;
|
||||||
|
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ANDROID_ALARM_SET_OLD:
|
||||||
|
case ANDROID_ALARM_SET_AND_WAIT_OLD:
|
||||||
|
if (get_user(new_alarm_time.tv_sec, (int __user *)arg)) {
|
||||||
|
rv = -EFAULT;
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
new_alarm_time.tv_nsec = 0;
|
||||||
|
goto from_old_alarm_set;
|
||||||
|
|
||||||
|
case ANDROID_ALARM_SET_AND_WAIT(0):
|
||||||
|
case ANDROID_ALARM_SET(0):
|
||||||
|
if (copy_from_user(&new_alarm_time, (void __user *)arg,
|
||||||
|
sizeof(new_alarm_time))) {
|
||||||
|
rv = -EFAULT;
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
from_old_alarm_set:
|
||||||
|
spin_lock_irqsave(&alarm_slock, flags);
|
||||||
|
pr_alarm(IO, "alarm %d set %ld.%09ld\n", alarm_type,
|
||||||
|
new_alarm_time.tv_sec, new_alarm_time.tv_nsec);
|
||||||
|
alarm_enabled |= alarm_type_mask;
|
||||||
|
android_alarm_start_range(&alarms[alarm_type],
|
||||||
|
timespec_to_ktime(new_alarm_time),
|
||||||
|
timespec_to_ktime(new_alarm_time));
|
||||||
|
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||||
|
if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_SET_AND_WAIT(0)
|
||||||
|
&& cmd != ANDROID_ALARM_SET_AND_WAIT_OLD)
|
||||||
|
break;
|
||||||
|
/* fall though */
|
||||||
|
case ANDROID_ALARM_WAIT:
|
||||||
|
spin_lock_irqsave(&alarm_slock, flags);
|
||||||
|
pr_alarm(IO, "alarm wait\n");
|
||||||
|
if (!alarm_pending && wait_pending) {
|
||||||
|
wake_unlock(&alarm_wake_lock);
|
||||||
|
wait_pending = 0;
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||||
|
rv = wait_event_interruptible(alarm_wait_queue, alarm_pending);
|
||||||
|
if (rv)
|
||||||
|
goto err1;
|
||||||
|
spin_lock_irqsave(&alarm_slock, flags);
|
||||||
|
rv = alarm_pending;
|
||||||
|
wait_pending = 1;
|
||||||
|
alarm_pending = 0;
|
||||||
|
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||||
|
break;
|
||||||
|
case ANDROID_ALARM_SET_RTC:
|
||||||
|
if (copy_from_user(&new_rtc_time, (void __user *)arg,
|
||||||
|
sizeof(new_rtc_time))) {
|
||||||
|
rv = -EFAULT;
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
rv = android_alarm_set_rtc(new_rtc_time);
|
||||||
|
spin_lock_irqsave(&alarm_slock, flags);
|
||||||
|
alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK;
|
||||||
|
wake_up(&alarm_wait_queue);
|
||||||
|
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||||
|
if (rv < 0)
|
||||||
|
goto err1;
|
||||||
|
break;
|
||||||
|
case ANDROID_ALARM_GET_TIME(0):
|
||||||
|
switch (alarm_type) {
|
||||||
|
case ANDROID_ALARM_RTC_WAKEUP:
|
||||||
|
case ANDROID_ALARM_RTC:
|
||||||
|
getnstimeofday(&tmp_time);
|
||||||
|
break;
|
||||||
|
case ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP:
|
||||||
|
case ANDROID_ALARM_ELAPSED_REALTIME:
|
||||||
|
tmp_time =
|
||||||
|
ktime_to_timespec(alarm_get_elapsed_realtime());
|
||||||
|
break;
|
||||||
|
case ANDROID_ALARM_TYPE_COUNT:
|
||||||
|
case ANDROID_ALARM_SYSTEMTIME:
|
||||||
|
ktime_get_ts(&tmp_time);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (copy_to_user((void __user *)arg, &tmp_time,
|
||||||
|
sizeof(tmp_time))) {
|
||||||
|
rv = -EFAULT;
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
rv = -EINVAL;
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
err1:
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int alarm_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
file->private_data = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int alarm_release(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&alarm_slock, flags);
|
||||||
|
if (file->private_data != 0) {
|
||||||
|
for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {
|
||||||
|
uint32_t alarm_type_mask = 1U << i;
|
||||||
|
if (alarm_enabled & alarm_type_mask) {
|
||||||
|
pr_alarm(INFO, "alarm_release: clear alarm, "
|
||||||
|
"pending %d\n",
|
||||||
|
!!(alarm_pending & alarm_type_mask));
|
||||||
|
alarm_enabled &= ~alarm_type_mask;
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||||
|
android_alarm_cancel(&alarms[i]);
|
||||||
|
spin_lock_irqsave(&alarm_slock, flags);
|
||||||
|
}
|
||||||
|
if (alarm_pending | wait_pending) {
|
||||||
|
if (alarm_pending)
|
||||||
|
pr_alarm(INFO, "alarm_release: clear "
|
||||||
|
"pending alarms %x\n", alarm_pending);
|
||||||
|
wake_unlock(&alarm_wake_lock);
|
||||||
|
wait_pending = 0;
|
||||||
|
alarm_pending = 0;
|
||||||
|
}
|
||||||
|
alarm_opened = 0;
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void alarm_triggered(struct android_alarm *alarm)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
uint32_t alarm_type_mask = 1U << alarm->type;
|
||||||
|
|
||||||
|
pr_alarm(INT, "alarm_triggered type %d\n", alarm->type);
|
||||||
|
spin_lock_irqsave(&alarm_slock, flags);
|
||||||
|
if (alarm_enabled & alarm_type_mask) {
|
||||||
|
wake_lock_timeout(&alarm_wake_lock, 5 * HZ);
|
||||||
|
alarm_enabled &= ~alarm_type_mask;
|
||||||
|
alarm_pending |= alarm_type_mask;
|
||||||
|
wake_up(&alarm_wait_queue);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations alarm_fops = {
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.unlocked_ioctl = alarm_ioctl,
|
||||||
|
.open = alarm_open,
|
||||||
|
.release = alarm_release,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct miscdevice alarm_device = {
|
||||||
|
.minor = MISC_DYNAMIC_MINOR,
|
||||||
|
.name = "alarm",
|
||||||
|
.fops = &alarm_fops,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init alarm_dev_init(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
err = misc_register(&alarm_device);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++)
|
||||||
|
android_alarm_init(&alarms[i], i, alarm_triggered);
|
||||||
|
wake_lock_init(&alarm_wake_lock, WAKE_LOCK_SUSPEND, "alarm");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit alarm_dev_exit(void)
|
||||||
|
{
|
||||||
|
misc_deregister(&alarm_device);
|
||||||
|
wake_lock_destroy(&alarm_wake_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
module_init(alarm_dev_init);
|
||||||
|
module_exit(alarm_dev_exit);
|
||||||
|
|
|
@ -0,0 +1,601 @@
|
||||||
|
/* drivers/rtc/alarm.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2007-2009 Google, Inc.
|
||||||
|
*
|
||||||
|
* This software is licensed under the terms of the GNU General Public
|
||||||
|
* License version 2, as published by the Free Software Foundation, and
|
||||||
|
* may be copied, distributed, and modified under those terms.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/time.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/miscdevice.h>
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/rtc.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/spinlock.h>
|
||||||
|
#include "android_alarm.h"
|
||||||
|
|
||||||
|
/* XXX - Hack out wakelocks, while they are out of tree */
|
||||||
|
struct wake_lock {
|
||||||
|
int i;
|
||||||
|
};
|
||||||
|
#define wake_lock(x)
|
||||||
|
#define wake_lock_timeout(x, y)
|
||||||
|
#define wake_unlock(x)
|
||||||
|
#define WAKE_LOCK_SUSPEND 0
|
||||||
|
#define wake_lock_init(x, y, z) ((x)->i = 1)
|
||||||
|
#define wake_lock_destroy(x)
|
||||||
|
|
||||||
|
#define ANDROID_ALARM_PRINT_ERROR (1U << 0)
|
||||||
|
#define ANDROID_ALARM_PRINT_INIT_STATUS (1U << 1)
|
||||||
|
#define ANDROID_ALARM_PRINT_TSET (1U << 2)
|
||||||
|
#define ANDROID_ALARM_PRINT_CALL (1U << 3)
|
||||||
|
#define ANDROID_ALARM_PRINT_SUSPEND (1U << 4)
|
||||||
|
#define ANDROID_ALARM_PRINT_INT (1U << 5)
|
||||||
|
#define ANDROID_ALARM_PRINT_FLOW (1U << 6)
|
||||||
|
|
||||||
|
static int debug_mask = ANDROID_ALARM_PRINT_ERROR | \
|
||||||
|
ANDROID_ALARM_PRINT_INIT_STATUS;
|
||||||
|
module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
|
||||||
|
|
||||||
|
#define pr_alarm(debug_level_mask, args...) \
|
||||||
|
do { \
|
||||||
|
if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask) { \
|
||||||
|
pr_info(args); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define ANDROID_ALARM_WAKEUP_MASK ( \
|
||||||
|
ANDROID_ALARM_RTC_WAKEUP_MASK | \
|
||||||
|
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK)
|
||||||
|
|
||||||
|
/* support old usespace code */
|
||||||
|
#define ANDROID_ALARM_SET_OLD _IOW('a', 2, time_t) /* set alarm */
|
||||||
|
#define ANDROID_ALARM_SET_AND_WAIT_OLD _IOW('a', 3, time_t)
|
||||||
|
|
||||||
|
struct alarm_queue {
|
||||||
|
struct rb_root alarms;
|
||||||
|
struct rb_node *first;
|
||||||
|
struct hrtimer timer;
|
||||||
|
ktime_t delta;
|
||||||
|
bool stopped;
|
||||||
|
ktime_t stopped_time;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct rtc_device *alarm_rtc_dev;
|
||||||
|
static DEFINE_SPINLOCK(alarm_slock);
|
||||||
|
static DEFINE_MUTEX(alarm_setrtc_mutex);
|
||||||
|
static struct wake_lock alarm_rtc_wake_lock;
|
||||||
|
static struct platform_device *alarm_platform_dev;
|
||||||
|
struct alarm_queue alarms[ANDROID_ALARM_TYPE_COUNT];
|
||||||
|
static bool suspended;
|
||||||
|
|
||||||
|
static void update_timer_locked(struct alarm_queue *base, bool head_removed)
|
||||||
|
{
|
||||||
|
struct android_alarm *alarm;
|
||||||
|
bool is_wakeup = base == &alarms[ANDROID_ALARM_RTC_WAKEUP] ||
|
||||||
|
base == &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP];
|
||||||
|
|
||||||
|
if (base->stopped) {
|
||||||
|
pr_alarm(FLOW, "changed alarm while setting the wall time\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_wakeup && !suspended && head_removed)
|
||||||
|
wake_unlock(&alarm_rtc_wake_lock);
|
||||||
|
|
||||||
|
if (!base->first)
|
||||||
|
return;
|
||||||
|
|
||||||
|
alarm = container_of(base->first, struct android_alarm, node);
|
||||||
|
|
||||||
|
pr_alarm(FLOW, "selected alarm, type %d, func %pF at %lld\n",
|
||||||
|
alarm->type, alarm->function, ktime_to_ns(alarm->expires));
|
||||||
|
|
||||||
|
if (is_wakeup && suspended) {
|
||||||
|
pr_alarm(FLOW, "changed alarm while suspened\n");
|
||||||
|
wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
hrtimer_try_to_cancel(&base->timer);
|
||||||
|
base->timer.node.expires = ktime_add(base->delta, alarm->expires);
|
||||||
|
base->timer._softexpires = ktime_add(base->delta, alarm->softexpires);
|
||||||
|
hrtimer_start_expires(&base->timer, HRTIMER_MODE_ABS);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void alarm_enqueue_locked(struct android_alarm *alarm)
|
||||||
|
{
|
||||||
|
struct alarm_queue *base = &alarms[alarm->type];
|
||||||
|
struct rb_node **link = &base->alarms.rb_node;
|
||||||
|
struct rb_node *parent = NULL;
|
||||||
|
struct android_alarm *entry;
|
||||||
|
int leftmost = 1;
|
||||||
|
bool was_first = false;
|
||||||
|
|
||||||
|
pr_alarm(FLOW, "added alarm, type %d, func %pF at %lld\n",
|
||||||
|
alarm->type, alarm->function, ktime_to_ns(alarm->expires));
|
||||||
|
|
||||||
|
if (base->first == &alarm->node) {
|
||||||
|
base->first = rb_next(&alarm->node);
|
||||||
|
was_first = true;
|
||||||
|
}
|
||||||
|
if (!RB_EMPTY_NODE(&alarm->node)) {
|
||||||
|
rb_erase(&alarm->node, &base->alarms);
|
||||||
|
RB_CLEAR_NODE(&alarm->node);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (*link) {
|
||||||
|
parent = *link;
|
||||||
|
entry = rb_entry(parent, struct android_alarm, node);
|
||||||
|
/*
|
||||||
|
* We dont care about collisions. Nodes with
|
||||||
|
* the same expiry time stay together.
|
||||||
|
*/
|
||||||
|
if (alarm->expires.tv64 < entry->expires.tv64) {
|
||||||
|
link = &(*link)->rb_left;
|
||||||
|
} else {
|
||||||
|
link = &(*link)->rb_right;
|
||||||
|
leftmost = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (leftmost)
|
||||||
|
base->first = &alarm->node;
|
||||||
|
if (leftmost || was_first)
|
||||||
|
update_timer_locked(base, was_first);
|
||||||
|
|
||||||
|
rb_link_node(&alarm->node, parent, link);
|
||||||
|
rb_insert_color(&alarm->node, &base->alarms);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* android_alarm_init - initialize an alarm
|
||||||
|
* @alarm: the alarm to be initialized
|
||||||
|
* @type: the alarm type to be used
|
||||||
|
* @function: alarm callback function
|
||||||
|
*/
|
||||||
|
void android_alarm_init(struct android_alarm *alarm,
|
||||||
|
enum android_alarm_type type, void (*function)(struct android_alarm *))
|
||||||
|
{
|
||||||
|
RB_CLEAR_NODE(&alarm->node);
|
||||||
|
alarm->type = type;
|
||||||
|
alarm->function = function;
|
||||||
|
|
||||||
|
pr_alarm(FLOW, "created alarm, type %d, func %pF\n", type, function);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* android_alarm_start_range - (re)start an alarm
|
||||||
|
* @alarm: the alarm to be added
|
||||||
|
* @start: earliest expiry time
|
||||||
|
* @end: expiry time
|
||||||
|
*/
|
||||||
|
void android_alarm_start_range(struct android_alarm *alarm, ktime_t start,
|
||||||
|
ktime_t end)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&alarm_slock, flags);
|
||||||
|
alarm->softexpires = start;
|
||||||
|
alarm->expires = end;
|
||||||
|
alarm_enqueue_locked(alarm);
|
||||||
|
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* android_alarm_try_to_cancel - try to deactivate an alarm
|
||||||
|
* @alarm: alarm to stop
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 when the alarm was not active
|
||||||
|
* 1 when the alarm was active
|
||||||
|
* -1 when the alarm may currently be excuting the callback function and
|
||||||
|
* cannot be stopped (it may also be inactive)
|
||||||
|
*/
|
||||||
|
int android_alarm_try_to_cancel(struct android_alarm *alarm)
|
||||||
|
{
|
||||||
|
struct alarm_queue *base = &alarms[alarm->type];
|
||||||
|
unsigned long flags;
|
||||||
|
bool first = false;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&alarm_slock, flags);
|
||||||
|
if (!RB_EMPTY_NODE(&alarm->node)) {
|
||||||
|
pr_alarm(FLOW, "canceled alarm, type %d, func %pF at %lld\n",
|
||||||
|
alarm->type, alarm->function,
|
||||||
|
ktime_to_ns(alarm->expires));
|
||||||
|
ret = 1;
|
||||||
|
if (base->first == &alarm->node) {
|
||||||
|
base->first = rb_next(&alarm->node);
|
||||||
|
first = true;
|
||||||
|
}
|
||||||
|
rb_erase(&alarm->node, &base->alarms);
|
||||||
|
RB_CLEAR_NODE(&alarm->node);
|
||||||
|
if (first)
|
||||||
|
update_timer_locked(base, true);
|
||||||
|
} else
|
||||||
|
pr_alarm(FLOW, "tried to cancel alarm, type %d, func %pF\n",
|
||||||
|
alarm->type, alarm->function);
|
||||||
|
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||||
|
if (!ret && hrtimer_callback_running(&base->timer))
|
||||||
|
ret = -1;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* android_alarm_cancel - cancel an alarm and wait for the handler to finish.
|
||||||
|
* @alarm: the alarm to be cancelled
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 0 when the alarm was not active
|
||||||
|
* 1 when the alarm was active
|
||||||
|
*/
|
||||||
|
int android_alarm_cancel(struct android_alarm *alarm)
|
||||||
|
{
|
||||||
|
for (;;) {
|
||||||
|
int ret = android_alarm_try_to_cancel(alarm);
|
||||||
|
if (ret >= 0)
|
||||||
|
return ret;
|
||||||
|
cpu_relax();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* alarm_set_rtc - set the kernel and rtc walltime
|
||||||
|
* @new_time: timespec value containing the new time
|
||||||
|
*/
|
||||||
|
int android_alarm_set_rtc(struct timespec new_time)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
int ret;
|
||||||
|
unsigned long flags;
|
||||||
|
struct rtc_time rtc_new_rtc_time;
|
||||||
|
struct timespec tmp_time;
|
||||||
|
|
||||||
|
rtc_time_to_tm(new_time.tv_sec, &rtc_new_rtc_time);
|
||||||
|
|
||||||
|
pr_alarm(TSET, "set rtc %ld %ld - rtc %02d:%02d:%02d %02d/%02d/%04d\n",
|
||||||
|
new_time.tv_sec, new_time.tv_nsec,
|
||||||
|
rtc_new_rtc_time.tm_hour, rtc_new_rtc_time.tm_min,
|
||||||
|
rtc_new_rtc_time.tm_sec, rtc_new_rtc_time.tm_mon + 1,
|
||||||
|
rtc_new_rtc_time.tm_mday,
|
||||||
|
rtc_new_rtc_time.tm_year + 1900);
|
||||||
|
|
||||||
|
mutex_lock(&alarm_setrtc_mutex);
|
||||||
|
spin_lock_irqsave(&alarm_slock, flags);
|
||||||
|
wake_lock(&alarm_rtc_wake_lock);
|
||||||
|
getnstimeofday(&tmp_time);
|
||||||
|
for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
|
||||||
|
hrtimer_try_to_cancel(&alarms[i].timer);
|
||||||
|
alarms[i].stopped = true;
|
||||||
|
alarms[i].stopped_time = timespec_to_ktime(tmp_time);
|
||||||
|
}
|
||||||
|
alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta =
|
||||||
|
alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta =
|
||||||
|
ktime_sub(alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta,
|
||||||
|
timespec_to_ktime(timespec_sub(tmp_time, new_time)));
|
||||||
|
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||||
|
ret = do_settimeofday(&new_time);
|
||||||
|
spin_lock_irqsave(&alarm_slock, flags);
|
||||||
|
for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
|
||||||
|
alarms[i].stopped = false;
|
||||||
|
update_timer_locked(&alarms[i], false);
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||||
|
if (ret < 0) {
|
||||||
|
pr_alarm(ERROR, "alarm_set_rtc: Failed to set time\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
if (!alarm_rtc_dev) {
|
||||||
|
pr_alarm(ERROR,
|
||||||
|
"alarm_set_rtc: no RTC, time will be lost on reboot\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
ret = rtc_set_time(alarm_rtc_dev, &rtc_new_rtc_time);
|
||||||
|
if (ret < 0)
|
||||||
|
pr_alarm(ERROR, "alarm_set_rtc: "
|
||||||
|
"Failed to set RTC, time will be lost on reboot\n");
|
||||||
|
err:
|
||||||
|
wake_unlock(&alarm_rtc_wake_lock);
|
||||||
|
mutex_unlock(&alarm_setrtc_mutex);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* alarm_get_elapsed_realtime - get the elapsed real time in ktime_t format
|
||||||
|
*
|
||||||
|
* returns the time in ktime_t format
|
||||||
|
*/
|
||||||
|
ktime_t alarm_get_elapsed_realtime(void)
|
||||||
|
{
|
||||||
|
ktime_t now;
|
||||||
|
unsigned long flags;
|
||||||
|
struct alarm_queue *base = &alarms[ANDROID_ALARM_ELAPSED_REALTIME];
|
||||||
|
|
||||||
|
spin_lock_irqsave(&alarm_slock, flags);
|
||||||
|
now = base->stopped ? base->stopped_time : ktime_get_real();
|
||||||
|
now = ktime_sub(now, base->delta);
|
||||||
|
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||||
|
return now;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum hrtimer_restart alarm_timer_triggered(struct hrtimer *timer)
|
||||||
|
{
|
||||||
|
struct alarm_queue *base;
|
||||||
|
struct android_alarm *alarm;
|
||||||
|
unsigned long flags;
|
||||||
|
ktime_t now;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&alarm_slock, flags);
|
||||||
|
|
||||||
|
base = container_of(timer, struct alarm_queue, timer);
|
||||||
|
now = base->stopped ? base->stopped_time : hrtimer_cb_get_time(timer);
|
||||||
|
now = ktime_sub(now, base->delta);
|
||||||
|
|
||||||
|
pr_alarm(INT, "alarm_timer_triggered type %ld at %lld\n",
|
||||||
|
base - alarms, ktime_to_ns(now));
|
||||||
|
|
||||||
|
while (base->first) {
|
||||||
|
alarm = container_of(base->first, struct android_alarm, node);
|
||||||
|
if (alarm->softexpires.tv64 > now.tv64) {
|
||||||
|
pr_alarm(FLOW, "don't call alarm, %pF, %lld (s %lld)\n",
|
||||||
|
alarm->function, ktime_to_ns(alarm->expires),
|
||||||
|
ktime_to_ns(alarm->softexpires));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
base->first = rb_next(&alarm->node);
|
||||||
|
rb_erase(&alarm->node, &base->alarms);
|
||||||
|
RB_CLEAR_NODE(&alarm->node);
|
||||||
|
pr_alarm(CALL, "call alarm, type %d, func %pF, %lld (s %lld)\n",
|
||||||
|
alarm->type, alarm->function,
|
||||||
|
ktime_to_ns(alarm->expires),
|
||||||
|
ktime_to_ns(alarm->softexpires));
|
||||||
|
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||||
|
alarm->function(alarm);
|
||||||
|
spin_lock_irqsave(&alarm_slock, flags);
|
||||||
|
}
|
||||||
|
if (!base->first)
|
||||||
|
pr_alarm(FLOW, "no more alarms of type %ld\n", base - alarms);
|
||||||
|
update_timer_locked(base, true);
|
||||||
|
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||||
|
return HRTIMER_NORESTART;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void alarm_triggered_func(void *p)
|
||||||
|
{
|
||||||
|
struct rtc_device *rtc = alarm_rtc_dev;
|
||||||
|
if (!(rtc->irq_data & RTC_AF))
|
||||||
|
return;
|
||||||
|
pr_alarm(INT, "rtc alarm triggered\n");
|
||||||
|
wake_lock_timeout(&alarm_rtc_wake_lock, 1 * HZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int alarm_suspend(struct platform_device *pdev, pm_message_t state)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
unsigned long flags;
|
||||||
|
struct rtc_wkalrm rtc_alarm;
|
||||||
|
struct rtc_time rtc_current_rtc_time;
|
||||||
|
unsigned long rtc_current_time;
|
||||||
|
unsigned long rtc_alarm_time;
|
||||||
|
struct timespec rtc_delta;
|
||||||
|
struct timespec wall_time;
|
||||||
|
struct alarm_queue *wakeup_queue = NULL;
|
||||||
|
struct alarm_queue *tmp_queue = NULL;
|
||||||
|
|
||||||
|
pr_alarm(SUSPEND, "alarm_suspend(%p, %d)\n", pdev, state.event);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&alarm_slock, flags);
|
||||||
|
suspended = true;
|
||||||
|
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||||
|
|
||||||
|
hrtimer_cancel(&alarms[ANDROID_ALARM_RTC_WAKEUP].timer);
|
||||||
|
hrtimer_cancel(&alarms[
|
||||||
|
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].timer);
|
||||||
|
|
||||||
|
tmp_queue = &alarms[ANDROID_ALARM_RTC_WAKEUP];
|
||||||
|
if (tmp_queue->first)
|
||||||
|
wakeup_queue = tmp_queue;
|
||||||
|
tmp_queue = &alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP];
|
||||||
|
if (tmp_queue->first && (!wakeup_queue ||
|
||||||
|
hrtimer_get_expires(&tmp_queue->timer).tv64 <
|
||||||
|
hrtimer_get_expires(&wakeup_queue->timer).tv64))
|
||||||
|
wakeup_queue = tmp_queue;
|
||||||
|
if (wakeup_queue) {
|
||||||
|
rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time);
|
||||||
|
getnstimeofday(&wall_time);
|
||||||
|
rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time);
|
||||||
|
set_normalized_timespec(&rtc_delta,
|
||||||
|
wall_time.tv_sec - rtc_current_time,
|
||||||
|
wall_time.tv_nsec);
|
||||||
|
|
||||||
|
rtc_alarm_time = timespec_sub(ktime_to_timespec(
|
||||||
|
hrtimer_get_expires(&wakeup_queue->timer)),
|
||||||
|
rtc_delta).tv_sec;
|
||||||
|
|
||||||
|
rtc_time_to_tm(rtc_alarm_time, &rtc_alarm.time);
|
||||||
|
rtc_alarm.enabled = 1;
|
||||||
|
rtc_set_alarm(alarm_rtc_dev, &rtc_alarm);
|
||||||
|
rtc_read_time(alarm_rtc_dev, &rtc_current_rtc_time);
|
||||||
|
rtc_tm_to_time(&rtc_current_rtc_time, &rtc_current_time);
|
||||||
|
pr_alarm(SUSPEND,
|
||||||
|
"rtc alarm set at %ld, now %ld, rtc delta %ld.%09ld\n",
|
||||||
|
rtc_alarm_time, rtc_current_time,
|
||||||
|
rtc_delta.tv_sec, rtc_delta.tv_nsec);
|
||||||
|
if (rtc_current_time + 1 >= rtc_alarm_time) {
|
||||||
|
pr_alarm(SUSPEND, "alarm about to go off\n");
|
||||||
|
memset(&rtc_alarm, 0, sizeof(rtc_alarm));
|
||||||
|
rtc_alarm.enabled = 0;
|
||||||
|
rtc_set_alarm(alarm_rtc_dev, &rtc_alarm);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&alarm_slock, flags);
|
||||||
|
suspended = false;
|
||||||
|
wake_lock_timeout(&alarm_rtc_wake_lock, 2 * HZ);
|
||||||
|
update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP],
|
||||||
|
false);
|
||||||
|
update_timer_locked(&alarms[
|
||||||
|
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP], false);
|
||||||
|
err = -EBUSY;
|
||||||
|
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int alarm_resume(struct platform_device *pdev)
|
||||||
|
{
|
||||||
|
struct rtc_wkalrm alarm;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
pr_alarm(SUSPEND, "alarm_resume(%p)\n", pdev);
|
||||||
|
|
||||||
|
memset(&alarm, 0, sizeof(alarm));
|
||||||
|
alarm.enabled = 0;
|
||||||
|
rtc_set_alarm(alarm_rtc_dev, &alarm);
|
||||||
|
|
||||||
|
spin_lock_irqsave(&alarm_slock, flags);
|
||||||
|
suspended = false;
|
||||||
|
update_timer_locked(&alarms[ANDROID_ALARM_RTC_WAKEUP], false);
|
||||||
|
update_timer_locked(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP],
|
||||||
|
false);
|
||||||
|
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct rtc_task alarm_rtc_task = {
|
||||||
|
.func = alarm_triggered_func
|
||||||
|
};
|
||||||
|
|
||||||
|
static int rtc_alarm_add_device(struct device *dev,
|
||||||
|
struct class_interface *class_intf)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
struct rtc_device *rtc = to_rtc_device(dev);
|
||||||
|
|
||||||
|
mutex_lock(&alarm_setrtc_mutex);
|
||||||
|
|
||||||
|
if (alarm_rtc_dev) {
|
||||||
|
err = -EBUSY;
|
||||||
|
goto err1;
|
||||||
|
}
|
||||||
|
|
||||||
|
alarm_platform_dev =
|
||||||
|
platform_device_register_simple("alarm", -1, NULL, 0);
|
||||||
|
if (IS_ERR(alarm_platform_dev)) {
|
||||||
|
err = PTR_ERR(alarm_platform_dev);
|
||||||
|
goto err2;
|
||||||
|
}
|
||||||
|
err = rtc_irq_register(rtc, &alarm_rtc_task);
|
||||||
|
if (err)
|
||||||
|
goto err3;
|
||||||
|
alarm_rtc_dev = rtc;
|
||||||
|
pr_alarm(INIT_STATUS, "using rtc device, %s, for alarms", rtc->name);
|
||||||
|
mutex_unlock(&alarm_setrtc_mutex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err3:
|
||||||
|
platform_device_unregister(alarm_platform_dev);
|
||||||
|
err2:
|
||||||
|
err1:
|
||||||
|
mutex_unlock(&alarm_setrtc_mutex);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void rtc_alarm_remove_device(struct device *dev,
|
||||||
|
struct class_interface *class_intf)
|
||||||
|
{
|
||||||
|
if (dev == &alarm_rtc_dev->dev) {
|
||||||
|
pr_alarm(INIT_STATUS, "lost rtc device for alarms");
|
||||||
|
rtc_irq_unregister(alarm_rtc_dev, &alarm_rtc_task);
|
||||||
|
platform_device_unregister(alarm_platform_dev);
|
||||||
|
alarm_rtc_dev = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct class_interface rtc_alarm_interface = {
|
||||||
|
.add_dev = &rtc_alarm_add_device,
|
||||||
|
.remove_dev = &rtc_alarm_remove_device,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct platform_driver alarm_driver = {
|
||||||
|
.suspend = alarm_suspend,
|
||||||
|
.resume = alarm_resume,
|
||||||
|
.driver = {
|
||||||
|
.name = "alarm"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static int __init alarm_late_init(void)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
struct timespec tmp_time, system_time;
|
||||||
|
|
||||||
|
/* this needs to run after the rtc is read at boot */
|
||||||
|
spin_lock_irqsave(&alarm_slock, flags);
|
||||||
|
/* We read the current rtc and system time so we can later calulate
|
||||||
|
* elasped realtime to be (boot_systemtime + rtc - boot_rtc) ==
|
||||||
|
* (rtc - (boot_rtc - boot_systemtime))
|
||||||
|
*/
|
||||||
|
getnstimeofday(&tmp_time);
|
||||||
|
ktime_get_ts(&system_time);
|
||||||
|
alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].delta =
|
||||||
|
alarms[ANDROID_ALARM_ELAPSED_REALTIME].delta =
|
||||||
|
timespec_to_ktime(timespec_sub(tmp_time, system_time));
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&alarm_slock, flags);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init alarm_driver_init(void)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++) {
|
||||||
|
hrtimer_init(&alarms[i].timer,
|
||||||
|
CLOCK_REALTIME, HRTIMER_MODE_ABS);
|
||||||
|
alarms[i].timer.function = alarm_timer_triggered;
|
||||||
|
}
|
||||||
|
hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].timer,
|
||||||
|
CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
|
||||||
|
alarms[ANDROID_ALARM_SYSTEMTIME].timer.function = alarm_timer_triggered;
|
||||||
|
err = platform_driver_register(&alarm_driver);
|
||||||
|
if (err < 0)
|
||||||
|
goto err1;
|
||||||
|
wake_lock_init(&alarm_rtc_wake_lock, WAKE_LOCK_SUSPEND, "alarm_rtc");
|
||||||
|
rtc_alarm_interface.class = rtc_class;
|
||||||
|
err = class_interface_register(&rtc_alarm_interface);
|
||||||
|
if (err < 0)
|
||||||
|
goto err2;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err2:
|
||||||
|
wake_lock_destroy(&alarm_rtc_wake_lock);
|
||||||
|
platform_driver_unregister(&alarm_driver);
|
||||||
|
err1:
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __exit alarm_exit(void)
|
||||||
|
{
|
||||||
|
class_interface_unregister(&rtc_alarm_interface);
|
||||||
|
wake_lock_destroy(&alarm_rtc_wake_lock);
|
||||||
|
platform_driver_unregister(&alarm_driver);
|
||||||
|
}
|
||||||
|
|
||||||
|
late_initcall(alarm_late_init);
|
||||||
|
module_init(alarm_driver_init);
|
||||||
|
module_exit(alarm_exit);
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
/* include/linux/android_alarm.h
|
||||||
|
*
|
||||||
|
* Copyright (C) 2006-2007 Google, Inc.
|
||||||
|
*
|
||||||
|
* This software is licensed under the terms of the GNU General Public
|
||||||
|
* License version 2, as published by the Free Software Foundation, and
|
||||||
|
* may be copied, distributed, and modified under those terms.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _LINUX_ANDROID_ALARM_H
|
||||||
|
#define _LINUX_ANDROID_ALARM_H
|
||||||
|
|
||||||
|
#include <linux/ioctl.h>
|
||||||
|
#include <linux/time.h>
|
||||||
|
|
||||||
|
enum android_alarm_type {
|
||||||
|
/* return code bit numbers or set alarm arg */
|
||||||
|
ANDROID_ALARM_RTC_WAKEUP,
|
||||||
|
ANDROID_ALARM_RTC,
|
||||||
|
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
|
||||||
|
ANDROID_ALARM_ELAPSED_REALTIME,
|
||||||
|
ANDROID_ALARM_SYSTEMTIME,
|
||||||
|
|
||||||
|
ANDROID_ALARM_TYPE_COUNT,
|
||||||
|
|
||||||
|
/* return code bit numbers */
|
||||||
|
/* ANDROID_ALARM_TIME_CHANGE = 16 */
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
|
||||||
|
#include <linux/ktime.h>
|
||||||
|
#include <linux/rbtree.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The alarm interface is similar to the hrtimer interface but adds support
|
||||||
|
* for wakeup from suspend. It also adds an elapsed realtime clock that can
|
||||||
|
* be used for periodic timers that need to keep runing while the system is
|
||||||
|
* suspended and not be disrupted when the wall time is set.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct alarm - the basic alarm structure
|
||||||
|
* @node: red black tree node for time ordered insertion
|
||||||
|
* @type: alarm type. rtc/elapsed-realtime/systemtime, wakeup/non-wakeup.
|
||||||
|
* @softexpires: the absolute earliest expiry time of the alarm.
|
||||||
|
* @expires: the absolute expiry time.
|
||||||
|
* @function: alarm expiry callback function
|
||||||
|
*
|
||||||
|
* The alarm structure must be initialized by alarm_init()
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct android_alarm {
|
||||||
|
struct rb_node node;
|
||||||
|
enum android_alarm_type type;
|
||||||
|
ktime_t softexpires;
|
||||||
|
ktime_t expires;
|
||||||
|
void (*function)(struct android_alarm *);
|
||||||
|
};
|
||||||
|
|
||||||
|
void android_alarm_init(struct android_alarm *alarm,
|
||||||
|
enum android_alarm_type type, void (*function)(struct android_alarm *));
|
||||||
|
void android_alarm_start_range(struct android_alarm *alarm, ktime_t start,
|
||||||
|
ktime_t end);
|
||||||
|
int android_alarm_try_to_cancel(struct android_alarm *alarm);
|
||||||
|
int android_alarm_cancel(struct android_alarm *alarm);
|
||||||
|
ktime_t alarm_get_elapsed_realtime(void);
|
||||||
|
|
||||||
|
/* set rtc while preserving elapsed realtime */
|
||||||
|
int android_alarm_set_rtc(const struct timespec ts);
|
||||||
|
|
||||||
|
#ifdef CONFIG_ANDROID_ALARM_OLDDRV_COMPAT
|
||||||
|
/*
|
||||||
|
* Some older drivers depend on the old API,
|
||||||
|
* so provide compatability macros for now.
|
||||||
|
*/
|
||||||
|
#define alarm android_alarm
|
||||||
|
#define alarm_init(x, y, z) android_alarm_init(x, y, z)
|
||||||
|
#define alarm_start_range(x, y, z) android_alarm_start_range(x, y, z)
|
||||||
|
#define alarm_try_to_cancel(x) android_alarm_try_to_cancel(x)
|
||||||
|
#define alarm_cancel(x) android_alarm_cancel(x)
|
||||||
|
#define alarm_set_rtc(x) android_alarm_set_rtc(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum android_alarm_return_flags {
|
||||||
|
ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP,
|
||||||
|
ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC,
|
||||||
|
ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK =
|
||||||
|
1U << ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
|
||||||
|
ANDROID_ALARM_ELAPSED_REALTIME_MASK =
|
||||||
|
1U << ANDROID_ALARM_ELAPSED_REALTIME,
|
||||||
|
ANDROID_ALARM_SYSTEMTIME_MASK = 1U << ANDROID_ALARM_SYSTEMTIME,
|
||||||
|
ANDROID_ALARM_TIME_CHANGE_MASK = 1U << 16
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Disable alarm */
|
||||||
|
#define ANDROID_ALARM_CLEAR(type) _IO('a', 0 | ((type) << 4))
|
||||||
|
|
||||||
|
/* Ack last alarm and wait for next */
|
||||||
|
#define ANDROID_ALARM_WAIT _IO('a', 1)
|
||||||
|
|
||||||
|
#define ALARM_IOW(c, type, size) _IOW('a', (c) | ((type) << 4), size)
|
||||||
|
/* Set alarm */
|
||||||
|
#define ANDROID_ALARM_SET(type) ALARM_IOW(2, type, struct timespec)
|
||||||
|
#define ANDROID_ALARM_SET_AND_WAIT(type) ALARM_IOW(3, type, struct timespec)
|
||||||
|
#define ANDROID_ALARM_GET_TIME(type) ALARM_IOW(4, type, struct timespec)
|
||||||
|
#define ANDROID_ALARM_SET_RTC _IOW('a', 5, struct timespec)
|
||||||
|
#define ANDROID_ALARM_BASE_CMD(cmd) (cmd & ~(_IOC(0, 0, 0xf0, 0)))
|
||||||
|
#define ANDROID_ALARM_IOCTL_TO_TYPE(cmd) (_IOC_NR(cmd) >> 4)
|
||||||
|
|
||||||
|
#endif
|
|
@ -315,7 +315,7 @@ static int ashmem_mmap(struct file *file, struct vm_area_struct *vma)
|
||||||
get_file(asma->file);
|
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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
@ -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*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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 |
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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",
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 <<
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -0,0 +1,454 @@
|
||||||
|
/* Industrial I/O event handling
|
||||||
|
*
|
||||||
|
* Copyright (c) 2008 Jonathan Cameron
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 as published by
|
||||||
|
* the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* Based on elements of hwmon and input subsystems.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/anon_inodes.h>
|
||||||
|
#include <linux/device.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/kfifo.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/poll.h>
|
||||||
|
#include <linux/sched.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/uaccess.h>
|
||||||
|
#include <linux/wait.h>
|
||||||
|
#include "iio.h"
|
||||||
|
#include "iio_core.h"
|
||||||
|
#include "sysfs.h"
|
||||||
|
#include "events.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct iio_event_interface - chrdev interface for an event line
|
||||||
|
* @wait: wait queue to allow blocking reads of events
|
||||||
|
* @event_list_lock: mutex to protect the list of detected events
|
||||||
|
* @det_events: list of detected events
|
||||||
|
* @dev_attr_list: list of event interface sysfs attribute
|
||||||
|
* @flags: file operations related flags including busy flag.
|
||||||
|
* @group: event interface sysfs attribute group
|
||||||
|
*/
|
||||||
|
struct iio_event_interface {
|
||||||
|
wait_queue_head_t wait;
|
||||||
|
DECLARE_KFIFO(det_events, struct iio_event_data, 16);
|
||||||
|
|
||||||
|
struct list_head dev_attr_list;
|
||||||
|
unsigned long flags;
|
||||||
|
struct attribute_group group;
|
||||||
|
};
|
||||||
|
|
||||||
|
int iio_push_event(struct iio_dev *indio_dev, u64 ev_code, s64 timestamp)
|
||||||
|
{
|
||||||
|
struct iio_event_interface *ev_int = indio_dev->event_interface;
|
||||||
|
struct iio_event_data ev;
|
||||||
|
int copied;
|
||||||
|
|
||||||
|
/* Does anyone care? */
|
||||||
|
spin_lock(&ev_int->wait.lock);
|
||||||
|
if (test_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
|
||||||
|
|
||||||
|
ev.id = ev_code;
|
||||||
|
ev.timestamp = timestamp;
|
||||||
|
|
||||||
|
copied = kfifo_put(&ev_int->det_events, &ev);
|
||||||
|
if (copied != 0)
|
||||||
|
wake_up_locked_poll(&ev_int->wait, POLLIN);
|
||||||
|
}
|
||||||
|
spin_unlock(&ev_int->wait.lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(iio_push_event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* iio_event_poll() - poll the event queue to find out if it has data
|
||||||
|
*/
|
||||||
|
static unsigned int iio_event_poll(struct file *filep,
|
||||||
|
struct poll_table_struct *wait)
|
||||||
|
{
|
||||||
|
struct iio_event_interface *ev_int = filep->private_data;
|
||||||
|
unsigned int events = 0;
|
||||||
|
|
||||||
|
poll_wait(filep, &ev_int->wait, wait);
|
||||||
|
|
||||||
|
spin_lock(&ev_int->wait.lock);
|
||||||
|
if (!kfifo_is_empty(&ev_int->det_events))
|
||||||
|
events = POLLIN | POLLRDNORM;
|
||||||
|
spin_unlock(&ev_int->wait.lock);
|
||||||
|
|
||||||
|
return events;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t iio_event_chrdev_read(struct file *filep,
|
||||||
|
char __user *buf,
|
||||||
|
size_t count,
|
||||||
|
loff_t *f_ps)
|
||||||
|
{
|
||||||
|
struct iio_event_interface *ev_int = filep->private_data;
|
||||||
|
unsigned int copied;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (count < sizeof(struct iio_event_data))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
spin_lock(&ev_int->wait.lock);
|
||||||
|
if (kfifo_is_empty(&ev_int->det_events)) {
|
||||||
|
if (filep->f_flags & O_NONBLOCK) {
|
||||||
|
ret = -EAGAIN;
|
||||||
|
goto error_unlock;
|
||||||
|
}
|
||||||
|
/* Blocking on device; waiting for something to be there */
|
||||||
|
ret = wait_event_interruptible_locked(ev_int->wait,
|
||||||
|
!kfifo_is_empty(&ev_int->det_events));
|
||||||
|
if (ret)
|
||||||
|
goto error_unlock;
|
||||||
|
/* Single access device so no one else can get the data */
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = kfifo_to_user(&ev_int->det_events, buf, count, &copied);
|
||||||
|
|
||||||
|
error_unlock:
|
||||||
|
spin_unlock(&ev_int->wait.lock);
|
||||||
|
|
||||||
|
return ret ? ret : copied;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iio_event_chrdev_release(struct inode *inode, struct file *filep)
|
||||||
|
{
|
||||||
|
struct iio_event_interface *ev_int = filep->private_data;
|
||||||
|
|
||||||
|
spin_lock(&ev_int->wait.lock);
|
||||||
|
__clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
|
||||||
|
/*
|
||||||
|
* In order to maintain a clean state for reopening,
|
||||||
|
* clear out any awaiting events. The mask will prevent
|
||||||
|
* any new __iio_push_event calls running.
|
||||||
|
*/
|
||||||
|
kfifo_reset_out(&ev_int->det_events);
|
||||||
|
spin_unlock(&ev_int->wait.lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations iio_event_chrdev_fileops = {
|
||||||
|
.read = iio_event_chrdev_read,
|
||||||
|
.poll = iio_event_poll,
|
||||||
|
.release = iio_event_chrdev_release,
|
||||||
|
.owner = THIS_MODULE,
|
||||||
|
.llseek = noop_llseek,
|
||||||
|
};
|
||||||
|
|
||||||
|
int iio_event_getfd(struct iio_dev *indio_dev)
|
||||||
|
{
|
||||||
|
struct iio_event_interface *ev_int = indio_dev->event_interface;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if (ev_int == NULL)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
spin_lock(&ev_int->wait.lock);
|
||||||
|
if (__test_and_set_bit(IIO_BUSY_BIT_POS, &ev_int->flags)) {
|
||||||
|
spin_unlock(&ev_int->wait.lock);
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
spin_unlock(&ev_int->wait.lock);
|
||||||
|
fd = anon_inode_getfd("iio:event",
|
||||||
|
&iio_event_chrdev_fileops, ev_int, O_RDONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
spin_lock(&ev_int->wait.lock);
|
||||||
|
__clear_bit(IIO_BUSY_BIT_POS, &ev_int->flags);
|
||||||
|
spin_unlock(&ev_int->wait.lock);
|
||||||
|
}
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char * const iio_ev_type_text[] = {
|
||||||
|
[IIO_EV_TYPE_THRESH] = "thresh",
|
||||||
|
[IIO_EV_TYPE_MAG] = "mag",
|
||||||
|
[IIO_EV_TYPE_ROC] = "roc",
|
||||||
|
[IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive",
|
||||||
|
[IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char * const iio_ev_dir_text[] = {
|
||||||
|
[IIO_EV_DIR_EITHER] = "either",
|
||||||
|
[IIO_EV_DIR_RISING] = "rising",
|
||||||
|
[IIO_EV_DIR_FALLING] = "falling"
|
||||||
|
};
|
||||||
|
|
||||||
|
static ssize_t iio_ev_state_store(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||||
|
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||||
|
int ret;
|
||||||
|
bool val;
|
||||||
|
|
||||||
|
ret = strtobool(buf, &val);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = indio_dev->info->write_event_config(indio_dev,
|
||||||
|
this_attr->address,
|
||||||
|
val);
|
||||||
|
return (ret < 0) ? ret : len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t iio_ev_state_show(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||||
|
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||||
|
int val = indio_dev->info->read_event_config(indio_dev,
|
||||||
|
this_attr->address);
|
||||||
|
|
||||||
|
if (val < 0)
|
||||||
|
return val;
|
||||||
|
else
|
||||||
|
return sprintf(buf, "%d\n", val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t iio_ev_value_show(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
char *buf)
|
||||||
|
{
|
||||||
|
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||||
|
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||||
|
int val, ret;
|
||||||
|
|
||||||
|
ret = indio_dev->info->read_event_value(indio_dev,
|
||||||
|
this_attr->address, &val);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return sprintf(buf, "%d\n", val);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t iio_ev_value_store(struct device *dev,
|
||||||
|
struct device_attribute *attr,
|
||||||
|
const char *buf,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
struct iio_dev *indio_dev = dev_get_drvdata(dev);
|
||||||
|
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
||||||
|
unsigned long val;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!indio_dev->info->write_event_value)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
ret = strict_strtoul(buf, 10, &val);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
ret = indio_dev->info->write_event_value(indio_dev, this_attr->address,
|
||||||
|
val);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int iio_device_add_event_sysfs(struct iio_dev *indio_dev,
|
||||||
|
struct iio_chan_spec const *chan)
|
||||||
|
{
|
||||||
|
int ret = 0, i, attrcount = 0;
|
||||||
|
u64 mask = 0;
|
||||||
|
char *postfix;
|
||||||
|
if (!chan->event_mask)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
for_each_set_bit(i, &chan->event_mask, sizeof(chan->event_mask)*8) {
|
||||||
|
postfix = kasprintf(GFP_KERNEL, "%s_%s_en",
|
||||||
|
iio_ev_type_text[i/IIO_EV_DIR_MAX],
|
||||||
|
iio_ev_dir_text[i%IIO_EV_DIR_MAX]);
|
||||||
|
if (postfix == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto error_ret;
|
||||||
|
}
|
||||||
|
if (chan->modified)
|
||||||
|
mask = IIO_MOD_EVENT_CODE(chan->type, 0, chan->channel,
|
||||||
|
i/IIO_EV_DIR_MAX,
|
||||||
|
i%IIO_EV_DIR_MAX);
|
||||||
|
else if (chan->differential)
|
||||||
|
mask = IIO_EVENT_CODE(chan->type,
|
||||||
|
0, 0,
|
||||||
|
i%IIO_EV_DIR_MAX,
|
||||||
|
i/IIO_EV_DIR_MAX,
|
||||||
|
0,
|
||||||
|
chan->channel,
|
||||||
|
chan->channel2);
|
||||||
|
else
|
||||||
|
mask = IIO_UNMOD_EVENT_CODE(chan->type,
|
||||||
|
chan->channel,
|
||||||
|
i/IIO_EV_DIR_MAX,
|
||||||
|
i%IIO_EV_DIR_MAX);
|
||||||
|
|
||||||
|
ret = __iio_add_chan_devattr(postfix,
|
||||||
|
chan,
|
||||||
|
&iio_ev_state_show,
|
||||||
|
iio_ev_state_store,
|
||||||
|
mask,
|
||||||
|
0,
|
||||||
|
&indio_dev->dev,
|
||||||
|
&indio_dev->event_interface->
|
||||||
|
dev_attr_list);
|
||||||
|
kfree(postfix);
|
||||||
|
if (ret)
|
||||||
|
goto error_ret;
|
||||||
|
attrcount++;
|
||||||
|
postfix = kasprintf(GFP_KERNEL, "%s_%s_value",
|
||||||
|
iio_ev_type_text[i/IIO_EV_DIR_MAX],
|
||||||
|
iio_ev_dir_text[i%IIO_EV_DIR_MAX]);
|
||||||
|
if (postfix == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto error_ret;
|
||||||
|
}
|
||||||
|
ret = __iio_add_chan_devattr(postfix, chan,
|
||||||
|
iio_ev_value_show,
|
||||||
|
iio_ev_value_store,
|
||||||
|
mask,
|
||||||
|
0,
|
||||||
|
&indio_dev->dev,
|
||||||
|
&indio_dev->event_interface->
|
||||||
|
dev_attr_list);
|
||||||
|
kfree(postfix);
|
||||||
|
if (ret)
|
||||||
|
goto error_ret;
|
||||||
|
attrcount++;
|
||||||
|
}
|
||||||
|
ret = attrcount;
|
||||||
|
error_ret:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void __iio_remove_event_config_attrs(struct iio_dev *indio_dev)
|
||||||
|
{
|
||||||
|
struct iio_dev_attr *p, *n;
|
||||||
|
list_for_each_entry_safe(p, n,
|
||||||
|
&indio_dev->event_interface->
|
||||||
|
dev_attr_list, l) {
|
||||||
|
kfree(p->dev_attr.attr.name);
|
||||||
|
kfree(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int __iio_add_event_config_attrs(struct iio_dev *indio_dev)
|
||||||
|
{
|
||||||
|
int j, ret, attrcount = 0;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&indio_dev->event_interface->dev_attr_list);
|
||||||
|
/* Dynically created from the channels array */
|
||||||
|
for (j = 0; j < indio_dev->num_channels; j++) {
|
||||||
|
ret = iio_device_add_event_sysfs(indio_dev,
|
||||||
|
&indio_dev->channels[j]);
|
||||||
|
if (ret < 0)
|
||||||
|
goto error_clear_attrs;
|
||||||
|
attrcount += ret;
|
||||||
|
}
|
||||||
|
return attrcount;
|
||||||
|
|
||||||
|
error_clear_attrs:
|
||||||
|
__iio_remove_event_config_attrs(indio_dev);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool iio_check_for_dynamic_events(struct iio_dev *indio_dev)
|
||||||
|
{
|
||||||
|
int j;
|
||||||
|
|
||||||
|
for (j = 0; j < indio_dev->num_channels; j++)
|
||||||
|
if (indio_dev->channels[j].event_mask != 0)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void iio_setup_ev_int(struct iio_event_interface *ev_int)
|
||||||
|
{
|
||||||
|
INIT_KFIFO(ev_int->det_events);
|
||||||
|
init_waitqueue_head(&ev_int->wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char *iio_event_group_name = "events";
|
||||||
|
int iio_device_register_eventset(struct iio_dev *indio_dev)
|
||||||
|
{
|
||||||
|
struct iio_dev_attr *p;
|
||||||
|
int ret = 0, attrcount_orig = 0, attrcount, attrn;
|
||||||
|
struct attribute **attr;
|
||||||
|
|
||||||
|
if (!(indio_dev->info->event_attrs ||
|
||||||
|
iio_check_for_dynamic_events(indio_dev)))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
indio_dev->event_interface =
|
||||||
|
kzalloc(sizeof(struct iio_event_interface), GFP_KERNEL);
|
||||||
|
if (indio_dev->event_interface == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto error_ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
iio_setup_ev_int(indio_dev->event_interface);
|
||||||
|
if (indio_dev->info->event_attrs != NULL) {
|
||||||
|
attr = indio_dev->info->event_attrs->attrs;
|
||||||
|
while (*attr++ != NULL)
|
||||||
|
attrcount_orig++;
|
||||||
|
}
|
||||||
|
attrcount = attrcount_orig;
|
||||||
|
if (indio_dev->channels) {
|
||||||
|
ret = __iio_add_event_config_attrs(indio_dev);
|
||||||
|
if (ret < 0)
|
||||||
|
goto error_free_setup_event_lines;
|
||||||
|
attrcount += ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
indio_dev->event_interface->group.name = iio_event_group_name;
|
||||||
|
indio_dev->event_interface->group.attrs = kcalloc(attrcount + 1,
|
||||||
|
sizeof(indio_dev->event_interface->group.attrs[0]),
|
||||||
|
GFP_KERNEL);
|
||||||
|
if (indio_dev->event_interface->group.attrs == NULL) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto error_free_setup_event_lines;
|
||||||
|
}
|
||||||
|
if (indio_dev->info->event_attrs)
|
||||||
|
memcpy(indio_dev->event_interface->group.attrs,
|
||||||
|
indio_dev->info->event_attrs->attrs,
|
||||||
|
sizeof(indio_dev->event_interface->group.attrs[0])
|
||||||
|
*attrcount_orig);
|
||||||
|
attrn = attrcount_orig;
|
||||||
|
/* Add all elements from the list. */
|
||||||
|
list_for_each_entry(p,
|
||||||
|
&indio_dev->event_interface->dev_attr_list,
|
||||||
|
l)
|
||||||
|
indio_dev->event_interface->group.attrs[attrn++] =
|
||||||
|
&p->dev_attr.attr;
|
||||||
|
indio_dev->groups[indio_dev->groupcounter++] =
|
||||||
|
&indio_dev->event_interface->group;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error_free_setup_event_lines:
|
||||||
|
__iio_remove_event_config_attrs(indio_dev);
|
||||||
|
kfree(indio_dev->event_interface);
|
||||||
|
error_ret:
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
void iio_device_unregister_eventset(struct iio_dev *indio_dev)
|
||||||
|
{
|
||||||
|
if (indio_dev->event_interface == NULL)
|
||||||
|
return;
|
||||||
|
__iio_remove_event_config_attrs(indio_dev);
|
||||||
|
kfree(indio_dev->event_interface->group.attrs);
|
||||||
|
kfree(indio_dev->event_interface);
|
||||||
|
}
|
|
@ -59,21 +59,6 @@ static struct attribute_group iio_kfifo_attribute_group = {
|
||||||
.name = "buffer",
|
.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");
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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_ */
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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, ®, buffer_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
dev->host_hw_state |= H_IG;
|
dev->host_hw_state |= H_IG;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -0,0 +1,479 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* Intel Management Engine Interface (Intel MEI) Linux driver
|
||||||
|
* Intel MEI Interface Header
|
||||||
|
*
|
||||||
|
* This file is provided under a dual BSD/GPLv2 license. When using or
|
||||||
|
* redistributing this file, you may do so under either license.
|
||||||
|
*
|
||||||
|
* GPL LICENSE SUMMARY
|
||||||
|
*
|
||||||
|
* Copyright(c) 2012 Intel Corporation. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of version 2 of the GNU General Public License as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but
|
||||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
|
||||||
|
* USA
|
||||||
|
*
|
||||||
|
* The full GNU General Public License is included in this distribution
|
||||||
|
* in the file called LICENSE.GPL.
|
||||||
|
*
|
||||||
|
* Contact Information:
|
||||||
|
* Intel Corporation.
|
||||||
|
* linux-mei@linux.intel.com
|
||||||
|
* http://www.intel.com
|
||||||
|
*
|
||||||
|
* BSD LICENSE
|
||||||
|
*
|
||||||
|
* Copyright(c) 2003 - 2012 Intel Corporation. All rights reserved.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
* * Neither the name Intel Corporation nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||||
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <bits/wordsize.h>
|
||||||
|
#include "mei.h"
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Intel Management Enginin Interface
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#define mei_msg(_me, fmt, ARGS...) do { \
|
||||||
|
if (_me->verbose) \
|
||||||
|
fprintf(stderr, fmt, ##ARGS); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define mei_err(_me, fmt, ARGS...) do { \
|
||||||
|
fprintf(stderr, "Error: " fmt, ##ARGS); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
struct mei {
|
||||||
|
uuid_le guid;
|
||||||
|
bool initialized;
|
||||||
|
bool verbose;
|
||||||
|
unsigned int buf_size;
|
||||||
|
unsigned char prot_ver;
|
||||||
|
int fd;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void mei_deinit(struct mei *cl)
|
||||||
|
{
|
||||||
|
if (cl->fd != -1)
|
||||||
|
close(cl->fd);
|
||||||
|
cl->fd = -1;
|
||||||
|
cl->buf_size = 0;
|
||||||
|
cl->prot_ver = 0;
|
||||||
|
cl->initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool mei_init(struct mei *me, const uuid_le *guid,
|
||||||
|
unsigned char req_protocol_version, bool verbose)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
struct mei_client *cl;
|
||||||
|
struct mei_connect_client_data data;
|
||||||
|
|
||||||
|
mei_deinit(me);
|
||||||
|
|
||||||
|
me->verbose = verbose;
|
||||||
|
|
||||||
|
me->fd = open("/dev/mei", O_RDWR);
|
||||||
|
if (me->fd == -1) {
|
||||||
|
mei_err(me, "Cannot establish a handle to the Intel MEI driver\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
memcpy(&me->guid, guid, sizeof(*guid));
|
||||||
|
memset(&data, 0, sizeof(data));
|
||||||
|
me->initialized = true;
|
||||||
|
|
||||||
|
memcpy(&data.in_client_uuid, &me->guid, sizeof(me->guid));
|
||||||
|
result = ioctl(me->fd, IOCTL_MEI_CONNECT_CLIENT, &data);
|
||||||
|
if (result) {
|
||||||
|
mei_err(me, "IOCTL_MEI_CONNECT_CLIENT receive message. err=%d\n", result);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
cl = &data.out_client_properties;
|
||||||
|
mei_msg(me, "max_message_length %d\n", cl->max_msg_length);
|
||||||
|
mei_msg(me, "protocol_version %d\n", cl->protocol_version);
|
||||||
|
|
||||||
|
if ((req_protocol_version > 0) &&
|
||||||
|
(cl->protocol_version != req_protocol_version)) {
|
||||||
|
mei_err(me, "Intel MEI protocol version not supported\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
me->buf_size = cl->max_msg_length;
|
||||||
|
me->prot_ver = cl->protocol_version;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
err:
|
||||||
|
mei_deinit(me);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t mei_recv_msg(struct mei *me, unsigned char *buffer,
|
||||||
|
ssize_t len, unsigned long timeout)
|
||||||
|
{
|
||||||
|
ssize_t rc;
|
||||||
|
|
||||||
|
mei_msg(me, "call read length = %zd\n", len);
|
||||||
|
|
||||||
|
rc = read(me->fd, buffer, len);
|
||||||
|
if (rc < 0) {
|
||||||
|
mei_err(me, "read failed with status %zd %s\n",
|
||||||
|
rc, strerror(errno));
|
||||||
|
mei_deinit(me);
|
||||||
|
} else {
|
||||||
|
mei_msg(me, "read succeeded with result %zd\n", rc);
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t mei_send_msg(struct mei *me, const unsigned char *buffer,
|
||||||
|
ssize_t len, unsigned long timeout)
|
||||||
|
{
|
||||||
|
struct timeval tv;
|
||||||
|
ssize_t written;
|
||||||
|
ssize_t rc;
|
||||||
|
fd_set set;
|
||||||
|
|
||||||
|
tv.tv_sec = timeout / 1000;
|
||||||
|
tv.tv_usec = (timeout % 1000) * 1000000;
|
||||||
|
|
||||||
|
mei_msg(me, "call write length = %zd\n", len);
|
||||||
|
|
||||||
|
written = write(me->fd, buffer, len);
|
||||||
|
if (written < 0) {
|
||||||
|
rc = -errno;
|
||||||
|
mei_err(me, "write failed with status %zd %s\n",
|
||||||
|
written, strerror(errno));
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
FD_ZERO(&set);
|
||||||
|
FD_SET(me->fd, &set);
|
||||||
|
rc = select(me->fd + 1 , &set, NULL, NULL, &tv);
|
||||||
|
if (rc > 0 && FD_ISSET(me->fd, &set)) {
|
||||||
|
mei_msg(me, "write success\n");
|
||||||
|
} else if (rc == 0) {
|
||||||
|
mei_err(me, "write failed on timeout with status\n");
|
||||||
|
goto out;
|
||||||
|
} else { /* rc < 0 */
|
||||||
|
mei_err(me, "write failed on select with status %zd\n", rc);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = written;
|
||||||
|
out:
|
||||||
|
if (rc < 0)
|
||||||
|
mei_deinit(me);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* Intel Advanced Management Technolgy ME Client
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#define AMT_MAJOR_VERSION 1
|
||||||
|
#define AMT_MINOR_VERSION 1
|
||||||
|
|
||||||
|
#define AMT_STATUS_SUCCESS 0x0
|
||||||
|
#define AMT_STATUS_INTERNAL_ERROR 0x1
|
||||||
|
#define AMT_STATUS_NOT_READY 0x2
|
||||||
|
#define AMT_STATUS_INVALID_AMT_MODE 0x3
|
||||||
|
#define AMT_STATUS_INVALID_MESSAGE_LENGTH 0x4
|
||||||
|
|
||||||
|
#define AMT_STATUS_HOST_IF_EMPTY_RESPONSE 0x4000
|
||||||
|
#define AMT_STATUS_SDK_RESOURCES 0x1004
|
||||||
|
|
||||||
|
|
||||||
|
#define AMT_BIOS_VERSION_LEN 65
|
||||||
|
#define AMT_VERSIONS_NUMBER 50
|
||||||
|
#define AMT_UNICODE_STRING_LEN 20
|
||||||
|
|
||||||
|
struct amt_unicode_string {
|
||||||
|
uint16_t length;
|
||||||
|
char string[AMT_UNICODE_STRING_LEN];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct amt_version_type {
|
||||||
|
struct amt_unicode_string description;
|
||||||
|
struct amt_unicode_string version;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct amt_version {
|
||||||
|
uint8_t major;
|
||||||
|
uint8_t minor;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct amt_code_versions {
|
||||||
|
uint8_t bios[AMT_BIOS_VERSION_LEN];
|
||||||
|
uint32_t count;
|
||||||
|
struct amt_version_type versions[AMT_VERSIONS_NUMBER];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* Intel Advanced Management Technolgy Host Interface
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
struct amt_host_if_msg_header {
|
||||||
|
struct amt_version version;
|
||||||
|
uint16_t _reserved;
|
||||||
|
uint32_t command;
|
||||||
|
uint32_t length;
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
struct amt_host_if_resp_header {
|
||||||
|
struct amt_host_if_msg_header header;
|
||||||
|
uint32_t status;
|
||||||
|
unsigned char data[0];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
const uuid_le MEI_IAMTHIF = UUID_LE(0x12f80028, 0xb4b7, 0x4b2d, \
|
||||||
|
0xac, 0xa8, 0x46, 0xe0, 0xff, 0x65, 0x81, 0x4c);
|
||||||
|
|
||||||
|
#define AMT_HOST_IF_CODE_VERSIONS_REQUEST 0x0400001A
|
||||||
|
#define AMT_HOST_IF_CODE_VERSIONS_RESPONSE 0x0480001A
|
||||||
|
|
||||||
|
const struct amt_host_if_msg_header CODE_VERSION_REQ = {
|
||||||
|
.version = {AMT_MAJOR_VERSION, AMT_MINOR_VERSION},
|
||||||
|
._reserved = 0,
|
||||||
|
.command = AMT_HOST_IF_CODE_VERSIONS_REQUEST,
|
||||||
|
.length = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct amt_host_if {
|
||||||
|
struct mei mei_cl;
|
||||||
|
unsigned long send_timeout;
|
||||||
|
bool initialized;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
bool amt_host_if_init(struct amt_host_if *acmd,
|
||||||
|
unsigned long send_timeout, bool verbose)
|
||||||
|
{
|
||||||
|
acmd->send_timeout = (send_timeout) ? send_timeout : 20000;
|
||||||
|
acmd->initialized = mei_init(&acmd->mei_cl, &MEI_IAMTHIF, 0, verbose);
|
||||||
|
return acmd->initialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
void amt_host_if_deinit(struct amt_host_if *acmd)
|
||||||
|
{
|
||||||
|
mei_deinit(&acmd->mei_cl);
|
||||||
|
acmd->initialized = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t amt_verify_code_versions(const struct amt_host_if_resp_header *resp)
|
||||||
|
{
|
||||||
|
uint32_t status = AMT_STATUS_SUCCESS;
|
||||||
|
struct amt_code_versions *code_ver;
|
||||||
|
size_t code_ver_len;
|
||||||
|
uint32_t ver_type_cnt;
|
||||||
|
uint32_t len;
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
code_ver = (struct amt_code_versions *)resp->data;
|
||||||
|
/* length - sizeof(status) */
|
||||||
|
code_ver_len = resp->header.length - sizeof(uint32_t);
|
||||||
|
ver_type_cnt = code_ver_len -
|
||||||
|
sizeof(code_ver->bios) -
|
||||||
|
sizeof(code_ver->count);
|
||||||
|
if (code_ver->count != ver_type_cnt / sizeof(struct amt_version_type)) {
|
||||||
|
status = AMT_STATUS_INTERNAL_ERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < code_ver->count; i++) {
|
||||||
|
len = code_ver->versions[i].description.length;
|
||||||
|
|
||||||
|
if (len > AMT_UNICODE_STRING_LEN) {
|
||||||
|
status = AMT_STATUS_INTERNAL_ERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = code_ver->versions[i].version.length;
|
||||||
|
if (code_ver->versions[i].version.string[len] != '\0' ||
|
||||||
|
len != strlen(code_ver->versions[i].version.string)) {
|
||||||
|
status = AMT_STATUS_INTERNAL_ERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t amt_verify_response_header(uint32_t command,
|
||||||
|
const struct amt_host_if_msg_header *resp_hdr,
|
||||||
|
uint32_t response_size)
|
||||||
|
{
|
||||||
|
if (response_size < sizeof(struct amt_host_if_resp_header)) {
|
||||||
|
return AMT_STATUS_INTERNAL_ERROR;
|
||||||
|
} else if (response_size != (resp_hdr->length +
|
||||||
|
sizeof(struct amt_host_if_msg_header))) {
|
||||||
|
return AMT_STATUS_INTERNAL_ERROR;
|
||||||
|
} else if (resp_hdr->command != command) {
|
||||||
|
return AMT_STATUS_INTERNAL_ERROR;
|
||||||
|
} else if (resp_hdr->_reserved != 0) {
|
||||||
|
return AMT_STATUS_INTERNAL_ERROR;
|
||||||
|
} else if (resp_hdr->version.major != AMT_MAJOR_VERSION ||
|
||||||
|
resp_hdr->version.minor < AMT_MINOR_VERSION) {
|
||||||
|
return AMT_STATUS_INTERNAL_ERROR;
|
||||||
|
}
|
||||||
|
return AMT_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t amt_host_if_call(struct amt_host_if *acmd,
|
||||||
|
const unsigned char *command, ssize_t command_sz,
|
||||||
|
uint8_t **read_buf, uint32_t rcmd,
|
||||||
|
unsigned int expected_sz)
|
||||||
|
{
|
||||||
|
uint32_t in_buf_sz;
|
||||||
|
uint32_t out_buf_sz;
|
||||||
|
ssize_t written;
|
||||||
|
uint32_t status;
|
||||||
|
struct amt_host_if_resp_header *msg_hdr;
|
||||||
|
|
||||||
|
in_buf_sz = acmd->mei_cl.buf_size;
|
||||||
|
*read_buf = (uint8_t *)malloc(sizeof(uint8_t) * in_buf_sz);
|
||||||
|
if (*read_buf == NULL)
|
||||||
|
return AMT_STATUS_SDK_RESOURCES;
|
||||||
|
memset(*read_buf, 0, in_buf_sz);
|
||||||
|
msg_hdr = (struct amt_host_if_resp_header *)*read_buf;
|
||||||
|
|
||||||
|
written = mei_send_msg(&acmd->mei_cl,
|
||||||
|
command, command_sz, acmd->send_timeout);
|
||||||
|
if (written != command_sz)
|
||||||
|
return AMT_STATUS_INTERNAL_ERROR;
|
||||||
|
|
||||||
|
out_buf_sz = mei_recv_msg(&acmd->mei_cl, *read_buf, in_buf_sz, 2000);
|
||||||
|
if (out_buf_sz <= 0)
|
||||||
|
return AMT_STATUS_HOST_IF_EMPTY_RESPONSE;
|
||||||
|
|
||||||
|
status = msg_hdr->status;
|
||||||
|
if (status != AMT_STATUS_SUCCESS)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
status = amt_verify_response_header(rcmd,
|
||||||
|
&msg_hdr->header, out_buf_sz);
|
||||||
|
if (status != AMT_STATUS_SUCCESS)
|
||||||
|
return status;
|
||||||
|
|
||||||
|
if (expected_sz && expected_sz != out_buf_sz)
|
||||||
|
return AMT_STATUS_INTERNAL_ERROR;
|
||||||
|
|
||||||
|
return AMT_STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t amt_get_code_versions(struct amt_host_if *cmd,
|
||||||
|
struct amt_code_versions *versions)
|
||||||
|
{
|
||||||
|
struct amt_host_if_resp_header *response = NULL;
|
||||||
|
uint32_t status;
|
||||||
|
|
||||||
|
status = amt_host_if_call(cmd,
|
||||||
|
(const unsigned char *)&CODE_VERSION_REQ,
|
||||||
|
sizeof(CODE_VERSION_REQ),
|
||||||
|
(uint8_t **)&response,
|
||||||
|
AMT_HOST_IF_CODE_VERSIONS_RESPONSE, 0);
|
||||||
|
|
||||||
|
if (status != AMT_STATUS_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
status = amt_verify_code_versions(response);
|
||||||
|
if (status != AMT_STATUS_SUCCESS)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
memcpy(versions, response->data, sizeof(struct amt_code_versions));
|
||||||
|
out:
|
||||||
|
if (response != NULL)
|
||||||
|
free(response);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************** end of amt_host_if_command ***********************/
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
struct amt_code_versions ver;
|
||||||
|
struct amt_host_if acmd;
|
||||||
|
unsigned int i;
|
||||||
|
uint32_t status;
|
||||||
|
int ret;
|
||||||
|
bool verbose;
|
||||||
|
|
||||||
|
verbose = (argc > 1 && strcmp(argv[1], "-v") == 0);
|
||||||
|
|
||||||
|
if (!amt_host_if_init(&acmd, 5000, verbose)) {
|
||||||
|
ret = 1;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = amt_get_code_versions(&acmd, &ver);
|
||||||
|
|
||||||
|
switch (status) {
|
||||||
|
case AMT_STATUS_HOST_IF_EMPTY_RESPONSE:
|
||||||
|
printf("Intel AMT: DISABLED\n");
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
case AMT_STATUS_SUCCESS:
|
||||||
|
printf("Intel AMT: ENABLED\n");
|
||||||
|
for (i = 0; i < ver.count; i++) {
|
||||||
|
printf("%s:\t%s\n", ver.versions[i].description.string,
|
||||||
|
ver.versions[i].version.string);
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("An error has occurred\n");
|
||||||
|
ret = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -1,63 +1,68 @@
|
||||||
/*
|
/******************************************************************************
|
||||||
|
* Intel Management Engine Interface (Intel MEI) Linux driver
|
||||||
Intel 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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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 *
|
||||||
|
|
|
@ -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
Loading…
Reference in New Issue