📄 ircomm_tty.c
字号:
if (self->tx_skb) len = self->tx_skb->len; restore_flags(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, __FUNCTION__ "()\n"); if (!(self->flags & ASYNC_INITIALIZED)) return; save_flags(flags); cli(); 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; } ircomm_tty_detach_cable(self); if (self->ircomm) { ircomm_close(self->ircomm); self->ircomm = NULL; } self->flags &= ~ASYNC_INITIALIZED; restore_flags(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; IRDA_DEBUG(0, __FUNCTION__"()\n"); ASSERT(self != NULL, return;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); if (!tty) return; /* ircomm_tty_flush_buffer(tty); */ ircomm_tty_shutdown(self); self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); self->tty = 0; self->open_count = 0; 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, __FUNCTION__"(), not impl\n");}/* * 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, __FUNCTION__ "()\n"); 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, __FUNCTION__ "(), ircomm%d CD now %s...\n", self->line, (status & IRCOMM_CD) ? "on" : "off"); if (status & IRCOMM_CD) { wake_up_interruptible(&self->open_wait); } else if (!((self->flags & ASYNC_CALLOUT_ACTIVE) && (self->flags & ASYNC_CALLOUT_NOHUP))) { IRDA_DEBUG(2, __FUNCTION__ "(), Doing serial hangup..\n"); 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, __FUNCTION__ "(), CTS tx start...\n"); tty->hw_stopped = 0; /* Wake up processes blocked on open */ wake_up_interruptible(&self->open_wait); queue_task(&self->tqueue, &tq_immediate); mark_bh(IMMEDIATE_BH); return; } } else { if (!(status & IRCOMM_CTS)) { IRDA_DEBUG(2, __FUNCTION__ "(), CTS tx stop...\n"); tty->hw_stopped = 1; } } }}/* * Function ircomm_tty_data_indication (instance, sap, skb) * * Handle incomming 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, __FUNCTION__"()\n"); ASSERT(self != NULL, return -1;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); ASSERT(skb != NULL, return -1;); if (!self->tty) { IRDA_DEBUG(0, __FUNCTION__ "(), no tty!\n"); dev_kfree_skb(skb); 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, __FUNCTION__ "(), polling for line settings!\n"); 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); dev_kfree_skb(skb); return 0;}/* * Function ircomm_tty_control_indication (instance, sap, skb) * * Parse all incomming 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, __FUNCTION__"()\n"); 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); dev_kfree_skb(skb); 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, __FUNCTION__ "(), hw start!\n"); tty->hw_stopped = 0; /* ircomm_tty_do_softint will take care of the rest */ queue_task(&self->tqueue, &tq_immediate); mark_bh(IMMEDIATE_BH); break; default: /* If we get here, something is very wrong, better stop */ case FLOW_STOP: IRDA_DEBUG(2, __FUNCTION__ "(), hw stopped!\n"); 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 & ASYNC_CALLOUT_ACTIVE) ret += sprintf(buf+ret, "ASYNC_CALLOUT_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; self = (struct ircomm_tty_cb *) hashbin_get_first(ircomm_tty); while ((self != NULL) && (count < 4000)) { if (self->magic != IRCOMM_TTY_MAGIC) return 0; 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: if (offset >= count+begin) return 0; *start = buf + (offset-begin); return ((len < begin+count-offset) ? len : begin+count-offset);}#endif /* CONFIG_PROC_FS */#ifdef MODULEMODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");MODULE_DESCRIPTION("IrCOMM serial TTY driver");int init_module(void) { return ircomm_tty_init();}void cleanup_module(void){ ircomm_tty_cleanup();}#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -