diff options
author | Len Brown <len.brown@intel.com> | 2009-01-09 03:39:43 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2009-01-09 03:39:43 -0500 |
commit | b2576e1d4408e134e2188c967b1f28af39cd79d4 (patch) | |
tree | 004f3c82faab760f304ce031d6d2f572e7746a50 /drivers/w1 | |
parent | 3cc8a5f4ba91f67bbdb81a43a99281a26aab8d77 (diff) | |
parent | 2150edc6c5cf00f7adb54538b9ea2a3e9cedca3f (diff) |
Merge branch 'linus' into release
Diffstat (limited to 'drivers/w1')
-rw-r--r-- | drivers/w1/masters/Kconfig | 6 | ||||
-rw-r--r-- | drivers/w1/masters/Makefile | 2 | ||||
-rw-r--r-- | drivers/w1/masters/mxc_w1.c | 211 | ||||
-rw-r--r-- | drivers/w1/w1.c | 19 | ||||
-rw-r--r-- | drivers/w1/w1.h | 1 | ||||
-rw-r--r-- | drivers/w1/w1_int.c | 3 | ||||
-rw-r--r-- | drivers/w1/w1_io.c | 26 | ||||
-rw-r--r-- | drivers/w1/w1_netlink.c | 261 | ||||
-rw-r--r-- | drivers/w1/w1_netlink.h | 16 |
9 files changed, 488 insertions, 57 deletions
diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig index 90616822cd2..96d2f8e4c27 100644 --- a/drivers/w1/masters/Kconfig +++ b/drivers/w1/masters/Kconfig | |||
@@ -34,6 +34,12 @@ config W1_MASTER_DS2482 | |||
34 | This driver can also be built as a module. If so, the module | 34 | This driver can also be built as a module. If so, the module |
35 | will be called ds2482. | 35 | will be called ds2482. |
36 | 36 | ||
37 | config W1_MASTER_MXC | ||
38 | tristate "Freescale MXC 1-wire busmaster" | ||
39 | depends on W1 && ARCH_MXC | ||
40 | help | ||
41 | Say Y here to enable MXC 1-wire host | ||
42 | |||
37 | config W1_MASTER_DS1WM | 43 | config W1_MASTER_DS1WM |
38 | tristate "Maxim DS1WM 1-wire busmaster" | 44 | tristate "Maxim DS1WM 1-wire busmaster" |
39 | depends on W1 && ARM && HAVE_CLK | 45 | depends on W1 && ARM && HAVE_CLK |
diff --git a/drivers/w1/masters/Makefile b/drivers/w1/masters/Makefile index bc4714a75f3..c5a3e96fcba 100644 --- a/drivers/w1/masters/Makefile +++ b/drivers/w1/masters/Makefile | |||
@@ -5,6 +5,8 @@ | |||
5 | obj-$(CONFIG_W1_MASTER_MATROX) += matrox_w1.o | 5 | obj-$(CONFIG_W1_MASTER_MATROX) += matrox_w1.o |
6 | obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o | 6 | obj-$(CONFIG_W1_MASTER_DS2490) += ds2490.o |
7 | obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o | 7 | obj-$(CONFIG_W1_MASTER_DS2482) += ds2482.o |
8 | obj-$(CONFIG_W1_MASTER_MXC) += mxc_w1.o | ||
9 | |||
8 | obj-$(CONFIG_W1_MASTER_DS1WM) += ds1wm.o | 10 | obj-$(CONFIG_W1_MASTER_DS1WM) += ds1wm.o |
9 | obj-$(CONFIG_W1_MASTER_GPIO) += w1-gpio.o | 11 | obj-$(CONFIG_W1_MASTER_GPIO) += w1-gpio.o |
10 | obj-$(CONFIG_HDQ_MASTER_OMAP) += omap_hdq.o | 12 | obj-$(CONFIG_HDQ_MASTER_OMAP) += omap_hdq.o |
diff --git a/drivers/w1/masters/mxc_w1.c b/drivers/w1/masters/mxc_w1.c new file mode 100644 index 00000000000..b9d74d0b353 --- /dev/null +++ b/drivers/w1/masters/mxc_w1.c | |||
@@ -0,0 +1,211 @@ | |||
1 | /* | ||
2 | * Copyright 2005-2008 Freescale Semiconductor, Inc. All Rights Reserved. | ||
3 | * Copyright 2008 Luotao Fu, kernel@pengutronix.de | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License | ||
7 | * as published by the Free Software Foundation; either version 2 | ||
8 | * of the License, or (at your option) any later version. | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #include <linux/module.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/clk.h> | ||
24 | #include <linux/delay.h> | ||
25 | #include <linux/io.h> | ||
26 | |||
27 | #include "../w1.h" | ||
28 | #include "../w1_int.h" | ||
29 | #include "../w1_log.h" | ||
30 | |||
31 | /* According to the mx27 Datasheet the reset procedure should take up to about | ||
32 | * 1350us. We set the timeout to 500*100us = 50ms for sure */ | ||
33 | #define MXC_W1_RESET_TIMEOUT 500 | ||
34 | |||
35 | /* | ||
36 | * MXC W1 Register offsets | ||
37 | */ | ||
38 | #define MXC_W1_CONTROL 0x00 | ||
39 | #define MXC_W1_TIME_DIVIDER 0x02 | ||
40 | #define MXC_W1_RESET 0x04 | ||
41 | #define MXC_W1_COMMAND 0x06 | ||
42 | #define MXC_W1_TXRX 0x08 | ||
43 | #define MXC_W1_INTERRUPT 0x0A | ||
44 | #define MXC_W1_INTERRUPT_EN 0x0C | ||
45 | |||
46 | struct mxc_w1_device { | ||
47 | void __iomem *regs; | ||
48 | unsigned int clkdiv; | ||
49 | struct clk *clk; | ||
50 | struct w1_bus_master bus_master; | ||
51 | }; | ||
52 | |||
53 | /* | ||
54 | * this is the low level routine to | ||
55 | * reset the device on the One Wire interface | ||
56 | * on the hardware | ||
57 | */ | ||
58 | static u8 mxc_w1_ds2_reset_bus(void *data) | ||
59 | { | ||
60 | u8 reg_val; | ||
61 | unsigned int timeout_cnt = 0; | ||
62 | struct mxc_w1_device *dev = data; | ||
63 | |||
64 | __raw_writeb(0x80, (dev->regs + MXC_W1_CONTROL)); | ||
65 | |||
66 | while (1) { | ||
67 | reg_val = __raw_readb(dev->regs + MXC_W1_CONTROL); | ||
68 | |||
69 | if (((reg_val >> 7) & 0x1) == 0 || | ||
70 | timeout_cnt > MXC_W1_RESET_TIMEOUT) | ||
71 | break; | ||
72 | else | ||
73 | timeout_cnt++; | ||
74 | |||
75 | udelay(100); | ||
76 | } | ||
77 | return (reg_val >> 7) & 0x1; | ||
78 | } | ||
79 | |||
80 | /* | ||
81 | * this is the low level routine to read/write a bit on the One Wire | ||
82 | * interface on the hardware. It does write 0 if parameter bit is set | ||
83 | * to 0, otherwise a write 1/read. | ||
84 | */ | ||
85 | static u8 mxc_w1_ds2_touch_bit(void *data, u8 bit) | ||
86 | { | ||
87 | struct mxc_w1_device *mdev = data; | ||
88 | void __iomem *ctrl_addr = mdev->regs + MXC_W1_CONTROL; | ||
89 | unsigned int timeout_cnt = 400; /* Takes max. 120us according to | ||
90 | * datasheet. | ||
91 | */ | ||
92 | |||
93 | __raw_writeb((1 << (5 - bit)), ctrl_addr); | ||
94 | |||
95 | while (timeout_cnt--) { | ||
96 | if (!((__raw_readb(ctrl_addr) >> (5 - bit)) & 0x1)) | ||
97 | break; | ||
98 | |||
99 | udelay(1); | ||
100 | } | ||
101 | |||
102 | return ((__raw_readb(ctrl_addr)) >> 3) & 0x1; | ||
103 | } | ||
104 | |||
105 | static int __init mxc_w1_probe(struct platform_device *pdev) | ||
106 | { | ||
107 | struct mxc_w1_device *mdev; | ||
108 | struct resource *res; | ||
109 | int err = 0; | ||
110 | |||
111 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
112 | if (!res) | ||
113 | return -ENODEV; | ||
114 | |||
115 | mdev = kzalloc(sizeof(struct mxc_w1_device), GFP_KERNEL); | ||
116 | if (!mdev) | ||
117 | return -ENOMEM; | ||
118 | |||
119 | mdev->clk = clk_get(&pdev->dev, "owire_clk"); | ||
120 | if (!mdev->clk) { | ||
121 | err = -ENODEV; | ||
122 | goto failed_clk; | ||
123 | } | ||
124 | |||
125 | mdev->clkdiv = (clk_get_rate(mdev->clk) / 1000000) - 1; | ||
126 | |||
127 | res = request_mem_region(res->start, resource_size(res), | ||
128 | "mxc_w1"); | ||
129 | if (!res) { | ||
130 | err = -EBUSY; | ||
131 | goto failed_req; | ||
132 | } | ||
133 | |||
134 | mdev->regs = ioremap(res->start, resource_size(res)); | ||
135 | if (!mdev->regs) { | ||
136 | printk(KERN_ERR "Cannot map frame buffer registers\n"); | ||
137 | goto failed_ioremap; | ||
138 | } | ||
139 | |||
140 | clk_enable(mdev->clk); | ||
141 | __raw_writeb(mdev->clkdiv, mdev->regs + MXC_W1_TIME_DIVIDER); | ||
142 | |||
143 | mdev->bus_master.data = mdev; | ||
144 | mdev->bus_master.reset_bus = mxc_w1_ds2_reset_bus; | ||
145 | mdev->bus_master.touch_bit = mxc_w1_ds2_touch_bit; | ||
146 | |||
147 | err = w1_add_master_device(&mdev->bus_master); | ||
148 | |||
149 | if (err) | ||
150 | goto failed_add; | ||
151 | |||
152 | platform_set_drvdata(pdev, mdev); | ||
153 | return 0; | ||
154 | |||
155 | failed_add: | ||
156 | iounmap(mdev->regs); | ||
157 | failed_ioremap: | ||
158 | release_mem_region(res->start, resource_size(res)); | ||
159 | failed_req: | ||
160 | clk_put(mdev->clk); | ||
161 | failed_clk: | ||
162 | kfree(mdev); | ||
163 | return err; | ||
164 | } | ||
165 | |||
166 | /* | ||
167 | * disassociate the w1 device from the driver | ||
168 | */ | ||
169 | static int mxc_w1_remove(struct platform_device *pdev) | ||
170 | { | ||
171 | struct mxc_w1_device *mdev = platform_get_drvdata(pdev); | ||
172 | struct resource *res; | ||
173 | |||
174 | res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | ||
175 | |||
176 | w1_remove_master_device(&mdev->bus_master); | ||
177 | |||
178 | iounmap(mdev->regs); | ||
179 | release_mem_region(res->start, resource_size(res)); | ||
180 | clk_disable(mdev->clk); | ||
181 | clk_put(mdev->clk); | ||
182 | |||
183 | platform_set_drvdata(pdev, NULL); | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static struct platform_driver mxc_w1_driver = { | ||
189 | .driver = { | ||
190 | .name = "mxc_w1", | ||
191 | }, | ||
192 | .probe = mxc_w1_probe, | ||
193 | .remove = mxc_w1_remove, | ||
194 | }; | ||
195 | |||
196 | static int __init mxc_w1_init(void) | ||
197 | { | ||
198 | return platform_driver_register(&mxc_w1_driver); | ||
199 | } | ||
200 | |||
201 | static void mxc_w1_exit(void) | ||
202 | { | ||
203 | platform_driver_unregister(&mxc_w1_driver); | ||
204 | } | ||
205 | |||
206 | module_init(mxc_w1_init); | ||
207 | module_exit(mxc_w1_exit); | ||
208 | |||
209 | MODULE_LICENSE("GPL"); | ||
210 | MODULE_AUTHOR("Freescale Semiconductors Inc"); | ||
211 | MODULE_DESCRIPTION("Driver for One-Wire on MXC"); | ||
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index 3b615d4022e..acc7e3b7fe1 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c | |||
@@ -197,7 +197,7 @@ struct device_driver w1_master_driver = { | |||
197 | struct device w1_master_device = { | 197 | struct device w1_master_device = { |
198 | .parent = NULL, | 198 | .parent = NULL, |
199 | .bus = &w1_bus_type, | 199 | .bus = &w1_bus_type, |
200 | .bus_id = "w1 bus master", | 200 | .init_name = "w1 bus master", |
201 | .driver = &w1_master_driver, | 201 | .driver = &w1_master_driver, |
202 | .release = &w1_master_release | 202 | .release = &w1_master_release |
203 | }; | 203 | }; |
@@ -211,7 +211,7 @@ static struct device_driver w1_slave_driver = { | |||
211 | struct device w1_slave_device = { | 211 | struct device w1_slave_device = { |
212 | .parent = NULL, | 212 | .parent = NULL, |
213 | .bus = &w1_bus_type, | 213 | .bus = &w1_bus_type, |
214 | .bus_id = "w1 bus slave", | 214 | .init_name = "w1 bus slave", |
215 | .driver = &w1_slave_driver, | 215 | .driver = &w1_slave_driver, |
216 | .release = &w1_slave_release | 216 | .release = &w1_slave_release |
217 | }; | 217 | }; |
@@ -573,7 +573,7 @@ static int w1_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
573 | } | 573 | } |
574 | 574 | ||
575 | dev_dbg(dev, "Hotplug event for %s %s, bus_id=%s.\n", | 575 | dev_dbg(dev, "Hotplug event for %s %s, bus_id=%s.\n", |
576 | event_owner, name, dev->bus_id); | 576 | event_owner, name, dev_name(dev)); |
577 | 577 | ||
578 | if (dev->driver != &w1_slave_driver || !sl) | 578 | if (dev->driver != &w1_slave_driver || !sl) |
579 | return 0; | 579 | return 0; |
@@ -605,8 +605,7 @@ static int __w1_attach_slave_device(struct w1_slave *sl) | |||
605 | sl->dev.bus = &w1_bus_type; | 605 | sl->dev.bus = &w1_bus_type; |
606 | sl->dev.release = &w1_slave_release; | 606 | sl->dev.release = &w1_slave_release; |
607 | 607 | ||
608 | snprintf(&sl->dev.bus_id[0], sizeof(sl->dev.bus_id), | 608 | dev_set_name(&sl->dev, "%02x-%012llx", |
609 | "%02x-%012llx", | ||
610 | (unsigned int) sl->reg_num.family, | 609 | (unsigned int) sl->reg_num.family, |
611 | (unsigned long long) sl->reg_num.id); | 610 | (unsigned long long) sl->reg_num.id); |
612 | snprintf(&sl->name[0], sizeof(sl->name), | 611 | snprintf(&sl->name[0], sizeof(sl->name), |
@@ -615,13 +614,13 @@ static int __w1_attach_slave_device(struct w1_slave *sl) | |||
615 | (unsigned long long) sl->reg_num.id); | 614 | (unsigned long long) sl->reg_num.id); |
616 | 615 | ||
617 | dev_dbg(&sl->dev, "%s: registering %s as %p.\n", __func__, | 616 | dev_dbg(&sl->dev, "%s: registering %s as %p.\n", __func__, |
618 | &sl->dev.bus_id[0], sl); | 617 | dev_name(&sl->dev), sl); |
619 | 618 | ||
620 | err = device_register(&sl->dev); | 619 | err = device_register(&sl->dev); |
621 | if (err < 0) { | 620 | if (err < 0) { |
622 | dev_err(&sl->dev, | 621 | dev_err(&sl->dev, |
623 | "Device registration [%s] failed. err=%d\n", | 622 | "Device registration [%s] failed. err=%d\n", |
624 | sl->dev.bus_id, err); | 623 | dev_name(&sl->dev), err); |
625 | return err; | 624 | return err; |
626 | } | 625 | } |
627 | 626 | ||
@@ -630,7 +629,7 @@ static int __w1_attach_slave_device(struct w1_slave *sl) | |||
630 | if (err < 0) { | 629 | if (err < 0) { |
631 | dev_err(&sl->dev, | 630 | dev_err(&sl->dev, |
632 | "sysfs file creation for [%s] failed. err=%d\n", | 631 | "sysfs file creation for [%s] failed. err=%d\n", |
633 | sl->dev.bus_id, err); | 632 | dev_name(&sl->dev), err); |
634 | goto out_unreg; | 633 | goto out_unreg; |
635 | } | 634 | } |
636 | 635 | ||
@@ -639,7 +638,7 @@ static int __w1_attach_slave_device(struct w1_slave *sl) | |||
639 | if (err < 0) { | 638 | if (err < 0) { |
640 | dev_err(&sl->dev, | 639 | dev_err(&sl->dev, |
641 | "sysfs file creation for [%s] failed. err=%d\n", | 640 | "sysfs file creation for [%s] failed. err=%d\n", |
642 | sl->dev.bus_id, err); | 641 | dev_name(&sl->dev), err); |
643 | goto out_rem1; | 642 | goto out_rem1; |
644 | } | 643 | } |
645 | 644 | ||
@@ -648,7 +647,7 @@ static int __w1_attach_slave_device(struct w1_slave *sl) | |||
648 | ((err = sl->family->fops->add_slave(sl)) < 0)) { | 647 | ((err = sl->family->fops->add_slave(sl)) < 0)) { |
649 | dev_err(&sl->dev, | 648 | dev_err(&sl->dev, |
650 | "sysfs file creation for [%s] failed. err=%d\n", | 649 | "sysfs file creation for [%s] failed. err=%d\n", |
651 | sl->dev.bus_id, err); | 650 | dev_name(&sl->dev), err); |
652 | goto out_rem2; | 651 | goto out_rem2; |
653 | } | 652 | } |
654 | 653 | ||
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h index 97304bd83ec..d8a9709f344 100644 --- a/drivers/w1/w1.h +++ b/drivers/w1/w1.h | |||
@@ -210,6 +210,7 @@ u8 w1_read_8(struct w1_master *); | |||
210 | int w1_reset_bus(struct w1_master *); | 210 | int w1_reset_bus(struct w1_master *); |
211 | u8 w1_calc_crc8(u8 *, int); | 211 | u8 w1_calc_crc8(u8 *, int); |
212 | void w1_write_block(struct w1_master *, const u8 *, int); | 212 | void w1_write_block(struct w1_master *, const u8 *, int); |
213 | void w1_touch_block(struct w1_master *, u8 *, int); | ||
213 | u8 w1_read_block(struct w1_master *, u8 *, int); | 214 | u8 w1_read_block(struct w1_master *, u8 *, int); |
214 | int w1_reset_select_slave(struct w1_slave *sl); | 215 | int w1_reset_select_slave(struct w1_slave *sl); |
215 | void w1_next_pullup(struct w1_master *, int); | 216 | void w1_next_pullup(struct w1_master *, int); |
diff --git a/drivers/w1/w1_int.c b/drivers/w1/w1_int.c index a3a54567bfb..4a46ed58ece 100644 --- a/drivers/w1/w1_int.c +++ b/drivers/w1/w1_int.c | |||
@@ -75,8 +75,7 @@ static struct w1_master * w1_alloc_dev(u32 id, int slave_count, int slave_ttl, | |||
75 | mutex_init(&dev->mutex); | 75 | mutex_init(&dev->mutex); |
76 | 76 | ||
77 | memcpy(&dev->dev, device, sizeof(struct device)); | 77 | memcpy(&dev->dev, device, sizeof(struct device)); |
78 | snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id), | 78 | dev_set_name(&dev->dev, "w1_bus_master%u", dev->id); |
79 | "w1_bus_master%u", dev->id); | ||
80 | snprintf(dev->name, sizeof(dev->name), "w1_bus_master%u", dev->id); | 79 | snprintf(dev->name, sizeof(dev->name), "w1_bus_master%u", dev->id); |
81 | 80 | ||
82 | dev->driver = driver; | 81 | dev->driver = driver; |
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c index 5139c25ca96..442bd8bbd4a 100644 --- a/drivers/w1/w1_io.c +++ b/drivers/w1/w1_io.c | |||
@@ -238,7 +238,6 @@ EXPORT_SYMBOL_GPL(w1_read_8); | |||
238 | * @param dev the master device | 238 | * @param dev the master device |
239 | * @param buf pointer to the data to write | 239 | * @param buf pointer to the data to write |
240 | * @param len the number of bytes to write | 240 | * @param len the number of bytes to write |
241 | * @return the byte read | ||
242 | */ | 241 | */ |
243 | void w1_write_block(struct w1_master *dev, const u8 *buf, int len) | 242 | void w1_write_block(struct w1_master *dev, const u8 *buf, int len) |
244 | { | 243 | { |
@@ -256,6 +255,31 @@ void w1_write_block(struct w1_master *dev, const u8 *buf, int len) | |||
256 | EXPORT_SYMBOL_GPL(w1_write_block); | 255 | EXPORT_SYMBOL_GPL(w1_write_block); |
257 | 256 | ||
258 | /** | 257 | /** |
258 | * Touches a series of bytes. | ||
259 | * | ||
260 | * @param dev the master device | ||
261 | * @param buf pointer to the data to write | ||
262 | * @param len the number of bytes to write | ||
263 | */ | ||
264 | void w1_touch_block(struct w1_master *dev, u8 *buf, int len) | ||
265 | { | ||
266 | int i, j; | ||
267 | u8 tmp; | ||
268 | |||
269 | for (i = 0; i < len; ++i) { | ||
270 | tmp = 0; | ||
271 | for (j = 0; j < 8; ++j) { | ||
272 | if (j == 7) | ||
273 | w1_pre_write(dev); | ||
274 | tmp |= w1_touch_bit(dev, (buf[i] >> j) & 0x1) << j; | ||
275 | } | ||
276 | |||
277 | buf[i] = tmp; | ||
278 | } | ||
279 | } | ||
280 | EXPORT_SYMBOL_GPL(w1_touch_block); | ||
281 | |||
282 | /** | ||
259 | * Reads a series of bytes. | 283 | * Reads a series of bytes. |
260 | * | 284 | * |
261 | * @param dev the master device | 285 | * @param dev the master device |
diff --git a/drivers/w1/w1_netlink.c b/drivers/w1/w1_netlink.c index 65c5ebd0787..fdf72851c57 100644 --- a/drivers/w1/w1_netlink.c +++ b/drivers/w1/w1_netlink.c | |||
@@ -47,21 +47,56 @@ void w1_netlink_send(struct w1_master *dev, struct w1_netlink_msg *msg) | |||
47 | cn_netlink_send(m, 0, GFP_KERNEL); | 47 | cn_netlink_send(m, 0, GFP_KERNEL); |
48 | } | 48 | } |
49 | 49 | ||
50 | static int w1_process_command_master(struct w1_master *dev, struct cn_msg *msg, | 50 | static void w1_send_slave(struct w1_master *dev, u64 rn) |
51 | struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) | 51 | { |
52 | struct cn_msg *msg = dev->priv; | ||
53 | struct w1_netlink_msg *hdr = (struct w1_netlink_msg *)(msg + 1); | ||
54 | struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)(hdr + 1); | ||
55 | int avail; | ||
56 | |||
57 | avail = dev->priv_size - cmd->len; | ||
58 | |||
59 | if (avail > 8) { | ||
60 | u64 *data = (void *)(cmd + 1) + cmd->len; | ||
61 | |||
62 | *data = rn; | ||
63 | cmd->len += 8; | ||
64 | hdr->len += 8; | ||
65 | msg->len += 8; | ||
66 | return; | ||
67 | } | ||
68 | |||
69 | msg->ack++; | ||
70 | cn_netlink_send(msg, 0, GFP_KERNEL); | ||
71 | |||
72 | msg->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd); | ||
73 | hdr->len = sizeof(struct w1_netlink_cmd); | ||
74 | cmd->len = 0; | ||
75 | } | ||
76 | |||
77 | static int w1_process_search_command(struct w1_master *dev, struct cn_msg *msg, | ||
78 | unsigned int avail) | ||
52 | { | 79 | { |
53 | dev_dbg(&dev->dev, "%s: %s: cmd=%02x, len=%u.\n", | 80 | struct w1_netlink_msg *hdr = (struct w1_netlink_msg *)(msg + 1); |
54 | __func__, dev->name, cmd->cmd, cmd->len); | 81 | struct w1_netlink_cmd *cmd = (struct w1_netlink_cmd *)(hdr + 1); |
82 | int search_type = (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH; | ||
55 | 83 | ||
56 | if (cmd->cmd != W1_CMD_SEARCH && cmd->cmd != W1_CMD_ALARM_SEARCH) | 84 | dev->priv = msg; |
57 | return -EINVAL; | 85 | dev->priv_size = avail; |
86 | |||
87 | w1_search_devices(dev, search_type, w1_send_slave); | ||
88 | |||
89 | msg->ack = 0; | ||
90 | cn_netlink_send(msg, 0, GFP_KERNEL); | ||
91 | |||
92 | dev->priv = NULL; | ||
93 | dev->priv_size = 0; | ||
58 | 94 | ||
59 | w1_search_process(dev, (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH); | ||
60 | return 0; | 95 | return 0; |
61 | } | 96 | } |
62 | 97 | ||
63 | static int w1_send_read_reply(struct w1_slave *sl, struct cn_msg *msg, | 98 | static int w1_send_read_reply(struct cn_msg *msg, struct w1_netlink_msg *hdr, |
64 | struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) | 99 | struct w1_netlink_cmd *cmd) |
65 | { | 100 | { |
66 | void *data; | 101 | void *data; |
67 | struct w1_netlink_msg *h; | 102 | struct w1_netlink_msg *h; |
@@ -85,7 +120,8 @@ static int w1_send_read_reply(struct w1_slave *sl, struct cn_msg *msg, | |||
85 | memcpy(c, cmd, sizeof(struct w1_netlink_cmd)); | 120 | memcpy(c, cmd, sizeof(struct w1_netlink_cmd)); |
86 | 121 | ||
87 | cm->ack = msg->seq+1; | 122 | cm->ack = msg->seq+1; |
88 | cm->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd) + cmd->len; | 123 | cm->len = sizeof(struct w1_netlink_msg) + |
124 | sizeof(struct w1_netlink_cmd) + cmd->len; | ||
89 | 125 | ||
90 | h->len = sizeof(struct w1_netlink_cmd) + cmd->len; | 126 | h->len = sizeof(struct w1_netlink_cmd) + cmd->len; |
91 | 127 | ||
@@ -98,36 +134,178 @@ static int w1_send_read_reply(struct w1_slave *sl, struct cn_msg *msg, | |||
98 | return err; | 134 | return err; |
99 | } | 135 | } |
100 | 136 | ||
101 | static int w1_process_command_slave(struct w1_slave *sl, struct cn_msg *msg, | 137 | static int w1_process_command_io(struct w1_master *dev, struct cn_msg *msg, |
102 | struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) | 138 | struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) |
103 | { | 139 | { |
104 | int err = 0; | 140 | int err = 0; |
105 | 141 | ||
106 | dev_dbg(&sl->master->dev, "%s: %02x.%012llx.%02x: cmd=%02x, len=%u.\n", | 142 | switch (cmd->cmd) { |
107 | __func__, sl->reg_num.family, (unsigned long long)sl->reg_num.id, sl->reg_num.crc, | 143 | case W1_CMD_TOUCH: |
108 | cmd->cmd, cmd->len); | 144 | w1_touch_block(dev, cmd->data, cmd->len); |
145 | w1_send_read_reply(msg, hdr, cmd); | ||
146 | break; | ||
147 | case W1_CMD_READ: | ||
148 | w1_read_block(dev, cmd->data, cmd->len); | ||
149 | w1_send_read_reply(msg, hdr, cmd); | ||
150 | break; | ||
151 | case W1_CMD_WRITE: | ||
152 | w1_write_block(dev, cmd->data, cmd->len); | ||
153 | break; | ||
154 | default: | ||
155 | err = -EINVAL; | ||
156 | break; | ||
157 | } | ||
158 | |||
159 | return err; | ||
160 | } | ||
161 | |||
162 | static int w1_process_command_master(struct w1_master *dev, struct cn_msg *req_msg, | ||
163 | struct w1_netlink_msg *req_hdr, struct w1_netlink_cmd *req_cmd) | ||
164 | { | ||
165 | int err = -EINVAL; | ||
166 | struct cn_msg *msg; | ||
167 | struct w1_netlink_msg *hdr; | ||
168 | struct w1_netlink_cmd *cmd; | ||
169 | |||
170 | msg = kzalloc(PAGE_SIZE, GFP_KERNEL); | ||
171 | if (!msg) | ||
172 | return -ENOMEM; | ||
173 | |||
174 | msg->id = req_msg->id; | ||
175 | msg->seq = req_msg->seq; | ||
176 | msg->ack = 0; | ||
177 | msg->len = sizeof(struct w1_netlink_msg) + sizeof(struct w1_netlink_cmd); | ||
178 | |||
179 | hdr = (struct w1_netlink_msg *)(msg + 1); | ||
180 | cmd = (struct w1_netlink_cmd *)(hdr + 1); | ||
181 | |||
182 | hdr->type = W1_MASTER_CMD; | ||
183 | hdr->id = req_hdr->id; | ||
184 | hdr->len = sizeof(struct w1_netlink_cmd); | ||
185 | |||
186 | cmd->cmd = req_cmd->cmd; | ||
187 | cmd->len = 0; | ||
109 | 188 | ||
110 | switch (cmd->cmd) { | 189 | switch (cmd->cmd) { |
111 | case W1_CMD_READ: | 190 | case W1_CMD_SEARCH: |
112 | w1_read_block(sl->master, cmd->data, cmd->len); | 191 | case W1_CMD_ALARM_SEARCH: |
113 | w1_send_read_reply(sl, msg, hdr, cmd); | 192 | err = w1_process_search_command(dev, msg, |
114 | break; | 193 | PAGE_SIZE - msg->len - sizeof(struct cn_msg)); |
115 | case W1_CMD_WRITE: | 194 | break; |
116 | w1_write_block(sl->master, cmd->data, cmd->len); | 195 | case W1_CMD_READ: |
117 | break; | 196 | case W1_CMD_WRITE: |
118 | case W1_CMD_SEARCH: | 197 | case W1_CMD_TOUCH: |
119 | case W1_CMD_ALARM_SEARCH: | 198 | err = w1_process_command_io(dev, req_msg, req_hdr, req_cmd); |
120 | w1_search_process(sl->master, | 199 | break; |
121 | (cmd->cmd == W1_CMD_ALARM_SEARCH)?W1_ALARM_SEARCH:W1_SEARCH); | 200 | case W1_CMD_RESET: |
122 | break; | 201 | err = w1_reset_bus(dev); |
123 | default: | 202 | break; |
124 | err = -1; | 203 | default: |
125 | break; | 204 | err = -EINVAL; |
205 | break; | ||
126 | } | 206 | } |
127 | 207 | ||
208 | kfree(msg); | ||
128 | return err; | 209 | return err; |
129 | } | 210 | } |
130 | 211 | ||
212 | static int w1_process_command_slave(struct w1_slave *sl, struct cn_msg *msg, | ||
213 | struct w1_netlink_msg *hdr, struct w1_netlink_cmd *cmd) | ||
214 | { | ||
215 | dev_dbg(&sl->master->dev, "%s: %02x.%012llx.%02x: cmd=%02x, len=%u.\n", | ||
216 | __func__, sl->reg_num.family, (unsigned long long)sl->reg_num.id, | ||
217 | sl->reg_num.crc, cmd->cmd, cmd->len); | ||
218 | |||
219 | return w1_process_command_io(sl->master, msg, hdr, cmd); | ||
220 | } | ||
221 | |||
222 | static int w1_process_command_root(struct cn_msg *msg, struct w1_netlink_msg *mcmd) | ||
223 | { | ||
224 | struct w1_master *m; | ||
225 | struct cn_msg *cn; | ||
226 | struct w1_netlink_msg *w; | ||
227 | u32 *id; | ||
228 | |||
229 | if (mcmd->type != W1_LIST_MASTERS) { | ||
230 | printk(KERN_NOTICE "%s: msg: %x.%x, wrong type: %u, len: %u.\n", | ||
231 | __func__, msg->id.idx, msg->id.val, mcmd->type, mcmd->len); | ||
232 | return -EPROTO; | ||
233 | } | ||
234 | |||
235 | cn = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
236 | if (!cn) | ||
237 | return -ENOMEM; | ||
238 | |||
239 | cn->id.idx = CN_W1_IDX; | ||
240 | cn->id.val = CN_W1_VAL; | ||
241 | |||
242 | cn->seq = msg->seq; | ||
243 | cn->ack = 1; | ||
244 | cn->len = sizeof(struct w1_netlink_msg); | ||
245 | w = (struct w1_netlink_msg *)(cn + 1); | ||
246 | |||
247 | w->type = W1_LIST_MASTERS; | ||
248 | w->status = 0; | ||
249 | w->len = 0; | ||
250 | id = (u32 *)(w + 1); | ||
251 | |||
252 | mutex_lock(&w1_mlock); | ||
253 | list_for_each_entry(m, &w1_masters, w1_master_entry) { | ||
254 | if (cn->len + sizeof(*id) > PAGE_SIZE - sizeof(struct cn_msg)) { | ||
255 | cn_netlink_send(cn, 0, GFP_KERNEL); | ||
256 | cn->ack++; | ||
257 | cn->len = sizeof(struct w1_netlink_msg); | ||
258 | w->len = 0; | ||
259 | id = (u32 *)(w + 1); | ||
260 | } | ||
261 | |||
262 | *id = m->id; | ||
263 | w->len += sizeof(*id); | ||
264 | cn->len += sizeof(*id); | ||
265 | id++; | ||
266 | } | ||
267 | cn->ack = 0; | ||
268 | cn_netlink_send(cn, 0, GFP_KERNEL); | ||
269 | mutex_unlock(&w1_mlock); | ||
270 | |||
271 | kfree(cn); | ||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static int w1_netlink_send_error(struct cn_msg *rcmsg, struct w1_netlink_msg *rmsg, | ||
276 | struct w1_netlink_cmd *rcmd, int error) | ||
277 | { | ||
278 | struct cn_msg *cmsg; | ||
279 | struct w1_netlink_msg *msg; | ||
280 | struct w1_netlink_cmd *cmd; | ||
281 | |||
282 | cmsg = kzalloc(sizeof(*msg) + sizeof(*cmd) + sizeof(*cmsg), GFP_KERNEL); | ||
283 | if (!cmsg) | ||
284 | return -ENOMEM; | ||
285 | |||
286 | msg = (struct w1_netlink_msg *)(cmsg + 1); | ||
287 | cmd = (struct w1_netlink_cmd *)(msg + 1); | ||
288 | |||
289 | memcpy(cmsg, rcmsg, sizeof(*cmsg)); | ||
290 | cmsg->len = sizeof(*msg); | ||
291 | |||
292 | memcpy(msg, rmsg, sizeof(*msg)); | ||
293 | msg->len = 0; | ||
294 | msg->status = (short)-error; | ||
295 | |||
296 | if (rcmd) { | ||
297 | memcpy(cmd, rcmd, sizeof(*cmd)); | ||
298 | cmd->len = 0; | ||
299 | msg->len += sizeof(*cmd); | ||
300 | cmsg->len += sizeof(*cmd); | ||
301 | } | ||
302 | |||
303 | error = cn_netlink_send(cmsg, 0, GFP_KERNEL); | ||
304 | kfree(cmsg); | ||
305 | |||
306 | return error; | ||
307 | } | ||
308 | |||
131 | static void w1_cn_callback(void *data) | 309 | static void w1_cn_callback(void *data) |
132 | { | 310 | { |
133 | struct cn_msg *msg = data; | 311 | struct cn_msg *msg = data; |
@@ -144,6 +322,7 @@ static void w1_cn_callback(void *data) | |||
144 | 322 | ||
145 | dev = NULL; | 323 | dev = NULL; |
146 | sl = NULL; | 324 | sl = NULL; |
325 | cmd = NULL; | ||
147 | 326 | ||
148 | memcpy(&id, m->id.id, sizeof(id)); | 327 | memcpy(&id, m->id.id, sizeof(id)); |
149 | #if 0 | 328 | #if 0 |
@@ -155,15 +334,15 @@ static void w1_cn_callback(void *data) | |||
155 | break; | 334 | break; |
156 | } | 335 | } |
157 | 336 | ||
158 | if (!mlen) | ||
159 | goto out_cont; | ||
160 | |||
161 | if (m->type == W1_MASTER_CMD) { | 337 | if (m->type == W1_MASTER_CMD) { |
162 | dev = w1_search_master_id(m->id.mst.id); | 338 | dev = w1_search_master_id(m->id.mst.id); |
163 | } else if (m->type == W1_SLAVE_CMD) { | 339 | } else if (m->type == W1_SLAVE_CMD) { |
164 | sl = w1_search_slave(&id); | 340 | sl = w1_search_slave(&id); |
165 | if (sl) | 341 | if (sl) |
166 | dev = sl->master; | 342 | dev = sl->master; |
343 | } else { | ||
344 | err = w1_process_command_root(msg, m); | ||
345 | goto out_cont; | ||
167 | } | 346 | } |
168 | 347 | ||
169 | if (!dev) { | 348 | if (!dev) { |
@@ -171,6 +350,10 @@ static void w1_cn_callback(void *data) | |||
171 | goto out_cont; | 350 | goto out_cont; |
172 | } | 351 | } |
173 | 352 | ||
353 | err = 0; | ||
354 | if (!mlen) | ||
355 | goto out_cont; | ||
356 | |||
174 | mutex_lock(&dev->mutex); | 357 | mutex_lock(&dev->mutex); |
175 | 358 | ||
176 | if (sl && w1_reset_select_slave(sl)) { | 359 | if (sl && w1_reset_select_slave(sl)) { |
@@ -187,9 +370,12 @@ static void w1_cn_callback(void *data) | |||
187 | } | 370 | } |
188 | 371 | ||
189 | if (sl) | 372 | if (sl) |
190 | w1_process_command_slave(sl, msg, m, cmd); | 373 | err = w1_process_command_slave(sl, msg, m, cmd); |
191 | else | 374 | else |
192 | w1_process_command_master(dev, msg, m, cmd); | 375 | err = w1_process_command_master(dev, msg, m, cmd); |
376 | |||
377 | w1_netlink_send_error(msg, m, cmd, err); | ||
378 | err = 0; | ||
193 | 379 | ||
194 | cmd_data += cmd->len + sizeof(struct w1_netlink_cmd); | 380 | cmd_data += cmd->len + sizeof(struct w1_netlink_cmd); |
195 | mlen -= cmd->len + sizeof(struct w1_netlink_cmd); | 381 | mlen -= cmd->len + sizeof(struct w1_netlink_cmd); |
@@ -200,6 +386,8 @@ out_up: | |||
200 | atomic_dec(&sl->refcnt); | 386 | atomic_dec(&sl->refcnt); |
201 | mutex_unlock(&dev->mutex); | 387 | mutex_unlock(&dev->mutex); |
202 | out_cont: | 388 | out_cont: |
389 | if (!cmd || err) | ||
390 | w1_netlink_send_error(msg, m, cmd, err); | ||
203 | msg->len -= sizeof(struct w1_netlink_msg) + m->len; | 391 | msg->len -= sizeof(struct w1_netlink_msg) + m->len; |
204 | m = (struct w1_netlink_msg *)(((u8 *)m) + sizeof(struct w1_netlink_msg) + m->len); | 392 | m = (struct w1_netlink_msg *)(((u8 *)m) + sizeof(struct w1_netlink_msg) + m->len); |
205 | 393 | ||
@@ -209,11 +397,6 @@ out_cont: | |||
209 | if (err == -ENODEV) | 397 | if (err == -ENODEV) |
210 | err = 0; | 398 | err = 0; |
211 | } | 399 | } |
212 | #if 0 | ||
213 | if (err) { | ||
214 | printk("%s: malformed message. Dropping.\n", __func__); | ||
215 | } | ||
216 | #endif | ||
217 | } | 400 | } |
218 | 401 | ||
219 | int w1_init_netlink(void) | 402 | int w1_init_netlink(void) |
diff --git a/drivers/w1/w1_netlink.h b/drivers/w1/w1_netlink.h index 56122b9e929..27e950f935b 100644 --- a/drivers/w1/w1_netlink.h +++ b/drivers/w1/w1_netlink.h | |||
@@ -34,12 +34,13 @@ enum w1_netlink_message_types { | |||
34 | W1_MASTER_REMOVE, | 34 | W1_MASTER_REMOVE, |
35 | W1_MASTER_CMD, | 35 | W1_MASTER_CMD, |
36 | W1_SLAVE_CMD, | 36 | W1_SLAVE_CMD, |
37 | W1_LIST_MASTERS, | ||
37 | }; | 38 | }; |
38 | 39 | ||
39 | struct w1_netlink_msg | 40 | struct w1_netlink_msg |
40 | { | 41 | { |
41 | __u8 type; | 42 | __u8 type; |
42 | __u8 reserved; | 43 | __u8 status; |
43 | __u16 len; | 44 | __u16 len; |
44 | union { | 45 | union { |
45 | __u8 id[8]; | 46 | __u8 id[8]; |
@@ -51,10 +52,15 @@ struct w1_netlink_msg | |||
51 | __u8 data[0]; | 52 | __u8 data[0]; |
52 | }; | 53 | }; |
53 | 54 | ||
54 | #define W1_CMD_READ 0x0 | 55 | enum w1_commands { |
55 | #define W1_CMD_WRITE 0x1 | 56 | W1_CMD_READ = 0, |
56 | #define W1_CMD_SEARCH 0x2 | 57 | W1_CMD_WRITE, |
57 | #define W1_CMD_ALARM_SEARCH 0x3 | 58 | W1_CMD_SEARCH, |
59 | W1_CMD_ALARM_SEARCH, | ||
60 | W1_CMD_TOUCH, | ||
61 | W1_CMD_RESET, | ||
62 | W1_CMD_MAX, | ||
63 | }; | ||
58 | 64 | ||
59 | struct w1_netlink_cmd | 65 | struct w1_netlink_cmd |
60 | { | 66 | { |