[b459526] | 1 | /*************************************************************************** |
---|
| 2 | * |
---|
| 3 | * MODULE DESCRIPTION: |
---|
| 4 | * This module implements the RTEMS drivers for the PC serial ports |
---|
| 5 | * as /dev/ttyS1 for COM1 and /dev/ttyS2 as COM2. If one of the ports |
---|
| 6 | * is used as the console, this driver would fail to initialize. |
---|
| 7 | * |
---|
[6128a4a] | 8 | * This code was based on the console driver. It is based on the |
---|
[b459526] | 9 | * current termios framework. This is just a shell around the |
---|
| 10 | * termios support. |
---|
| 11 | * |
---|
| 12 | * by: Rosimildo da Silva: |
---|
| 13 | * rdasilva@connecttel.com |
---|
| 14 | * http://www.connecttel.com |
---|
| 15 | * |
---|
| 16 | ****************************************************************************/ |
---|
| 17 | |
---|
[9492fb7f] | 18 | |
---|
[b459526] | 19 | #include <stdio.h> |
---|
| 20 | #include <stdlib.h> |
---|
| 21 | #include <assert.h> |
---|
| 22 | |
---|
| 23 | #include <bsp.h> |
---|
[529cebf0] | 24 | #include <bsp/irq.h> |
---|
[b459526] | 25 | #include <rtems/libio.h> |
---|
[caeb33b2] | 26 | #include <rtems/termiostypes.h> |
---|
[b459526] | 27 | #include <termios.h> |
---|
| 28 | #include <uart.h> |
---|
| 29 | #include <libcpu/cpuModel.h> |
---|
[2bdcf4fd] | 30 | #include "tty_drv.h" |
---|
[b459526] | 31 | |
---|
| 32 | int BSP_poll_read(int); |
---|
| 33 | |
---|
| 34 | /* Internal routines */ |
---|
| 35 | static int tty1_conSetAttr( int minor, const struct termios *t); |
---|
| 36 | static int tty2_conSetAttr( int minor, const struct termios *t); |
---|
| 37 | |
---|
| 38 | extern BSP_polling_getchar_function_type BSP_poll_char; |
---|
| 39 | extern int BSPConsolePort; |
---|
| 40 | extern void rtems_set_waiting_id_comx( int port, rtems_id id, rtems_event_set event ); |
---|
| 41 | |
---|
| 42 | /* |
---|
| 43 | * TTYS1 - device driver INITIALIZE entry point. |
---|
| 44 | */ |
---|
| 45 | rtems_device_driver |
---|
| 46 | tty1_initialize(rtems_device_major_number major, |
---|
| 47 | rtems_device_minor_number minor, |
---|
| 48 | void *arg) |
---|
| 49 | { |
---|
| 50 | rtems_status_code status; |
---|
| 51 | |
---|
| 52 | /* Check if this port is not been used as console */ |
---|
| 53 | if( BSPConsolePort == BSP_UART_COM1 ) |
---|
| 54 | { |
---|
| 55 | status = -1; |
---|
| 56 | printk("TTYS1: port selected as console.\n"); |
---|
| 57 | rtems_fatal_error_occurred( status ); |
---|
| 58 | } |
---|
| 59 | |
---|
| 60 | /* |
---|
| 61 | * Set up TERMIOS |
---|
| 62 | */ |
---|
| 63 | rtems_termios_initialize(); |
---|
[6128a4a] | 64 | |
---|
[b459526] | 65 | /* |
---|
| 66 | * Do device-specific initialization |
---|
| 67 | */ |
---|
| 68 | /* 9600-8-N-1, without hardware flow control */ |
---|
[8ad5399] | 69 | BSP_uart_init( BSP_UART_COM1, 9600, CHR_8_BITS, 0, 0, 0 ); |
---|
[2bdcf4fd] | 70 | status = rtems_interrupt_handler_install( |
---|
| 71 | BSP_UART_COM1_IRQ, |
---|
| 72 | "tty_drv", |
---|
| 73 | RTEMS_INTERRUPT_UNIQUE, |
---|
| 74 | BSP_uart_termios_isr_com1, |
---|
| 75 | NULL |
---|
| 76 | ); |
---|
| 77 | assert(status == RTEMS_SUCCESSFUL); |
---|
[b459526] | 78 | /* |
---|
| 79 | * Register the device |
---|
| 80 | */ |
---|
| 81 | status = rtems_io_register_name ("/dev/ttyS1", major, 0); |
---|
| 82 | if (status != RTEMS_SUCCESSFUL) |
---|
| 83 | { |
---|
| 84 | printk("Error registering ttyS1 device!\n"); |
---|
| 85 | rtems_fatal_error_occurred (status); |
---|
| 86 | } |
---|
| 87 | printk("Device: /dev/ttyS1 initialized.\n"); |
---|
| 88 | return RTEMS_SUCCESSFUL; |
---|
| 89 | } /* tty_initialize */ |
---|
| 90 | |
---|
| 91 | static int tty1_last_close(int major, int minor, void *arg) |
---|
| 92 | { |
---|
[2bdcf4fd] | 93 | rtems_status_code status; |
---|
| 94 | |
---|
| 95 | status = rtems_interrupt_handler_remove( |
---|
| 96 | BSP_UART_COM1_IRQ, |
---|
| 97 | BSP_uart_termios_isr_com1, |
---|
| 98 | NULL |
---|
| 99 | ); |
---|
| 100 | assert(status == RTEMS_SUCCESSFUL); |
---|
[b459526] | 101 | return 0; |
---|
| 102 | } |
---|
| 103 | |
---|
| 104 | /* |
---|
| 105 | * TTY1 - device driver OPEN entry point |
---|
| 106 | */ |
---|
| 107 | rtems_device_driver |
---|
| 108 | tty1_open(rtems_device_major_number major, |
---|
| 109 | rtems_device_minor_number minor, |
---|
| 110 | void *arg) |
---|
| 111 | { |
---|
| 112 | rtems_status_code status; |
---|
[caeb33b2] | 113 | #ifndef USE_TASK_DRIVEN |
---|
[6128a4a] | 114 | static rtems_termios_callbacks cb = |
---|
[caeb33b2] | 115 | { |
---|
| 116 | NULL, /* firstOpen */ |
---|
| 117 | tty1_last_close, /* lastClose */ |
---|
| 118 | NULL, /* poll read */ |
---|
| 119 | BSP_uart_termios_write_com1, /* write */ |
---|
| 120 | tty1_conSetAttr, /* setAttributes */ |
---|
| 121 | NULL, /* stopRemoteTx */ |
---|
| 122 | NULL, /* startRemoteTx */ |
---|
| 123 | TERMIOS_IRQ_DRIVEN /* outputUsesInterrupts */ |
---|
| 124 | }; |
---|
| 125 | #else |
---|
[6128a4a] | 126 | static rtems_termios_callbacks cb = |
---|
[b459526] | 127 | { |
---|
[caeb33b2] | 128 | NULL, /* firstOpen */ |
---|
[b9ff276c] | 129 | NULL, /* lastClose */ |
---|
[caeb33b2] | 130 | BSP_uart_termios_read_com1, /* poll read */ |
---|
[b459526] | 131 | BSP_uart_termios_write_com1, /* write */ |
---|
[caeb33b2] | 132 | tty1_conSetAttr, /* setAttributes */ |
---|
| 133 | NULL, /* stopRemoteTx */ |
---|
| 134 | NULL, /* startRemoteTx */ |
---|
| 135 | TERMIOS_TASK_DRIVEN /* outputUsesInterrupts */ |
---|
[b459526] | 136 | }; |
---|
[caeb33b2] | 137 | #endif |
---|
[b459526] | 138 | |
---|
| 139 | status = rtems_termios_open( major, minor, arg, &cb ); |
---|
| 140 | if(status != RTEMS_SUCCESSFUL) |
---|
| 141 | { |
---|
| 142 | printk("Error openning tty1 device\n"); |
---|
| 143 | return status; |
---|
| 144 | } |
---|
| 145 | |
---|
| 146 | /* |
---|
| 147 | * Pass data area info down to driver |
---|
| 148 | */ |
---|
[6128a4a] | 149 | BSP_uart_termios_set( BSP_UART_COM1, |
---|
[b459526] | 150 | ((rtems_libio_open_close_args_t *)arg)->iop->data1 ); |
---|
| 151 | /* Enable interrupts on channel */ |
---|
| 152 | BSP_uart_intr_ctrl( BSP_UART_COM1, BSP_UART_INTR_CTRL_TERMIOS); |
---|
| 153 | return RTEMS_SUCCESSFUL; |
---|
| 154 | } |
---|
| 155 | |
---|
| 156 | /* |
---|
| 157 | * TTY - device driver CLOSE entry point |
---|
| 158 | */ |
---|
| 159 | rtems_device_driver |
---|
| 160 | tty_close(rtems_device_major_number major, |
---|
| 161 | rtems_device_minor_number minor, |
---|
| 162 | void *arg) |
---|
| 163 | { |
---|
| 164 | |
---|
| 165 | return (rtems_termios_close (arg)); |
---|
[6128a4a] | 166 | |
---|
[b459526] | 167 | } /* tty_close */ |
---|
| 168 | |
---|
| 169 | /* |
---|
| 170 | * TTY device driver READ entry point. |
---|
| 171 | * Read characters from the tty device. |
---|
| 172 | */ |
---|
| 173 | rtems_device_driver |
---|
| 174 | tty_read(rtems_device_major_number major, |
---|
| 175 | rtems_device_minor_number minor, |
---|
| 176 | void *arg) |
---|
| 177 | { |
---|
| 178 | return rtems_termios_read (arg); |
---|
| 179 | } /* tty_read */ |
---|
[6128a4a] | 180 | |
---|
[b459526] | 181 | /* |
---|
| 182 | * TTY device driver WRITE entry point. |
---|
| 183 | * Write characters to the tty device. |
---|
| 184 | */ |
---|
| 185 | rtems_device_driver |
---|
| 186 | tty_write(rtems_device_major_number major, |
---|
| 187 | rtems_device_minor_number minor, |
---|
| 188 | void * arg) |
---|
| 189 | { |
---|
| 190 | return rtems_termios_write (arg); |
---|
[6128a4a] | 191 | |
---|
[b459526] | 192 | } /* tty_write */ |
---|
| 193 | |
---|
| 194 | /* |
---|
| 195 | * Handle ioctl request. This is a generic internal |
---|
| 196 | * routine to handle both devices. |
---|
| 197 | */ |
---|
| 198 | static rtems_device_driver tty_control( int port, void *arg ) |
---|
[6128a4a] | 199 | { |
---|
[b459526] | 200 | rtems_libio_ioctl_args_t *args = arg; |
---|
[6128a4a] | 201 | switch( args->command ) |
---|
[b459526] | 202 | { |
---|
| 203 | default: |
---|
| 204 | return rtems_termios_ioctl (arg); |
---|
| 205 | break; |
---|
| 206 | } |
---|
| 207 | args->ioctl_return = 0; |
---|
| 208 | return RTEMS_SUCCESSFUL; |
---|
| 209 | } |
---|
| 210 | |
---|
| 211 | /* |
---|
| 212 | * Handle ioctl request for ttyS1. |
---|
| 213 | */ |
---|
[6128a4a] | 214 | rtems_device_driver |
---|
[b459526] | 215 | tty1_control(rtems_device_major_number major, |
---|
| 216 | rtems_device_minor_number minor, |
---|
| 217 | void * arg |
---|
| 218 | ) |
---|
[6128a4a] | 219 | { |
---|
[b459526] | 220 | return tty_control( BSP_UART_COM1, arg ); |
---|
| 221 | } |
---|
| 222 | |
---|
| 223 | static int |
---|
| 224 | conSetAttr(int port, int minor, const struct termios *t) |
---|
| 225 | { |
---|
[8ad5399] | 226 | unsigned long baud, databits, parity, stopbits; |
---|
[b459526] | 227 | |
---|
[e2f17090] | 228 | baud = rtems_termios_baud_to_number(t->c_cflag & CBAUD); |
---|
[38c8516] | 229 | if ( baud > 115200 ) |
---|
| 230 | rtems_fatal_error_occurred (RTEMS_INTERNAL_ERROR); |
---|
| 231 | |
---|
[8ad5399] | 232 | if (t->c_cflag & PARENB) { |
---|
| 233 | /* Parity is enabled */ |
---|
| 234 | if (t->c_cflag & PARODD) { |
---|
| 235 | /* Parity is odd */ |
---|
| 236 | parity = PEN; |
---|
| 237 | } |
---|
| 238 | else { |
---|
| 239 | /* Parity is even */ |
---|
| 240 | parity = PEN | EPS; |
---|
| 241 | } |
---|
| 242 | } |
---|
| 243 | else { |
---|
| 244 | /* No parity */ |
---|
| 245 | parity = 0; |
---|
| 246 | } |
---|
[6128a4a] | 247 | |
---|
[8ad5399] | 248 | switch (t->c_cflag & CSIZE) { |
---|
| 249 | case CS5: databits = CHR_5_BITS; break; |
---|
| 250 | case CS6: databits = CHR_6_BITS; break; |
---|
| 251 | case CS7: databits = CHR_7_BITS; break; |
---|
[9751c913] | 252 | default: /* just to avoid warnings -- all cases are covered */ |
---|
[8ad5399] | 253 | case CS8: databits = CHR_8_BITS; break; |
---|
| 254 | } |
---|
| 255 | |
---|
| 256 | if (t->c_cflag & CSTOPB) { |
---|
| 257 | /* 2 stop bits */ |
---|
| 258 | stopbits = STB; |
---|
| 259 | } |
---|
| 260 | else { |
---|
| 261 | /* 1 stop bit */ |
---|
| 262 | stopbits = 0; |
---|
| 263 | } |
---|
| 264 | |
---|
| 265 | printk("Setting attributes, port=%X, baud=%d, linemode = 0x%02x\n", port, baud, databits | parity | stopbits ); |
---|
| 266 | BSP_uart_set_attributes(port, baud, databits, parity, stopbits); |
---|
[b459526] | 267 | return 0; |
---|
| 268 | } |
---|
| 269 | |
---|
| 270 | /* |
---|
| 271 | * Handle ioctl request for ttyS2. |
---|
| 272 | */ |
---|
| 273 | static int |
---|
| 274 | tty1_conSetAttr( int minor, const struct termios *t) |
---|
| 275 | { |
---|
| 276 | return conSetAttr( BSP_UART_COM1, minor, t ); |
---|
| 277 | } |
---|
| 278 | |
---|
| 279 | /* |
---|
| 280 | * TTY2 device driver INITIALIZE entry point. |
---|
| 281 | */ |
---|
| 282 | rtems_device_driver |
---|
| 283 | tty2_initialize(rtems_device_major_number major, |
---|
| 284 | rtems_device_minor_number minor, |
---|
| 285 | void *arg) |
---|
| 286 | { |
---|
| 287 | rtems_status_code status; |
---|
| 288 | |
---|
| 289 | /* Check if this port is not been used as console */ |
---|
| 290 | if( BSPConsolePort == BSP_UART_COM2 ) |
---|
| 291 | { |
---|
| 292 | status = -1; |
---|
| 293 | printk("TTY2: port selected as console.\n"); |
---|
| 294 | rtems_fatal_error_occurred( status ); |
---|
| 295 | } |
---|
| 296 | |
---|
| 297 | /* |
---|
| 298 | * Set up TERMIOS |
---|
| 299 | */ |
---|
| 300 | rtems_termios_initialize(); |
---|
[6128a4a] | 301 | |
---|
[b459526] | 302 | /* |
---|
| 303 | * Do device-specific initialization |
---|
| 304 | */ |
---|
| 305 | /* 9600-8-N-1, without hardware flow control */ |
---|
[8ad5399] | 306 | BSP_uart_init( BSP_UART_COM2, 9600, CHR_8_BITS, 0, 0, 0); |
---|
[2bdcf4fd] | 307 | status = rtems_interrupt_handler_install( |
---|
| 308 | BSP_UART_COM2_IRQ, |
---|
| 309 | "tty_drv", |
---|
| 310 | RTEMS_INTERRUPT_UNIQUE, |
---|
| 311 | BSP_uart_termios_isr_com2, |
---|
| 312 | NULL |
---|
| 313 | ); |
---|
| 314 | assert(status == RTEMS_SUCCESSFUL); |
---|
| 315 | |
---|
[b459526] | 316 | /* |
---|
| 317 | * Register the device |
---|
| 318 | */ |
---|
| 319 | status = rtems_io_register_name ("/dev/ttyS2", major, 0); |
---|
| 320 | if (status != RTEMS_SUCCESSFUL) |
---|
| 321 | { |
---|
| 322 | printk("Error registering tty2 device!\n"); |
---|
| 323 | rtems_fatal_error_occurred (status); |
---|
| 324 | } |
---|
| 325 | printk("Device: /dev/ttyS2 initialized.\n"); |
---|
| 326 | return RTEMS_SUCCESSFUL; |
---|
| 327 | } /* tty_initialize */ |
---|
| 328 | |
---|
| 329 | static int tty2_last_close(int major, int minor, void *arg) |
---|
| 330 | { |
---|
[2bdcf4fd] | 331 | rtems_status_code status; |
---|
| 332 | |
---|
| 333 | status = rtems_interrupt_handler_remove( |
---|
| 334 | BSP_UART_COM2_IRQ, |
---|
| 335 | BSP_uart_termios_isr_com2, |
---|
| 336 | NULL |
---|
| 337 | ); |
---|
| 338 | assert(status == RTEMS_SUCCESSFUL); |
---|
[b459526] | 339 | return 0; |
---|
| 340 | } |
---|
| 341 | |
---|
| 342 | /* |
---|
| 343 | * TTY2 device driver OPEN entry point |
---|
| 344 | */ |
---|
| 345 | rtems_device_driver |
---|
| 346 | tty2_open(rtems_device_major_number major, |
---|
| 347 | rtems_device_minor_number minor, |
---|
| 348 | void *arg) |
---|
| 349 | { |
---|
| 350 | rtems_status_code status; |
---|
[caeb33b2] | 351 | #ifndef USE_TASK_DRIVEN |
---|
[6128a4a] | 352 | static rtems_termios_callbacks cb = |
---|
[caeb33b2] | 353 | { |
---|
| 354 | NULL, /* firstOpen */ |
---|
| 355 | tty2_last_close, /* lastClose */ |
---|
| 356 | NULL, /* poll read */ |
---|
| 357 | BSP_uart_termios_write_com2, /* write */ |
---|
| 358 | tty2_conSetAttr, /* setAttributes */ |
---|
| 359 | NULL, /* stopRemoteTx */ |
---|
| 360 | NULL, /* startRemoteTx */ |
---|
| 361 | TERMIOS_IRQ_DRIVEN /* outputUsesInterrupts */ |
---|
| 362 | }; |
---|
| 363 | #else |
---|
[6128a4a] | 364 | static rtems_termios_callbacks cb = |
---|
[b459526] | 365 | { |
---|
[caeb33b2] | 366 | NULL, /* firstOpen */ |
---|
[b9ff276c] | 367 | NULL, /* lastClose */ |
---|
[caeb33b2] | 368 | BSP_uart_termios_read_com2, /* poll read */ |
---|
[b459526] | 369 | BSP_uart_termios_write_com2, /* write */ |
---|
[caeb33b2] | 370 | tty2_conSetAttr, /* setAttributes */ |
---|
| 371 | NULL, /* stopRemoteTx */ |
---|
| 372 | NULL, /* startRemoteTx */ |
---|
| 373 | TERMIOS_TASK_DRIVEN /* outputUsesInterrupts */ |
---|
[b459526] | 374 | }; |
---|
[caeb33b2] | 375 | #endif |
---|
[b459526] | 376 | |
---|
| 377 | status = rtems_termios_open (major, minor, arg, &cb); |
---|
| 378 | if(status != RTEMS_SUCCESSFUL) |
---|
| 379 | { |
---|
| 380 | printk("Error openning tty1 device\n"); |
---|
| 381 | return status; |
---|
| 382 | } |
---|
| 383 | |
---|
| 384 | /* |
---|
| 385 | * Pass data area info down to driver |
---|
| 386 | */ |
---|
[6128a4a] | 387 | BSP_uart_termios_set( BSP_UART_COM2, |
---|
[b459526] | 388 | ((rtems_libio_open_close_args_t *)arg)->iop->data1 ); |
---|
| 389 | /* Enable interrupts on channel */ |
---|
| 390 | BSP_uart_intr_ctrl( BSP_UART_COM2, BSP_UART_INTR_CTRL_TERMIOS); |
---|
| 391 | return RTEMS_SUCCESSFUL; |
---|
| 392 | } |
---|
| 393 | |
---|
| 394 | /* |
---|
| 395 | * Handle ioctl request for TTY2 |
---|
| 396 | */ |
---|
[6128a4a] | 397 | rtems_device_driver |
---|
[b459526] | 398 | tty2_control(rtems_device_major_number major, |
---|
| 399 | rtems_device_minor_number minor, |
---|
| 400 | void * arg |
---|
| 401 | ) |
---|
[6128a4a] | 402 | { |
---|
[b459526] | 403 | return tty_control( BSP_UART_COM2, arg ); |
---|
| 404 | } |
---|
| 405 | |
---|
| 406 | static int |
---|
| 407 | tty2_conSetAttr( int minor, const struct termios *t) |
---|
| 408 | { |
---|
| 409 | return conSetAttr( BSP_UART_COM2, minor, t ); |
---|
| 410 | } |
---|