source: rtems/cpukit/libi2c/libi2c.c @ 121dd881

4.115
Last change on this file since 121dd881 was 39046f7, checked in by Sebastian Huber <sebastian.huber@…>, on 07/24/13 at 09:09:23

score: Merge sysstate API into one file

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