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