📄 ircomm_tty.c
字号:
-EAGAIN : -ERESTARTSYS);#else return -EAGAIN;#endif } /* Check if this is a "normal" ircomm device, or an irlpt device */ if (line < 0x10) { self->service_type = IRCOMM_3_WIRE | IRCOMM_9_WIRE; self->settings.service_type = IRCOMM_9_WIRE; /* Default */ IRDA_DEBUG(2, __FUNCTION__ "(), IrCOMM device\n"); } else { IRDA_DEBUG(2, __FUNCTION__ "(), IrLPT device\n"); self->service_type = IRCOMM_3_WIRE_RAW; self->settings.service_type = IRCOMM_3_WIRE_RAW; /* Default */ } ret = ircomm_tty_startup(self); if (ret) return ret; ret = ircomm_tty_block_til_ready(self, filp); if (ret) { /* MOD_DEC_USE_COUNT; "info->tty" will cause this? */ IRDA_DEBUG(2, __FUNCTION__ "(), returning after block_til_ready with %d\n", ret); return ret; } self->session = current->session; self->pgrp = current->pgrp; return 0;}/* * Function ircomm_tty_close (tty, filp) * * This routine is called when a particular tty device is closed. * */static void ircomm_tty_close(struct tty_struct *tty, struct file *filp){ struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; unsigned long flags; IRDA_DEBUG(0, __FUNCTION__ "()\n"); if (!tty) return; save_flags(flags); cli(); if (tty_hung_up_p(filp)) { MOD_DEC_USE_COUNT; restore_flags(flags); IRDA_DEBUG(0, __FUNCTION__ "(), returning 1\n"); return; } ASSERT(self != NULL, return;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); if ((tty->count == 1) && (self->open_count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. state->count should always * be one in these conditions. If it's greater than * one, we've got real problems, since it means the * serial port won't be shutdown. */ IRDA_DEBUG(0, __FUNCTION__ "(), bad serial port count; " "tty->count is 1, state->count is %d\n", self->open_count); self->open_count = 1; } if (--self->open_count < 0) { ERROR(__FUNCTION__ "(), bad serial port count for ttys%d: %d\n", self->line, self->open_count); self->open_count = 0; } if (self->open_count) { MOD_DEC_USE_COUNT; restore_flags(flags); IRDA_DEBUG(0, __FUNCTION__ "(), open count > 0\n"); return; } self->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 (self->closing_wait != ASYNC_CLOSING_WAIT_NONE) tty_wait_until_sent(tty, self->closing_wait); ircomm_tty_shutdown(self); if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); tty->closing = 0; self->tty = 0; if (self->blocked_open) { if (self->close_delay) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(self->close_delay); } wake_up_interruptible(&self->open_wait); } self->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| ASYNC_CLOSING); wake_up_interruptible(&self->close_wait); MOD_DEC_USE_COUNT; restore_flags(flags);}/* * Function ircomm_tty_flush_buffer (tty) * * * */static void ircomm_tty_flush_buffer(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;); /* * Let do_softint() do this to avoid race condition with * do_softint() ;-) */ queue_task(&self->tqueue, &tq_immediate); mark_bh(IMMEDIATE_BH);}/* * Function ircomm_tty_do_softint (private_) * * We use this routine to give the write wakeup to the user at at a * safe time (as fast as possible after write have completed). This * can be compared to the Tx interrupt. */static void ircomm_tty_do_softint(void *private_){ struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) private_; struct tty_struct *tty; unsigned long flags; struct sk_buff *skb, *ctrl_skb; IRDA_DEBUG(2, __FUNCTION__ "()\n"); if (!self || self->magic != IRCOMM_TTY_MAGIC) return; tty = self->tty; if (!tty) return; /* Unlink control buffer */ save_flags(flags); cli(); ctrl_skb = self->ctrl_skb; self->ctrl_skb = NULL; restore_flags(flags); /* Flush control buffer if any */ if (ctrl_skb && self->flow == FLOW_START) ircomm_control_request(self->ircomm, ctrl_skb); if (tty->hw_stopped) return; /* Unlink transmit buffer */ save_flags(flags); cli(); skb = self->tx_skb; self->tx_skb = NULL; restore_flags(flags); /* Flush transmit buffer if any */ if (skb) ircomm_tty_do_event(self, IRCOMM_TTY_DATA_REQUEST, skb, NULL); /* Check if user (still) wants to be waken up */ if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) { (tty->ldisc.write_wakeup)(tty); } wake_up_interruptible(&tty->write_wait);}/* * Function ircomm_tty_write (tty, from_user, buf, count) * * This routine is called by the kernel to write a series of characters * to the tty device. The characters may come from user space or kernel * space. This routine will return the number of characters actually * accepted for writing. This routine is mandatory. */static int ircomm_tty_write(struct tty_struct *tty, int from_user, const unsigned char *buf, int count){ struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; unsigned long flags; struct sk_buff *skb; int tailroom = 0; int len = 0; int size; IRDA_DEBUG(2, __FUNCTION__ "(), count=%d, hw_stopped=%d\n", count, tty->hw_stopped); ASSERT(self != NULL, return -1;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); save_flags(flags); cli(); /* Fetch current transmit buffer */ skb = self->tx_skb; /* * Send out all the data we get, possibly as multiple fragmented * frames, but this will only happen if the data is larger than the * max data size. The normal case however is just the opposite, and * this function may be called multiple times, and will then actually * defragment the data and send it out as one packet as soon as * possible, but at a safer point in time */ while (count) { size = count; /* Adjust data size to the max data size */ if (size > self->max_data_size) size = self->max_data_size; /* * Do we already have a buffer ready for transmit, or do * we need to allocate a new frame */ if (skb) { /* * Any room for more data at the end of the current * transmit buffer? Cannot use skb_tailroom, since * dev_alloc_skb gives us a larger skb than we * requested */ if ((tailroom = (self->max_data_size-skb->len)) > 0) { /* Adjust data to tailroom */ if (size > tailroom) size = tailroom; } else { /* * Current transmit frame is full, so break * out, so we can send it as soon as possible */ break; } } else { /* Prepare a full sized frame */ skb = dev_alloc_skb(self->max_data_size+ self->max_header_size); if (!skb) { restore_flags(flags); return -ENOBUFS; } skb_reserve(skb, self->max_header_size); self->tx_skb = skb; } /* Copy data */ if (from_user) copy_from_user(skb_put(skb,size), buf+len, size); else memcpy(skb_put(skb,size), buf+len, size); count -= size; len += size; } restore_flags(flags); /* * Schedule a new thread which will transmit the frame as soon * as possible, but at a safe point in time. We do this so the * "user" can give us data multiple times, as PPP does (because of * its 256 byte tx buffer). We will then defragment and send out * all this data as one single packet. */ queue_task(&self->tqueue, &tq_immediate); mark_bh(IMMEDIATE_BH); return len;}/* * Function ircomm_tty_write_room (tty) * * This routine returns the numbers of characters the tty driver will * accept for queuing to be written. This number is subject to change as * output buffers get emptied, or if the output flow control is acted. */static int ircomm_tty_write_room(struct tty_struct *tty){ struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; unsigned long flags; int ret; ASSERT(self != NULL, return -1;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return -1;); /* Check if we are allowed to transmit any data */ if (tty->hw_stopped) ret = 0; else { save_flags(flags); cli(); if (self->tx_skb) ret = self->max_data_size - self->tx_skb->len; else ret = self->max_data_size; restore_flags(flags); } IRDA_DEBUG(2, __FUNCTION__ "(), ret=%d\n", ret); return ret;}/* * Function ircomm_tty_wait_until_sent (tty, timeout) * * This routine waits until the device has written out all of the * characters in its transmitter FIFO. */static void ircomm_tty_wait_until_sent(struct tty_struct *tty, int timeout){ struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; unsigned long orig_jiffies, poll_time; IRDA_DEBUG(2, __FUNCTION__ "()\n"); ASSERT(self != NULL, return;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); orig_jiffies = jiffies; /* Set poll time to 200 ms */ poll_time = IRDA_MIN(timeout, MSECS_TO_JIFFIES(200)); while (self->tx_skb && self->tx_skb->len) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(poll_time); if (signal_pending(current)) break; if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; } current->state = TASK_RUNNING;}/* * Function ircomm_tty_throttle (tty) * * This routine notifies the tty driver that input buffers for the line * discipline are close to full, and it should somehow signal that no * more characters should be sent to the tty. */static void ircomm_tty_throttle(struct tty_struct *tty){ struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; IRDA_DEBUG(2, __FUNCTION__ "()\n"); ASSERT(self != NULL, return;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); /* Software flow control? */ if (I_IXOFF(tty)) ircomm_tty_send_xchar(tty, STOP_CHAR(tty)); /* Hardware flow control? */ if (tty->termios->c_cflag & CRTSCTS) { self->settings.dte &= ~IRCOMM_RTS; self->settings.dte |= IRCOMM_DELTA_RTS; ircomm_param_request(self, IRCOMM_DTE, TRUE); } ircomm_flow_request(self->ircomm, FLOW_STOP);}/* * Function ircomm_tty_unthrottle (tty) * * This routine notifies the tty drivers that it should signals that * characters can now be sent to the tty without fear of overrunning the * input buffers of the line disciplines. */static void ircomm_tty_unthrottle(struct tty_struct *tty){ struct ircomm_tty_cb *self = (struct ircomm_tty_cb *) tty->driver_data; IRDA_DEBUG(2, __FUNCTION__ "()\n"); ASSERT(self != NULL, return;); ASSERT(self->magic == IRCOMM_TTY_MAGIC, return;); /* Using software flow control? */ if (I_IXOFF(tty)) { ircomm_tty_send_xchar(tty, START_CHAR(tty)); } /* Using hardware flow control? */ if (tty->termios->c_cflag & CRTSCTS) { self->settings.dte |= (IRCOMM_RTS|IRCOMM_DELTA_RTS); ircomm_param_request(self, IRCOMM_DTE, TRUE); IRDA_DEBUG(1, __FUNCTION__"(), FLOW_START\n"); } 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;); save_flags(flags); cli();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -