?? ircomm_tty.c
字號:
self->settings.dte |= (IRCOMM_RTS|IRCOMM_DELTA_RTS); ircomm_param_request(self, IRCOMM_DTE, TRUE); IRDA_DEBUG(1, "%s(), FLOW_START\n", __FUNCTION__ ); } ircomm_flow_request(self->ircomm, FLOW_START);}/* * Function ircomm_tty_chars_in_buffer (tty) * * Indicates if there are any data in the buffer * */static int ircomm_tty_chars_in_buffer(struct tty_struct *tty){ struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; unsigned long flags; int len = 0; ASSERT(self != NULL, return -1;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); spin_lock_irqsave(&self->spinlock, flags); if (self->tx_skb) len = self->tx_skb->len; spin_unlock_irqrestore(&self->spinlock, flags); return len;}static void ircomm_tty_shutdown(struct ircomm_tty_cb *self){ unsigned long flags; ASSERT(self != NULL, return;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); if (!test_and_clear_bit(ASYNC_B_INITIALIZED, &self->flags)) return; ircomm_tty_detach_cable(self); spin_lock_irqsave(&self->spinlock, flags); del_timer(&self->watchdog_timer); /* Free parameter buffer */ if (self->ctrl_skb) { dev_kfree_skb(self->ctrl_skb); self->ctrl_skb = NULL; } /* Free transmit buffer */ if (self->tx_skb) { dev_kfree_skb(self->tx_skb); self->tx_skb = NULL; } if (self->ircomm) { ircomm_close(self->ircomm); self->ircomm = NULL; } spin_unlock_irqrestore(&self->spinlock, flags);}/* * Function ircomm_tty_hangup (tty) * * This routine notifies the tty driver that it should hangup the tty * device. * */static void ircomm_tty_hangup(struct tty_struct *tty){ struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; unsigned long flags; IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); ASSERT(self != NULL, return;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); if (!tty) return; /* ircomm_tty_flush_buffer(tty); */ ircomm_tty_shutdown(self); /* I guess we need to lock here - Jean II */ spin_lock_irqsave(&self->spinlock, flags); self->flags &= ~ASYNC_NORMAL_ACTIVE; self->tty = NULL; self->open_count = 0; spin_unlock_irqrestore(&self->spinlock, flags); wake_up_interruptible(&self->open_wait);}/* * Function ircomm_tty_send_xchar (tty, ch) * * This routine is used to send a high-priority XON/XOFF character to * the device. */static void ircomm_tty_send_xchar(struct tty_struct *tty, char ch){ IRDA_DEBUG(0, "%s(), not impl\n", __FUNCTION__ );}/* * Function ircomm_tty_start (tty) * * This routine notifies the tty driver that it resume sending * characters to the tty device. */void ircomm_tty_start(struct tty_struct *tty){ struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; ircomm_flow_request(self->ircomm, FLOW_START);}/* * Function ircomm_tty_stop (tty) * * This routine notifies the tty driver that it should stop outputting * characters to the tty device. */void ircomm_tty_stop(struct tty_struct *tty) { struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; ASSERT(self != NULL, return;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); ircomm_flow_request(self->ircomm, FLOW_STOP);}/* * Function ircomm_check_modem_status (self) * * Check for any changes in the DCE's line settings. This function should * be called whenever the dce parameter settings changes, to update the * flow control settings and other things */void ircomm_tty_check_modem_status(struct ircomm_tty_cb *self){ struct tty_struct *tty; int status; IRDA_DEBUG(0, "%s()\n", __FUNCTION__ ); ASSERT(self != NULL, return;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); tty = self->tty; status = self->settings.dce; if (status & IRCOMM_DCE_DELTA_ANY) { /*wake_up_interruptible(&self->delta_msr_wait);*/ } if ((self->flags & ASYNC_CHECK_CD) && (status & IRCOMM_DELTA_CD)) { IRDA_DEBUG(2, "%s(), ircomm%d CD now %s...\n", __FUNCTION__ , self->line, (status & IRCOMM_CD) ? "on" : "off"); if (status & IRCOMM_CD) { wake_up_interruptible(&self->open_wait); } else { IRDA_DEBUG(2, "%s(), Doing serial hangup..\n", __FUNCTION__ ); if (tty) tty_hangup(tty); /* Hangup will remote the tty, so better break out */ return; } } if (self->flags & ASYNC_CTS_FLOW) { if (tty->hw_stopped) { if (status & IRCOMM_CTS) { IRDA_DEBUG(2, "%s(), CTS tx start...\n", __FUNCTION__ ); tty->hw_stopped = 0; /* Wake up processes blocked on open */ wake_up_interruptible(&self->open_wait); schedule_work(&self->tqueue); return; } } else { if (!(status & IRCOMM_CTS)) { IRDA_DEBUG(2, "%s(), CTS tx stop...\n", __FUNCTION__ ); tty->hw_stopped = 1; } } }}/* * Function ircomm_tty_data_indication (instance, sap, skb) * * Handle incoming data, and deliver it to the line discipline * */static int ircomm_tty_data_indication(void *instance, void *sap, struct sk_buff *skb){ struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; IRDA_DEBUG(2, "%s()\n", __FUNCTION__ ); ASSERT(self != NULL, return -1;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); ASSERT(skb != NULL, return -1;); if (!self->tty) { IRDA_DEBUG(0, "%s(), no tty!\n", __FUNCTION__ ); return 0; } /* * If we receive data when hardware is stopped then something is wrong. * We try to poll the peers line settings to check if we are up todate. * Devices like WinCE can do this, and since they don't send any * params, we can just as well declare the hardware for running. */ if (self->tty->hw_stopped && (self->flow == FLOW_START)) { IRDA_DEBUG(0, "%s(), polling for line settings!\n", __FUNCTION__ ); ircomm_param_request(self, IRCOMM_POLL, TRUE); /* We can just as well declare the hardware for running */ ircomm_tty_send_initial_parameters(self); ircomm_tty_link_established(self); } /* * Just give it over to the line discipline. There is no need to * involve the flip buffers, since we are not running in an interrupt * handler */ self->tty->ldisc.receive_buf(self->tty, skb->data, NULL, skb->len); /* No need to kfree_skb - see ircomm_ttp_data_indication() */ return 0;}/* * Function ircomm_tty_control_indication (instance, sap, skb) * * Parse all incoming parameters (easy!) * */static int ircomm_tty_control_indication(void *instance, void *sap, struct sk_buff *skb){ struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; int clen; IRDA_DEBUG(4, "%s()\n", __FUNCTION__ ); ASSERT(self != NULL, return -1;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); ASSERT(skb != NULL, return -1;); clen = skb->data[0]; irda_param_extract_all(self, skb->data+1, IRDA_MIN(skb->len-1, clen), &ircomm_param_info); /* No need to kfree_skb - see ircomm_control_indication() */ return 0;}/* * Function ircomm_tty_flow_indication (instance, sap, cmd) * * This function is called by IrTTP when it wants us to slow down the * transmission of data. We just mark the hardware as stopped, and wait * for IrTTP to notify us that things are OK again. */static void ircomm_tty_flow_indication(void *instance, void *sap, LOCAL_FLOW cmd){ struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) instance; struct tty_struct *tty; ASSERT(self != NULL, return;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); tty = self->tty; switch (cmd) { case FLOW_START: IRDA_DEBUG(2, "%s(), hw start!\n", __FUNCTION__ ); tty->hw_stopped = 0; /* ircomm_tty_do_softint will take care of the rest */ schedule_work(&self->tqueue); break; default: /* If we get here, something is very wrong, better stop */ case FLOW_STOP: IRDA_DEBUG(2, "%s(), hw stopped!\n", __FUNCTION__ ); tty->hw_stopped = 1; break; } self->flow = cmd;}static int ircomm_tty_line_info(struct ircomm_tty_cb *self, char *buf){ int ret=0; ret += sprintf(buf+ret, "State: %s\n", ircomm_tty_state[self->state]); ret += sprintf(buf+ret, "Service type: "); if (self->service_type & IRCOMM_9_WIRE) ret += sprintf(buf+ret, "9_WIRE"); else if (self->service_type & IRCOMM_3_WIRE) ret += sprintf(buf+ret, "3_WIRE"); else if (self->service_type & IRCOMM_3_WIRE_RAW) ret += sprintf(buf+ret, "3_WIRE_RAW"); else ret += sprintf(buf+ret, "No common service type!\n"); ret += sprintf(buf+ret, "\n"); ret += sprintf(buf+ret, "Port name: %s\n", self->settings.port_name); ret += sprintf(buf+ret, "DTE status: "); if (self->settings.dte & IRCOMM_RTS) ret += sprintf(buf+ret, "RTS|"); if (self->settings.dte & IRCOMM_DTR) ret += sprintf(buf+ret, "DTR|"); if (self->settings.dte) ret--; /* remove the last | */ ret += sprintf(buf+ret, "\n"); ret += sprintf(buf+ret, "DCE status: "); if (self->settings.dce & IRCOMM_CTS) ret += sprintf(buf+ret, "CTS|"); if (self->settings.dce & IRCOMM_DSR) ret += sprintf(buf+ret, "DSR|"); if (self->settings.dce & IRCOMM_CD) ret += sprintf(buf+ret, "CD|"); if (self->settings.dce & IRCOMM_RI) ret += sprintf(buf+ret, "RI|"); if (self->settings.dce) ret--; /* remove the last | */ ret += sprintf(buf+ret, "\n"); ret += sprintf(buf+ret, "Configuration: "); if (!self->settings.null_modem) ret += sprintf(buf+ret, "DTE <-> DCE\n"); else ret += sprintf(buf+ret, "DTE <-> DTE (null modem emulation)\n"); ret += sprintf(buf+ret, "Data rate: %d\n", self->settings.data_rate); ret += sprintf(buf+ret, "Flow control: "); if (self->settings.flow_control & IRCOMM_XON_XOFF_IN) ret += sprintf(buf+ret, "XON_XOFF_IN|"); if (self->settings.flow_control & IRCOMM_XON_XOFF_OUT) ret += sprintf(buf+ret, "XON_XOFF_OUT|"); if (self->settings.flow_control & IRCOMM_RTS_CTS_IN) ret += sprintf(buf+ret, "RTS_CTS_IN|"); if (self->settings.flow_control & IRCOMM_RTS_CTS_OUT) ret += sprintf(buf+ret, "RTS_CTS_OUT|"); if (self->settings.flow_control & IRCOMM_DSR_DTR_IN) ret += sprintf(buf+ret, "DSR_DTR_IN|"); if (self->settings.flow_control & IRCOMM_DSR_DTR_OUT) ret += sprintf(buf+ret, "DSR_DTR_OUT|"); if (self->settings.flow_control & IRCOMM_ENQ_ACK_IN) ret += sprintf(buf+ret, "ENQ_ACK_IN|"); if (self->settings.flow_control & IRCOMM_ENQ_ACK_OUT) ret += sprintf(buf+ret, "ENQ_ACK_OUT|"); if (self->settings.flow_control) ret--; /* remove the last | */ ret += sprintf(buf+ret, "\n"); ret += sprintf(buf+ret, "Flags: "); if (self->flags & ASYNC_CTS_FLOW) ret += sprintf(buf+ret, "ASYNC_CTS_FLOW|"); if (self->flags & ASYNC_CHECK_CD) ret += sprintf(buf+ret, "ASYNC_CHECK_CD|"); if (self->flags & ASYNC_INITIALIZED) ret += sprintf(buf+ret, "ASYNC_INITIALIZED|"); if (self->flags & ASYNC_LOW_LATENCY) ret += sprintf(buf+ret, "ASYNC_LOW_LATENCY|"); if (self->flags & ASYNC_CLOSING) ret += sprintf(buf+ret, "ASYNC_CLOSING|"); if (self->flags & ASYNC_NORMAL_ACTIVE) ret += sprintf(buf+ret, "ASYNC_NORMAL_ACTIVE|"); if (self->flags) ret--; /* remove the last | */ ret += sprintf(buf+ret, "\n"); ret += sprintf(buf+ret, "Role: %s\n", self->client ? "client" : "server"); ret += sprintf(buf+ret, "Open count: %d\n", self->open_count); ret += sprintf(buf+ret, "Max data size: %d\n", self->max_data_size); ret += sprintf(buf+ret, "Max header size: %d\n", self->max_header_size); if (self->tty) ret += sprintf(buf+ret, "Hardware: %s\n", self->tty->hw_stopped ? "Stopped" : "Running"); ret += sprintf(buf+ret, "\n"); return ret;}/* * Function ircomm_tty_read_proc (buf, start, offset, len, eof, unused) * * * */#ifdef CONFIG_PROC_FSstatic int ircomm_tty_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *unused){ struct ircomm_tty_cb *self; int count = 0, l; off_t begin = 0; unsigned long flags; spin_lock_irqsave(&ircomm_tty->hb_spinlock, flags); self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty); while ((self != NULL) && (count < 4000)) { if (self->magic != IRCOMM_TTY_MAGIC) break; l = ircomm_tty_line_info(self, buf + count); count += l; if (count+begin > offset+len) goto done; if (count+begin < offset) { begin += count; count = 0; } self = (struct ircomm_tty_cb *) hashbin_get_next(ircomm_tty); } *eof = 1;done: spin_unlock_irqrestore(&ircomm_tty->hb_spinlock, flags); if (offset >= count+begin) return 0; *start = buf + (offset-begin); return ((len < begin+count-offset) ? len : begin+count-offset);}#endif /* CONFIG_PROC_FS */MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");MODULE_DESCRIPTION("IrCOMM serial TTY driver");MODULE_LICENSE("GPL");MODULE_ALIAS_CHARDEV_MAJOR(IRCOMM_TTY_MAJOR);module_init(ircomm_tty_init);module_exit(ircomm_tty_cleanup);
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -