source: rtems/cpukit/dev/i2c/i2c-bus.c @ c6bb1c33

Last change on this file since c6bb1c33 was c6bb1c33, checked in by Kevin Kirspel <kevin-kirspel@…>, on Jun 29, 2017 at 2:36:43 PM

posix/mmap: Add support for file handler and MAP_ANON

Added a mmap file handler to struct _rtems_filesystem_file_handlers_r.
Updated each file handler object to support the default mmap handler.
Updated mmap() to call the mmap handler for MAP_SHARED.
Added a mmap file handler for shm

Added support for MAP_ANON in mmap().

Updates #2859

  • Property mode set to 100644
File size: 6.7 KB
Line 
1/**
2 * @file
3 *
4 * @brief Inter-Integrated Circuit (I2C) Bus Implementation
5 *
6 * @ingroup I2CBus
7 */
8
9/*
10 * Copyright (c) 2014 embedded brains GmbH.  All rights reserved.
11 *
12 *  embedded brains GmbH
13 *  Dornierstr. 4
14 *  82178 Puchheim
15 *  Germany
16 *  <rtems@embedded-brains.de>
17 *
18 * The license and distribution terms for this file may be
19 * found in the file LICENSE in this distribution or at
20 * http://www.rtems.org/license/LICENSE.
21 */
22
23#if HAVE_CONFIG_H
24  #include "config.h"
25#endif
26
27#include <dev/i2c/i2c.h>
28
29#include <rtems/imfs.h>
30
31#include <stdlib.h>
32#include <string.h>
33
34void i2c_bus_obtain(i2c_bus *bus)
35{
36  rtems_status_code sc;
37
38  sc = rtems_semaphore_obtain(bus->mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
39  _Assert(sc == RTEMS_SUCCESSFUL);
40  (void) sc;
41}
42
43void i2c_bus_release(i2c_bus *bus)
44{
45  rtems_status_code sc;
46
47  sc = rtems_semaphore_release(bus->mutex);
48  _Assert(sc == RTEMS_SUCCESSFUL);
49  (void) sc;
50}
51
52int i2c_bus_transfer(i2c_bus *bus, i2c_msg *msgs, uint32_t msg_count)
53{
54  int err;
55  uint32_t i;
56  uint32_t j;
57
58  _Assert(msg_count > 0);
59
60  for (i = 0, j = 0; i < msg_count; ++i) {
61    if ((msgs[i].flags & I2C_M_NOSTART) != 0) {
62      if ((msgs[i].flags & I2C_M_RD) != (msgs[j].flags & I2C_M_RD)) {
63        return -EINVAL;
64      }
65
66      if (msgs[i].addr != msgs[j].addr) {
67        return -EINVAL;
68      }
69    } else {
70      j = i;
71    }
72  }
73
74  i2c_bus_obtain(bus);
75  err = (*bus->transfer)(bus, msgs, msg_count);
76  i2c_bus_release(bus);
77
78  return err;
79}
80
81static ssize_t i2c_bus_read(
82  rtems_libio_t *iop,
83  void *buffer,
84  size_t count
85)
86{
87  i2c_bus *bus = IMFS_generic_get_context_by_iop(iop);
88  i2c_msg msg = {
89    .addr = bus->default_address,
90    .flags = I2C_M_RD,
91    .len = (uint16_t) count,
92    .buf = buffer
93  };
94  int err;
95
96  if (bus->ten_bit_address) {
97    msg.flags |= I2C_M_TEN;
98  }
99
100  err = i2c_bus_transfer(bus, &msg, 1);
101  if (err == 0) {
102    return msg.len;
103  } else {
104    rtems_set_errno_and_return_minus_one(-err);
105  }
106}
107
108static ssize_t i2c_bus_write(
109  rtems_libio_t *iop,
110  const void *buffer,
111  size_t count
112)
113{
114  i2c_bus *bus = IMFS_generic_get_context_by_iop(iop);
115  i2c_msg msg = {
116    .addr = bus->default_address,
117    .flags = 0,
118    .len = (uint16_t) count,
119    .buf = RTEMS_DECONST(void *, buffer)
120  };
121  int err;
122
123  if (bus->ten_bit_address) {
124    msg.flags |= I2C_M_TEN;
125  }
126
127  err = i2c_bus_transfer(bus, &msg, 1);
128  if (err == 0) {
129    return msg.len;
130  } else {
131    rtems_set_errno_and_return_minus_one(-err);
132  }
133}
134
135static int i2c_bus_ioctl(
136  rtems_libio_t *iop,
137  ioctl_command_t command,
138  void *arg
139)
140{
141  i2c_bus *bus = IMFS_generic_get_context_by_iop(iop);
142  i2c_rdwr_ioctl_data *rdwr;
143  int err;
144
145  switch (command) {
146    case I2C_RDWR:
147      rdwr = arg;
148      if (rdwr->nmsgs > 0) {
149        err = i2c_bus_transfer(bus, rdwr->msgs, rdwr->nmsgs);
150      } else {
151        err = 0;
152      }
153      break;
154    case I2C_BUS_OBTAIN:
155      i2c_bus_obtain(bus);
156      err = 0;
157      break;
158    case I2C_BUS_RELEASE:
159      i2c_bus_release(bus);
160      err = 0;
161      break;
162    case I2C_BUS_GET_CONTROL:
163      *(i2c_bus **) arg = bus;
164      err = 0;
165      break;
166    case I2C_FUNCS:
167      *(unsigned long *) arg = bus->functionality;
168      err = 0;
169      break;
170    case I2C_RETRIES:
171      bus->retries = (unsigned long) arg;
172      err = 0;
173      break;
174    case I2C_TIMEOUT:
175      bus->timeout = RTEMS_MILLISECONDS_TO_TICKS(10 * (unsigned long) arg);
176      err = 0;
177      break;
178    case I2C_SLAVE:
179    case I2C_SLAVE_FORCE:
180      bus->default_address = (unsigned long) arg;
181      err = 0;
182      break;
183    case I2C_TENBIT:
184      bus->ten_bit_address = (unsigned long) arg != 0;
185      err = 0;
186      break;
187    case I2C_PEC:
188      bus->use_pec = (unsigned long) arg != 0;
189      err = 0;
190      break;
191    case I2C_BUS_SET_CLOCK:
192      i2c_bus_obtain(bus);
193      err = (*bus->set_clock)(bus, (unsigned long) arg);
194      i2c_bus_release(bus);
195      break;
196    default:
197      err = -ENOTTY;
198      break;
199  }
200
201  if (err == 0) {
202    return 0;
203  } else {
204    rtems_set_errno_and_return_minus_one(-err);
205  }
206}
207
208static const rtems_filesystem_file_handlers_r i2c_bus_handler = {
209  .open_h = rtems_filesystem_default_open,
210  .close_h = rtems_filesystem_default_close,
211  .read_h = i2c_bus_read,
212  .write_h = i2c_bus_write,
213  .ioctl_h = i2c_bus_ioctl,
214  .lseek_h = rtems_filesystem_default_lseek,
215  .fstat_h = IMFS_stat,
216  .ftruncate_h = rtems_filesystem_default_ftruncate,
217  .fsync_h = rtems_filesystem_default_fsync_or_fdatasync,
218  .fdatasync_h = rtems_filesystem_default_fsync_or_fdatasync,
219  .fcntl_h = rtems_filesystem_default_fcntl,
220  .kqfilter_h = rtems_filesystem_default_kqfilter,
221  .mmap_h = rtems_filesystem_default_mmap,
222  .poll_h = rtems_filesystem_default_poll,
223  .readv_h = rtems_filesystem_default_readv,
224  .writev_h = rtems_filesystem_default_writev
225};
226
227static void i2c_bus_node_destroy(IMFS_jnode_t *node)
228{
229  i2c_bus *bus;
230
231  bus = IMFS_generic_get_context_by_node(node);
232  (*bus->destroy)(bus);
233
234  IMFS_node_destroy_default(node);
235}
236
237static const IMFS_node_control i2c_bus_node_control = IMFS_GENERIC_INITIALIZER(
238  &i2c_bus_handler,
239  IMFS_node_initialize_generic,
240  i2c_bus_node_destroy
241);
242
243int i2c_bus_register(
244  i2c_bus *bus,
245  const char *bus_path
246)
247{
248  int rv;
249
250  rv = IMFS_make_generic_node(
251    bus_path,
252    S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO,
253    &i2c_bus_node_control,
254    bus
255  );
256  if (rv != 0) {
257    (*bus->destroy)(bus);
258  }
259
260  return rv;
261}
262
263static int i2c_bus_transfer_default(
264  i2c_bus *bus,
265  i2c_msg *msgs,
266  uint32_t msg_count
267)
268{
269  (void) bus;
270  (void) msgs;
271  (void) msg_count;
272
273  return -EIO;
274}
275
276static int i2c_bus_set_clock_default(i2c_bus *bus, unsigned long clock)
277{
278  (void) bus;
279  (void) clock;
280
281  return -EIO;
282}
283
284static int i2c_bus_do_init(
285  i2c_bus *bus,
286  void (*destroy)(i2c_bus *bus)
287)
288{
289  rtems_status_code sc;
290
291  sc = rtems_semaphore_create(
292    rtems_build_name('I', '2', 'C', ' '),
293    1,
294    RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
295    0,
296    &bus->mutex
297  );
298  if (sc != RTEMS_SUCCESSFUL) {
299    (*destroy)(bus);
300
301    rtems_set_errno_and_return_minus_one(ENOMEM);
302  }
303
304  bus->transfer = i2c_bus_transfer_default;
305  bus->set_clock = i2c_bus_set_clock_default;
306  bus->destroy = destroy;
307
308  return 0;
309}
310
311void i2c_bus_destroy(i2c_bus *bus)
312{
313  rtems_status_code sc;
314
315  sc = rtems_semaphore_delete(bus->mutex);
316  _Assert(sc == RTEMS_SUCCESSFUL);
317  (void) sc;
318}
319
320void i2c_bus_destroy_and_free(i2c_bus *bus)
321{
322  i2c_bus_destroy(bus);
323  free(bus);
324}
325
326int i2c_bus_init(i2c_bus *bus)
327{
328  memset(bus, 0, sizeof(*bus));
329
330  return i2c_bus_do_init(bus, i2c_bus_destroy);
331}
332
333i2c_bus *i2c_bus_alloc_and_init(size_t size)
334{
335  i2c_bus *bus = NULL;
336
337  if (size >= sizeof(*bus)) {
338    bus = calloc(1, size);
339    if (bus != NULL) {
340      int rv;
341
342      rv = i2c_bus_do_init(bus, i2c_bus_destroy_and_free);
343      if (rv != 0) {
344        return NULL;
345      }
346    }
347  }
348
349  return bus;
350}
Note: See TracBrowser for help on using the repository browser.