home *** CD-ROM | disk | FTP | other *** search
- /*
- * Filename:
- * Version:
- * Author: Frank Naumann
- * Started: 1999-07-28
- * Last Updated: 1999-08-06
- * Target O/S: TOS/MiNT
- * Description:
- *
- * Note: Please send suggestions, patches or bug reports to me
- * or the MiNT mailing list <mint@fishpool.com>.
- *
- * Copying: Copyright 1999 Frank Naumann <fnaumann@cs.uni-magdeburg.de>
- * Portions copyright 1998, 1999 Rainer Mannigel, Michael Schwingen.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * changes since last version:
- *
- * 1999-08-21: (v0.40)
- *
- * - new: added MiNT version and Milan check
- * - new: added tty tread & twrite functions, ttys work now
- * - new: added automatic tty install (init, open)
- * - new: check & evaluate file sharing modes (open, close)
- * - new: wake up sleeping process on close
- * - fix: wrong return value in read & write for N_DELAY
- *
- * 1999-08-14: (v0.30b)
- *
- * - new: optimized read data interrupt routine
- * - new: return EWOULDBLOCK in read & write if N_DELAY is set
- *
- * 1999-08-09: (v0.20b)
- *
- * - inital revision
- *
- *
- * known bugs:
- *
- *
- * todo:
- *
- *
- *
- * UART BIOS and XBIOS Routinen for Milan.
- * Rainer Mannigel, Michael Schwingen
- *
- * We now support lots (currently 10) of UARTs, and interrupt sharing
- * between them. We install one interrupt handler for each physical
- * interrupt line that belongs to one or more UARTs, and that gets the
- * pointer to the first UART's iovar in its corresponding intr_iovar. The
- * iovars are chained together by the next field, so the interrupt handler
- * services one UART at a time as long as there are events left to be
- * handled and then goes on to the next UART.
- *
- * Due to the braindamaged design using Bconmap() to access more than one
- * serial port, we do not get a useable device number in the BIOS calls
- * (Bconin/out/stat/ostat), which means that we have to provide one entry
- * point for each of these routines (and for Rsconf, which gets no device
- * numbger at all) for every port we want to handle - this is why there is a
- * statical limit - these routines are in stubs.s
- */
-
- /* FreeMiNT header */
- # include <atarierr.h>
- # include <default.h>
- # include <dcntl.h>
- # include <file.h>
- # include <fstring.h>
-
- # include <osbind.h>
-
- # include "kernel.h"
- # include "rsvf.h"
- # include "pc16550.h"
-
-
- /*
- * version
- */
-
- # define VER_MAJOR 0
- # define VER_MINOR 40
- # define VER_STATUS
-
-
- /*
- * debugging stuff
- */
-
- # if 0
- # define DEV_DEBUG 1
- # endif
-
- # if 0
- # define INT_DEBUG 1
- # endif
-
-
- /*
- * default settings
- */
-
- # define RSVF_BASENAME "serial"
- # define RSVF_OFFSETT 1
-
- # define TTY_BASENAME "tty"
- # define TTY_OFFSETT 'c'
-
-
- # define IOBUFSIZE 4096
-
- # define MAX_PORTS 10
- # define MAX_INTS 5 /* 2 onboard + 3 ISA cards */
-
-
- /*
- * messages
- */
-
- # define MSG_VERSION str (VER_MAJOR) "." str (VER_MINOR) str (VER_STATUS)
- # define MSG_BUILDDATE __DATE__
-
- # define MSG_BOOT \
- "\033p Milan UART serial driver version " MSG_VERSION " \033q\r\n"
-
- # define MSG_GREET \
- "╜ 1998, 1999 by Rainer Mannigel, Michael Schwingen.\r\n" \
- "╜ " MSG_BUILDDATE " by Frank Naumann <fnaumann@cs.uni-magdeburg.de>.\r\n\r\n"
-
- # define MSG_MINT \
- "\033pMiNT to old!\033q\r\n"
-
- # define MSG_MILAN \
- "\033pThis driver require a Milan!\033q\r\n"
-
- # define MSG_FAILURE \
- "\7\r\nSorry, driver NOT installed - initialization failed!\r\n\r\n"
-
-
- /****************************************************************************/
- /* BEGIN kernel interface */
-
- struct kerinfo *kernel;
-
- /* END kernel interface */
- /****************************************************************************/
-
- /****************************************************************************/
- /* BEGIN definition part */
-
- typedef struct iorec IOREC;
- struct iorec
- {
- uchar *buffer; /* buffer location pointer */
- ushort size; /* maximum size of this buffer */
- volatile ushort head; /* offset to next byte to be taken
- * from this buffer */
- volatile ushort tail; /* offset to next location available
- * to insert a new byte */
- ushort low_water; /* amount of space in buffer before a "xon"
- * may be sent to restore normal use of
- * buffer */
- ushort high_water; /* amount of space used in buffer that
- * trigger's the sending of a "xoff" signal
- * to the host */
- ushort res; /* alignment */
- };
-
- typedef struct iovar IOVAR;
- struct iovar
- {
- UART *regs; /* UART register base address */
- IOVAR *next; /* for Interrupt-Sharing */
-
- IOREC input; /* input buffer */
- IOREC output; /* output buffer */
-
- ushort rxoff; /* flag: receiver stopped (buffer full) */
- ushort txoff; /* flag: transmitter stopped */
-
- ushort hsk_mode; /* handshake mode */
- # define SHAKE_XON_OFF 0x1
- # define SHAKE_RTS_CTS 0x2
-
- uchar sendnow; /* one byte of control data, bypasses buffer */
- uchar res1; /* alignment */
-
- long baudrate; /* current baud rate value */
- long baudbase; /* crystal frequency / 16 */
-
- ushort intr; /* intr number */
- ushort lockpid; /* */
-
- FILEPTR *open; /* */
- TTY tty; /* */
- };
-
-
- # define XON 0x11
- # define XOFF 0x13
-
-
- # if 0
- void int_autoprobe_start(void);
- int int_autoprobe_end(void);
- void set_int_levelmode(uchar int_nr);
- # endif
-
-
- /*
- * inline assembler primitives
- */
- FASTFN ushort spl7 (void);
- FASTFN void spl (ushort old_sr);
-
- FASTFN void rts_on (UART *regs);
- FASTFN void rts_off (UART *regs);
- FASTFN void dtr_on (UART *regs);
- FASTFN void dtr_off (UART *regs);
- FASTFN void brk_on (UART *regs);
- FASTFN void brk_off (UART *regs);
- FASTFN void txint_on (UART *regs);
- FASTFN void txint_off (UART *regs);
-
-
- /*
- * initialization
- */
- FASTFN int detect_uart (UART *regs, ulong *baudbase);
- FASTFN int init_uart (IOVAR **iovar, ushort base, int intr, long baudbase);
- FASTFN void init_pc16550 (void);
- DEVDRV * _cdecl init (struct kerinfo *k);
-
-
- /*
- * buffer manipulation
- */
- FASTFN int iorec_empty (IOREC *iorec);
- FASTFN int iorec_full (IOREC *iorec);
- FASTFN uchar iorec_get (IOREC *iorec);
- FASTFN int iorec_put (IOREC *iorec, uchar data);
- FASTFN long iorec_used (IOREC *iorec);
- FASTFN long iorec_free (IOREC *iorec);
-
-
- /*
- * start/stop primitives
- */
- static void stop_receiver (IOVAR *iovar, UART *regs);
- static void start_receiver (IOVAR *iovar, UART *regs);
- FASTFN void stop_transmitter (IOVAR *iovar);
- FASTFN void start_transmitter (IOVAR *iovar);
-
-
- /*
- * interrupt handling
- */
- FASTFN void pc16550_read_x (IOVAR *iovar, UART *regs);
- FASTFN void pc16550_read_o (IOVAR *iovar, UART *regs);
- FASTFN void pc16550_read (IOVAR *iovar, UART *regs);
- FASTFN void pc16550_write (IOVAR *iovar, UART *regs);
- FASTFN void pc16550_ctsint (IOVAR *iovar, uchar msr);
- static void pc16550_int (void);
-
- void pc16550_intx (void);
- void pc16550_int0 (void);
- void pc16550_int1 (void);
- void pc16550_int2 (void);
- void pc16550_int3 (void);
- void pc16550_int4 (void);
-
-
- /*
- * device driver
- */
- static long _cdecl uart_open (FILEPTR *f);
- static long _cdecl uart_writeb (FILEPTR *f, const char *buf, long bytes);
- static long _cdecl uart_readb (FILEPTR *f, char *buf, long bytes);
- static long _cdecl uart_twrite (FILEPTR *f, const char *buf, long bytes);
- static long _cdecl uart_tread (FILEPTR *f, char *buf, long bytes);
- static long _cdecl uart_lseek (FILEPTR *f, long where, int whence);
- static long _cdecl uart_ioctl (FILEPTR *f, int mode, void *buf);
- static long _cdecl uart_datime (FILEPTR *f, ushort *timeptr, int rwflag);
- static long _cdecl uart_close (FILEPTR *f, int pid);
- static long _cdecl uart_select (FILEPTR *f, long proc, int mode);
- static void _cdecl uart_unselect (FILEPTR *f, long proc, int mode);
-
- static DEVDRV raw_devtab =
- {
- uart_open,
- uart_writeb, uart_readb, uart_lseek, uart_ioctl, uart_datime,
- uart_close,
- uart_select, uart_unselect,
- };
-
- static DEVDRV tty_devtab =
- {
- uart_open,
- uart_twrite, uart_tread, uart_lseek, uart_ioctl, uart_datime,
- uart_close,
- uart_select, uart_unselect,
- uart_writeb, uart_readb
- };
-
-
- /*
- * debugging stuff
- */
-
- # ifdef DEV_DEBUG
- # define DEBUG(x) KERNEL_DEBUG x
- # define TRACE(x) KERNEL_TRACE x
- # define ALERT(x) KERNEL_ALERT x
- # else
- # define DEBUG(x)
- # define TRACE(x)
- # define ALERT(x) KERNEL_ALERT x
- # endif
-
- # ifdef INT_DEBUG
- # define DEBUG_I(x) KERNEL_DEBUG x
- # define TRACE_I(x) KERNEL_TRACE x
- # define ALERT_I(x) KERNEL_ALERT x
- # else
- # define DEBUG_I(x)
- # define TRACE_I(x)
- # define ALERT_I(x) KERNEL_ALERT x
- # endif
-
- /* END definition part */
- /****************************************************************************/
-
- /****************************************************************************/
- /* BEGIN global data definition & access implementation */
-
- /*
- * global data structures
- */
-
- static IOVAR *pc16550_iovar [MAX_PORTS * 2];
-
- # define IOVARS(nr) (pc16550_iovar [nr])
- # define IOVAR_TTY_OFFSET (MAX_PORTS)
- # define IOVAR_MAX (MAX_PORTS * 2 - 1)
-
-
- /*
- * interrupt data structures
- */
-
- /* ptr to first UART struct for each interrupt handler
- */
- static IOVAR *intr_iovar [MAX_INTS];
-
- /* ptr to interrupt handler routine, used for Setexc
- */
- static void (*intr_handler [MAX_INTS])(void) =
- {
- pc16550_int0,
- pc16550_int1,
- pc16550_int2,
- pc16550_int3,
- pc16550_int4
- };
-
- /* END global data & access implementation */
- /****************************************************************************/
-
- /****************************************************************************/
- /* BEGIN inline assembler primitives */
-
- FASTFN ushort
- spl7 (void)
- {
- ushort old_sr;
-
- __asm__ volatile
- (
- "move.w %%sr,%0;"
- "ori #0x0700,%%sr"
- : "=d" (old_sr) /* output register */
- : /* input registers */
- : "cc" /* clobbered */
- );
-
- return old_sr;
- }
-
- FASTFN void
- spl (ushort old_sr)
- {
- __asm__ volatile
- (
- "move.w %0,%%sr"
- : /* output register */
- : "d" (old_sr) /* input registers */
- : "cc" /* clobbered */
- );
- }
-
-
-
- FASTFN void
- rts_on (UART *regs)
- {
- # if 0
- ushort sr = spl7 ();
- regs->mcr |= RTSO;
- spl (sr);
- # else
- asm volatile
- (
- "bset.b #1,4(%0)" /* set RTSO in MCR */
- :
- : "a" (regs)
- : "cc"
- );
- # endif
- DEBUG_I (("PC16550 RTS on"));
- }
-
- FASTFN void
- rts_off (UART *regs)
- {
- # if 0
- ushort sr = spl7 ();
- regs->mcr &= ~RTSO;
- spl (sr);
- # else
- asm volatile
- (
- "bclr.b #1,4(%0)" /* delete RTSO in MCR */
- :
- : "a" (regs)
- : "cc"
- );
- # endif
- DEBUG_I (("PC16550 RTS off"));
- }
-
-
- FASTFN void
- dtr_on (UART *regs)
- {
- DEBUG_I (("PC16550 DTR on"));
- # if 0
- regs->mcr |= DTRO;
- # else
- asm volatile
- (
- "bset.b #0,4(%0)" /* set DTRO in MCR */
- :
- : "a" (regs)
- : "cc"
- );
- # endif
- }
-
- FASTFN void
- dtr_off (UART *regs)
- {
- DEBUG_I (("PC16550 DTR off"));
- # if 0
- regs->mcr |= DTRO;
- # else
- asm volatile
- (
- "bclr.b #0,4(%0)" /* delete DTRO in MCR */
- :
- : "a" (regs)
- : "cc"
- );
- # endif
- }
-
-
- FASTFN void
- brk_on (UART *regs)
- {
- DEBUG_I (("PC16550 BRK on"));
- regs->lcr |= SBRK;
- }
-
- FASTFN void
- brk_off (UART *regs)
- {
- DEBUG_I (("PC16550 BRK off"));
- regs->lcr &= ~SBRK;
- }
-
-
- FASTFN void
- txint_on (UART *regs)
- {
- DEBUG_I (("PC16550 TXINT on"));
- # if 0
- regs->ier |= TXLDL_IE;
- # else
- asm volatile
- (
- "bset.b #1,1(%0)" /* set TXLDL_IE in IER */
- :
- : "a" (regs)
- : "cc"
- );
- # endif
- }
-
- FASTFN void
- txint_off (UART *regs)
- {
- DEBUG_I (("PC16550 TXINT off"));
- # if 0
- regs->ier &= ~TXLDL_IE;
- # else
- asm volatile
- (
- "bclr.b #1,1(%0)" /* delete TXLDL_IE in IER */
- :
- : "a" (regs)
- : "cc"
- );
- # endif
- }
-
- /* END inline assembler primitives */
- /****************************************************************************/
-
- /****************************************************************************/
- /* BEGIN initialization */
-
- /*
- * Autodetect a UART.
- *
- * This routine first does some sanity checks to be sure that there is a
- * UART at the diven address. It then enables the interrupt and toggles the
- * IER to generate an interrupt, to autodetect the interrupt line. The
- * interrupt driver is disabled after this, which means that multiple UARTs
- * using the same interrupt will be detected OK even if the hardware does
- * not support sharing the interrupt line once all UARTs are enabled later.
- * The last thing is to measure the BRG crystal by transmitting some
- * characters (in loopback mode) with disabled FIFOs and measuring the time
- * needed by using MFP timer A.
- *
- * We time sending 18 characters (or 180 bits) at the highest possible speed
- * (BRG divide by 1, or 115200 bps at 1.8432MHz). At a MFP clock of
- * 2.4576MHz and a :16 prescaler, this gives the following counted values:
- *
- * Crystal (MHz) count BRG=1 rate
- * 1.8432 240 115200
- * 3.6864 120 230400
- * 7.3728 60 460800
- *
- * 4.0 111 250000 (for MIDI cards)
- * 6.0 74 375000 (for MIDI cards)
- *
- */
-
- /* only in one place used -> FASTFN
- */
- FASTFN int
- detect_uart (UART *regs, ulong *baudbase)
- {
- ulong rate = 115200;
- int intr = 0;
- int i;
-
-
- *baudbase = 0L;
-
- /* read LSR */
- (void) regs->lsr;
- /* now LSR may not be $FF! */
- if (regs->lsr == 0xff)
- return 0;
-
- regs->scr = 0x55;
- if (regs->scr != 0x55)
- return 0;
-
- regs->scr = 0xAA;
- if (regs->scr != 0xAA)
- return 0;
-
- /* set DLAB */
- regs->lcr = 0x83;
-
- /* set baudrate */
- regs->dlm = (115200 / rate) >> 8;
- regs->dll = (115200 / rate) & 0xFF;
-
- /* 8N1 */
- regs->lcr = 0x03;
- regs->ier = 0;
-
- /* Reset FIFOs */
- regs->fcr = RXFR | TXFR;
- /* Disable FIFOs */
- regs->fcr = 0;
-
- /* enable loopback */
- regs->mcr = LOOP;
-
- /* check loopback */
- if ((regs->msr & 0xf0) != 0)
- return 0;
-
- /* enable loopback */
- regs->mcr = LOOP | 0x0f;
-
- /* check loopback */
- if ((regs->msr & 0xf0) != 0xf0)
- return 0;
-
- # if 0
- int_autoprobe_start ();
-
- regs->mcr = GI_EN;
-
- /* this will create enough INTs */
- regs->ier = 0x00;
- regs->ier = 0x0f;
- regs->ier = 0x00;
- regs->ier = 0x0f;
-
- /* short delay */
- for (i = 255; i >= 0; i--)
- (void) regs->rbr;
-
- regs->ier = 0;
- regs->mcr = 0;
-
- intr = int_autoprobe_end ();
- # else
- if ((UART *) (0x03f8L + 0xc0000000L) == regs)
- {
- /* builtin port 1 */
- intr = 4;
- }
- else if ((UART *) (0x02f8L + 0xc0000000L) == regs)
- {
- /* builtin port 2 */
- intr = 3;
- }
- else
- {
- /* no detection available yet */
- intr = 0;
- }
- # endif
-
- if (intr > 0)
- {
- # if 0
- *baudbase = 115200L;
- # else
- /* volatile uchar *tcdr = (volatile uchar *) 0xffffc103L + 17 * 4; */
- volatile uchar *tadr = (volatile uchar *) 0xffffc103L + 15 * 4;
- volatile uchar *tacr = (volatile uchar *) 0xffffc103L + 12 * 4;
-
- ushort sr;
- short time;
-
-
- sr = spl7 ();
-
- /* enable loopback */
- regs->mcr = LOOP;
-
- *tacr = 0;
- *tadr = 0xff;
- while (*tadr != 0xff)
- ;
-
- for (i = 0; i < 19; i++)
- {
- /* send 1 char */
- regs->thr = 0x00;
-
- /* wait until done */
- while ((regs->lsr & TXDE) == 0)
- ;
-
- if (i == 0)
- *tacr = 3;
- }
-
- /* stop timer */
- *tacr = 0;
- time = 255 - *tadr;
-
- /* get Rx data */
- while ((regs->lsr & RXDA))
- (void) regs->rbr;
-
- /* disable loopback */
- regs->mcr = GI_EN;
- (void) regs->iir;
- (void) regs->msr;
-
- spl (sr);
-
-
- if (time > 230 && time <= 250) *baudbase = 115200L;
- else if (time > 115 && time <= 125) *baudbase = 230400L;
- else if (time > 55 && time <= 65) *baudbase = 460800L;
- else if (time > 105 && time <= 115) *baudbase = 250000L;
- else if (time > 70 && time <= 80) *baudbase = 375000L;
- # endif
-
- DEBUG (("detect_clock: t = %d, baudbase = %lu", time, *baudbase));
- }
-
- /* Reset FIFOs */
- regs->fcr = FIFO_EN | RXFR | TXFR;
- regs->fcr = FIFO_EN | RXFTH_8;
-
- if ((regs->iir & 0xc0) != 0xc0)
- {
- DEBUG (("no 16550A at %lx, INT %i", regs, intr));
- return 0;
- }
-
- DEBUG (("detected 16550A at %lx, INT %i", regs, intr));
- return intr;
- }
-
- /* only in one place used -> FASTFN
- */
- FASTFN int
- init_uart (IOVAR **iovar, ushort base, int intr, long baudbase)
- {
- char *buffer;
-
- *iovar = kmalloc (sizeof (**iovar));
- if (!*iovar)
- goto error;
-
- bzero (*iovar, sizeof (**iovar));
-
- buffer = kmalloc (2 * IOBUFSIZE);
- if (!buffer)
- goto error;
-
- (*iovar)->input.buffer = buffer;
- (*iovar)->output.buffer = buffer + IOBUFSIZE;
-
- (*iovar)->input.size = (*iovar)->output.size = IOBUFSIZE;
- (*iovar)->input.low_water = (*iovar)->output.low_water = 1 * (IOBUFSIZE / 4);
- (*iovar)->input.high_water = (*iovar)->output.high_water = 3 * (IOBUFSIZE / 4);
-
- (*iovar)->regs = (UART *) (0xC0000000L | base);
- (*iovar)->intr = intr;
- (*iovar)->baudbase = baudbase;
-
- {
- UART *regs = (*iovar)->regs;
- long div;
-
- regs->ier = 0;
-
- (*iovar)->baudrate = 9600;
- div = (*iovar)->baudbase / 9600;
-
- regs->lcr |= BNKSE;
- regs->dll = (div ) & 0xFF;
- regs->dlm = (div >> 8) & 0xFF;
- regs->lcr &= ~BNKSE;
-
- /* Reset FIFOs */
- regs->fcr = FIFO_EN | RXFR | TXFR;
- /* Enable FIFOs, set Rcv Threshold */
- regs->fcr = FIFO_EN | RXFTH_8;
-
- regs->lcr = 3; /* 8bit char, 1 stopbit, no parity */
-
- (*iovar)->rxoff = 0; /* receiver on */
- (*iovar)->txoff = 1; /* transmitter off */
- (*iovar)->hsk_mode = SHAKE_RTS_CTS; /* RTS/CTS */
-
- rts_on (regs);
- dtr_on (regs);
-
- regs->ier = RXHDL_IE | LS_IE | MS_IE;
- regs->mcr |= (GI_EN | RTSO);
- }
-
- return 1;
-
- error:
- if (*iovar)
- kfree (*iovar);
-
- ALERT (("uart.xdd: kmalloc(%li, %li) fail, out of memory?", sizeof (**iovar), IOBUFSIZE));
- return 0;
- }
-
- /* only in one place used -> FASTFN
- */
- FASTFN void
- init_pc16550 (void)
- {
- # define NUM_BASES 12
- ushort bases[NUM_BASES] =
- {
- 0x03f8L, 0x02f8L, /* on-board SERIAL1 + SERIAL2 */
- 0x03e8L, 0x02e8L,
- 0x02a0L, 0x02a8L, 0x02b0, 0x02b8, /* first AST fourport */
- 0x01a0L, 0x01a8L, 0x01b0, 0x01b8 /* second AST fourport */
- };
- ulong baudbase[NUM_BASES];
- uchar intr[NUM_BASES];
-
- static int did_init;
-
- int i, j;
- ushort sr;
-
- int current_iovar = 0;
- int intr_num = 0;
-
-
- if (!did_init)
- {
- for (i = 0; i < NUM_BASES; i++)
- intr[i] = detect_uart ((UART *) (bases[i] + 0xc0000000L), &baudbase[i]);
-
- did_init = 1;
- }
-
- DEBUG (("UARTS found:"));
-
- sr = spl7 ();
- for (i = 0; i < NUM_BASES; i++)
- {
- if (intr[i] && baudbase[i] && current_iovar < MAX_PORTS)
- {
- DEBUG (("base %x, intr %i, baudbase %lu", bases[i], intr[i], baudbase[i]));
-
- if (init_uart (&(IOVARS (current_iovar)), bases[i], intr[i], baudbase[i]))
- current_iovar++;
- }
- }
-
- /* install interrupt handlers
- * chain iovars into a linked list per shared interrupt
- */
- for (i = 0; i < current_iovar; i++)
- {
- int chain_int = 0;
-
- DEBUG (("installing INT for UART %d:",i));
-
- for (j = 0; j < i; j++)
- if (IOVARS (i)->intr == IOVARS (j)->intr)
- chain_int = j;
-
- if (chain_int)
- {
- DEBUG (("chaining iovar %d to iovar %d", i, chain_int));
-
- IOVARS (chain_int)->next = IOVARS (i);
- /* set_int_levelmode (IOVARS (i)->intr); */
- }
- else if (intr_num < MAX_INTS)
- {
- void *old;
-
- DEBUG (("allocating new int handler %d to iovar %d, INT %d", intr_num, i, IOVARS (i)->intr));
-
- intr_iovar[intr_num] = IOVARS (i);
- old = Setexc (80 + IOVARS (i)->intr, intr_handler[intr_num]);
- DEBUG (("old int handler = %lx", old));
-
- intr_num++;
- }
- else
- DEBUG (("ERROR: no free int handler for UART using int %d", IOVARS (i)->intr));
- }
-
- spl (sr);
- }
-
- DEVDRV * _cdecl
- init (struct kerinfo *k)
- {
- RSVF *rsvfptr;
- RSVF *rsvf;
- char *ptr;
- long mch;
- int initialized;
- int i;
-
- struct dev_descr raw_dev_descriptor =
- {
- &raw_devtab,
- 0, /* dinfo -> fc.aux */
- 0, /* flags */
- NULL, /* struct tty * */
- 0, /* drvsize */
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH,
- { 0, 0 }
- };
-
- struct dev_descr tty_dev_descriptor =
- {
- &tty_devtab,
- 0, /* dinfo -> fc.aux */
- O_TTY, /* flags */
- NULL, /* struct tty * */
- 44, /* drvsize */
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH,
- { 0, 0 }
- };
-
-
- kernel = k;
-
- c_conws (MSG_BOOT);
- c_conws (MSG_GREET);
-
- DEBUG (("%s: enter init", __FILE__));
-
- if ((MINT_MAJOR == 0)
- || ((MINT_MAJOR == 1) && (MINT_MINOR < 15)))
- {
- c_conws (MSG_MINT);
- goto failure;
- }
-
- # define SSYS_GETCOOKIE 8
- # define COOKIE__MCH 0x5f4d4348L
- # define MILAN_C 0x00040000L
- if ((s_system (SSYS_GETCOOKIE, COOKIE__MCH, &mch) != 0)
- || (mch != MILAN_C))
- {
- c_conws (MSG_MILAN);
- goto failure;
- }
-
- /* temporary until MiNT will do this */
- # define RSVF_BUF 1024L
- rsvf = rsvfptr = (RSVF *) m_xalloc (RSVF_BUF, 0x40);
- if (!rsvf)
- {
- DEBUG (("%s: m_xalloc fail!", __FILE__));
- goto failure;
- }
-
- bzero (rsvf, RSVF_BUF);
-
- ptr = (char *) rsvf;
- ptr += 512;
-
- init_pc16550 ();
- initialized = 1;
-
- for (i = 0; i < MAX_PORTS && IOVARS (i); i++)
- {
- char name [64];
-
-
- ksprintf (name, "u:\\dev\\%s%i", RSVF_BASENAME, i + RSVF_OFFSETT);
-
- raw_dev_descriptor.dinfo = i;
- raw_dev_descriptor.tty = &(IOVARS (i)->tty);
- if (d_cntl (DEV_INSTALL, name, &raw_dev_descriptor) >= 0)
- {
- DEBUG (("%s: %s installed", __FILE__, name));
-
- rsvfptr->data = ptr;
- rsvfptr->type = RSVF_PORT | RSVF_GEMDOS | RSVF_BIOS;
- rsvfptr->bdev = 7 + i;
-
- ksprintf (rsvfptr->data, "%s%i", RSVF_BASENAME, i + RSVF_OFFSETT);
-
- DEBUG (("uart: installed %s on %i", rsvfptr->data, 7 + i));
-
- ptr += ((strlen (rsvfptr->data) + 1) + 3) & ~3;
- rsvfptr++;
- }
-
-
- ksprintf (name, "u:\\dev\\%s%c", TTY_BASENAME, (char) (i + TTY_OFFSETT));
-
- tty_dev_descriptor.dinfo = i + IOVAR_TTY_OFFSET;
- tty_dev_descriptor.tty = &(IOVARS (i)->tty);
- if (d_cntl (DEV_INSTALL, name, &tty_dev_descriptor) >= 0)
- {
- DEBUG (("%s: %s installed", __FILE__, name));
-
- IOVARS (i + IOVAR_TTY_OFFSET) = IOVARS (i);
- }
- }
-
- if (initialized)
- {
- # define COOKIE_RSVF 0x52535646L
- # define SSYS_SETCOOKIE 9
- s_system (SSYS_SETCOOKIE, COOKIE_RSVF, rsvf);
-
- return (DEVDRV *) 1;
- }
-
- failure:
- # if 0
- if (rsvf)
- m_free (rsvf);
- # endif
-
- c_conws (MSG_FAILURE);
- return NULL;
- }
-
- /* END initialization */
- /****************************************************************************/
-
- /****************************************************************************/
- /* BEGIN buffer manipulation */
-
- /* helper function */
- FASTFN ushort
- inc_ptr (ushort ptr, ushort size)
- {
- if (++ptr >= size)
- ptr = 0;
-
- return ptr;
- }
-
- FASTFN int
- iorec_empty (IOREC *iorec)
- {
- return (iorec->head == iorec->tail);
- }
-
- FASTFN int
- iorec_full (IOREC *iorec)
- {
- return (iorec->head == inc_ptr (iorec->tail, iorec->size));
- }
-
- FASTFN uchar
- iorec_get (IOREC *iorec)
- {
- register ushort i = inc_ptr (iorec->head, iorec->size);
- register uchar data;
-
- data = iorec->buffer[i];
- iorec->head = i;
-
- return data;
- }
-
- FASTFN int
- iorec_put (IOREC *iorec, uchar data)
- {
- register ushort i = inc_ptr (iorec->tail, iorec->size);
-
- if (i == iorec->head)
- {
- /* buffer full */
- return 0;
- }
-
- iorec->buffer[i] = data;
- iorec->tail = i;
-
- return 1;
- }
-
- FASTFN long
- iorec_used (IOREC *iorec)
- {
- register long tmp;
-
- tmp = iorec->tail;
- tmp -= iorec->head;
-
- if (tmp < 0)
- tmp += iorec->size;
-
- return tmp;
- }
-
- FASTFN long
- iorec_free (IOREC *iorec)
- {
- register long tmp;
-
- tmp = iorec->head;
- tmp -= iorec->tail;
-
- if (tmp <= 0)
- tmp += iorec->size;
-
- return tmp;
- }
-
- /* END buffer manipulation */
- /****************************************************************************/
-
- /****************************************************************************/
- /* BEGIN start/stop primitives */
-
- static void
- stop_receiver (IOVAR *iovar, UART *regs)
- {
- if (!iovar->rxoff)
- {
- /* set stop flag */
- iovar->rxoff = 1;
-
- DEBUG_I (("uart: stop receiver"));
-
- if (iovar->hsk_mode & SHAKE_XON_OFF)
- {
- /* send XOFF */
- iovar->sendnow = XOFF;
-
- /* enable interrupt */
- txint_on (regs);
- }
-
- if (iovar->hsk_mode & SHAKE_RTS_CTS)
- {
- /* set rts off */
- rts_off (regs);
- }
- }
- }
-
- static void
- start_receiver (IOVAR *iovar, UART *regs)
- {
- if (iovar->rxoff)
- {
- /* clear stop flag */
- iovar->rxoff = 0;
-
- DEBUG_I (("uart: start receiver"));
-
- if (iovar->hsk_mode & SHAKE_RTS_CTS)
- {
- /* set rts on */
- rts_on (regs);
- }
-
- if (iovar->hsk_mode & SHAKE_XON_OFF)
- {
- /* send XON */
- iovar->sendnow = XON;
-
- /* enable interrupt */
- txint_on (regs);
- }
- }
- }
-
- FASTFN void
- stop_transmitter (IOVAR *iovar)
- {
- /* set stop flag */
- iovar->txoff = 1;
-
- DEBUG_I (("uart: transmitter stoped"));
- }
-
- FASTFN void
- start_transmitter (IOVAR *iovar)
- {
- DEBUG_I (("uart: transmitter started"));
-
- /* clear stop flag */
- iovar->txoff = 0;
-
- /* enable interrupt */
- txint_on (iovar->regs);
- }
-
- /* END start/stop primitives */
- /****************************************************************************/
-
- /****************************************************************************/
- /* BEGIN interrupt handling */
-
- /*
- * pc16550_read(): uart receive buffer full.
- * Holt Zeichen vom UART und schreibt es in den Puffer.
- * XON/XOFF- oder RTS/CTS-Mode wird beachtet.
- *
- * only called from pc16550_int
- */
-
- FASTFN void
- pc16550_read_x (IOVAR *iovar, UART *regs)
- {
- while (regs->lsr & RXDA)
- {
- register uchar data = regs->rbr;
-
- if (data == XOFF)
- {
- /* receiver can't accept more data */
-
- stop_transmitter (iovar);
- }
- else if (data == XON)
- {
- /* receiver ready now */
-
- start_transmitter (iovar);
- }
- else
- {
- DEBUG_I (("rcv: put data %d in buffer", data));
-
- if (!iorec_put (&iovar->input, data))
- {
- DEBUG_I (("rcvint: buffer full!"));
- }
- }
- }
- }
-
- FASTFN void
- pc16550_read_o (IOVAR *iovar, UART *regs)
- {
- while (regs->lsr & RXDA)
- {
- register uchar data = regs->rbr;
-
- DEBUG_I (("rcv: put data %d in buffer", data));
-
- if (!iorec_put (&iovar->input, data))
- {
- DEBUG_I (("rcvint: buffer full!"));
- }
- }
- }
-
- FASTFN void
- pc16550_read (IOVAR *iovar, UART *regs)
- {
- if (iovar->hsk_mode & SHAKE_XON_OFF) pc16550_read_x (iovar, regs);
- else pc16550_read_o (iovar, regs);
-
- if (iovar->hsk_mode == 0 || iovar->rxoff)
- {
- /* no handshake or already off */
- return;
- }
-
- /* in handshake mode test the free space
- */
- if (iorec_used (&iovar->input) > iovar->input.high_water)
- stop_receiver (iovar, regs);
- }
-
- /*
- * pc16550_write():
- *
- * only called from pc16550_int
- */
- FASTFN void
- pc16550_write (IOVAR *iovar, UART *regs)
- {
- register int count = 16;
-
- if (iovar->sendnow)
- {
- /* control byte
- */
-
- DEBUG_I (("pc16550_write: send control %i", iovar->sendnow));
-
- regs->thr = iovar->sendnow;
- iovar->sendnow = 0;
-
- count--;
- }
-
- /* real data
- */
-
- /* is somebody ready to receive data? */
- if (iovar->hsk_mode && iovar->txoff)
- {
- DEBUG_I (("pc16550_write: sender disabled - INT turned off, ier=$%x", regs->ier));
-
- /* disable interrupt */
- txint_off (regs);
- }
- else
- {
- while (count--)
- {
- if (iorec_empty (&iovar->output))
- {
- DEBUG_I (("pc16550_write: buffer empty - INT turned off, ier=$%x", regs->ier));
-
- /* disable interrupt */
- txint_off (regs);
-
- break;
- }
-
- /* send character from buffer */
- regs->thr = iorec_get (&iovar->output);
- }
- }
- }
-
- /*
- * pc16550_ctsint(): CTS-Interruptroutine.
- *
- * only called from pc16550_int
- */
- FASTFN void
- pc16550_ctsint (IOVAR *iovar, uchar msr)
- {
- if (iovar->hsk_mode & SHAKE_RTS_CTS)
- {
- DEBUG_I (("ctsint: (RTS/CTS active)"));
-
- if (msr & CTSI)
- /* CTS is on */
- start_transmitter (iovar);
- else
- /* CTS is off */
- stop_transmitter (iovar);
- }
- }
-
- /*
- * Der eigentliche Interrupthandler. Wird vom Assemblerteil aufgerufen.
- * HACK: Der IOVAR-Zeiger wird in A0 uebergeben!
- */
- static void
- pc16550_int (void)
- {
- IOVAR *iovar;
- UART *regs;
- ushort sr;
- uchar event;
-
- asm volatile
- (
- "move.l %%a0,%0"
- : "=da" (iovar) /* output register */
- : /* input registers */
- : "cc" /* clobbered */
- );
-
- next_uart:
-
- regs = iovar->regs;
- DEBUG_I (("pc16550_int: handling UART at %lx", regs));
-
- sr = spl7 ();
-
- while (!((event = (regs->iir & 0x0f)) & 1))
- {
- /* Int pending */
-
- DEBUG_I (("pc16550_int: event %d ", event));
-
- switch (event)
- {
- case 6: /* Highest priority */
- {
- /* Parity error, framing error, data overrun
- * or break event
- */
- if (regs->lsr & OE)
- pc16550_read (iovar, regs);
- else
- (void) regs->rbr;
-
- break;
- }
- case 4:
- {
- /* Receive Buffer Register (RBR) full, or
- * reception FIFO level equal to or above
- * treshold
- */
- }
- case 12:
- {
- /* At least one character is in the reception
- * FIFO, and no character has been input to or
- * read from the reception FIFO for four
- * character times
- */
- pc16550_read (iovar, regs);
-
- break;
- }
- case 2:
- {
- /* Transmitter Data Register Empty
- */
- pc16550_write (iovar, regs);
-
- break;
- }
- case 0:
- {
- /* Any transition on /CTS, /DSR or /DCD or a low to
- * high transition on /RI
- */
- register uchar msr = regs->msr;
-
- if (msr & DCTS)
- pc16550_ctsint (iovar, msr);
-
- /* (msr & DDSR)
- ; */
-
- /* (msr & TERI)
- ; */
-
- /* (msr & DDCD)
- ; */
-
- DEBUG_I (("pc16550_int: E0: %d", msr));
- break;
- }
- default:
- {
- /* unknown event
- */
-
- (void) regs->lsr;
- (void) regs->msr;
-
- DEBUG_I (("pc16550_int: unknown event, ignored"));
- break;
- }
- }
- }
-
- spl (sr);
-
- iovar = iovar->next;
- if (iovar)
- {
- DEBUG_I (("pc16550_int: continuing on next IOVAR!"));
- goto next_uart;
- }
-
- DEBUG_I (("PC16550_int: exit"));
- }
-
- /* Interrupt-Routinen fuer PC16550 - rufen die eigentlichen C-Routinen auf
- */
- void
- pc16550_intx (void)
- {
- (void) pc16550_int; /* tell the compiler that we need it */
-
- asm volatile
- (
- "_pc16550_int0:
- movem.l %%a0-%%a2/%%d0-%%d2,-(%%sp)
- move.l _intr_iovar,%%a0
- bsr _pc16550_int
- movem.l (%%sp)+,%%a0-%%a2/%%d0-%%d2
- rte"
- : /* output register */
- : /* input registers */
- /* clobbered */
- );
-
- asm volatile
- (
- "_pc16550_int1:
- movem.l %%a0-%%a2/%%d0-%%d2,-(%%sp)
- move.l _intr_iovar+4,%%a0
- bsr _pc16550_int
- movem.l (%%sp)+,%%a0-%%a2/%%d0-%%d2
- rte"
- : /* output register */
- : /* input registers */
- /* clobbered */
- );
-
- asm volatile
- (
- "_pc16550_int2:
- movem.l %%a0-%%a2/%%d0-%%d2,-(%%sp)
- move.l _intr_iovar+8,%%a0
- bsr _pc16550_int
- movem.l (%%sp)+,%%a0-%%a2/%%d0-%%d2
- rte"
- : /* output register */
- : /* input registers */
- /* clobbered */
- );
-
- asm volatile
- (
- "_pc16550_int3:
- movem.l %%a0-%%a2/%%d0-%%d2,-(%%sp)
- move.l _intr_iovar+12,%%a0
- bsr _pc16550_int
- movem.l (%%sp)+,%%a0-%%a2/%%d0-%%d2
- rte"
- : /* output register */
- : /* input registers */
- /* clobbered */
- );
-
- asm volatile
- (
- "_pc16550_int4:
- movem.l %%a0-%%a2/%%d0-%%d2,-(%%sp)
- move.l _intr_iovar+16,%%a0
- bsr _pc16550_int
- movem.l (%%sp)+,%%a0-%%a2/%%d0-%%d2
- rte"
- : /* output register */
- : /* input registers */
- /* clobbered */
- );
- }
-
- /* END interrupt handling */
- /****************************************************************************/
-
- /****************************************************************************/
- /* BEGIN */
-
- static void _cdecl
- check_select (void)
- {
- int flag = 0;
- int i;
-
- for (i = 0; IOVARS (i); i++)
- {
- IOVAR *iovar = IOVARS (i);
-
- if (iovar->tty.rsel)
- {
- if (!iorec_empty (&iovar->input))
- wakeselect (iovar->tty.rsel);
- else
- flag = 1;
- }
-
- if (iovar->tty.wsel)
- {
- if (iorec_free (&iovar->output))
- wakeselect (iovar->tty.wsel);
- else
- flag = 1;
- }
- }
-
- if (flag)
- addroottimeout (1000L, check_select, 0);
- }
-
- /* END */
- /****************************************************************************/
-
- /****************************************************************************/
- /* BEGIN device driver routines */
-
- static long _cdecl
- uart_open (FILEPTR *f)
- {
- ushort dev = f->fc.aux;
- IOVAR *iovar;
-
- DEBUG (("uart_open [%i]: enter (%lx)", f->fc.aux, f->flags));
-
- if (dev > IOVAR_MAX)
- return EACCDN;
-
- iovar = IOVARS (dev);
-
- if (iovar->open && denyshare (iovar->open, f))
- {
- DEBUG (("uart_open: file sharing denied"));
- return EACCDN;
- }
-
- f->pos = 0;
- f->next = iovar->open;
- iovar->open = f;
-
- if (dev >= IOVAR_TTY_OFFSET)
- f->flags |= O_TTY;
-
- return E_OK;
- }
-
- static long _cdecl
- uart_writeb (FILEPTR *f, const char *buf, long bytes)
- {
- IOVAR *iovar = IOVARS (f->fc.aux);
- IOREC *iorec = &iovar->output;
- long done = 0;
-
- DEBUG (("uart_writeb [%i]: enter (%lx, %ld)", f->fc.aux, buf, bytes));
- for (;;)
- {
- /* copy as much as possible */
- while ((bytes > 0) && iorec_put (iorec, *buf))
- {
- DEBUG (("%x - %c", (int) *buf, *buf));
-
- buf++; done++;
- bytes--;
- }
-
- /* start transfer - interrupt controlled */
- start_transmitter (iovar);
-
- if (f->flags & O_NDELAY)
- {
- if (!done)
- done = EWOULDBLOCK;
-
- break;
- }
-
- if (!bytes)
- break;
-
- /* sleep until there is enough room in the buffer
- * to continue
- */
- while (iorec_used (iorec) > iorec->high_water)
- sleep (READY_Q, 0L);
- }
-
- if (done > 0)
- {
- struct bios_file *b = (struct bios_file *) f->fc.index;
-
- b->xattr.atime = timestamp;
- b->xattr.adate = datestamp;
- }
-
- DEBUG (("uart_writeb: leave (%ld)", done));
- return done;
- }
-
- static long _cdecl
- uart_readb (FILEPTR *f, char *buf, long bytes)
- {
- IOVAR *iovar = IOVARS (f->fc.aux);
- IOREC *iorec = &iovar->input;
- long done = 0;
-
- DEBUG (("uart_readb [%i]: enter (%lx, %ld)", f->fc.aux, buf, bytes));
- for (;;)
- {
- /* copy as much as possible */
- while ((bytes > 0) && !iorec_empty (iorec))
- {
- *buf = iorec_get (iorec);
- DEBUG (("%x - %c", (int) *buf, *buf));
-
- buf++; done++;
- bytes--;
- }
-
- if (iorec_used (iorec) < iorec->low_water)
- /* start receiver */
- start_receiver (iovar, iovar->regs);
-
- if (f->flags & O_NDELAY)
- {
- if (!done)
- done = EWOULDBLOCK;
-
- break;
- }
-
- if (!bytes)
- break;
-
- /* sleep until we received enough data or the buffer
- * become to full
- */
- {
- long i;
-
- i = iorec_used (iorec);
- while ((i < bytes) && (i < iorec->high_water))
- {
- sleep (READY_Q, 0L);
- i = iorec_used (iorec);
- }
- }
- }
-
- if (done > 0)
- {
- struct bios_file *b = (struct bios_file *) f->fc.index;
-
- b->xattr.atime = timestamp;
- b->xattr.adate = datestamp;
- }
-
- DEBUG (("uart_readb: leave (%ld)", done));
- return done;
- }
-
- /*
- * Note: when a BIOS device is a terminal (i.e. has the O_TTY flag
- * set), bios_read and bios_write will only ever be called indirectly, via
- * tty_read and tty_write. That's why we can afford to play a bit fast and
- * loose with the pointers ("buf" is really going to point to a long) and
- * why we know that "bytes" is divisible by 4.
- */
-
- static long _cdecl
- uart_twrite (FILEPTR *f, const char *buf, long bytes)
- {
- IOVAR *iovar = IOVARS (f->fc.aux);
- IOREC *iorec = &iovar->output;
- long done = 0;
- const long *r = (const long *) buf;
-
- DEBUG (("uart_twrite [%i]: enter (%lx, %ld)", f->fc.aux, buf, bytes));
- for (;;)
- {
- /* copy as much as possible */
- while ((bytes > 0) && iorec_put (iorec, (char) *r))
- {
- DEBUG (("%lx - %c", *r, (char) *r));
-
- r++; done += 4;
- bytes -= 4;
- }
-
- /* start transfer - interrupt controlled */
- start_transmitter (iovar);
-
- if (f->flags & O_NDELAY)
- {
- if (!done)
- done = EWOULDBLOCK;
-
- break;
- }
-
- if (!bytes)
- break;
-
- /* sleep until there is enough room in the buffer
- * to continue
- */
- while (iorec_used (iorec) > iorec->high_water)
- sleep (READY_Q, 0L);
- }
-
- if (done > 0)
- {
- struct bios_file *b = (struct bios_file *) f->fc.index;
-
- b->xattr.atime = timestamp;
- b->xattr.adate = datestamp;
- }
-
- DEBUG (("uart_twrite: leave (%ld)", done));
- return done;
- }
-
- static long _cdecl
- uart_tread (FILEPTR *f, char *buf, long bytes)
- {
- IOVAR *iovar = IOVARS (f->fc.aux);
- IOREC *iorec = &iovar->input;
- long done = 0;
- long *r = (long *) buf;
-
- DEBUG (("uart_tread [%i]: enter (%lx, %ld)", f->fc.aux, buf, bytes));
- for (;;)
- {
- /* copy as much as possible */
- while ((bytes > 0) && !iorec_empty (iorec))
- {
- *r = (long) iorec_get (iorec);
- DEBUG (("%lx - %c", *r, (char) *r));
-
- r++; done += 4;
- bytes -= 4;
- }
-
- if (iorec_used (iorec) < iorec->low_water)
- /* start receiver */
- start_receiver (iovar, iovar->regs);
-
- if (f->flags & O_NDELAY)
- {
- if (!done)
- done = EWOULDBLOCK;
-
- break;
- }
-
- if (!bytes)
- break;
-
- /* sleep until we received enough data or the buffer
- * become to full
- */
- {
- long i;
-
- i = iorec_used (iorec);
- while ((i < bytes) && (i < iorec->high_water))
- {
- sleep (READY_Q, 0L);
- i = iorec_used (iorec);
- }
- }
- }
-
- if (done > 0)
- {
- struct bios_file *b = (struct bios_file *) f->fc.index;
-
- b->xattr.atime = timestamp;
- b->xattr.adate = datestamp;
- }
-
- DEBUG (("uart_tread: leave (%ld)", done));
- return done;
- }
-
- static long _cdecl
- uart_lseek (FILEPTR *f, long where, int whence)
- {
- DEBUG (("uart_lseek [%i]: enter (%ld, %d)", f->fc.aux, where, whence));
-
- /* (terminal) devices are always at position 0 */
- return 0;
- }
-
- static long _cdecl
- uart_ioctl (FILEPTR *f, int mode, void *buf)
- {
- IOVAR *iovar = IOVARS (f->fc.aux);
- long r = E_OK;
-
- DEBUG (("uart_ioctl [%i]: (%x, (%c %i), %lx)", f->fc.aux, mode, (char) (mode >> 8), (mode & 0xff), buf));
-
- switch (mode)
- {
- case FIONREAD:
- {
- *(long *) buf = iorec_used (&iovar->input);
- break;
- }
- case FIONWRITE:
- {
- long bytes;
-
- bytes = iorec_free (&iovar->output);
- bytes -= 2;
- if (bytes < 0)
- bytes = 0;
-
- *(long *) buf = bytes;
- break;
- }
- case FIOEXCEPT: /* anywhere documented? */
- {
- *(long *) buf = 0;
- break;
- }
- case TIOCFLUSH:
- {
- int flushtype;
-
- /* HSMODEM put the value itself in arg
- * MiNT use arg as a pointer to the value
- *
- * if opened as terminal we assume MiNT convention
- * otherwise HSMODEM convention
- */
- if (f->fc.aux >= IOVAR_TTY_OFFSET)
- flushtype = *(int *) buf;
- else
- flushtype = (int) ((long) buf);
-
- if (flushtype <= 0)
- {
- r = EINVFN;
- break;
- }
-
- if (flushtype & 1)
- {
- IOREC *iorec = &(iovar->input);
- ushort sr;
-
- sr = spl7 ();
- iorec->head = iorec->tail = 0;
- spl (sr);
- }
-
- if (flushtype & 2)
- {
- IOREC *iorec = &(iovar->output);
- ushort sr;
-
- sr = spl7 ();
- iorec->head = iorec->tail = 0;
- spl (sr);
- }
-
- break;
- }
- case TIOCSTOP: /* HSMODEM */
- {
- if (iovar->hsk_mode)
- stop_receiver (iovar, iovar->regs);
-
- break;
- }
- case TIOCSTART: /* HSMODEM */
- {
- start_receiver (iovar, iovar->regs);
- break;
- }
- case TIOCIBAUD:
- case TIOCOBAUD:
- {
- long speed = *(long *) buf;
-
- DEBUG (("uart_ioctl(TIOCIBAUD) to %li", speed));
-
- if (speed == -1)
- {
- /* current baudrate */
-
- *(long *) buf = iovar->baudrate;
- break;
- }
- else if (speed == 0)
- {
- /* clear dtr */
-
- dtr_off (iovar->regs);
- break;
- }
- else
- {
- /* set baudrate to speed, enable dtr */
-
- static const long table [] =
- {
- 300, 600,
- 1200, 1800, 2400, 3600, 4800, 9600,
- 14400, 19200, 28800, 38400, 57600,
- 115200, 230400, 460800,
- 0
- };
-
- long baudrate;
- long div;
-
- div = iovar->baudbase / speed;
-
- if (div < 1)
- div = 1;
- if (div > 65534)
- div = 65534;
-
- baudrate = iovar->baudbase / div;
-
- if ((baudrate != speed) || (iovar->baudbase % div))
- {
- # if 0
- if (baudrate > speed)
- {
- div++;
- baudrate = iovar->baudbase / div;
- }
-
- if (baudrate < 9600)
- baudrate = 9600;
- # else
- if (speed > iovar->baudbase)
- {
- baudrate = iovar->baudbase;
- }
- else
- {
- int i;
-
- baudrate = table [0];
-
- for (i = 0; table [i] != 0; i++)
- {
- if (speed > table [i] && speed <= iovar->baudbase)
- baudrate = table [i];
- }
- }
- # endif
-
- *(long *) buf = baudrate;
- DEBUG (("uart_ioctl(TIOCIBAUD) error -> %li", baudrate));
-
- r = ERANGE;
- break;
- }
-
- if (baudrate != iovar->baudrate)
- {
- UART *regs = iovar->regs;
- ushort sr;
- uchar old_ier;
-
- sr = spl7 ();
-
- /* save old interrupts */
- old_ier = regs->ier;
-
- /* and lock */
- regs->ier = 0;
-
- old_ier |= (LS_IE | MS_IE);
-
- /* set new daudrate
- */
- iovar->baudrate = baudrate;
- div = iovar->baudbase / baudrate;
-
- regs->lcr |= BNKSE;
- regs->dll = (div) & 0xFF;
- regs->dlm = (div >> 8) & 0xFF;
- regs->lcr &= ~BNKSE;
-
- /* Reset FIFOs */
- regs->fcr = FIFO_EN | RXFR | TXFR;
- /* Enable FIFOs, set Rcv Threshold */
- regs->fcr = FIFO_EN | RXFTH_8;
-
- /* freeup new interrupts */
- regs->ier = old_ier;
- regs->mcr |= (GI_EN | RTSO);
-
- spl (sr);
- }
-
- /* always enable dtr */
- dtr_on (iovar->regs);
- }
-
- break;
- }
- case TIOCCBRK:
- {
- brk_off (iovar->regs);
- break;
- }
- case TIOCSBRK:
- {
- brk_on (iovar->regs);
- break;
- }
- case TIOCGFLAGS:
- {
- ushort flags = 0;
- uchar lcr = iovar->regs->lcr;
-
- switch (lcr & WLS)
- {
- case 0: flags |= TF_5BIT; break;
- case 1: flags |= TF_6BIT; break;
- case 2: flags |= TF_7BIT; break;
- case 3: flags |= TF_8BIT; break;
- }
-
- if (lcr & STB) flags |= TF_2STOP;
- else flags |= TF_1STOP;
-
- if (lcr & PEN)
- {
- if (lcr & EPS) flags |= T_EVENP;
- else flags |= T_ODDP;
- }
-
- if (iovar->hsk_mode & SHAKE_XON_OFF)
- flags |= T_TANDEM;
-
- if (iovar->hsk_mode & SHAKE_RTS_CTS)
- flags |= T_RTSCTS;
-
- *(ushort *) buf = flags;
- break;
- }
- case TIOCSFLAGS:
- {
- ushort flags = *(ushort *) buf;
- ushort lcr = iovar->regs->lcr;
-
- lcr &= ~WLS;
- switch (flags & TF_CHARBITS)
- {
- case TF_5BIT: lcr |= 0; break;
- case TF_6BIT: lcr |= 1; break;
- case TF_7BIT: lcr |= 2; break;
- case TF_8BIT: lcr |= 3; break;
- default: goto err_erange; break;
- }
-
- switch (flags & TF_STOPBITS)
- {
- case TF_1STOP: lcr &= ~STB; break;
- case TF_15STOP: goto err_erange; break;
- case TF_2STOP: lcr |= STB; break;
- default: goto err_erange; break;
- }
-
- if (flags & (T_EVENP | T_ODDP))
- {
- if ((flags & (T_EVENP | T_ODDP)) == (T_EVENP | T_ODDP))
- goto err_erange;
-
- /* enable parity */
- lcr |= PEN;
-
- /* set even/odd parity */
- if (flags & T_EVENP) lcr |= EPS;
- else lcr &= ~EPS;
- }
- else
- {
- /* disable parity */
- lcr &= ~PEN;
-
- /* even/odd bit ignored in this case */
- }
-
- if (flags & T_TANDEM) iovar->hsk_mode |= SHAKE_XON_OFF;
- else iovar->hsk_mode &= ~SHAKE_XON_OFF;
-
- if (flags & T_RTSCTS) iovar->hsk_mode |= SHAKE_RTS_CTS;
- else iovar->hsk_mode &= ~SHAKE_RTS_CTS;
-
- /* setup in register */
- iovar->regs->lcr = lcr;
-
- break;
- }
- case TIONOTSEND:
- case TIOCOUTQ:
- {
- *(long *) buf = iorec_used (&iovar->output);
- break;
- }
- case TIOCSFLAGSB: /* anywhere documented? */
- {
- r = EINVFN;
- break;
- }
- case TIOCGVMIN:
- {
- struct tty *tty = (struct tty *) f->devinfo;
- ushort *v = buf;
-
- v [0] = tty->vmin;
- v [1] = tty->vtime;
-
- break;
- }
- case TIOCSVMIN:
- {
- struct tty *tty = (struct tty *) f->devinfo;
- ushort *v = buf;
-
- if (v [0] > iovar->input.size / 2)
- v [0] = iovar->input.size / 2;
-
- tty->vmin = v [0];
- tty->vtime = v [1];
-
- /* t->vticks = 0; */
-
- break;
- }
- case TIOCWONLINE:
- {
- # if 0
- struct tty *tty = (struct tty *) f->devinfo;
-
- while (tty->state & TS_BLIND)
- sleep (IO_Q, (long) &tty->state);
- # else
- r = EINVFN;
- # endif
- break;
- }
- case TIOCBUFFER: /* HSMODEM special */
- {
- long *ptr = (long *) buf;
-
- /* input buffer size */
- if (*ptr == -1) *ptr = iovar->input.size;
- else *ptr = -1;
-
- ptr++;
-
- /* input low watermark */
- if (*ptr == -1) *ptr = iovar->input.low_water;
- else *ptr = -1;
-
- ptr++;
-
- /* input high watermark */
- if (*ptr == -1) *ptr = iovar->input.high_water;
- else *ptr = -1;
-
- ptr++;
-
- /* output buffer size */
- if (*ptr == -1) *ptr = iovar->output.size;
- else *ptr = -1;
-
- break;
- }
- case TIOCCTLMAP: /* HSMODEM */
- {
- long *ptr = (long *) buf;
-
- ptr [0] = 0
- /* | TIOCMH_LE */
- | TIOCMH_DTR
- | TIOCMH_RTS
- | TIOCMH_CTS
- | TIOCMH_CD
- | TIOCMH_RI
- | TIOCMH_DSR
- /* | TIOCMH_LEI */
- /* | TIOCMH_TXD */
- /* | TIOCMH_RXD */
- | TIOCMH_BRK
- /* | TIOCMH_TER */
- /* | TIOCMH_RER */
- | TIOCMH_TBE
- | TIOCMH_RBF
- ;
-
- ptr [1] = 0; /* will be never supported */
- ptr [2] = 0; /* will be never supported */
- ptr [3] = 0; /* reserved */
- ptr [4] = 0; /* reserved */
- ptr [5] = 0; /* reserved */
-
- break;
- }
- case TIOCCTLGET: /* HSMODEM */
- {
- /* register long mask = *(long *) buf; */
- register long val = 0;
- register char reg;
-
- /* TIOCMH_LE */
-
- /* mcr */
- reg = iovar->regs->mcr;
- if (reg & DTRO) val |= TIOCMH_DTR;
- if (reg & RTSO) val |= TIOCMH_RTS;
-
- /* msr */
- reg = iovar->regs->msr;
- if (reg & CTSI) val |= TIOCMH_CTS;
- if (reg & RII ) val |= TIOCMH_RI;
- if (reg & DCDI) val |= TIOCMH_CD;
- if (reg & DSRI) val |= TIOCMH_DSR;
-
- /* TIOCMH_LEI */
- /* TIOCMH_TXD */
- /* TIOCMH_RXD */
-
- /* lsr */
- reg = iovar->regs->lsr;
- if (reg & BRK ) val |= TIOCMH_BRK;
- /* TIOCMH_TER */
- /* TIOCMH_RER */
- if (reg & TXDE) val |= TIOCMH_TBE;
- if (reg & RXDA) val |= TIOCMH_RBF;
-
- *(long *) buf = val;
- break;
- }
- case TIOCCTLSET: /* HSMODEM */
- {
- long *arg = (long *) buf;
-
- register long mask = *arg++;
- register long val = *arg;
-
- if (mask & (TIOCMH_DTR | TIOCMH_RTS))
- {
- /* mcr */
- register char reg_val = iovar->regs->mcr;
-
- if (mask & TIOCMH_DTR)
- {
- if (val & TIOCMH_DTR) reg_val |= DTRO;
- else reg_val &= ~DTRO;
- }
-
- if (mask & TIOCMH_RTS)
- {
- if (val & TIOCMH_RTS) reg_val |= RTSO;
- else reg_val &= ~RTSO;
- }
-
- iovar->regs->mcr = reg_val;
- }
-
- break;
- }
- case TIOCERROR: /* HSMODEM */
- {
- r = ERANGE;
- break;
- }
- case TIOCCDTR:
- {
- dtr_off (iovar->regs);
- break;
- }
- case TIOCSDTR:
- {
- dtr_on (iovar->regs);
- break;
- }
-
- case F_SETLK:
- case F_SETLKW:
- {
- struct flock *lck = (struct flock *) buf;
- int cpid = p_getpid ();
-
- while (iovar->lockpid && iovar->lockpid != cpid)
- {
- if (mode == F_SETLKW && lck->l_type != F_UNLCK)
- sleep (IO_Q, (long) iovar);
- else
- return ELOCKED;
- }
-
- if (lck->l_type == F_UNLCK)
- {
- if (!(f->flags & O_LOCK))
- {
- DEBUG (("uart_ioctl: wrong file descriptor for UNLCK"));
- return ENSLOCK;
- }
-
- if (iovar->lockpid != cpid)
- return ENSLOCK;
-
- iovar->lockpid = 0;
- f->flags &= ~O_LOCK;
-
- /* wake anyone waiting for this lock */
- wake (IO_Q, (long) iovar);
- }
- else
- {
- iovar->lockpid = cpid;
- f->flags |= O_LOCK;
- }
-
- break;
- }
- case F_GETLK:
- {
- struct flock *lck = (struct flock *) buf;
-
- if (iovar->lockpid)
- {
- lck->l_type = F_WRLCK;
- lck->l_start = lck->l_len = 0;
- lck->l_pid = iovar->lockpid;
- }
- else
- {
- lck->l_type = F_UNLCK;
- }
-
- break;
- }
-
- default:
- {
- /* Fcntl will automatically call tty_ioctl to handle
- * terminal calls that we didn't deal with
- */
- r = EINVFN;
- break;
- }
- }
-
- goto out;
-
- err_erange:
- r = ERANGE;
-
- out:
- DEBUG (("uart_ioctl: return %li", r));
- return r;
- }
-
- static long _cdecl
- uart_datime (FILEPTR *f, ushort *timeptr, int rwflag)
- {
- DEBUG (("uart_datime [%i]: enter (%i)", f->fc.aux, rwflag));
-
- if (rwflag)
- return EACCDN;
-
- *timeptr++ = timestamp;
- *timeptr = datestamp;
-
- return E_OK;
- }
-
- static long _cdecl
- uart_close (FILEPTR *f, int pid)
- {
- IOVAR *iovar = IOVARS (f->fc.aux);
-
- DEBUG (("uart_close [%i]: enter", f->fc.aux));
-
- if (iovar->lockpid == pid)
- {
- /* wake anyone waiting for this lock */
- wake (IO_Q, (long) iovar);
- }
-
- if (f->links <= 0)
- {
- register FILEPTR **temp;
- register long flag = 1;
-
- /* remove the FILEPTR from the linked list */
- temp = &iovar->open;
- while (*temp)
- {
- if (*temp == f)
- {
- *temp = f->next;
- f->next = NULL;
- flag = 0;
-
- break;
- }
-
- temp = &(*temp)->next;
- }
-
- if (flag)
- {
- ALERT (("uart_close: remove open FILEPTR fail!", f->fc.aux));
- }
- }
-
- DEBUG (("uart_close: leave ok"));
- return E_OK;
- }
-
- static long _cdecl
- uart_select (FILEPTR *f, long proc, int mode)
- {
- IOVAR *iovar = IOVARS (f->fc.aux);
- struct tty *tty = (struct tty *) f->devinfo;
-
- DEBUG (("uart_select [%i]: enter (%li, %i, %lx)", f->fc.aux, proc, mode, tty));
-
- if (mode == O_RDONLY)
- {
- if (!iorec_empty (&iovar->input))
- {
- TRACE (("uart_select: data present for device %lx", iovar));
- return 1;
- }
-
- if (tty)
- {
- /* avoid collisions with other processes
- */
-
- if (tty->rsel)
- /* collision */
- return 2;
-
- tty->rsel = proc;
- }
-
- return 0;
- }
- else if (mode == O_WRONLY)
- {
- if ((!tty || !(tty->state & (TS_BLIND | TS_HOLD))) && !iorec_empty (&iovar->output))
- {
- TRACE (("uart_select: ready to output on %lx", iovar));
- return 1;
- }
-
- if (tty)
- {
- /* avoid collisions with other processes
- */
-
- if (tty->wsel)
- /* collision */
- return 2;
-
- tty->wsel = proc;
- }
-
- return 0;
- }
-
- /* default -- we don't know this mode, return 0 */
- return 0;
- }
-
- static void _cdecl
- uart_unselect (FILEPTR *f, long proc, int mode)
- {
- struct tty *tty = (struct tty *) f->devinfo;
-
- DEBUG (("uart_unselect [%i]: enter (%li, %i, %lx)", f->fc.aux, proc, mode, tty));
-
- if (tty)
- {
- if (mode == O_RDONLY && tty->rsel == proc)
- tty->rsel = 0;
- else if (mode == O_WRONLY && tty->wsel == proc)
- tty->wsel = 0;
- }
- }
-
- /* END device driver routines */
- /****************************************************************************/
-