lwip-contrib-mac/ports/mac/sio.c
Eric Pooch 9a5b3d8918 Support for Macintosh System 1.1 on 128K Macintosh
This port of lwip adds support for 128K Macintosh
with the original 64K ROMs running System 1.1 or
later.
Modem port must be connected to a server running pppd
at 9600 baud.
2018-03-12 21:40:46 -07:00

401 lines
10 KiB
C

/*
* Copyright (c) 2001-2003 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
*/
#include "lwip/opt.h"
#include "lwip/sys.h"
#include "lwip/sio.h"
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <Errors.h>
#include <Files.h>
#include <Devices.h>
#include <Serial.h>
/**
* SIO_DEBUG: Enable debugging for SIO.
*/
#ifndef SIO_DEBUG
#define SIO_DEBUG LWIP_DBG_OFF
#endif
/**
* MACOS_INPUT_BUFF_SIZE: Set the ppp input buffer.
* 64 or less uses driver's default 64 byte buffer.
*/
#ifndef MACOS_SIO_BUFF_SIZE
#define MACOS_SIO_BUFF_SIZE 64
#endif
/* sio_fd_t is supposed to be a void pointer, so we need to do some casting back. */
#define PORT_NUM(sd) (*(short *)sd)
#define IN_REF(sd) (int)(PORT_NUM(sd) + 3) * -2
#define OUT_REF(sd) (int)IN_REF(sd)-1
u8_t sio_setup(sio_fd_t sd);
OSErr ROMSDOpen(SPortSel whichPort);
char *sio_input_buffer;
#if NO_SYS==0
static unsigned char sio_abort = 0xFF;
#endif
#pragma segment LWUPDN
u8_t sio_setup(sio_fd_t fd)
{
OSErr error;
unsigned short baud;
short databits;
short stopbits;
short parity;
short config;
SerShk shake;
/* Set the new data */
baud = baud19200; /* 19200 */
parity = noParity; /* None*/
databits = data8; /* 8 */
stopbits = stop10; /* 1 */
/* do not use flow control */
shake.fXOn = 0;
shake.fCTS = 0;
shake.xOn = 0;
shake.xOff = 0;
shake.errs = 0;
shake.evts = 0;
shake.fInX = 0;
shake.fDTR = 0;
config = baud + parity + databits + stopbits;
//config = (baud | parity | databits | stopbits);
LWIP_DEBUGF(SIO_DEBUG, ("sio_setup(%d, %d)\n", IN_REF(fd), OUT_REF(fd))) ;
if (error = SerReset(IN_REF(fd), config))
LWIP_DEBUGF(SIO_DEBUG | LWIP_DBG_LEVEL_WARNING, ("sio_setup(%d) can't configure serial port due to \'SerReset\' error:%d. Continuing...\n", IN_REF(fd), error)) ;
if (error = SerHShake(IN_REF(fd), &shake))
LWIP_DEBUGF(SIO_DEBUG | LWIP_DBG_LEVEL_WARNING, ("sio_setup(%d) can't disable serial handshake due to \'SerHShake\' error:%d. Continuing...\n", IN_REF(fd), error)) ;
if (error = SerReset(OUT_REF(fd), config))
LWIP_DEBUGF(SIO_DEBUG | LWIP_DBG_LEVEL_WARNING, ("sio_setup(%d) can't configure serial port due to \'SerReset\' error:%d. Continuing...\n", OUT_REF(fd), error)) ;
if (error = SerHShake(OUT_REF(fd), &shake))
LWIP_DEBUGF(SIO_DEBUG | LWIP_DBG_LEVEL_WARNING, ("sio_setup(%d) can't disable serial handshake due to \'SerHShake\' error:%d. Continuing...\n", OUT_REF(fd), error)) ;
return 1;
}
OSErr ROMSDOpen(SPortSel whichPort)
{
OSErr error = fnfErr;
short inRef, outRef;
char *inDriver;
char *outDriver;
switch (whichPort)
{
case sPortA:
inDriver = ".AIn";
outDriver = ".AOut";
break;
case sPortB:
inDriver = ".BIn";
outDriver = ".BOut";
break;
default:
return error;
break;
}
error = opendriver(outDriver, &outRef);
LWIP_DEBUGF(SIO_DEBUG, ("ROMSDOpen(%d) 'opendriver(%s, %d)\n", whichPort, outDriver, outRef )) ;
if (error == noErr)
{
error = opendriver(inDriver, &inRef);
LWIP_DEBUGF(SIO_DEBUG, ("ROMSDOpen(%d) 'opendriver(%s, %d)\n", whichPort, inDriver, inRef )) ;
}
LWIP_DEBUGF(SIO_DEBUG, ("ROMSDOpen(%d) will return: %d\n", whichPort, error));
return error;
}
/**
* Opens a serial device for communication.
*
* @param devnum device number
* @return handle to serial device if successful, NULL otherwise
*/
sio_fd_t sio_open(u8_t devnum)
{
OSErr error = fnfErr;
/* These are the the serial port numbers that 'sio_fd_t sd' points to. */
static const short modemPort = sPortA;
static const short printerPort = sPortB;
/* The serial port device is just a pointer to one of the constant port numbers. */
sio_fd_t sd;
/* Keep track of the port name for debugging and warnings. */
char* port_name;
/* We don't have devices, but sPortA (0) is Modem and sPortB (1) is Printer. */
switch (devnum)
{
case 'P' :
case 'p' :
case 'b' :
case 'B' :
case sPortB :
port_name = "Printer";
sd = (sio_fd_t)&printerPort;
error = ROMSDOpen(sPortB);
break;
case 'M' :
case 'm' :
case 'a' :
case 'A' :
case sPortA :
default:
port_name = "Modem";
sd = (sio_fd_t)&modemPort;
error = ROMSDOpen(sPortA);
/* PPP was overflowing the input buffer, so make it bigger.*/
if (MACOS_SIO_BUFF_SIZE > 64 && sio_input_buffer == NULL)
{
sio_input_buffer = (char *)malloc(MACOS_SIO_BUFF_SIZE);
LWIP_ASSERT("sio_open() can't allocate memory", sio_input_buffer != NULL);
}
if ( error == noErr && sio_input_buffer)
SerSetBuf(IN_REF(sd), sio_input_buffer, MACOS_SIO_BUFF_SIZE);
break;
}
switch (error)
{
case (int)noErr: //0
LWIP_DEBUGF(SIO_TRACE, ("Serial Port successfully opened.\n", devnum));
break;
case (int)badUnitErr: //-21
LWIP_ERROR("Bad Reference Number for Serial Port.\n", (error == noErr ), return NULL;);
break;
case (int)dInstErr: //-26
LWIP_ERROR("Couldn't Find Serial Driver in Resource File.\n", (error == noErr ), return NULL;);
break;
case (int)openErr: //-23
LWIP_ERROR("Driver can't perform the requested reading or writing.\n", (error == noErr ), return NULL;);
break;
case (int)unitEmptyErr: //-22
LWIP_ERROR("Bad Reference Number for Serial Port.\n", (error == noErr ), return NULL;);
break;
case (int)fnfErr: //-43
LWIP_ERROR(("Serial Port Not Found.\n"), (error == noErr ), return NULL;);
break;
default:
//printf("%d", (int)error);
LWIP_ERROR("Unknown Error opening Serial Port.\n", (error == noErr ), return NULL;);
break;
}
sio_setup(sd);
LWIP_DEBUGF(SIO_DEBUG, ("%s Port Successfully Opened.\n", (PORT_NUM(sd) == (int)sPortA)? "Modem":"Printer"));
return sd;
}
/**
* Closes a serial device.
*
* @param fd device
*/
void
sio_close(sio_fd_t fd)
{
if (PORT_NUM(fd) == (int)sPortA && sio_input_buffer)
SerSetBuf(IN_REF(fd), sio_input_buffer, 0);
/* Don't Close the ROM Serial Driver */
}
/**
* Sends a single character to the serial device.
*
* @param c character to send
* @param fd serial device handle
*
* @note This function will block until the character can be sent.
*/
#pragma segment LWPPP
void sio_send(u8_t c, sio_fd_t fd)
{
OSErr error;
long count = 1;
error = FSWrite(OUT_REF(fd), &count, &(char)c);
if (error)
LWIP_DEBUGF(SIO_DEBUG | LWIP_DBG_LEVEL_WARNING, ("sio_send(%c, %d) failed due to \'FSWrite\' error: %d.\n", c, PORT_NUM(fd), error));
return;
}
/**
* Receives a single character from the serial device.
*
* @param fd serial device handle
*
* @note This function will block until a character is received. The blocking
* can be cancelled by calling sio_read_abort().
*/
#if NO_SYS==0
u8_t sio_recv(sio_fd_t fd)
{
static unsigned char cbuff;
sio_read(fd, &(char)cbuff, 1);
return cbuff;
}
#endif
/**
* Reads from the serial device.
*
* @param fd serial device handle
* @param data pointer to data buffer for receiving
* @param len maximum length (in bytes) of data to receive
* @return number of bytes actually received - may be 0 if aborted by sio_read_abort
*
* @note If NO_SYS is > 0, this function will block until data can be received.
* The blocking can be cancelled by calling sio_read_abort().
*/
u32_t sio_read(sio_fd_t fd, u8_t* data, u32_t len)
{
long count = 0;
#if NO_SYS==0
while (sio_abort != IN_REF(fd) && count < len)
#endif
{
count = sio_tryread(fd, data, len);
}
#if NO_SYS==0
if (sio_abort == IN_REF(fd))
sio_abort = 0xFF;
#endif
return count;
}
/**
* Non-Blocking Read from the serial device.
*
* @param fd serial device handle
* @param data pointer to data buffer for receiving
* @param len maximum length (in bytes) of data to receive
* @return number of bytes actually received - may be 0
*
*/
u32_t sio_tryread(sio_fd_t fd, u8_t* data, u32_t len)
{
OSErr error;
long count = 0;
(void)SerGetBuf(IN_REF(fd), &count);
if (count)
{
/* only get up to the length asked for. */
if (count > len) count = (long)len;
if ((error = FSRead(IN_REF(fd), &count, (char *)data)))
LWIP_DEBUGF(SIO_DEBUG | LWIP_DBG_LEVEL_WARNING, ("sio_read(%d, %d) failed due to \'FSRead\' error: %d.\n", IN_REF(fd), len, error));
}
return count;
}
/**
* Writes to the serial device.
*
* @param fd serial device handle
* @param data pointer to data to send
* @param len length (in bytes) of data to send
* @return number of bytes actually sent
*
* @note This function will block until all data can be sent.
*/
u32_t sio_write(sio_fd_t fd, u8_t* data, u32_t len)
{
OSErr error;
long count = (long)len;
error = FSWrite(OUT_REF(fd), &count, (char *)data);
// The ppp module will log the error for us.
if (error)
return error;
return len;
}
#if NO_SYS==0
/**
* Aborts a blocking sio_read() call.
*
* @param fd serial device handle
*/
void sio_read_abort(sio_fd_t fd)
{
LWIP_DEBUGF(SIO_DEBUG, ("sio_read_abort(%d)\n", IN_REF(fd) ));
sio_abort = IN_REF(fd);
return;
}
#endif