]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - arch/um/drivers/port_kern.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/drzeus/mmc
[linux-2.6-omap-h63xx.git] / arch / um / drivers / port_kern.c
1 /*
2  * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com)
3  * Licensed under the GPL
4  */
5
6 #include "linux/list.h"
7 #include "linux/sched.h"
8 #include "linux/slab.h"
9 #include "linux/interrupt.h"
10 #include "linux/spinlock.h"
11 #include "linux/errno.h"
12 #include "asm/atomic.h"
13 #include "asm/semaphore.h"
14 #include "asm/errno.h"
15 #include "kern_util.h"
16 #include "kern.h"
17 #include "irq_user.h"
18 #include "irq_kern.h"
19 #include "port.h"
20 #include "init.h"
21 #include "os.h"
22
23 struct port_list {
24         struct list_head list;
25         atomic_t wait_count;
26         int has_connection;
27         struct completion done;
28         int port;
29         int fd;
30         spinlock_t lock;
31         struct list_head pending;
32         struct list_head connections;
33 };
34
35 struct port_dev {
36         struct port_list *port;
37         int helper_pid;
38         int telnetd_pid;
39 };
40
41 struct connection {
42         struct list_head list;
43         int fd;
44         int helper_pid;
45         int socket[2];
46         int telnetd_pid;
47         struct port_list *port;
48 };
49
50 static irqreturn_t pipe_interrupt(int irq, void *data)
51 {
52         struct connection *conn = data;
53         int fd;
54
55         fd = os_rcv_fd(conn->socket[0], &conn->helper_pid);
56         if(fd < 0){
57                 if(fd == -EAGAIN)
58                         return IRQ_NONE;
59
60                 printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n",
61                        -fd);
62                 os_close_file(conn->fd);
63         }
64
65         list_del(&conn->list);
66
67         conn->fd = fd;
68         list_add(&conn->list, &conn->port->connections);
69
70         complete(&conn->port->done);
71         return IRQ_HANDLED;
72 }
73
74 #define NO_WAITER_MSG \
75     "****\n" \
76     "There are currently no UML consoles waiting for port connections.\n" \
77     "Either disconnect from one to make it available or activate some more\n" \
78     "by enabling more consoles in the UML /etc/inittab.\n" \
79     "****\n"
80
81 static int port_accept(struct port_list *port)
82 {
83         struct connection *conn;
84         int fd, socket[2], pid, ret = 0;
85
86         fd = port_connection(port->fd, socket, &pid);
87         if(fd < 0){
88                 if(fd != -EAGAIN)
89                         printk(KERN_ERR "port_accept : port_connection "
90                                "returned %d\n", -fd);
91                 goto out;
92         }
93
94         conn = kmalloc(sizeof(*conn), GFP_ATOMIC);
95         if(conn == NULL){
96                 printk(KERN_ERR "port_accept : failed to allocate "
97                        "connection\n");
98                 goto out_close;
99         }
100         *conn = ((struct connection)
101                 { .list         = LIST_HEAD_INIT(conn->list),
102                   .fd           = fd,
103                   .socket       = { socket[0], socket[1] },
104                   .telnetd_pid  = pid,
105                   .port         = port });
106
107         if(um_request_irq(TELNETD_IRQ, socket[0], IRQ_READ, pipe_interrupt,
108                           IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
109                           "telnetd", conn)){
110                 printk(KERN_ERR "port_accept : failed to get IRQ for "
111                        "telnetd\n");
112                 goto out_free;
113         }
114
115         if(atomic_read(&port->wait_count) == 0){
116                 os_write_file(fd, NO_WAITER_MSG, sizeof(NO_WAITER_MSG));
117                 printk("No one waiting for port\n");
118         }
119         list_add(&conn->list, &port->pending);
120         return 1;
121
122  out_free:
123         kfree(conn);
124  out_close:
125         os_close_file(fd);
126         if(pid != -1)
127                 os_kill_process(pid, 1);
128  out:
129         return ret;
130 }
131
132 static DECLARE_MUTEX(ports_sem);
133 static LIST_HEAD(ports);
134
135 void port_work_proc(struct work_struct *unused)
136 {
137         struct port_list *port;
138         struct list_head *ele;
139         unsigned long flags;
140
141         local_irq_save(flags);
142         list_for_each(ele, &ports){
143                 port = list_entry(ele, struct port_list, list);
144                 if(!port->has_connection)
145                         continue;
146                 reactivate_fd(port->fd, ACCEPT_IRQ);
147                 while(port_accept(port)) ;
148                 port->has_connection = 0;
149         }
150         local_irq_restore(flags);
151 }
152
153 DECLARE_WORK(port_work, port_work_proc);
154
155 static irqreturn_t port_interrupt(int irq, void *data)
156 {
157         struct port_list *port = data;
158
159         port->has_connection = 1;
160         schedule_work(&port_work);
161         return IRQ_HANDLED;
162 }
163
164 void *port_data(int port_num)
165 {
166         struct list_head *ele;
167         struct port_list *port;
168         struct port_dev *dev = NULL;
169         int fd;
170
171         down(&ports_sem);
172         list_for_each(ele, &ports){
173                 port = list_entry(ele, struct port_list, list);
174                 if(port->port == port_num) goto found;
175         }
176         port = kmalloc(sizeof(struct port_list), GFP_KERNEL);
177         if(port == NULL){
178                 printk(KERN_ERR "Allocation of port list failed\n");
179                 goto out;
180         }
181
182         fd = port_listen_fd(port_num);
183         if(fd < 0){
184                 printk(KERN_ERR "binding to port %d failed, errno = %d\n",
185                        port_num, -fd);
186                 goto out_free;
187         }
188         if(um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt,
189                           IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
190                           "port", port)){
191                 printk(KERN_ERR "Failed to get IRQ for port %d\n", port_num);
192                 goto out_close;
193         }
194
195         *port = ((struct port_list)
196                 { .list                 = LIST_HEAD_INIT(port->list),
197                   .wait_count           = ATOMIC_INIT(0),
198                   .has_connection       = 0,
199                   .port                 = port_num,
200                   .fd                   = fd,
201                   .pending              = LIST_HEAD_INIT(port->pending),
202                   .connections          = LIST_HEAD_INIT(port->connections) });
203         spin_lock_init(&port->lock);
204         init_completion(&port->done);
205         list_add(&port->list, &ports);
206
207  found:
208         dev = kmalloc(sizeof(struct port_dev), GFP_KERNEL);
209         if(dev == NULL){
210                 printk(KERN_ERR "Allocation of port device entry failed\n");
211                 goto out;
212         }
213
214         *dev = ((struct port_dev) { .port               = port,
215                                     .helper_pid         = -1,
216                                     .telnetd_pid        = -1 });
217         goto out;
218
219  out_free:
220         kfree(port);
221  out_close:
222         os_close_file(fd);
223  out:
224         up(&ports_sem);
225         return dev;
226 }
227
228 int port_wait(void *data)
229 {
230         struct port_dev *dev = data;
231         struct connection *conn;
232         struct port_list *port = dev->port;
233         int fd;
234
235         atomic_inc(&port->wait_count);
236         while(1){
237                 fd = -ERESTARTSYS;
238                 if(wait_for_completion_interruptible(&port->done))
239                         goto out;
240
241                 spin_lock(&port->lock);
242
243                 conn = list_entry(port->connections.next, struct connection,
244                                   list);
245                 list_del(&conn->list);
246                 spin_unlock(&port->lock);
247
248                 os_shutdown_socket(conn->socket[0], 1, 1);
249                 os_close_file(conn->socket[0]);
250                 os_shutdown_socket(conn->socket[1], 1, 1);
251                 os_close_file(conn->socket[1]);
252
253                 /* This is done here because freeing an IRQ can't be done
254                  * within the IRQ handler.  So, pipe_interrupt always ups
255                  * the semaphore regardless of whether it got a successful
256                  * connection.  Then we loop here throwing out failed
257                  * connections until a good one is found.
258                  */
259                 free_irq(TELNETD_IRQ, conn);
260
261                 if(conn->fd >= 0) break;
262                 os_close_file(conn->fd);
263                 kfree(conn);
264         }
265
266         fd = conn->fd;
267         dev->helper_pid = conn->helper_pid;
268         dev->telnetd_pid = conn->telnetd_pid;
269         kfree(conn);
270  out:
271         atomic_dec(&port->wait_count);
272         return fd;
273 }
274
275 void port_remove_dev(void *d)
276 {
277         struct port_dev *dev = d;
278
279         if(dev->helper_pid != -1)
280                 os_kill_process(dev->helper_pid, 0);
281         if(dev->telnetd_pid != -1)
282                 os_kill_process(dev->telnetd_pid, 1);
283         dev->helper_pid = -1;
284         dev->telnetd_pid = -1;
285 }
286
287 void port_kern_free(void *d)
288 {
289         struct port_dev *dev = d;
290
291         port_remove_dev(dev);
292         kfree(dev);
293 }
294
295 static void free_port(void)
296 {
297         struct list_head *ele;
298         struct port_list *port;
299
300         list_for_each(ele, &ports){
301                 port = list_entry(ele, struct port_list, list);
302                 free_irq_by_fd(port->fd);
303                 os_close_file(port->fd);
304         }
305 }
306
307 __uml_exitcall(free_port);