struct serio_raw *serio_raw = client->serio_raw;
        char uninitialized_var(c);
        ssize_t read = 0;
-       int retval;
+       int error = 0;
 
-       if (serio_raw->dead)
-               return -ENODEV;
+       do {
+               if (serio_raw->dead)
+                       return -ENODEV;
 
-       if (serio_raw->head == serio_raw->tail && (file->f_flags & O_NONBLOCK))
-               return -EAGAIN;
+               if (serio_raw->head == serio_raw->tail &&
+                   (file->f_flags & O_NONBLOCK))
+                       return -EAGAIN;
 
-       retval = wait_event_interruptible(serio_raw->wait,
-                       serio_raw->head != serio_raw->tail || serio_raw->dead);
-       if (retval)
-               return retval;
+               if (count == 0)
+                       break;
 
-       if (serio_raw->dead)
-               return -ENODEV;
+               while (read < count && serio_raw_fetch_byte(serio_raw, &c)) {
+                       if (put_user(c, buffer++)) {
+                               error = -EFAULT;
+                               goto out;
+                       }
+                       read++;
+               }
 
-       while (read < count && serio_raw_fetch_byte(serio_raw, &c)) {
-               if (put_user(c, buffer++)) {
-                       retval = -EFAULT;
+               if (read)
                        break;
-               }
-               read++;
-       }
 
-       return read ?: retval;
+               if (!(file->f_flags & O_NONBLOCK))
+                       error = wait_event_interruptible(serio_raw->wait,
+                                       serio_raw->head != serio_raw->tail ||
+                                       serio_raw->dead);
+       } while (!error);
+
+out:
+       return read ?: error;
 }
 
 static ssize_t serio_raw_write(struct file *file, const char __user *buffer,