static ssize_t r3964_read(struct tty_struct *tty, struct file *file, unsigned char __user * buf, size_t nr) { struct r3964_info *pInfo = tty->disc_data; struct r3964_client_info *pClient; struct r3964_message *pMsg; struct r3964_client_message theMsg; int ret; TRACE_L("read()"); tty_lock(); pClient = findClient(pInfo, task_pid(current)); if (pClient) { pMsg = remove_msg(pInfo, pClient); if (pMsg == NULL) { /* no messages available. */ if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; goto unlock; } /* block until there is a message: */ wait_event_interruptible_tty(pInfo->read_wait, (pMsg = remove_msg(pInfo, pClient))); } /* If we still haven't got a message, we must have been signalled */ if (!pMsg) { ret = -EINTR; goto unlock; } /* deliver msg to client process: */ theMsg.msg_id = pMsg->msg_id; theMsg.arg = pMsg->arg; theMsg.error_code = pMsg->error_code; ret = sizeof(struct r3964_client_message); kfree(pMsg); TRACE_M("r3964_read - msg kfree %p", pMsg); if (copy_to_user(buf, &theMsg, ret)) { ret = -EFAULT; goto unlock; } TRACE_PS("read - return %d", ret); goto unlock; } ret = -EPERM; unlock: tty_unlock(); return ret; }
int tty_port_block_til_ready(struct tty_port *port, struct tty_struct *tty, struct file *filp) { int do_clocal = 0, retval; unsigned long flags; DEFINE_WAIT(wait); /* block if port is in the process of being closed */ if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) { wait_event_interruptible_tty(tty, port->close_wait, !(port->flags & ASYNC_CLOSING)); if (port->flags & ASYNC_HUP_NOTIFY) return -EAGAIN; else return -ERESTARTSYS; } /* if non-blocking mode is set we can pass directly to open unless the port has just hung up or is in another error state */ if (tty->flags & (1 << TTY_IO_ERROR)) { port->flags |= ASYNC_NORMAL_ACTIVE; return 0; } if (filp->f_flags & O_NONBLOCK) { /* Indicate we are open */ if (tty->termios->c_cflag & CBAUD) tty_port_raise_dtr_rts(port); port->flags |= ASYNC_NORMAL_ACTIVE; return 0; } if (C_CLOCAL(tty)) do_clocal = 1; /* Block waiting until we can proceed. We may need to wait for the carrier, but we must also wait for any close that is in progress before the next open may complete */ retval = 0; /* The port lock protects the port counts */ spin_lock_irqsave(&port->lock, flags); if (!tty_hung_up_p(filp)) port->count--; port->blocked_open++; spin_unlock_irqrestore(&port->lock, flags); while (1) { /* Indicate we are open */ if (tty->termios->c_cflag & CBAUD) tty_port_raise_dtr_rts(port); prepare_to_wait(&port->open_wait, &wait, TASK_INTERRUPTIBLE); /* Check for a hangup or uninitialised port. Return accordingly */ if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { if (port->flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS; break; } /* * Probe the carrier. For devices with no carrier detect * tty_port_carrier_raised will always return true. * Never ask drivers if CLOCAL is set, this causes troubles * on some hardware. */ if (!(port->flags & ASYNC_CLOSING) && (do_clocal || tty_port_carrier_raised(port))) break; if (signal_pending(current)) { retval = -ERESTARTSYS; break; } tty_unlock(tty); schedule(); tty_lock(tty); } finish_wait(&port->open_wait, &wait); /* Update counts. A parallel hangup will have set count to zero and we must not mess that up further */ spin_lock_irqsave(&port->lock, flags); if (!tty_hung_up_p(filp)) port->count++; port->blocked_open--; if (retval == 0) port->flags |= ASYNC_NORMAL_ACTIVE; spin_unlock_irqrestore(&port->lock, flags); return retval; }