mirror of
				https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
				synced 2025-10-31 08:08:51 +01:00 
			
		
		
		
	Fixed MTP to work with TWRP
This commit is contained in:
		
						commit
						f6dfaef42e
					
				
					 50820 changed files with 20846062 additions and 0 deletions
				
			
		
							
								
								
									
										546
									
								
								arch/um/os-Linux/sigio.c
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										546
									
								
								arch/um/os-Linux/sigio.c
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,546 @@ | |||
| /*
 | ||||
|  * Copyright (C) 2002 - 2008 Jeff Dike (jdike@{addtoit,linux.intel}.com) | ||||
|  * Licensed under the GPL | ||||
|  */ | ||||
| 
 | ||||
| #include <unistd.h> | ||||
| #include <errno.h> | ||||
| #include <fcntl.h> | ||||
| #include <poll.h> | ||||
| #include <pty.h> | ||||
| #include <sched.h> | ||||
| #include <signal.h> | ||||
| #include <string.h> | ||||
| #include <kern_util.h> | ||||
| #include <init.h> | ||||
| #include <os.h> | ||||
| #include <sigio.h> | ||||
| #include <um_malloc.h> | ||||
| 
 | ||||
| /*
 | ||||
|  * Protected by sigio_lock(), also used by sigio_cleanup, which is an | ||||
|  * exitcall. | ||||
|  */ | ||||
| static int write_sigio_pid = -1; | ||||
| static unsigned long write_sigio_stack; | ||||
| 
 | ||||
| /*
 | ||||
|  * These arrays are initialized before the sigio thread is started, and | ||||
|  * the descriptors closed after it is killed.  So, it can't see them change. | ||||
|  * On the UML side, they are changed under the sigio_lock. | ||||
|  */ | ||||
| #define SIGIO_FDS_INIT {-1, -1} | ||||
| 
 | ||||
| static int write_sigio_fds[2] = SIGIO_FDS_INIT; | ||||
| static int sigio_private[2] = SIGIO_FDS_INIT; | ||||
| 
 | ||||
| struct pollfds { | ||||
| 	struct pollfd *poll; | ||||
| 	int size; | ||||
| 	int used; | ||||
| }; | ||||
| 
 | ||||
| /*
 | ||||
|  * Protected by sigio_lock().  Used by the sigio thread, but the UML thread | ||||
|  * synchronizes with it. | ||||
|  */ | ||||
| static struct pollfds current_poll; | ||||
| static struct pollfds next_poll; | ||||
| static struct pollfds all_sigio_fds; | ||||
| 
 | ||||
| static int write_sigio_thread(void *unused) | ||||
| { | ||||
| 	struct pollfds *fds, tmp; | ||||
| 	struct pollfd *p; | ||||
| 	int i, n, respond_fd; | ||||
| 	char c; | ||||
| 
 | ||||
| 	os_fix_helper_signals(); | ||||
| 	fds = ¤t_poll; | ||||
| 	while (1) { | ||||
| 		n = poll(fds->poll, fds->used, -1); | ||||
| 		if (n < 0) { | ||||
| 			if (errno == EINTR) | ||||
| 				continue; | ||||
| 			printk(UM_KERN_ERR "write_sigio_thread : poll returned " | ||||
| 			       "%d, errno = %d\n", n, errno); | ||||
| 		} | ||||
| 		for (i = 0; i < fds->used; i++) { | ||||
| 			p = &fds->poll[i]; | ||||
| 			if (p->revents == 0) | ||||
| 				continue; | ||||
| 			if (p->fd == sigio_private[1]) { | ||||
| 				CATCH_EINTR(n = read(sigio_private[1], &c, | ||||
| 						     sizeof(c))); | ||||
| 				if (n != sizeof(c)) | ||||
| 					printk(UM_KERN_ERR | ||||
| 					       "write_sigio_thread : " | ||||
| 					       "read on socket failed, " | ||||
| 					       "err = %d\n", errno); | ||||
| 				tmp = current_poll; | ||||
| 				current_poll = next_poll; | ||||
| 				next_poll = tmp; | ||||
| 				respond_fd = sigio_private[1]; | ||||
| 			} | ||||
| 			else { | ||||
| 				respond_fd = write_sigio_fds[1]; | ||||
| 				fds->used--; | ||||
| 				memmove(&fds->poll[i], &fds->poll[i + 1], | ||||
| 					(fds->used - i) * sizeof(*fds->poll)); | ||||
| 			} | ||||
| 
 | ||||
| 			CATCH_EINTR(n = write(respond_fd, &c, sizeof(c))); | ||||
| 			if (n != sizeof(c)) | ||||
| 				printk(UM_KERN_ERR "write_sigio_thread : " | ||||
| 				       "write on socket failed, err = %d\n", | ||||
| 				       errno); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int need_poll(struct pollfds *polls, int n) | ||||
| { | ||||
| 	struct pollfd *new; | ||||
| 
 | ||||
| 	if (n <= polls->size) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	new = uml_kmalloc(n * sizeof(struct pollfd), UM_GFP_ATOMIC); | ||||
| 	if (new == NULL) { | ||||
| 		printk(UM_KERN_ERR "need_poll : failed to allocate new " | ||||
| 		       "pollfds\n"); | ||||
| 		return -ENOMEM; | ||||
| 	} | ||||
| 
 | ||||
| 	memcpy(new, polls->poll, polls->used * sizeof(struct pollfd)); | ||||
| 	kfree(polls->poll); | ||||
| 
 | ||||
| 	polls->poll = new; | ||||
| 	polls->size = n; | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Must be called with sigio_lock held, because it's needed by the marked | ||||
|  * critical section. | ||||
|  */ | ||||
| static void update_thread(void) | ||||
| { | ||||
| 	unsigned long flags; | ||||
| 	int n; | ||||
| 	char c; | ||||
| 
 | ||||
| 	flags = set_signals(0); | ||||
| 	CATCH_EINTR(n = write(sigio_private[0], &c, sizeof(c))); | ||||
| 	if (n != sizeof(c)) { | ||||
| 		printk(UM_KERN_ERR "update_thread : write failed, err = %d\n", | ||||
| 		       errno); | ||||
| 		goto fail; | ||||
| 	} | ||||
| 
 | ||||
| 	CATCH_EINTR(n = read(sigio_private[0], &c, sizeof(c))); | ||||
| 	if (n != sizeof(c)) { | ||||
| 		printk(UM_KERN_ERR "update_thread : read failed, err = %d\n", | ||||
| 		       errno); | ||||
| 		goto fail; | ||||
| 	} | ||||
| 
 | ||||
| 	set_signals(flags); | ||||
| 	return; | ||||
|  fail: | ||||
| 	/* Critical section start */ | ||||
| 	if (write_sigio_pid != -1) { | ||||
| 		os_kill_process(write_sigio_pid, 1); | ||||
| 		free_stack(write_sigio_stack, 0); | ||||
| 	} | ||||
| 	write_sigio_pid = -1; | ||||
| 	close(sigio_private[0]); | ||||
| 	close(sigio_private[1]); | ||||
| 	close(write_sigio_fds[0]); | ||||
| 	close(write_sigio_fds[1]); | ||||
| 	/* Critical section end */ | ||||
| 	set_signals(flags); | ||||
| } | ||||
| 
 | ||||
| int add_sigio_fd(int fd) | ||||
| { | ||||
| 	struct pollfd *p; | ||||
| 	int err = 0, i, n; | ||||
| 
 | ||||
| 	sigio_lock(); | ||||
| 	for (i = 0; i < all_sigio_fds.used; i++) { | ||||
| 		if (all_sigio_fds.poll[i].fd == fd) | ||||
| 			break; | ||||
| 	} | ||||
| 	if (i == all_sigio_fds.used) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	p = &all_sigio_fds.poll[i]; | ||||
| 
 | ||||
| 	for (i = 0; i < current_poll.used; i++) { | ||||
| 		if (current_poll.poll[i].fd == fd) | ||||
| 			goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	n = current_poll.used; | ||||
| 	err = need_poll(&next_poll, n + 1); | ||||
| 	if (err) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	memcpy(next_poll.poll, current_poll.poll, | ||||
| 	       current_poll.used * sizeof(struct pollfd)); | ||||
| 	next_poll.poll[n] = *p; | ||||
| 	next_poll.used = n + 1; | ||||
| 	update_thread(); | ||||
|  out: | ||||
| 	sigio_unlock(); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| int ignore_sigio_fd(int fd) | ||||
| { | ||||
| 	struct pollfd *p; | ||||
| 	int err = 0, i, n = 0; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * This is called from exitcalls elsewhere in UML - if | ||||
| 	 * sigio_cleanup has already run, then update_thread will hang | ||||
| 	 * or fail because the thread is no longer running. | ||||
| 	 */ | ||||
| 	if (write_sigio_pid == -1) | ||||
| 		return -EIO; | ||||
| 
 | ||||
| 	sigio_lock(); | ||||
| 	for (i = 0; i < current_poll.used; i++) { | ||||
| 		if (current_poll.poll[i].fd == fd) | ||||
| 			break; | ||||
| 	} | ||||
| 	if (i == current_poll.used) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	err = need_poll(&next_poll, current_poll.used - 1); | ||||
| 	if (err) | ||||
| 		goto out; | ||||
| 
 | ||||
| 	for (i = 0; i < current_poll.used; i++) { | ||||
| 		p = ¤t_poll.poll[i]; | ||||
| 		if (p->fd != fd) | ||||
| 			next_poll.poll[n++] = *p; | ||||
| 	} | ||||
| 	next_poll.used = current_poll.used - 1; | ||||
| 
 | ||||
| 	update_thread(); | ||||
|  out: | ||||
| 	sigio_unlock(); | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static struct pollfd *setup_initial_poll(int fd) | ||||
| { | ||||
| 	struct pollfd *p; | ||||
| 
 | ||||
| 	p = uml_kmalloc(sizeof(struct pollfd), UM_GFP_KERNEL); | ||||
| 	if (p == NULL) { | ||||
| 		printk(UM_KERN_ERR "setup_initial_poll : failed to allocate " | ||||
| 		       "poll\n"); | ||||
| 		return NULL; | ||||
| 	} | ||||
| 	*p = ((struct pollfd) { .fd		= fd, | ||||
| 				.events 	= POLLIN, | ||||
| 				.revents 	= 0 }); | ||||
| 	return p; | ||||
| } | ||||
| 
 | ||||
| static void write_sigio_workaround(void) | ||||
| { | ||||
| 	struct pollfd *p; | ||||
| 	int err; | ||||
| 	int l_write_sigio_fds[2]; | ||||
| 	int l_sigio_private[2]; | ||||
| 	int l_write_sigio_pid; | ||||
| 
 | ||||
| 	/* We call this *tons* of times - and most ones we must just fail. */ | ||||
| 	sigio_lock(); | ||||
| 	l_write_sigio_pid = write_sigio_pid; | ||||
| 	sigio_unlock(); | ||||
| 
 | ||||
| 	if (l_write_sigio_pid != -1) | ||||
| 		return; | ||||
| 
 | ||||
| 	err = os_pipe(l_write_sigio_fds, 1, 1); | ||||
| 	if (err < 0) { | ||||
| 		printk(UM_KERN_ERR "write_sigio_workaround - os_pipe 1 failed, " | ||||
| 		       "err = %d\n", -err); | ||||
| 		return; | ||||
| 	} | ||||
| 	err = os_pipe(l_sigio_private, 1, 1); | ||||
| 	if (err < 0) { | ||||
| 		printk(UM_KERN_ERR "write_sigio_workaround - os_pipe 2 failed, " | ||||
| 		       "err = %d\n", -err); | ||||
| 		goto out_close1; | ||||
| 	} | ||||
| 
 | ||||
| 	p = setup_initial_poll(l_sigio_private[1]); | ||||
| 	if (!p) | ||||
| 		goto out_close2; | ||||
| 
 | ||||
| 	sigio_lock(); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Did we race? Don't try to optimize this, please, it's not so likely | ||||
| 	 * to happen, and no more than once at the boot. | ||||
| 	 */ | ||||
| 	if (write_sigio_pid != -1) | ||||
| 		goto out_free; | ||||
| 
 | ||||
| 	current_poll = ((struct pollfds) { .poll 	= p, | ||||
| 					   .used 	= 1, | ||||
| 					   .size 	= 1 }); | ||||
| 
 | ||||
| 	if (write_sigio_irq(l_write_sigio_fds[0])) | ||||
| 		goto out_clear_poll; | ||||
| 
 | ||||
| 	memcpy(write_sigio_fds, l_write_sigio_fds, sizeof(l_write_sigio_fds)); | ||||
| 	memcpy(sigio_private, l_sigio_private, sizeof(l_sigio_private)); | ||||
| 
 | ||||
| 	write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, | ||||
| 					    CLONE_FILES | CLONE_VM, | ||||
| 					    &write_sigio_stack); | ||||
| 
 | ||||
| 	if (write_sigio_pid < 0) | ||||
| 		goto out_clear; | ||||
| 
 | ||||
| 	sigio_unlock(); | ||||
| 	return; | ||||
| 
 | ||||
| out_clear: | ||||
| 	write_sigio_pid = -1; | ||||
| 	write_sigio_fds[0] = -1; | ||||
| 	write_sigio_fds[1] = -1; | ||||
| 	sigio_private[0] = -1; | ||||
| 	sigio_private[1] = -1; | ||||
| out_clear_poll: | ||||
| 	current_poll = ((struct pollfds) { .poll	= NULL, | ||||
| 					   .size	= 0, | ||||
| 					   .used	= 0 }); | ||||
| out_free: | ||||
| 	sigio_unlock(); | ||||
| 	kfree(p); | ||||
| out_close2: | ||||
| 	close(l_sigio_private[0]); | ||||
| 	close(l_sigio_private[1]); | ||||
| out_close1: | ||||
| 	close(l_write_sigio_fds[0]); | ||||
| 	close(l_write_sigio_fds[1]); | ||||
| } | ||||
| 
 | ||||
| void sigio_broken(int fd, int read) | ||||
| { | ||||
| 	int err; | ||||
| 
 | ||||
| 	write_sigio_workaround(); | ||||
| 
 | ||||
| 	sigio_lock(); | ||||
| 	err = need_poll(&all_sigio_fds, all_sigio_fds.used + 1); | ||||
| 	if (err) { | ||||
| 		printk(UM_KERN_ERR "maybe_sigio_broken - failed to add pollfd " | ||||
| 		       "for descriptor %d\n", fd); | ||||
| 		goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	all_sigio_fds.poll[all_sigio_fds.used++] = | ||||
| 		((struct pollfd) { .fd  	= fd, | ||||
| 				   .events 	= read ? POLLIN : POLLOUT, | ||||
| 				   .revents 	= 0 }); | ||||
| out: | ||||
| 	sigio_unlock(); | ||||
| } | ||||
| 
 | ||||
| /* Changed during early boot */ | ||||
| static int pty_output_sigio; | ||||
| static int pty_close_sigio; | ||||
| 
 | ||||
| void maybe_sigio_broken(int fd, int read) | ||||
| { | ||||
| 	if (!isatty(fd)) | ||||
| 		return; | ||||
| 
 | ||||
| 	if ((read || pty_output_sigio) && (!read || pty_close_sigio)) | ||||
| 		return; | ||||
| 
 | ||||
| 	sigio_broken(fd, read); | ||||
| } | ||||
| 
 | ||||
| static void sigio_cleanup(void) | ||||
| { | ||||
| 	if (write_sigio_pid == -1) | ||||
| 		return; | ||||
| 
 | ||||
| 	os_kill_process(write_sigio_pid, 1); | ||||
| 	free_stack(write_sigio_stack, 0); | ||||
| 	write_sigio_pid = -1; | ||||
| } | ||||
| 
 | ||||
| __uml_exitcall(sigio_cleanup); | ||||
| 
 | ||||
| /* Used as a flag during SIGIO testing early in boot */ | ||||
| static int got_sigio; | ||||
| 
 | ||||
| static void __init handler(int sig) | ||||
| { | ||||
| 	got_sigio = 1; | ||||
| } | ||||
| 
 | ||||
| struct openpty_arg { | ||||
| 	int master; | ||||
| 	int slave; | ||||
| 	int err; | ||||
| }; | ||||
| 
 | ||||
| static void openpty_cb(void *arg) | ||||
| { | ||||
| 	struct openpty_arg *info = arg; | ||||
| 
 | ||||
| 	info->err = 0; | ||||
| 	if (openpty(&info->master, &info->slave, NULL, NULL, NULL)) | ||||
| 		info->err = -errno; | ||||
| } | ||||
| 
 | ||||
| static int async_pty(int master, int slave) | ||||
| { | ||||
| 	int flags; | ||||
| 
 | ||||
| 	flags = fcntl(master, F_GETFL); | ||||
| 	if (flags < 0) | ||||
| 		return -errno; | ||||
| 
 | ||||
| 	if ((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || | ||||
| 	    (fcntl(master, F_SETOWN, os_getpid()) < 0)) | ||||
| 		return -errno; | ||||
| 
 | ||||
| 	if ((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)) | ||||
| 		return -errno; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static void __init check_one_sigio(void (*proc)(int, int)) | ||||
| { | ||||
| 	struct sigaction old, new; | ||||
| 	struct openpty_arg pty = { .master = -1, .slave = -1 }; | ||||
| 	int master, slave, err; | ||||
| 
 | ||||
| 	initial_thread_cb(openpty_cb, &pty); | ||||
| 	if (pty.err) { | ||||
| 		printk(UM_KERN_ERR "check_one_sigio failed, errno = %d\n", | ||||
| 		       -pty.err); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	master = pty.master; | ||||
| 	slave = pty.slave; | ||||
| 
 | ||||
| 	if ((master == -1) || (slave == -1)) { | ||||
| 		printk(UM_KERN_ERR "check_one_sigio failed to allocate a " | ||||
| 		       "pty\n"); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Not now, but complain so we now where we failed. */ | ||||
| 	err = raw(master); | ||||
| 	if (err < 0) { | ||||
| 		printk(UM_KERN_ERR "check_one_sigio : raw failed, errno = %d\n", | ||||
| 		      -err); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	err = async_pty(master, slave); | ||||
| 	if (err < 0) { | ||||
| 		printk(UM_KERN_ERR "check_one_sigio : sigio_async failed, " | ||||
| 		       "err = %d\n", -err); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (sigaction(SIGIO, NULL, &old) < 0) { | ||||
| 		printk(UM_KERN_ERR "check_one_sigio : sigaction 1 failed, " | ||||
| 		       "errno = %d\n", errno); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	new = old; | ||||
| 	new.sa_handler = handler; | ||||
| 	if (sigaction(SIGIO, &new, NULL) < 0) { | ||||
| 		printk(UM_KERN_ERR "check_one_sigio : sigaction 2 failed, " | ||||
| 		       "errno = %d\n", errno); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	got_sigio = 0; | ||||
| 	(*proc)(master, slave); | ||||
| 
 | ||||
| 	close(master); | ||||
| 	close(slave); | ||||
| 
 | ||||
| 	if (sigaction(SIGIO, &old, NULL) < 0) | ||||
| 		printk(UM_KERN_ERR "check_one_sigio : sigaction 3 failed, " | ||||
| 		       "errno = %d\n", errno); | ||||
| } | ||||
| 
 | ||||
| static void tty_output(int master, int slave) | ||||
| { | ||||
| 	int n; | ||||
| 	char buf[512]; | ||||
| 
 | ||||
| 	printk(UM_KERN_INFO "Checking that host ptys support output SIGIO..."); | ||||
| 
 | ||||
| 	memset(buf, 0, sizeof(buf)); | ||||
| 
 | ||||
| 	while (write(master, buf, sizeof(buf)) > 0) ; | ||||
| 	if (errno != EAGAIN) | ||||
| 		printk(UM_KERN_ERR "tty_output : write failed, errno = %d\n", | ||||
| 		       errno); | ||||
| 	while (((n = read(slave, buf, sizeof(buf))) > 0) && | ||||
| 	       !({ barrier(); got_sigio; })) | ||||
| 		; | ||||
| 
 | ||||
| 	if (got_sigio) { | ||||
| 		printk(UM_KERN_CONT "Yes\n"); | ||||
| 		pty_output_sigio = 1; | ||||
| 	} else if (n == -EAGAIN) | ||||
| 		printk(UM_KERN_CONT "No, enabling workaround\n"); | ||||
| 	else | ||||
| 		printk(UM_KERN_CONT "tty_output : read failed, err = %d\n", n); | ||||
| } | ||||
| 
 | ||||
| static void tty_close(int master, int slave) | ||||
| { | ||||
| 	printk(UM_KERN_INFO "Checking that host ptys support SIGIO on " | ||||
| 	       "close..."); | ||||
| 
 | ||||
| 	close(slave); | ||||
| 	if (got_sigio) { | ||||
| 		printk(UM_KERN_CONT "Yes\n"); | ||||
| 		pty_close_sigio = 1; | ||||
| 	} else | ||||
| 		printk(UM_KERN_CONT "No, enabling workaround\n"); | ||||
| } | ||||
| 
 | ||||
| static void __init check_sigio(void) | ||||
| { | ||||
| 	if ((access("/dev/ptmx", R_OK) < 0) && | ||||
| 	    (access("/dev/ptyp0", R_OK) < 0)) { | ||||
| 		printk(UM_KERN_WARNING "No pseudo-terminals available - " | ||||
| 		       "skipping pty SIGIO check\n"); | ||||
| 		return; | ||||
| 	} | ||||
| 	check_one_sigio(tty_output); | ||||
| 	check_one_sigio(tty_close); | ||||
| } | ||||
| 
 | ||||
| /* Here because it only does the SIGIO testing for now */ | ||||
| void __init os_check_bugs(void) | ||||
| { | ||||
| 	check_sigio(); | ||||
| } | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 awab228
						awab228