/* n_hdlc_release() * * release an n_hdlc per device line discipline info structure * */ static void n_hdlc_release (struct n_hdlc *n_hdlc) { struct tty_struct *tty = n_hdlc2tty (n_hdlc); N_HDLC_BUF *buf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_release() called\n",__FILE__,__LINE__); /* Ensure that the n_hdlcd process is not hanging on select()/poll() */ wake_up_interruptible (&n_hdlc->read_wait); wake_up_interruptible (&n_hdlc->poll_wait); wake_up_interruptible (&n_hdlc->write_wait); if (tty != NULL && tty->disc_data == n_hdlc) tty->disc_data = NULL; /* Break the tty->n_hdlc link */ /* Release transmit and receive buffers */ for(;;) { buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list); if (buf) { kfree(buf); } else break; } for(;;) { buf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list); if (buf) { kfree(buf); } else break; } for(;;) { buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list); if (buf) { kfree(buf); } else break; } for(;;) { buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); if (buf) { kfree(buf); } else break; } kfree(n_hdlc); } /* end of n_hdlc_release() */
static void n_hdlc_release(struct n_hdlc *n_hdlc) { struct tty_struct *tty = n_hdlc2tty (n_hdlc); struct n_hdlc_buf *buf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_release() called\n",__FILE__,__LINE__); wake_up_interruptible (&tty->read_wait); wake_up_interruptible (&tty->write_wait); if (tty->disc_data == n_hdlc) tty->disc_data = NULL; for(;;) { buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list); if (buf) { kfree(buf); } else break; } for(;;) { buf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list); if (buf) { kfree(buf); } else break; } for(;;) { buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list); if (buf) { kfree(buf); } else break; } for(;;) { buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); if (buf) { kfree(buf); } else break; } kfree(n_hdlc->tbuf); kfree(n_hdlc); }
static void flush_rx_queue(struct tty_struct *tty) { struct n_hdlc *n_hdlc = tty2n_hdlc(tty); struct n_hdlc_buf *buf; while ((buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list))) n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, buf); }
/* n_hdlc_tty_receive() * * Called by tty low level driver when receive data is * available. Data is interpreted as one HDLC frame. * * Arguments: tty pointer to tty isntance data * data pointer to received data * flags pointer to flags for data * count count of received data in bytes * * Return Value: None */ static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 * data, char *flags, int count) { register struct n_hdlc *n_hdlc = tty2n_hdlc (tty); register N_HDLC_BUF *buf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_receive() called count=%d\n", __FILE__,__LINE__, count); /* This can happen if stuff comes in on the backup tty */ if (n_hdlc == 0 || tty != n_hdlc->tty) return; /* verify line is using HDLC discipline */ if (n_hdlc->magic != HDLC_MAGIC) { printk("%s(%d) line not using HDLC discipline\n", __FILE__,__LINE__); return; } if ( count>maxframe ) { if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d) rx count>maxframesize, data discarded\n", __FILE__,__LINE__); return; } /* get a free HDLC buffer */ buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list); if (!buf) { /* no buffers in free list, attempt to allocate another rx buffer */ /* unless the maximum count has been reached */ if (n_hdlc->rx_buf_list.count < MAX_RX_BUF_COUNT) buf = (N_HDLC_BUF*)kmalloc(N_HDLC_BUF_SIZE,GFP_ATOMIC); } if (!buf) { if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d) no more rx buffers, data discarded\n", __FILE__,__LINE__); return; } /* copy received data to HDLC buffer */ memcpy(buf->buf,data,count); buf->count=count; /* add HDLC buffer to list of received frames */ n_hdlc_buf_put(&n_hdlc->rx_buf_list,buf); /* wake up any blocked reads and perform async signalling */ wake_up_interruptible (&n_hdlc->read_wait); wake_up_interruptible (&n_hdlc->poll_wait); if (n_hdlc->tty->fasync != NULL) kill_fasync (&n_hdlc->tty->fasync, SIGIO, POLL_IN); } /* end of n_hdlc_tty_receive() */
static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data, char *flags, int count) { register struct n_hdlc *n_hdlc = tty2n_hdlc (tty); register struct n_hdlc_buf *buf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_receive() called count=%d\n", __FILE__,__LINE__, count); if (!n_hdlc || tty != n_hdlc->tty) return; if (n_hdlc->magic != HDLC_MAGIC) { printk("%s(%d) line not using HDLC discipline\n", __FILE__,__LINE__); return; } if ( count>maxframe ) { if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d) rx count>maxframesize, data discarded\n", __FILE__,__LINE__); return; } buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list); if (!buf) { if (n_hdlc->rx_buf_list.count < MAX_RX_BUF_COUNT) buf = kmalloc(N_HDLC_BUF_SIZE, GFP_ATOMIC); } if (!buf) { if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d) no more rx buffers, data discarded\n", __FILE__,__LINE__); return; } memcpy(buf->buf,data,count); buf->count=count; n_hdlc_buf_put(&n_hdlc->rx_buf_list, buf); wake_up_interruptible (&tty->read_wait); if (n_hdlc->tty->fasync != NULL) kill_fasync (&n_hdlc->tty->fasync, SIGIO, POLL_IN); }
static size_t vs_sdlc_kernel_write(void *context, const void *buf, size_t count) { struct vl_sync_port *port = (struct vl_sync_port *)context; struct vl_sync_port *paired_port = NULL; struct n_hdlc *n_hdlc = NULL; struct n_hdlc_buf *tbuf; //unsigned long flags; /* Validate the pointers */ if(!port || !IS_OPEN(port)) return -ENODEV; paired_port = port->paired_port; if (!paired_port || !IS_OPEN(paired_port)) return -EINVAL; // Write into paired_port receive buffer, if available n_hdlc = paired_port->n_hdlc; if (!n_hdlc) return -EIO; /* Verify frame size */ if (count > MAX_HDLC_FRAME_SIZE) { pr_debug("vs_sdlc_kernel_write: truncating user packet from %lu to %d\n", (unsigned long) count, MAX_HDLC_FRAME_SIZE); count = MAX_HDLC_FRAME_SIZE; } // Lock paired_port //spin_lock_irqsave(&paired_port->ctrl_lock, flags); /* Allocate transmit buffer */ if (!(tbuf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list))) { //spin_unlock_irqrestore(&paired_port->ctrl_lock, flags); return -EAGAIN; } /* Copy the user's buffer */ memcpy(tbuf->buf, buf, count); pr_debug("vs_sdlc_kernel_write: %d bytes: %02x\n", count, tbuf->buf[0]); /* Send the data */ tbuf->count = count; n_hdlc_buf_put(&n_hdlc->rx_buf_list,tbuf); //spin_unlock_irqrestore(&paired_port->ctrl_lock, flags); /* Wake up any blocked reads on paired port and perform async signalling */ wake_up_interruptible (&paired_port->read_wait); if (paired_port->fasync_queue != NULL) kill_fasync (&paired_port->fasync_queue, SIGIO, POLL_IN); return count; }
static void n_hdlc_release(struct n_hdlc *n_hdlc) { struct n_hdlc_buf *buf; /* Release transmit and receive buffers */ for(;;) { buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list); if (buf) { kfree(buf); } else break; } for(;;) { buf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list); if (buf) { kfree(buf); } else break; } for(;;) { buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list); if (buf) { kfree(buf); } else break; } for(;;) { buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); if (buf) { kfree(buf); } else break; } kfree(n_hdlc->tbuf); kfree(n_hdlc); } /* end of n_hdlc_release() */
static void flush_tx_queue(struct tty_struct *tty) { struct n_hdlc *n_hdlc = tty2n_hdlc(tty); struct n_hdlc_buf *buf; unsigned long flags; while ((buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list))) n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, buf); spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags); if (n_hdlc->tbuf) { n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, n_hdlc->tbuf); n_hdlc->tbuf = NULL; } spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); }
static int vs_sdlc_kernel_read( void *context, void *buf, size_t count) { struct vl_sync_port *port = (struct vl_sync_port *)context; struct n_hdlc *n_hdlc = port->n_hdlc; struct n_hdlc_buf *rbuf; pr_debug("%s(%d)vs_sdlc_kernel_read() called\n",__FILE__,__LINE__); /* Validate the pointers */ if(!port || !IS_OPEN(port) || !n_hdlc) return -EBADF; rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list); if (!rbuf) { /* no data */ return 0; } /* Copy the data to the caller's buffer */ if (count > rbuf->count) count = rbuf->count; memcpy(buf, rbuf->buf, count); pr_debug("vs_sdlc_kernel_read: %d bytes: %02x\n", count, rbuf->buf[0]); /* return HDLC buffer to free list unless the free list */ /* count has exceeded the default value, in which case the */ /* buffer is freed back to the OS to conserve memory */ if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT) kfree(rbuf); else n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf); // Wake up paired_port write wait queue if (port->paired_port && IS_OPEN(port->paired_port)) /* wake up sleeping writers */ wake_up_interruptible(&port->paired_port->write_wait); return count; }
/** * n_hdlc_tty_read - Called to retrieve one frame of data (if available) * @tty - pointer to tty instance data * @file - pointer to open file object * @buf - pointer to returned data buffer * @nr - size of returned data buffer * * Returns the number of bytes returned or error code. */ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, __u8 __user *buf, size_t nr) { struct n_hdlc *n_hdlc = tty2n_hdlc(tty); int ret = 0; struct n_hdlc_buf *rbuf; DECLARE_WAITQUEUE(wait, current); if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_read() called\n",__FILE__,__LINE__); /* Validate the pointers */ if (!n_hdlc) return -EIO; /* verify user access to buffer */ if (!access_ok(VERIFY_WRITE, buf, nr)) { printk(KERN_WARNING "%s(%d) n_hdlc_tty_read() can't verify user " "buffer\n", __FILE__, __LINE__); return -EFAULT; } add_wait_queue(&tty->read_wait, &wait); for (;;) { if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { ret = -EIO; break; } if (tty_hung_up_p(file)) break; set_current_state(TASK_INTERRUPTIBLE); rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list); if (rbuf) { if (rbuf->count > nr) { /* too large for caller's buffer */ ret = -EOVERFLOW; } else { if (copy_to_user(buf, rbuf->buf, rbuf->count)) ret = -EFAULT; else ret = rbuf->count; } if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT) kfree(rbuf); else n_hdlc_buf_put(&n_hdlc->rx_free_buf_list, rbuf); break; } /* no data */ if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; break; } schedule(); if (signal_pending(current)) { ret = -EINTR; break; } } remove_wait_queue(&tty->read_wait, &wait); __set_current_state(TASK_RUNNING); return ret; } /* end of n_hdlc_tty_read() */
/** * n_hdlc_tty_write - write a single frame of data to device * @tty - pointer to associated tty device instance data * @file - pointer to file object data * @data - pointer to transmit data (one frame) * @count - size of transmit frame in bytes * * Returns the number of bytes written (or error code). */ static ssize_t n_hdlc_tty_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count) { struct n_hdlc *n_hdlc = tty2n_hdlc (tty); int error = 0; DECLARE_WAITQUEUE(wait, current); struct n_hdlc_buf *tbuf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_write() called count=%Zd\n", __FILE__,__LINE__,count); /* Verify pointers */ if (!n_hdlc) return -EIO; if (n_hdlc->magic != HDLC_MAGIC) return -EIO; /* verify frame size */ if (count > maxframe ) { if (debuglevel & DEBUG_LEVEL_INFO) printk (KERN_WARNING "n_hdlc_tty_write: truncating user packet " "from %lu to %d\n", (unsigned long) count, maxframe ); count = maxframe; } add_wait_queue(&tty->write_wait, &wait); for (;;) { set_current_state(TASK_INTERRUPTIBLE); tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list); if (tbuf) break; if (file->f_flags & O_NONBLOCK) { error = -EAGAIN; break; } schedule(); n_hdlc = tty2n_hdlc (tty); if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || tty != n_hdlc->tty) { printk("n_hdlc_tty_write: %p invalid after wait!\n", n_hdlc); error = -EIO; break; } if (signal_pending(current)) { error = -EINTR; break; } } __set_current_state(TASK_RUNNING); remove_wait_queue(&tty->write_wait, &wait); if (!error) { /* Retrieve the user's buffer */ memcpy(tbuf->buf, data, count); /* Send the data */ tbuf->count = error = count; n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf); n_hdlc_send_frames(n_hdlc,tty); } return error; } /* end of n_hdlc_tty_write() */
/* n_hdlc_tty_read() * * Called to retreive one frame of data (if available) * * Arguments: * * tty pointer to tty instance data * file pointer to open file object * buf pointer to returned data buffer * nr size of returned data buffer * * Return Value: * * Number of bytes returned or error code */ static rw_ret_t n_hdlc_tty_read (struct tty_struct *tty, struct file *file, __u8 * buf, rw_count_t nr) { struct n_hdlc *n_hdlc = tty2n_hdlc(tty); int error; rw_ret_t ret; N_HDLC_BUF *rbuf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_read() called\n",__FILE__,__LINE__); /* Validate the pointers */ if (!n_hdlc) return -EIO; /* verify user access to buffer */ error = verify_area (VERIFY_WRITE, buf, nr); if (error != 0) { printk(KERN_WARNING"%s(%d) n_hdlc_tty_read() can't verify user " "buffer\n",__FILE__,__LINE__); return (error); } for (;;) { n_hdlc = tty2n_hdlc (tty); if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || tty != n_hdlc->tty) return 0; rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list); if (rbuf) break; /* no data */ if (file->f_flags & O_NONBLOCK) return -EAGAIN; interruptible_sleep_on (&n_hdlc->read_wait); if (signal_pending(current)) return -EINTR; } if (rbuf->count > nr) { /* frame too large for caller's buffer (discard frame) */ ret = (rw_ret_t)-EOVERFLOW; } else { /* Copy the data to the caller's buffer */ COPY_TO_USER(error,buf,rbuf->buf,rbuf->count); if (error) ret = (rw_ret_t)error; else ret = (rw_ret_t)rbuf->count; } /* return HDLC buffer to free list unless the free list */ /* count has exceeded the default value, in which case the */ /* buffer is freed back to the OS to conserve memory */ if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT) kfree(rbuf); else n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf); return ret; } /* end of n_hdlc_tty_read() */
/** * n_hdlc_send_frames - send frames on pending send buffer list * @n_hdlc - pointer to ldisc instance data * @tty - pointer to tty instance data * * Send frames on pending send buffer list until the driver does not accept a * frame (busy) this function is called after adding a frame to the send buffer * list and by the tty wakeup callback. */ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) { register int actual; unsigned long flags; struct n_hdlc_buf *tbuf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_send_frames() called\n",__FILE__,__LINE__); check_again: spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags); if (n_hdlc->tbusy) { n_hdlc->woke_up = 1; spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); return; } n_hdlc->tbusy = 1; n_hdlc->woke_up = 0; spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); /* get current transmit buffer or get new transmit */ /* buffer from list of pending transmit buffers */ tbuf = n_hdlc->tbuf; if (!tbuf) tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); while (tbuf) { if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)sending frame %p, count=%d\n", __FILE__,__LINE__,tbuf,tbuf->count); /* Send the next block of data to device */ tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); actual = tty->ops->write(tty, tbuf->buf, tbuf->count); /* rollback was possible and has been done */ if (actual == -ERESTARTSYS) { n_hdlc->tbuf = tbuf; break; } /* if transmit error, throw frame away by */ /* pretending it was accepted by driver */ if (actual < 0) actual = tbuf->count; if (actual == tbuf->count) { if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)frame %p completed\n", __FILE__,__LINE__,tbuf); /* free current transmit buffer */ n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf); /* this tx buffer is done */ n_hdlc->tbuf = NULL; /* wait up sleeping writers */ wake_up_interruptible(&tty->write_wait); /* get next pending transmit buffer */ tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); } else { if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)frame %p pending\n", __FILE__,__LINE__,tbuf); /* buffer not accepted by driver */ /* set this buffer as pending buffer */ n_hdlc->tbuf = tbuf; break; } } if (!tbuf) tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); /* Clear the re-entry flag */ spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags); n_hdlc->tbusy = 0; spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); if (n_hdlc->woke_up) goto check_again; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_send_frames() exit\n",__FILE__,__LINE__); } /* end of n_hdlc_send_frames() */
/* n_hdlc_tty_write() * * write a single frame of data to device * * Arguments: tty pointer to associated tty device instance data * file pointer to file object data * data pointer to transmit data (one frame) * count size of transmit frame in bytes * * Return Value: number of bytes written (or error code) */ static rw_ret_t n_hdlc_tty_write (struct tty_struct *tty, struct file *file, const __u8 * data, rw_count_t count) { struct n_hdlc *n_hdlc = tty2n_hdlc (tty); int error = 0; DECLARE_WAITQUEUE(wait, current); N_HDLC_BUF *tbuf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_write() called count=%d\n", __FILE__,__LINE__,count); /* Verify pointers */ if (!n_hdlc) return -EIO; if (n_hdlc->magic != HDLC_MAGIC) return -EIO; /* verify frame size */ if (count > maxframe ) { if (debuglevel & DEBUG_LEVEL_INFO) printk (KERN_WARNING "n_hdlc_tty_write: truncating user packet " "from %lu to %d\n", (unsigned long) count, maxframe ); count = maxframe; } add_wait_queue(&n_hdlc->write_wait, &wait); set_current_state(TASK_INTERRUPTIBLE); /* Allocate transmit buffer */ /* sleep until transmit buffer available */ while (!(tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list))) { schedule(); n_hdlc = tty2n_hdlc (tty); if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || tty != n_hdlc->tty) { printk("n_hdlc_tty_write: %p invalid after wait!\n", n_hdlc); error = -EIO; break; } if (signal_pending(current)) { error = -EINTR; break; } } set_current_state(TASK_RUNNING); remove_wait_queue(&n_hdlc->write_wait, &wait); if (!error) { /* Retrieve the user's buffer */ COPY_FROM_USER (error, tbuf->buf, data, count); if (error) { /* return tx buffer to free list */ n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,tbuf); } else { /* Send the data */ tbuf->count = error = count; n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf); n_hdlc_send_frames(n_hdlc,tty); } } return error; } /* end of n_hdlc_tty_write() */
static ssize_t vl_sync_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) { struct vl_sync_port *port = (struct vl_sync_port *)filp->private_data; struct vl_sync_port *paired_port = port->paired_port; register struct n_hdlc *n_hdlc = NULL; register struct n_hdlc_buf *tbuf; int error = 0; DECLARE_WAITQUEUE(wait, current); /* Verify pointers */ if (!port) return -ENODEV; if (!paired_port || !IS_OPEN(port)) return -EINVAL; n_hdlc = paired_port->n_hdlc; if ((!n_hdlc) || (n_hdlc->magic != HDLC_MAGIC)) return -EIO; /* verify frame size */ if (count > MAX_HDLC_FRAME_SIZE ) { pr_err("vl_sync_write: truncating user packet " "from %lu to %d\n", (unsigned long) count, MAX_HDLC_FRAME_SIZE ); count = MAX_HDLC_FRAME_SIZE; } add_wait_queue(&port->write_wait, &wait); set_current_state(TASK_INTERRUPTIBLE); //Write the data buffer into the receive buffer for the paired port /* Allocate transmit buffer */ /* sleep until transmit buffer available */ while (!(tbuf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list))) { if (filp->f_flags & O_NONBLOCK) { error = -EAGAIN; break; } schedule(); n_hdlc = paired_port->n_hdlc; if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC ) { pr_err("vl_sync_write: %p invalid after wait!\n", n_hdlc); error = -EIO; break; } if (signal_pending(current)) { error = -EINTR; break; } } set_current_state(TASK_RUNNING); remove_wait_queue(&port->write_wait, &wait); if (!error) { /* Retrieve the user's buffer */ if (copy_from_user(tbuf->buf, buf, count)) error = -EFAULT; else { /* Send the data */ tbuf->count = error = count; n_hdlc_buf_put(&n_hdlc->rx_buf_list,tbuf); /* Wake up any blocked reads on paired port and perform async signalling */ wake_up_interruptible (&paired_port->read_wait); if (paired_port->fasync_queue != NULL) kill_fasync (&paired_port->fasync_queue, SIGIO, POLL_IN); } } return error; }
static ssize_t vl_sync_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { struct vl_sync_port *port = (struct vl_sync_port *)filp->private_data; struct n_hdlc *n_hdlc = port->n_hdlc; int ret; struct n_hdlc_buf *rbuf; pr_debug("%s(%d)vl_sync_read() called\n",__FILE__,__LINE__); /* Validate the pointers */ if (!n_hdlc) return -EIO; /* verify user access to buffer */ if (!access_ok(VERIFY_WRITE, buf, count)) { pr_err("%s(%d) vl_sync_read() can't verify user buffer\n", __FILE__, __LINE__); return -EFAULT; } /*spin_lock_irqsave(&port->read_ctrl_lock, flags);*/ for (;;) { rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list); if (rbuf) break; /* no data */ pr_debug("%s(%d): no data to read\n", __FILE__, __LINE__); if (filp->f_flags & O_NONBLOCK) { return -EAGAIN; } interruptible_sleep_on (&port->read_wait); if (signal_pending(current)) { return -EINTR; } } if (rbuf->count > count) /* frame too large for caller's buffer (discard frame) */ ret = -EOVERFLOW; else { /* Copy the data to the caller's buffer */ if (copy_to_user(buf, rbuf->buf, rbuf->count)) ret = -EFAULT; else ret = rbuf->count; } /* return HDLC buffer to free list unless the free list */ /* count has exceeded the default value, in which case the */ /* buffer is freed back to the OS to conserve memory */ if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT) kfree(rbuf); else n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf); // Wake up paired_port write wait queue if (port->paired_port && IS_OPEN(port->paired_port)) /* wake up sleeping writers */ wake_up_interruptible(&port->paired_port->write_wait); return ret; }
static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) { register int actual; unsigned long flags; struct n_hdlc_buf *tbuf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_send_frames() called\n",__FILE__,__LINE__); check_again: spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags); if (n_hdlc->tbusy) { n_hdlc->woke_up = 1; spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); return; } n_hdlc->tbusy = 1; n_hdlc->woke_up = 0; spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); tbuf = n_hdlc->tbuf; if (!tbuf) tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); while (tbuf) { if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)sending frame %p, count=%d\n", __FILE__,__LINE__,tbuf,tbuf->count); set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); actual = tty->ops->write(tty, tbuf->buf, tbuf->count); if (actual == -ERESTARTSYS) { n_hdlc->tbuf = tbuf; break; } if (actual < 0) actual = tbuf->count; if (actual == tbuf->count) { if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)frame %p completed\n", __FILE__,__LINE__,tbuf); n_hdlc_buf_put(&n_hdlc->tx_free_buf_list, tbuf); n_hdlc->tbuf = NULL; wake_up_interruptible(&tty->write_wait); tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list); } else { if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)frame %p pending\n", __FILE__,__LINE__,tbuf); n_hdlc->tbuf = tbuf; break; } } if (!tbuf) clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock, flags); n_hdlc->tbusy = 0; spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock, flags); if (n_hdlc->woke_up) goto check_again; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_send_frames() exit\n",__FILE__,__LINE__); }
/** * n_hdlc_tty_read - Called to retrieve one frame of data (if available) * @tty - pointer to tty instance data * @file - pointer to open file object * @buf - pointer to returned data buffer * @nr - size of returned data buffer * * Returns the number of bytes returned or error code. */ static ssize_t n_hdlc_tty_read(struct tty_struct *tty, struct file *file, __u8 __user *buf, size_t nr) { struct n_hdlc *n_hdlc = tty2n_hdlc(tty); int ret; struct n_hdlc_buf *rbuf; if (debuglevel >= DEBUG_LEVEL_INFO) printk("%s(%d)n_hdlc_tty_read() called\n",__FILE__,__LINE__); /* Validate the pointers */ if (!n_hdlc) return -EIO; /* verify user access to buffer */ if (!access_ok(VERIFY_WRITE, buf, nr)) { printk(KERN_WARNING "%s(%d) n_hdlc_tty_read() can't verify user " "buffer\n", __FILE__, __LINE__); return -EFAULT; } tty_lock(); for (;;) { if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { tty_unlock(); return -EIO; } n_hdlc = tty2n_hdlc (tty); if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC || tty != n_hdlc->tty) { tty_unlock(); return 0; } rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list); if (rbuf) break; /* no data */ if (file->f_flags & O_NONBLOCK) { tty_unlock(); return -EAGAIN; } interruptible_sleep_on (&tty->read_wait); if (signal_pending(current)) { tty_unlock(); return -EINTR; } } if (rbuf->count > nr) /* frame too large for caller's buffer (discard frame) */ ret = -EOVERFLOW; else { /* Copy the data to the caller's buffer */ if (copy_to_user(buf, rbuf->buf, rbuf->count)) ret = -EFAULT; else ret = rbuf->count; } /* return HDLC buffer to free list unless the free list */ /* count has exceeded the default value, in which case the */ /* buffer is freed back to the OS to conserve memory */ if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT) kfree(rbuf); else n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf); tty_unlock(); return ret; } /* end of n_hdlc_tty_read() */