diff options
Diffstat (limited to 'net/irda/ircomm/irvtd_driver.c')
-rw-r--r-- | net/irda/ircomm/irvtd_driver.c | 2071 |
1 files changed, 0 insertions, 2071 deletions
diff --git a/net/irda/ircomm/irvtd_driver.c b/net/irda/ircomm/irvtd_driver.c deleted file mode 100644 index 7b1ddf3cb..000000000 --- a/net/irda/ircomm/irvtd_driver.c +++ /dev/null @@ -1,2071 +0,0 @@ -/********************************************************************* - * - * Filename: irvtd_driver.c - * Version: - * Description: Virtual tty driver (the "port emulation entity" of IrCOMM) - * Status: Experimental. - * Author: Takahide Higuchi <thiguchi@pluto.dti.ne.jp> - * Source: serial.c by Linus Torvalds - * isdn_tty.c by Fritz Elfert - * - * Copyright (c) 1998-1999, Takahide Higuchi, <thiguchi@pluto.dti.ne.jp>, - * All Rights Reserved. - * - * 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. - * - * I, Takahide Higuchi, provide no warranty for any of this software. - * This material is provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#include <linux/module.h> -#include <linux/init.h> - -#include <linux/fs.h> -#include <linux/sched.h> -#include <linux/termios.h> -#include <linux/tty.h> -#include <asm/segment.h> -#include <asm/uaccess.h> - -#include <net/irda/irda.h> -#include <net/irda/irttp.h> -#include <net/irda/irias_object.h> - -#include <net/irda/irvtd.h> - -#ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) -#endif - -#define DO_RESTART -#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) - -struct tty_driver irvtd_drv; -struct tty_struct *irvtd_table[COMM_MAX_TTY]; -struct termios *irvtd_termios[COMM_MAX_TTY]; -struct termios *irvtd_termios_locked[COMM_MAX_TTY]; -static int irvtd_refcount; -struct irvtd_cb **irvtd = NULL; - -static char *revision_date = "Wed May 26 00:49:11 1999"; - - -/* - * prototypes - */ - -int irvtd_open(struct tty_struct *tty, struct file *filp); -void irvtd_close(struct tty_struct * tty, struct file * filp); -int irvtd_write(struct tty_struct * tty, int from_user, - const unsigned char *buf, int count); -void irvtd_put_char(struct tty_struct *tty, unsigned char ch); -int irvtd_write_room(struct tty_struct *tty); -int irvtd_chars_in_buffer(struct tty_struct *tty); -int irvtd_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg); -void irvtd_set_termios(struct tty_struct *tty, struct termios * old); -void irvtd_throttle(struct tty_struct *tty); -void irvtd_unthrottle(struct tty_struct *tty); -void irvtd_stop(struct tty_struct *tty); -void irvtd_start(struct tty_struct *tty); -void irvtd_hangup(struct tty_struct *tty); -void irvtd_flush_buffer(struct tty_struct *tty); -void irvtd_flush_chars(struct tty_struct *tty); - -static void change_speed(struct irvtd_cb *driver); -static void irvtd_write_to_tty( struct irvtd_cb *); -static void irvtd_send_data_request( struct irvtd_cb *); -static void irvtd_break(struct tty_struct *tty, int break_state); -static void irvtd_send_xchar(struct tty_struct *tty, char ch); -static void irvtd_wait_until_sent(struct tty_struct *tty, int timeout); - -static void irvtd_start_tx_timer( struct irvtd_cb *driver, int timeout); -static void irvtd_tx_timer_expired(unsigned long data); -static void irvtd_start_rx_timer( struct irvtd_cb *driver, int timeout); -static void irvtd_rx_timer_expired(unsigned long data); - -static int line_info(char *buf, struct irvtd_cb *driver); -static int irvtd_read_proc(char *buf, char **start, off_t offset, int len, - int *eof, void *unused); - - -/* - ********************************************************************** - * - * ircomm_receive_data() and friends - * - * like interrupt handler in the serial.c,we receive data when - * ircomm_data_indication comes - * - ********************************************************************** - */ - - - -/* - * irvtd_write_to_tty - * send incoming/queued data to tty - */ - -static void irvtd_write_to_tty( struct irvtd_cb *driver) -{ - int status, c, flag; - struct sk_buff *skb; - struct tty_struct *tty = driver->tty; - - if(driver->rx_disable) - return; - - skb = skb_dequeue(&driver->rxbuff); - if(skb == NULL) - return; /* there's nothing */ - - /* - * we should parse controlchannel field here. - * (see process_data() in ircomm.c) - */ - ircomm_parse_tuples(driver->comm, skb, CONTROL_CHANNEL); - -#ifdef IRVTD_DEBUG_RX - printk("received data:"); - { - int i; - for ( i=0;i<skb->len;i++) - printk("%02x ", skb->data[i]); - printk("\n"); - } -#endif - - status = driver->comm->peer_line_status & driver->read_status_mask; - - /* - * if there are too many errors which make a character ignored, - * drop characters - */ - - if(status & driver->ignore_status_mask){ - DEBUG(0,__FUNCTION__":some error:ignore characters.\n"); - dev_kfree_skb(skb); - return; - } - - c = MIN(skb->len, (TTY_FLIPBUF_SIZE - tty->flip.count)); - DEBUG(4, __FUNCTION__"skb_len=%d, tty->flip.count=%d \n" - ,(int)skb->len, tty->flip.count); - - if (driver->comm->peer_break_signal ) { - driver->comm->peer_break_signal = 0; - DEBUG(0,"handling break....\n"); - - flag = TTY_BREAK; - if (driver->flags & ASYNC_SAK) - /* - * do_SAK() seems to be an implementation of the - * idea called "Secure Attention Key", - * which seems to be discribed in "Orange book". - * (which is published by U.S.military!!?? , - * see source of do_SAK()) - * - * but what kind of security do we need - * when we use infrared communication??? :p) - */ - do_SAK(tty); - }else if (status & LSR_PE) - flag = TTY_PARITY; - else if (status & LSR_FE) - flag = TTY_FRAME; - else if (status & LSR_OE) - flag = TTY_OVERRUN; - else - flag = TTY_NORMAL; - - if(c){ - DEBUG(4,"writing %d chars to tty\n",c); - driver->icount.rx += c; - memset(tty->flip.flag_buf_ptr, flag, c); - memcpy(tty->flip.char_buf_ptr, skb->data, c); - tty->flip.flag_buf_ptr += c; - tty->flip.char_buf_ptr += c; - tty->flip.count += c; - skb_pull(skb,c); - } - - if(skb->len == 0) - dev_kfree_skb(skb); - else - { - /* queue rest of data again */ - DEBUG(4,__FUNCTION__":retrying frame!\n"); - - /* build a dummy control channel */ - skb_push(skb,1); - *skb->data = 0; /* clen is 0 */ - skb_queue_head( &driver->rxbuff, skb ); - } - - if(c) - /* let the process read its buffer! */ - tty_flip_buffer_push(tty); - - if(skb_queue_len(&driver->rxbuff)< IRVTD_RX_QUEUE_LOW && - driver->ttp_stoprx){ - DEBUG(1, __FUNCTION__"():FLOW_START\n"); - /* - * next 2 lines must follow this order since irttp_flow_request() - * will run its rx queue - */ - driver->ttp_stoprx = 0; - irttp_flow_request(driver->comm->tsap, FLOW_START); - } - - if(skb_queue_empty(&driver->rxbuff) && driver->disconnect_pend){ - /* disconnect */ - driver->disconnect_pend = 0; - driver->rx_disable = 1; - tty_hangup(driver->tty); - } -} - -static int irvtd_receive_data(void *instance, void *sap, struct sk_buff *skb) -{ - struct irvtd_cb *driver = (struct irvtd_cb *)instance; - - ASSERT(driver != NULL, return -1;); - ASSERT(driver->magic == IRVTD_MAGIC, return -1;); - DEBUG(4, __FUNCTION__"(): queue frame\n"); - - /* queue incoming data and make bottom half handler ready */ - - skb_queue_tail( &driver->rxbuff, skb ); - - if(skb_queue_len(&driver->rxbuff) > IRVTD_RX_QUEUE_HIGH){ - DEBUG(1, __FUNCTION__"():FLOW_STOP\n"); - irttp_flow_request(driver->comm->tsap, FLOW_STOP); - driver->ttp_stoprx = 1; - } - irvtd_write_to_tty(driver); - - if(!skb_queue_empty(&driver->rxbuff)) - irvtd_start_rx_timer(driver,0); - return 0; -} - -/* - *********************************************************************** - * - * irvtd_send_data() and friends - * - * like interrupt handler in the serial.c,we send data when - * a timer is expired - * - *********************************************************************** - */ - - -static void irvtd_start_tx_timer( struct irvtd_cb *driver, int timeout) -{ - ASSERT( driver != NULL, return;); - ASSERT( driver->magic == IRVTD_MAGIC, return;); - - del_timer( &driver->tx_timer); - - driver->tx_timer.data = (unsigned long) driver; - driver->tx_timer.function = &irvtd_tx_timer_expired; - driver->tx_timer.expires = jiffies + timeout; - - add_timer( &driver->tx_timer); -} - -static void irvtd_start_rx_timer( struct irvtd_cb *driver, int timeout) -{ - ASSERT( driver != NULL, return;); - ASSERT( driver->magic == IRVTD_MAGIC, return;); - - del_timer( &driver->rx_timer); - - driver->rx_timer.data = (unsigned long) driver; - driver->rx_timer.function = &irvtd_rx_timer_expired; - driver->rx_timer.expires = jiffies + timeout; - - add_timer( &driver->rx_timer); -} - - -static void irvtd_tx_timer_expired(unsigned long data) -{ - struct irvtd_cb *driver = (struct irvtd_cb *)data; - - ASSERT(driver != NULL,return;); - ASSERT(driver->magic == IRVTD_MAGIC,return;); - DEBUG(4, __FUNCTION__"()\n"); - - irvtd_send_data_request(driver); -} - -static void irvtd_rx_timer_expired(unsigned long data) -{ - struct irvtd_cb *driver = (struct irvtd_cb *)data; - - ASSERT(driver != NULL,return;); - ASSERT(driver->magic == IRVTD_MAGIC,return;); - DEBUG(4, __FUNCTION__"()\n"); - - while(TTY_FLIPBUF_SIZE - driver->tty->flip.count - && !skb_queue_empty(&driver->rxbuff)) - irvtd_write_to_tty(driver); - - DEBUG(1, __FUNCTION__"(): room in flip_buffer = %d\n", - TTY_FLIPBUF_SIZE - driver->tty->flip.count); - - if(!skb_queue_empty(&driver->rxbuff)) - /* handle it later */ - irvtd_start_rx_timer(driver, 1); -} - - -static void irvtd_send_data_request(struct irvtd_cb *driver) -{ - int err; - struct sk_buff *skb = driver->txbuff; - - ASSERT(skb != NULL,return;); - DEBUG(4, __FUNCTION__"()\n"); - - if(driver->tty->hw_stopped || driver->tx_disable) - return; - if(!skb->len) - return; /* no data to send */ - -#ifdef IRVTD_DEBUG_TX - DEBUG(4, "flush_txbuff:count(%d)\n",(int)skb->len); - { - int i; - for ( i=0;i<skb->len;i++) - printk("%02x", skb->data[i]); - printk("\n"); - } -#endif - - DEBUG(1, __FUNCTION__"():len = %d, room = %d\n",(int)skb->len, - skb_tailroom(skb)); - driver->icount.tx += skb->len; - err = ircomm_data_request(driver->comm, driver->txbuff); - if (err){ - ASSERT(err == 0,;); - DEBUG(1,"%d chars are lost\n",(int)skb->len); - skb_trim(skb, 0); - } - - /* allocate a new frame */ - skb = driver->txbuff - = dev_alloc_skb(driver->tx_max_sdu_size + driver->max_header_size); - if (skb == NULL){ - printk(__FUNCTION__"():alloc_skb failed!\n"); - } else { - skb_reserve(skb, driver->max_header_size); - } - - wake_up_interruptible(&driver->tty->write_wait); -} - - -/* - *********************************************************************** - * - * indication/confirmation handlers: - * - * these routines are handlers for IrCOMM protocol stack - * - *********************************************************************** - */ - -/* - * Function irvtd_connect_confirm (instance, sap, qos, max_sdu_size, skb) - * - * ircomm_connect_request which we have send, has succeeded! - * - */ -void irvtd_connect_confirm(void *instance, void *sap, struct qos_info *qos, - __u32 max_sdu_size, __u8 max_header_size, - struct sk_buff *skb) -{ - struct irvtd_cb *driver = (struct irvtd_cb *)instance; - ASSERT(driver != NULL, return;); - ASSERT(driver->magic == IRVTD_MAGIC, return;); - - - driver->tx_max_sdu_size = max_sdu_size; - driver->max_header_size = max_header_size; - /* - * set default value - */ - - driver->msr |= (MSR_DCD|MSR_RI|MSR_DSR|MSR_CTS); - - /* - * sending initial control parameters here - */ - if (driver->comm->servicetype == THREE_WIRE_RAW) - return; /* do nothing */ - - driver->comm->dte |= (MCR_DTR | MCR_RTS | DELTA_DTR | DELTA_RTS); - - ircomm_control_request(driver->comm, SERVICETYPE); - ircomm_control_request(driver->comm, DATA_RATE); - ircomm_control_request(driver->comm, DATA_FORMAT); - ircomm_control_request(driver->comm, FLOW_CONTROL); - ircomm_control_request(driver->comm, XON_XOFF_CHAR); - /* ircomm_control_request(driver->comm, ENQ_ACK_CHAR); */ - - switch (driver->comm->servicetype) { - case CENTRONICS: - break; - - case NINE_WIRE: - ircomm_control_request(driver->comm, DTELINE_STATE); - break; - default: - } - - driver->tx_disable = 0; - wake_up_interruptible(&driver->open_wait); -} - -/* - * Function irvtd_connect_indication (instance, sap, qos, max_sdu_size, skb) - * - * we are discovered and being requested to connect by remote device ! - * - */ -void irvtd_connect_indication(void *instance, void *sap, struct qos_info *qos, - __u32 max_sdu_size, __u8 max_header_size, - struct sk_buff *skb) -{ - struct irvtd_cb *driver = (struct irvtd_cb *)instance; - struct ircomm_cb *comm = (struct ircomm_cb *)sap; - - ASSERT(driver != NULL, return;); - ASSERT(driver->magic == IRVTD_MAGIC, return;); - ASSERT(comm != NULL, return;); - ASSERT(comm->magic == IRCOMM_MAGIC, return;); - - driver->tx_max_sdu_size = max_sdu_size; - driver->max_header_size = max_header_size; - DEBUG(4, __FUNCTION__ "():sending connect_response...\n"); - - ircomm_connect_response(comm, NULL, SAR_DISABLE ); - - driver->tx_disable = 0; - - /* - * send initial control parameters - */ - if (driver->comm->servicetype == THREE_WIRE_RAW) - return; /* do nothing */ - - driver->comm->dte |= (MCR_DTR | MCR_RTS | DELTA_DTR | DELTA_RTS); - - switch(driver->comm->servicetype){ - case NINE_WIRE: - ircomm_control_request(driver->comm, DTELINE_STATE); - break; - default: - DEBUG(0, __FUNCTION__ "(), not implemented!\n"); - } - - - driver->msr |= (MSR_DCD|MSR_RI|MSR_DSR|MSR_CTS); - wake_up_interruptible(&driver->open_wait); -} - -/* - * Function irvtd_disconnect_indication (instance, sap, reason, skb) - * - * This is a handler for ircomm_disconnect_indication. since this - * function is called in the context of interrupt handler, - * interruptible_sleep_on() MUST not be used. - */ -void irvtd_disconnect_indication(void *instance, void *sap , LM_REASON reason, - struct sk_buff *skb) -{ - struct irvtd_cb *driver = (struct irvtd_cb *)instance; - - ASSERT(driver != NULL, return;); - ASSERT(driver->tty != NULL, return;); - ASSERT(driver->magic == IRVTD_MAGIC, return;); - - DEBUG(4,"irvtd_disconnect_indication:\n"); - - driver->tx_disable = 1; - if(skb_queue_empty(&driver->rxbuff)){ - /* disconnect */ - driver->rx_disable = 1; - tty_hangup(driver->tty); - } else { - driver->disconnect_pend = 1; - } -} - -/* - * Function irvtd_control_indication (instance, sap, cmd) - * - * - * - */ -void irvtd_control_indication(void *instance, void *sap, IRCOMM_CMD cmd) -{ - struct irvtd_cb *driver = (struct irvtd_cb *)instance; - - ASSERT(driver != NULL, return;); - ASSERT(driver->magic == IRVTD_MAGIC, return;); - - DEBUG(4,__FUNCTION__"()\n"); - - if(cmd == TX_READY){ - driver->ttp_stoptx = 0; - driver->tty->hw_stopped = driver->cts_stoptx; - - if(driver->cts_stoptx) - return; - - /* push tx queue so that client can send at least 1 octet */ - irvtd_send_data_request(driver); - /* - * driver->tty->write_wait will keep asleep if - * our txbuff is full. - * now that we can send packets to IrTTP layer, - * we kick it here. - */ - if ((driver->tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - driver->tty->ldisc.write_wakeup) - (driver->tty->ldisc.write_wakeup)(driver->tty); - return; - } - - if(cmd == TX_BUSY){ - driver->ttp_stoptx = driver->tty->hw_stopped = 1; - del_timer( &driver->tx_timer); - return; - } - - - ASSERT(cmd == CONTROL_CHANNEL,return;); - - switch(driver->comm->pi){ - - case DCELINE_STATE: - driver->msr = driver->comm->peer_dce; - - if(driver->msr & (DELTA_CTS|DELTA_DSR|DELTA_RI|DELTA_DCD)){ - if(driver->msr & DELTA_CTS) - driver->icount.cts++; - if(driver->msr & DELTA_DSR) - driver->icount.dsr++; - if(driver->msr & DELTA_RI) - driver->icount.rng++; - if(driver->msr & DELTA_DCD) - driver->icount.dcd++; - wake_up_interruptible(&driver->delta_msr_wait); - } - - if ((driver->flags & ASYNC_CHECK_CD) && (driver->msr & DELTA_DCD)) { - - DEBUG(0,"CD now %s...\n", - (driver->msr & MSR_DCD) ? "on" : "off"); - - if (driver->msr & MSR_DCD) - { - /* DCD raised! */ - wake_up_interruptible(&driver->open_wait); - } - else - { - /* DCD falled */ - DEBUG(0,__FUNCTION__"():hangup..\n"); - tty_hangup(driver->tty); - } - - } - - if (driver->comm->flow_ctrl & USE_CTS) { - if (driver->tty->hw_stopped) { - if (driver->msr & MSR_CTS) { - DEBUG(0,"CTS tx start...\n"); - - driver->cts_stoptx = 0; - driver->tty->hw_stopped = driver->ttp_stoptx; - /* - * replacement of - * rs_sched_event(info, RS_EVENT_WRITE_WAKEUP) - * in serial.c - */ - - if ((driver->tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - driver->tty->ldisc.write_wakeup) - (driver->tty->ldisc.write_wakeup)(driver->tty); - - wake_up_interruptible(&driver->tty->write_wait); - return; - } - } else { - if (!(driver->msr & MSR_CTS)) { - DEBUG(0,"CTS tx stop..."); - - driver->cts_stoptx = 1; - driver->tty->hw_stopped = 1; - } - } - } - break; - - case FLOW_CONTROL: - case DATA_RATE: - case XON_XOFF_CHAR: - case DTELINE_STATE: - case ENQ_ACK_CHAR: /* got this from win95 */ - /* (maybe) nothing to do */ - break; - default: - DEBUG(0,__FUNCTION__"():PI = 0x%02x is not implemented\n", - (int)driver->comm->pi); - } -} - -/* - *********************************************************************** - * - * driver kernel interfaces - * these functions work as an interface between the kernel and this driver - * - *********************************************************************** - */ - - - -/* - * ---------------------------------------------------------------------- - * irvtd_open() and friends - * - * ---------------------------------------------------------------------- - */ - - -static int irvtd_block_til_ready(struct tty_struct *tty, struct file * filp, - struct irvtd_cb *driver) -{ - - DECLARE_WAITQUEUE(wait,current); - int retval = 0; - int do_clocal = 0; - - /* - * If non-blocking mode is set, or the port is not enabled, - * then make the check up front and then exit. - */ - - if ((filp->f_flags & O_NONBLOCK) || - (tty->flags & (1 << TTY_IO_ERROR))) { - - return 0; - } - - if (tty->termios->c_cflag & CLOCAL) - do_clocal = 1; - - - /* - * We wait until ircomm_connect_request() succeed or - * ircomm_connect_indication comes - */ - - - add_wait_queue(&driver->open_wait, &wait); - - DEBUG(0,__FUNCTION__"():before block( line = %d, count = %d )\n", - driver->line, driver->count); - - driver->blocked_open++; - - /* wait for a connection established */ - while (1) { - current->state = TASK_INTERRUPTIBLE; - - if (tty_hung_up_p(filp) || - !(driver->flags & ASYNC_INITIALIZED)) { -#ifdef DO_RESTART - if (driver->flags & ASYNC_HUP_NOTIFY) - retval = -EAGAIN; - else - retval = -ERESTARTSYS; -#else - retval = -EAGAIN; -#endif - break; - } - - if (!(driver->flags & ASYNC_CLOSING) && - (driver->comm->state == COMM_CONN) && - ( do_clocal || (driver->msr & MSR_DCD))) - break; - - if(signal_pending(current)){ - retval = -ERESTARTSYS; - break; - } - - - DEBUG(4,__FUNCTION__"():blocking( %s%d, count = %d )\n", - tty->driver.name, driver->line, driver->count); - - schedule(); - } - - current->state = TASK_RUNNING; - remove_wait_queue(&driver->open_wait, &wait); - - driver->blocked_open--; - - DEBUG(1, __FUNCTION__"():after blocking\n"); - - if (retval) - return retval; - return 0; -} - -static void change_speed(struct irvtd_cb *driver) -{ - unsigned cflag,cval; - - if (!driver->tty || !driver->tty->termios || !driver->comm) - return; - cflag = driver->tty->termios->c_cflag; - - /* - * byte size and parity - */ - switch (cflag & CSIZE) - { - case CS5: cval = IRCOMM_WLEN5; break; - case CS6: cval = IRCOMM_WLEN6; break; - case CS7: cval = IRCOMM_WLEN7; break; - case CS8: cval = IRCOMM_WLEN8; break; - default: cval = IRCOMM_WLEN5; break; /* too keep GCC shut... */ - } - if (cflag & CSTOPB) { /* use 2 stop bit mode */ - cval |= IRCOMM_STOP2; - } - if (cflag & PARENB) - cval |= IRCOMM_PARENB; /* enable parity check */ - if (!(cflag & PARODD)) - cval |= IRCOMM_PAREVEN; /* even parity */ - - /* CTS flow control flag and modem status interrupts */ - - if (cflag & CRTSCTS) - driver->comm->flow_ctrl |= USE_CTS; - else - driver->comm->flow_ctrl |= ~USE_CTS; - - if (cflag & CLOCAL) - driver->flags &= ~ASYNC_CHECK_CD; - else - driver->flags |= ASYNC_CHECK_CD; - - /* - * Set up parity check flag - */ - - driver->read_status_mask = LSR_OE; - if (I_INPCK(driver->tty)) - driver->read_status_mask |= LSR_FE | LSR_PE; - if (I_BRKINT(driver->tty) || I_PARMRK(driver->tty)) - driver->read_status_mask |= LSR_BI; - - /* - * Characters to ignore - */ - driver->ignore_status_mask = 0; - if (I_IGNPAR(driver->tty)) - driver->ignore_status_mask |= LSR_PE | LSR_FE; - - if (I_IGNBRK(driver->tty)) { - driver->ignore_status_mask |= LSR_BI; - /* - * If we're ignore parity and break indicators, ignore - * overruns too. (For real raw support). - */ - if (I_IGNPAR(driver->tty)) - driver->ignore_status_mask |= LSR_OE; - } - - driver->comm->data_format = cval; - ircomm_control_request(driver->comm, DATA_FORMAT); - ircomm_control_request(driver->comm, FLOW_CONTROL); -} - - - - -static int irvtd_startup(struct irvtd_cb *driver) -{ - struct ias_object* obj; - struct notify_t irvtd_notify; - - /* FIXME: it should not be hard coded */ - __u8 oct_seq[6] = { 0,1,6,1,1,1 }; - - DEBUG(4,__FUNCTION__"()\n" ); - if(driver->flags & ASYNC_INITIALIZED) - return 0; - - /* - * initialize our tx/rx buffer - */ - - skb_queue_head_init(&driver->rxbuff); - driver->txbuff = dev_alloc_skb(COMM_DEFAULT_SDU_SIZE + COMM_MAX_HEADER_SIZE); - if (!driver->txbuff){ - DEBUG(0,__FUNCTION__"(), alloc_skb failed!\n"); - return -ENOMEM; - } - skb_reserve(driver->txbuff, COMM_MAX_HEADER_SIZE); - - irda_notify_init(&irvtd_notify); - irvtd_notify.data_indication = irvtd_receive_data; - irvtd_notify.connect_confirm = irvtd_connect_confirm; - irvtd_notify.connect_indication = irvtd_connect_indication; - irvtd_notify.disconnect_indication = irvtd_disconnect_indication; - irvtd_notify.flow_indication = irvtd_control_indication; - strncpy( irvtd_notify.name, "ircomm_tty", NOTIFY_MAX_NAME); - irvtd_notify.instance = driver; - - driver->comm = ircomm_open_instance(irvtd_notify); - if (!driver->comm) - return -ENODEV; - - - /* - * Register with LM-IAS as a server - */ - - obj = irias_new_object( "IrDA:IrCOMM", IAS_IRCOMM_ID); - irias_add_integer_attrib( obj, "IrDA:TinyTP:LsapSel", - driver->comm->tsap->stsap_sel ); - - irias_add_octseq_attrib( obj, "Parameters", &oct_seq[0], 6); - irias_insert_object( obj); - - driver->flags |= ASYNC_INITIALIZED; - - if (driver->tty) - clear_bit(TTY_IO_ERROR, &driver->tty->flags); - - change_speed(driver); - - /* - * discover a peer device - */ - if(driver->tty->termios->c_cflag & CRTSCTS) - ircomm_connect_request(driver->comm, NINE_WIRE); - else - ircomm_connect_request(driver->comm, THREE_WIRE); - - /* irvtd_start_timer( driver); */ - - driver->rx_disable = 0; - driver->tx_disable = 1; - driver->disconnect_pend = 0; - return 0; -} - - -int irvtd_open(struct tty_struct * tty, struct file * filp) -{ - struct irvtd_cb *driver; - int retval; - int line; - - DEBUG(4, __FUNCTION__"():\n"); - MOD_INC_USE_COUNT; - - line = MINOR(tty->device) - tty->driver.minor_start; - if ((line <0) || (line >= COMM_MAX_TTY)){ - MOD_DEC_USE_COUNT; - return -ENODEV; - } - - driver = irvtd[line]; - ASSERT(driver != NULL, MOD_DEC_USE_COUNT;return -ENOMEM;); - ASSERT(driver->magic == IRVTD_MAGIC, MOD_DEC_USE_COUNT;return -EINVAL;); - - driver->count++; - - DEBUG(0, __FUNCTION__"():%s%d count %d\n", tty->driver.name, line, - driver->count); - - tty->driver_data = driver; - driver->tty = tty; - - driver->tty->low_latency = (driver->flags & ASYNC_LOW_LATENCY) ? 1 : 0; - - /* - * If the device is in the middle of being closed, then block - * (sleep) until it's done, then exit. - */ - - if (tty_hung_up_p(filp) || - (driver->flags & ASYNC_CLOSING)) { - if (driver->flags & ASYNC_CLOSING) - interruptible_sleep_on(&driver->close_wait); -#ifdef DO_RESTART - if (driver->flags & ASYNC_HUP_NOTIFY) - return -EAGAIN; - else - return -ERESTARTSYS; -#else - return -EAGAIN; -#endif - } - - /* - * start up discovering process and ircomm_layer - */ - - retval = irvtd_startup(driver); - if (retval){ - DEBUG(0, __FUNCTION__"():irvtd_startup returns %d\n",retval); - return retval; - } - - retval = irvtd_block_til_ready(tty, filp, driver); - if (retval){ - DEBUG(0,__FUNCTION__ - "():returning after block_til_ready (errno = %d)\n", retval); - return retval; - } - - driver->session = current->session; - driver->pgrp = current->pgrp; - return 0; -} - - - - - -/* - * ---------------------------------------------------------------------- - * irvtd_close() and friends - * - * most of this function is stolen from serial.c - * ---------------------------------------------------------------------- - */ - -/* - * Function irvtd_wait_until_sent (tty, timeout) - * - * wait until Tx queue of IrTTP is empty - * - */ -static void irvtd_wait_until_sent(struct tty_struct *tty, int timeout) -{ - struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data; - unsigned long orig_jiffies; - - ASSERT(driver != NULL, return;); - ASSERT(driver->magic == IRVTD_MAGIC, return;); - ASSERT(driver->comm != NULL, return;); - - DEBUG(1, __FUNCTION__"():\n"); - if(!tty->closing) - return; /* nothing to do */ - - /* - * at disconnection, we should wait until Tx queue of IrTTP is - * flushed - */ - - ircomm_disconnect_request(driver->comm, NULL, P_NORMAL); - orig_jiffies = jiffies; - - while (driver->comm->tsap->disconnect_pend) { - DEBUG(1, __FUNCTION__"():wait..\n"); - current->state = TASK_INTERRUPTIBLE; - current->counter = 0; /* make us low-priority */ - schedule_timeout(HZ); /* 1sec */ - if (signal_pending(current)) - break; - if (timeout && time_after(jiffies, orig_jiffies + timeout)) - break; - } - current->state = TASK_RUNNING; -} - - -static void irvtd_shutdown(struct irvtd_cb * driver) -{ - unsigned long flags; - - if (!(driver->flags & ASYNC_INITIALIZED)) - return; - - DEBUG(1,__FUNCTION__"()\n"); - - /* - * This comment is written in serial.c: - * - * clear delta_msr_wait queue to avoid mem leaks: we may free the irq - * here so the queue might never be waken up - */ - wake_up_interruptible(&driver->delta_msr_wait); - - /* clear DTR and RTS */ - if (!driver->tty || (driver->tty->termios->c_cflag & HUPCL)) - driver->mcr &= ~(MCR_DTR|MCR_RTS); - - driver->comm->dte = driver->mcr; - ircomm_control_request(driver->comm, DTELINE_STATE ); - - - - save_flags(flags); cli(); /* Disable interrupts */ - - if (driver->tty) - set_bit(TTY_IO_ERROR, &driver->tty->flags); - - del_timer( &driver->tx_timer); - del_timer( &driver->rx_timer); - - irias_delete_object("IrDA:IrCOMM"); - - /* - * Free the transmit buffer here - */ - - while(skb_queue_len(&driver->rxbuff)){ - struct sk_buff *skb; - skb = skb_dequeue( &driver->rxbuff); - dev_kfree_skb(skb); - } - if(driver->txbuff){ - dev_kfree_skb(driver->txbuff); - driver->txbuff = NULL; - } - ircomm_close_instance(driver->comm); - driver->comm = NULL; - driver->flags &= ~ASYNC_INITIALIZED; - restore_flags(flags); -} - -void irvtd_close(struct tty_struct * tty, struct file * filp) -{ - struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data; - int line; - unsigned long flags; - - DEBUG(1, __FUNCTION__"():refcount= %d\n",irvtd_refcount); - - ASSERT(driver != NULL, return;); - ASSERT(driver->magic == IRVTD_MAGIC, return;); - - save_flags(flags);cli(); - - - if(tty_hung_up_p(filp)){ - /* - * upper tty layer caught a HUP signal and called irvtd_hangup() - * before. so we do nothing here. - */ - DEBUG(1, __FUNCTION__"():tty_hung_up_p.\n"); - MOD_DEC_USE_COUNT; - restore_flags(flags); - return; - } - - - line = MINOR(tty->device) - tty->driver.minor_start; - DEBUG(0, __FUNCTION__"():%s%d count %d\n", tty->driver.name, line, - driver->count); - - if ((tty->count == 1) && (driver->count != 1)) { - /* - * Uh, oh. tty->count is 1, which means that the tty - * structure will be freed. Driver->count should always - * be one in these conditions. If it's greater than - * one, we've got real problems, since it means the - * ircomm service layer won't be shutdown. - */ - printk(KERN_ERR"irvtd_close: bad serial port count;" - "tty->count is 1, but driver->count is %d\n", driver->count); - driver->count = 1; - } - if (--driver->count < 0) { - printk(KERN_ERR"irvtd_close: bad count for line%d: %d\n", - line, driver->count); - driver->count = 0; - } - - if (driver->count) { /* do nothing */ - DEBUG(0, __FUNCTION__"():driver->count is not 0\n"); - MOD_DEC_USE_COUNT; - restore_flags(flags); - return; - } - - driver->flags |= ASYNC_CLOSING; - - /* - * Now we wait for the transmit buffer to clear; and we notify - * the line discipline to only process XON/XOFF characters. - */ - tty->closing = 1; - if (driver->closing_wait != ASYNC_CLOSING_WAIT_NONE){ - DEBUG(4, __FUNCTION__"():calling tty_wait_until_sent()\n"); - tty_wait_until_sent(tty, driver->closing_wait); - } - /* - * we can send disconnect_request with P_HIGH since - * tty_wait_until_sent() and irvtd_wait_until_sent() should - * have disconnected the link - */ - ircomm_disconnect_request(driver->comm, NULL, P_HIGH); - - /* - * Now we stop accepting input. - */ - - driver->rx_disable = TRUE; - /* drop ldisc's buffer */ - if (tty->ldisc.flush_buffer) - tty->ldisc.flush_buffer(tty); - - if (tty->driver.flush_buffer) - tty->driver.flush_buffer(driver->tty); - - tty->closing = 0; - driver->tty = NULL; - - if (driver->blocked_open) - { - if (driver->close_delay) { - /* kill time */ - current->state = TASK_INTERRUPTIBLE; - schedule_timeout(driver->close_delay); - } - wake_up_interruptible(&driver->open_wait); - } - irvtd_shutdown(driver); - driver->flags &= ~ASYNC_CLOSING; - wake_up_interruptible(&driver->close_wait); - - MOD_DEC_USE_COUNT; - restore_flags(flags); - DEBUG(4, __FUNCTION__"():done\n"); -} - -/* - * ---------------------------------------------------------------------- - * irvtd_write() and friends - * This routine will be called when something data are passed from - * kernel or user. - * ---------------------------------------------------------------------- - */ - -int irvtd_write(struct tty_struct * tty, int from_user, - const unsigned char *buf, int count) -{ - struct irvtd_cb *driver; - int c = 0; - int wrote = 0; - unsigned long flags; - struct sk_buff *skb; - __u8 *frame; - - ASSERT(tty != NULL, return -EFAULT;); - driver = (struct irvtd_cb *)tty->driver_data; - ASSERT(driver != NULL, return -EFAULT;); - ASSERT(driver->magic == IRVTD_MAGIC, return -EFAULT;); - - DEBUG(4, __FUNCTION__"()\n"); - - save_flags(flags); - while(count > 0){ - cli(); - skb = driver->txbuff; - ASSERT(skb != NULL, break;); - c = MIN(count, (skb_tailroom(skb))); - if (c <= 0) - { - if(!driver->ttp_stoptx) - { - irvtd_send_data_request(driver); - continue; - } - else - break; - } - - /* write to the frame */ - - frame = skb_put(skb,c); - if(from_user){ - copy_from_user(frame,buf,c); - } else - memcpy(frame, buf, c); - - restore_flags(flags); - wrote += c; - count -= c; - buf += c; - } - restore_flags(flags); - irvtd_send_data_request(driver); - return (wrote); -} - -void irvtd_flush_chars(struct tty_struct *tty) -{ - struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data; - ASSERT( driver != NULL, return;); - ASSERT( driver->magic == IRVTD_MAGIC, return;); - - DEBUG(4, __FUNCTION__"()\n"); - irvtd_send_data_request(driver); -} - - -/* - * Function irvtd_put_char (tty, ch) - * - * This routine is called by the kernel to pass a single character. - * If we exausted our buffer,we can ignore the character! - * - */ -void irvtd_put_char(struct tty_struct *tty, unsigned char ch) -{ - __u8 *frame ; - struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data; - struct sk_buff *skb; - unsigned long flags; - - ASSERT(driver != NULL, return;); - DEBUG(4, __FUNCTION__"()\n"); - - - again: - save_flags(flags);cli(); - skb = driver->txbuff; - ASSERT(skb != NULL,return;); - if(!skb_tailroom(skb)) - { - restore_flags(flags); - irvtd_send_data_request(driver); - goto again; - } - ASSERT(skb_tailroom(skb) > 0, return;); - DEBUG(4, "irvtd_put_char(0x%02x) skb_len(%d) room(%d):\n", - (int)ch ,(int)skb->len, - skb_tailroom(skb)); - - /* append a character */ - frame = skb_put(skb,1); - frame[0] = ch; - - restore_flags(flags); - irvtd_start_tx_timer(driver,20); - return; -} - -/* - * Function irvtd_write_room (tty) - * - * This routine returns the room that our buffer has now. - * - */ -int irvtd_write_room(struct tty_struct *tty){ - - int ret; - struct sk_buff *skb = ((struct irvtd_cb *) tty->driver_data)->txbuff; - - ASSERT(skb !=NULL, return 0;); - - ret = skb_tailroom(skb); - - DEBUG(4, __FUNCTION__"(): room is %d bytes\n",ret); - - return(ret); -} - -/* - * Function irvtd_chars_in_buffer (tty) - * - * This function returns how many characters which have not been sent yet - * are still in buffer. - * - */ -int irvtd_chars_in_buffer(struct tty_struct *tty){ - - struct sk_buff *skb; - unsigned long flags; - - DEBUG(4, __FUNCTION__"()\n"); - - save_flags(flags);cli(); - skb = ((struct irvtd_cb *) tty->driver_data)->txbuff; - if(skb == NULL) goto err; - - restore_flags(flags); - return (skb->len ); -err: - ASSERT(skb != NULL, ;); - restore_flags(flags); - return 0; /* why not -EFAULT or such? see driver/char/serial.c */ -} - -/* - * Function irvtd_break (tty, break_state) - * - * Routine which turns the break handling on or off - * - */ -static void irvtd_break(struct tty_struct *tty, int break_state){ - - struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data; - unsigned long flags; - - DEBUG(0, __FUNCTION__"()\n"); - ASSERT(tty->driver_data != NULL, return;); - ASSERT(driver->magic == IRVTD_MAGIC, return;); - - save_flags(flags);cli(); - if (break_state == -1) - { - driver->comm->break_signal = 0x01; - ircomm_control_request(driver->comm, BREAK_SIGNAL); - - } - else - { - driver->comm->break_signal = 0x00; - ircomm_control_request(driver->comm, BREAK_SIGNAL); - - } - - restore_flags(flags); -} - -/* - * ---------------------------------------------------------------------- - * irvtd_ioctl() and friends - * This routine allows us to implement device-specific ioctl's. - * If passed ioctl number (i.e.cmd) is unknown one, we should return - * ENOIOCTLCMD. - * - * TODO: we can't use setserial on IrCOMM because some ioctls are not implemented. - * we should add some ioctls and make some tool which is resemble to setserial. - * ---------------------------------------------------------------------- - */ - -static int get_modem_info(struct irvtd_cb * driver, unsigned int *value) -{ - unsigned int result; - result = ((driver->mcr & MCR_RTS) ? TIOCM_RTS : 0) - | ((driver->mcr & MCR_DTR) ? TIOCM_DTR : 0) - | ((driver->msr & DELTA_DCD) ? TIOCM_CAR : 0) - | ((driver->msr & DELTA_RI) ? TIOCM_RNG : 0) - | ((driver->msr & DELTA_DSR) ? TIOCM_DSR : 0) - | ((driver->msr & DELTA_CTS) ? TIOCM_CTS : 0); - return put_user(result,value); -} - -static int set_modem_info(struct irvtd_cb * driver, unsigned int cmd, - unsigned int *value) -{ - int error; - unsigned int arg; - - error = get_user(arg, value); - if(error) - return error; - - switch (cmd) { - case TIOCMBIS: - if (arg & TIOCM_RTS) - driver->mcr |= MCR_RTS; - if (arg & TIOCM_DTR) - driver->mcr |= MCR_DTR; - break; - - case TIOCMBIC: - if (arg & TIOCM_RTS) - driver->mcr &= ~MCR_RTS; - if (arg & TIOCM_DTR) - driver->mcr &= ~MCR_DTR; - break; - - case TIOCMSET: - driver->mcr = ((driver->mcr & ~(MCR_RTS | MCR_DTR)) - | ((arg & TIOCM_RTS) ? MCR_RTS : 0) - | ((arg & TIOCM_DTR) ? MCR_DTR : 0)); - break; - - default: - return -EINVAL; - } - - driver->comm->dte = driver->mcr; - ircomm_control_request(driver->comm, DTELINE_STATE ); - - return 0; -} - -static int get_serial_info(struct irvtd_cb * driver, - struct serial_struct * retinfo) -{ - struct serial_struct tmp; - - if (!retinfo) - return -EFAULT; - memset(&tmp, 0, sizeof(tmp)); - tmp.line = driver->line; - tmp.flags = driver->flags; - tmp.baud_base = driver->comm->data_rate; - tmp.close_delay = driver->close_delay; - tmp.closing_wait = driver->closing_wait; - - /* for compatibility */ - - tmp.type = PORT_16550A; - tmp.port = 0; - tmp.irq = 0; - tmp.xmit_fifo_size = 0; - tmp.hub6 = 0; - tmp.custom_divisor = driver->custom_divisor; - - if (copy_to_user(retinfo,&tmp,sizeof(*retinfo))) - return -EFAULT; - return 0; -} - -static int set_serial_info(struct irvtd_cb * driver, - struct serial_struct * new_info) -{ - struct serial_struct new_serial; - struct irvtd_cb old_driver; - - if (copy_from_user(&new_serial,new_info,sizeof(new_serial))) - return -EFAULT; - - old_driver = *driver; - - if (!capable(CAP_SYS_ADMIN)) { - if ((new_serial.baud_base != driver->comm->data_rate) || - (new_serial.close_delay != driver->close_delay) || - ((new_serial.flags & ~ASYNC_USR_MASK) != - (driver->flags & ~ASYNC_USR_MASK))) - return -EPERM; - driver->flags = ((driver->flags & ~ASYNC_USR_MASK) | - (new_serial.flags & ASYNC_USR_MASK)); - driver->custom_divisor = new_serial.custom_divisor; - goto check_and_exit; - } - - /* - * OK, past this point, all the error checking has been done. - * At this point, we start making changes..... - */ - - if(driver->comm->data_rate != new_serial.baud_base){ - driver->comm->data_rate = new_serial.baud_base; - if(driver->comm->state == COMM_CONN) - ircomm_control_request(driver->comm,DATA_RATE); - } - driver->close_delay = new_serial.close_delay * HZ/100; - driver->closing_wait = new_serial.closing_wait * HZ/100; - driver->custom_divisor = new_serial.custom_divisor; - - driver->flags = ((driver->flags & ~ASYNC_FLAGS) | - (new_serial.flags & ASYNC_FLAGS)); - driver->tty->low_latency = (driver->flags & ASYNC_LOW_LATENCY) ? 1 : 0; - - check_and_exit: - if (driver->flags & ASYNC_INITIALIZED) { - if (((old_driver.flags & ASYNC_SPD_MASK) != - (driver->flags & ASYNC_SPD_MASK)) || - (old_driver.custom_divisor != driver->custom_divisor)) { - if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) - driver->tty->alt_speed = 57600; - if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) - driver->tty->alt_speed = 115200; - if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) - driver->tty->alt_speed = 230400; - if ((driver->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) - driver->tty->alt_speed = 460800; - change_speed(driver); - } - } - return 0; -} - - - - -int irvtd_ioctl(struct tty_struct *tty, struct file * file, - unsigned int cmd, unsigned long arg) -{ - int error; - unsigned long flags; - struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data; - - struct serial_icounter_struct cnow,cprev; - struct serial_icounter_struct *p_cuser; /* user space */ - - - DEBUG(4,"irvtd_ioctl:requested ioctl(0x%08x)\n",cmd); - -#ifdef IRVTD_DEBUG_IOCTL - { - /* kill time so that debug messages will come slowly */ - save_flags(flags);cli(); - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + HZ/4; /*0.25sec*/ - schedule(); - restore_flags(flags); - } -#endif - - - - if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && - (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGSTRUCT) && - (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { - if (tty->flags & (1 << TTY_IO_ERROR)){ - return -EIO; - } - } - - switch (cmd) { - - case TIOCMGET: - return get_modem_info(driver, (unsigned int *) arg); - - case TIOCMBIS: - case TIOCMBIC: - case TIOCMSET: - return set_modem_info(driver, cmd, (unsigned int *) arg); - case TIOCGSERIAL: - return get_serial_info(driver, (struct serial_struct *) arg); - case TIOCSSERIAL: - return set_serial_info(driver, (struct serial_struct *) arg); - - - case TIOCMIWAIT: - save_flags(flags); cli(); - /* note the counters on entry */ - cprev = driver->icount; - restore_flags(flags); - while (1) { - interruptible_sleep_on(&driver->delta_msr_wait); - /* see if a signal did it */ - if (signal_pending(current)) - return -ERESTARTSYS; - save_flags(flags); cli(); - cnow = driver->icount; /* atomic copy */ - restore_flags(flags); - if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && - cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) - return -EIO; /* no change => error */ - if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || - ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || - ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || - ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { - return 0; - } - cprev = cnow; - } - /* NOTREACHED */ - - case TIOCGICOUNT: - save_flags(flags); cli(); - cnow = driver->icount; - restore_flags(flags); - p_cuser = (struct serial_icounter_struct *) arg; - error = put_user(cnow.cts, &p_cuser->cts); - if (error) return error; - error = put_user(cnow.dsr, &p_cuser->dsr); - if (error) return error; - error = put_user(cnow.rng, &p_cuser->rng); - if (error) return error; - error = put_user(cnow.dcd, &p_cuser->dcd); - if (error) return error; - error = put_user(cnow.rx, &p_cuser->rx); - if (error) return error; - error = put_user(cnow.tx, &p_cuser->tx); - if (error) return error; - error = put_user(cnow.frame, &p_cuser->frame); - if (error) return error; - error = put_user(cnow.overrun, &p_cuser->overrun); - if (error) return error; - error = put_user(cnow.parity, &p_cuser->parity); - if (error) return error; - error = put_user(cnow.brk, &p_cuser->brk); - if (error) return error; - error = put_user(cnow.buf_overrun, &p_cuser->buf_overrun); - if (error) return error; - return 0; - - - /* ioctls which are imcompatible with serial.c */ - - case TIOCSERGSTRUCT: - DEBUG(0,__FUNCTION__"():sorry, TIOCSERGSTRUCT is not supported\n"); - return -ENOIOCTLCMD; - case TIOCSERGETLSR: - DEBUG(0,__FUNCTION__"():sorry, TIOCSERGETLSR is not supported\n"); - return -ENOIOCTLCMD; - case TIOCSERCONFIG: - DEBUG(0,__FUNCTION__"():sorry, TIOCSERCONFIG is not supported\n"); - return -ENOIOCTLCMD; - - - default: - return -ENOIOCTLCMD; /* ioctls which we must ignore */ - } - return 0; -} - - - -/* - * ---------------------------------------------------------------------- - * irvtd_set_termios() - * This is called when termios is changed. - * If things that changed is significant for us,(i.e. changing baud rate etc.) - * send something to peer device. - * ---------------------------------------------------------------------- - */ - -void irvtd_set_termios(struct tty_struct *tty, struct termios * old_termios){ - - struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data; - - ASSERT(driver != NULL,return;); - ASSERT(driver->magic == IRVTD_MAGIC ,return;); - - DEBUG(0, "irvtd_set_termios:\n"); - return; - - if((tty->termios->c_cflag == old_termios->c_cflag) && - (RELEVANT_IFLAG(tty->termios->c_iflag) - == RELEVANT_IFLAG(old_termios->c_iflag))) - return; - - change_speed(driver); - - if((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { - tty->hw_stopped = driver->ttp_stoptx; - /* irvtd_start(tty); */ /* we don't need this */ - } -} - -/* - * ---------------------------------------------------------------------- - * irvtd_throttle,irvtd_unthrottle - * These routines will be called when we have to pause sending up data to tty. - * We use RTS virtual signal when servicetype is NINE_WIRE - * ---------------------------------------------------------------------- - */ - -static void irvtd_send_xchar(struct tty_struct *tty, char ch){ - - DEBUG(1, __FUNCTION__"():\n"); - irvtd_put_char(tty, ch); -} - -void irvtd_throttle(struct tty_struct *tty){ - struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data; - - DEBUG(1, "irvtd_throttle:\n"); - - if (I_IXOFF(tty)) - irvtd_put_char(tty, STOP_CHAR(tty)); - - driver->mcr &= ~MCR_RTS; - driver->mcr |= DELTA_RTS; - driver->comm->dte = driver->mcr; - ircomm_control_request(driver->comm, DTELINE_STATE ); - - DEBUG(1, __FUNCTION__"():FLOW_STOP\n"); - irttp_flow_request(driver->comm->tsap, FLOW_STOP); -} - -void irvtd_unthrottle(struct tty_struct *tty){ - struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data; - DEBUG(1, "irvtd_unthrottle:\n"); - - if (I_IXOFF(tty)) - irvtd_put_char(tty, START_CHAR(tty)); - - driver->mcr |= (MCR_RTS|DELTA_RTS); - driver->comm->dte = driver->mcr; - ircomm_control_request(driver->comm, DTELINE_STATE ); - - DEBUG(1, __FUNCTION__"():FLOW_START\n"); - irttp_flow_request(driver->comm->tsap, FLOW_START); -} - - -/* - * ------------------------------------------------------------ - * irvtd_stop() and irvtd_start() - * - * This routines are called before setting or resetting tty->stopped. - * They enable or disable an interrupt which means "transmitter-is-ready" - * in serial.c, but I think these routine are not necessary for us. - * ------------------------------------------------------------ - */ - -#if 0 -irvtd_stop(struct tty_struct *tty){ - DEBUG(0, "irvtd_stop()\n"); - - struct irvtd_cb *info = (struct irvtd_cb *)tty->driver_data; - DEBUG(0, "irvtd_start():not implemented!\n"); -} -irvtd_start(struct tty_struct *tty){ - - struct irvtd_cb *info = (struct irvtd_cb *)tty->driver_data; - DEBUG(0, "irvtd_start():not_implemented!\n"); -} -#endif - -/* - * ------------------------------------------------------------ - * irvtd_hangup() - * This routine notifies that tty layer have got HUP signal - * ------------------------------------------------------------ - */ - -void irvtd_hangup(struct tty_struct *tty){ - - struct irvtd_cb *info = (struct irvtd_cb *)tty->driver_data; - DEBUG(0, __FUNCTION__"()\n"); - - irvtd_flush_buffer(tty); - irvtd_shutdown(info); - info->count = 0; - info->tty = NULL; - wake_up_interruptible(&info->open_wait); -} - -void irvtd_flush_buffer(struct tty_struct *tty){ - - struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data; - struct sk_buff *skb; - - skb = driver->txbuff; - ASSERT(skb != NULL, return;); - - if(skb->len){ - DEBUG(0, __FUNCTION__"():%d chars in txbuff are lost..\n",(int)skb->len); - skb_trim(skb,0); - } - - /* write_wait is a wait queue of tty_wait_until_sent(). - * see tty_io.c of kernel - */ - wake_up_interruptible(&tty->write_wait); - - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - tty->ldisc.write_wakeup) - (tty->ldisc.write_wakeup)(tty); -} - - - -/* - * Function ircomm_register_device(void), init_module() and friends - * - * we register "port emulation entity"(see IrCOMM specification) here - * as a tty device. - */ - -int irvtd_register_ttydriver(void){ - - DEBUG( 4, "-->irvtd_register_ttydriver\n"); - - /* setup virtual serial port device */ - - /* Initialize the tty_driver structure ,which is defined in - tty_driver.h */ - - memset(&irvtd_drv, 0, sizeof(struct tty_driver)); - irvtd_drv.magic = IRVTD_MAGIC; - irvtd_drv.driver_name = "IrCOMM_tty"; - irvtd_drv.name = "irnine"; - irvtd_drv.major = IRCOMM_MAJOR; - irvtd_drv.minor_start = IRVTD_MINOR; - irvtd_drv.num = COMM_MAX_TTY; - irvtd_drv.type = TTY_DRIVER_TYPE_SERIAL; /* see tty_driver.h */ - - - /* - * see drivers/char/tty_io.c and termios(3) - */ - - irvtd_drv.init_termios = tty_std_termios; - irvtd_drv.init_termios.c_cflag = - B9600 | CS8 | CREAD | HUPCL | CLOCAL; - irvtd_drv.flags = TTY_DRIVER_REAL_RAW; /* see tty_driver.h */ - irvtd_drv.refcount = &irvtd_refcount; - - /* pointer to the tty data structures */ - - irvtd_drv.table = irvtd_table; - irvtd_drv.termios = irvtd_termios; - irvtd_drv.termios_locked = irvtd_termios_locked; - - /* - * Interface table from the kernel(tty driver) to the ircomm - * layer - */ - - irvtd_drv.open = irvtd_open; - irvtd_drv.close = irvtd_close; - irvtd_drv.write = irvtd_write; - irvtd_drv.put_char = irvtd_put_char; - irvtd_drv.flush_chars = irvtd_flush_chars; - irvtd_drv.write_room = irvtd_write_room; - irvtd_drv.chars_in_buffer = irvtd_chars_in_buffer; - irvtd_drv.flush_buffer = irvtd_flush_buffer; - irvtd_drv.ioctl = irvtd_ioctl; - irvtd_drv.throttle = irvtd_throttle; - irvtd_drv.unthrottle = irvtd_unthrottle; - irvtd_drv.set_termios = irvtd_set_termios; - irvtd_drv.stop = NULL; /* irvtd_stop; */ - irvtd_drv.start = NULL; /* irvtd_start; */ - irvtd_drv.hangup = irvtd_hangup; - - irvtd_drv.send_xchar = irvtd_send_xchar; - irvtd_drv.break_ctl = irvtd_break; - irvtd_drv.read_proc = irvtd_read_proc; - irvtd_drv.wait_until_sent = irvtd_wait_until_sent; - - - - if (tty_register_driver(&irvtd_drv)){ - DEBUG(0,"IrCOMM:Couldn't register tty driver\n"); - return(1); - } - - DEBUG( 4, "irvtd_register_ttydriver: done.\n"); - return(0); -} - - -/* - * Function irvtd_unregister_device(void) - * it will be called when you rmmod - */ - -void irvtd_unregister_ttydriver(void){ - - int err; - DEBUG( 4, "--> irvtd_unregister_device\n"); - - /* unregister tty device */ - - err = tty_unregister_driver(&irvtd_drv); - if (err) - printk("IrCOMM: failed to unregister vtd driver(%d)\n",err); - DEBUG( 4, "irvtd_unregister_device -->\n"); - return; -} - -/* - ********************************************************************** - * proc stuff - * - ********************************************************************** - */ - -static int line_info(char *buf, struct irvtd_cb *driver) -{ - int ret=0; - - ASSERT(driver != NULL,goto exit;); - ASSERT(driver->magic == IRVTD_MAGIC,goto exit;); - - ret += sprintf(buf, "tx: %d rx: %d" - ,driver->icount.tx, driver->icount.rx); - - if (driver->icount.frame) - ret += sprintf(buf+ret, " fe:%d", driver->icount.frame); - if (driver->icount.parity) - ret += sprintf(buf+ret, " pe:%d", driver->icount.parity); - if (driver->icount.brk) - ret += sprintf(buf+ret, " brk:%d", driver->icount.brk); - if (driver->icount.overrun) - ret += sprintf(buf+ret, " oe:%d", driver->icount.overrun); - - if (driver->mcr & MCR_RTS) - ret += sprintf(buf+ret, "|RTS"); - if (driver->msr & MSR_CTS) - ret += sprintf(buf+ret, "|CTS"); - if (driver->mcr & MCR_DTR) - ret += sprintf(buf+ret, "|DTR"); - if (driver->msr & MSR_DSR) - ret += sprintf(buf+ret, "|DSR"); - if (driver->msr & MSR_DCD) - ret += sprintf(buf+ret, "|CD"); - if (driver->msr & MSR_RI) - ret += sprintf(buf+ret, "|RI"); - - ret += sprintf(buf+ret, "\n"); - ret += sprintf(buf+ret, "rx queue:%d", - skb_queue_len( &driver->rxbuff)); - ret += sprintf(buf+ret, "ttp_stoprx:%s", - driver->ttp_stoprx?"TRUE":"FALSE"); - - exit: - ret += sprintf(buf+ret, "\n"); - return ret; -} - - - -static int irvtd_read_proc(char *buf, char **start, off_t offset, int len, - int *eof, void *unused) -{ - int i, count = 0, l; - off_t begin = 0; - - count += sprintf(buf, "driver revision:%s\n", revision_date); - for (i = 0; i < COMM_MAX_TTY && count < 4000; i++) { - l = line_info(buf + count, irvtd[i]); - count += l; - if (count+begin > offset+len) - goto done; - if (count+begin < offset) { - begin += count; - count = 0; - } - } - *eof = 1; -done: - if (offset >= count+begin) - return 0; - *start = buf + (begin-offset); - return ((len < begin+count-offset) ? len : begin+count-offset); -} - - - - -/************************************************************ - * init & cleanup this module - ************************************************************/ - -__initfunc(int irvtd_init(void)) -{ - int i; - - DEBUG( 4, __FUNCTION__"()\n"); - printk( KERN_INFO - "ircomm_tty: virtual tty driver for IrCOMM ( revision:%s )\n", - revision_date); - - - /* allocate a master array */ - - irvtd = (struct irvtd_cb **) kmalloc( sizeof(void *) * - COMM_MAX_TTY,GFP_KERNEL); - if ( irvtd == NULL) { - printk( KERN_WARNING __FUNCTION__"(): kmalloc failed!\n"); - return -ENOMEM; - } - - memset( irvtd, 0, sizeof(void *) * COMM_MAX_TTY); - - for (i=0; i < COMM_MAX_TTY; i++){ - irvtd[i] = kmalloc( sizeof(struct irvtd_cb), GFP_KERNEL); - if(irvtd[i] == NULL){ - printk(KERN_ERR __FUNCTION__"(): kmalloc failed!\n"); - return -ENOMEM; - } - memset( irvtd[i], 0, sizeof(struct irvtd_cb)); - irvtd[i]->magic = IRVTD_MAGIC; - irvtd[i]->line = i; - irvtd[i]->closing_wait = 10*HZ ; - irvtd[i]->close_delay = 5*HZ/10 ; - init_waitqueue_head(&irvtd[i]->open_wait); - init_waitqueue_head(&irvtd[i]->close_wait); - init_waitqueue_head(&irvtd[i]->tx_wait); - init_waitqueue_head(&irvtd[i]->delta_msr_wait); - } - - /* - * initialize a "port emulation entity" - */ - - if(irvtd_register_ttydriver()){ - printk( KERN_WARNING "IrCOMM: Error in ircomm_register_device\n"); - return -ENODEV; - } - - return 0; -} - -void irvtd_cleanup(void) -{ - int i; - DEBUG( 4, __FUNCTION__"()\n"); - - /* - * free some resources - */ - if (irvtd) { - for (i=0; i<COMM_MAX_TTY; i++) { - if (irvtd[i]) { - if(irvtd[i]->comm) - ircomm_close_instance(irvtd[i]->comm); - if(irvtd[i]->txbuff) - dev_kfree_skb(irvtd[i]->txbuff); - DEBUG( 4, "freeing structures\n"); - kfree(irvtd[i]); - irvtd[i] = NULL; - } - } - DEBUG( 4, "freeing master array\n"); - kfree(irvtd); - irvtd = NULL; - } - - irvtd_unregister_ttydriver(); - -} - -#ifdef MODULE - -int init_module(void) -{ - irvtd_init(); - return 0; -} - -/* - * Function ircomm_cleanup (void) - * This is called when you rmmod. - */ - -void cleanup_module(void) -{ - irvtd_cleanup(); -} - -#endif /* MODULE */ |