diff options
author | Evgeniy Polyakov <johnpol@2ka.mipt.ru> | 2005-06-03 17:30:43 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-06-22 00:43:11 -0400 |
commit | 6b729861831177b270a2932a13e79cb41d673146 (patch) | |
tree | 443c86578d04ba42d9b4e483d6ebee91ba30d25e /drivers | |
parent | be57ce267fd558c52d2389530c15618681b7cfa7 (diff) |
[PATCH] w1: Added the triplet w1 master method and changes w1_search() to use it.
Adds the triplet w1 master method and changes w1_search() to use it.
Signed-off-by: Ben Gardner <bgardner@wabtec.com>
Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/w1/w1.c | 138 | ||||
-rw-r--r-- | drivers/w1/w1.h | 87 | ||||
-rw-r--r-- | drivers/w1/w1_io.c | 43 | ||||
-rw-r--r-- | drivers/w1/w1_io.h | 1 |
4 files changed, 175 insertions, 94 deletions
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c index c85d75ed835a..4fa959f08554 100644 --- a/drivers/w1/w1.c +++ b/drivers/w1/w1.c | |||
@@ -135,7 +135,7 @@ struct device w1_device = { | |||
135 | 135 | ||
136 | static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_attribute *attr, char *buf) | 136 | static ssize_t w1_master_attribute_show_name(struct device *dev, struct device_attribute *attr, char *buf) |
137 | { | 137 | { |
138 | struct w1_master *md = container_of (dev, struct w1_master, dev); | 138 | struct w1_master *md = container_of(dev, struct w1_master, dev); |
139 | ssize_t count; | 139 | ssize_t count; |
140 | 140 | ||
141 | if (down_interruptible (&md->mutex)) | 141 | if (down_interruptible (&md->mutex)) |
@@ -212,7 +212,6 @@ static ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct d | |||
212 | } | 212 | } |
213 | 213 | ||
214 | static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device_attribute *attr, char *buf) | 214 | static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device_attribute *attr, char *buf) |
215 | |||
216 | { | 215 | { |
217 | struct w1_master *md = container_of(dev, struct w1_master, dev); | 216 | struct w1_master *md = container_of(dev, struct w1_master, dev); |
218 | int c = PAGE_SIZE; | 217 | int c = PAGE_SIZE; |
@@ -286,13 +285,13 @@ static int __w1_attach_slave_device(struct w1_slave *sl) | |||
286 | sl->dev.release = &w1_slave_release; | 285 | sl->dev.release = &w1_slave_release; |
287 | 286 | ||
288 | snprintf(&sl->dev.bus_id[0], sizeof(sl->dev.bus_id), | 287 | snprintf(&sl->dev.bus_id[0], sizeof(sl->dev.bus_id), |
289 | "%02x-%012llx", | 288 | "%02x-%012llx", |
290 | (unsigned int) sl->reg_num.family, | 289 | (unsigned int) sl->reg_num.family, |
291 | (unsigned long long) sl->reg_num.id); | 290 | (unsigned long long) sl->reg_num.id); |
292 | snprintf (&sl->name[0], sizeof(sl->name), | 291 | snprintf(&sl->name[0], sizeof(sl->name), |
293 | "%02x-%012llx", | 292 | "%02x-%012llx", |
294 | (unsigned int) sl->reg_num.family, | 293 | (unsigned int) sl->reg_num.family, |
295 | (unsigned long long) sl->reg_num.id); | 294 | (unsigned long long) sl->reg_num.id); |
296 | 295 | ||
297 | dev_dbg(&sl->dev, "%s: registering %s.\n", __func__, | 296 | dev_dbg(&sl->dev, "%s: registering %s.\n", __func__, |
298 | &sl->dev.bus_id[0]); | 297 | &sl->dev.bus_id[0]); |
@@ -300,8 +299,8 @@ static int __w1_attach_slave_device(struct w1_slave *sl) | |||
300 | err = device_register(&sl->dev); | 299 | err = device_register(&sl->dev); |
301 | if (err < 0) { | 300 | if (err < 0) { |
302 | dev_err(&sl->dev, | 301 | dev_err(&sl->dev, |
303 | "Device registration [%s] failed. err=%d\n", | 302 | "Device registration [%s] failed. err=%d\n", |
304 | sl->dev.bus_id, err); | 303 | sl->dev.bus_id, err); |
305 | return err; | 304 | return err; |
306 | } | 305 | } |
307 | 306 | ||
@@ -314,8 +313,8 @@ static int __w1_attach_slave_device(struct w1_slave *sl) | |||
314 | err = device_create_file(&sl->dev, &sl->attr_name); | 313 | err = device_create_file(&sl->dev, &sl->attr_name); |
315 | if (err < 0) { | 314 | if (err < 0) { |
316 | dev_err(&sl->dev, | 315 | dev_err(&sl->dev, |
317 | "sysfs file creation for [%s] failed. err=%d\n", | 316 | "sysfs file creation for [%s] failed. err=%d\n", |
318 | sl->dev.bus_id, err); | 317 | sl->dev.bus_id, err); |
319 | device_unregister(&sl->dev); | 318 | device_unregister(&sl->dev); |
320 | return err; | 319 | return err; |
321 | } | 320 | } |
@@ -323,8 +322,8 @@ static int __w1_attach_slave_device(struct w1_slave *sl) | |||
323 | err = sysfs_create_bin_file(&sl->dev.kobj, &sl->attr_bin); | 322 | err = sysfs_create_bin_file(&sl->dev.kobj, &sl->attr_bin); |
324 | if (err < 0) { | 323 | if (err < 0) { |
325 | dev_err(&sl->dev, | 324 | dev_err(&sl->dev, |
326 | "sysfs file creation for [%s] failed. err=%d\n", | 325 | "sysfs file creation for [%s] failed. err=%d\n", |
327 | sl->dev.bus_id, err); | 326 | sl->dev.bus_id, err); |
328 | device_remove_file(&sl->dev, &sl->attr_name); | 327 | device_remove_file(&sl->dev, &sl->attr_name); |
329 | device_unregister(&sl->dev); | 328 | device_unregister(&sl->dev); |
330 | return err; | 329 | return err; |
@@ -483,26 +482,39 @@ static void w1_slave_found(unsigned long data, u64 rn) | |||
483 | atomic_dec(&dev->refcnt); | 482 | atomic_dec(&dev->refcnt); |
484 | } | 483 | } |
485 | 484 | ||
486 | void w1_search(struct w1_master *dev) | 485 | /** |
486 | * Performs a ROM Search & registers any devices found. | ||
487 | * The 1-wire search is a simple binary tree search. | ||
488 | * For each bit of the address, we read two bits and write one bit. | ||
489 | * The bit written will put to sleep all devies that don't match that bit. | ||
490 | * When the two reads differ, the direction choice is obvious. | ||
491 | * When both bits are 0, we must choose a path to take. | ||
492 | * When we can scan all 64 bits without having to choose a path, we are done. | ||
493 | * | ||
494 | * See "Application note 187 1-wire search algorithm" at www.maxim-ic.com | ||
495 | * | ||
496 | * @dev The master device to search | ||
497 | * @cb Function to call when a device is found | ||
498 | */ | ||
499 | void w1_search(struct w1_master *dev, w1_slave_found_callback cb) | ||
487 | { | 500 | { |
488 | u64 last, rn, tmp; | 501 | u64 last_rn, rn, tmp64; |
489 | int i, count = 0; | 502 | int i, slave_count = 0; |
490 | int last_family_desc, last_zero, last_device; | 503 | int last_zero, last_device; |
491 | int search_bit, id_bit, comp_bit, desc_bit; | 504 | int search_bit, desc_bit; |
505 | u8 triplet_ret = 0; | ||
492 | 506 | ||
493 | search_bit = id_bit = comp_bit = 0; | 507 | search_bit = 0; |
494 | rn = tmp = last = 0; | 508 | rn = last_rn = 0; |
495 | last_device = last_zero = last_family_desc = 0; | 509 | last_device = 0; |
510 | last_zero = -1; | ||
496 | 511 | ||
497 | desc_bit = 64; | 512 | desc_bit = 64; |
498 | 513 | ||
499 | while (!(id_bit && comp_bit) && !last_device && | 514 | while ( !last_device && (slave_count++ < dev->max_slave_count) ) { |
500 | count++ < dev->max_slave_count) { | 515 | last_rn = rn; |
501 | last = rn; | ||
502 | rn = 0; | 516 | rn = 0; |
503 | 517 | ||
504 | last_family_desc = 0; | ||
505 | |||
506 | /* | 518 | /* |
507 | * Reset bus and all 1-wire device state machines | 519 | * Reset bus and all 1-wire device state machines |
508 | * so they can respond to our requests. | 520 | * so they can respond to our requests. |
@@ -514,59 +526,39 @@ void w1_search(struct w1_master *dev) | |||
514 | break; | 526 | break; |
515 | } | 527 | } |
516 | 528 | ||
517 | #if 1 | 529 | /* Start the search */ |
518 | w1_write_8(dev, W1_SEARCH); | 530 | w1_write_8(dev, W1_SEARCH); |
519 | for (i = 0; i < 64; ++i) { | 531 | for (i = 0; i < 64; ++i) { |
520 | /* | 532 | /* Determine the direction/search bit */ |
521 | * Read 2 bits from bus. | 533 | if (i == desc_bit) |
522 | * All who don't sleep must send ID bit and COMPLEMENT ID bit. | 534 | search_bit = 1; /* took the 0 path last time, so take the 1 path */ |
523 | * They actually are ANDed between all senders. | 535 | else if (i > desc_bit) |
524 | */ | 536 | search_bit = 0; /* take the 0 path on the next branch */ |
525 | id_bit = w1_touch_bit(dev, 1); | 537 | else |
526 | comp_bit = w1_touch_bit(dev, 1); | 538 | search_bit = ((last_rn >> i) & 0x1); |
527 | |||
528 | if (id_bit && comp_bit) | ||
529 | break; | ||
530 | |||
531 | if (id_bit == 0 && comp_bit == 0) { | ||
532 | if (i == desc_bit) | ||
533 | search_bit = 1; | ||
534 | else if (i > desc_bit) | ||
535 | search_bit = 0; | ||
536 | else | ||
537 | search_bit = ((last >> i) & 0x1); | ||
538 | |||
539 | if (search_bit == 0) { | ||
540 | last_zero = i; | ||
541 | if (last_zero < 9) | ||
542 | last_family_desc = last_zero; | ||
543 | } | ||
544 | 539 | ||
545 | } else | 540 | /** Read two bits and write one bit */ |
546 | search_bit = id_bit; | 541 | triplet_ret = w1_triplet(dev, search_bit); |
547 | 542 | ||
548 | tmp = search_bit; | 543 | /* quit if no device responded */ |
549 | rn |= (tmp << i); | 544 | if ( (triplet_ret & 0x03) == 0x03 ) |
545 | break; | ||
550 | 546 | ||
551 | /* | 547 | /* If both directions were valid, and we took the 0 path... */ |
552 | * Write 1 bit to bus | 548 | if (triplet_ret == 0) |
553 | * and make all who don't have "search_bit" in "i"'th position | 549 | last_zero = i; |
554 | * in it's registration number sleep. | ||
555 | */ | ||
556 | if (dev->bus_master->touch_bit) | ||
557 | w1_touch_bit(dev, search_bit); | ||
558 | else | ||
559 | w1_write_bit(dev, search_bit); | ||
560 | 550 | ||
551 | /* extract the direction taken & update the device number */ | ||
552 | tmp64 = (triplet_ret >> 2); | ||
553 | rn |= (tmp64 << i); | ||
561 | } | 554 | } |
562 | #endif | ||
563 | |||
564 | if (desc_bit == last_zero) | ||
565 | last_device = 1; | ||
566 | 555 | ||
567 | desc_bit = last_zero; | 556 | if ( (triplet_ret & 0x03) != 0x03 ) { |
568 | 557 | if ( (desc_bit == last_zero) || (last_zero < 0)) | |
569 | w1_slave_found(dev->bus_master->data, rn); | 558 | last_device = 1; |
559 | desc_bit = last_zero; | ||
560 | cb(dev->bus_master->data, rn); | ||
561 | } | ||
570 | } | 562 | } |
571 | } | 563 | } |
572 | 564 | ||
diff --git a/drivers/w1/w1.h b/drivers/w1/w1.h index 44dfb92e55cd..3cfdd08d32fc 100644 --- a/drivers/w1/w1.h +++ b/drivers/w1/w1.h | |||
@@ -25,9 +25,9 @@ | |||
25 | struct w1_reg_num | 25 | struct w1_reg_num |
26 | { | 26 | { |
27 | #if defined(__LITTLE_ENDIAN_BITFIELD) | 27 | #if defined(__LITTLE_ENDIAN_BITFIELD) |
28 | __u64 family:8, | 28 | __u64 family:8, |
29 | id:48, | 29 | id:48, |
30 | crc:8; | 30 | crc:8; |
31 | #elif defined(__BIG_ENDIAN_BITFIELD) | 31 | #elif defined(__BIG_ENDIAN_BITFIELD) |
32 | __u64 crc:8, | 32 | __u64 crc:8, |
33 | id:48, | 33 | id:48, |
@@ -84,24 +84,71 @@ struct w1_slave | |||
84 | 84 | ||
85 | typedef void (* w1_slave_found_callback)(unsigned long, u64); | 85 | typedef void (* w1_slave_found_callback)(unsigned long, u64); |
86 | 86 | ||
87 | |||
88 | /** | ||
89 | * Note: read_bit and write_bit are very low level functions and should only | ||
90 | * be used with hardware that doesn't really support 1-wire operations, | ||
91 | * like a parallel/serial port. | ||
92 | * Either define read_bit and write_bit OR define, at minimum, touch_bit and | ||
93 | * reset_bus. | ||
94 | */ | ||
87 | struct w1_bus_master | 95 | struct w1_bus_master |
88 | { | 96 | { |
89 | unsigned long data; | 97 | /** the first parameter in all the functions below */ |
90 | 98 | unsigned long data; | |
91 | u8 (*read_bit)(unsigned long); | 99 | |
92 | void (*write_bit)(unsigned long, u8); | 100 | /** |
93 | 101 | * Sample the line level | |
94 | u8 (*read_byte)(unsigned long); | 102 | * @return the level read (0 or 1) |
95 | void (*write_byte)(unsigned long, u8); | 103 | */ |
96 | 104 | u8 (*read_bit)(unsigned long); | |
97 | u8 (*read_block)(unsigned long, u8 *, int); | 105 | |
98 | void (*write_block)(unsigned long, u8 *, int); | 106 | /** Sets the line level */ |
99 | 107 | void (*write_bit)(unsigned long, u8); | |
100 | u8 (*touch_bit)(unsigned long, u8); | 108 | |
101 | 109 | /** | |
102 | u8 (*reset_bus)(unsigned long); | 110 | * touch_bit is the lowest-level function for devices that really |
103 | 111 | * support the 1-wire protocol. | |
104 | void (*search)(unsigned long, w1_slave_found_callback); | 112 | * touch_bit(0) = write-0 cycle |
113 | * touch_bit(1) = write-1 / read cycle | ||
114 | * @return the bit read (0 or 1) | ||
115 | */ | ||
116 | u8 (*touch_bit)(unsigned long, u8); | ||
117 | |||
118 | /** | ||
119 | * Reads a bytes. Same as 8 touch_bit(1) calls. | ||
120 | * @return the byte read | ||
121 | */ | ||
122 | u8 (*read_byte)(unsigned long); | ||
123 | |||
124 | /** | ||
125 | * Writes a byte. Same as 8 touch_bit(x) calls. | ||
126 | */ | ||
127 | void (*write_byte)(unsigned long, u8); | ||
128 | |||
129 | /** | ||
130 | * Same as a series of read_byte() calls | ||
131 | * @return the number of bytes read | ||
132 | */ | ||
133 | u8 (*read_block)(unsigned long, u8 *, int); | ||
134 | |||
135 | /** Same as a series of write_byte() calls */ | ||
136 | void (*write_block)(unsigned long, const u8 *, int); | ||
137 | |||
138 | /** | ||
139 | * Combines two reads and a smart write for ROM searches | ||
140 | * @return bit0=Id bit1=comp_id bit2=dir_taken | ||
141 | */ | ||
142 | u8 (*triplet)(unsigned long, u8); | ||
143 | |||
144 | /** | ||
145 | * long write-0 with a read for the presence pulse detection | ||
146 | * @return -1=Error, 0=Device present, 1=No device present | ||
147 | */ | ||
148 | u8 (*reset_bus)(unsigned long); | ||
149 | |||
150 | /** Really nice hardware can handles the ROM searches */ | ||
151 | void (*search)(unsigned long, w1_slave_found_callback); | ||
105 | }; | 152 | }; |
106 | 153 | ||
107 | struct w1_master | 154 | struct w1_master |
@@ -137,7 +184,7 @@ struct w1_master | |||
137 | }; | 184 | }; |
138 | 185 | ||
139 | int w1_create_master_attributes(struct w1_master *); | 186 | int w1_create_master_attributes(struct w1_master *); |
140 | void w1_search(struct w1_master *dev); | 187 | void w1_search(struct w1_master *dev, w1_slave_found_callback cb); |
141 | 188 | ||
142 | #endif /* __KERNEL__ */ | 189 | #endif /* __KERNEL__ */ |
143 | 190 | ||
diff --git a/drivers/w1/w1_io.c b/drivers/w1/w1_io.c index 2173336b60a7..00f032220173 100644 --- a/drivers/w1/w1_io.c +++ b/drivers/w1/w1_io.c | |||
@@ -130,6 +130,47 @@ static u8 w1_read_bit(struct w1_master *dev) | |||
130 | } | 130 | } |
131 | 131 | ||
132 | /** | 132 | /** |
133 | * Does a triplet - used for searching ROM addresses. | ||
134 | * Return bits: | ||
135 | * bit 0 = id_bit | ||
136 | * bit 1 = comp_bit | ||
137 | * bit 2 = dir_taken | ||
138 | * If both bits 0 & 1 are set, the search should be restarted. | ||
139 | * | ||
140 | * @param dev the master device | ||
141 | * @param bdir the bit to write if both id_bit and comp_bit are 0 | ||
142 | * @return bit fields - see above | ||
143 | */ | ||
144 | u8 w1_triplet(struct w1_master *dev, int bdir) | ||
145 | { | ||
146 | if ( dev->bus_master->triplet ) | ||
147 | return(dev->bus_master->triplet(dev->bus_master->data, bdir)); | ||
148 | else { | ||
149 | u8 id_bit = w1_touch_bit(dev, 1); | ||
150 | u8 comp_bit = w1_touch_bit(dev, 1); | ||
151 | u8 retval; | ||
152 | |||
153 | if ( id_bit && comp_bit ) | ||
154 | return(0x03); /* error */ | ||
155 | |||
156 | if ( !id_bit && !comp_bit ) { | ||
157 | /* Both bits are valid, take the direction given */ | ||
158 | retval = bdir ? 0x04 : 0; | ||
159 | } else { | ||
160 | /* Only one bit is valid, take that direction */ | ||
161 | bdir = id_bit; | ||
162 | retval = id_bit ? 0x05 : 0x02; | ||
163 | } | ||
164 | |||
165 | if ( dev->bus_master->touch_bit ) | ||
166 | w1_touch_bit(dev, bdir); | ||
167 | else | ||
168 | w1_write_bit(dev, bdir); | ||
169 | return(retval); | ||
170 | } | ||
171 | } | ||
172 | |||
173 | /** | ||
133 | * Reads 8 bits. | 174 | * Reads 8 bits. |
134 | * | 175 | * |
135 | * @param dev the master device | 176 | * @param dev the master device |
@@ -233,7 +274,7 @@ void w1_search_devices(struct w1_master *dev, w1_slave_found_callback cb) | |||
233 | if (dev->bus_master->search) | 274 | if (dev->bus_master->search) |
234 | dev->bus_master->search(dev->bus_master->data, cb); | 275 | dev->bus_master->search(dev->bus_master->data, cb); |
235 | else | 276 | else |
236 | w1_search(dev); | 277 | w1_search(dev, cb); |
237 | } | 278 | } |
238 | 279 | ||
239 | EXPORT_SYMBOL(w1_touch_bit); | 280 | EXPORT_SYMBOL(w1_touch_bit); |
diff --git a/drivers/w1/w1_io.h b/drivers/w1/w1_io.h index d6daa3189c61..af5829778aaa 100644 --- a/drivers/w1/w1_io.h +++ b/drivers/w1/w1_io.h | |||
@@ -26,6 +26,7 @@ | |||
26 | 26 | ||
27 | void w1_delay(unsigned long); | 27 | void w1_delay(unsigned long); |
28 | u8 w1_touch_bit(struct w1_master *, int); | 28 | u8 w1_touch_bit(struct w1_master *, int); |
29 | u8 w1_triplet(struct w1_master *dev, int bdir); | ||
29 | void w1_write_8(struct w1_master *, u8); | 30 | void w1_write_8(struct w1_master *, u8); |
30 | u8 w1_read_8(struct w1_master *); | 31 | u8 w1_read_8(struct w1_master *); |
31 | int w1_reset_bus(struct w1_master *); | 32 | int w1_reset_bus(struct w1_master *); |