+static inline int __hvc_write_user(struct hvc_struct *hp,
+ const unsigned char *buf, int count)
+{
+ char *tbuf, *p;
+ int tbsize, rsize, written = 0;
+ unsigned long flags;
+
+ tbsize = min(count, (int)PAGE_SIZE);
+ if (!(tbuf = kmalloc(tbsize, GFP_KERNEL)))
+ return -ENOMEM;
+
+ while ((rsize = count - written) > 0) {
+ int wsize;
+ if (rsize > tbsize)
+ rsize = tbsize;
+
+ p = tbuf;
+ rsize -= copy_from_user(p, buf, rsize);
+ if (!rsize) {
+ if (written == 0)
+ written = -EFAULT;
+ break;
+ }
+ buf += rsize;
+
+ spin_lock_irqsave(&hp->lock, flags);
+
+ /* Push pending writes: make some room in buffer */
+ if (hp->n_outbuf > 0)
+ hvc_push(hp);
+
+ for (wsize = N_OUTBUF - hp->n_outbuf; rsize && wsize;
+ wsize = N_OUTBUF - hp->n_outbuf) {
+ if (wsize > rsize)
+ wsize = rsize;
+ memcpy(hp->outbuf + hp->n_outbuf, p, wsize);
+ hp->n_outbuf += wsize;
+ hvc_push(hp);
+ rsize -= wsize;
+ p += wsize;
+ written += wsize;
+ }
+ spin_unlock_irqrestore(&hp->lock, flags);
+
+ if (rsize)
+ break;
+
+ if (count < tbsize)
+ tbsize = count;
+ }
+
+ kfree(tbuf);
+
+ return written;
+}
+