Hello,

I've developed a onewire driver for the DS2XXX one wire EEPROMs (such as
DS2431). In the email you should find the .c and the .h files attached
containing the lowerhalf driver. Before the PR on GitHub, I'd like to hear
your opinions on my implementation.

I shall put this file into drivers/eeprom, as this makes more sense. You
should perform writes, reads and lseeks on this eeprom as it acts as a
file. I've tested this in my application and it seems to be fully
functional, I was inspired by the 24xxxx driver.

However, I'd like to address some issues I am not really sure about. I ran
into a compilation problem when I tried to define the priv with the
onewire_master_s struct. Also, I do not see any point in using
onewire_master_s instead of onewire_dev_s (the lowerhalf driver) other than
you can use struct onewire_master_s to perform the ROM bus scan. Moreover I
need to interface multiple eeproms on the same bus - I solved this by using
an ioctl call which just assigns the target rom to a uint64_t variable
located in priv. All the available devices on the network can be scanned by
this hack of mine: I defined a boardctl all which just calls onewire_search
(here, the compilation somehow works as it needs onewire_master_s). All
scanned ROMS are saved in the userspace application and then via the ioctl
call I update the internal ROM variable.

The previous paragraph implies that I don't really get the purpose of
onewire_master_s, when I can just use the lowlevel onewire_dev_s. I think
the 1wire driver should be restructuralized that it features an unified API
for rom scanning (for example ROMSCANIOC) that returns devices' ROMs
corresponding to the driver's family code. Then other ioctl call (such as
SETROMIOC) "selects" the devices which should be interfaced.

I agree this is not really ideal and the ideal solution would involve
periodic scanning of the bus and then dynamically registering/unregistering
the devices in the file system (such as /sys in linux) but I think this
really goes against the lightweight philosophy of nuttx.

Also some delays are needed between the scratchpad writes to the eeprom.
Now I'm using up_udelay which should not be multitasking friendly - are
there any other approaches that allow for multitasking friendly delays in
the driver? What about workqueue?

Thanks in advance and BR,
Štěpán Pressl
/****************************************************************************
 * drivers/eeprom/1wire_ds2xxx.c
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.  The
 * ASF licenses this file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the
 * License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 ****************************************************************************/

/* This is a driver for 1Wire Maxim Integrated DS2xxx EEPROMs.
 * Currently, the driver was tested against the DS2431 EEPROM but other
 * EEPROMs listed in 1wire_ds2xxx.h
 */

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <assert.h>
#include <nuttx/config.h>

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <inttypes.h>
#include <debug.h>
#include <nuttx/fs/fs.h>

#include <nuttx/kmalloc.h>
#include <nuttx/mutex.h>
#include <nuttx/1wire/1wire.h>
#include <nuttx/1wire/1wire_crc.h>
#include <nuttx/eeprom/1wire_ds2xxx.h>

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

#ifndef CONFIG_ENDIAN_BIG
#  define onewire_leuint64(x) (x)
#  define onewire_leuint32(x) (x)
#endif

#define WS_HEADER_OFFSET   ((uint8_t)3)
#define RS_HEADER_SIZE     ((uint8_t)3)
#define CS_HEADER_SIZE     ((uint8_t)4)
#define HELPBUF_MARGIN     ((uint8_t)5)
#define MATCHROM_BUF_SIZE  ((uint8_t)9)
#define DS2XXX_TPROG_US    ((useconds_t)12000)

/****************************************************************************
 * Priavate Types
 ****************************************************************************/

struct ds2xxx_dev_s
{
  FAR struct onewire_dev_s *dev;

  uint64_t romcode;
  int devtype;
  uint8_t *helpbuf;

  mutex_t lock;
  uint8_t refs;
};

/****************************************************************************
 * Private Function Prototypes
 ****************************************************************************/

static int     ds2xxx_open(FAR struct file *filep);
static int     ds2xxx_close(FAR struct file *filep);
static int     ds2xxx_ioctl(FAR struct file *filep, int cmd,
                             unsigned long arg);
static ssize_t ds2xxx_read(FAR struct file *filep, FAR char *buffer,
                            size_t buflen);
static ssize_t ds2xxx_read_internal(FAR struct ds2xxx_dev_s *priv,
                                    off_t eeprom_addr,
                                    FAR uint8_t *buffer, size_t buflen);
static ssize_t ds2xxx_write(FAR struct file *filep, FAR const char *buffer,
                             size_t buflen);
static ssize_t ds2xxx_write_internal(FAR struct ds2xxx_dev_s *priv,
                                     off_t eeprom_addr,
                                     FAR uint8_t *buffer, size_t buflen);
static off_t   ds2xxx_seek(FAR struct file *filep, off_t offset, int whence);
static int     ds2xxx_ioctl(FAR struct file *filep, int cmd,
                             unsigned long arg);

/* Mapping from ds2xxx_types_e to eeprom sizes and pages */

static size_t g_eeprom_sizes[EEPROM_DS_COUNT] =
{
  32,
  128,
  128,
  512,
  512,
  128,
  2560
};

static size_t g_eeprom_scratchpad_sizes[EEPROM_DS_COUNT] =
{
  8,
  8,
  8,
  32,
  32,
  8,
  32
};

/****************************************************************************
 * Private Data
 ****************************************************************************/

static const struct file_operations g_ds2xxx_fops =
{
  .open = ds2xxx_open,
  .close = ds2xxx_close,
  .read = ds2xxx_read,
  .write = ds2xxx_write,
  .seek = ds2xxx_seek,
  .ioctl = ds2xxx_ioctl,
};

/****************************************************************************
 * Private Functions
 ****************************************************************************/

#ifdef CONFIG_ENDIAN_BIG
static inline uint64_t onewire_leuint64(uint64_t x)
{
  return (((x & 0xff00000000000000ull) >> 56) |
          ((x & 0x00ff000000000000ull) >> 40) |
          ((x & 0x0000ff0000000000ull) >> 24) |
          ((x & 0x000000ff00000000ull) >> 8)  |
          ((x & 0x00000000ff000000ull) << 8)  |
          ((x & 0x0000000000ff0000ull) << 24) |
          ((x & 0x000000000000ff00ull) << 40) |
          ((x & 0x00000000000000ffull) << 56));
}
#endif

#ifdef CONFIG_ENDIAN_BIG
static inline uint32_t onewire_leuint32(uint32_t x)
{
  return (((x & 0xff000000) >> 24) |
          ((x & 0x00ff0000) >> 8)  |
          ((x & 0x0000ff00) << 8)  |
          ((x & 0x000000ff) << 24));
}
#endif

static int ds2xxx_startcomm(struct ds2xxx_dev_s *priv, uint8_t *wrbuf)
{
  int ret;
  uint64_t tmp;

  ret = ONEWIRE_RESET(priv->dev);
  if (ret < 0)
    {
      return ret;
    }

  wrbuf[0] = DS2XXX_MATCH_ROM;
  tmp = onewire_leuint64(priv->romcode);
  memcpy(&wrbuf[1], &tmp, MATCHROM_BUF_SIZE - 1);

  return ONEWIRE_WRITE(priv->dev, wrbuf, MATCHROM_BUF_SIZE);
}

static ssize_t ds2xxx_read_internal(FAR struct ds2xxx_dev_s *priv,
                                    off_t eeprom_addr,
                                    FAR uint8_t *buffer, size_t buflen)
{
  int ret;

  /* The process of reading is much simpler.
   * The master must issue the Read Memory command followed with 2 bytes
   * of address to be read from. The address is sent in little endian order.
   */

  /* Initialize the communication */

  ret = ds2xxx_startcomm(priv, buffer);
  if (ret < 0)
    {
      return ret;
    }

  priv->helpbuf[0] = DS2XXX_READ_MEMORY;
  priv->helpbuf[1] = eeprom_addr & 0xff;
  priv->helpbuf[2] = eeprom_addr >> 8;
  ret = ONEWIRE_WRITE(priv->dev, priv->helpbuf, 3);
  if (ret < 0)
    {
      return ret;
    }

  /* Now read real data. */

  ret = ONEWIRE_READ(priv->dev, (uint8_t *)buffer, buflen);
  return ret;
}

static ssize_t ds2xxx_write_internal(FAR struct ds2xxx_dev_s *priv,
                                     off_t eeprom_addr,
                                     FAR uint8_t *buffer, size_t buflen)
{
  ssize_t ret;
  uint8_t buf[40];
  uint16_t crc;
  uint16_t reccrc;

  i2cinfo("writing %d bytes to %d", buflen, eeprom_addr);

  ret = ds2xxx_startcomm(priv, buf);
  if (ret < 0)
    {
      return ret;
    }

  /* Now issue the write scratchpad command. Also calculate
   * CRC16 which must be compared with the received one.
   */

  buf[0] = DS2XXX_WRITE_SCRATCHPAD;
  buf[1] = eeprom_addr & 0xff;
  buf[2] = eeprom_addr >> 8;
  crc = onewire_crc16(buf, 3, 0);

  ret = ONEWIRE_WRITE(priv->dev, buf, 3);
  if (ret < 0)
    {
      return ret;
    }

  crc = onewire_crc16(buffer, buflen, crc);
  ret = ONEWIRE_WRITE(priv->dev, buffer, buflen);
  if (ret < 0)
    {
      return ret;
    }

  /* We now need to receive the CRC. The order is little endian. */

  ret = ONEWIRE_READ(priv->dev, buf, 2);
  if (ret < 0)
    {
      return ret;
    }

  reccrc = buf[0] | (buf[1] << 8);
  if (reccrc != (uint16_t) ~crc)
    {
      return -EPROTO;
    }

  /* We have succesfully performed the Write Scratchpad command.
   * Now issue read scratchpad.
   */

  ret = ds2xxx_startcomm(priv, buf);
  if (ret < 0)
    {
      return ret;
    }

  buf[0] = DS2XXX_READ_SCRATCHPAD;
  ret = ONEWIRE_WRITE(priv->dev, buf, 1);
  if (ret < 0)
    {
      return ret;
    }

  crc = onewire_crc16(buf, 1, 0);

  /* TA-E/S + buflen + ~CRC16 => buflen + 5 */

  ret = ONEWIRE_READ(priv->dev, buf,
                     buflen + HELPBUF_MARGIN);
  if (ret < 0)
    {
      return ret;
    }

  crc = onewire_crc16(buf, buflen + RS_HEADER_SIZE, crc);
  reccrc = buf[RS_HEADER_SIZE + buflen] |
           buf[RS_HEADER_SIZE + buflen + 1] << 8;
  if (reccrc != (uint16_t) ~crc)
    {
      return -EPROTO;
    }

  /* Memcheck should be performed, but imho CRC16 is already a good check.
   * Commit the scratchpad into the eeprom.
   */

  priv->helpbuf[0] = DS2XXX_COPY_SCRATCHPAD;
  priv->helpbuf[1] = buf[0];
  priv->helpbuf[2] = buf[1];
  priv->helpbuf[3] = buf[2];
  ret = ds2xxx_startcomm(priv, buf);
  if (ret < 0)
    {
      return ret;
    }

  ret = ONEWIRE_WRITE(priv->dev, priv->helpbuf, CS_HEADER_SIZE);
  if (ret < 0)
    {
      return ret;
    }

  /* Impose a delay. Across all supported devices, the maximum delay is 12 ms
   * for a page.
   */

  up_udelay(DS2XXX_TPROG_US);

  i2cinfo("aligned write of %d bytes at 0x%x succesful",
          buflen, eeprom_addr);
  return OK;
}

static int ds2xxx_open(FAR struct file *filep)
{
  FAR struct ds2xxx_dev_s *priv;
  FAR struct inode *inode = filep->f_inode;
  int ret = OK;

  DEBUGASSERT(inode->i_private);
  priv = inode->i_private;

  ret = nxmutex_lock(&priv->lock);
  if (ret < 0)
    {
      return ret;
    }

  if ((priv->refs + 1) == 0)
    {
      ret = -EMFILE;
    }
  else
    {
      priv->refs++;
    }

  nxmutex_unlock(&priv->lock);
  return OK;
}

static int ds2xxx_write(FAR struct file *filep, FAR const char *buffer,
                        size_t buflen)
{
  FAR struct ds2xxx_dev_s *priv;
  FAR struct inode *inode = filep->f_inode;
  off_t addr;
  off_t misalign;
  size_t to_write;
  size_t scratchpad_size;
  size_t buflen_save = buflen;
  int ret = OK;

  DEBUGASSERT(inode->i_private);
  priv = inode->i_private;
  scratchpad_size = g_eeprom_scratchpad_sizes[priv->devtype];

  i2cwarn("writing %d bytes to ptr %d", buflen, filep->f_pos);

  if (filep->f_pos >= g_eeprom_sizes[priv->devtype])
    {
      return -EFBIG;
    }

  if ((filep->f_pos + buflen) >= g_eeprom_sizes[priv->devtype])
    {
      buflen = g_eeprom_sizes[priv->devtype] - filep->f_pos;
      buflen_save = buflen;
    }

  ret = nxmutex_lock(&priv->lock);
  if (ret < 0)
    {
      goto done;
    }

  /* The process of writing to 1WIRE EEPROMs involves the usage
   * of the scratchpad. Firstly, the Write Scratchpad command
   * must be issued, the payload is as follows:
   * 2 bytes ADDR (Little Endian) | DATA,
   * where ADDR must be aligned to the scratchpad size
   * (DS2431's scratchpad is 8 bytes, DS2433's scratchpad is 32 bytes
   * and the DATA is maximally 8 bytes or 32 bytes, depending on the EEPROM.
   *
   * Since writes are not generally row aligned, we must read
   * the corresponding unaligned ends beforehand, modifying respective parts
   * and writing this back.
   *
   * To check the transaction has completed succesfully, Read Scratchpad
   * command is issued, returning the 3-byte authorization pattern, also.
   *
   * The writing procedure is ended with issuing the Copy Scratchpad
   * command.
   */

  /* Calculate the misalignment in the beginning. And the starting address. */

  misalign = (filep->f_pos) % scratchpad_size;
  addr = (filep->f_pos / scratchpad_size) * scratchpad_size;

  /* The pointer points at the beginning of a page, decide if we skip. */

  if (misalign == 0)
    {
      goto no_misalign_begin;
    }

  ret = ds2xxx_read_internal(priv, addr, priv->helpbuf, scratchpad_size);
  if (ret < 0)
    {
      goto done;
    }

  /* Fill in the misaligned data. But decide the length of the write. */

  if (buflen >= scratchpad_size - misalign)
    {
      to_write = scratchpad_size - misalign;
    }
  else
    {
      to_write = buflen;
    }

  memcpy(priv->helpbuf + misalign, buffer, to_write);
  ret = ds2xxx_write_internal(priv, addr, priv->helpbuf, scratchpad_size);
  if (ret < 0)
    {
      goto done;
    }

  /* Move all the pointers */

  buffer += to_write;
  buflen -= to_write;
  addr += scratchpad_size;

no_misalign_begin:

  /* Now loop over all aligned writes. If everything was already
   * written in the misaligned write or the next write is also misaligned,
   * this loop won't run.
   */

  while (buflen >= scratchpad_size)
    {
      ret = ds2xxx_write_internal(priv, addr, (uint8_t *)buffer,
                                  scratchpad_size);
      if (ret < 0)
        {
          goto done;
        }

      buffer += scratchpad_size;
      buflen -= scratchpad_size;
      addr += scratchpad_size;
    }

  /* There's no rest. */

  if (buflen == 0)
    {
      goto success;
    }

  /* Finish this with the last read. The read is aligned but needs to be
   * of the same size as the scratchpad.
   */

  ret = ds2xxx_read_internal(priv, addr, priv->helpbuf, scratchpad_size);
  if (ret < 0)
    {
      goto done;
    }

  memcpy(priv->helpbuf, buffer, buflen);
  ret = ds2xxx_write_internal(priv, addr, priv->helpbuf, scratchpad_size);
  if (ret < 0)
    {
      goto done;
    }

  /* Everything went well. Move the pointer */

success:
    i2cwarn("success writing %d bytes", buflen_save);
    filep->f_pos += buflen_save;
    ret = buflen_save;
done:
  nxmutex_unlock(&priv->lock);
  return ret;
}

static ssize_t ds2xxx_read(FAR struct file *filep, FAR char *buffer,
                           size_t len)
{
  FAR struct ds2xxx_dev_s *priv;
  FAR struct inode *inode = filep->f_inode;
  int ret = OK;

  DEBUGASSERT(inode->i_private);
  priv = inode->i_private;

  ret = nxmutex_lock(&priv->lock);
  if (ret < 0)
    {
      return ret;
    }

  /* The pointer is outside the "file" */

  if (filep->f_pos >= g_eeprom_sizes[priv->devtype])
    {
      goto done;
    }

  /* Trim the length */

  if ((filep->f_pos + len) > g_eeprom_sizes[priv->devtype])
    {
      len = g_eeprom_sizes[priv->devtype] - filep->f_pos;
    }

  ret = ds2xxx_read_internal(priv, filep->f_pos, (uint8_t *)buffer, len);
  if (ret < 0)
    {
      goto done;
    }

  ret = len;
  filep->f_pos += len;

  i2cinfo("DS2XXX read OK, curpos=%d", filep->f_pos);

done:
  nxmutex_unlock(&priv->lock);
  return ret;
}

static int ds2xxx_close(FAR struct file *filep)
{
  FAR struct ds2xxx_dev_s *priv;
  FAR struct inode *inode = filep->f_inode;
  int ret = OK;

  DEBUGASSERT(inode->i_private);
  priv = inode->i_private;

  ret = nxmutex_lock(&priv->lock);
  if (ret < 0)
    {
      return ret;
    }

  if (priv->refs == 0)
    {
      ret = -EIO;
    }
  else
    {
      priv->refs--;
    }

  nxmutex_unlock(&priv->lock);
  return ret;
}

static off_t ds2xxx_seek(FAR struct file *filep, off_t offset, int whence)
{
  FAR struct ds2xxx_dev_s *priv;
  FAR struct inode *inode = filep->f_inode;
  int ret;
  off_t newpos;

  DEBUGASSERT(inode->i_private);
  priv = inode->i_private;

  ret = nxmutex_lock(&priv->lock);
  if (ret < 0)
    {
      return ret;
    }

  switch (whence)
    {
    case SEEK_CUR:
      newpos = filep->f_pos + offset;
      break;
    case SEEK_SET:
      newpos = offset;
      break;
    case SEEK_END:
      newpos = g_eeprom_sizes[priv->devtype] + offset;
      break;
    default:
      nxmutex_unlock(&priv->lock);
      return -EINVAL;
    }

  /* Opengroup.org:
   *
   *  "The lseek() function shall allow the file offset to be set beyond the
   *   end of the existing data in the file. If data is later written at
   *   this point, subsequent reads of data in the gap shall return bytes
   *   with the value 0 until data is actually written into the gap."
   *
   * We can conform to the first part, but not the second. But return -EINVAL
   * if
   *
   *  "...the resulting file offset would be negative for a regular file,
   *   block special file, or directory."
   */

  if (newpos >= 0)
    {
      filep->f_pos = newpos;
      ret = newpos;
      i2cinfo("ds2xxx_seek: newpos %" PRIdOFF, newpos);
    }
  else
    {
      ret = -EINVAL;
    }

  nxmutex_unlock(&priv->lock);
  return ret;
}

static int ds2xxx_ioctl(FAR struct file *filep, int cmd, unsigned long arg)
{
  FAR struct ds2xxx_dev_s *priv;
  FAR struct inode *inode = filep->f_inode;
  int ret = OK;

  DEBUGASSERT(inode->i_private);
  priv = inode->i_private;

  nxmutex_lock(&priv->lock);
  switch (cmd)
    {
      case ONEWIREIOC_EE_DS2XXX_SETROM:
        /* The issue is that unsigned long is 32bits on most architectures.
         * That means we should not pass the romcode as a value.
         */

        i2cinfo("Rom to be set is 0x%" PRIx64, *((uint64_t *)arg));
        priv->romcode = *((uint64_t *)arg);
        break;
      default:
        ret = -ENOTTY;
    }

  nxmutex_unlock(&priv->lock);
  return ret;
}

/****************************************************************************
 * Public Functions
 ****************************************************************************/

int ds2xxx_initialize(FAR struct onewire_dev_s *dev,
                      enum ds2xxx_eeproms_e devtype, FAR char *devname)
{
  FAR struct ds2xxx_dev_s *priv;

  if (devtype < 0 || devtype > EEPROM_DS_COUNT)
    {
      return -EINVAL;
    }

  priv = kmm_zalloc(sizeof(struct ds2xxx_dev_s));
  if (priv == NULL)
    {
      return -ENOMEM;
    }

  /* We need extra 5 bytes for the Copy Scratchpad command. */

  priv->helpbuf = kmm_zalloc(HELPBUF_MARGIN +
                             g_eeprom_scratchpad_sizes[devtype]);
  if (priv->helpbuf == NULL)
    {
      kmm_free(priv);
      return -ENOMEM;
    }

  nxmutex_init(&priv->lock);
  priv->dev     = dev;
  priv->devtype = devtype;

  return register_driver(devname, &g_ds2xxx_fops, 0666, priv);
}
/****************************************************************************
 * include/nuttx/eeprom/1wire_ds2xxx.h
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.  The
 * ASF licenses this file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the
 * License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 ****************************************************************************/

#ifndef __INCLUDE_NUTTX_EEPROM_1WIRE_DS2XXX_H
#define __INCLUDE_NUTTX_EEPROM_1WIRE_DS2XXX_H

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <nuttx/config.h>
#include <sys/types.h>

/****************************************************************************
 * Public Types
 ****************************************************************************/

/* All device specific commands for the scratchpad are luckily the same
 * for all the devices.
 */

#define DS2XXX_WRITE_SCRATCHPAD 0x0f
#define DS2XXX_READ_SCRATCHPAD  0xaa
#define DS2XXX_COPY_SCRATCHPAD  0x55
#define DS2XXX_READ_MEMORY      0xf0

/* There are other commands, also. For example, the common commands
 * have a different code then specified in drivers/1wire/1wire.c.
 */

#define DS2XXX_MATCH_ROM 0x55

/* DS28E05 has a different architecture,
 * as it does not use a scratchpad. Let's keep this device out of here.
 */

enum ds2xxx_eeproms_e
{
    EEPROM_DS2430 = 0,
    EEPROM_DS2431,
    EEPROM_DS2432,
    EEPROM_DS2433,
    EEPROM_DS28E04,
    EEPROM_DS28E07,
    EEPROM_DS28EC20,
    EEPROM_DS_COUNT
};

enum ds2xxx_familycodes_e
{
    FAMILY_DS2430   = 0x14,
    FAMILY_DS2431   = 0x2d,
    FAMILY_DS2432   = 0xb3, /* Use only the EEPROM part of the IC */
    FAMILY_DS2433   = 0x23,
    FAMILY_DS28E04  = 0x1c,
    FAMILY_DS28E05  = 0x0d,
    FAMILY_DS28E07  = 0x2d, /* It has the same family code as DS2431 */
    FAMILY_DS28EC20 = 0x43
};

/****************************************************************************
 * Public Function Prototypes
 ****************************************************************************/

/****************************************************************************
 * Name: ds2xxx_initialize
 *
 * Description: Bind a onewire_master_s struct to this driver,
 * capable of interfacing DS2XXX 1Wire EEPROMs. The user must specify
 * the device type and also the name of the device (e.g. /dev/ds2xxx).
 *
 ****************************************************************************/

int ds2xxx_initialize(FAR struct onewire_dev_s *dev,
                      enum ds2xxx_eeproms_e devtype, FAR char *devname);

#endif /* __INCLUDE_NUTTX_EEPROM_1WIRE_DS2XXX_H */

Reply via email to