[f96e8ee] | 1 | @c |
---|
[47eab0a] | 2 | @c COPYRIGHT (c) 1988-2008. |
---|
[f96e8ee] | 3 | @c On-Line Applications Research Corporation (OAR). |
---|
| 4 | @c All rights reserved. |
---|
| 5 | @c |
---|
| 6 | @c $Id$ |
---|
| 7 | @c |
---|
| 8 | |
---|
[abfbfa7] | 9 | @chapter Console Driver |
---|
[07b3693f] | 10 | |
---|
[abfbfa7] | 11 | @section Introduction |
---|
[07b3693f] | 12 | |
---|
[bc950e87] | 13 | This chapter describes the operation of a console driver using |
---|
| 14 | the RTEMS POSIX Termios support. Traditionally RTEMS has referred |
---|
| 15 | to all serial device drivers as console device drivers. A |
---|
| 16 | console driver can be used to do raw data processing in addition |
---|
| 17 | to the "normal" standard input and output device functions required |
---|
| 18 | of a console. |
---|
| 19 | |
---|
| 20 | The serial driver may be called as the consequence of a C Library |
---|
| 21 | call such as @code{printf} or @code{scanf} or directly via the |
---|
| 22 | @code{read} or @code{write} system calls. |
---|
| 23 | There are two main functioning modes: |
---|
[07b3693f] | 24 | |
---|
| 25 | @itemize @bullet |
---|
| 26 | |
---|
| 27 | @item console: formatted input/output, with special characters (end of |
---|
[bc950e87] | 28 | line, tabulations, etc.) recognition and processing, |
---|
[07b3693f] | 29 | |
---|
| 30 | @item raw: permits raw data processing. |
---|
| 31 | |
---|
| 32 | @end itemize |
---|
| 33 | |
---|
[183369d] | 34 | One may think that two serial drivers are needed to handle these two types |
---|
[07b3693f] | 35 | of data, but Termios permits having only one driver. |
---|
| 36 | |
---|
[abfbfa7] | 37 | @section Termios |
---|
[07b3693f] | 38 | |
---|
[47eab0a] | 39 | Termios is a standard for terminal management, included in the POSIX |
---|
| 40 | 1003.1b standard. As part of the POSIX and Open Group Single UNIX |
---|
| 41 | Specification, is commonly provided on UNIX implementations. The |
---|
| 42 | Open Group has the termios portion of the POSIX standard online |
---|
| 43 | at @uref{http://opengroup.org/onlinepubs/007908775/xbd/termios.html |
---|
| 44 | ,http://opengroup.org/onlinepubs/007908775/xbd/termios.html}. |
---|
| 45 | The requirements for the @code{<termios.h>} file are also provided |
---|
| 46 | and are at @uref{http://opengroup.org/onlinepubs/007908775/xsh/termios.h.html, |
---|
| 47 | http://opengroup.org/onlinepubs/007908775/xsh/termios.h.html}. |
---|
| 48 | |
---|
| 49 | Having RTEMS support for Termios is beneficial because: |
---|
[07b3693f] | 50 | |
---|
| 51 | @itemize @bullet |
---|
| 52 | |
---|
[bc950e87] | 53 | @item from the user's side because it provides standard primitive operations |
---|
| 54 | to access the terminal and change configuration settings. These operations |
---|
| 55 | are the same under Unix and Rtems. |
---|
[07b3693f] | 56 | |
---|
[bc950e87] | 57 | @item from the BSP developer's side because it frees the |
---|
| 58 | developer from dealing with buffer states and mutual exclusions on them. |
---|
| 59 | Early RTEMS console device drivers also did their own special |
---|
| 60 | character processing. |
---|
[07b3693f] | 61 | |
---|
[47eab0a] | 62 | @item it is part of an internationally recognized standard. |
---|
| 63 | |
---|
| 64 | @item it makes porting code from other environments easier. |
---|
| 65 | |
---|
[07b3693f] | 66 | @end itemize |
---|
| 67 | |
---|
| 68 | Termios support includes: |
---|
| 69 | |
---|
| 70 | @itemize @bullet |
---|
| 71 | |
---|
| 72 | @item raw and console handling, |
---|
| 73 | |
---|
| 74 | @item blocking or non-blocking characters receive, with or without |
---|
| 75 | Timeout. |
---|
| 76 | |
---|
| 77 | @end itemize |
---|
| 78 | |
---|
[bc950e87] | 79 | At this time, RTEMS documentation does not include a thorough discussion |
---|
| 80 | of the Termios functionality. For more information on Termios, |
---|
| 81 | type @code{man termios} on a Unix box or point a web browser |
---|
| 82 | at |
---|
[b406ad20] | 83 | @uref{http://www.freebsd.org/cgi/man.cgi}. |
---|
[07b3693f] | 84 | |
---|
[abfbfa7] | 85 | @section Driver Functioning Modes |
---|
[07b3693f] | 86 | |
---|
| 87 | There are generally two main functioning modes for an UART (Universal |
---|
| 88 | Asynchronous Receiver-Transmitter, i.e. the serial chip): |
---|
| 89 | |
---|
| 90 | @itemize @bullet |
---|
| 91 | |
---|
[bc950e87] | 92 | @item polled mode |
---|
| 93 | @item interrupt driven mode |
---|
[07b3693f] | 94 | |
---|
| 95 | @end itemize |
---|
| 96 | |
---|
[bc950e87] | 97 | In polled mode, the processor blocks on sending/receiving characters. |
---|
| 98 | This mode is not the most efficient way to utilize the UART. But |
---|
| 99 | polled mode is usually necessary when one wants to print an |
---|
[183369d] | 100 | error message in the event of a fatal error such as a fatal error |
---|
[bc950e87] | 101 | in the BSP. This is also the simplest mode to |
---|
| 102 | program. Polled mode is generally preferred if the serial port is |
---|
| 103 | to be used primarily as a debug console. In a simple polled driver, |
---|
| 104 | the software will continuously check the status of the UART when |
---|
| 105 | it is reading or writing to the UART. Termios improves on this |
---|
| 106 | by delaying the caller for 1 clock tick between successive checks |
---|
| 107 | of the UART on a read operation. |
---|
| 108 | |
---|
| 109 | In interrupt driven mode, the processor does not block on sending/receiving |
---|
| 110 | characters. Data is buffered between the interrupt service routine |
---|
| 111 | and application code. Two buffers are used to insulate the application |
---|
| 112 | from the relative slowness of the serial device. One of the buffers is |
---|
| 113 | used for incoming characters, while the other is used for outgoing characters. |
---|
| 114 | |
---|
| 115 | An interrupt is raised when a character is received by the UART. |
---|
| 116 | The interrupt subroutine places the incoming character at the end |
---|
| 117 | of the input buffer. When an application asks for input, |
---|
| 118 | the characters at the front of the buffer are returned. |
---|
| 119 | |
---|
| 120 | When the application prints to the serial device, the outgoing characters |
---|
| 121 | are placed at the end of the output buffer. The driver will place |
---|
| 122 | one or more characters in the UART (the exact number depends on the UART) |
---|
| 123 | An interrupt will be raised when all the characters have been transmitted. |
---|
| 124 | The interrupt service routine has to send the characters |
---|
| 125 | remaining in the output buffer the same way. When the transmitting side |
---|
| 126 | of the UART is idle, it is typically necessary to prime the transmitter |
---|
| 127 | before the first interrupt will occur. |
---|
| 128 | |
---|
[abfbfa7] | 129 | @section Serial Driver Functioning Overview |
---|
[07b3693f] | 130 | |
---|
[bc950e87] | 131 | The following Figure shows how a Termios driven serial driver works: |
---|
| 132 | |
---|
[47eab0a] | 133 | @ifset use-ascii |
---|
| 134 | @center Figure not included in ASCII version |
---|
| 135 | @end ifset |
---|
| 136 | |
---|
| 137 | @ifset use-tex |
---|
| 138 | @sp1 |
---|
| 139 | @center{@image{TERMIOSFlow,,6in}} |
---|
| 140 | @end ifset |
---|
| 141 | |
---|
| 142 | @ifset use-html |
---|
| 143 | @html |
---|
[f4b6dc0] | 144 | <P ALIGN="center"><IMG SRC="TERMIOSFlow.png" ALT="Termios Flow"></P> |
---|
[47eab0a] | 145 | @end html |
---|
| 146 | @end ifset |
---|
| 147 | |
---|
[bc950e87] | 148 | The following list describes the basic flow. |
---|
[07b3693f] | 149 | |
---|
| 150 | @itemize @bullet |
---|
| 151 | |
---|
| 152 | @item the application programmer uses standard C library call (printf, |
---|
| 153 | scanf, read, write, etc.), |
---|
| 154 | |
---|
[47eab0a] | 155 | @item C library (e.g. RedHat (formerly Cygnus) Newlib) calls |
---|
| 156 | the RTEMS system call interface. This code can be found in the |
---|
| 157 | @code{cpukit/libcsupport/src} directory. |
---|
[07b3693f] | 158 | |
---|
[bc950e87] | 159 | @item Glue code calls the serial driver entry routines. |
---|
[07b3693f] | 160 | |
---|
| 161 | @end itemize |
---|
| 162 | |
---|
[47eab0a] | 163 | @subsection Basics |
---|
[07b3693f] | 164 | |
---|
[47eab0a] | 165 | You need to include the following header files in your Termios device driver |
---|
| 166 | source file: |
---|
| 167 | @example |
---|
| 168 | @group |
---|
| 169 | #include <unistd.h> |
---|
| 170 | #include <termios.h> |
---|
[07b3693f] | 171 | |
---|
[47eab0a] | 172 | #include <rtems.h> |
---|
| 173 | #include <rtems/libio.h> |
---|
| 174 | #include <rtems/console.h> |
---|
| 175 | @end group |
---|
| 176 | @end example |
---|
| 177 | |
---|
| 178 | You need to provide a data structure for the Termios driver interface. The |
---|
| 179 | functions are described later in this chapter. The functions should return |
---|
| 180 | zero on succes and minus one in case of an error. Currently the return value |
---|
| 181 | will be not checked from the Termios infrastructure in most cases. One notable |
---|
| 182 | exception is the polled read function, here is the return value important. |
---|
[07b3693f] | 183 | |
---|
[47eab0a] | 184 | If you want to use polled IO it should look like the following. You may also |
---|
| 185 | have a look at @code{c/src/lib/libbsp/shared/console-polled.c} for a shared |
---|
| 186 | implementation of the basic framework. Termios must be told the addresses of |
---|
| 187 | the functions that are to be used for simple character IO, i.e. pointers to the |
---|
| 188 | @code{my_driver_poll_read} and @code{my_driver_poll_write} functions described |
---|
| 189 | later in @ref{Console Driver Termios and Polled IO}. |
---|
[07b3693f] | 190 | |
---|
| 191 | @example |
---|
[bc950e87] | 192 | @group |
---|
[47eab0a] | 193 | static const rtems_termios_callbacks my_driver_callbacks_polled = @{ |
---|
| 194 | .firstOpen = my_driver_first_open, |
---|
| 195 | .lastClose = my_driver_last_close, |
---|
| 196 | .pollRead = my_driver_poll_read, |
---|
| 197 | .write = my_driver_poll_write, |
---|
| 198 | .setAttributes = my_driver_set_attributes, |
---|
| 199 | .stopRemoteTx = NULL, |
---|
| 200 | .startRemoteTx = NULL, |
---|
| 201 | .outputUsesInterrupts = TERMIOS_POLLED |
---|
| 202 | @}; |
---|
[bc950e87] | 203 | @end group |
---|
[07b3693f] | 204 | @end example |
---|
| 205 | |
---|
[47eab0a] | 206 | For an interrupt driven implementation you need the following. The driver |
---|
| 207 | functioning is quite different in this mode. There is no device driver read |
---|
| 208 | function to be passed to Termios. Indeed a @code{console_read} call returns |
---|
| 209 | the contents of Termios input buffer. This buffer is filled in the driver |
---|
| 210 | interrupt subroutine, see also |
---|
| 211 | @ref{Console Driver Termios and Interrupt Driven IO}. |
---|
| 212 | The driver is responsible for providing a pointer to the |
---|
| 213 | @code{my_driver_interrupt_write} function. |
---|
[bc950e87] | 214 | |
---|
| 215 | @example |
---|
| 216 | @group |
---|
[47eab0a] | 217 | static const rtems_termios_callbacks my_driver_callbacks_interrupt = @{ |
---|
| 218 | .firstOpen = my_driver_first_open, |
---|
| 219 | .lastClose = my_driver_last_close, |
---|
| 220 | .pollRead = NULL, |
---|
| 221 | .write = my_driver_interrupt_write, |
---|
| 222 | .setAttributes = my_driver_set_attributes, |
---|
| 223 | .stopRemoteTx = NULL, |
---|
| 224 | .startRemoteTx = NULL, |
---|
| 225 | .outputUsesInterrupts = TERMIOS_IRQ_DRIVEN |
---|
| 226 | @}; |
---|
[bc950e87] | 227 | @end group |
---|
| 228 | @end example |
---|
[07b3693f] | 229 | |
---|
[47eab0a] | 230 | You can also provide callback functions for remote transmission control. This |
---|
| 231 | is not covered in this manual, so thay are set to @code{NULL} in the above |
---|
| 232 | examples. |
---|
[07b3693f] | 233 | |
---|
[47eab0a] | 234 | Normally the device specific data structures are stored in a table which is |
---|
| 235 | indexed by the minor number. You may need an entry for the Termios handler |
---|
| 236 | pointer in your data structure. For simplicity of the console initialization |
---|
| 237 | example the device name is also present. |
---|
[bc950e87] | 238 | |
---|
[47eab0a] | 239 | @example |
---|
| 240 | @group |
---|
| 241 | /* Driver specific data structure */ |
---|
| 242 | typedef struct @{ |
---|
| 243 | const char *device_name; |
---|
| 244 | struct rtems_termios_tty *tty; |
---|
| 245 | @} my_driver_entry; |
---|
| 246 | |
---|
| 247 | /* |
---|
| 248 | * This table contains the driver specific data. It is later |
---|
| 249 | * indexed by the minor number. |
---|
| 250 | */ |
---|
| 251 | static my_driver_entry my_driver_table [MY_DRIVER_DEVICE_NUMBER]; |
---|
| 252 | @end group |
---|
| 253 | @end example |
---|
[bc950e87] | 254 | |
---|
[47eab0a] | 255 | @subsection Termios and Polled IO |
---|
| 256 | |
---|
| 257 | The following functions are provided by the driver and invoked by |
---|
| 258 | Termios for simple character IO. |
---|
[bc950e87] | 259 | |
---|
[47eab0a] | 260 | The @code{my_driver_poll_write} routine is responsible for writing @code{n} |
---|
| 261 | characters from @code{buf} to the serial device specified by @code{minor}. |
---|
[07b3693f] | 262 | |
---|
| 263 | @example |
---|
[bc950e87] | 264 | @group |
---|
[47eab0a] | 265 | static int my_driver_poll_write(int minor, const char *buf, int n) |
---|
[bc950e87] | 266 | @{ |
---|
[47eab0a] | 267 | my_driver_entry *e = &my_driver_table [minor]; |
---|
| 268 | int i = 0; |
---|
| 269 | |
---|
| 270 | /* |
---|
| 271 | * There is no need to check the minor number since it is derived |
---|
| 272 | * from a file descriptor. The upper layer takes care that it is |
---|
| 273 | * in a valid range. |
---|
| 274 | */ |
---|
| 275 | |
---|
| 276 | /* Write */ |
---|
| 277 | for (i = 0; i < n; ++i) @{ |
---|
| 278 | my_driver_write_char(e, buf [i]); |
---|
| 279 | @} |
---|
| 280 | |
---|
| 281 | return 0; |
---|
[bc950e87] | 282 | @} |
---|
| 283 | @end group |
---|
[07b3693f] | 284 | @end example |
---|
| 285 | |
---|
[47eab0a] | 286 | The @code{my_driver_poll_read} routine is responsible for reading a single |
---|
| 287 | character from the serial device specified by @code{minor}. If no character is |
---|
| 288 | available, then the routine should return minus one. |
---|
[07b3693f] | 289 | |
---|
| 290 | @example |
---|
[47eab0a] | 291 | @group |
---|
| 292 | static int my_driver_poll_read(int minor) |
---|
[bc950e87] | 293 | @{ |
---|
[47eab0a] | 294 | my_driver_entry *e = &my_driver_table [minor]; |
---|
| 295 | |
---|
| 296 | /* |
---|
| 297 | * There is no need to check the minor number since it is derived |
---|
| 298 | * from a file descriptor. The upper layer takes care that it is |
---|
| 299 | * in a valid range. |
---|
| 300 | */ |
---|
| 301 | |
---|
| 302 | /* Check if a character is available */ |
---|
| 303 | if (my_driver_can_read_char(e)) @{ |
---|
| 304 | /* Return the character */ |
---|
| 305 | return my_driver_read_char(e); |
---|
| 306 | @} else @{ |
---|
| 307 | /* Return an error status */ |
---|
| 308 | return -1; |
---|
| 309 | @} |
---|
[bc950e87] | 310 | @} |
---|
[47eab0a] | 311 | @end group |
---|
[07b3693f] | 312 | @end example |
---|
| 313 | |
---|
[47eab0a] | 314 | @subsection Termios and Interrupt Driven IO |
---|
[07b3693f] | 315 | |
---|
[47eab0a] | 316 | The UART generally generates interrupts when it is ready to accept or to emit a |
---|
| 317 | number of characters. In this mode, the interrupt subroutine is the core of |
---|
| 318 | the driver. |
---|
[07b3693f] | 319 | |
---|
[47eab0a] | 320 | The @code{my_driver_interrupt_handler} is responsible for processing |
---|
| 321 | asynchronous interrupts from the UART. There may be multiple interrupt |
---|
| 322 | handlers for a single UART. Some UARTs can generate a unique interrupt vector |
---|
| 323 | for each interrupt source such as a character has been received or the |
---|
| 324 | transmitter is ready for another character. |
---|
[07b3693f] | 325 | |
---|
[47eab0a] | 326 | In the simplest case, the @code{my_driver_interrupt_handler} will have to check |
---|
| 327 | the status of the UART and determine what caused the interrupt. The following |
---|
| 328 | describes the operation of an @code{my_driver_interrupt_handler} which has to |
---|
| 329 | do this: |
---|
[07b3693f] | 330 | |
---|
[47eab0a] | 331 | @example |
---|
| 332 | @group |
---|
| 333 | static void my_driver_interrupt_handler( |
---|
| 334 | rtems_vector_number vector, |
---|
| 335 | void *arg |
---|
| 336 | ) |
---|
| 337 | @{ |
---|
| 338 | my_driver_entry *e = (my_driver_entry *) arg; |
---|
| 339 | char buf [N]; |
---|
| 340 | int n = 0; |
---|
| 341 | |
---|
| 342 | /* |
---|
| 343 | * Check if we have received something. The function reads the |
---|
| 344 | * received characters from the device and stores them in the |
---|
| 345 | * buffer. It returns the number of read characters. |
---|
| 346 | */ |
---|
| 347 | n = my_driver_read_received_chars(e, buf, N); |
---|
| 348 | if (n > 0) @{ |
---|
| 349 | /* Hand the data over to the Termios infrastructure */ |
---|
| 350 | rtems_termios_enqueue_raw_characters(e->tty, buf, n); |
---|
| 351 | @} |
---|
| 352 | |
---|
| 353 | /* |
---|
| 354 | * Check if we have something transmitted. The functions returns |
---|
| 355 | * the number of transmitted characters since the last write to the |
---|
| 356 | * device. |
---|
| 357 | */ |
---|
| 358 | n = my_driver_transmitted_chars(e); |
---|
| 359 | if (n > 0) @{ |
---|
| 360 | /* |
---|
| 361 | * Notify Termios that we have transmitted some characters. It |
---|
| 362 | * will call now the interrupt write function if more characters |
---|
| 363 | * are ready for transmission. |
---|
| 364 | */ |
---|
| 365 | rtems_termios_dequeue_characters(e->tty, n); |
---|
| 366 | @} |
---|
| 367 | @} |
---|
| 368 | @end group |
---|
| 369 | @end example |
---|
[07b3693f] | 370 | |
---|
[47eab0a] | 371 | The @code{my_driver_interrupt_write} function is responsible for telling the |
---|
| 372 | device that the @code{n} characters at @code{buf} are to be transmitted. The |
---|
| 373 | return value may be arbitrary since it is not checked from Termios. |
---|
[07b3693f] | 374 | |
---|
| 375 | @example |
---|
[47eab0a] | 376 | @group |
---|
| 377 | static int my_driver_interrupt_write(int minor, const char *buf, int n) |
---|
| 378 | @{ |
---|
| 379 | my_driver_entry *e = &my_driver_table [minor]; |
---|
| 380 | |
---|
| 381 | /* |
---|
| 382 | * There is no need to check the minor number since it is derived |
---|
| 383 | * from a file descriptor. The upper layer takes care that it is |
---|
| 384 | * in a valid range. |
---|
| 385 | */ |
---|
| 386 | |
---|
| 387 | /* |
---|
| 388 | * Tell the device to transmit some characters from buf (less than |
---|
| 389 | * or equal to n). If the device is finished it should raise an |
---|
| 390 | * interrupt. The interrupt handler will notify Termios that these |
---|
| 391 | * characters have been transmitted and this may trigger this write |
---|
| 392 | * function again. You may have to store the number of outstanding |
---|
| 393 | * characters in the device data structure. |
---|
| 394 | */ |
---|
| 395 | |
---|
| 396 | return 0; |
---|
| 397 | @} |
---|
| 398 | @end group |
---|
[07b3693f] | 399 | @end example |
---|
| 400 | |
---|
[47eab0a] | 401 | @subsection Initialization |
---|
| 402 | |
---|
| 403 | The driver initialization is called once during the RTEMS initialization |
---|
| 404 | process. |
---|
[07b3693f] | 405 | |
---|
[47eab0a] | 406 | The @code{console_initialize} function may look like this: |
---|
[07b3693f] | 407 | |
---|
| 408 | @example |
---|
[47eab0a] | 409 | @group |
---|
| 410 | rtems_device_driver console_initialize( |
---|
| 411 | rtems_device_major_number major, |
---|
| 412 | rtems_device_minor_number minor, |
---|
| 413 | void *arg |
---|
| 414 | ) |
---|
| 415 | @{ |
---|
| 416 | rtems_status_code sc = RTEMS_SUCCESSFUL; |
---|
| 417 | rtems_device_minor_number i = 0; |
---|
| 418 | |
---|
| 419 | /* |
---|
| 420 | * Initialize the Termios infrastructure. If Termios has already |
---|
| 421 | * been initialized by another device driver, then this call will |
---|
| 422 | * have no effect. |
---|
| 423 | */ |
---|
| 424 | rtems_termios_initialize(); |
---|
| 425 | |
---|
| 426 | /* Initialize each device */ |
---|
| 427 | for (i = 0; i < MY_DRIVER_DEVICE_NUMBER; ++i) @{ |
---|
| 428 | my_driver_entry *e = &my_driver_table [i]; |
---|
| 429 | |
---|
| 430 | /* |
---|
| 431 | * Register this device in the file system. In order to use the |
---|
| 432 | * console (i.e. being able to do printf, scanf etc. on stdin, |
---|
| 433 | * stdout and stderr), some device must be registered |
---|
| 434 | * as "/dev/console" (CONSOLE_DEVICE_NAME). |
---|
| 435 | */ |
---|
| 436 | sc = rtems_io_register_name (e->device_name, major, i); |
---|
| 437 | RTEMS_CHECK_SC(sc, "Register IO device"); |
---|
| 438 | |
---|
| 439 | /* |
---|
| 440 | * Initialize this device and install the interrupt handler if |
---|
| 441 | * necessary. You may also initialize the device in the first |
---|
| 442 | * open call. |
---|
| 443 | */ |
---|
| 444 | @} |
---|
| 445 | |
---|
| 446 | return RTEMS_SUCCESSFUL; |
---|
| 447 | @} |
---|
| 448 | @end group |
---|
[07b3693f] | 449 | @end example |
---|
| 450 | |
---|
[3351d41] | 451 | @subsection Opening a serial device |
---|
[07b3693f] | 452 | |
---|
[47eab0a] | 453 | The @code{console_open} function is called whenever a serial device is opened. |
---|
| 454 | The device registered as @code{"/dev/console"} (@code{CONSOLE_DEVICE_NAME}) is |
---|
| 455 | opened automatically during RTEMS initialization. For instance, if UART |
---|
| 456 | channel 2 is registered as "/dev/tty1", the @code{console_open} entry point |
---|
| 457 | will be called as the result of an @code{fopen("/dev/tty1", mode)} in the |
---|
[07b3693f] | 458 | application. |
---|
| 459 | |
---|
[bc950e87] | 460 | The @code{console_open} function has to inform Termios of the low-level |
---|
[47eab0a] | 461 | functions for serial line support. |
---|
[07b3693f] | 462 | |
---|
[47eab0a] | 463 | @example |
---|
| 464 | @group |
---|
| 465 | rtems_device_driver console_open( |
---|
| 466 | rtems_device_major_number major, |
---|
| 467 | rtems_device_minor_number minor, |
---|
| 468 | void *arg |
---|
| 469 | ) |
---|
| 470 | @{ |
---|
| 471 | struct rtems_termios_callbacks *callbacks = |
---|
| 472 | &my_driver_callbacks_polled; |
---|
| 473 | |
---|
| 474 | /* |
---|
| 475 | * Check the minor number. Termios does currently not check |
---|
| 476 | * the return value of the first open call so the minor |
---|
| 477 | * number must be checked here. |
---|
| 478 | */ |
---|
| 479 | if (MY_DRIVER_IS_MINOR_INVALID(minor)) @{ |
---|
| 480 | return RTEMS_INVALID_NUMBER; |
---|
| 481 | @} |
---|
| 482 | |
---|
| 483 | /* |
---|
| 484 | * Depending on the IO mode you need to pass a different set of |
---|
| 485 | * callback functions to Termios. |
---|
| 486 | */ |
---|
| 487 | if (MY_DRIVER_USES_INTERRUPTS(minor)) @{ |
---|
| 488 | callbacks = &my_driver_callbacks_interrupt; |
---|
| 489 | @} |
---|
| 490 | |
---|
| 491 | return rtems_termios_open(major, minor, arg, callbacks); |
---|
| 492 | @} |
---|
| 493 | @end group |
---|
| 494 | @end example |
---|
[07b3693f] | 495 | |
---|
[47eab0a] | 496 | During the first open of the device Termios will call @code{my_driver_first_open}. |
---|
[07b3693f] | 497 | |
---|
[47eab0a] | 498 | @example |
---|
| 499 | @group |
---|
| 500 | static int my_driver_first_open(int major, int minor, void *arg) |
---|
| 501 | @{ |
---|
| 502 | my_driver_entry *e = &my_driver_table [minor]; |
---|
| 503 | struct rtems_termios_tty *tty = |
---|
| 504 | ((rtems_libio_open_close_args_t *) arg)->iop->data1; |
---|
| 505 | |
---|
| 506 | /* Check minor number */ |
---|
| 507 | if (MY_DRIVER_IS_MINOR_INVALID(minor)) @{ |
---|
| 508 | return -1; |
---|
| 509 | @} |
---|
| 510 | |
---|
| 511 | /* Connect the TTY data structure */ |
---|
| 512 | e->tty = tty; |
---|
| 513 | |
---|
| 514 | /* |
---|
| 515 | * You may add some initialization code here. |
---|
| 516 | */ |
---|
| 517 | |
---|
| 518 | /* |
---|
| 519 | * Sets the inital baud rate. This should be set to the value of |
---|
| 520 | * the boot loader. |
---|
| 521 | */ |
---|
| 522 | return rtems_termios_set_initial_baud(e->tty, MY_DRIVER_BAUD_RATE); |
---|
| 523 | @} |
---|
| 524 | @end group |
---|
| 525 | @end example |
---|
[07b3693f] | 526 | |
---|
[47eab0a] | 527 | @subsection Closing a Serial Device |
---|
[07b3693f] | 528 | |
---|
[47eab0a] | 529 | The @code{console_close} is invoked when the serial device is to be closed. |
---|
| 530 | This entry point corresponds to the device driver close entry point. |
---|
[07b3693f] | 531 | |
---|
[47eab0a] | 532 | This routine is responsible for notifying Termios that the serial device was |
---|
| 533 | closed. This is done with a call to @code{rtems_termios_close}. |
---|
[bc950e87] | 534 | |
---|
[47eab0a] | 535 | @example |
---|
| 536 | @group |
---|
| 537 | rtems_device_driver console_close( |
---|
| 538 | rtems_device_major_number major, |
---|
| 539 | rtems_device_minor_number minor, |
---|
| 540 | void *arg |
---|
| 541 | ) |
---|
| 542 | @{ |
---|
| 543 | return rtems_termios_close(arg); |
---|
| 544 | @} |
---|
| 545 | @end group |
---|
| 546 | @end example |
---|
[07b3693f] | 547 | |
---|
[47eab0a] | 548 | Termios will call the @code{my_driver_last_close} function if the last close |
---|
| 549 | happens on the device. |
---|
| 550 | @example |
---|
| 551 | @group |
---|
| 552 | static int my_driver_last_close(int major, int minor, void *arg) |
---|
| 553 | @{ |
---|
| 554 | my_driver_entry *e = &my_driver_table [minor]; |
---|
| 555 | |
---|
| 556 | /* |
---|
| 557 | * There is no need to check the minor number since it is derived |
---|
| 558 | * from a file descriptor. The upper layer takes care that it is |
---|
| 559 | * in a valid range. |
---|
| 560 | */ |
---|
| 561 | |
---|
| 562 | /* Disconnect the TTY data structure */ |
---|
| 563 | e->tty = NULL; |
---|
| 564 | |
---|
| 565 | /* |
---|
| 566 | * The driver may do some cleanup here. |
---|
| 567 | */ |
---|
| 568 | |
---|
| 569 | return 0; |
---|
| 570 | @} |
---|
| 571 | @end group |
---|
| 572 | @end example |
---|
[07b3693f] | 573 | |
---|
[47eab0a] | 574 | @subsection Reading Characters from a Serial Device |
---|
[07b3693f] | 575 | |
---|
[47eab0a] | 576 | The @code{console_read} is invoked when the serial device is to be read from. |
---|
| 577 | This entry point corresponds to the device driver read entry point. |
---|
[07b3693f] | 578 | |
---|
[47eab0a] | 579 | This routine is responsible for returning the content of the Termios input |
---|
| 580 | buffer. This is done by invoking the @code{rtems_termios_read} routine. |
---|
[07b3693f] | 581 | |
---|
[47eab0a] | 582 | @example |
---|
| 583 | @group |
---|
| 584 | rtems_device_driver console_read( |
---|
| 585 | rtems_device_major_number major, |
---|
| 586 | rtems_device_minor_number minor, |
---|
| 587 | void *arg |
---|
| 588 | ) |
---|
| 589 | @{ |
---|
| 590 | return rtems_termios_read(arg); |
---|
| 591 | @} |
---|
| 592 | @end group |
---|
| 593 | @end example |
---|
[07b3693f] | 594 | |
---|
[47eab0a] | 595 | @subsection Writing Characters to a Serial Device |
---|
[07b3693f] | 596 | |
---|
[47eab0a] | 597 | The @code{console_write} is invoked when the serial device is to be written to. |
---|
| 598 | This entry point corresponds to the device driver write entry point. |
---|
[07b3693f] | 599 | |
---|
[47eab0a] | 600 | This routine is responsible for adding the requested characters to the Termios |
---|
| 601 | output queue for this device. This is done by calling the routine |
---|
| 602 | @code{rtems_termios_write} to add the characters at the end of the Termios |
---|
| 603 | output buffer. |
---|
[07b3693f] | 604 | |
---|
[47eab0a] | 605 | @example |
---|
| 606 | @group |
---|
| 607 | rtems_device_driver console_write( |
---|
| 608 | rtems_device_major_number major, |
---|
| 609 | rtems_device_minor_number minor, |
---|
| 610 | void *arg |
---|
| 611 | ) |
---|
| 612 | @{ |
---|
| 613 | return rtems_termios_write(arg); |
---|
| 614 | @} |
---|
| 615 | @end group |
---|
| 616 | @end example |
---|
[07b3693f] | 617 | |
---|
[47eab0a] | 618 | @subsection Changing Serial Line Parameters |
---|
[07b3693f] | 619 | |
---|
[47eab0a] | 620 | The @code{console_control} is invoked when the line parameters for a particular |
---|
| 621 | serial device are to be changed. This entry point corresponds to the device |
---|
| 622 | driver io_control entry point. |
---|
[07b3693f] | 623 | |
---|
[47eab0a] | 624 | The application writer is able to control the serial line configuration with |
---|
| 625 | Termios calls (such as the @code{ioctl} command, see the Termios documentation |
---|
| 626 | for more details). If the driver is to support dynamic configuration, then it |
---|
| 627 | must have the @code{console_control} piece of code. Basically @code{ioctl} |
---|
| 628 | commands call @code{console_control} with the serial line configuration in a |
---|
| 629 | Termios defined data structure. |
---|
[07b3693f] | 630 | |
---|
[47eab0a] | 631 | @example |
---|
| 632 | @group |
---|
| 633 | rtems_device_driver console_control( |
---|
| 634 | rtems_device_major_number major, |
---|
| 635 | rtems_device_minor_number minor, |
---|
| 636 | void *arg |
---|
| 637 | ) |
---|
| 638 | @{ |
---|
| 639 | return rtems_termios_ioctl(arg); |
---|
| 640 | @} |
---|
| 641 | @end group |
---|
| 642 | @end example |
---|
[07b3693f] | 643 | |
---|
[47eab0a] | 644 | The driver is responsible for reinitializing the device with the correct |
---|
| 645 | settings. For this purpuse Termios calls the @code{my_driver_set_attributes} |
---|
| 646 | function. |
---|
[07b3693f] | 647 | |
---|
[47eab0a] | 648 | @example |
---|
| 649 | @group |
---|
| 650 | static int my_driver_set_attributes( |
---|
| 651 | int minor, |
---|
| 652 | const struct termios *t |
---|
| 653 | ) |
---|
| 654 | @{ |
---|
| 655 | my_driver_entry *e = &my_driver_table [minor]; |
---|
| 656 | |
---|
| 657 | /* |
---|
| 658 | * There is no need to check the minor number since it is derived |
---|
| 659 | * from a file descriptor. The upper layer takes care that it is |
---|
| 660 | * in a valid range. |
---|
| 661 | */ |
---|
| 662 | |
---|
| 663 | /* |
---|
| 664 | * Inspect the termios data structure and configure the device |
---|
| 665 | * appropriately. The driver should only be concerned with the |
---|
| 666 | * parts of the structure that specify hardware setting for the |
---|
| 667 | * communications channel such as baud, character size, etc. |
---|
| 668 | */ |
---|
| 669 | |
---|
| 670 | return 0; |
---|
| 671 | @} |
---|
| 672 | @end group |
---|
| 673 | @end example |
---|