source: rtems/bsps/shared/dev/serial/legacy-console.c @ b43ea9f

5
Last change on this file since b43ea9f was b43ea9f, checked in by Sebastian Huber <sebastian.huber@…>, on 04/05/18 at 15:07:20

bsps: Move legacy console driver to bsps

This patch is a part of the BSP source reorganization.

Update #3285.

  • Property mode set to 100644
File size: 10.1 KB
Line 
1/**
2 * @file
3 *
4 * @ingroup Console
5 *
6 * @brief Extension of the generic libchip console driver shell
7 */
8
9/*
10 *  COPYRIGHT (c) 1989-2011, 2016.
11 *  On-Line Applications Research Corporation (OAR).
12 *
13 *  The license and distribution terms for this file may be
14 *  found in the file LICENSE in this distribution or at
15 *  http://www.rtems.org/license/LICENSE.
16 */
17
18#include <bsp.h>
19#include <bsp/fatal.h>
20#include <rtems/libio.h>
21#include <rtems/console.h>
22#include <stdlib.h>
23#include <string.h>
24#include <assert.h>
25#include <termios.h>
26
27#include <rtems/termiostypes.h>
28#include <libchip/serial.h>
29#include "legacy-console.h"
30
31unsigned long               Console_Port_Count  = 0;
32console_tbl               **Console_Port_Tbl    = NULL;
33console_data               *Console_Port_Data   = NULL;
34rtems_device_minor_number   Console_Port_Minor  = 0;
35static bool                 console_initialized = false;
36
37/*
38 *  console_find_console_entry
39 *
40 *  This method is used to search the console entries for a
41 *  specific device entry.
42 */
43console_tbl* console_find_console_entry(
44  const char                *match,
45  size_t                     length,
46  rtems_device_minor_number *match_minor
47)
48{
49  rtems_device_minor_number  minor;
50
51  /*
52   * The the match name is NULL get the minor number entry.
53   */
54  if (match == NULL) {
55    if (*match_minor < Console_Port_Count)
56      return Console_Port_Tbl[*match_minor];
57    return NULL;
58  }
59
60  for (minor=0; minor < Console_Port_Count ; minor++) {
61    console_tbl  *cptr = Console_Port_Tbl[minor];
62
63    /*
64     * Console table entries include /dev/ prefix, device names passed
65     * in on command line do not.
66     */
67    if ( !strncmp( cptr->sDeviceName, match, length ) ) {
68      *match_minor = minor;
69      return cptr;
70    }
71  }
72
73  return NULL;
74}
75
76/*
77 *  console_initialize_data
78 *
79 *  This method is used to initialize the table of pointers to the
80 *  serial port configuration structure entries.
81 */
82void console_initialize_data(void)
83{
84  int i;
85
86  if ( Console_Port_Tbl )
87    return;
88
89  /*
90   * Allocate memory for the table of device pointers.
91   */
92  Console_Port_Count = Console_Configuration_Count;
93  Console_Port_Tbl   = malloc( Console_Port_Count * sizeof( console_tbl * ) );
94  if (Console_Port_Tbl == NULL)
95    bsp_fatal( BSP_FATAL_CONSOLE_NO_MEMORY_0 );
96
97  /*
98   * Allocate memory for the table of device specific data pointers.
99   */
100  Console_Port_Data  = calloc( Console_Port_Count, sizeof( console_data ) );
101  if ( Console_Port_Data == NULL ) {
102    bsp_fatal( BSP_FATAL_CONSOLE_NO_MEMORY_3 );
103  }
104
105  /*
106   * Fill in the Console Table
107   */
108  for (i=0 ; i < Console_Port_Count ; i++) {
109    Console_Port_Tbl[i] = &Console_Configuration_Ports[i];
110  }
111}
112
113/*
114 *  console_register_devices
115 *
116 *  This method is used to add dynamically discovered devices to the
117 *  set of serial ports supported.
118 */
119void console_register_devices(
120  console_tbl *new_ports,
121  size_t       number_of_ports
122)
123{
124  int  old_number_of_ports;
125  int  i;
126
127  /*
128   * Initialize the console data elements
129   */
130  console_initialize_data();
131
132  /*
133   *  console_initialize() has been invoked so it is now too late to
134   *  register devices.
135   */
136  if ( console_initialized ) {
137    bsp_fatal( BSP_FATAL_CONSOLE_MULTI_INIT );
138  }
139
140  /*
141   *  Allocate memory for the console port extension
142   */
143  old_number_of_ports = Console_Port_Count;
144  Console_Port_Count += number_of_ports;
145  Console_Port_Tbl = realloc(
146    Console_Port_Tbl,
147    Console_Port_Count * sizeof(console_tbl *)
148  );
149  if ( Console_Port_Tbl == NULL ) {
150    bsp_fatal( BSP_FATAL_CONSOLE_NO_MEMORY_1 );
151  }
152
153  /*
154   * Since we can only add devices before console_initialize(),
155   * the data area will contain no information and must be zero
156   * before it is used. So extend the area and zero it out.
157   */
158  Console_Port_Data = realloc(
159    Console_Port_Data,
160    Console_Port_Count * sizeof(console_data)
161  );
162  if ( Console_Port_Data == NULL ) {
163    bsp_fatal( BSP_FATAL_CONSOLE_NO_MEMORY_2 );
164  }
165  memset(Console_Port_Data, '\0', Console_Port_Count * sizeof(console_data));
166
167  /*
168   *  Now add the new devices at the end.
169   */
170  for (i=0 ; i < number_of_ports ; i++) {
171    Console_Port_Tbl[old_number_of_ports + i]  = &new_ports[i];
172  }
173}
174
175/*
176 *  console_open
177 *
178 *  open a port as a termios console.
179 */
180rtems_device_driver console_open(
181  rtems_device_major_number major,
182  rtems_device_minor_number minor,
183  void                    * arg
184)
185{
186  rtems_status_code              status;
187  rtems_libio_open_close_args_t *args = arg;
188  rtems_libio_ioctl_args_t       IoctlArgs;
189  struct termios                 Termios;
190  rtems_termios_callbacks        Callbacks;
191  console_tbl                   *cptr;
192  struct rtems_termios_tty      *current_tty;
193
194  /*
195   * Verify the port number is valid.
196   */
197  if ( minor > Console_Port_Count ) {
198    return RTEMS_INVALID_NUMBER;
199  }
200
201  /*
202   * Open the port as a termios console driver.
203   */
204
205  cptr = Console_Port_Tbl[minor];
206  Callbacks.firstOpen            = cptr->pDeviceFns->deviceFirstOpen;
207  Callbacks.lastClose            = cptr->pDeviceFns->deviceLastClose;
208  Callbacks.pollRead             = cptr->pDeviceFns->deviceRead;
209  Callbacks.write                = cptr->pDeviceFns->deviceWrite;
210  Callbacks.setAttributes        = cptr->pDeviceFns->deviceSetAttributes;
211  if (cptr->pDeviceFlow != NULL) {
212    Callbacks.stopRemoteTx  = cptr->pDeviceFlow->deviceStopRemoteTx;
213    Callbacks.startRemoteTx = cptr->pDeviceFlow->deviceStartRemoteTx;
214  } else {
215    Callbacks.stopRemoteTx  = NULL;
216    Callbacks.startRemoteTx = NULL;
217  }
218  Callbacks.outputUsesInterrupts = cptr->pDeviceFns->deviceOutputUsesInterrupts;
219
220  /* XXX what about
221   *        Console_Port_Tbl[minor].ulMargin,
222   *        Console_Port_Tbl[minor].ulHysteresis);
223   */
224
225  status = rtems_termios_open( major, minor, arg, &Callbacks );
226  Console_Port_Data[minor].termios_data = args->iop->data1;
227
228  /* Get tty pointur from the Console_Port_Data */
229  current_tty = Console_Port_Data[minor].termios_data;
230
231  if ( (current_tty->refcount == 1) ) {
232
233    /*
234     *  If this BSP has a preferred default rate, then use that.
235     */
236    #if defined(BSP_DEFAULT_BAUD_RATE)
237      rtems_termios_set_initial_baud( current_tty, BSP_DEFAULT_BAUD_RATE );
238    #endif
239
240    /*
241     * If it's the first open, modified, if need, the port parameters
242     */
243    if ( minor != Console_Port_Minor ) {
244      /*
245       * If this is not the console we do not want ECHO and so forth
246       */
247      IoctlArgs.iop     = args->iop;
248      IoctlArgs.command = TIOCGETA;
249      IoctlArgs.buffer  = &Termios;
250      rtems_termios_ioctl( &IoctlArgs );
251
252      Termios.c_lflag   = ICANON;
253      IoctlArgs.command = TIOCSETA;
254      rtems_termios_ioctl( &IoctlArgs );
255    }
256  }
257
258  if (rtems_libio_iop_is_readable(args->iop) &&
259      cptr->pDeviceFlow &&
260      cptr->pDeviceFlow->deviceStartRemoteTx) {
261    cptr->pDeviceFlow->deviceStartRemoteTx(minor);
262  }
263
264  return status;
265}
266
267/*
268 *  console_close
269 *
270 *  This routine closes a port that has been opened as console.
271 */
272rtems_device_driver console_close(
273  rtems_device_major_number major,
274  rtems_device_minor_number minor,
275  void                    * arg
276)
277{
278  rtems_libio_open_close_args_t *args = arg;
279  struct rtems_termios_tty      *current_tty;
280  console_tbl                   *cptr;
281
282  cptr  = Console_Port_Tbl[minor];
283
284  /* Get tty pointer from the Console_Port_Data */
285  current_tty = Console_Port_Data[minor].termios_data;
286
287  /* Get the tty refcount to determine if we need to do deviceStopRemoteTx.
288   * Stop only if it's the last one opened.
289   */
290  if ( (current_tty->refcount == 1) ) {
291    if (rtems_libio_iop_is_readable(args->iop) &&
292          cptr->pDeviceFlow &&
293          cptr->pDeviceFlow->deviceStopRemoteTx) {
294      cptr->pDeviceFlow->deviceStopRemoteTx(minor);
295    }
296  }
297
298  return rtems_termios_close (arg);
299}
300
301/*
302 *  console_initialize
303 *
304 *  Routine called to initialize the console device driver.
305 */
306rtems_device_driver console_initialize(
307  rtems_device_major_number  major,
308  rtems_device_minor_number  minor_arg,
309  void                      *arg
310)
311{
312  rtems_status_code          status;
313  rtems_device_minor_number  minor;
314  console_tbl               *port;
315
316  /*
317   * If we have no devices which were registered earlier then we
318   * must still initialize pointers for Console_Port_Tbl and
319   * Console_Port_Data.
320   */
321  console_initialize_data();
322
323  /*
324   *  console_initialize has been invoked so it is now too late to
325   *  register devices.
326   */
327  console_initialized = true;
328
329  /*
330   *  Initialize the termio interface, our table of pointers to device
331   *  information structures, and determine if the user has explicitly
332   *  specified which device is to be used for the console.
333   */
334  rtems_termios_initialize();
335  bsp_console_select();
336
337  /*
338   *  Iterate over all of the console devices we know about
339   *  and initialize them.
340   */
341  for (minor=0 ; minor < Console_Port_Count ; minor++) {
342    /*
343     *  First perform the configuration dependent probe, then the
344     *  device dependent probe
345     */
346    port = Console_Port_Tbl[minor];
347
348    if ( (!port->deviceProbe || port->deviceProbe(minor)) &&
349         port->pDeviceFns->deviceProbe(minor)) {
350
351      if (port->sDeviceName != NULL) {
352        status = rtems_io_register_name( port->sDeviceName, major, minor );
353        if (status != RTEMS_SUCCESSFUL) {
354          bsp_fatal( BSP_FATAL_CONSOLE_REGISTER_DEV_0 );
355        }
356      }
357
358      if (minor == Console_Port_Minor) {
359        status = rtems_io_register_name( CONSOLE_DEVICE_NAME, major, minor );
360        if (status != RTEMS_SUCCESSFUL) {
361          bsp_fatal( BSP_FATAL_CONSOLE_REGISTER_DEV_1 );
362        }
363      }
364
365      /*
366       * Initialize the hardware device.
367       */
368      port->pDeviceFns->deviceInitialize(minor);
369
370    }
371  }
372
373  return RTEMS_SUCCESSFUL;
374}
375
376/*
377 *  console_read
378 *
379 *  This routine uses the termios driver to read a character.
380 */
381rtems_device_driver console_read(
382  rtems_device_major_number major,
383  rtems_device_minor_number minor,
384  void                    * arg
385)
386{
387  return rtems_termios_read (arg);
388}
389
390/*
391 *  console_write
392 *
393 *  this routine uses the termios driver to write a character.
394 */
395rtems_device_driver console_write(
396  rtems_device_major_number major,
397  rtems_device_minor_number minor,
398  void                    * arg
399)
400{
401  return rtems_termios_write (arg);
402}
Note: See TracBrowser for help on using the repository browser.