aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/w1/w1.c
diff options
context:
space:
mode:
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