#include <linux/mm.h>
#include <linux/generic_serial.h>
#include <linux/interrupt.h>
-#include <linux/delay.h>
#include <asm/semaphore.h>
#include <asm/uaccess.h>
#define RS_EVENT_WRITE_WAKEUP 1
-module_param(gs_debug, int, 0644);
+MODULE_PARM(gs_debug, "i");
void gs_put_char(struct tty_struct * tty, unsigned char ch)
> -3- Other processes that are also trying to do a "write".
*/
-int gs_write(struct tty_struct * tty,
+int gs_write(struct tty_struct * tty, int from_user,
const unsigned char *buf, int count)
{
struct gs_port *port;
/* Can't copy more? break out! */
if (c <= 0) break;
+ if (from_user) {
+ if (copy_from_user (port->xmit_buf + port->xmit_head,
+ buf, c)) {
+ up (& port->port_write_sem);
+ return -EFAULT;
+ }
- memcpy (port->xmit_buf + port->xmit_head, buf, c);
+ } else
+ memcpy (port->xmit_buf + port->xmit_head, buf, c);
port -> xmit_cnt += c;
port -> xmit_head = (port->xmit_head + c) & (SERIAL_XMIT_SIZE -1);
> -3- Other processes that are also trying to do a "write".
*/
-int gs_write(struct tty_struct * tty,
+int gs_write(struct tty_struct * tty, int from_user,
const unsigned char *buf, int count)
{
struct gs_port *port;
return -EIO;
save_flags(flags);
- while (1) {
- cli();
- c = count;
-
- /* This is safe because we "OWN" the "head". Noone else can
- change the "head": we own the port_write_sem. */
- /* Don't overrun the end of the buffer */
- t = SERIAL_XMIT_SIZE - port->xmit_head;
- if (t < c) c = t;
-
- /* This is safe because the xmit_cnt can only decrease. This
- would increase "t", so we might copy too little chars. */
- /* Don't copy past the "head" of the buffer */
- t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt;
- if (t < c) c = t;
-
- /* Can't copy more? break out! */
- if (c <= 0) {
+ if (from_user) {
+ down(&tmp_buf_sem);
+ while (1) {
+ c = count;
+
+ /* This is safe because we "OWN" the "head". Noone else can
+ change the "head": we own the port_write_sem. */
+ /* Don't overrun the end of the buffer */
+ t = SERIAL_XMIT_SIZE - port->xmit_head;
+ if (t < c) c = t;
+
+ /* This is safe because the xmit_cnt can only decrease. This
+ would increase "t", so we might copy too little chars. */
+ /* Don't copy past the "head" of the buffer */
+ t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt;
+ if (t < c) c = t;
+
+ /* Can't copy more? break out! */
+ if (c <= 0) break;
+
+ c -= copy_from_user(tmp_buf, buf, c);
+ if (!c) {
+ if (!total)
+ total = -EFAULT;
+ break;
+ }
+ cli();
+ t = SERIAL_XMIT_SIZE - port->xmit_head;
+ if (t < c) c = t;
+ t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt;
+ if (t < c) c = t;
+
+ memcpy(port->xmit_buf + port->xmit_head, tmp_buf, c);
+ port->xmit_head = ((port->xmit_head + c) &
+ (SERIAL_XMIT_SIZE-1));
+ port->xmit_cnt += c;
restore_flags(flags);
- break;
+ buf += c;
+ count -= c;
+ total += c;
+ }
+ up(&tmp_buf_sem);
+ } else {
+ while (1) {
+ cli();
+ c = count;
+
+ /* This is safe because we "OWN" the "head". Noone else can
+ change the "head": we own the port_write_sem. */
+ /* Don't overrun the end of the buffer */
+ t = SERIAL_XMIT_SIZE - port->xmit_head;
+ if (t < c) c = t;
+
+ /* This is safe because the xmit_cnt can only decrease. This
+ would increase "t", so we might copy too little chars. */
+ /* Don't copy past the "head" of the buffer */
+ t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt;
+ if (t < c) c = t;
+
+ /* Can't copy more? break out! */
+ if (c <= 0) {
+ restore_flags(flags);
+ break;
+ }
+ memcpy(port->xmit_buf + port->xmit_head, buf, c);
+ port->xmit_head = ((port->xmit_head + c) &
+ (SERIAL_XMIT_SIZE-1));
+ port->xmit_cnt += c;
+ restore_flags(flags);
+ buf += c;
+ count -= c;
+ total += c;
}
- memcpy(port->xmit_buf + port->xmit_head, buf, c);
- port->xmit_head = ((port->xmit_head + c) &
- (SERIAL_XMIT_SIZE-1));
- port->xmit_cnt += c;
- restore_flags(flags);
- buf += c;
- count -= c;
- total += c;
}
if (port->xmit_cnt &&
gs_dprintk (GS_DEBUG_FLUSH, "Expect to finish in %d jiffies "
"(%d chars).\n", jiffies_to_transmit, charsleft);
- msleep_interruptible(jiffies_to_msecs(jiffies_to_transmit));
+ set_current_state (TASK_INTERRUPTIBLE);
+ schedule_timeout(jiffies_to_transmit);
if (signal_pending (current)) {
gs_dprintk (GS_DEBUG_FLUSH, "Signal pending. Bombing out: ");
rv = -EINTR;
if (port->blocked_open) {
if (port->close_delay) {
- msleep_interruptible(jiffies_to_msecs(port->close_delay));
+ set_current_state (TASK_INTERRUPTIBLE);
+ schedule_timeout(port->close_delay);
}
wake_up_interruptible(&port->open_wait);
}