lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Date:	Fri, 4 Sep 2009 08:59:51 +0200
From:	christian pellegrin <chripell@...il.com>
To:	Chris Verges <chrisv@...erswitching.com>,
	Andrew Morton <akpm@...ux-foundation.org>,
	linux-kernel@...r.kernel.org
Subject: [PATCH -mm] rtc-pcf2123 fixes

Hi, the following patch:

fixes bug with write command bitfield

fixes bug on crashing when module unloaded but no chip present

adds access to registers via sysfs (needed for accessing calibration
register which is needed for a good stability of the RTC)

Signed-off: Christian Pellegrin <chripell@...e.org>
Tested-by: Christian Pellegrin <chripell@...e.org>
---
diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c
index 2fcff82..0c55f7d 100644
--- a/drivers/rtc/rtc-pcf2123.c
+++ b/drivers/rtc/rtc-pcf2123.c
@@ -10,6 +10,23 @@
  * 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.
+ *
+ * Please note that the CS is active high, so platform data
+ * should look something like:
+
+ static struct spi_board_info ek_spi_devices[] = {
+ ...
+  {
+    .modalias	= "rtc-pcf2123",
+    .chip_select	= 1,
+    .controller_data = (void *) AT91_PIN_PA10,
+    .max_speed_hz	= 1000 * 1000,
+    .mode = SPI_CS_HIGH,
+    .bus_num	= 0,
+  },
+...
+};
+
  */

 #include <linux/bcd.h>
@@ -20,10 +37,9 @@
 #include <linux/kernel.h>
 #include <linux/string.h>
 #include <linux/rtc.h>
-#include <linux/workqueue.h>
 #include <linux/spi/spi.h>

-#define DRV_VERSION "0.3"
+#define DRV_VERSION "0.4"

 #define PCF2123_REG_CTRL1	0x00 /* Control Register 1 */
 #define PCF2123_REG_CTRL2	0x01 /* Control Register 2 */
@@ -36,13 +52,19 @@
 #define PCF2123_REG_MO		0x07
 #define PCF2123_REG_YR		0x08

-#define PCF2123_CMD_W(addr)	(((addr) & 0x0F) | 0x40)  /* single write */
+#define PCF2123_CMD_W(addr)	(((addr) & 0x0F) | 0x10)  /* single write */
 #define PCF2123_CMD_R(addr)	(((addr) & 0x0F) | 0x90)  /* single read */

 static struct spi_driver pcf2123_driver;

+struct pcf2123_sysfs_reg {
+	struct device_attribute attr; /* must be first */
+	char name[2];
+};
+
 struct pcf2123_plat_data {
 	struct rtc_device *rtc;
+	struct pcf2123_sysfs_reg regs[16];
 };

 /*
@@ -55,6 +77,39 @@ static inline void pcf2123_delay_trec(void)
 	ndelay(30);
 }

+static ssize_t pcf2123_show(struct device *dev, struct device_attribute *attr,
+			    char *buffer)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct pcf2123_sysfs_reg *r = (struct pcf2123_sysfs_reg *) attr;
+	u8 txbuf[1], rxbuf[1];
+	int ret;
+
+	txbuf[0] = PCF2123_CMD_R(simple_strtoul(r->name, NULL, 16));
+	ret = spi_write_then_read(spi, txbuf, 1, rxbuf, 1);
+	if (ret < 0)
+		return sprintf(buffer, "error: %d", ret);
+	pcf2123_delay_trec();
+	return sprintf(buffer, "0x%x", rxbuf[0]);
+}
+
+static ssize_t pcf2123_store(struct device *dev, struct device_attribute *attr,
+			     const char *buffer, size_t count)
+{
+	struct spi_device *spi = to_spi_device(dev);
+	struct pcf2123_sysfs_reg *r = (struct pcf2123_sysfs_reg *) attr;
+	u8 txbuf[2];
+	int ret;
+
+	txbuf[0] = PCF2123_CMD_W(simple_strtoul(r->name, NULL, 16));
+	txbuf[1] = simple_strtoul(buffer, NULL, 0);
+	ret = spi_write(spi, txbuf, sizeof(txbuf));
+	if (ret < 0)
+		return -EIO;
+	pcf2123_delay_trec();
+	return count;
+}
+
 static int pcf2123_rtc_read_time(struct device *dev, struct rtc_time *tm)
 {
 	struct spi_device *spi = to_spi_device(dev);
@@ -149,7 +204,7 @@ static int __devinit pcf2123_probe(struct spi_device *spi)
 	struct rtc_device *rtc;
 	struct pcf2123_plat_data *pdata;
 	u8 txbuf[2], rxbuf[1];
-	int ret;
+	int ret, i;

 	pdata = kzalloc(sizeof(struct pcf2123_plat_data), GFP_KERNEL);
 	if (!pdata)
@@ -201,28 +256,50 @@ static int __devinit pcf2123_probe(struct spi_device *spi)
 			&pcf2123_rtc_ops, THIS_MODULE);

 	if (IS_ERR(rtc)) {
+		dev_err(&spi->dev, "failed to register.\n");
 		ret = PTR_ERR(rtc);
 		goto kfree_exit;
 	}

 	pdata->rtc = rtc;

+	for (i = 0; i < 16; i++) {
+		sprintf(pdata->regs[i].name, "%1x", i);
+		pdata->regs[i].attr.attr.mode = S_IRUGO | S_IWUSR;
+		pdata->regs[i].attr.attr.name = pdata->regs[i].name;
+		pdata->regs[i].attr.show = pcf2123_show;
+		pdata->regs[i].attr.store = pcf2123_store;
+		ret = device_create_file(&spi->dev, &pdata->regs[i].attr);
+		if (ret) {
+			dev_err(&spi->dev, "Unable to create sysfs %s\n",
+				pdata->regs[i].name);
+			pdata->regs[i].name[0] = '\0';
+		}
+	}
+
 	return 0;
 kfree_exit:
 	kfree(pdata);
+	spi->dev.platform_data = NULL;
 	return ret;
 }

 static int pcf2123_remove(struct spi_device *spi)
 {
 	struct pcf2123_plat_data *pdata = spi->dev.platform_data;
-	struct rtc_device *rtc = pdata->rtc;
-
-	if (rtc)
-		rtc_device_unregister(rtc);
-
-	kfree(pdata);
-
+	int i;
+
+	if (pdata) {
+		struct rtc_device *rtc = pdata->rtc;
+
+		if (rtc)
+			rtc_device_unregister(rtc);
+		for (i = 0; i < 16; i++)
+			if (pdata->regs[i].name[0])
+				device_remove_file(&spi->dev,
+						   &pdata->regs[i].attr);
+		kfree(pdata);
+	}
 	return 0;
 }

-- 
Christian Pellegrin, see http://www.evolware.org/chri/
"Real Programmers don't play tennis, or any other sport which requires
you to change clothes. Mountain climbing is OK, and Real Programmers
wear their climbing boots to work in case a mountain should suddenly
spring up in the middle of the computer room."
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ