/** * 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", ; /* 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) { ; 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() */
static ssize_t thp_read(struct file *filp, char *buf, size_t count, loff_t*ppos) { DECLARE_WAITQUEUE(wait, current); struct sk_buff_head *head = &to_sqntool_queue; struct sk_buff *curr = NULL; ssize_t retval; const struct sqn_thp_header *th = 0; sqn_pr_enter(); #if THP_DEBUG printk(KERN_WARNING "thp_read +\n"); #endif add_wait_queue(&to_sqntool_wait, &wait); retval = -ERESTARTSYS; if(0 == this_device) { printk(KERN_WARNING "thp_read() device removed\n"); retval = -EINVAL; goto out; } while(1) { if(!skb_queue_empty(head)) break; if(signal_pending(current) || 0 == this_device) { printk(KERN_WARNING "thp_read() interrupted by signal\n"); retval = -EINTR; goto out; } set_current_state(TASK_INTERRUPTIBLE); schedule(); } curr = skb_dequeue(head); if (count < curr->len) { printk(KERN_WARNING "%s: userspace buffer is too small (%u bytes)" " to hold THP packet (%u bytes)\n" , __func__, count, curr->len); retval = -EINVAL; goto free_skb; } else { count = curr->len; } if(copy_to_user(buf, curr->data, count)) { printk(KERN_ERR "error copying data to user space\n"); retval = -EFAULT; goto free_skb; } if (mmc_wimax_get_thp_log()) { sqn_pr_info("%s: [to_user]: len = %d\n", __func__, count); th = (struct sqn_thp_header *) curr->data; sqn_pr_info("%s: PKTLen: %4u | TVer: 0x0%x | Flags: 0x0%x | Len: %4u" " | SeqNum: %5u | AckNum: %5u | TLen: %5u\n", __func__ , count , th->transport_version , th->flags , be16_to_cpu(th->length) , be16_to_cpu(th->seq_number) , be16_to_cpu(th->ack_number) , be32_to_cpu(th->total_length)); sqn_pr_dbg_dump("THP RX:", curr->data, count); } #if SKB_DEBUG sqn_pr_info("%s: free skb [0x%p], users %d\n", __func__, curr, atomic_read(&curr->users)); #endif retval = (ssize_t)count; free_skb: dev_kfree_skb_any(curr); out: set_current_state(TASK_RUNNING); remove_wait_queue(&to_sqntool_wait, &wait); #if THP_DEBUG printk(KERN_WARNING "thp_read -\n"); #endif sqn_pr_leave(); return retval; }
/** * 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) ; /* 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 " ; 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() */