FreeBASIC  0.91.0
io_serial.c
Go to the documentation of this file.
1 /* serial port driver for Dos */
2 
3 #include "../fb.h"
4 #include <dos.h>
5 #include <pc.h>
6 #include <go32.h>
7 #include <dpmi.h>
8 
9 /* PIC port addresses. */
10 #define ICU_BASE 0x20
11 #define ICU_OCW2 (ICU_BASE + 0)
12 #define ICU_MASK (ICU_BASE + 1)
13 
14 /* UART port registers */
15 #define UART_RBR 0x00 /* DLAB = 0 - Receive Buffer*/
16 #define UART_THR 0x00 /* DLAB = 0 - Transmit Hold */
17 #define UART_IER 0x01 /* interrupt enable register */
18 #define UART_IIR 0x02 /* interrupt ID register */
19 #define UART_FCR 0x02 /* FIFO control register */
20 #define UART_LCR 0x03 /* line control / data format */
21 #define UART_MCR 0x04 /* modem control register */
22 #define UART_LSR 0x05 /* line status register */
23 #define UART_MSR 0x06 /* modem status register */
24 #define UART_SCR 0x07 /* scratch register */
25 #define UART_DL_LSB 0x00 /* DLAB = 1 */
26 #define UART_DL_MSB 0x01 /* DLAB = 1 */
27 
28 #define LCR_DLAB 0x80
29 
30 #define MCR_OUT2 8
31 #define MCR_OUT1 4
32 #define MCR_RTS 2
33 #define MCR_DTR 1
34 
35 #define IER_SINP 8
36 #define IER_EBRK 4
37 #define IER_TBE 2
38 #define IER_RXRD 1
39 
40 /* FLAGS */
41 #define FLAG_KEEP_DTR 1
42 #define FLAG_SUPPRESS_RTS 2
43 
44 /* UART types */
45 #define UART_IS_NONE 0
46 #define UART_IS_8250 1
47 #define UART_IS_16450 2
48 #define UART_IS_16550 3
49 #define UART_IS_16550A 4
50 
51 #define DEFAULT_BUFFERSIZE 2048
52 #define MAX_BUFFERSIZE 0x40000000
53 
54 #define COMM_CHECKED_CHIPTYPE 1
55 #define COMM_HAVE_BUFFER 2
56 
57 /* Only irq3 to irq7 are supported */
58 #define FIRST_IRQ 3
59 #define IRQ_COUNT 5
60 #define LAST_IRQ (FIRST_IRQ+IRQ_COUNT-1)
61 
62 #define MAX_COMM 4
63 
64 #define COMM_PROPS( n ) &comm_props[n-1]
65 #define IRQ_PROPS( n ) &irq_props[n-FIRST_IRQ]
66 
67 /*
68  This define will make this source use the "built-in"
69  DOS-ISR management routines. My tests failed under
70  win98 using the fb_isr_set() routines whereas the
71  ones defined in this module appear to work OK.
72  (jeffm)
73 
74  #define FB_MANAGED_IRQ
75 */
76 
77 typedef struct
78 {
79  int usecount; /* irq usage count for IRQ sharing */
80  int old_pic_mask; /* old pic mask */
81  int first; /* first comm in shared IRQ chain */
82 #ifndef FB_MANAGED_IRQ
83  int irq;
84  int intnum; /* interrupt number */
85  void (*irq_handler) ( void ); /* irq handler */
86  _go32_dpmi_seginfo old_rmhandler;
87  _go32_dpmi_seginfo old_pmhandler;
88  _go32_dpmi_seginfo new_rmhandler;
89  _go32_dpmi_seginfo new_pmhandler;
90  _go32_dpmi_registers regs;
91 #endif
92 } irq_props_t;
93 
94 typedef struct
95 {
96  unsigned char * data; /* pointer to buffer */
97  int size; /* size of buffer */
98  int head; /* next char position to get */
99  int tail; /* next char position to put */
100  int length; /* length of chars to get in the buffer */
101 } buffer_t;
102 
103 typedef struct
104 {
105  int baseaddr; /* base port address */
106  int def_irq; /* default irq number */
107  int irq; /* actual irq number in use */
108  int initflags; /* initialization flags */
109  int inuse; /* in use flag */
110  int chiptype; /* chiptype */
111  int counter; /* interrupt counter */
112  int next; /* next comm in shared IRQ */
113  buffer_t rxbuf; /* receive buffer */
114  buffer_t txbuf; /* transmit buffer */
115  int txclear; /* transmit buffer cleared */
116  int flags; /* additional flags */
117 } comm_props_t;
118 
119 typedef struct
120 {
121  int com_num;
124 
125 /* private local procs */
126 static int UART_detect_chiptype( unsigned int baseaddr );
127 static int UART_set_baud( unsigned int baseaddr, int baud );
128 static int UART_set_data_format( unsigned int baseaddr,
129  int parity, int data, int stop );
130 static int comm_isr( unsigned irq );
131 static int comm_init( int com_num, unsigned int baseaddr, int irq );
132 static void comm_exit( int com_num );
133 
134 #ifndef FB_MANAGED_IRQ
135 
136 static void comm_handler_irq_3 ( void );
137 static void comm_handler_irq_4 ( void );
138 static void comm_handler_irq_5 ( void );
139 static void comm_handler_irq_6 ( void );
140 static void comm_handler_irq_7 ( void );
141 static int comm_init_irq( irq_props_t *ip );
142 static void comm_exit_irq( irq_props_t *ip );
143 #define ENABLE() enable()
144 #define DISABLE() disable()
145 
146 #else /* !FB_MANAGED_IRQ */
147 
148 #define ENABLE() fb_dos_sti()
149 #define DISABLE() fb_dos_cli()
150 
151 #endif /* FB_MANAGED_IRQ */
152 
153 /* public procs */
154 int comm_open( int com_num,
155  int baud, int parity, int data, int stop,
156  int txbufsize, int rxbufsize, int flags, int irq );
157 int comm_close( int com_num );
158 int comm_putc( int com_num, int ch );
159 int comm_getc( int com_num );
160 int comm_bytes_remaining( int com_num );
161 
162 /* local state */
163 static int comm_init_count = 0;
164 
165 #ifndef FB_MANAGED_IRQ
167  { 0, 0, 0, 3, 0xb, comm_handler_irq_3 },
168  { 0, 0, 0, 4, 0xc, comm_handler_irq_4 },
169  { 0, 0, 0, 5, 0xd, comm_handler_irq_5 },
170  { 0, 0, 0, 6, 0xe, comm_handler_irq_6 },
171  { 0, 0, 0, 7, 0xf, comm_handler_irq_7 }
172 };
173 #else
174 static irq_props_t irq_props[IRQ_COUNT] = {
175  { 0, 0, 0 },
176  { 0, 0, 0 },
177  { 0, 0, 0 },
178  { 0, 0, 0 },
179  { 0, 0, 0 }
180 };
181 #endif
182 
184  { 0x3f8, 4, 4, 0, 0, 0, 0, 0 },
185  { 0x2f8, 3, 3, 0, 0, 0, 0, 0 },
186  { 0x3e8, 4, 4, 0, 0, 0, 0, 0 },
187  { 0x2e8, 3, 3, 0, 0, 0, 0, 0 }
188 };
189 
190 static inline unsigned int next_pow2( unsigned int n )
191 {
192  --n;
193  n |= n >> 16;
194  n |= n >> 8;
195  n |= n >> 4;
196  n |= n >> 2;
197  n |= n >> 1;
198  ++n;
199  return n;
200 }
201 
202 static void BUFFER_reset( buffer_t * buf )
203 {
204  if( buf )
205  {
206  if( buf->data && buf->size )
207  memset( buf->data, 0, buf->size);
208  buf->head = buf->tail = buf->length = 0;
209  }
210 }
211 
212 static int BUFFER_alloc( buffer_t * buf, int size )
213 {
214  size = next_pow2( size );
215 
216  buf->size = 0;
217 
218  buf->data = malloc( size );
219  if( buf->data )
220  {
221  buf->size = size;
222  fb_dos_lock_data( buf->data, buf->size);
223  }
224 
225  BUFFER_reset( buf );
226 
227  /* TRUE = success */
228  return ( buf->size != 0 );
229 }
230 
231 static void BUFFER_free( buffer_t * buf )
232 {
233  if( buf->data )
234  {
235  memset( buf->data, 0, buf->size);
236  fb_dos_unlock_data( buf->data, buf->size);
237  free( buf->data );
238  buf->data = NULL;
239  }
240  buf->head = buf->tail = buf->size = buf->length = 0;
241 }
242 
243 static int BUFFER_putc( buffer_t * buf, int ch )
244 {
245  if( buf->length == buf->size )
246  return -1;
247 
248  buf->data[ buf->tail ] = ch;
249  buf->tail = (buf->tail + 1) & ( buf->size - 1 );
250  buf->length++;
251 
252  return ch;
253 }
254 static void end_BUFFER_putc( void ) { }
255 
256 static int BUFFER_getc( buffer_t * buf )
257 {
258  int ch = -1;
259  if( buf->length )
260  {
261  ch = buf->data[ buf->head ];
262  buf->head = (buf->head + 1) & ( buf->size - 1 );
263  buf->length--;
264  }
265  return ch;
266 }
267 static void end_BUFFER_getc( void ) { }
268 
269 static int UART_detect_chiptype( unsigned int baseaddr )
270 {
271  int tmp;
272 
273  /* test for LCR */
274  outportb( baseaddr + UART_LCR ,0x1b );
275  if ( inportb( baseaddr + UART_LCR ) != 0x1b )
276  return UART_IS_NONE;
277 
278  outportb( baseaddr + UART_LCR, 0x3 );
279  if ( inportb( baseaddr + UART_LCR ) != UART_LCR )
280  return UART_IS_NONE;
281 
282  /* test for scratch register */
283  outportb( baseaddr + UART_SCR, 0x55 );
284  if ( inportb( baseaddr + UART_SCR ) != 0x55 )
285  return UART_IS_8250;
286 
287  outportb( baseaddr + UART_SCR, 0xAA );
288  if ( inportb( baseaddr + UART_SCR ) != 0xAA )
289  return UART_IS_8250;
290 
291  /* check for FIFO */
292  outportb(baseaddr + UART_FCR, 1);
293  tmp = inportb( baseaddr + UART_IIR);
294 
295  if ( ( tmp & 0x80 ) == 0 )
296  return UART_IS_16450;
297  if ( ( tmp & 0x40 ) == 0 )
298  return UART_IS_16550;
299 
300  /* clear FCR */
301  outportb( baseaddr + UART_FCR, 0x0 );
302 
303  return UART_IS_16550A;
304 }
305 
306 static int UART_set_baud( unsigned int baseaddr, int baud )
307 {
308  int divisor, lsb, msb, tmp;
309 
310  if(( baud < 50 ) || ( baud > 115200 ))
311  return FALSE;
312 
313  divisor = 115200 / baud;
314  lsb = divisor & 0xff;
315  msb = divisor >> 8;
316 
317  tmp = inportb( baseaddr + UART_LCR );
318  tmp |= LCR_DLAB;
319  outportb( baseaddr + UART_LCR, tmp );
320 
321  outportb( baseaddr + UART_DL_LSB, lsb );
322  outportb( baseaddr + UART_DL_MSB, msb );
323 
324  tmp = inportb( baseaddr + UART_LCR );
325  tmp &= ~LCR_DLAB;
326  outportb( baseaddr + UART_LCR, tmp );
327 
328  return( TRUE );
329 }
330 
331 static int UART_set_data_format( unsigned int baseaddr,
332  int parity, int data, int stop )
333 {
334  int fmt = 0;
335 
336  switch( data )
337  {
338  case 5:
339  break;
340  case 6:
341  fmt |= 1;
342  break;
343  case 7:
344  fmt |= 2;
345  break;
346  case 8:
347  fmt |= 3;
348  break;
349  default:
350  return FALSE;
351  }
352 
353  switch( parity )
354  {
356  break;
358  fmt |= 1 << 3;
359  break;
361  fmt |= 3 << 3;
362  break;
364  fmt |= 5 << 3;
365  break;
367  fmt |= 7 << 3;
368  break;
369  default:
370  return FALSE;
371  }
372 
373  switch( stop )
374  {
376  break;
378  if( data != 5 )
379  return FALSE;
380  break;
382  fmt |= 4;
383  break;
384  default:
385  return FALSE;
386  }
387 
388  /* set data format - assumes DLAB is clear */
389  outportb( baseaddr + UART_LCR, fmt );
390 
391  return TRUE;
392 }
393 
394 #ifndef FB_MANAGED_IRQ
395 
396 static void comm_handler_irq_3( void ) { comm_isr( 3 ); } void end_comm_handler_irq_3( void ) { }
397 static void comm_handler_irq_4( void ) { comm_isr( 4 ); } void end_comm_handler_irq_4( void ) { }
398 static void comm_handler_irq_5( void ) { comm_isr( 5 ); } void end_comm_handler_irq_5( void ) { }
399 static void comm_handler_irq_6( void ) { comm_isr( 6 ); } void end_comm_handler_irq_6( void ) { }
400 static void comm_handler_irq_7( void ) { comm_isr( 7 ); } void end_comm_handler_irq_7( void ) { }
401 
402 #endif /* #ifndef FB_MANAGED_IRQ */
403 
404 static int comm_isr( unsigned irq )
405 {
406  comm_props_t *cp;
407  irq_props_t *ip;
408  int ret, i, ch;
409 
410  outportb (ICU_OCW2, 0x20);
411 
412 #if 0
413  ENABLE();
414 #endif
415 
416  ip = IRQ_PROPS(irq);
417 
418  if( ip->usecount == 0)
419  return 0;
420 
421  i = ip->first;
422 
423  /* TODO: FIFO Support on UARTs that support it */
424 
425  while(i)
426  {
427  cp = COMM_PROPS(i);
428 
429  while(1)
430  {
431  ret = inportb( cp->baseaddr + UART_IIR ) & 0xf;
432 
433  if( ret == 1)
434  break;
435 
436  switch( ret )
437  {
438  case 4:
439  /* receive data */
440  ch = inportb( cp->baseaddr + UART_RBR );
441  BUFFER_putc( &cp->rxbuf, ch );
442  break;
443 
444  case 2:
445  /* tx buffer empty */
446  ch = BUFFER_getc( &cp->txbuf );
447  if( ch >= 0 )
448  {
449  cp->txclear = FALSE;
450  outportb( cp->baseaddr + UART_THR, ch );
451 
452  /* TODO: check CTS if CS option set and start timer */
453 
454  }
455  else
456  {
457  ret = inportb( cp->baseaddr + UART_IIR );
458  cp->txclear = TRUE;
459  }
460  break;
461 
462  case 0:
463  /* change in input signal */
464  ret = inportb( cp->baseaddr + UART_MSR );
465 
466  /* TODO: start DSR low timer if DS option set */
467  /* TODO: start DCD low timer if CD option set */
468  /* TODO: check errors */
469 
470  break;
471 
472  case 6:
473  /* reception error or break */
474  ret = inportb( cp->baseaddr + UART_LSR );
475 
476  /* TODO: check errors */
477 
478  break;
479 
480  default:
481  break;
482  }
483 
484  }
485 
486  /* next comm port in a shared IRQ chain */
487  i = cp->next;
488  }
489  return 0;
490 }
491 static void end_comm_isr( void ) { };
492 
493 static void comm_init_addref( void )
494 {
495  /* lock memory when comm ports are in use */
496  if( comm_init_count == 0 )
497  {
499  lock_array( irq_props );
500  lock_array( comm_props );
501 
502 #ifndef FB_MANAGED_IRQ
508 #endif
509 
510  lock_proc( comm_isr );
511 
514 
515  comm_init_count++;
516  }
517 }
518 
519 static void comm_init_release( void )
520 {
521  /* no more com ports in use? */
522  if( comm_init_count == 1 )
523  {
526 
528 
529 #ifndef FB_MANAGED_IRQ
535 #endif
536 
537  unlock_array( comm_props );
538  unlock_array( irq_props );
540  }
541 
542  if( comm_init_count != 0 )
543  comm_init_count--;
544 }
545 
546 static int comm_init_irq( irq_props_t *ip )
547 {
548  /* setup real mode handler */
549  _go32_dpmi_get_real_mode_interrupt_vector (ip->intnum, &ip->old_rmhandler);
550 
551  ip->new_rmhandler.pm_selector = _go32_my_cs ();
552  ip->new_rmhandler.pm_offset = (unsigned long ) ip->irq_handler;
553 
554  if( _go32_dpmi_allocate_real_mode_callback_iret (&ip->new_rmhandler, &ip->regs) )
555  {
556  /* failed */
557  return FALSE;
558  }
559 
560  if( _go32_dpmi_set_real_mode_interrupt_vector (ip->intnum, &ip->new_rmhandler) )
561  {
562  /* failed */
563  _go32_dpmi_free_real_mode_callback (&ip->new_rmhandler);
564  return FALSE;
565  }
566 
567  /* setup protected mode handler */
568  _go32_dpmi_get_protected_mode_interrupt_vector (ip->intnum, &ip->old_pmhandler);
569 
570  ip->new_pmhandler.pm_selector = _go32_my_cs ();
571  ip->new_pmhandler.pm_offset = (unsigned long) ip->irq_handler;
572  _go32_dpmi_allocate_iret_wrapper( &ip->new_pmhandler );
573 
574  if( _go32_dpmi_set_protected_mode_interrupt_vector (ip->intnum, &ip->new_pmhandler) )
575  {
576  /* failed */
577  _go32_dpmi_set_real_mode_interrupt_vector (ip->intnum, &ip->old_rmhandler);
578  _go32_dpmi_free_real_mode_callback (&ip->new_rmhandler);
579  _go32_dpmi_free_iret_wrapper (&ip->new_pmhandler);
580  return FALSE;
581  }
582 
583  /* success - installed */
584  return TRUE;
585 }
586 
587 static void comm_exit_irq( irq_props_t *ip )
588 {
589  _go32_dpmi_set_real_mode_interrupt_vector (ip->intnum, &ip->old_rmhandler);
590  _go32_dpmi_free_real_mode_callback (&ip->new_rmhandler);
591 
592  _go32_dpmi_set_protected_mode_interrupt_vector (ip->intnum, &ip->old_pmhandler);
593  _go32_dpmi_free_iret_wrapper (&ip->new_pmhandler);
594  }
595 
596 static int comm_init( int com_num, unsigned int baseaddr, int irq )
597 {
598  comm_props_t *cp;
599  irq_props_t *ip;
600  int tmp, i;
601 
602  if( com_num < 1 || com_num > MAX_COMM )
603  return FALSE;
604 
605  cp = COMM_PROPS(com_num);
606 
608 
609  if( baseaddr )
610  cp->baseaddr = baseaddr;
611 
612  if( irq )
613  cp->irq = irq;
614  else
615  cp->irq = cp->def_irq;
616 
617  /* irq is valid? */
618  if( (cp->irq < FIRST_IRQ) || (cp->irq > LAST_IRQ) )
619  {
621  return FALSE;
622  }
623 
624  outportb( cp->baseaddr + UART_FCR, 0 );
625 
626  /* TODO: FIFO setup on UARTs that support it */
627 
628  /* flush ints pending */
629  for( i = 0; i < 17; i++ )
630  {
631  tmp = inportb( cp->baseaddr + UART_IIR );
632  if( (tmp & 0x38) == 0 )
633  break;
634  tmp = inportb( cp->baseaddr + UART_RBR );
635  }
636 
637  /* disable interrupts on the UART */
638  outportb( cp->baseaddr + UART_IER, 0 );
639 
640  /* clear status ints */
641  tmp = inportb( cp->baseaddr + UART_LSR );
642  tmp = inportb( cp->baseaddr + UART_MSR );
643 
644  /* enable interrupt gate */
645  outportb( cp->baseaddr + UART_MCR, MCR_OUT2 );
646 
647 
648  /* steup the irq for comm handling */
649  ip = IRQ_PROPS(cp->irq);
650 
651  if( ip->usecount == 0 )
652  {
653 
654 #ifndef FB_MANAGED_IRQ
655  if( !comm_init_irq( ip ) )
656 #else
657  if( !fb_isr_set( cp->irq, comm_isr, 0, 1024 ))
658 #endif
659  {
661  return FALSE;
662  }
663 
664  /* set the interrupt controller mask */
665  DISABLE();
666 
667  ip->usecount++;
668 
669  /* TODO: Support for slave PIC? */
670  ip->old_pic_mask = inportb (ICU_MASK);
671  outportb (ICU_MASK, ip->old_pic_mask & ~(1 << cp->irq));
672 
673  ENABLE();
674  }
675 
676  DISABLE();
677 
678  /* chain comm ports for IRQ sharing */
679  if( ip->first )
680  comm_props[ip->first - 1].next = ip->first;
681  ip->first = com_num;
682 
683  /* enable the UART's interrupts */
684  tmp = inportb( cp->baseaddr + UART_IER );
685  tmp |= IER_SINP | IER_EBRK | IER_TBE | IER_RXRD;
686  outportb( cp->baseaddr + UART_IER, tmp );
687 
688  /* TODO: MCR_RTS should be set only after waiting for DSR if the OP/CS protocol option is set */
689  tmp = inportb( cp->baseaddr + UART_MCR );
690  tmp |= MCR_OUT2 | MCR_RTS | MCR_DTR;
691  if( cp->flags & FLAG_SUPPRESS_RTS )
692  tmp ^= MCR_RTS;
693  outportb( cp->baseaddr + UART_MCR, tmp );
694 
695 
696  ENABLE();
697 
698  return TRUE;
699 }
700 
701 static void comm_exit( int com_num )
702 {
703  comm_props_t *cp;
704  irq_props_t *ip;
705  int tmp, i;
706 
707  DBG_ASSERT( com_num >= 1 && com_num < MAX_COMM );
708 
709  cp = COMM_PROPS(com_num);
710 
711  /* disable interrupt gate on the UART */
712  tmp = inportb( cp->baseaddr + UART_MCR );
713  if( cp->flags & FLAG_KEEP_DTR )
714  tmp &= ~( MCR_OUT2 | MCR_OUT1 | MCR_RTS );
715  else
716  tmp &= ~( MCR_OUT2 | MCR_OUT1 | MCR_RTS | MCR_DTR );
717 
718  outportb( cp->baseaddr + UART_MCR, tmp );
719 
720  /* disable interrupts on the UART */
721  tmp = inportb( cp->baseaddr + UART_IER );
722  tmp &= ~( IER_SINP | IER_EBRK | IER_TBE | IER_RXRD );
723  outportb( cp->baseaddr + UART_IER, tmp );
724 
725  ip = IRQ_PROPS(cp->irq);
726 
727  /* un-chain comm ports for IRQ sharing */
728  DISABLE();
729  if( ip->first == com_num )
730  {
731  ip->first = cp->next;
732  }
733  else
734  {
735  for( i = 0; i < MAX_COMM; i ++ )
736  {
737  if( comm_props[i].next == com_num )
738  {
739  comm_props[i].next = cp->next;
740  break;
741  }
742  }
743  }
744  cp->next = 0;
745  ENABLE();
746 
747  /* restore interrupt controller mask */
748  if( ip->usecount == 1 )
749  {
750  DISABLE();
751  /* TODO: Support for slave PIC? */
752  outportb (ICU_MASK, inportb (ICU_MASK) | (ip->old_pic_mask & (1 << cp->irq)));
753  ENABLE();
754 
755 #ifndef FB_MANAGED_IRQ
756  comm_exit_irq( ip );
757 #else
758  fb_isr_reset( cp->irq );
759 #endif
760  }
761 
762  if( ip->usecount != 0 )
763  ip->usecount--;
764 
766 }
767 
768 int comm_open( int com_num,
769  int baud, int parity, int data, int stop,
770  int txbufsize, int rxbufsize, int flags, int irq )
771 {
772  comm_props_t *cp;
773  int ret = FALSE;
774 
775  if( com_num < 1 || com_num > MAX_COMM )
776  return FALSE;
777 
778  cp = COMM_PROPS(com_num);
779 
780  if( cp->inuse )
781  return ret;
782 
783  if( (cp->initflags & COMM_CHECKED_CHIPTYPE) == 0 )
784  {
787  }
788 
789  /* TODO: Autodetect IRQ in use by baseaddr */
790 
791  if( cp->chiptype == 0 )
792  return FALSE;
793 
794  cp->txbuf.data = NULL;
795  cp->txbuf.size = cp->txbuf.head = cp->txbuf.tail = 0;
796  cp->rxbuf.data = NULL;
797  cp->rxbuf.size = cp->rxbuf.head = cp->rxbuf.tail = 0;
798  cp->txclear = TRUE;
799  cp->flags = flags;
800 
801  ret = FALSE;
802 
803  if( BUFFER_alloc( &cp->txbuf, txbufsize ))
804  if( BUFFER_alloc( &cp->rxbuf, rxbufsize ))
805  if( UART_set_baud( cp->baseaddr, baud ))
806  if( UART_set_data_format( cp->baseaddr, parity, data, stop ))
807  if( comm_init( com_num, 0, irq ))
808  ret = TRUE;
809 
810  /* TODO: wait for DSR if OP/DS option is set */
811 
812  /* TODO: Set RTS if RS option not set */
813 
814  /* TODO: wait for DCD if OP/CD option is set */
815 
816  /* TODO: Clean-up on TIMEOUT */
817 
818  if( ret )
819  {
820  cp->inuse = TRUE;
821  }
822  else
823  {
824  BUFFER_free( &cp->rxbuf);
825  BUFFER_free( &cp->txbuf);
826  }
827 
828  /* TRUE == success */
829  return cp->inuse;
830 }
831 
832 int comm_close( int com_num )
833 {
834  comm_props_t *cp;
835 
836  if( com_num < 1 || com_num > MAX_COMM )
837  return FALSE;
838 
839  cp = COMM_PROPS(com_num);
840 
841  if( cp->inuse == FALSE )
842  return FALSE;
843 
844  comm_exit( com_num );
845 
846  cp->inuse = FALSE;
847 
848  BUFFER_free( &cp->rxbuf);
849  BUFFER_free( &cp->txbuf);
850 
851  return TRUE;
852 }
853 
854 int comm_putc( int com_num, int ch )
855 {
856  comm_props_t *cp;
857  cp = COMM_PROPS(com_num);
858 
859  DISABLE();
860  if( cp->txclear )
861  {
862  cp->txclear = FALSE;
863  outportb( cp->baseaddr + UART_THR, ch );
864  }
865  else
866  {
867  ch = BUFFER_putc( &cp->txbuf, ch );
868  }
869  ENABLE();
870  return ch;
871 }
872 
873 int comm_getc( int com_num )
874 {
875  int ch;
876  comm_props_t *cp;
877  cp = COMM_PROPS(com_num);
878  DISABLE();
879  ch = BUFFER_getc( &cp->rxbuf );
880  ENABLE();
881  return ch;
882 }
883 
884 int comm_bytes_remaining( int com_num )
885 {
886  int bytes;
887  comm_props_t *cp;
888  cp = COMM_PROPS(com_num);
889  DISABLE();
890  bytes = cp->rxbuf.length;
891  ENABLE();
892  return bytes;
893 }
894 
895 int fb_SerialOpen
896  (
897  FB_FILE *handle,
898  int iPort,
899  FB_SERIAL_OPTIONS *options,
900  const char *pszDevice,
901  void **ppvHandle
902  )
903 {
904  int ret, flags = 0;
905 
906  if( options->TransmitBuffer == 0 )
908  else if( options->TransmitBuffer < 0 || options->TransmitBuffer > MAX_BUFFERSIZE )
910 
911  if( options->ReceiveBuffer == 0 )
913  else if( options->ReceiveBuffer < 0 || options->ReceiveBuffer > MAX_BUFFERSIZE )
915 
916  if( options->KeepDTREnabled )
917  flags |= FLAG_KEEP_DTR;
918 
919  if( options->SuppressRTS )
920  flags |= FLAG_SUPPRESS_RTS;
921 
922  ret = comm_open(
923  iPort,
924  options->uiSpeed,
925  options->Parity,
926  options->uiDataBits,
927  options->StopBits,
928  options->TransmitBuffer,
929  options->ReceiveBuffer,
930  flags,
931  options->IRQNumber
932  );
933 
934  if( ret )
935  {
936  DOS_SERIAL_INFO *pInfo = (DOS_SERIAL_INFO *) calloc( 1, sizeof(DOS_SERIAL_INFO) );
937  DBG_ASSERT( ppvHandle!=NULL );
938  *ppvHandle = pInfo;
939  pInfo->com_num = iPort;
940  pInfo->pOptions = options;
941  return fb_ErrorSetNum( FB_RTERROR_OK );
942  }
943 
945 
946  /*
947  [x] unsigned uiSpeed
948  [x] unsigned uiDataBits
949  [x] FB_SERIAL_PARITY Parity
950  [x] FB_SERIAL_STOP_BITS StopBits
951  [ ] unsigned DurationCTS -- CS[msec]
952  [ ] unsigned DurationDSR -- DS[msec]
953  [ ] unsigned DurationCD -- CD[msec]
954  [ ] unsigned OpenTimeout -- OP[msec]
955  [ ] int SuppressRTS -- RS
956  [ ] int AddLF -- LF, or ASC, or BIN
957  [ ] int CheckParity -- PE
958  [x] int KeepDTREnabled -- DT
959  [ ] int DiscardOnError -- FE
960  [ ] int IgnoreAllErrors -- ME
961  [ ] unsigned IRQNumber -- IR2..IR15
962  [x] unsigned IRQNumber -- IR2..IR7
963  [x] unsigned TransmitBuffer -- TBn - a value 0 means: default value
964  [x] unsigned ReceiveBuffer -- RBn - a value 0 means: default value
965  */
966 }
967 
968 int fb_SerialGetRemaining( FB_FILE *handle, void *pvHandle, fb_off_t *pLength )
969 {
970  size_t bytes;
971  DOS_SERIAL_INFO *pInfo = (DOS_SERIAL_INFO *) pvHandle;
972 
973  bytes = comm_bytes_remaining( pInfo->com_num );
974  if( bytes < 0 )
976 
977  if( pLength )
978  *pLength = bytes;
979 
980  return fb_ErrorSetNum( FB_RTERROR_OK );
981 }
982 
983 int fb_SerialWrite
984  (
985  FB_FILE *handle,
986  void *pvHandle,
987  const void *data,
988  size_t length
989  )
990 {
991  DOS_SERIAL_INFO *pInfo = (DOS_SERIAL_INFO *) pvHandle;
992  unsigned char * p = (unsigned char *)data;
993  int ch;
994  size_t i;
995 
996  /* TODO: Support for ASC/LF options */
997 
998  for( i=0; i<length; i++ )
999  {
1000  ch = comm_putc( pInfo->com_num, p[i]);
1001  if( ch < 0 )
1003  }
1004  return fb_ErrorSetNum( FB_RTERROR_OK );
1005 }
1006 
1007 int fb_SerialRead
1008  (
1009  FB_FILE *handle,
1010  void *pvHandle,
1011  void *data,
1012  size_t *pLength
1013  )
1014 {
1015  DOS_SERIAL_INFO *pInfo = (DOS_SERIAL_INFO *) pvHandle;
1016  size_t n = *pLength, i, count = 0;
1017  int ch;
1018  unsigned char * p = (unsigned char *)data;
1019  int res = FB_RTERROR_OK;
1020 
1021  for( i = 0; i < n; i++ )
1022  {
1023  ch = comm_getc( pInfo->com_num );
1024  if( ch < 0 )
1025  {
1026  res = FB_RTERROR_FILEIO;
1027  break;
1028  }
1029  p[i] = ch;
1030  count++;
1031  }
1032 
1033  *pLength = count;
1034 
1035  return fb_ErrorSetNum( res );
1036 }
1037 
1038 int fb_SerialClose( FB_FILE *handle, void *pvHandle )
1039 {
1040  DOS_SERIAL_INFO *pInfo = (DOS_SERIAL_INFO *) pvHandle;
1041  comm_close( pInfo->com_num );
1042  free(pInfo);
1043  return fb_ErrorSetNum( FB_RTERROR_OK );
1044 }