source: rtems/cpukit/libi2c/libi2c.c @ cd784cb7

4.104.11
Last change on this file since cd784cb7 was cd784cb7, checked in by Joel Sherrill <joel.sherrill@…>, on Sep 24, 2008 at 2:31:26 PM

2008-09-24 Joel Sherrill <joel.sherrill@…>

PR 1326/cpukit

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