RTC 层次结构
来源:互联网 发布:淘宝空中充值店怎么开 编辑:程序博客网 时间:2024/05/28 05:18
alarm.c rtc-dev.c
| /
| /
|/
interface.c
|
|
rtc-m41t80.c
rtc-m41t80.c
static struct rtc_class_ops m41t80_rtc_ops = {
.read_time = m41t80_rtc_read_time,
.set_time = m41t80_rtc_set_time,
.read_alarm = m41t80_rtc_read_alarm,
.set_alarm = m41t80_rtc_set_alarm,
.proc = m41t80_rtc_proc,
.ioctl = m41t80_rtc_ioctl,
};
static int m41t80_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
rtc = rtc_device_register(client->name, &client->dev,
&m41t80_rtc_ops, THIS_MODULE);
rc = m41t80_sysfs_register(&client->dev);
}
static struct i2c_driver m41t80_driver = {
.driver = {
.name = "rtc-m41t80",
},
.probe = m41t80_probe,
.remove = m41t80_remove,
.id_table = m41t80_id,
};
static int __init m41t80_rtc_init(void)
{
return i2c_add_driver(&m41t80_driver);
}
/rtc/class.c
struct rtc_device *rtc_device_register(const char *name, struct device *dev,
const struct rtc_class_ops *ops,
struct module *owner)
{
strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
dev_set_name(&rtc->dev, "rtc%d", id);
rtc_dev_prepare(rtc);
err = device_register(&rtc->dev);
if (err)
goto exit_kfree;
rtc_dev_add_device(rtc);
rtc_sysfs_add_device(rtc);
rtc_proc_add_device(rtc);
}
rtc-dev.c
static const struct file_operations rtc_dev_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.read = rtc_dev_read,
.poll = rtc_dev_poll,
.unlocked_ioctl = rtc_dev_ioctl,
.open = rtc_dev_open,
.release = rtc_dev_release,
.fasync = rtc_dev_fasync,
};
rtc/interface.c
#include <linux/rtc.h>
#include <linux/log2.h>
int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
{
int err;
memset(tm, 0, sizeof(struct rtc_time));
err = rtc->ops->read_time(rtc->dev.parent, tm);
return err;
}
EXPORT_SYMBOL_GPL(rtc_read_time);
int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
{
int err;
if (!rtc->ops)
err = -ENODEV;
else if (rtc->ops->set_time)
err = rtc->ops->set_time(rtc->dev.parent, tm);
else if (rtc->ops->set_mmss) {
unsigned long secs;
err = rtc_tm_to_time(tm, &secs);
if (err == 0)
err = rtc->ops->set_mmss(rtc->dev.parent, secs);
} else
err = -EINVAL;
mutex_unlock(&rtc->ops_lock);
return err;
}
EXPORT_SYMBOL_GPL(rtc_set_time);
int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs)
{
int err;
rtc_time_to_tm(secs, &new);
return err;
}
EXPORT_SYMBOL_GPL(rtc_set_mmss);
static int rtc_read_alarm_internal(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
{
int err;
err = rtc->ops->read_alarm(rtc->dev.parent, alarm);
return err;
}
int rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
{
int err;
struct rtc_time before, now;
int first_time = 1;
unsigned long t_now, t_alm;
enum { none, day, month, year } missing = none;
unsigned days;
/* Get the "before" timestamp */
err = rtc_read_time(rtc, &before);
/* get the RTC alarm values, which may be incomplete */
err = rtc_read_alarm_internal(rtc, alarm);
if (err)
return err;
/* get the "after" timestamp, to detect wrapped fields */
err = rtc_read_time(rtc, &now);
/* with luck, no rollover is needed */
rtc_tm_to_time(&now, &t_now);
rtc_tm_to_time(&alarm->time, &t_alm);
if (t_now < t_alm)
goto done;
switch (missing) {
/* 24 hour rollover ... if it's now 10am Monday, an alarm that
* that will trigger at 5am will do so at 5am Tuesday, which
* could also be in the next month or year. This is a common
* case, especially for PCs.
*/
case day:
dev_dbg(&rtc->dev, "alarm rollover: %s/n", "day");
t_alm += 24 * 60 * 60;
rtc_time_to_tm(t_alm, &alarm->time);
break;
/* Month rollover ... if it's the 31th, an alarm on the 3rd will
* be next month. An alarm matching on the 30th, 29th, or 28th
* may end up in the month after that! Many newer PCs support
* this type of alarm.
*/
case month:
dev_dbg(&rtc->dev, "alarm rollover: %s/n", "month");
do {
if (alarm->time.tm_mon < 11)
alarm->time.tm_mon++;
else {
alarm->time.tm_mon = 0;
alarm->time.tm_year++;
}
days = rtc_month_days(alarm->time.tm_mon,
alarm->time.tm_year);
} while (days < alarm->time.tm_mday);
break;
/* Year rollover ... easy except for leap years! */
case year:
dev_dbg(&rtc->dev, "alarm rollover: %s/n", "year");
do {
alarm->time.tm_year++;
} while (rtc_valid_tm(&alarm->time) != 0);
break;
default:
dev_warn(&rtc->dev, "alarm rollover not handled/n");
}
done:
return 0;
}
EXPORT_SYMBOL_GPL(rtc_read_alarm);
int rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
{
int err;
err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
return err;
}
EXPORT_SYMBOL_GPL(rtc_set_alarm);
int rtc_alarm_irq_enable(struct rtc_device *rtc, unsigned int enabled)
{
int err = mutex_lock_interruptible(&rtc->ops_lock);
if (err)
return err;
if (!rtc->ops)
err = -ENODEV;
else if (!rtc->ops->alarm_irq_enable)
err = -EINVAL;
else
err = rtc->ops->alarm_irq_enable(rtc->dev.parent, enabled);
mutex_unlock(&rtc->ops_lock);
return err;
}
EXPORT_SYMBOL_GPL(rtc_alarm_irq_enable);
int rtc_update_irq_enable(struct rtc_device *rtc, unsigned int enabled)
{
int err = mutex_lock_interruptible(&rtc->ops_lock);
if (err)
return err;
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
if (enabled == 0 && rtc->uie_irq_active) {
mutex_unlock(&rtc->ops_lock);
return rtc_dev_update_irq_enable_emul(rtc, enabled);
}
#endif
if (!rtc->ops)
err = -ENODEV;
else if (!rtc->ops->update_irq_enable)
err = -EINVAL;
else
err = rtc->ops->update_irq_enable(rtc->dev.parent, enabled);
mutex_unlock(&rtc->ops_lock);
#ifdef CONFIG_RTC_INTF_DEV_UIE_EMUL
/*
* Enable emulation if the driver did not provide
* the update_irq_enable function pointer or if returned
* -EINVAL to signal that it has been configured without
* interrupts or that are not available at the moment.
*/
if (err == -EINVAL)
err = rtc_dev_update_irq_enable_emul(rtc, enabled);
#endif
return err;
}
EXPORT_SYMBOL_GPL(rtc_update_irq_enable);
/**
* rtc_update_irq - report RTC periodic, alarm, and/or update irqs
* @rtc: the rtc device
* @num: how many irqs are being reported (usually one)
* @events: mask of RTC_IRQF with one or more of RTC_PF, RTC_AF, RTC_UF
* Context: in_interrupt(), irqs blocked
*/
void rtc_update_irq(struct rtc_device *rtc,
unsigned long num, unsigned long events)
{
spin_lock(&rtc->irq_lock);
rtc->irq_data = (rtc->irq_data + (num << 8)) | events;
spin_unlock(&rtc->irq_lock);
spin_lock(&rtc->irq_task_lock);
if (rtc->irq_task)
rtc->irq_task->func(rtc->irq_task->private_data);
spin_unlock(&rtc->irq_task_lock);
wake_up_interruptible(&rtc->irq_queue);
kill_fasync(&rtc->async_queue, SIGIO, POLL_IN);
}
EXPORT_SYMBOL_GPL(rtc_update_irq);
static int __rtc_match(struct device *dev, void *data)
{
char *name = (char *)data;
if (strcmp(dev_name(dev), name) == 0)
return 1;
return 0;
}
struct rtc_device *rtc_class_open(char *name)
{
struct device *dev;
struct rtc_device *rtc = NULL;
dev = class_find_device(rtc_class, NULL, name, __rtc_match);
if (dev)
rtc = to_rtc_device(dev);
if (rtc) {
if (!try_module_get(rtc->owner)) {
put_device(dev);
rtc = NULL;
}
}
return rtc;
}
EXPORT_SYMBOL_GPL(rtc_class_open);
void rtc_class_close(struct rtc_device *rtc)
{
module_put(rtc->owner);
put_device(&rtc->dev);
}
EXPORT_SYMBOL_GPL(rtc_class_close);
int rtc_irq_register(struct rtc_device *rtc, struct rtc_task *task)
{
int retval = -EBUSY;
if (task == NULL || task->func == NULL)
return -EINVAL;
/* Cannot register while the char dev is in use */
if (test_and_set_bit_lock(RTC_DEV_BUSY, &rtc->flags))
return -EBUSY;
spin_lock_irq(&rtc->irq_task_lock);
if (rtc->irq_task == NULL) {
rtc->irq_task = task;
retval = 0;
}
spin_unlock_irq(&rtc->irq_task_lock);
clear_bit_unlock(RTC_DEV_BUSY, &rtc->flags);
return retval;
}
EXPORT_SYMBOL_GPL(rtc_irq_register);
void rtc_irq_unregister(struct rtc_device *rtc, struct rtc_task *task)
{
spin_lock_irq(&rtc->irq_task_lock);
if (rtc->irq_task == task)
rtc->irq_task = NULL;
spin_unlock_irq(&rtc->irq_task_lock);
}
EXPORT_SYMBOL_GPL(rtc_irq_unregister);
/**
* rtc_irq_set_state - enable/disable 2^N Hz periodic IRQs
* @rtc: the rtc device
* @task: currently registered with rtc_irq_register()
* @enabled: true to enable periodic IRQs
* Context: any
*
* Note that rtc_irq_set_freq() should previously have been used to
* specify the desired frequency of periodic IRQ task->func() callbacks.
*/
int rtc_irq_set_state(struct rtc_device *rtc, struct rtc_task *task, int enabled)
{
int err = 0;
unsigned long flags;
if (rtc->ops->irq_set_state == NULL)
return -ENXIO;
spin_lock_irqsave(&rtc->irq_task_lock, flags);
if (rtc->irq_task != NULL && task == NULL)
err = -EBUSY;
if (rtc->irq_task != task)
err = -EACCES;
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
if (err == 0)
err = rtc->ops->irq_set_state(rtc->dev.parent, enabled);
return err;
}
EXPORT_SYMBOL_GPL(rtc_irq_set_state);
/**
* rtc_irq_set_freq - set 2^N Hz periodic IRQ frequency for IRQ
* @rtc: the rtc device
* @task: currently registered with rtc_irq_register()
* @freq: positive frequency with which task->func() will be called
* Context: any
*
* Note that rtc_irq_set_state() is used to enable or disable the
* periodic IRQs.
*/
int rtc_irq_set_freq(struct rtc_device *rtc, struct rtc_task *task, int freq)
{
int err = 0;
unsigned long flags;
if (rtc->ops->irq_set_freq == NULL)
return -ENXIO;
spin_lock_irqsave(&rtc->irq_task_lock, flags);
if (rtc->irq_task != NULL && task == NULL)
err = -EBUSY;
if (rtc->irq_task != task)
err = -EACCES;
spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
if (err == 0) {
err = rtc->ops->irq_set_freq(rtc->dev.parent, freq);
if (err == 0)
rtc->irq_freq = freq;
}
return err;
}
EXPORT_SYMBOL_GPL(rtc_irq_se
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
alarm.c
static int rtc_alarm_add_device(struct device *dev,
struct class_interface *class_intf)
{
err = misc_register(&alarm_device);
alarm_platform_dev =
platform_device_register_simple("alarm", -1, NULL, 0);
err = rtc_irq_register(rtc, &alarm_rtc_task);
return err;
}
static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
switch (ANDROID_ALARM_BASE_CMD(cmd)) {
case ANDROID_ALARM_CLEAR(0):
alarm_enabled &= ~alarm_type_mask;
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);
ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_IO,
"alarm %d set %ld.%09ld/n", alarm_type,
new_alarm_time.tv_sec, new_alarm_time.tv_nsec);
alarm_time[alarm_type] = new_alarm_time;
alarm_enabled |= alarm_type_mask;
alarm_start_hrtimer(alarm_type);
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);
break;
case ANDROID_ALARM_SET_RTC:
if (copy_from_user(&new_rtc_time, (void __user *)arg,
sizeof(new_rtc_time))) {
rv = -EFAULT;
goto err1;
}
rtc_time_to_tm(new_rtc_time.tv_sec, &rtc_new_rtc_time);
mutex_lock(&alarm_setrtc_mutex);
spin_lock_irqsave(&alarm_slock, flags);
for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++)
hrtimer_try_to_cancel(&alarm_timer[i]);
getnstimeofday(&tmp_time);
elapsed_rtc_delta = timespec_sub(elapsed_rtc_delta,
timespec_sub(tmp_time, new_rtc_time));
spin_unlock_irqrestore(&alarm_slock, flags);
rv = do_settimeofday(&new_rtc_time);
spin_lock_irqsave(&alarm_slock, flags);
for (i = 0; i < ANDROID_ALARM_SYSTEMTIME; i++)
alarm_start_hrtimer(i);
spin_unlock_irqrestore(&alarm_slock, flags);
if (rv < 0) {
ANDROID_ALARM_DPRINTF(ANDROID_ALARM_PRINT_ERRORS,
"Failed to set time/n");
mutex_unlock(&alarm_setrtc_mutex);
goto err1;
}
rv = rtc_set_time(alarm_rtc_dev, &rtc_new_rtc_time);
alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK;
break;
case ANDROID_ALARM_GET_TIME(0):
mutex_lock(&alarm_setrtc_mutex);
spin_lock_irqsave(&alarm_slock, flags);
if (alarm_type != ANDROID_ALARM_SYSTEMTIME) {
getnstimeofday(&tmp_time);
if (alarm_type >= ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP)
tmp_time = timespec_sub(tmp_time,
elapsed_rtc_delta);
} else
ktime_get_ts(&tmp_time);
spin_unlock_irqrestore(&alarm_slock, flags);
mutex_unlock(&alarm_setrtc_mutex);
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 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 struct rtc_task alarm_rtc_task = {
.func = alarm_triggered_func
};
static 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_init(void)
{
err = platform_driver_register(&alarm_driver);
rtc_alarm_interface.class = rtc_class;
err = class_interface_register(&rtc_alarm_interface);
return err;
}
alarm_ioctl----> alarm_enabled |= alarm_type_mask;
| alarm_start_hrtimer(alarm_type);
|
alarm_suspend--> 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);
|(alarm.c)
|
|
rtc_set_alarm(alarm_rtc_dev, &rtc_alarm);------> err = rtc->ops->set_alarm(rtc->dev.parent, alarm);
|(interface.c)
|
|
m41t80_rtc_set_alarm
(rtc-m41t80.c)
- RTC 层次结构
- RTC m48t59 层次结构
- 层次结构
- 展开层次结构
- servlet层次结构
- 存储系统的层次结构
- BlackBerry UI层次结构
- JAVA层次结构开发
- javaee层次结构
- 存储器的层次结构
- unix的层次结构
- J2EE的层次结构
- Android 软件层次结构
- 存储器层次结构
- 存储器层次结构
- 驱动程序的层次结构
- 流层次结构
- html 显示层次结构
- 表达式 (MDX)
- 标识符 (MDX)
- css如何控制div高度等于另一个DIV的高度?
- Analysis Services MDX 中的重要概念
- 用Photoshop CS2 快速制作DIV+CSS
- RTC 层次结构
- MDX学习笔记之Tuple
- SQLSERVER2000 用过程来模拟MDX分析报表的效果(1)
- MDX语句及函数应用举例
- SSAS函数举例
- Analysis Services 查询性能十大最佳实践
- MDX children与members的误区
- 一些常用的MDX查询语句(基于SSAS 2008)
- 过渡到SSAS之一:简单模型认识