source: rtems/cpukit/libi2c/libi2c.c @ 39aa5cfa

4.115
Last change on this file since 39aa5cfa was 39aa5cfa, checked in by Joel Sherrill <joel.sherrill@…>, on 08/25/10 at 21:17:03

2010-08-25 Joel Sherrill <joel.sherrill@…>

Coverity Id 125
Coverity Id 126

  • libi2c/libi2c.c: Use strncpy and snprintf.
  • Property mode set to 100644
File size: 18.9 KB
RevLine 
[6339f467]1/* $Id$ */
2
3/* libi2c Implementation */
4
[0893220]5/*
[6a03edd5]6 * Authorship
7 * ----------
8 * This software was created by
9 *     Till Straumann <strauman@slac.stanford.edu>, 2005,
10 *         Stanford Linear Accelerator Center, Stanford University.
[0893220]11 *
[6a03edd5]12 * Acknowledgement of sponsorship
13 * ------------------------------
14 * This software was produced by
15 *     the Stanford Linear Accelerator Center, Stanford University,
16 *         under Contract DE-AC03-76SFO0515 with the Department of Energy.
[0893220]17 *
[6a03edd5]18 * Government disclaimer of liability
19 * ----------------------------------
20 * Neither the United States nor the United States Department of Energy,
21 * nor any of their employees, makes any warranty, express or implied, or
22 * assumes any legal liability or responsibility for the accuracy,
23 * completeness, or usefulness of any data, apparatus, product, or process
24 * disclosed, or represents that its use would not infringe privately owned
25 * rights.
[0893220]26 *
[6a03edd5]27 * Stanford disclaimer of liability
28 * --------------------------------
29 * Stanford University makes no representations or warranties, express or
30 * implied, nor assumes any liability for the use of this software.
[0893220]31 *
[6a03edd5]32 * Stanford disclaimer of copyright
33 * --------------------------------
34 * Stanford University, owner of the copyright, hereby disclaims its
35 * copyright and all other rights in this software.  Hence, anyone may
[0893220]36 * freely use it for any purpose without restriction.
37 *
[6a03edd5]38 * Maintenance of notices
39 * ----------------------
40 * In the interest of clarity regarding the origin and status of this
41 * SLAC software, this and all the preceding Stanford University notices
42 * are to remain affixed to any copy or derivative of this software made
43 * or distributed by the recipient and are to be affixed to any copy of
44 * software made or distributed by the recipient that contains a copy or
45 * derivative of this software.
[0893220]46 *
[6a03edd5]47 * ------------------ SLAC Software Notices, Set 4 OTT.002a, 2004 FEB 03
[0893220]48 */
[55a685b]49/*
[0893220]50 * adaptations to also handle SPI devices
[55a685b]51 * by Thomas Doerfler, embedded brains GmbH, Puchheim, Germany
52 */
[199e748]53#if HAVE_CONFIG_H
54#include "config.h"
55#endif
56
[6339f467]57#include <string.h>
58#include <stdio.h>
59#include <stdlib.h>
60#include <errno.h>
61#include <assert.h>
[55a685b]62#include <stdarg.h>
[6339f467]63
64#include <rtems.h>
65#include <rtems/error.h>
[d2ff24c2]66#include <rtems/bspIo.h>
[6339f467]67#include <rtems/libio.h>
68
69#include <rtems/libi2c.h>
70
[5e4831f]71#define DRVNM "libi2c: "
[6339f467]72
73#define MAX_NO_BUSSES   8       /* Also limited by the macro building minor numbers */
74#define MAX_NO_DRIVERS  16      /* Number of high level drivers we support          */
75
76#define MINOR2ADDR(minor)       ((minor)&((1<<10)-1))
77#define MINOR2BUS(minor)        (((minor)>>10)&7)
78#define MINOR2DRV(minor)        ((minor)>>13)
79
80/* Check the 'minor' argument, i.e., verify that
81 * we have a driver connected
82 */
83#define DECL_CHECKED_BH(b, bh, m, s)\
84        unsigned b = MINOR2BUS(m);              \
85        rtems_libi2c_bus_t      *bh;            \
86        if ( b >= MAX_NO_BUSSES || 0 == (bh=busses[b].bush) ) { \
87                return s RTEMS_INVALID_NUMBER;  \
88        }
89
90#define DECL_CHECKED_DRV(d, b, m)       \
91        unsigned d = MINOR2DRV(m);              \
92        unsigned b = MINOR2BUS(m);              \
93        if (   b >= MAX_NO_BUSSES  || 0 == busses[b].bush       \
94                || d >  MAX_NO_DRIVERS || (d && 0 == drvs[d-1].drv )) {\
95                return RTEMS_INVALID_NUMBER;    \
96        }
97
98#define DISPATCH(rval, entry, dflt)     \
99        do {                            \
[5e4831f]100                const rtems_driver_address_table *ops = drvs[--drv].drv->ops;   \
[6339f467]101                rval = ops->entry ? ops->entry(major,minor,arg) : dflt; \
102        } while (0)
103
104
105rtems_device_major_number rtems_libi2c_major;
106
[f002800e]107static bool is_initialized = false;
[d2ff24c2]108
[6339f467]109static struct i2cbus
110{
111  rtems_libi2c_bus_t *bush;
112  volatile rtems_id mutex;      /* lock this across start -> stop */
[c85ab23]113  volatile bool started;
[6339f467]114  char *name;
[400a04a]115} busses[MAX_NO_BUSSES] = { { NULL, RTEMS_ID_NONE, false, NULL } };
[6339f467]116
117static struct
118{
119  rtems_libi2c_drv_t *drv;
[400a04a]120} drvs[MAX_NO_DRIVERS] = { { NULL } };
[6339f467]121
[c85ab23]122static rtems_id libmutex = RTEMS_ID_NONE;
[6339f467]123
124#define LOCK(m)         assert(!rtems_semaphore_obtain((m), RTEMS_WAIT, RTEMS_NO_TIMEOUT))
125#define UNLOCK(m)       rtems_semaphore_release((m))
126
127#define LIBLOCK()       LOCK(libmutex)
128#define LIBUNLOCK()     UNLOCK(libmutex)
129
130#define MUTEX_ATTS      \
131        (  RTEMS_PRIORITY                       \
132         | RTEMS_BINARY_SEMAPHORE       \
133         |RTEMS_INHERIT_PRIORITY        \
134         |RTEMS_NO_PRIORITY_CEILING     \
135         |RTEMS_LOCAL )
136
[d2ff24c2]137/* During early stages of life, stdio is not available */
138
139static void
140safe_printf (const char *fmt, ...)
141{
142va_list ap;
143
144        va_start(ap, fmt);
145        if ( _System_state_Is_up( _System_state_Get() ) )
146                vfprintf( stderr, fmt, ap );
147        else
148                vprintk( fmt, ap );
149        va_end(ap);
150}
151
152static rtems_status_code
153mutexCreate (rtems_name nm, rtems_id *pm)
[6339f467]154{
155  rtems_status_code sc;
[d2ff24c2]156
[6339f467]157  if (RTEMS_SUCCESSFUL !=
[d2ff24c2]158      (sc = rtems_semaphore_create (nm, 1, MUTEX_ATTS, 0, pm))) {
159        if ( _System_state_Is_up( _System_state_Get() ) )
[5e4831f]160        rtems_error (sc, DRVNM "Unable to create mutex\n");
[d2ff24c2]161        else
[5e4831f]162                printk (DRVNM "Unable to create mutex (status code %i)\n", sc);
[6339f467]163  }
[d2ff24c2]164  return sc;
[6339f467]165}
166
167/* Lock a bus avoiding to have a mutex, which is mostly
168 * unused, hanging around all the time. We just create
169 * and delete it on the fly...
170 *
171 * ASSUMES: argument checked by caller
172 */
173
174static void
175lock_bus (int busno)
176{
[c85ab23]177  struct i2cbus *bus = &busses[busno];
[d2ff24c2]178
[c85ab23]179  if (bus->mutex == RTEMS_ID_NONE) {
180    /*
181     * Nobody is holding the bus mutex - it's not there.  Create it on the fly.
182     */
183    LIBLOCK ();
184    if (bus->mutex == RTEMS_ID_NONE) {
185      rtems_id m = RTEMS_ID_NONE;
186      rtems_status_code sc = mutexCreate (
187        rtems_build_name ('i', '2', 'c', '0' + busno),
188        &m
189      );
190      if (sc != RTEMS_SUCCESSFUL) {
191        LIBUNLOCK ();
192        rtems_panic (DRVNM "Unable to create bus lock");
193        return;
194      }
195      bus->mutex = m;
196    }
197    LIBUNLOCK ();
[6339f467]198  }
[c85ab23]199
[6339f467]200  /* Now lock this bus */
201  LOCK (bus->mutex);
202}
203
204static void
205unlock_bus (int busno)
206{
207  struct i2cbus *bus = &busses[busno];
208  UNLOCK (bus->mutex);
209}
210
211/* Note that 'arg' is always passed in as NULL */
[d2ff24c2]212rtems_status_code
213rtems_i2c_init (rtems_device_major_number major, rtems_device_minor_number minor,
[6339f467]214          void *arg)
215{
216  rtems_status_code rval;
[d2ff24c2]217  /* No busses or drivers can be registered at this point;
218   * avoid the macro aborting with an error
[6339f467]219  DECL_CHECKED_DRV (drv, busno, minor)
[d2ff24c2]220   */
[6339f467]221
[d2ff24c2]222  rval = mutexCreate (rtems_build_name ('l', 'I', '2', 'C'), &libmutex);
223
224  if ( RTEMS_SUCCESSFUL == rval ) {
[f002800e]225        is_initialized     = true;
[d2ff24c2]226        rtems_libi2c_major = major;
[6339f467]227  } else {
[c85ab23]228        libmutex = RTEMS_ID_NONE;
[6339f467]229  }
230  return rval;
231}
232
[d2ff24c2]233rtems_status_code
234rtems_i2c_open (rtems_device_major_number major, rtems_device_minor_number minor,
[6339f467]235          void *arg)
236{
237  rtems_status_code rval;
238  DECL_CHECKED_DRV (drv, busno, minor)
239
240    if (0 == drv) {
241    rval = RTEMS_SUCCESSFUL;
242  } else {
243    DISPATCH (rval, open_entry, RTEMS_SUCCESSFUL);
244  }
245  return rval;
246}
247
[d2ff24c2]248rtems_status_code
249rtems_i2c_close (rtems_device_major_number major, rtems_device_minor_number minor,
[6339f467]250           void *arg)
251{
252  rtems_status_code rval;
253  DECL_CHECKED_DRV (drv, busno, minor)
254
255    if (0 == drv) {
256    rval = RTEMS_SUCCESSFUL;
257  } else {
258    DISPATCH (rval, close_entry, RTEMS_SUCCESSFUL);
259  }
260  return rval;
261}
262
[d2ff24c2]263rtems_status_code
264rtems_i2c_read (rtems_device_major_number major, rtems_device_minor_number minor,
[6339f467]265          void *arg)
266{
267  int rval;                     /* int so we can check for negative value */
268  rtems_libio_rw_args_t *rwargs = arg;
269  DECL_CHECKED_DRV (drv, busno, minor)
270
271    if (0 == rwargs->count) {
272    rwargs->bytes_moved = 0;
273    return RTEMS_SUCCESSFUL;
274  }
275
276  if (0 == drv) {
277    rval =
278      rtems_libi2c_start_read_bytes (minor, (unsigned char *) rwargs->buffer,
279                                     rwargs->count);
280    if (rval >= 0) {
281      rwargs->bytes_moved = rval;
282      rtems_libi2c_send_stop (minor);
283      rval = RTEMS_SUCCESSFUL;
284    } else {
285      rval = -rval;
286    }
287  } else {
288    DISPATCH (rval, read_entry, RTEMS_NOT_IMPLEMENTED);
289  }
290  return rval;
291}
292
[d2ff24c2]293rtems_status_code
294rtems_i2c_write (rtems_device_major_number major, rtems_device_minor_number minor,
[6339f467]295           void *arg)
296{
297  int rval;                     /* int so we can check for negative value */
298  rtems_libio_rw_args_t *rwargs = arg;
299  DECL_CHECKED_DRV (drv, busno, minor)
300
301    if (0 == rwargs->count) {
302    rwargs->bytes_moved = 0;
303    return RTEMS_SUCCESSFUL;
304  }
305
306  if (0 == drv) {
307    rval =
308      rtems_libi2c_start_write_bytes (minor, (unsigned char *) rwargs->buffer,
309                                      rwargs->count);
310    if (rval >= 0) {
311      rwargs->bytes_moved = rval;
312      rtems_libi2c_send_stop (minor);
313      rval = RTEMS_SUCCESSFUL;
314    } else {
315      rval = -rval;
316    }
317  } else {
318    DISPATCH (rval, write_entry, RTEMS_NOT_IMPLEMENTED);
319  }
320  return rval;
321}
322
[d2ff24c2]323rtems_status_code
324rtems_i2c_ioctl (rtems_device_major_number major, rtems_device_minor_number minor,
[6339f467]325           void *arg)
326{
327  rtems_status_code rval;
328  DECL_CHECKED_DRV (drv, busno, minor)
329
330    if (0 == drv) {
331    rval = RTEMS_NOT_IMPLEMENTED;
332  } else {
333    DISPATCH (rval, control_entry, RTEMS_NOT_IMPLEMENTED);
334  }
335  return rval;
336}
337
338
339/* Our ops just dispatch to the registered drivers */
[5e4831f]340const rtems_driver_address_table rtems_libi2c_io_ops = {
[d2ff24c2]341  initialization_entry:  rtems_i2c_init,
342  open_entry:            rtems_i2c_open,
343  close_entry:           rtems_i2c_close,
344  read_entry:            rtems_i2c_read,
345  write_entry:           rtems_i2c_write,
346  control_entry:         rtems_i2c_ioctl,
[6339f467]347};
348
349int
[ee0c82f]350rtems_libi2c_initialize (void)
[6339f467]351{
352  rtems_status_code sc;
353
[55a685b]354  if (is_initialized) {
355    /*
356     * already called before? then skip this step
357     */
358    return 0;
359  }
[0893220]360
[d2ff24c2]361  /* rtems_io_register_driver does NOT currently check nor report back
362   * the return code of the 'init' operation, so we cannot
363   * rely on return code since it may seem OK even if the driver 'init;
364   * op failed.
365   * Let 'init' handle 'is_initialized'...
366   */
367  sc = rtems_io_register_driver (0, &rtems_libi2c_io_ops, &rtems_libi2c_major);
[c57316a]368  if (RTEMS_SUCCESSFUL != sc) {
[d2ff24c2]369    safe_printf(
[5e4831f]370             DRVNM "Claiming driver slot failed (rtems status code %i)\n",
[6339f467]371             sc);
[c85ab23]372    if (libmutex != RTEMS_ID_NONE) {
373      rtems_semaphore_delete (libmutex);
374    }
375    libmutex = RTEMS_ID_NONE;
376    is_initialized = false;
[6339f467]377    return -1;
378  }
379
380  return 0;
381}
382
383int
[5e4831f]384rtems_libi2c_register_bus (const char *name, rtems_libi2c_bus_t * bus)
[6339f467]385{
386  int i;
387  rtems_status_code err;
[39aa5cfa]388  size_t length = (name ? strlen (name) + 1 : 20);
389  char *nmcpy = malloc(length);
[6339f467]390  char tmp, *chpt;
391  struct stat sbuf;
392
[ad37630]393  if (nmcpy == NULL) {
394    safe_printf ( DRVNM "No memory\n");
395    return -RTEMS_NO_MEMORY;
396  }
[6339f467]397
[39aa5cfa]398  strncpy (nmcpy, name ? name : "/dev/i2c", length);
[6339f467]399
400  /* check */
401  if ('/' != *nmcpy) {
[5e4831f]402    safe_printf ( DRVNM "Bad name: must be an absolute path starting with '/'\n");
[ad37630]403    free( nmcpy );
[6339f467]404    return -RTEMS_INVALID_NAME;
405  }
406  /* file must not exist */
407  if (!stat (nmcpy, &sbuf)) {
[5e4831f]408    safe_printf ( DRVNM "Bad name: file exists already\n");
[ad37630]409    free( nmcpy );
[6339f467]410    return -RTEMS_INVALID_NAME;
411  }
412
413  /* we already verified that there is at least one '/' */
414  chpt = strrchr (nmcpy, '/') + 1;
415  tmp = *chpt;
416  *chpt = 0;
417  i = stat (nmcpy, &sbuf);
418  *chpt = tmp;
419  if (i) {
[d2ff24c2]420    safe_printf ( DRVNM "Get %s status failed: %s\n",
421             nmcpy, strerror(errno));
[ad37630]422    free( nmcpy );
[6339f467]423    return -RTEMS_INVALID_NAME;
424  }
425  /* should be a directory since name terminates in '/' */
426
427
[c85ab23]428  if (libmutex == RTEMS_ID_NONE) {
[5e4831f]429    safe_printf ( DRVNM "Library not initialized\n");
[ad37630]430    free( nmcpy );
[6339f467]431    return -RTEMS_NOT_DEFINED;
432  }
433
[5e4831f]434  if (bus == NULL || bus->size < sizeof (*bus)) {
435    safe_printf ( DRVNM "No bus-ops or size too small -- misconfiguration?\n");
[ad37630]436    free( nmcpy );
[6339f467]437    return -RTEMS_NOT_CONFIGURED;
438  }
439
440  LIBLOCK ();
441  for (i = 0; i < MAX_NO_BUSSES; i++) {
442    if (!busses[i].bush) {
443      /* found a free slot */
444      busses[i].bush = bus;
[c85ab23]445      busses[i].mutex = RTEMS_ID_NONE;
446      busses[i].started = false;
[6339f467]447
448      if (!name)
449        sprintf (nmcpy + strlen (nmcpy), "%i", i);
450
451      if ((err = busses[i].bush->ops->init (busses[i].bush))) {
452        /* initialization failed */
453        i = -err;
454      } else {
455        busses[i].name = nmcpy;;
456        nmcpy = 0;
457      }
458
459      break;
460    }
461  }
462  LIBUNLOCK ();
463
464  if (i >= MAX_NO_BUSSES) {
465    i = -RTEMS_TOO_MANY;
466  }
467
468  free (nmcpy);
469
470  return i;
471}
472
473static int
474not_started (int busno)
475{
476  int rval;
477  lock_bus (busno);
478  rval = !busses[busno].started;
479  unlock_bus (busno);
480  return rval;
481}
482
483rtems_status_code
[55a685b]484rtems_libi2c_send_start (rtems_device_minor_number minor)
[6339f467]485{
486  int rval;
487  DECL_CHECKED_BH (busno, bush, minor, +)
488
489    lock_bus (busno);
490  rval = bush->ops->send_start (bush);
491
492  /* if this failed or is not the first start, unlock */
493  if (rval || busses[busno].started) {
494    /* HMM - what to do if the 1st start failed ?
495     * try to reset...
496     */
497    if (!busses[busno].started) {
498      /* just in case the bus driver fiddles with errno */
499      int errno_saved = errno;
500      bush->ops->init (bush);
501      errno = errno_saved;
502    } else if (rval) {
503      /* failed restart */
504      rtems_libi2c_send_stop (minor);
505    }
506    unlock_bus (busno);
507  } else {
508    /* successful 1st start; keep bus locked until stop is sent */
[c85ab23]509    busses[busno].started = true;
[6339f467]510  }
511  return rval;
512}
513
514rtems_status_code
[55a685b]515rtems_libi2c_send_stop (rtems_device_minor_number minor)
[6339f467]516{
517  rtems_status_code rval;
518  DECL_CHECKED_BH (busno, bush, minor, +)
519
520    if (not_started (busno))
521    return RTEMS_NOT_OWNER_OF_RESOURCE;
522
523  rval = bush->ops->send_stop (bush);
524
[c85ab23]525  busses[busno].started = false;
[6339f467]526
527  unlock_bus (busno);
528  return rval;
529}
530
531rtems_status_code
[55a685b]532rtems_libi2c_send_addr (rtems_device_minor_number minor, int rw)
[6339f467]533{
534  rtems_status_code sc;
535  DECL_CHECKED_BH (busno, bush, minor, +)
536
537    if (not_started (busno))
538    return RTEMS_NOT_OWNER_OF_RESOURCE;
539
540  sc = bush->ops->send_addr (bush, MINOR2ADDR (minor), rw);
541  if (RTEMS_SUCCESSFUL != sc)
542    rtems_libi2c_send_stop (minor);
543  return sc;
544}
545
546int
[0893220]547rtems_libi2c_read_bytes (rtems_device_minor_number minor,
548                         unsigned char *bytes,
[55a685b]549                         int nbytes)
[6339f467]550{
551  int sc;
552  DECL_CHECKED_BH (busno, bush, minor, -)
553
[cd784cb7]554  if (not_started (busno))
[6339f467]555    return -RTEMS_NOT_OWNER_OF_RESOURCE;
556
557  sc = bush->ops->read_bytes (bush, bytes, nbytes);
558  if (sc < 0)
559    rtems_libi2c_send_stop (minor);
560  return sc;
561}
562
563int
[0893220]564rtems_libi2c_write_bytes (rtems_device_minor_number minor,
565                          const unsigned char *bytes,
[55a685b]566                          int nbytes)
[6339f467]567{
568  int sc;
569  DECL_CHECKED_BH (busno, bush, minor, -)
570
[cd784cb7]571  if (not_started (busno))
[6339f467]572    return -RTEMS_NOT_OWNER_OF_RESOURCE;
573
[9ab94a1f]574  sc = bush->ops->write_bytes (bush, (unsigned char *)bytes, nbytes);
[6339f467]575  if (sc < 0)
576    rtems_libi2c_send_stop (minor);
577  return sc;
578}
579
[55a685b]580int
[0893220]581rtems_libi2c_ioctl (rtems_device_minor_number minor,
[55a685b]582                    int cmd,
583                    ...)
584{
585  va_list            ap;
586  int sc = 0;
587  void *args;
[f002800e]588  bool is_started = false;
[55a685b]589  DECL_CHECKED_BH (busno, bush, minor, -)
[0893220]590
[55a685b]591  va_start(ap, cmd);
592  args = va_arg(ap, void *);
593
594  switch(cmd) {
595    /*
[0893220]596     * add ioctls defined for this level here:
[55a685b]597     */
[0893220]598
[42bf1b9]599  case RTEMS_LIBI2C_IOCTL_GET_DRV_T:
600    /*
601     * query driver table entry
602     */
603    *(rtems_libi2c_drv_t **)args = (drvs[MINOR2DRV(minor)-1].drv);
604    break;
605
[55a685b]606  case RTEMS_LIBI2C_IOCTL_START_TFM_READ_WRITE:
[3fc6b565]607    if (not_started (busno)) {
608      va_end(ap);
[42bf1b9]609      return -RTEMS_NOT_OWNER_OF_RESOURCE;
[3fc6b565]610    }
[42bf1b9]611
[55a685b]612    /*
613     * address device, then set transfer mode and perform read_write transfer
614     */
615    /*
616     * perform start/address
617     */
618    if (sc == 0) {
619      sc = rtems_libi2c_send_start (minor);
[42bf1b9]620      is_started = (sc == 0);
[55a685b]621    }
622    /*
623     * set tfr mode
624     */
625    if (sc == 0) {
[0893220]626      sc = bush->ops->ioctl
627        (bush,
628         RTEMS_LIBI2C_IOCTL_SET_TFRMODE,
[55a685b]629         &((rtems_libi2c_tfm_read_write_t *)args)->tfr_mode);
630    }
631    /*
632     * perform read_write
633     */
634    if (sc == 0) {
[0893220]635      sc = bush->ops->ioctl
636        (bush,
637         RTEMS_LIBI2C_IOCTL_READ_WRITE,
[55a685b]638         &((rtems_libi2c_tfm_read_write_t *)args)->rd_wr);
639    }
[42bf1b9]640    if ((sc < 0) && (is_started)) {
641      rtems_libi2c_send_stop (minor);
642    }
[55a685b]643    break;
644  default:
645    sc = bush->ops->ioctl (bush, cmd, args);
646    break;
647  }
[3fc6b565]648  va_end(ap);
649  return sc;
[55a685b]650}
651
[6339f467]652static int
[0893220]653do_s_rw (rtems_device_minor_number minor,
654         unsigned char *bytes,
655         int nbytes,
[55a685b]656         int rw)
[6339f467]657{
[cd784cb7]658  rtems_status_code   sc;
[6339f467]659  rtems_libi2c_bus_t *bush;
[cd784cb7]660  int                 status;
[6339f467]661
662  if ((sc = rtems_libi2c_send_start (minor)))
663    return -sc;
664
665  /* at this point, we hold the bus and are sure the minor number is valid */
666  bush = busses[MINOR2BUS (minor)].bush;
667
668  if ((sc = bush->ops->send_addr (bush, MINOR2ADDR (minor), rw))) {
669    rtems_libi2c_send_stop (minor);
670    return -sc;
671  }
672
673  if (rw)
[cd784cb7]674    status = bush->ops->read_bytes (bush, bytes, nbytes);
[6339f467]675  else
[cd784cb7]676    status = bush->ops->write_bytes (bush, bytes, nbytes);
[6339f467]677
[cd784cb7]678  if (status < 0) {
[6339f467]679    rtems_libi2c_send_stop (minor);
680  }
[cd784cb7]681  return status;
[6339f467]682}
683
684int
[0893220]685rtems_libi2c_start_read_bytes (rtems_device_minor_number minor,
[55a685b]686                               unsigned char *bytes,
[6339f467]687                               int nbytes)
688{
689  return do_s_rw (minor, bytes, nbytes, 1);
690}
691
692int
[0893220]693rtems_libi2c_start_write_bytes (rtems_device_minor_number minor,
[9ab94a1f]694                                const unsigned char *bytes,
[6339f467]695                                int nbytes)
696{
[9ab94a1f]697  return do_s_rw (minor, (unsigned char *)bytes, nbytes, 0);
[6339f467]698}
699
700int
[5e4831f]701rtems_libi2c_register_drv (const char *name, rtems_libi2c_drv_t * drvtbl,
[6339f467]702                           unsigned busno, unsigned i2caddr)
703{
704  int i;
705  rtems_status_code err;
706  rtems_device_minor_number minor;
707
[c85ab23]708  if (libmutex == RTEMS_ID_NONE) {
[5e4831f]709    safe_printf ( DRVNM "Library not initialized\n");
[6339f467]710    return -RTEMS_NOT_DEFINED;
711  }
712
713  if (name && strchr (name, '/')) {
[d2ff24c2]714    safe_printf ( DRVNM "Invalid name: '%s' -- must not contain '/'\n", name);
[6339f467]715    return -RTEMS_INVALID_NAME;
716  }
717
718  if (busno >= MAX_NO_BUSSES || !busses[busno].bush || i2caddr >= 1 << 10) {
719    errno = EINVAL;
720    return -RTEMS_INVALID_NUMBER;
721  }
722
[5e4831f]723  if (drvtbl == NULL || drvtbl->size < sizeof (*drvtbl)) {
724    safe_printf ( DRVNM "No driver table or size too small -- misconfiguration?\n");
[6339f467]725    return -RTEMS_NOT_CONFIGURED;
726  }
727
728  /* allocate slot */
729  LIBLOCK ();
730  for (i = 0; i < MAX_NO_DRIVERS; i++) {
731    /* driver # 0 is special, it is the built-in raw driver */
732    if (!drvs[i].drv) {
733      char *str;
734      dev_t dev;
[199e748]735      uint32_t mode;
[6339f467]736
737      /* found a free slot; encode slot + 1 ! */
738      minor = ((i + 1) << 13) | RTEMS_LIBI2C_MAKE_MINOR (busno, i2caddr);
739
740      if (name) {
[39aa5cfa]741        size_t length = strlen (busses[busno].name) + strlen (name) + 2;
742        str = malloc (length);
743        snprintf (str, length, "%s.%s", busses[busno].name, name);
[6339f467]744
745        dev = rtems_filesystem_make_dev_t (rtems_libi2c_major, minor);
746
747        mode = 0111 | S_IFCHR;
748        if (drvtbl->ops->read_entry)
749          mode |= 0444;
750        if (drvtbl->ops->write_entry)
751          mode |= 0222;
752
753        /* note that 'umask' is applied to 'mode' */
754        if (mknod (str, mode, dev)) {
[d2ff24c2]755          safe_printf( DRVNM
[6339f467]756                   "Creating device node failed: %s; you can try to do it manually...\n",
757                   strerror (errno));
758        }
759
760        free (str);
761      }
762
763      drvs[i].drv = drvtbl;
764
765      if (drvtbl->ops->initialization_entry)
766        err =
767          drvs[i].drv->ops->initialization_entry (rtems_libi2c_major, minor,
768                                                  0);
769      else
770        err = RTEMS_SUCCESSFUL;
771
772      LIBUNLOCK ();
773      return err ? -err : minor;
774    }
775  }
776  LIBUNLOCK ();
777  return -RTEMS_TOO_MANY;
778}
Note: See TracBrowser for help on using the repository browser.