aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/w1/w1.c
diff options
context:
space:
mode:
authorDavid Fries <david@fries.net>2008-10-16 01:04:43 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-10-16 14:21:49 -0400
commit9b46741119590bf23c5c519b49024eb2001cfafa (patch)
treea13e3a46148861e9ffe0cb8c0de66c3ce2c7199e /drivers/w1/w1.c
parent6cd159744eaf212f3729d154f3881230a7c19eb2 (diff)
W1: be able to manually add and remove slaves
sysfs entries were added to manually add and remove slave devices. This is useful if the automatic bus searching is disabled, and the device ids are already known. [akpm@linux-foundation.org: fix printk types] Signed-off-by: David Fries <david@fries.net> Signed-off-by: Evgeniy Polyakov <johnpol@2ka.mipt.ru> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/w1/w1.c')
-rw-r--r--drivers/w1/w1.c138
1 files changed, 137 insertions, 1 deletions
diff --git a/drivers/w1/w1.c b/drivers/w1/w1.c
index 32418d4e555a..f3be2991e6e8 100644
--- a/drivers/w1/w1.c
+++ b/drivers/w1/w1.c
@@ -56,6 +56,8 @@ module_param_named(slave_ttl, w1_max_slave_ttl, int, 0);
56DEFINE_MUTEX(w1_mlock); 56DEFINE_MUTEX(w1_mlock);
57LIST_HEAD(w1_masters); 57LIST_HEAD(w1_masters);
58 58
59static int w1_attach_slave_device(struct w1_master *dev, struct w1_reg_num *rn);
60
59static int w1_master_match(struct device *dev, struct device_driver *drv) 61static int w1_master_match(struct device *dev, struct device_driver *drv)
60{ 62{
61 return 1; 63 return 1;
@@ -357,7 +359,8 @@ static ssize_t w1_master_attribute_show_slave_count(struct device *dev, struct d
357 return count; 359 return count;
358} 360}
359 361
360static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device_attribute *attr, char *buf) 362static ssize_t w1_master_attribute_show_slaves(struct device *dev,
363 struct device_attribute *attr, char *buf)
361{ 364{
362 struct w1_master *md = dev_to_w1_master(dev); 365 struct w1_master *md = dev_to_w1_master(dev);
363 int c = PAGE_SIZE; 366 int c = PAGE_SIZE;
@@ -382,6 +385,135 @@ static ssize_t w1_master_attribute_show_slaves(struct device *dev, struct device
382 return PAGE_SIZE - c; 385 return PAGE_SIZE - c;
383} 386}
384 387
388static ssize_t w1_master_attribute_show_add(struct device *dev,
389 struct device_attribute *attr, char *buf)
390{
391 int c = PAGE_SIZE;
392 c -= snprintf(buf+PAGE_SIZE - c, c,
393 "write device id xx-xxxxxxxxxxxx to add slave\n");
394 return PAGE_SIZE - c;
395}
396
397static int w1_atoreg_num(struct device *dev, const char *buf, size_t count,
398 struct w1_reg_num *rn)
399{
400 unsigned int family;
401 unsigned long long id;
402 int i;
403 u64 rn64_le;
404
405 /* The CRC value isn't read from the user because the sysfs directory
406 * doesn't include it and most messages from the bus search don't
407 * print it either. It would be unreasonable for the user to then
408 * provide it.
409 */
410 const char *error_msg = "bad slave string format, expecting "
411 "ff-dddddddddddd\n";
412
413 if (buf[2] != '-') {
414 dev_err(dev, "%s", error_msg);
415 return -EINVAL;
416 }
417 i = sscanf(buf, "%02x-%012llx", &family, &id);
418 if (i != 2) {
419 dev_err(dev, "%s", error_msg);
420 return -EINVAL;
421 }
422 rn->family = family;
423 rn->id = id;
424
425 rn64_le = cpu_to_le64(*(u64 *)rn);
426 rn->crc = w1_calc_crc8((u8 *)&rn64_le, 7);
427
428#if 0
429 dev_info(dev, "With CRC device is %02x.%012llx.%02x.\n",
430 rn->family, (unsigned long long)rn->id, rn->crc);
431#endif
432
433 return 0;
434}
435
436/* Searches the slaves in the w1_master and returns a pointer or NULL.
437 * Note: must hold the mutex
438 */
439static struct w1_slave *w1_slave_search_device(struct w1_master *dev,
440 struct w1_reg_num *rn)
441{
442 struct w1_slave *sl;
443 list_for_each_entry(sl, &dev->slist, w1_slave_entry) {
444 if (sl->reg_num.family == rn->family &&
445 sl->reg_num.id == rn->id &&
446 sl->reg_num.crc == rn->crc) {
447 return sl;
448 }
449 }
450 return NULL;
451}
452
453static ssize_t w1_master_attribute_store_add(struct device *dev,
454 struct device_attribute *attr,
455 const char *buf, size_t count)
456{
457 struct w1_master *md = dev_to_w1_master(dev);
458 struct w1_reg_num rn;
459 struct w1_slave *sl;
460 ssize_t result = count;
461
462 if (w1_atoreg_num(dev, buf, count, &rn))
463 return -EINVAL;
464
465 mutex_lock(&md->mutex);
466 sl = w1_slave_search_device(md, &rn);
467 /* It would be nice to do a targeted search one the one-wire bus
468 * for the new device to see if it is out there or not. But the
469 * current search doesn't support that.
470 */
471 if (sl) {
472 dev_info(dev, "Device %s already exists\n", sl->name);
473 result = -EINVAL;
474 } else {
475 w1_attach_slave_device(md, &rn);
476 }
477 mutex_unlock(&md->mutex);
478
479 return result;
480}
481
482static ssize_t w1_master_attribute_show_remove(struct device *dev,
483 struct device_attribute *attr, char *buf)
484{
485 int c = PAGE_SIZE;
486 c -= snprintf(buf+PAGE_SIZE - c, c,
487 "write device id xx-xxxxxxxxxxxx to remove slave\n");
488 return PAGE_SIZE - c;
489}
490
491static ssize_t w1_master_attribute_store_remove(struct device *dev,
492 struct device_attribute *attr,
493 const char *buf, size_t count)
494{
495 struct w1_master *md = dev_to_w1_master(dev);
496 struct w1_reg_num rn;
497 struct w1_slave *sl;
498 ssize_t result = count;
499
500 if (w1_atoreg_num(dev, buf, count, &rn))
501 return -EINVAL;
502
503 mutex_lock(&md->mutex);
504 sl = w1_slave_search_device(md, &rn);
505 if (sl) {
506 w1_slave_detach(sl);
507 } else {
508 dev_info(dev, "Device %02x-%012llx doesn't exists\n", rn.family,
509 (unsigned long long)rn.id);
510 result = -EINVAL;
511 }
512 mutex_unlock(&md->mutex);
513
514 return result;
515}
516
385#define W1_MASTER_ATTR_RO(_name, _mode) \ 517#define W1_MASTER_ATTR_RO(_name, _mode) \
386 struct device_attribute w1_master_attribute_##_name = \ 518 struct device_attribute w1_master_attribute_##_name = \
387 __ATTR(w1_master_##_name, _mode, \ 519 __ATTR(w1_master_##_name, _mode, \
@@ -402,6 +534,8 @@ static W1_MASTER_ATTR_RO(timeout, S_IRUGO);
402static W1_MASTER_ATTR_RO(pointer, S_IRUGO); 534static W1_MASTER_ATTR_RO(pointer, S_IRUGO);
403static W1_MASTER_ATTR_RW(search, S_IRUGO | S_IWUGO); 535static W1_MASTER_ATTR_RW(search, S_IRUGO | S_IWUGO);
404static W1_MASTER_ATTR_RW(pullup, S_IRUGO | S_IWUGO); 536static W1_MASTER_ATTR_RW(pullup, S_IRUGO | S_IWUGO);
537static W1_MASTER_ATTR_RW(add, S_IRUGO | S_IWUGO);
538static W1_MASTER_ATTR_RW(remove, S_IRUGO | S_IWUGO);
405 539
406static struct attribute *w1_master_default_attrs[] = { 540static struct attribute *w1_master_default_attrs[] = {
407 &w1_master_attribute_name.attr, 541 &w1_master_attribute_name.attr,
@@ -413,6 +547,8 @@ static struct attribute *w1_master_default_attrs[] = {
413 &w1_master_attribute_pointer.attr, 547 &w1_master_attribute_pointer.attr,
414 &w1_master_attribute_search.attr, 548 &w1_master_attribute_search.attr,
415 &w1_master_attribute_pullup.attr, 549 &w1_master_attribute_pullup.attr,
550 &w1_master_attribute_add.attr,
551 &w1_master_attribute_remove.attr,
416 NULL 552 NULL
417}; 553};
418 554