/*
* pc300_tty.c Cyclades-PC300(tm) TTY Driver.
*
* Author: Regina Kodato <reginak@cyclades.com>
*
* Copyright: (c) 1999-2002 Cyclades Corp.
*
* 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 of the License, or (at your option) any later version.
*
* $Log: pc300_tty.c,v $
* Revision 3.7 2002/03/07 14:17:09 henrique
* License data fixed
*
* Revision 3.6 2001/12/10 12:29:42 regina
* Fix the MLPPP bug
*
* Revision 3.5 2001/10/31 11:20:05 regina
* automatic pppd starts
*
* Revision 3.4 2001/08/06 12:01:51 regina
* problem in DSR_DE bit
*
* Revision 3.3 2001/07/26 22:58:41 regina
* update EDA value
*
* Revision 3.2 2001/07/12 13:11:20 regina
* bug fix - DCD-OFF in pc300 tty driver
*
* DMA transmission bug fix
*
* Revision 3.1 2001/06/22 13:13:02 regina
* MLPPP implementation
*
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
#include <linux/if.h>
#include <linux/skbuff.h>
/* TTY includes */
#include <linux/tty.h>
#include <linux/tty_flip.h>
#include <linux/serial.h>
#include <asm/io.h>
#include <asm/uaccess.h>
#include "pc300.h"
/* defines and macros */
/* TTY Global definitions */
#define CPC_TTY_NPORTS 8 /* maximum number of the sync tty connections */
#define CPC_TTY_MAJOR CYCLADES_MAJOR
#define CPC_TTY_MINOR_START 240 /* minor of the first PC300 interface */
#define CPC_TTY_MAX_MTU 2000
/* tty interface state */
#define CPC_TTY_ST_IDLE 0
#define CPC_TTY_ST_INIT 1 /* configured with MLPPP and up */
#define CPC_TTY_ST_OPEN 2 /* opened by application */
#define CPC_TTY_LOCK(card,flags)\
do {\
spin_lock_irqsave(&card->card_lock, flags); \
} while (0)
#define CPC_TTY_UNLOCK(card,flags) \
do {\
spin_unlock_irqrestore(&card->card_lock, flags); \
} while (0)
//#define CPC_TTY_DBG(format,a...) printk(format,##a)
#define CPC_TTY_DBG(format,a...)
/* data structures */
typedef struct _st_cpc_rx_buf {
struct _st_cpc_rx_buf *next;
int size;
unsigned char data[1];
} st_cpc_rx_buf;
struct st_cpc_rx_list {
st_cpc_rx_buf *first;
st_cpc_rx_buf *last;
};
typedef struct _st_cpc_tty_area {
int state; /* state of the TTY interface */
int num_open;
unsigned int tty_minor; /* minor this interface */
volatile struct st_cpc_rx_list buf_rx; /* ptr. to reception buffer */
unsigned char* buf_tx; /* ptr. to transmission buffer */
pc300dev_t* pc300dev; /* ptr. to info struct in PC300 driver */
unsigned char name[20]; /* interf. name + "-tty" */
struct tty_struct *tty;
struct work_struct tty_tx_work; /* tx work - tx interrupt */
struct work_struct tty_rx_work; /* rx work - rx interrupt */
} st_cpc_tty_area;
/* TTY data structures */
static struct tty_driver serial_drv;
/* local variables */
st_cpc_tty_area cpc_tty_area[CPC_TTY_NPORTS];
int cpc_tty_cnt=0; /* number of intrfaces configured with MLPPP */
int cpc_tty_unreg_flag = 0;
/* TTY functions prototype */
static int cpc_tty_open(struct tty_struct *tty, struct file *flip);
static void cpc_tty_close(struct tty_struct *tty, struct file *flip);
static int cpc_tty_write(struct tty_struct *tty, const unsigned char *buf, int count);
static int cpc_tty_write_room(struct tty_struct *tty);
static int cpc_tty_chars_in_buffer(struct tty_struct *tty);
static void cpc_tty_flush_buffer(struct tty_struct *tty);
static void cpc_tty_hangup(struct tty_struct *tty);
static void cpc_tty_rx_work(void *data);
static void cpc_tty_tx_work(void *data);
static int cpc_tty_send_to_card(pc300dev_t *dev,void *buf, int len);
static void cpc_tty_trace(pc300dev_t *dev, char* buf, int len, char rxtx);
static void cpc_tty_signal_off(pc300dev_t *pc300dev, unsigned char);
static void cpc_tty_signal_on(pc300dev_t *pc300dev, unsigned char);
int pc300_tiocmset(struct tty_struct *, struct file *,
unsigned int, unsigned int);
int pc300_tiocmget(struct tty_struct *, struct file *);
/* functions called by PC300 driver */
void cpc_tty_init(pc300dev_t *dev);
void cpc_tty_unregister_service(pc300dev_t *pc300dev);
void cpc_tty_receive(pc300dev_t *pc300dev);
void cpc_tty_trigger_poll(pc300dev_t *pc300dev);
void cpc_tty_reset_var(void);
/*
* PC300 TTY clear "signal"
*/
static void cpc_tty_signal_off(pc300dev_t *pc300dev, unsigned char signal)
{
pc300ch_t *pc300chan = (pc300ch_t