745 lines
16 KiB
C
745 lines
16 KiB
C
/*====================================================================
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
|
|
#include <linux/wanpipe_lip.h>
|
|
|
|
#define NR_PORTS 32
|
|
#define WAN_TTY_MAJOR 240
|
|
#define WAN_TTY_MINOR 0
|
|
|
|
#define WPLIP_MINOR_DEV(_port) (tty_lip_link_map[_port])
|
|
#define MIN_PORT 0
|
|
#define MAX_PORT NR_PORTS-1
|
|
|
|
#define CRC_LENGTH 2
|
|
|
|
#define MAX_TTY_RX_BUF 30
|
|
#define TTY_MAX_MTU 4096
|
|
|
|
#ifdef __LINUX__
|
|
|
|
static struct tty_driver serial_driver;
|
|
static int tty_init_cnt=0;
|
|
static struct serial_state rs_table[NR_PORTS];
|
|
|
|
#ifndef LINUX_2_6
|
|
static int serial_refcount=1;
|
|
static struct tty_struct *serial_table[NR_PORTS];
|
|
static struct tty_driver callout_driver;
|
|
static struct termios *serial_termios[NR_PORTS];
|
|
static struct termios *serial_termios_locked[NR_PORTS];
|
|
#endif
|
|
|
|
|
|
static void* tty_lip_link_map[NR_PORTS] = {NULL,NULL,NULL,NULL,
|
|
NULL,NULL,NULL,NULL,
|
|
NULL,NULL,NULL,NULL,
|
|
NULL,NULL,NULL,NULL,
|
|
NULL,NULL,NULL,NULL,
|
|
NULL,NULL,NULL,NULL,
|
|
NULL,NULL,NULL,NULL,
|
|
NULL,NULL,NULL,NULL};
|
|
|
|
|
|
int wanpipe_tty_trigger_poll(wplip_link_t *lip_link)
|
|
{
|
|
WAN_TASKQ_SCHEDULE((&lip_link->tty_task_queue));
|
|
return 0;
|
|
}
|
|
|
|
|
|
# if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20))
|
|
static void tty_poll_task (void *arg)
|
|
# else
|
|
static void tty_poll_task (struct work_struct *work)
|
|
# endif
|
|
{
|
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
|
|
wplip_link_t *lip_link=(wplip_link_t *)container_of(work, wplip_link_t, tty_task_queue);
|
|
#else
|
|
wplip_link_t *lip_link=(wplip_link_t *)arg;
|
|
#endif
|
|
struct tty_struct *tty;
|
|
netskb_t *skb;
|
|
char fp=0;
|
|
int err=0;
|
|
unsigned long smp_flags;
|
|
|
|
DEBUG_TEST("%s: TQ=0x%lX\n",__FUNCTION__,
|
|
lip_link->tq_working);
|
|
|
|
if ((tty=lip_link->tty)==NULL)
|
|
return;
|
|
|
|
while ((skb=wan_skb_dequeue(&lip_link->tty_rx)) != NULL){
|
|
if (tty->ldisc.receive_buf){
|
|
tty->ldisc.receive_buf(tty,wan_skb_data(skb),&fp,wan_skb_len(skb));
|
|
}
|
|
wan_skb_free(skb);
|
|
}
|
|
|
|
wan_spin_lock_irq(&lip_link->bh_lock,&smp_flags);
|
|
if (wan_test_and_clear_bit(WPLIP_TTY_BUSY,&lip_link->tq_working)){
|
|
err=1;
|
|
}
|
|
wan_spin_unlock_irq(&lip_link->bh_lock,&smp_flags);
|
|
|
|
if (err){
|
|
|
|
DEBUG_TEST("%s: Got TTY Wakeup!\n",lip_link->name);
|
|
|
|
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
|
|
tty->ldisc.write_wakeup){
|
|
(tty->ldisc.write_wakeup)(tty);
|
|
}
|
|
|
|
wake_up_interruptible(&tty->write_wait);
|
|
#if defined(SERIAL_HAVE_POLL_WAIT) || \
|
|
(defined LINUX_2_1 && LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,15))
|
|
wake_up_interruptible(&tty->poll_wait);
|
|
#endif
|
|
|
|
}
|
|
return;
|
|
}
|
|
|
|
static void wanpipe_tty_close(struct tty_struct *tty, struct file * filp)
|
|
{
|
|
wplip_link_t *lip_link;
|
|
unsigned long smp_flags;
|
|
|
|
if (!tty || !tty->driver_data){
|
|
return;
|
|
}
|
|
|
|
lip_link = (wplip_link_t*)tty->driver_data;
|
|
|
|
if (!lip_link)
|
|
return;
|
|
|
|
DEBUG_EVENT( "%s: Closing TTY Driver!\n",
|
|
lip_link->name);
|
|
|
|
/* Sanity Check */
|
|
if (!lip_link->tty_open)
|
|
return;
|
|
|
|
if (--lip_link->tty_open == 0){
|
|
|
|
netskb_t *skb;
|
|
|
|
wplip_link_prot_change_state(lip_link,WAN_DISCONNECTED,NULL,0);
|
|
|
|
wan_spin_lock_irq(&lip_link->bh_lock,&smp_flags);
|
|
lip_link->tty=NULL;
|
|
|
|
while ((skb=wan_skb_dequeue(&lip_link->tty_rx)) != NULL){
|
|
wan_skb_free(skb);
|
|
}
|
|
|
|
/* BUGFIX: Moved down here */
|
|
wan_spin_unlock_irq(&lip_link->bh_lock,&smp_flags);
|
|
|
|
}
|
|
return;
|
|
}
|
|
static int wanpipe_tty_open(struct tty_struct *tty, struct file * filp)
|
|
{
|
|
unsigned long smp_flags;
|
|
wplip_link_t *lip_link;
|
|
|
|
if (!tty){
|
|
return -ENODEV;
|
|
}
|
|
|
|
if (!tty->driver_data){
|
|
int port;
|
|
#ifdef LINUX_2_6
|
|
port = tty->index;
|
|
#else
|
|
port = MINOR(tty->device) - tty->driver.minor_start;
|
|
#endif
|
|
if ((port < 0) || (port >= NR_PORTS))
|
|
return -ENODEV;
|
|
|
|
tty->driver_data = WPLIP_MINOR_DEV(port);
|
|
if (!tty->driver_data)
|
|
return -ENODEV;
|
|
}
|
|
|
|
lip_link = (wplip_link_t*)tty->driver_data;
|
|
|
|
if (!lip_link){
|
|
wan_spin_lock_irq(&lip_link->bh_lock,&smp_flags);
|
|
lip_link->tty=NULL;
|
|
wan_spin_unlock_irq(&lip_link->bh_lock,&smp_flags);
|
|
return -ENODEV;
|
|
}
|
|
|
|
DEBUG_EVENT( "%s: Opening TTY Driver!\n",
|
|
lip_link->name);
|
|
|
|
if (lip_link->tty_open == 0){
|
|
|
|
wan_spin_lock_irq(&lip_link->bh_lock,&smp_flags);
|
|
lip_link->tty=tty;
|
|
wan_spin_unlock_irq(&lip_link->bh_lock,&smp_flags);
|
|
|
|
wan_skb_queue_init(&lip_link->tty_rx);
|
|
|
|
wplip_link_prot_change_state(lip_link,WAN_CONNECTED,NULL,0);
|
|
}
|
|
|
|
++lip_link->tty_open;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
|
|
static int wanpipe_tty_write(struct tty_struct * tty,
|
|
const unsigned char *buf, int count)
|
|
#else
|
|
static int wanpipe_tty_write(struct tty_struct * tty, int from_user,
|
|
const unsigned char *buf, int count)
|
|
#endif
|
|
{
|
|
wplip_link_t *lip_link=NULL;
|
|
unsigned char *tmp_buf;
|
|
netskb_t *skb;
|
|
int err;
|
|
unsigned long smp_flags;
|
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
|
|
int from_user=0;
|
|
#endif
|
|
|
|
if (!tty){
|
|
DEBUG_EVENT("NO TTY in Write\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
lip_link = (wplip_link_t *)tty->driver_data;
|
|
|
|
if (!lip_link){
|
|
DEBUG_EVENT("No lip_link in TTY Write\n");
|
|
return -ENODEV;
|
|
}
|
|
|
|
|
|
if (count > TTY_MAX_MTU){
|
|
DEBUG_EVENT("%s: Frame too big in %s() %d Max: %d\n",
|
|
lip_link->name,__FUNCTION__,count, TTY_MAX_MTU);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (lip_link->state != WAN_CONNECTED){
|
|
DEBUG_TEST("%s: Link not connected (0x%x) in TTY Write\n",
|
|
lip_link->name,lip_link->state);
|
|
return -EINVAL;
|
|
}
|
|
|
|
skb=wan_skb_alloc(count);
|
|
if (!skb){
|
|
return -ENOMEM;
|
|
}
|
|
|
|
tmp_buf=wan_skb_put(skb,count);
|
|
|
|
if (from_user) {
|
|
if (WAN_COPY_FROM_USER(tmp_buf,buf,count)){
|
|
DEBUG_TEST("%s: Failed to copy from user!\n",
|
|
lip_link->name);
|
|
return -EINVAL;
|
|
}
|
|
}else{
|
|
memcpy(tmp_buf,buf,count);
|
|
}
|
|
|
|
err=wplip_data_tx_down(lip_link,skb);
|
|
if (err){
|
|
wan_spin_lock_irq(&lip_link->bh_lock,&smp_flags);
|
|
wan_set_bit(WPLIP_TTY_BUSY,&lip_link->tq_working);
|
|
wan_spin_unlock_irq(&lip_link->bh_lock,&smp_flags);
|
|
|
|
DEBUG_TEST("%s: Failed to tx down!\n",
|
|
lip_link->name);
|
|
wan_skb_free(skb);
|
|
return 0;
|
|
}
|
|
|
|
|
|
DEBUG_TEST("%s: Packet sent OK: %d\n",lip_link->name,count);
|
|
return count;
|
|
}
|
|
|
|
void wplip_tty_receive(wplip_link_t *lip_link, void *skb)
|
|
{
|
|
struct tty_struct *tty;
|
|
|
|
if (!lip_link->tty_open){
|
|
DEBUG_TEST("%s: TTY not open during receive\n",
|
|
lip_link->name);
|
|
wan_skb_free(skb);
|
|
return;
|
|
}
|
|
|
|
if ((tty=lip_link->tty) == NULL){
|
|
DEBUG_TEST("%s: No TTY on receive\n",
|
|
lip_link->name);
|
|
wan_skb_free(skb);
|
|
return;
|
|
}
|
|
|
|
if (!tty->driver_data){
|
|
DEBUG_TEST("%s: No Driver Data, or Flip on receive\n",
|
|
lip_link->name);
|
|
wan_skb_free(skb);
|
|
return;
|
|
}
|
|
|
|
if (wan_skb_len(skb) > TTY_MAX_MTU){
|
|
if (WAN_NET_RATELIMIT()){
|
|
DEBUG_EVENT(
|
|
"%s: Received packet size too big: %d bytes, Max: %d!\n",
|
|
lip_link->name,wan_skb_len(skb),TTY_MAX_MTU);
|
|
}
|
|
wan_skb_free(skb);
|
|
return;
|
|
}
|
|
|
|
if (wan_skb_queue_len(&lip_link->tty_rx) > MAX_TTY_RX_BUF){
|
|
wanpipe_tty_trigger_poll(lip_link);
|
|
wan_skb_free(skb);
|
|
return;
|
|
}
|
|
|
|
wan_skb_queue_tail(&lip_link->tty_rx,skb);
|
|
wanpipe_tty_trigger_poll(lip_link);
|
|
|
|
return;
|
|
}
|
|
|
|
#if 0
|
|
static int wanpipe_tty_ioctl(struct tty_struct *tty, struct file * file,
|
|
unsigned int cmd, unsigned long arg)
|
|
{
|
|
return -ENOIOCTLCMD;
|
|
}
|
|
#endif
|
|
|
|
static void wanpipe_tty_stop(struct tty_struct *tty)
|
|
{
|
|
return;
|
|
}
|
|
|
|
static void wanpipe_tty_start(struct tty_struct *tty)
|
|
{
|
|
return;
|
|
}
|
|
|
|
|
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20))
|
|
static void wanpipe_tty_set_termios(struct tty_struct *tty, struct ktermios *old_termios)
|
|
#else
|
|
static void wanpipe_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
|
|
#endif
|
|
{
|
|
wplip_link_t *lip_link;
|
|
|
|
if (!tty){
|
|
return;
|
|
}
|
|
|
|
lip_link = (wplip_link_t *)tty->driver_data;
|
|
|
|
if (!lip_link)
|
|
return;
|
|
|
|
return;
|
|
}
|
|
|
|
static void wanpipe_tty_put_char(struct tty_struct *tty, unsigned char ch)
|
|
{
|
|
wplip_link_t *lip_link;
|
|
netskb_t *skb;
|
|
unsigned char *buf;
|
|
int err=0;
|
|
unsigned long smp_flags;
|
|
|
|
if (!tty){
|
|
return;
|
|
}
|
|
|
|
lip_link = (wplip_link_t *)tty->driver_data;
|
|
if (!lip_link){
|
|
return;
|
|
}
|
|
|
|
if (lip_link->state != WAN_CONNECTED){
|
|
return;
|
|
}
|
|
|
|
skb=wan_skb_alloc(5);
|
|
if (!skb){
|
|
return;
|
|
}
|
|
|
|
buf=wan_skb_put(skb,1);
|
|
buf[0]=ch;
|
|
|
|
err=wplip_data_tx_down(lip_link,skb);
|
|
if (err){
|
|
wan_spin_lock_irq(&lip_link->bh_lock,&smp_flags);
|
|
wan_set_bit(WPLIP_TTY_BUSY,&lip_link->tq_working);
|
|
wan_spin_unlock_irq(&lip_link->bh_lock,&smp_flags);
|
|
wan_skb_free(skb);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
static void wanpipe_tty_flush_chars(struct tty_struct *tty)
|
|
{
|
|
return;
|
|
}
|
|
|
|
static void wanpipe_tty_flush_buffer(struct tty_struct *tty)
|
|
{
|
|
if (!tty)
|
|
return;
|
|
|
|
wake_up_interruptible(&tty->write_wait);
|
|
#if defined(SERIAL_HAVE_POLL_WAIT) || \
|
|
(defined LINUX_2_1 && LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,15))
|
|
wake_up_interruptible(&tty->poll_wait);
|
|
#endif
|
|
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
|
|
tty->ldisc.write_wakeup)
|
|
(tty->ldisc.write_wakeup)(tty);
|
|
|
|
return;
|
|
}
|
|
|
|
/*
|
|
* This function is used to send a high-priority XON/XOFF character to
|
|
* the device
|
|
*/
|
|
#ifndef LINUX_2_6
|
|
static void wanpipe_tty_send_xchar(struct tty_struct *tty, char ch)
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
static int wanpipe_tty_chars_in_buffer(struct tty_struct *tty)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int wanpipe_tty_write_room(struct tty_struct *tty)
|
|
{
|
|
wplip_link_t *lip_link;
|
|
|
|
DEBUG_TEST("TTY Write Room\n");
|
|
|
|
if (!tty){
|
|
return 0;
|
|
}
|
|
|
|
lip_link = (wplip_link_t *)tty->driver_data;
|
|
if (!lip_link)
|
|
return 0;
|
|
|
|
if (lip_link->state != WAN_CONNECTED)
|
|
return 0;
|
|
|
|
return TTY_MAX_MTU;
|
|
}
|
|
|
|
|
|
static int set_modem_status(wplip_link_t *lip_link, unsigned char data)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static void wanpipe_tty_hangup(struct tty_struct *tty)
|
|
{
|
|
wplip_link_t *lip_link;
|
|
unsigned long smp_flags;
|
|
|
|
DEBUG_EVENT( "TTY Hangup!\n");
|
|
|
|
if (!tty){
|
|
return;
|
|
}
|
|
|
|
lip_link = (wplip_link_t *)tty->driver_data;
|
|
if (!lip_link)
|
|
return;
|
|
|
|
wan_spin_lock_irq(&lip_link->bh_lock,&smp_flags);
|
|
set_modem_status(lip_link,0);
|
|
wan_spin_unlock_irq(&lip_link->bh_lock,&smp_flags);
|
|
|
|
return;
|
|
}
|
|
|
|
#ifndef LINUX_2_6
|
|
static void wanpipe_tty_break(struct tty_struct *tty, int break_state)
|
|
{
|
|
return;
|
|
}
|
|
|
|
static void wanpipe_tty_wait_until_sent(struct tty_struct *tty, int timeout)
|
|
{
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
static void wanpipe_tty_throttle(struct tty_struct * tty)
|
|
{
|
|
return;
|
|
}
|
|
|
|
static void wanpipe_tty_unthrottle(struct tty_struct * tty)
|
|
{
|
|
return;
|
|
}
|
|
|
|
int wanpipe_tty_read_proc(char *page, char **start, off_t off, int count,
|
|
int *eof, void *data)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
#ifdef LINUX_2_6
|
|
static struct tty_operations wanpipe_tty_ops = {
|
|
.open = wanpipe_tty_open,
|
|
.close = wanpipe_tty_close,
|
|
.write = wanpipe_tty_write,
|
|
.put_char = wanpipe_tty_put_char,
|
|
.flush_chars = wanpipe_tty_flush_chars,
|
|
.write_room = wanpipe_tty_write_room,
|
|
.chars_in_buffer = wanpipe_tty_chars_in_buffer,
|
|
.flush_buffer = wanpipe_tty_flush_buffer,
|
|
// .ioctl = wanpipe_tty_ioctl,
|
|
.throttle = wanpipe_tty_throttle,
|
|
.unthrottle = wanpipe_tty_unthrottle,
|
|
.set_termios = wanpipe_tty_set_termios,
|
|
.stop = wanpipe_tty_stop,
|
|
.start = wanpipe_tty_start,
|
|
.hangup = wanpipe_tty_hangup,
|
|
};
|
|
#endif
|
|
|
|
|
|
/*
|
|
* The serial driver boot-time initialization code!
|
|
*/
|
|
int wplip_reg_tty(wplip_link_t *lip_link, wanif_conf_t *cfg)
|
|
{
|
|
struct serial_state * state;
|
|
|
|
lip_link->tty_minor = cfg->port;
|
|
|
|
/* Initialize the tty_driver structure */
|
|
|
|
if (lip_link->tty_minor < 0 || lip_link->tty_minor > NR_PORTS){
|
|
DEBUG_EVENT("%s: Illegal Minor TTY number (0-%d): %d\n",
|
|
lip_link->name,NR_PORTS,lip_link->tty_minor);
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (WPLIP_MINOR_DEV(lip_link->tty_minor)){
|
|
DEBUG_EVENT("%s: TTY Minor %d, already in use\n",
|
|
lip_link->name,lip_link->tty_minor);
|
|
return -EBUSY;
|
|
}
|
|
|
|
|
|
if (tty_init_cnt==0){
|
|
|
|
DEBUG_EVENT( "%s: TTY Driver Init: Major %d, Minor Range %d-%d\n",
|
|
lip_link->name,
|
|
WAN_TTY_MAJOR,MIN_PORT,MAX_PORT);
|
|
|
|
|
|
|
|
memset(&serial_driver, 0, sizeof(struct tty_driver));
|
|
serial_driver.magic = TTY_DRIVER_MAGIC;
|
|
|
|
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
|
|
serial_driver.owner = THIS_MODULE;
|
|
#endif
|
|
|
|
serial_driver.driver_name = "wanpipe_tty";
|
|
#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
|
|
serial_driver.name = "ttyWP/%d";
|
|
#else
|
|
serial_driver.name = "ttyWP";
|
|
#endif
|
|
serial_driver.major = WAN_TTY_MAJOR;
|
|
serial_driver.minor_start = WAN_TTY_MINOR;
|
|
serial_driver.num = NR_PORTS;
|
|
serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
|
|
serial_driver.subtype = SERIAL_TYPE_NORMAL;
|
|
|
|
serial_driver.init_termios = tty_std_termios;
|
|
serial_driver.init_termios.c_cflag =
|
|
B9600 | CS8 | CREAD | HUPCL | CLOCAL;
|
|
serial_driver.flags = TTY_DRIVER_REAL_RAW;
|
|
|
|
|
|
#ifdef LINUX_2_6
|
|
tty_set_operations(&serial_driver, &wanpipe_tty_ops);
|
|
#else
|
|
serial_driver.refcount = &serial_refcount;
|
|
serial_driver.table = serial_table;
|
|
serial_driver.termios = serial_termios;
|
|
serial_driver.termios_locked = serial_termios_locked;
|
|
|
|
serial_driver.open = wanpipe_tty_open;
|
|
serial_driver.close = wanpipe_tty_close;
|
|
serial_driver.write = wanpipe_tty_write;
|
|
|
|
serial_driver.put_char = wanpipe_tty_put_char;
|
|
serial_driver.flush_chars = wanpipe_tty_flush_chars;
|
|
serial_driver.write_room = wanpipe_tty_write_room;
|
|
serial_driver.chars_in_buffer = wanpipe_tty_chars_in_buffer;
|
|
serial_driver.flush_buffer = wanpipe_tty_flush_buffer;
|
|
//serial_driver.ioctl = wanpipe_tty_ioctl;
|
|
serial_driver.throttle = wanpipe_tty_throttle;
|
|
serial_driver.unthrottle = wanpipe_tty_unthrottle;
|
|
serial_driver.send_xchar = wanpipe_tty_send_xchar;
|
|
serial_driver.set_termios = wanpipe_tty_set_termios;
|
|
serial_driver.stop = wanpipe_tty_stop;
|
|
serial_driver.start = wanpipe_tty_start;
|
|
serial_driver.hangup = wanpipe_tty_hangup;
|
|
serial_driver.break_ctl = wanpipe_tty_break;
|
|
serial_driver.wait_until_sent = wanpipe_tty_wait_until_sent;
|
|
serial_driver.read_proc = wanpipe_tty_read_proc;
|
|
|
|
/*
|
|
* The callout device is just like normal device except for
|
|
* major number and the subtype code.
|
|
*/
|
|
callout_driver = serial_driver;
|
|
#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
|
|
callout_driver.name = "cuwp/%d";
|
|
#else
|
|
callout_driver.name = "cuwp";
|
|
#endif
|
|
callout_driver.major = TTYAUX_MAJOR;
|
|
callout_driver.subtype = SERIAL_TYPE_CALLOUT;
|
|
callout_driver.read_proc = 0;
|
|
callout_driver.proc_entry = 0;
|
|
#endif
|
|
|
|
if (tty_register_driver(&serial_driver)){
|
|
DEBUG_EVENT( "%s: Failed to register serial driver!\n",
|
|
lip_link->name);
|
|
}
|
|
|
|
#ifndef LINUX_2_6
|
|
if (tty_register_driver(&callout_driver)){
|
|
DEBUG_EVENT( "%s: Failed to register callout driver!\n",
|
|
lip_link->name);
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
/* The subsequent ports must comply to the initial configuration */
|
|
|
|
tty_init_cnt++;
|
|
|
|
#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS))
|
|
DEBUG_EVENT( "%s: TTY Sync Dev Minor %d : /dev/ttyWP/%d\n",
|
|
lip_link->name,
|
|
lip_link->tty_minor,lip_link->tty_minor);
|
|
#else
|
|
DEBUG_EVENT( "%s: TTY Sync Dev Minor %d : /dev/ttyWP%d\n",
|
|
lip_link->name,
|
|
lip_link->tty_minor,lip_link->tty_minor);
|
|
#endif
|
|
|
|
tty_lip_link_map[lip_link->tty_minor] = lip_link;
|
|
|
|
state = &rs_table[lip_link->tty_minor];
|
|
|
|
state->magic = SSTATE_MAGIC;
|
|
state->line = 0;
|
|
state->type = PORT_UNKNOWN;
|
|
state->custom_divisor = 0;
|
|
state->close_delay = 5*HZ/10;
|
|
state->closing_wait = 30*HZ;
|
|
|
|
#ifndef LINUX_2_6
|
|
state->callout_termios = callout_driver.init_termios;
|
|
state->normal_termios = serial_driver.init_termios;
|
|
#endif
|
|
state->icount.cts = state->icount.dsr =
|
|
state->icount.rng = state->icount.dcd = 0;
|
|
state->icount.rx = state->icount.tx = 0;
|
|
state->icount.frame = state->icount.parity = 0;
|
|
state->icount.overrun = state->icount.brk = 0;
|
|
state->irq = 0;
|
|
|
|
WAN_TASKQ_INIT((&lip_link->tty_task_queue),0,tty_poll_task,lip_link);
|
|
|
|
lip_link->tty_opt=1;
|
|
return 0;
|
|
}
|
|
|
|
|
|
int wplip_unreg_tty(wplip_link_t *lip_link)
|
|
{
|
|
struct serial_state * state;
|
|
unsigned long smp_flags;
|
|
|
|
DEBUG_TEST("%s: %s() cnt=%i\n",
|
|
lip_link->name,__FUNCTION__,tty_init_cnt);
|
|
|
|
|
|
if (lip_link->tty_open){
|
|
return -EBUSY;
|
|
}
|
|
|
|
if ((--tty_init_cnt) == 0){
|
|
int e1;
|
|
#ifndef LINUX_2_6
|
|
*serial_driver.refcount=0;
|
|
#endif
|
|
if ((e1 = tty_unregister_driver(&serial_driver))){
|
|
DEBUG_EVENT( "SERIAL: failed to unregister serial driver (%d)\n",
|
|
e1);
|
|
}
|
|
#ifndef LINUX_2_6
|
|
if ((e1 = tty_unregister_driver(&callout_driver))){
|
|
DEBUG_EVENT( "SERIAL: failed to unregister callout driver (%d)\n",
|
|
e1);
|
|
}
|
|
#endif
|
|
DEBUG_EVENT( "%s: Unregistering TTY Driver, Major %i\n",
|
|
lip_link->name,WAN_TTY_MAJOR);
|
|
|
|
}
|
|
wan_spin_lock_irq(&lip_link->bh_lock,&smp_flags);
|
|
lip_link->tty=NULL;
|
|
|
|
if (tty_lip_link_map[lip_link->tty_minor] == lip_link){
|
|
tty_lip_link_map[lip_link->tty_minor]=NULL;
|
|
}
|
|
|
|
state = &rs_table[lip_link->tty_minor];
|
|
memset(state,0,sizeof(*state));
|
|
wan_spin_unlock_irq(&lip_link->bh_lock,&smp_flags);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /*__LINUX__*/
|