OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [tags/] [nog_patch_66/] [or1ksim/] [peripheral/] [16450.c] - Blame information for rev 185

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 31 lampret
/* 16450.c -- Simulation of 8250/16450 serial UART
2
   Copyright (C) 1999 Damjan Lampret, lampret@opencores.org
3
 
4
This file is part of OpenRISC 1000 Architectural Simulator.
5
 
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2 of the License, or
9
(at your option) any later version.
10
 
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
GNU General Public License for more details.
15
 
16
You should have received a copy of the GNU General Public License
17
along with this program; if not, write to the Free Software
18
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
 
20
/* This is functional simulation of 8250/16450 UARTs. Since we RX/TX data
21
   via file streams, we can't simulate modem control lines coming from the
22
   DCE and similar details of communication with the DCE.
23
 
24
   This simulated UART device is intended for basic UART device driver
25
   verification. From device driver perspective this device looks like a
26
   regular UART but never reports and modem control lines changes (the
27
   only DCE responses are incoming characters from the file stream).
28
*/
29
 
30
#include <stdlib.h>
31
#include <stdio.h>
32
#include <string.h>
33 185 chris
#include <sys/types.h>  /* CZ 250801 */
34
#include <sys/stat.h>   /* CZ 250801 */
35
#include <fcntl.h>      /* CZ 250801 */ 
36
#include <sys/poll.h>   /* CZ 250801 */
37
#include <sys/time.h>   /* CZ 250801 */ 
38
#include <unistd.h>     /* CZ 250801 */ 
39
#include <errno.h>      /* CZ 250801 */ 
40 31 lampret
 
41
#include "16450.h"
42
#include "sim-config.h"
43 102 lampret
#include "pic.h"
44 31 lampret
 
45
static struct dev_16450 uarts[NR_UARTS];
46
 
47
/* Number of clock cycles (one clock cycle is one call to the uart_clock())
48
   before a single character is transmitted or received. */
49
static void set_char_clks(int uartchip)
50
{
51
        int bauds_per_char = 0;
52
 
53
        uarts[uartchip].char_clks = (uarts[uartchip].regs.dlh << 8)
54
                                        + uarts[uartchip].regs.dll;
55
 
56
        if (uarts[uartchip].regs.lcr & UART_LCR_PARITY)
57
                bauds_per_char++;
58
 
59
        if (uarts[uartchip].regs.lcr & UART_LCR_STOP)
60
                bauds_per_char += 2;
61
        else
62
                bauds_per_char++;
63
 
64
        bauds_per_char += (5 + (uarts[uartchip].regs.lcr & 0x2));
65
 
66
        uarts[uartchip].char_clks *= bauds_per_char;
67
}
68
 
69 185 chris
/* CZ 260801 --- The simulator expects to access only 32
70
   bit words. Since we only have an 8 bit data space, simply
71
   ignore the bottom 24 bits. */
72 31 lampret
/* Set a specific UART register with value. */
73 185 chris
void uart_write(unsigned long addr, unsigned int arg_value)
74 31 lampret
{
75
        int chipsel;
76 185 chris
        unsigned char value = arg_value >> 24;
77
 
78 31 lampret
        debug("uart_write(%x,%x)\n", addr, value);
79
 
80
        for(chipsel = 0; chipsel < NR_UARTS; chipsel++)
81
                if ((addr & ~(UART_ADDR_SPACE-1)) == uarts[chipsel].baseaddr)
82
                        break;
83
                else if (chipsel == NR_UARTS)
84
                        return;
85
 
86 185 chris
        if (uarts[chipsel].regs.lcr & UART_LCR_DLAB)
87
          {
88
            switch (addr % UART_ADDR_SPACE)
89
              {
90
              case UART_DLL:
91
                uarts[chipsel].regs.dll = value;
92 31 lampret
                set_char_clks(chipsel);
93
                return;
94 185 chris
              case UART_DLH:
95
                uarts[chipsel].regs.dlh = value;
96
                set_char_clks(chipsel);
97
                return;
98
              default: /* Fall through to normal processing */
99
                break;
100
              }
101
          }
102 31 lampret
 
103
        switch (addr % UART_ADDR_SPACE) {
104
                case UART_TXBUF:
105
                        uarts[chipsel].regs.txbuf = value;
106
                        uarts[chipsel].istat.txbuf = FULL;
107
                        uarts[chipsel].regs.lsr &= ~UART_LSR_TXBUFE;
108
                        uarts[chipsel].regs.lsr &= ~UART_LSR_TXSERE;
109
                        break;
110
                case UART_IER:
111
                        uarts[chipsel].regs.ier = value & UART_VALID_IER;
112
                        break;
113
                case UART_LCR:
114
                        uarts[chipsel].regs.lcr = value & UART_VALID_LCR;
115
                        break;
116
                case UART_MCR:
117
                        uarts[chipsel].regs.mcr = value & UART_VALID_MCR;
118
                        break;
119
                case UART_SCR:
120
                        uarts[chipsel].regs.scr = value;
121
                        break;
122
                default:
123
                        debug("write out of range (addr %x)\n", addr);
124
        }
125
        set_char_clks(chipsel);
126
        return;
127
}
128
 
129 185 chris
/* CZ 260801 --- The simulator expects to access only 32
130
   bit words. Since we only have an 8 bit data space, simply
131
   fill in the bottom 24 bits with zero */
132 31 lampret
/* Read a specific UART register. */
133 185 chris
unsigned int uart_read(unsigned long addr)
134 31 lampret
{
135
        unsigned char value = 0;
136
        int chipsel;
137
 
138
        debug("uart_read(%x)\n", addr);
139
 
140
        for(chipsel = 0; chipsel < NR_UARTS; chipsel++)
141
                if ((addr & ~(UART_ADDR_SPACE-1)) == uarts[chipsel].baseaddr)
142
                        break;
143
                else if (chipsel == NR_UARTS)
144
                        return 0;
145
 
146 185 chris
        if (uarts[chipsel].regs.lcr & UART_LCR_DLAB)
147
          {
148
            switch (addr % UART_ADDR_SPACE)
149
              {
150
              case UART_DLL:
151
                return uarts[chipsel].regs.dll << 24;
152
              case UART_DLH:
153
                return uarts[chipsel].regs.dlh << 24;
154
              default: /* Fall through to normal processing */
155
                break;
156
              }
157
          }
158 31 lampret
 
159
        switch (addr % UART_ADDR_SPACE) {
160
                case UART_RXBUF:
161
                        value = uarts[chipsel].regs.rxbuf;
162
                        uarts[chipsel].istat.rxbuf = EMPTY;
163
                        uarts[chipsel].regs.lsr &= ~UART_LSR_RDRDY;
164
                        break;
165
                case UART_IER:
166
                        value = uarts[chipsel].regs.ier & UART_VALID_IER;
167
                        break;
168
                case UART_IIR:
169
                        value = uarts[chipsel].regs.iir & UART_VALID_IIR;
170
                        break;
171
                case UART_LCR:
172
                        value = uarts[chipsel].regs.lcr & UART_VALID_LCR;
173
                        break;
174
                case UART_MCR:
175
                        value = uarts[chipsel].regs.mcr & UART_VALID_MCR;
176
                        break;
177
                case UART_LSR:
178
                        value = uarts[chipsel].regs.lsr & UART_VALID_LSR;
179
                        uarts[chipsel].regs.lsr &=
180
                                ~(UART_LSR_OVRRUN | UART_LSR_PARITY
181
                                 | UART_LSR_FRAME | UART_LSR_BREAK);
182
                        break;
183
                case UART_MSR:
184
                        value = uarts[chipsel].regs.msr & UART_VALID_MSR;
185
                        uarts[chipsel].regs.msr = 0;
186
                        break;
187
                case UART_SCR:
188
                        value = uarts[chipsel].regs.scr;
189
                        break;
190
                default:
191
                        debug("read out of range (addr %x)\n", addr);
192
        }
193 185 chris
        return value << 24;
194 31 lampret
}
195
 
196 185 chris
 
197 31 lampret
/* Reset. It initializes all registers of all UART devices to zero values,
198
   (re)opens all RX/TX file streams and places devices in memory address
199
   space. */
200
void uart_reset()
201
{
202 123 markom
  int i;
203 185 chris
  static int initialized = 0; /* If we're not initialized, don't close it */
204
  int saved_tx_fds[NR_UARTS];
205
  int saved_rx_fds[NR_UARTS];
206
 
207
  if(initialized)
208
    {
209
      for(i = 0; i < NR_UARTS; i++)
210
        {
211
          struct stat buf;
212
 
213
          if(uarts[i].txfd >= 0)
214
            {
215
              if(fstat(uarts[i].txfd,&buf) ||
216
                 (!S_ISFIFO(buf.st_mode) &&
217
                  !S_ISSOCK(buf.st_mode)))
218
                {
219
                  close(uarts[i].txfd);
220
                  saved_tx_fds[i] = -1;
221
                }
222
              else
223
                saved_tx_fds[i] = uarts[i].txfd;
224
            }
225
          else
226
            saved_tx_fds[i] = -1;
227
 
228
          if(uarts[i].rxfd >= 0)
229
            {
230
              if(fstat(uarts[i].rxfd,&buf) ||
231
                 (!S_ISFIFO(buf.st_mode) &&
232
                  !S_ISSOCK(buf.st_mode)))
233
                {
234
                  close(uarts[i].rxfd);
235
                  saved_rx_fds[i] = -1;
236
                }
237
              else
238
                saved_rx_fds[i] = uarts[i].txfd;
239
            }
240
          else
241
            saved_rx_fds[i] = -1;
242
        }
243
    }
244
  else
245
    {
246
      for(i=0;i<NR_UARTS;i++)
247
        saved_tx_fds[i] = saved_rx_fds[i] = -1;
248
      initialized = 1;
249
    }
250
 
251 123 markom
  printf("Resetting %u UART(s).\n", NR_UARTS);
252
  memset(uarts, 0, sizeof(uarts));
253 185 chris
  for(i=0;i<NR_UARTS;i++)
254
    {
255
      uarts[i].txfd = saved_tx_fds[i];
256
      uarts[i].rxfd = saved_rx_fds[i];
257
    }
258 123 markom
 
259
  for(i = 0; i < NR_UARTS; i++)
260
    if (config.uarts[i].txfile) { /* MM: Try to create stream.  */
261 185 chris
      /* CZ changed this to use descriptors and non blocking I/O */
262
      if ((uarts[i].rxfd = open(config.uarts[i].rxfile,
263
                                O_RDONLY | O_NONBLOCK)) < 0)
264
        {
265
          char sTemp[256];
266
 
267
          sprintf(sTemp,"UART%d RX - \"%s\"",i,config.uarts[i].rxfile);
268
          perror(sTemp);
269
          continue;
270
        }
271
      if((uarts[i].txfd = open(config.uarts[i].txfile,
272
                                O_WRONLY | O_NONBLOCK)) < 0)
273
        {
274
          char sTemp[256];
275
 
276
          if(errno == ENXIO)
277
            {
278
              /* In this case, we're a pipe, and the user has
279
                 forgotten to start the read process first. Help
280
                 him out by writing an error message and exiting */
281
 
282
              fprintf(stderr,"Please start the serial port reader "
283
                      "before starting the simulator.\nIf you wish "
284
                      "to continue without this, please remove the "
285
                      "file \"%s\" and restart.\n",config.uarts[i].txfile);
286
              fflush(stderr);
287
              exit(1);
288
            }
289
          sprintf(sTemp,"UART%d TX - \"%s\"",i,config.uarts[i].txfile);
290
          perror(sTemp);
291
          close(uarts[i].rxfd);
292
          uarts[i].rxfd = -1;
293
          continue;
294
        }
295 123 markom
      uarts[i].baseaddr = config.uarts[i].baseaddr;
296 185 chris
      printf("UART%d at 0x%.8x uses ", i, uarts[i].baseaddr);
297
      printf("%s for RX and %s for TX.\n", config.uarts[i].rxfile,
298
             config.uarts[i].txfile);
299
      register_memoryarea(uarts[i].baseaddr, UART_ADDR_SPACE,
300
                          uart_read, uart_write);
301 123 markom
    }
302 31 lampret
}
303 123 markom
 
304 31 lampret
/* Simulation hook. Must be called every clock cycle to simulate all UART
305
   devices. It does internal functional UART simulation. */
306
void uart_clock()
307
{
308
        int i;
309
 
310
        for(i = 0; i < NR_UARTS; i++) {
311 185 chris
 
312
          if(uarts[i].txfd < 0)
313
            continue;
314 31 lampret
 
315 185 chris
          /* Transmit */
316
          if (uarts[i].istat.txser == EMPTY)
317
            {
318
              uarts[i].regs.lsr |= UART_LSR_TXBUFE;
319
              if (uarts[i].istat.txbuf == FULL)
320
                {
321
                  uarts[i].iregs.txser = uarts[i].regs.txbuf;
322
                  uarts[i].istat.txser = FULL;
323
                  uarts[i].istat.txbuf = EMPTY;
324
                  uarts[i].regs.lsr &= ~UART_LSR_TXSERE;
325
                }
326
              else
327
                uarts[i].regs.lsr |= UART_LSR_TXSERE;
328
            }
329
          else if (uarts[i].char_clks == uarts[i].istat.txser_clks++)
330
            {
331
              debug("TX \'%c\' via UART%d...\n", uarts[i].iregs.txser, i);
332
              if (uarts[i].regs.mcr & UART_MCR_LOOP)
333
                uarts[i].iregs.loopback = uarts[i].iregs.txser;
334
              else
335
                switch(send_byte(uarts[i].txfd,config.uarts[i].jitter,
336
                               i,(int)uarts[i].iregs.txser))
337
                  {
338
                  case -1: /* An error occurred */
339
                    close(uarts[i].txfd);
340
                    close(uarts[i].rxfd);
341
                    uarts[i].txfd = uarts[i].rxfd = -1;
342
                    continue;
343
                  case 0:  /* The device wasn't ready */
344
                    uarts[i].istat.txser_clks = 0; /* Try again later */
345
                    break;
346
                  case 1:  /* OK...it got sent */
347
                    uarts[i].istat.txser = EMPTY;
348
                    uarts[i].istat.txser_clks = 0;
349
                    break;
350
                  }
351
            }
352 31 lampret
 
353 185 chris
          /* Receive */
354
          if (uarts[i].istat.rxser == EMPTY)
355
            uarts[i].istat.rxser = FULL;
356
          else if (uarts[i].char_clks == uarts[i].istat.rxser_clks++)
357
            {
358
              debug("Receiving via UART%d...\n", i);
359
              if (uarts[i].regs.mcr & UART_MCR_LOOP)
360
                uarts[i].iregs.rxser = uarts[i].iregs.loopback;
361
              else
362
                switch(receive_byte(uarts[i].rxfd,config.uarts[i].jitter,
363
                                    i,&uarts[i].iregs.rxser))
364
                  {
365
                  case -1: /* An error occurred */
366
                    close(uarts[i].txfd);
367
                    close(uarts[i].rxfd);
368
                    uarts[i].txfd = uarts[i].rxfd = -1;
369
                    continue;
370
                  case 0:
371
                    uarts[i].istat.rxser_clks = 0;
372
                    break;
373
                  case 1:
374
                    uarts[i].istat.rxser = EMPTY;
375
                    uarts[i].istat.rxser_clks = 0;
376
                    if (uarts[i].istat.rxbuf == FULL)
377
                      uarts[i].regs.lsr |= UART_LSR_OVRRUN;
378
                    uarts[i].regs.lsr |= UART_LSR_RDRDY;
379
                    uarts[i].regs.rxbuf = uarts[i].iregs.rxser;
380
                    uarts[i].istat.rxbuf = FULL;
381
                    break;
382
                  }
383
            }
384
 
385
          /* Loopback */
386
          if (uarts[i].regs.mcr & UART_MCR_LOOP)
387
            {
388
              debug("uart_clock: Loopback\n");
389
              if ((uarts[i].regs.mcr & UART_MCR_AUX2) !=
390
                  ((uarts[i].regs.msr & UART_MSR_DCD) >> 4))
391
                uarts[i].regs.msr |= UART_MSR_DDCD;
392
              if ((uarts[i].regs.mcr & UART_MCR_AUX1) <
393
                  ((uarts[i].regs.msr & UART_MSR_RI) >> 4))
394
                uarts[i].regs.msr |= UART_MSR_TERI;
395
              if ((uarts[i].regs.mcr & UART_MCR_RTS) !=
396
                  ((uarts[i].regs.msr & UART_MSR_CTS) >> 3))
397
                uarts[i].regs.msr |= UART_MSR_DCTS;
398
              if ((uarts[i].regs.mcr & UART_MCR_DTR) !=
399
                  ((uarts[i].regs.msr & UART_MSR_DSR) >> 5))
400
                uarts[i].regs.msr |= UART_MSR_DDSR;
401
              uarts[i].regs.msr &= ~(UART_MSR_DCD | UART_MSR_RI
402
                                     | UART_MSR_DSR | UART_MSR_CTS);
403
              uarts[i].regs.msr |= ((uarts[i].regs.mcr & UART_MCR_AUX2) << 4);
404
              uarts[i].regs.msr |= ((uarts[i].regs.mcr & UART_MCR_AUX1) << 4);
405
              uarts[i].regs.msr |= ((uarts[i].regs.mcr & UART_MCR_RTS) << 3);
406
              uarts[i].regs.msr |= ((uarts[i].regs.mcr & UART_MCR_DTR) << 5);
407
            }
408 31 lampret
 
409 185 chris
          /* Interrupt detection in proper priority order. */
410
          uarts[i].regs.iir = UART_IIR_NO_INT;
411
          if (uarts[i].regs.ier & UART_IER_RLSI &&
412
              uarts[i].regs.lsr & (UART_LSR_OVRRUN | UART_LSR_PARITY
413
                                   | UART_LSR_FRAME | UART_LSR_BREAK))
414
            {
415
              uarts[i].regs.iir = UART_IIR_RLSI;
416
            }
417
          else if (uarts[i].regs.ier & UART_IER_RDI &&
418
                   uarts[i].regs.lsr & UART_LSR_RDRDY)
419
            {
420
              uarts[i].regs.iir = UART_IIR_RDI;
421
            }
422
          else if (uarts[i].regs.ier & UART_IER_THRI &&
423
                   uarts[i].regs.lsr & UART_LSR_TXBUFE)
424
            {
425
              uarts[i].regs.iir = UART_IIR_THRI;
426
            }
427
          else if (uarts[i].regs.ier & UART_IER_MSI &&
428
                   uarts[i].regs.msr & (UART_MSR_DCTS | UART_MSR_DDSR
429
                                        | UART_MSR_TERI | UART_MSR_DDCD))
430
            {
431
              uarts[i].regs.iir = UART_IIR_MSI;
432
            }
433
          if (!(uarts[i].regs.iir & UART_IIR_NO_INT))
434
            report_interrupt(INT_UART);
435 31 lampret
        }
436
}
437
 
438
/* Print register values on stdout. */
439
void uart_status()
440
{
441 185 chris
  int i;
442 31 lampret
 
443 185 chris
  for(i = 0; i < NR_UARTS; i++) {
444
    if (uarts[i].txfd < 0)
445
      continue;
446
 
447
    printf("\nUART%d visible registers at 0x%.8x:\n", i, uarts[i].baseaddr);
448
    printf("RXBUF: %.2x  TXBUF: %.2x\n", uarts[i].regs.rxbuf, uarts[i].regs.txbuf);
449
    printf("DLL  : %.2x  DLH  : %.2x\n", uarts[i].regs.dll, uarts[i].regs.dlh);
450
    printf("IER  : %.2x  IIR  : %.2x\n", uarts[i].regs.ier, uarts[i].regs.iir);
451
    printf("LCR  : %.2x  MCR  : %.2x\n", uarts[i].regs.lcr, uarts[i].regs.mcr);
452
    printf("LSR  : %.2x  MSR  : %.2x\n", uarts[i].regs.lsr, uarts[i].regs.msr);
453
    printf("SCR  : %.2x\n", uarts[i].regs.scr);
454 31 lampret
 
455 185 chris
    printf("\nInternal registers (sim debug):\n");
456
    printf("RXSER: %.2x  TXSER: %.2x\n", uarts[i].iregs.rxser, uarts[i].iregs.txser);
457 31 lampret
 
458 185 chris
    printf("\nInternal status (sim debug):\n");
459
    printf("char_clks: %d\n", uarts[i].char_clks);
460
    printf("rxser_clks: %d  txser_clks: %d\n", uarts[i].istat.rxser_clks, uarts[i].istat.txser_clks);
461
    printf("rxser: %d  txser: %d\n", uarts[i].istat.rxser, uarts[i].istat.txser);
462
    printf("rxbuf: %d  txbuf: %d\n", uarts[i].istat.rxbuf, uarts[i].istat.txbuf);
463 31 lampret
 
464 185 chris
    printf("RX fd: %d  TX fd: %d\n\n", uarts[i].rxfd, uarts[i].txfd);
465
  }
466
}
467
 
468
/* Send a byte. Return 1 for OK. 0 for timeout. -1 if a
469
   system error occurred. Asynchronous port is implied by
470
   passing a negative number to the timeout field. In this
471
   case, the function will return without generating an
472
   error message if it can not send. This simulates
473
   congestion control from the external source. */
474
int send_byte(int fd,int timeout,int uart_id,int byte)
475
{
476
  struct timeval now;
477
  struct timeval until;
478
  struct pollfd set;
479
  int msecs = 0;
480
  unsigned char ch = byte;
481
 
482
  if(gettimeofday(&now,NULL) < 0)
483
    {
484
      now.tv_sec = time(NULL);
485
      now.tv_usec = 0;
486
    }
487
 
488
  until.tv_sec = now.tv_sec;
489
  if(timeout > 0)
490
    until.tv_usec = now.tv_usec + timeout*1000;
491
  else
492
    until.tv_usec = now.tv_usec;
493
 
494
  if(until.tv_usec > 999999)
495
    {
496
      until.tv_sec++;
497
      until.tv_usec -= 1000000;
498
    }
499
 
500
  msecs = timeout > 0 ? timeout : 0;
501
  set.fd = fd;
502
  set.events = POLLOUT;
503
  set.revents = 0;
504
 
505
  while(msecs >= 0)
506
    {
507
      char sTemp[256];
508
 
509
      switch(poll(&set,1,msecs))
510
        {
511
        case 1: /* We're good, or we got an error */
512
          switch(write(fd,&ch,1))
513
            {
514
            case -1:
515
              sprintf(sTemp,"UART %d TX - write",uart_id);
516
              perror(sTemp);
517
              fflush(stderr);
518
              return -1;
519
            case 0:
520
              fprintf(stderr,"UART %d TX EOF detected. Shutting down"
521
                      " to prevent endless loop.\n",uart_id);
522
              fflush(stderr);
523
              if(uarts[uart_id].txfd >= 0)
524
                close(uarts[uart_id].txfd);
525
              if(uarts[uart_id].rxfd >= 0)
526
                close(uarts[uart_id].rxfd);
527
              uarts[uart_id].txfd = uarts[uart_id].rxfd = -1;
528
              return 0;
529
            case 1:
530
              return 1;
531
            }
532
        case 0: /* We timed out. Stop the loop. */
533
          msecs = -1;
534
          break;
535
        case -1:
536
          if(errno == EINTR)
537
            {
538
              if(gettimeofday(&now,NULL) < 0)
539
                {
540
                  now.tv_sec = time(NULL);
541
                  now.tv_usec = 0;
542
                }
543
              msecs = (until.tv_sec - now.tv_sec)*1000 +
544
                until.tv_usec - now.tv_usec;
545
              continue;
546
            }
547
          else
548
            {
549
              char sTemp[256];
550
 
551
              sprintf(sTemp,"UART %d TX - poll",uart_id);
552
              perror(sTemp);
553
              fflush(stderr);
554
              return -1;
555
            }
556 31 lampret
        }
557 185 chris
    }
558
 
559
  if(timeout >= 0)
560
    {
561
      fprintf(stderr,"Transmit timeout occurred on UART %d. Data "
562
              "may be corrupt.\n",uart_id);
563
      fflush(stderr);
564
    }
565
  return 0;
566 31 lampret
}
567 185 chris
 
568
/* Receive a byte. Return 1 for OK. 0 for timeout. -1 if a
569
   system error occurred. Asynchronous port is implied by
570
   passing a negative number to the timeout field. In this
571
   case, the function will return without generating an
572
   error message. */
573
int receive_byte(int fd,int timeout,int uart_id,unsigned char* byte)
574
{
575
  struct timeval now;
576
  struct timeval until;
577
  struct pollfd set;
578
  int msecs = 0;
579
 
580
  if(gettimeofday(&now,NULL) < 0)
581
    {
582
      now.tv_sec = time(NULL);
583
      now.tv_usec = 0;
584
    }
585
 
586
  until.tv_sec = now.tv_sec;
587
  if(timeout > 0)
588
    until.tv_usec = now.tv_usec + timeout*1000;
589
  else
590
    until.tv_usec = now.tv_usec;
591
 
592
  if(until.tv_usec > 999999)
593
    {
594
      until.tv_sec++;
595
      until.tv_usec -= 1000000;
596
    }
597
 
598
  msecs = timeout > 0 ? timeout : 0;
599
  set.fd = fd;
600
  set.events = POLLIN;
601
  set.revents = 0;
602
 
603
  while(msecs >= 0)
604
    {
605
      char sTemp[256];
606
 
607
      switch(poll(&set,1,msecs))
608
        {
609
        case 1: /* We're good, or we got an error */
610
          switch(read(fd,byte,1))
611
            {
612
            case -1:
613
              sprintf(sTemp,"UART %d RX - read",uart_id);
614
              perror(sTemp);
615
              fflush(stderr);
616
              return -1;
617
            case 0:
618
              fprintf(stderr,"UART %d RX EOF detected. Shutting down"
619
                      " to prevent endless loop.\n",uart_id);
620
              fflush(stderr);
621
              if(uarts[uart_id].txfd >= 0)
622
                close(uarts[uart_id].txfd);
623
              if(uarts[uart_id].rxfd >= 0)
624
                close(uarts[uart_id].rxfd);
625
              uarts[uart_id].txfd = uarts[uart_id].rxfd = -1;
626
              return 0;
627
            case 1:
628
              return 1;
629
            }
630
        case 0: /* We timed out. Stop the loop. */
631
          *byte = 0xFF;
632
          msecs = -1;
633
          break;
634
        case -1:
635
          if(errno == EINTR)
636
            {
637
              if(gettimeofday(&now,NULL) < 0)
638
                {
639
                  now.tv_sec = time(NULL);
640
                  now.tv_usec = 0;
641
                }
642
              msecs = (until.tv_sec - now.tv_sec)*1000 +
643
                until.tv_usec - now.tv_usec;
644
              continue;
645
            }
646
          else
647
            {
648
              char sTemp[256];
649
 
650
              sprintf(sTemp,"UART %d RX - poll",uart_id);
651
              perror(sTemp);
652
              fflush(stderr);
653
              return -1;
654
            }
655
        }
656
    }
657
 
658
  if(timeout >= 0)
659
    {
660
      fprintf(stderr,"Receive timeout occurred on UART %d. Data "
661
              "may be corrupt.\n",uart_id);
662
      fflush(stderr);
663
    }
664
  return 0;
665
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.