chan_user.c revision 89df6bfc04059716de2eb2fe529f05b3e124fafd
11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com)
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Licensed under the GPL
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <unistd.h>
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <stdlib.h>
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <errno.h>
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <termios.h>
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <string.h>
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <signal.h>
121d2ddcfb1935c9c0e98c4295458b01f24e3274f9Jeff Dike#include <sched.h>
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sys/stat.h>
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sys/ioctl.h>
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sys/socket.h>
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "kern_util.h"
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "chan_user.h"
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "user.h"
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "os.h"
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "choose-mode.h"
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "mode.h"
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2355c033c1f6cdedc350c79c3198b542e3ab496899Paolo 'Blaisorblade' Giarrussoint generic_console_write(int fd, const char *buf, int n)
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct termios save, new;
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int err;
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(isatty(fd)){
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CATCH_EINTR(err = tcgetattr(fd, &save));
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err)
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto error;
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new = save;
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* The terminal becomes a bit less raw, to handle \n also as
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * "Carriage Return", not only as "New Line". Otherwise, the new
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * line won't start at the first column.*/
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		new.c_oflag |= OPOST;
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CATCH_EINTR(err = tcsetattr(fd, TCSAFLUSH, &new));
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (err)
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto error;
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = generic_write(fd, buf, n, NULL);
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Restore raw mode, in any case; we *must* ignore any error apart
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * EINTR, except for debug.*/
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(isatty(fd))
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		CATCH_EINTR(tcsetattr(fd, TCSAFLUSH, &save));
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return(err);
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldserror:
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return(-errno);
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * UML SIGWINCH handling
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The point of this is to handle SIGWINCH on consoles which have host ttys and
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * relay them inside UML to whatever might be running on the console and cares
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * about the window size (since SIGWINCH notifies about terminal size changes).
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * So, we have a separate thread for each host tty attached to a UML device
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (side-issue - I'm annoyed that one thread can't have multiple controlling
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ttys for purposed of handling SIGWINCH, but I imagine there are other reasons
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * that doesn't make any sense).
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * SIGWINCH can't be received synchronously, so you have to set up to receive it
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * as a signal.  That being the case, if you are going to wait for it, it is
65ed1b58d8b53519e10a35c6a2bb49cac35f439621Bodo Stroesser * convenient to sit in sigsuspend() and wait for the signal to bounce you out of
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it (see below for how we make sure to exit only on SIGWINCH).
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void winch_handler(int sig)
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct winch_data {
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int pty_fd;
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int pipe_fd;
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int winch_thread(void *arg)
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct winch_data *data = arg;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigset_t sigs;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int pty_fd, pipe_fd;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int count, err;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char c = 1;
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pty_fd = data->pty_fd;
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pipe_fd = data->pipe_fd;
88a6ea4cceed18edebe1eb6001cb9e0f88cd741a6cJeff Dike	count = os_write_file(pipe_fd, &c, sizeof(c));
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(count != sizeof(c))
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("winch_thread : failed to write synchronization "
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "byte, err = %d\n", -count);
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* We are not using SIG_IGN on purpose, so don't fix it as I thought to
94ed1b58d8b53519e10a35c6a2bb49cac35f439621Bodo Stroesser	 * do! If using SIG_IGN, the sigsuspend() call below would not stop on
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * SIGWINCH. */
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	signal(SIGWINCH, winch_handler);
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	sigfillset(&sigs);
99ed1b58d8b53519e10a35c6a2bb49cac35f439621Bodo Stroesser	/* Block all signals possible. */
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(sigprocmask(SIG_SETMASK, &sigs, NULL) < 0){
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("winch_thread : sigprocmask failed, errno = %d\n",
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       errno);
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		exit(1);
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
105ed1b58d8b53519e10a35c6a2bb49cac35f439621Bodo Stroesser	/* In sigsuspend(), block anything else than SIGWINCH. */
106ed1b58d8b53519e10a35c6a2bb49cac35f439621Bodo Stroesser	sigdelset(&sigs, SIGWINCH);
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(setsid() < 0){
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("winch_thread : setsid failed, errno = %d\n", errno);
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		exit(1);
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = os_new_tty_pgrp(pty_fd, os_getpid());
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(err < 0){
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("winch_thread : new_tty_pgrp failed, err = %d\n", -err);
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		exit(1);
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* These are synchronization calls between various UML threads on the
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * host - since they are not different kernel threads, we cannot use
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	 * kernel semaphores. We don't use SysV semaphores because they are
12203a67a46af8647b2c7825107045ecae641e103d3Jan Engelhardt	 * persistent. */
123a6ea4cceed18edebe1eb6001cb9e0f88cd741a6cJeff Dike	count = os_read_file(pipe_fd, &c, sizeof(c));
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(count != sizeof(c))
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("winch_thread : failed to read synchronization byte, "
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		       "err = %d\n", -count);
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while(1){
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		/* This will be interrupted by SIGWINCH only, since other signals
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		 * are blocked.*/
131ed1b58d8b53519e10a35c6a2bb49cac35f439621Bodo Stroesser		sigsuspend(&sigs);
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
133a6ea4cceed18edebe1eb6001cb9e0f88cd741a6cJeff Dike		count = os_write_file(pipe_fd, &c, sizeof(c));
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if(count != sizeof(c))
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk("winch_thread : write failed, err = %d\n",
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			       -count);
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int winch_tramp(int fd, struct tty_struct *tty, int *fd_out)
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct winch_data data;
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long stack;
1441f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike	int fds[2], n, err;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char c;
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	err = os_pipe(fds, 1, 1);
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(err < 0){
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("winch_tramp : os_pipe failed, err = %d\n", -err);
1501f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike		goto out;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	data = ((struct winch_data) { .pty_fd 		= fd,
1541d2ddcfb1935c9c0e98c4295458b01f24e3274f9Jeff Dike				      .pipe_fd 		= fds[1] } );
1551d2ddcfb1935c9c0e98c4295458b01f24e3274f9Jeff Dike	/* CLONE_FILES so this thread doesn't hold open files which are open
1561d2ddcfb1935c9c0e98c4295458b01f24e3274f9Jeff Dike	 * now, but later closed.  This is a problem with /dev/net/tun.
1571d2ddcfb1935c9c0e98c4295458b01f24e3274f9Jeff Dike	 */
1581d2ddcfb1935c9c0e98c4295458b01f24e3274f9Jeff Dike	err = run_helper_thread(winch_thread, &data, CLONE_FILES, &stack, 0);
1591f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike	if(err < 0){
160b16895b63c504698b0c3ab26ca3c41a4fa162a42Andrew Morton		printk("fork of winch_thread failed - errno = %d\n", -err);
1611f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike		goto out_close;
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	*fd_out = fds[0];
165a6ea4cceed18edebe1eb6001cb9e0f88cd741a6cJeff Dike	n = os_read_file(fds[0], &c, sizeof(c));
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(n != sizeof(c)){
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("winch_tramp : failed to read synchronization byte\n");
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("read failed, err = %d\n", -n);
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk("fd %d will not support SIGWINCH\n", fd);
1701f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike                err = -EINVAL;
1711d2ddcfb1935c9c0e98c4295458b01f24e3274f9Jeff Dike		goto out_close;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
17389df6bfc04059716de2eb2fe529f05b3e124fafdEduard-Gabriel Munteanu
17489df6bfc04059716de2eb2fe529f05b3e124fafdEduard-Gabriel Munteanu	if (os_set_fd_block(*fd_out, 0)) {
17589df6bfc04059716de2eb2fe529f05b3e124fafdEduard-Gabriel Munteanu		printk("winch_tramp: failed to set thread_fd non-blocking.\n");
17689df6bfc04059716de2eb2fe529f05b3e124fafdEduard-Gabriel Munteanu		goto out_close;
17789df6bfc04059716de2eb2fe529f05b3e124fafdEduard-Gabriel Munteanu	}
17889df6bfc04059716de2eb2fe529f05b3e124fafdEduard-Gabriel Munteanu
17989df6bfc04059716de2eb2fe529f05b3e124fafdEduard-Gabriel Munteanu	return err;
1801f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike
1811f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike out_close:
1821f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike	os_close_file(fds[1]);
1831f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike	os_close_file(fds[0]);
1841f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike out:
1851f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike	return err;
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid register_winch(int fd, struct tty_struct *tty)
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1901f96ddb4fb40961a8ebebf7a00bbfaad55aacbd2Jeff Dike	int pid, thread, thread_fd = -1;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int count;
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	char c = 1;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(!isatty(fd))
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	pid = tcgetpgrp(fd);
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if(!CHOOSE_MODE_PROC(is_tracer_winch, is_skas_winch, pid, fd,
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			     tty) && (pid == -1)){
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		thread = winch_tramp(fd, tty, &thread_fd);
201da00d9a5466558ccd9e7b7d04b13d7cb9160c876Jeff Dike		if(thread > 0){
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			register_winch_irq(thread_fd, fd, thread, tty);
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
204a6ea4cceed18edebe1eb6001cb9e0f88cd741a6cJeff Dike			count = os_write_file(thread_fd, &c, sizeof(c));
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if(count != sizeof(c))
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				printk("register_winch : failed to write "
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				       "synchronization byte, err = %d\n",
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					-count);
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
212