| 
									
										
										
										
											2007-02-10 01:44:02 -08:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  |  * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{linux.intel,addtoit}.com) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  * Licensed under the GPL | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-08 03:27:32 +01:00
										 |  |  | #include <linux/completion.h>
 | 
					
						
							|  |  |  | #include <linux/interrupt.h>
 | 
					
						
							|  |  |  | #include <linux/list.h>
 | 
					
						
							|  |  |  | #include <linux/mutex.h>
 | 
					
						
							|  |  |  | #include <linux/slab.h>
 | 
					
						
							|  |  |  | #include <linux/workqueue.h>
 | 
					
						
							|  |  |  | #include <asm/atomic.h>
 | 
					
						
							|  |  |  | #include <init.h>
 | 
					
						
							|  |  |  | #include <irq_kern.h>
 | 
					
						
							|  |  |  | #include <os.h>
 | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | #include "port.h"
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | struct port_list { | 
					
						
							|  |  |  | 	struct list_head list; | 
					
						
							|  |  |  | 	atomic_t wait_count; | 
					
						
							|  |  |  | 	int has_connection; | 
					
						
							|  |  |  | 	struct completion done; | 
					
						
							|  |  |  | 	int port; | 
					
						
							|  |  |  | 	int fd; | 
					
						
							|  |  |  | 	spinlock_t lock; | 
					
						
							|  |  |  | 	struct list_head pending; | 
					
						
							|  |  |  | 	struct list_head connections; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct port_dev { | 
					
						
							|  |  |  | 	struct port_list *port; | 
					
						
							|  |  |  | 	int helper_pid; | 
					
						
							|  |  |  | 	int telnetd_pid; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct connection { | 
					
						
							|  |  |  | 	struct list_head list; | 
					
						
							|  |  |  | 	int fd; | 
					
						
							|  |  |  | 	int helper_pid; | 
					
						
							|  |  |  | 	int socket[2]; | 
					
						
							|  |  |  | 	int telnetd_pid; | 
					
						
							|  |  |  | 	struct port_list *port; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-10-08 22:49:34 +01:00
										 |  |  | static irqreturn_t pipe_interrupt(int irq, void *data) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct connection *conn = data; | 
					
						
							|  |  |  | 	int fd; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	fd = os_rcv_fd(conn->socket[0], &conn->helper_pid); | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 	if (fd < 0) { | 
					
						
							|  |  |  | 		if (fd == -EAGAIN) | 
					
						
							| 
									
										
										
										
											2007-02-10 01:44:02 -08:00
										 |  |  | 			return IRQ_NONE; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-10 01:44:02 -08:00
										 |  |  | 		printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n", | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		       -fd); | 
					
						
							|  |  |  | 		os_close_file(conn->fd); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	list_del(&conn->list); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	conn->fd = fd; | 
					
						
							|  |  |  | 	list_add(&conn->list, &conn->port->connections); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	complete(&conn->port->done); | 
					
						
							| 
									
										
										
										
											2007-02-10 01:44:02 -08:00
										 |  |  | 	return IRQ_HANDLED; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define NO_WAITER_MSG \
 | 
					
						
							|  |  |  |     "****\n" \ | 
					
						
							|  |  |  |     "There are currently no UML consoles waiting for port connections.\n" \ | 
					
						
							|  |  |  |     "Either disconnect from one to make it available or activate some more\n" \ | 
					
						
							|  |  |  |     "by enabling more consoles in the UML /etc/inittab.\n" \ | 
					
						
							|  |  |  |     "****\n" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int port_accept(struct port_list *port) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct connection *conn; | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 	int fd, socket[2], pid; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	fd = port_connection(port->fd, socket, &pid); | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 	if (fd < 0) { | 
					
						
							|  |  |  | 		if (fd != -EAGAIN) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			printk(KERN_ERR "port_accept : port_connection " | 
					
						
							|  |  |  | 			       "returned %d\n", -fd); | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	conn = kmalloc(sizeof(*conn), GFP_ATOMIC); | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 	if (conn == NULL) { | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		printk(KERN_ERR "port_accept : failed to allocate " | 
					
						
							|  |  |  | 		       "connection\n"); | 
					
						
							|  |  |  | 		goto out_close; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-02-10 01:44:02 -08:00
										 |  |  | 	*conn = ((struct connection) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		{ .list 	= LIST_HEAD_INIT(conn->list), | 
					
						
							|  |  |  | 		  .fd 		= fd, | 
					
						
							|  |  |  | 		  .socket  	= { socket[0], socket[1] }, | 
					
						
							|  |  |  | 		  .telnetd_pid 	= pid, | 
					
						
							|  |  |  | 		  .port 	= port }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 	if (um_request_irq(TELNETD_IRQ, socket[0], IRQ_READ, pipe_interrupt, | 
					
						
							| 
									
										
										
										
											2012-07-17 14:18:23 -04:00
										 |  |  | 			  IRQF_SHARED, "telnetd", conn)) { | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		printk(KERN_ERR "port_accept : failed to get IRQ for " | 
					
						
							|  |  |  | 		       "telnetd\n"); | 
					
						
							|  |  |  | 		goto out_free; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 	if (atomic_read(&port->wait_count) == 0) { | 
					
						
							| 
									
										
										
										
											2007-05-06 14:51:43 -07:00
										 |  |  | 		os_write_file(fd, NO_WAITER_MSG, sizeof(NO_WAITER_MSG)); | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 		printk(KERN_ERR "No one waiting for port\n"); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	list_add(&conn->list, &port->pending); | 
					
						
							| 
									
										
										
										
											2007-02-10 01:44:02 -08:00
										 |  |  | 	return 1; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |  out_free: | 
					
						
							|  |  |  | 	kfree(conn); | 
					
						
							|  |  |  |  out_close: | 
					
						
							|  |  |  | 	os_close_file(fd); | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 	os_kill_process(pid, 1); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  out: | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 	return 0; | 
					
						
							| 
									
										
										
										
											2007-02-10 01:44:02 -08:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-04 22:31:27 -08:00
										 |  |  | static DEFINE_MUTEX(ports_mutex); | 
					
						
							| 
									
										
										
										
											2007-02-10 01:44:04 -08:00
										 |  |  | static LIST_HEAD(ports); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | static void port_work_proc(struct work_struct *unused) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct port_list *port; | 
					
						
							|  |  |  | 	struct list_head *ele; | 
					
						
							|  |  |  | 	unsigned long flags; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	local_irq_save(flags); | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 	list_for_each(ele, &ports) { | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		port = list_entry(ele, struct port_list, list); | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 		if (!port->has_connection) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		reactivate_fd(port->fd, ACCEPT_IRQ); | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 		while (port_accept(port)) | 
					
						
							|  |  |  | 			; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		port->has_connection = 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	local_irq_restore(flags); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-12-05 19:36:26 +00:00
										 |  |  | DECLARE_WORK(port_work, port_work_proc); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-10-08 22:49:34 +01:00
										 |  |  | static irqreturn_t port_interrupt(int irq, void *data) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	struct port_list *port = data; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	port->has_connection = 1; | 
					
						
							|  |  |  | 	schedule_work(&port_work); | 
					
						
							| 
									
										
										
										
											2007-02-10 01:44:02 -08:00
										 |  |  | 	return IRQ_HANDLED; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | void *port_data(int port_num) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct list_head *ele; | 
					
						
							|  |  |  | 	struct port_list *port; | 
					
						
							|  |  |  | 	struct port_dev *dev = NULL; | 
					
						
							|  |  |  | 	int fd; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-02-04 22:31:27 -08:00
										 |  |  | 	mutex_lock(&ports_mutex); | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 	list_for_each(ele, &ports) { | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		port = list_entry(ele, struct port_list, list); | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 		if (port->port == port_num) | 
					
						
							|  |  |  | 			goto found; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	port = kmalloc(sizeof(struct port_list), GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 	if (port == NULL) { | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		printk(KERN_ERR "Allocation of port list failed\n"); | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	fd = port_listen_fd(port_num); | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 	if (fd < 0) { | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		printk(KERN_ERR "binding to port %d failed, errno = %d\n", | 
					
						
							|  |  |  | 		       port_num, -fd); | 
					
						
							|  |  |  | 		goto out_free; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt, | 
					
						
							| 
									
										
										
										
											2012-07-17 14:18:23 -04:00
										 |  |  | 			  IRQF_SHARED, "port", port)) { | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		printk(KERN_ERR "Failed to get IRQ for port %d\n", port_num); | 
					
						
							|  |  |  | 		goto out_close; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-10 01:44:02 -08:00
										 |  |  | 	*port = ((struct port_list) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		{ .list 	 	= LIST_HEAD_INIT(port->list), | 
					
						
							|  |  |  | 		  .wait_count		= ATOMIC_INIT(0), | 
					
						
							|  |  |  | 		  .has_connection 	= 0, | 
					
						
							|  |  |  | 		  .port 	 	= port_num, | 
					
						
							|  |  |  | 		  .fd  			= fd, | 
					
						
							|  |  |  | 		  .pending 		= LIST_HEAD_INIT(port->pending), | 
					
						
							|  |  |  | 		  .connections 		= LIST_HEAD_INIT(port->connections) }); | 
					
						
							|  |  |  | 	spin_lock_init(&port->lock); | 
					
						
							|  |  |  | 	init_completion(&port->done); | 
					
						
							|  |  |  | 	list_add(&port->list, &ports); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  found: | 
					
						
							|  |  |  | 	dev = kmalloc(sizeof(struct port_dev), GFP_KERNEL); | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 	if (dev == NULL) { | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		printk(KERN_ERR "Allocation of port device entry failed\n"); | 
					
						
							|  |  |  | 		goto out; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*dev = ((struct port_dev) { .port  		= port, | 
					
						
							|  |  |  | 				    .helper_pid  	= -1, | 
					
						
							|  |  |  | 				    .telnetd_pid  	= -1 }); | 
					
						
							|  |  |  | 	goto out; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  out_close: | 
					
						
							|  |  |  | 	os_close_file(fd); | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:40 -07:00
										 |  |  |  out_free: | 
					
						
							|  |  |  | 	kfree(port); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  |  out: | 
					
						
							| 
									
										
										
										
											2008-02-04 22:31:27 -08:00
										 |  |  | 	mutex_unlock(&ports_mutex); | 
					
						
							| 
									
										
										
										
											2007-02-10 01:44:02 -08:00
										 |  |  | 	return dev; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int port_wait(void *data) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct port_dev *dev = data; | 
					
						
							|  |  |  | 	struct connection *conn; | 
					
						
							|  |  |  | 	struct port_list *port = dev->port; | 
					
						
							|  |  |  | 	int fd; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-10 01:44:02 -08:00
										 |  |  | 	atomic_inc(&port->wait_count); | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 	while (1) { | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		fd = -ERESTARTSYS; | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 		if (wait_for_completion_interruptible(&port->done)) | 
					
						
							| 
									
										
										
										
											2007-02-10 01:44:02 -08:00
										 |  |  | 			goto out; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		spin_lock(&port->lock); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-02-10 01:44:02 -08:00
										 |  |  | 		conn = list_entry(port->connections.next, struct connection, | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 				  list); | 
					
						
							|  |  |  | 		list_del(&conn->list); | 
					
						
							|  |  |  | 		spin_unlock(&port->lock); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		os_shutdown_socket(conn->socket[0], 1, 1); | 
					
						
							|  |  |  | 		os_close_file(conn->socket[0]); | 
					
						
							|  |  |  | 		os_shutdown_socket(conn->socket[1], 1, 1); | 
					
						
							| 
									
										
										
										
											2007-02-10 01:44:02 -08:00
										 |  |  | 		os_close_file(conn->socket[1]); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		/* This is done here because freeing an IRQ can't be done
 | 
					
						
							|  |  |  | 		 * within the IRQ handler.  So, pipe_interrupt always ups | 
					
						
							|  |  |  | 		 * the semaphore regardless of whether it got a successful | 
					
						
							| 
									
										
										
										
											2007-02-10 01:44:02 -08:00
										 |  |  | 		 * connection.  Then we loop here throwing out failed | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		 * connections until a good one is found. | 
					
						
							|  |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2012-04-17 22:37:13 +02:00
										 |  |  | 		um_free_irq(TELNETD_IRQ, conn); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 		if (conn->fd >= 0) | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		os_close_file(conn->fd); | 
					
						
							|  |  |  | 		kfree(conn); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	fd = conn->fd; | 
					
						
							|  |  |  | 	dev->helper_pid = conn->helper_pid; | 
					
						
							|  |  |  | 	dev->telnetd_pid = conn->telnetd_pid; | 
					
						
							|  |  |  | 	kfree(conn); | 
					
						
							|  |  |  |  out: | 
					
						
							|  |  |  | 	atomic_dec(&port->wait_count); | 
					
						
							|  |  |  | 	return fd; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void port_remove_dev(void *d) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct port_dev *dev = d; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 	if (dev->helper_pid != -1) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		os_kill_process(dev->helper_pid, 0); | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 	if (dev->telnetd_pid != -1) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		os_kill_process(dev->telnetd_pid, 1); | 
					
						
							|  |  |  | 	dev->helper_pid = -1; | 
					
						
							|  |  |  | 	dev->telnetd_pid = -1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void port_kern_free(void *d) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct port_dev *dev = d; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	port_remove_dev(dev); | 
					
						
							|  |  |  | 	kfree(dev); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void free_port(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	struct list_head *ele; | 
					
						
							|  |  |  | 	struct port_list *port; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2007-10-16 01:26:41 -07:00
										 |  |  | 	list_for_each(ele, &ports) { | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 		port = list_entry(ele, struct port_list, list); | 
					
						
							|  |  |  | 		free_irq_by_fd(port->fd); | 
					
						
							|  |  |  | 		os_close_file(port->fd); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | __uml_exitcall(free_port); |