Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 83527
b: refs/heads/master
c: e07e232
h: refs/heads/master
i:
  83525: 3d33568
  83523: 5591dfd
  83519: ecb7806
v: v3
  • Loading branch information
David Brownell authored and Linus Torvalds committed Feb 6, 2008
1 parent 318a9fc commit 53053bf
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 13 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 9974b6ea7b85a32f34f824443f47aa501c85ee8f
refs/heads/master: e07e232cd96ef0092b2bddc72f9b7caf284633cb
129 changes: 117 additions & 12 deletions trunk/drivers/rtc/rtc-cmos.c
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,80 @@ static const struct rtc_class_ops cmos_rtc_ops = {

/*----------------------------------------------------------------*/

/*
* All these chips have at least 64 bytes of address space, shared by
* RTC registers and NVRAM. Most of those bytes of NVRAM are used
* by boot firmware. Modern chips have 128 or 256 bytes.
*/

#define NVRAM_OFFSET (RTC_REG_D + 1)

static ssize_t
cmos_nvram_read(struct kobject *kobj, struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
int retval;

if (unlikely(off >= attr->size))
return 0;
if ((off + count) > attr->size)
count = attr->size - off;

spin_lock_irq(&rtc_lock);
for (retval = 0, off += NVRAM_OFFSET; count--; retval++, off++)
*buf++ = CMOS_READ(off);
spin_unlock_irq(&rtc_lock);

return retval;
}

static ssize_t
cmos_nvram_write(struct kobject *kobj, struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
struct cmos_rtc *cmos;
int retval;

cmos = dev_get_drvdata(container_of(kobj, struct device, kobj));
if (unlikely(off >= attr->size))
return -EFBIG;
if ((off + count) > attr->size)
count = attr->size - off;

/* NOTE: on at least PCs and Ataris, the boot firmware uses a
* checksum on part of the NVRAM data. That's currently ignored
* here. If userspace is smart enough to know what fields of
* NVRAM to update, updating checksums is also part of its job.
*/
spin_lock_irq(&rtc_lock);
for (retval = 0, off += NVRAM_OFFSET; count--; retval++, off++) {
/* don't trash RTC registers */
if (off == cmos->day_alrm
|| off == cmos->mon_alrm
|| off == cmos->century)
buf++;
else
CMOS_WRITE(*buf++, off);
}
spin_unlock_irq(&rtc_lock);

return retval;
}

static struct bin_attribute nvram = {
.attr = {
.name = "nvram",
.mode = S_IRUGO | S_IWUSR,
.owner = THIS_MODULE,
},

.read = cmos_nvram_read,
.write = cmos_nvram_write,
/* size gets set up later */
};

/*----------------------------------------------------------------*/

static struct cmos_rtc cmos_rtc;

static irqreturn_t cmos_interrupt(int irq, void *p)
Expand All @@ -412,11 +486,9 @@ static irqreturn_t cmos_interrupt(int irq, void *p)
}

#ifdef CONFIG_PNP
#define is_pnp() 1
#define INITSECTION

#else
#define is_pnp() 0
#define INITSECTION __init
#endif

Expand All @@ -426,6 +498,7 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
struct cmos_rtc_board_info *info = dev->platform_data;
int retval = 0;
unsigned char rtc_control;
unsigned address_space;

/* there can be only one ... */
if (cmos_rtc.dev)
Expand All @@ -450,15 +523,36 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
cmos_rtc.irq = rtc_irq;
cmos_rtc.iomem = ports;

/* Heuristic to deduce NVRAM size ... do what the legacy NVRAM
* driver did, but don't reject unknown configs. Old hardware
* won't address 128 bytes, and for now we ignore the way newer
* chips can address 256 bytes (using two more i/o ports).
*/
#if defined(CONFIG_ATARI)
address_space = 64;
#elif defined(__i386__) || defined(__x86_64__) || defined(__arm__)
address_space = 128;
#else
#warning Assuming 128 bytes of RTC+NVRAM address space, not 64 bytes.
address_space = 128;
#endif

/* For ACPI systems extension info comes from the FADT. On others,
* board specific setup provides it as appropriate. Systems where
* the alarm IRQ isn't automatically a wakeup IRQ (like ACPI, and
* some almost-clones) can provide hooks to make that behave.
*
* Note that ACPI doesn't preclude putting these registers into
* "extended" areas of the chip, including some that we won't yet
* expect CMOS_READ and friends to handle.
*/
if (info) {
cmos_rtc.day_alrm = info->rtc_day_alarm;
cmos_rtc.mon_alrm = info->rtc_mon_alarm;
cmos_rtc.century = info->rtc_century;
if (info->rtc_day_alarm && info->rtc_day_alarm < 128)
cmos_rtc.day_alrm = info->rtc_day_alarm;
if (info->rtc_mon_alarm && info->rtc_mon_alarm < 128)
cmos_rtc.mon_alrm = info->rtc_mon_alarm;
if (info->rtc_century && info->rtc_century < 128)
cmos_rtc.century = info->rtc_century;

if (info->wake_on && info->wake_off) {
cmos_rtc.wake_on = info->wake_on;
Expand Down Expand Up @@ -518,10 +612,13 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
goto cleanup1;
}

/* REVISIT optionally make 50 or 114 bytes NVRAM available,
* like rtc-ds1553, rtc-ds1742 ... this will often include
* registers for century, and day/month alarm.
*/
/* export at least the first block of NVRAM */
nvram.size = address_space - NVRAM_OFFSET;
retval = sysfs_create_bin_file(&dev->kobj, &nvram);
if (retval < 0) {
dev_dbg(dev, "can't create nvram file? %d\n", retval);
goto cleanup2;
}

pr_info("%s: alarms up to one %s%s\n",
cmos_rtc.rtc->dev.bus_id,
Expand All @@ -536,6 +633,9 @@ cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)

return 0;

cleanup2:
if (is_valid_irq(rtc_irq))
free_irq(rtc_irq, cmos_rtc.rtc);
cleanup1:
cmos_rtc.dev = NULL;
rtc_device_unregister(cmos_rtc.rtc);
Expand Down Expand Up @@ -563,6 +663,8 @@ static void __exit cmos_do_remove(struct device *dev)

cmos_do_shutdown();

sysfs_remove_bin_file(&dev->kobj, &nvram);

if (is_valid_irq(cmos->irq))
free_irq(cmos->irq, cmos->rtc);

Expand Down Expand Up @@ -659,9 +761,12 @@ static int cmos_resume(struct device *dev)

/*----------------------------------------------------------------*/

/* The "CMOS" RTC normally lives on the platform_bus. On ACPI systems,
* the device node will always be created as a PNPACPI device. Plus
* pre-ACPI PCs probably list it in the PNPBIOS tables.
/* On non-x86 systems, a "CMOS" RTC lives most naturally on platform_bus.
* ACPI systems always list these as PNPACPI devices, and pre-ACPI PCs
* probably list them in similar PNPBIOS tables; so PNP is more common.
*
* We don't use legacy "poke at the hardware" probing. Ancient PCs that
* predate even PNPBIOS should set up platform_bus devices.
*/

#ifdef CONFIG_PNP
Expand Down

0 comments on commit 53053bf

Please sign in to comment.