]> err.no Git - linux-2.6/blob - drivers/s390/char/fs3270.c
Merge branch 'davem-fixes' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik...
[linux-2.6] / drivers / s390 / char / fs3270.c
1 /*
2  *  drivers/s390/char/fs3270.c
3  *    IBM/3270 Driver - fullscreen driver.
4  *
5  *  Author(s):
6  *    Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
7  *    Rewritten for 2.5/2.6 by Martin Schwidefsky <schwidefsky@de.ibm.com>
8  *      -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
9  */
10
11 #include <linux/bootmem.h>
12 #include <linux/console.h>
13 #include <linux/init.h>
14 #include <linux/interrupt.h>
15 #include <linux/list.h>
16 #include <linux/types.h>
17
18 #include <asm/ccwdev.h>
19 #include <asm/cio.h>
20 #include <asm/ebcdic.h>
21 #include <asm/idals.h>
22
23 #include "raw3270.h"
24 #include "ctrlchar.h"
25
26 static struct raw3270_fn fs3270_fn;
27
28 struct fs3270 {
29         struct raw3270_view view;
30         struct pid *fs_pid;             /* Pid of controlling program. */
31         int read_command;               /* ccw command to use for reads. */
32         int write_command;              /* ccw command to use for writes. */
33         int attention;                  /* Got attention. */
34         int active;                     /* Fullscreen view is active. */
35         struct raw3270_request *init;   /* single init request. */
36         wait_queue_head_t wait;         /* Init & attention wait queue. */
37         struct idal_buffer *rdbuf;      /* full-screen-deactivate buffer */
38         size_t rdbuf_size;              /* size of data returned by RDBUF */
39 };
40
41 static void
42 fs3270_wake_up(struct raw3270_request *rq, void *data)
43 {
44         wake_up((wait_queue_head_t *) data);
45 }
46
47 static inline int
48 fs3270_working(struct fs3270 *fp)
49 {
50         /*
51          * The fullscreen view is in working order if the view
52          * has been activated AND the initial request is finished.
53          */
54         return fp->active && raw3270_request_final(fp->init);
55 }
56
57 static int
58 fs3270_do_io(struct raw3270_view *view, struct raw3270_request *rq)
59 {
60         struct fs3270 *fp;
61         int rc;
62
63         fp = (struct fs3270 *) view;
64         rq->callback = fs3270_wake_up;
65         rq->callback_data = &fp->wait;
66
67         do {
68                 if (!fs3270_working(fp)) {
69                         /* Fullscreen view isn't ready yet. */
70                         rc = wait_event_interruptible(fp->wait,
71                                                       fs3270_working(fp));
72                         if (rc != 0)
73                                 break;
74                 }
75                 rc = raw3270_start(view, rq);
76                 if (rc == 0) {
77                         /* Started sucessfully. Now wait for completion. */
78                         wait_event(fp->wait, raw3270_request_final(rq));
79                 }
80         } while (rc == -EACCES);
81         return rc;
82 }
83
84 /*
85  * Switch to the fullscreen view.
86  */
87 static void
88 fs3270_reset_callback(struct raw3270_request *rq, void *data)
89 {
90         struct fs3270 *fp;
91
92         fp = (struct fs3270 *) rq->view;
93         raw3270_request_reset(rq);
94         wake_up(&fp->wait);
95 }
96
97 static void
98 fs3270_restore_callback(struct raw3270_request *rq, void *data)
99 {
100         struct fs3270 *fp;
101
102         fp = (struct fs3270 *) rq->view;
103         if (rq->rc != 0 || rq->rescnt != 0) {
104                 if (fp->fs_pid)
105                         kill_pid(fp->fs_pid, SIGHUP, 1);
106         }
107         fp->rdbuf_size = 0;
108         raw3270_request_reset(rq);
109         wake_up(&fp->wait);
110 }
111
112 static int
113 fs3270_activate(struct raw3270_view *view)
114 {
115         struct fs3270 *fp;
116         char *cp;
117         int rc;
118
119         fp = (struct fs3270 *) view;
120
121         /* If an old init command is still running just return. */
122         if (!raw3270_request_final(fp->init))
123                 return 0;
124
125         if (fp->rdbuf_size == 0) {
126                 /* No saved buffer. Just clear the screen. */
127                 raw3270_request_set_cmd(fp->init, TC_EWRITEA);
128                 fp->init->callback = fs3270_reset_callback;
129         } else {
130                 /* Restore fullscreen buffer saved by fs3270_deactivate. */
131                 raw3270_request_set_cmd(fp->init, TC_EWRITEA);
132                 raw3270_request_set_idal(fp->init, fp->rdbuf);
133                 fp->init->ccw.count = fp->rdbuf_size;
134                 cp = fp->rdbuf->data[0];
135                 cp[0] = TW_KR;
136                 cp[1] = TO_SBA;
137                 cp[2] = cp[6];
138                 cp[3] = cp[7];
139                 cp[4] = TO_IC;
140                 cp[5] = TO_SBA;
141                 cp[6] = 0x40;
142                 cp[7] = 0x40;
143                 fp->init->rescnt = 0;
144                 fp->init->callback = fs3270_restore_callback;
145         }
146         rc = fp->init->rc = raw3270_start_locked(view, fp->init);
147         if (rc)
148                 fp->init->callback(fp->init, NULL);
149         else
150                 fp->active = 1;
151         return rc;
152 }
153
154 /*
155  * Shutdown fullscreen view.
156  */
157 static void
158 fs3270_save_callback(struct raw3270_request *rq, void *data)
159 {
160         struct fs3270 *fp;
161
162         fp = (struct fs3270 *) rq->view;
163
164         /* Correct idal buffer element 0 address. */
165         fp->rdbuf->data[0] -= 5;
166         fp->rdbuf->size += 5;
167
168         /*
169          * If the rdbuf command failed or the idal buffer is
170          * to small for the amount of data returned by the
171          * rdbuf command, then we have no choice but to send
172          * a SIGHUP to the application.
173          */
174         if (rq->rc != 0 || rq->rescnt == 0) {
175                 if (fp->fs_pid)
176                         kill_pid(fp->fs_pid, SIGHUP, 1);
177                 fp->rdbuf_size = 0;
178         } else
179                 fp->rdbuf_size = fp->rdbuf->size - rq->rescnt;
180         raw3270_request_reset(rq);
181         wake_up(&fp->wait);
182 }
183
184 static void
185 fs3270_deactivate(struct raw3270_view *view)
186 {
187         struct fs3270 *fp;
188
189         fp = (struct fs3270 *) view;
190         fp->active = 0;
191
192         /* If an old init command is still running just return. */
193         if (!raw3270_request_final(fp->init))
194                 return;
195
196         /* Prepare read-buffer request. */
197         raw3270_request_set_cmd(fp->init, TC_RDBUF);
198         /*
199          * Hackish: skip first 5 bytes of the idal buffer to make
200          * room for the TW_KR/TO_SBA/<address>/<address>/TO_IC sequence
201          * in the activation command.
202          */
203         fp->rdbuf->data[0] += 5;
204         fp->rdbuf->size -= 5;
205         raw3270_request_set_idal(fp->init, fp->rdbuf);
206         fp->init->rescnt = 0;
207         fp->init->callback = fs3270_save_callback;
208
209         /* Start I/O to read in the 3270 buffer. */
210         fp->init->rc = raw3270_start_locked(view, fp->init);
211         if (fp->init->rc)
212                 fp->init->callback(fp->init, NULL);
213 }
214
215 static int
216 fs3270_irq(struct fs3270 *fp, struct raw3270_request *rq, struct irb *irb)
217 {
218         /* Handle ATTN. Set indication and wake waiters for attention. */
219         if (irb->scsw.dstat & DEV_STAT_ATTENTION) {
220                 fp->attention = 1;
221                 wake_up(&fp->wait);
222         }
223
224         if (rq) {
225                 if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK)
226                         rq->rc = -EIO;
227                 else
228                         /* Normal end. Copy residual count. */
229                         rq->rescnt = irb->scsw.count;
230         }
231         return RAW3270_IO_DONE;
232 }
233
234 /*
235  * Process reads from fullscreen 3270.
236  */
237 static ssize_t
238 fs3270_read(struct file *filp, char __user *data, size_t count, loff_t *off)
239 {
240         struct fs3270 *fp;
241         struct raw3270_request *rq;
242         struct idal_buffer *ib;
243         ssize_t rc;
244         
245         if (count == 0 || count > 65535)
246                 return -EINVAL;
247         fp = filp->private_data;
248         if (!fp)
249                 return -ENODEV;
250         ib = idal_buffer_alloc(count, 0);
251         if (IS_ERR(ib))
252                 return -ENOMEM;
253         rq = raw3270_request_alloc(0);
254         if (!IS_ERR(rq)) {
255                 if (fp->read_command == 0 && fp->write_command != 0)
256                         fp->read_command = 6;
257                 raw3270_request_set_cmd(rq, fp->read_command ? : 2);
258                 raw3270_request_set_idal(rq, ib);
259                 rc = wait_event_interruptible(fp->wait, fp->attention);
260                 fp->attention = 0;
261                 if (rc == 0) {
262                         rc = fs3270_do_io(&fp->view, rq);
263                         if (rc == 0) {
264                                 count -= rq->rescnt;
265                                 if (idal_buffer_to_user(ib, data, count) != 0)
266                                         rc = -EFAULT;
267                                 else
268                                         rc = count;
269
270                         }
271                 }
272                 raw3270_request_free(rq);
273         } else
274                 rc = PTR_ERR(rq);
275         idal_buffer_free(ib);
276         return rc;
277 }
278
279 /*
280  * Process writes to fullscreen 3270.
281  */
282 static ssize_t
283 fs3270_write(struct file *filp, const char __user *data, size_t count, loff_t *off)
284 {
285         struct fs3270 *fp;
286         struct raw3270_request *rq;
287         struct idal_buffer *ib;
288         int write_command;
289         ssize_t rc;
290
291         fp = filp->private_data;
292         if (!fp)
293                 return -ENODEV;
294         ib = idal_buffer_alloc(count, 0);
295         if (IS_ERR(ib))
296                 return -ENOMEM;
297         rq = raw3270_request_alloc(0);
298         if (!IS_ERR(rq)) {
299                 if (idal_buffer_from_user(ib, data, count) == 0) {
300                         write_command = fp->write_command ? : 1;
301                         if (write_command == 5)
302                                 write_command = 13;
303                         raw3270_request_set_cmd(rq, write_command);
304                         raw3270_request_set_idal(rq, ib);
305                         rc = fs3270_do_io(&fp->view, rq);
306                         if (rc == 0)
307                                 rc = count - rq->rescnt;
308                 } else
309                         rc = -EFAULT;
310                 raw3270_request_free(rq);
311         } else
312                 rc = PTR_ERR(rq);
313         idal_buffer_free(ib);
314         return rc;
315 }
316
317 /*
318  * process ioctl commands for the tube driver
319  */
320 static long
321 fs3270_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
322 {
323         struct fs3270 *fp;
324         struct raw3270_iocb iocb;
325         int rc;
326
327         fp = filp->private_data;
328         if (!fp)
329                 return -ENODEV;
330         rc = 0;
331         lock_kernel();
332         switch (cmd) {
333         case TUBICMD:
334                 fp->read_command = arg;
335                 break;
336         case TUBOCMD:
337                 fp->write_command = arg;
338                 break;
339         case TUBGETI:
340                 rc = put_user(fp->read_command, (char __user *) arg);
341                 break;
342         case TUBGETO:
343                 rc = put_user(fp->write_command,(char __user *) arg);
344                 break;
345         case TUBGETMOD:
346                 iocb.model = fp->view.model;
347                 iocb.line_cnt = fp->view.rows;
348                 iocb.col_cnt = fp->view.cols;
349                 iocb.pf_cnt = 24;
350                 iocb.re_cnt = 20;
351                 iocb.map = 0;
352                 if (copy_to_user((char __user *) arg, &iocb,
353                                  sizeof(struct raw3270_iocb)))
354                         rc = -EFAULT;
355                 break;
356         }
357         unlock_kernel();
358         return rc;
359 }
360
361 /*
362  * Allocate fs3270 structure.
363  */
364 static struct fs3270 *
365 fs3270_alloc_view(void)
366 {
367         struct fs3270 *fp;
368
369         fp = kzalloc(sizeof(struct fs3270),GFP_KERNEL);
370         if (!fp)
371                 return ERR_PTR(-ENOMEM);
372         fp->init = raw3270_request_alloc(0);
373         if (IS_ERR(fp->init)) {
374                 kfree(fp);
375                 return ERR_PTR(-ENOMEM);
376         }
377         return fp;
378 }
379
380 /*
381  * Free fs3270 structure.
382  */
383 static void
384 fs3270_free_view(struct raw3270_view *view)
385 {
386         struct fs3270 *fp;
387
388         fp = (struct fs3270 *) view;
389         if (fp->rdbuf)
390                 idal_buffer_free(fp->rdbuf);
391         raw3270_request_free(((struct fs3270 *) view)->init);
392         kfree(view);
393 }
394
395 /*
396  * Unlink fs3270 data structure from filp.
397  */
398 static void
399 fs3270_release(struct raw3270_view *view)
400 {
401 }
402
403 /* View to a 3270 device. Can be console, tty or fullscreen. */
404 static struct raw3270_fn fs3270_fn = {
405         .activate = fs3270_activate,
406         .deactivate = fs3270_deactivate,
407         .intv = (void *) fs3270_irq,
408         .release = fs3270_release,
409         .free = fs3270_free_view
410 };
411
412 /*
413  * This routine is called whenever a 3270 fullscreen device is opened.
414  */
415 static int
416 fs3270_open(struct inode *inode, struct file *filp)
417 {
418         struct fs3270 *fp;
419         struct idal_buffer *ib;
420         int minor, rc;
421
422         if (imajor(filp->f_path.dentry->d_inode) != IBM_FS3270_MAJOR)
423                 return -ENODEV;
424         minor = iminor(filp->f_path.dentry->d_inode);
425         /* Check for minor 0 multiplexer. */
426         if (minor == 0) {
427                 struct tty_struct *tty;
428                 mutex_lock(&tty_mutex);
429                 tty = get_current_tty();
430                 if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) {
431                         mutex_unlock(&tty_mutex);
432                         return -ENODEV;
433                 }
434                 minor = tty->index + RAW3270_FIRSTMINOR;
435                 mutex_unlock(&tty_mutex);
436         }
437         /* Check if some other program is already using fullscreen mode. */
438         fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor);
439         if (!IS_ERR(fp)) {
440                 raw3270_put_view(&fp->view);
441                 return -EBUSY;
442         }
443         /* Allocate fullscreen view structure. */
444         fp = fs3270_alloc_view();
445         if (IS_ERR(fp))
446                 return PTR_ERR(fp);
447
448         init_waitqueue_head(&fp->wait);
449         fp->fs_pid = get_pid(task_pid(current));
450         rc = raw3270_add_view(&fp->view, &fs3270_fn, minor);
451         if (rc) {
452                 fs3270_free_view(&fp->view);
453                 return rc;
454         }
455
456         /* Allocate idal-buffer. */
457         ib = idal_buffer_alloc(2*fp->view.rows*fp->view.cols + 5, 0);
458         if (IS_ERR(ib)) {
459                 raw3270_put_view(&fp->view);
460                 raw3270_del_view(&fp->view);
461                 return PTR_ERR(fp);
462         }
463         fp->rdbuf = ib;
464
465         rc = raw3270_activate_view(&fp->view);
466         if (rc) {
467                 raw3270_put_view(&fp->view);
468                 raw3270_del_view(&fp->view);
469                 return rc;
470         }
471         filp->private_data = fp;
472         return 0;
473 }
474
475 /*
476  * This routine is called when the 3270 tty is closed. We wait
477  * for the remaining request to be completed. Then we clean up.
478  */
479 static int
480 fs3270_close(struct inode *inode, struct file *filp)
481 {
482         struct fs3270 *fp;
483
484         fp = filp->private_data;
485         filp->private_data = NULL;
486         if (fp) {
487                 put_pid(fp->fs_pid);
488                 fp->fs_pid = NULL;
489                 raw3270_reset(&fp->view);
490                 raw3270_put_view(&fp->view);
491                 raw3270_del_view(&fp->view);
492         }
493         return 0;
494 }
495
496 static const struct file_operations fs3270_fops = {
497         .owner           = THIS_MODULE,         /* owner */
498         .read            = fs3270_read,         /* read */
499         .write           = fs3270_write,        /* write */
500         .unlocked_ioctl  = fs3270_ioctl,        /* ioctl */
501         .compat_ioctl    = fs3270_ioctl,        /* ioctl */
502         .open           = fs3270_open,          /* open */
503         .release        = fs3270_close,         /* release */
504 };
505
506 /*
507  * 3270 fullscreen driver initialization.
508  */
509 static int __init
510 fs3270_init(void)
511 {
512         int rc;
513
514         rc = register_chrdev(IBM_FS3270_MAJOR, "fs3270", &fs3270_fops);
515         if (rc) {
516                 printk(KERN_ERR "fs3270 can't get major number %d: errno %d\n",
517                        IBM_FS3270_MAJOR, rc);
518                 return rc;
519         }
520         return 0;
521 }
522
523 static void __exit
524 fs3270_exit(void)
525 {
526         unregister_chrdev(IBM_FS3270_MAJOR, "fs3270");
527 }
528
529 MODULE_LICENSE("GPL");
530 MODULE_ALIAS_CHARDEV_MAJOR(IBM_FS3270_MAJOR);
531
532 module_init(fs3270_init);
533 module_exit(fs3270_exit);