aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRichard Hitt <rbh00@utsglobal.com>2005-10-30 18:00:10 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-10-30 20:37:16 -0500
commited3cb6f039bb296457bfd2877cba6ad0287d8d54 (patch)
treec65ff2b245f17ab7e1da6f279b9d004b447d23bc
parentd89ea9b8bb4c4ad63122cd2d2ee5110a52da51b8 (diff)
[PATCH] s390: 3270 fullscreen view
Martin Schwidefsky <schwidefsky@de.ibm.com> Fix fullscreen view of the 3270 device driver. Signed-off-by: Richard Hitt <rbh00@utsglobal.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--arch/s390/kernel/compat_ioctl.c9
-rw-r--r--drivers/s390/char/con3270.c7
-rw-r--r--drivers/s390/char/fs3270.c234
-rw-r--r--drivers/s390/char/raw3270.c100
-rw-r--r--drivers/s390/char/raw3270.h7
-rw-r--r--drivers/s390/char/tty3270.c27
6 files changed, 315 insertions, 69 deletions
diff --git a/arch/s390/kernel/compat_ioctl.c b/arch/s390/kernel/compat_ioctl.c
index 24a1e9f069a7..6504c4e69986 100644
--- a/arch/s390/kernel/compat_ioctl.c
+++ b/arch/s390/kernel/compat_ioctl.c
@@ -18,6 +18,8 @@
18#include <asm/dasd.h> 18#include <asm/dasd.h>
19#include <asm/cmb.h> 19#include <asm/cmb.h>
20#include <asm/tape390.h> 20#include <asm/tape390.h>
21#include <asm/ccwdev.h>
22#include "../../../drivers/s390/char/raw3270.h"
21 23
22static int do_ioctl32_pointer(unsigned int fd, unsigned int cmd, 24static int do_ioctl32_pointer(unsigned int fd, unsigned int cmd,
23 unsigned long arg, struct file *f) 25 unsigned long arg, struct file *f)
@@ -62,6 +64,13 @@ COMPATIBLE_IOCTL(BIODASDCMFENABLE)
62COMPATIBLE_IOCTL(BIODASDCMFDISABLE) 64COMPATIBLE_IOCTL(BIODASDCMFDISABLE)
63COMPATIBLE_IOCTL(BIODASDREADALLCMB) 65COMPATIBLE_IOCTL(BIODASDREADALLCMB)
64 66
67COMPATIBLE_IOCTL(TUBICMD)
68COMPATIBLE_IOCTL(TUBOCMD)
69COMPATIBLE_IOCTL(TUBGETI)
70COMPATIBLE_IOCTL(TUBGETO)
71COMPATIBLE_IOCTL(TUBSETMOD)
72COMPATIBLE_IOCTL(TUBGETMOD)
73
65COMPATIBLE_IOCTL(TAPE390_DISPLAY) 74COMPATIBLE_IOCTL(TAPE390_DISPLAY)
66 75
67/* s390 doesn't need handlers here */ 76/* s390 doesn't need handlers here */
diff --git a/drivers/s390/char/con3270.c b/drivers/s390/char/con3270.c
index fc7a213e591f..c570a9f6ce9c 100644
--- a/drivers/s390/char/con3270.c
+++ b/drivers/s390/char/con3270.c
@@ -213,6 +213,9 @@ con3270_update(struct con3270 *cp)
213 struct string *s, *n; 213 struct string *s, *n;
214 int rc; 214 int rc;
215 215
216 if (cp->view.dev)
217 raw3270_activate_view(&cp->view);
218
216 wrq = xchg(&cp->write, 0); 219 wrq = xchg(&cp->write, 0);
217 if (!wrq) { 220 if (!wrq) {
218 con3270_set_timer(cp, 1); 221 con3270_set_timer(cp, 1);
@@ -489,8 +492,6 @@ con3270_write(struct console *co, const char *str, unsigned int count)
489 unsigned char c; 492 unsigned char c;
490 493
491 cp = condev; 494 cp = condev;
492 if (cp->view.dev)
493 raw3270_activate_view(&cp->view);
494 spin_lock_irqsave(&cp->view.lock, flags); 495 spin_lock_irqsave(&cp->view.lock, flags);
495 while (count-- > 0) { 496 while (count-- > 0) {
496 c = *str++; 497 c = *str++;
@@ -620,7 +621,7 @@ con3270_init(void)
620 (void (*)(unsigned long)) con3270_read_tasklet, 621 (void (*)(unsigned long)) con3270_read_tasklet,
621 (unsigned long) condev->read); 622 (unsigned long) condev->read);
622 623
623 raw3270_add_view(&condev->view, &con3270_fn, 0); 624 raw3270_add_view(&condev->view, &con3270_fn, 1);
624 625
625 INIT_LIST_HEAD(&condev->freemem); 626 INIT_LIST_HEAD(&condev->freemem);
626 for (i = 0; i < CON3270_STRING_PAGES; i++) { 627 for (i = 0; i < CON3270_STRING_PAGES; i++) {
diff --git a/drivers/s390/char/fs3270.c b/drivers/s390/char/fs3270.c
index 60afcdcf91c2..735a7fcdeff5 100644
--- a/drivers/s390/char/fs3270.c
+++ b/drivers/s390/char/fs3270.c
@@ -33,8 +33,11 @@ struct fs3270 {
33 int read_command; /* ccw command to use for reads. */ 33 int read_command; /* ccw command to use for reads. */
34 int write_command; /* ccw command to use for writes. */ 34 int write_command; /* ccw command to use for writes. */
35 int attention; /* Got attention. */ 35 int attention; /* Got attention. */
36 struct raw3270_request *clear; /* single clear request. */ 36 int active; /* Fullscreen view is active. */
37 wait_queue_head_t attn_wait; /* Attention wait queue. */ 37 struct raw3270_request *init; /* single init request. */
38 wait_queue_head_t wait; /* Init & attention wait queue. */
39 struct idal_buffer *rdbuf; /* full-screen-deactivate buffer */
40 size_t rdbuf_size; /* size of data returned by RDBUF */
38}; 41};
39 42
40static void 43static void
@@ -43,58 +46,172 @@ fs3270_wake_up(struct raw3270_request *rq, void *data)
43 wake_up((wait_queue_head_t *) data); 46 wake_up((wait_queue_head_t *) data);
44} 47}
45 48
49static inline int
50fs3270_working(struct fs3270 *fp)
51{
52 /*
53 * The fullscreen view is in working order if the view
54 * has been activated AND the initial request is finished.
55 */
56 return fp->active && raw3270_request_final(fp->init);
57}
58
46static int 59static int
47fs3270_do_io(struct raw3270_view *view, struct raw3270_request *rq) 60fs3270_do_io(struct raw3270_view *view, struct raw3270_request *rq)
48{ 61{
49 wait_queue_head_t wq; 62 struct fs3270 *fp;
50 int rc; 63 int rc;
51 64
52 init_waitqueue_head(&wq); 65 fp = (struct fs3270 *) view;
53 rq->callback = fs3270_wake_up; 66 rq->callback = fs3270_wake_up;
54 rq->callback_data = &wq; 67 rq->callback_data = &fp->wait;
55 rc = raw3270_start(view, rq); 68
56 if (rc) 69 do {
57 return rc; 70 if (!fs3270_working(fp)) {
58 /* Started sucessfully. Now wait for completion. */ 71 /* Fullscreen view isn't ready yet. */
59 wait_event(wq, raw3270_request_final(rq)); 72 rc = wait_event_interruptible(fp->wait,
60 return rq->rc; 73 fs3270_working(fp));
74 if (rc != 0)
75 break;
76 }
77 rc = raw3270_start(view, rq);
78 if (rc == 0) {
79 /* Started sucessfully. Now wait for completion. */
80 wait_event(fp->wait, raw3270_request_final(rq));
81 }
82 } while (rc == -EACCES);
83 return rc;
61} 84}
62 85
86/*
87 * Switch to the fullscreen view.
88 */
63static void 89static void
64fs3270_reset_callback(struct raw3270_request *rq, void *data) 90fs3270_reset_callback(struct raw3270_request *rq, void *data)
65{ 91{
92 struct fs3270 *fp;
93
94 fp = (struct fs3270 *) rq->view;
66 raw3270_request_reset(rq); 95 raw3270_request_reset(rq);
96 wake_up(&fp->wait);
97}
98
99static void
100fs3270_restore_callback(struct raw3270_request *rq, void *data)
101{
102 struct fs3270 *fp;
103
104 fp = (struct fs3270 *) rq->view;
105 if (rq->rc != 0 || rq->rescnt != 0) {
106 if (fp->fs_pid)
107 kill_proc(fp->fs_pid, SIGHUP, 1);
108 }
109 fp->rdbuf_size = 0;
110 raw3270_request_reset(rq);
111 wake_up(&fp->wait);
67} 112}
68 113
69/*
70 * Switch to the fullscreen view.
71 */
72static int 114static int
73fs3270_activate(struct raw3270_view *view) 115fs3270_activate(struct raw3270_view *view)
74{ 116{
75 struct fs3270 *fp; 117 struct fs3270 *fp;
118 char *cp;
119 int rc;
76 120
77 fp = (struct fs3270 *) view; 121 fp = (struct fs3270 *) view;
78 raw3270_request_set_cmd(fp->clear, TC_EWRITEA); 122
79 fp->clear->callback = fs3270_reset_callback; 123 /* If an old init command is still running just return. */
80 return raw3270_start(view, fp->clear); 124 if (!raw3270_request_final(fp->init))
125 return 0;
126
127 if (fp->rdbuf_size == 0) {
128 /* No saved buffer. Just clear the screen. */
129 raw3270_request_set_cmd(fp->init, TC_EWRITEA);
130 fp->init->callback = fs3270_reset_callback;
131 } else {
132 /* Restore fullscreen buffer saved by fs3270_deactivate. */
133 raw3270_request_set_cmd(fp->init, TC_EWRITEA);
134 raw3270_request_set_idal(fp->init, fp->rdbuf);
135 fp->init->ccw.count = fp->rdbuf_size;
136 cp = fp->rdbuf->data[0];
137 cp[0] = TW_KR;
138 cp[1] = TO_SBA;
139 cp[2] = cp[6];
140 cp[3] = cp[7];
141 cp[4] = TO_IC;
142 cp[5] = TO_SBA;
143 cp[6] = 0x40;
144 cp[7] = 0x40;
145 fp->init->rescnt = 0;
146 fp->init->callback = fs3270_restore_callback;
147 }
148 rc = fp->init->rc = raw3270_start_locked(view, fp->init);
149 if (rc)
150 fp->init->callback(fp->init, NULL);
151 else
152 fp->active = 1;
153 return rc;
81} 154}
82 155
83/* 156/*
84 * Shutdown fullscreen view. 157 * Shutdown fullscreen view.
85 */ 158 */
86static void 159static void
160fs3270_save_callback(struct raw3270_request *rq, void *data)
161{
162 struct fs3270 *fp;
163
164 fp = (struct fs3270 *) rq->view;
165
166 /* Correct idal buffer element 0 address. */
167 fp->rdbuf->data[0] -= 5;
168 fp->rdbuf->size += 5;
169
170 /*
171 * If the rdbuf command failed or the idal buffer is
172 * to small for the amount of data returned by the
173 * rdbuf command, then we have no choice but to send
174 * a SIGHUP to the application.
175 */
176 if (rq->rc != 0 || rq->rescnt == 0) {
177 if (fp->fs_pid)
178 kill_proc(fp->fs_pid, SIGHUP, 1);
179 fp->rdbuf_size = 0;
180 } else
181 fp->rdbuf_size = fp->rdbuf->size - rq->rescnt;
182 raw3270_request_reset(rq);
183 wake_up(&fp->wait);
184}
185
186static void
87fs3270_deactivate(struct raw3270_view *view) 187fs3270_deactivate(struct raw3270_view *view)
88{ 188{
89 // FIXME: is this a good idea? The user program using fullscreen 3270
90 // will die just because a console message appeared. On the other
91 // hand the fullscreen device is unoperational now.
92 struct fs3270 *fp; 189 struct fs3270 *fp;
93 190
94 fp = (struct fs3270 *) view; 191 fp = (struct fs3270 *) view;
95 if (fp->fs_pid != 0) 192 fp->active = 0;
96 kill_proc(fp->fs_pid, SIGHUP, 1); 193
97 fp->fs_pid = 0; 194 /* If an old init command is still running just return. */
195 if (!raw3270_request_final(fp->init))
196 return;
197
198 /* Prepare read-buffer request. */
199 raw3270_request_set_cmd(fp->init, TC_RDBUF);
200 /*
201 * Hackish: skip first 5 bytes of the idal buffer to make
202 * room for the TW_KR/TO_SBA/<address>/<address>/TO_IC sequence
203 * in the activation command.
204 */
205 fp->rdbuf->data[0] += 5;
206 fp->rdbuf->size -= 5;
207 raw3270_request_set_idal(fp->init, fp->rdbuf);
208 fp->init->rescnt = 0;
209 fp->init->callback = fs3270_save_callback;
210
211 /* Start I/O to read in the 3270 buffer. */
212 fp->init->rc = raw3270_start_locked(view, fp->init);
213 if (fp->init->rc)
214 fp->init->callback(fp->init, NULL);
98} 215}
99 216
100static int 217static int
@@ -103,7 +220,7 @@ fs3270_irq(struct fs3270 *fp, struct raw3270_request *rq, struct irb *irb)
103 /* Handle ATTN. Set indication and wake waiters for attention. */ 220 /* Handle ATTN. Set indication and wake waiters for attention. */
104 if (irb->scsw.dstat & DEV_STAT_ATTENTION) { 221 if (irb->scsw.dstat & DEV_STAT_ATTENTION) {
105 fp->attention = 1; 222 fp->attention = 1;
106 wake_up(&fp->attn_wait); 223 wake_up(&fp->wait);
107 } 224 }
108 225
109 if (rq) { 226 if (rq) {
@@ -125,7 +242,7 @@ fs3270_read(struct file *filp, char *data, size_t count, loff_t *off)
125 struct fs3270 *fp; 242 struct fs3270 *fp;
126 struct raw3270_request *rq; 243 struct raw3270_request *rq;
127 struct idal_buffer *ib; 244 struct idal_buffer *ib;
128 int rc; 245 ssize_t rc;
129 246
130 if (count == 0 || count > 65535) 247 if (count == 0 || count > 65535)
131 return -EINVAL; 248 return -EINVAL;
@@ -133,7 +250,7 @@ fs3270_read(struct file *filp, char *data, size_t count, loff_t *off)
133 if (!fp) 250 if (!fp)
134 return -ENODEV; 251 return -ENODEV;
135 ib = idal_buffer_alloc(count, 0); 252 ib = idal_buffer_alloc(count, 0);
136 if (!ib) 253 if (IS_ERR(ib))
137 return -ENOMEM; 254 return -ENOMEM;
138 rq = raw3270_request_alloc(0); 255 rq = raw3270_request_alloc(0);
139 if (!IS_ERR(rq)) { 256 if (!IS_ERR(rq)) {
@@ -141,10 +258,19 @@ fs3270_read(struct file *filp, char *data, size_t count, loff_t *off)
141 fp->read_command = 6; 258 fp->read_command = 6;
142 raw3270_request_set_cmd(rq, fp->read_command ? : 2); 259 raw3270_request_set_cmd(rq, fp->read_command ? : 2);
143 raw3270_request_set_idal(rq, ib); 260 raw3270_request_set_idal(rq, ib);
144 wait_event(fp->attn_wait, fp->attention); 261 rc = wait_event_interruptible(fp->wait, fp->attention);
145 rc = fs3270_do_io(&fp->view, rq); 262 fp->attention = 0;
146 if (rc == 0 && idal_buffer_to_user(ib, data, count)) 263 if (rc == 0) {
147 rc = -EFAULT; 264 rc = fs3270_do_io(&fp->view, rq);
265 if (rc == 0) {
266 count -= rq->rescnt;
267 if (idal_buffer_to_user(ib, data, count) != 0)
268 rc = -EFAULT;
269 else
270 rc = count;
271
272 }
273 }
148 raw3270_request_free(rq); 274 raw3270_request_free(rq);
149 } else 275 } else
150 rc = PTR_ERR(rq); 276 rc = PTR_ERR(rq);
@@ -162,13 +288,13 @@ fs3270_write(struct file *filp, const char *data, size_t count, loff_t *off)
162 struct raw3270_request *rq; 288 struct raw3270_request *rq;
163 struct idal_buffer *ib; 289 struct idal_buffer *ib;
164 int write_command; 290 int write_command;
165 int rc; 291 ssize_t rc;
166 292
167 fp = filp->private_data; 293 fp = filp->private_data;
168 if (!fp) 294 if (!fp)
169 return -ENODEV; 295 return -ENODEV;
170 ib = idal_buffer_alloc(count, 0); 296 ib = idal_buffer_alloc(count, 0);
171 if (!ib) 297 if (IS_ERR(ib))
172 return -ENOMEM; 298 return -ENOMEM;
173 rq = raw3270_request_alloc(0); 299 rq = raw3270_request_alloc(0);
174 if (!IS_ERR(rq)) { 300 if (!IS_ERR(rq)) {
@@ -179,6 +305,8 @@ fs3270_write(struct file *filp, const char *data, size_t count, loff_t *off)
179 raw3270_request_set_cmd(rq, write_command); 305 raw3270_request_set_cmd(rq, write_command);
180 raw3270_request_set_idal(rq, ib); 306 raw3270_request_set_idal(rq, ib);
181 rc = fs3270_do_io(&fp->view, rq); 307 rc = fs3270_do_io(&fp->view, rq);
308 if (rc == 0)
309 rc = count - rq->rescnt;
182 } else 310 } else
183 rc = -EFAULT; 311 rc = -EFAULT;
184 raw3270_request_free(rq); 312 raw3270_request_free(rq);
@@ -232,7 +360,7 @@ fs3270_ioctl(struct inode *inode, struct file *filp,
232} 360}
233 361
234/* 362/*
235 * Allocate tty3270 structure. 363 * Allocate fs3270 structure.
236 */ 364 */
237static struct fs3270 * 365static struct fs3270 *
238fs3270_alloc_view(void) 366fs3270_alloc_view(void)
@@ -243,8 +371,8 @@ fs3270_alloc_view(void)
243 if (!fp) 371 if (!fp)
244 return ERR_PTR(-ENOMEM); 372 return ERR_PTR(-ENOMEM);
245 memset(fp, 0, sizeof(struct fs3270)); 373 memset(fp, 0, sizeof(struct fs3270));
246 fp->clear = raw3270_request_alloc(0); 374 fp->init = raw3270_request_alloc(0);
247 if (!IS_ERR(fp->clear)) { 375 if (IS_ERR(fp->init)) {
248 kfree(fp); 376 kfree(fp);
249 return ERR_PTR(-ENOMEM); 377 return ERR_PTR(-ENOMEM);
250 } 378 }
@@ -252,12 +380,17 @@ fs3270_alloc_view(void)
252} 380}
253 381
254/* 382/*
255 * Free tty3270 structure. 383 * Free fs3270 structure.
256 */ 384 */
257static void 385static void
258fs3270_free_view(struct raw3270_view *view) 386fs3270_free_view(struct raw3270_view *view)
259{ 387{
260 raw3270_request_free(((struct fs3270 *) view)->clear); 388 struct fs3270 *fp;
389
390 fp = (struct fs3270 *) view;
391 if (fp->rdbuf)
392 idal_buffer_free(fp->rdbuf);
393 raw3270_request_free(((struct fs3270 *) view)->init);
261 kfree(view); 394 kfree(view);
262} 395}
263 396
@@ -285,11 +418,20 @@ static int
285fs3270_open(struct inode *inode, struct file *filp) 418fs3270_open(struct inode *inode, struct file *filp)
286{ 419{
287 struct fs3270 *fp; 420 struct fs3270 *fp;
421 struct idal_buffer *ib;
288 int minor, rc; 422 int minor, rc;
289 423
290 if (imajor(filp->f_dentry->d_inode) != IBM_FS3270_MAJOR) 424 if (imajor(filp->f_dentry->d_inode) != IBM_FS3270_MAJOR)
291 return -ENODEV; 425 return -ENODEV;
292 minor = iminor(filp->f_dentry->d_inode); 426 minor = iminor(filp->f_dentry->d_inode);
427 /* Check for minor 0 multiplexer. */
428 if (minor == 0) {
429 if (!current->signal->tty)
430 return -ENODEV;
431 if (current->signal->tty->driver->major != IBM_TTY3270_MAJOR)
432 return -ENODEV;
433 minor = current->signal->tty->index + RAW3270_FIRSTMINOR;
434 }
293 /* Check if some other program is already using fullscreen mode. */ 435 /* Check if some other program is already using fullscreen mode. */
294 fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor); 436 fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor);
295 if (!IS_ERR(fp)) { 437 if (!IS_ERR(fp)) {
@@ -301,7 +443,7 @@ fs3270_open(struct inode *inode, struct file *filp)
301 if (IS_ERR(fp)) 443 if (IS_ERR(fp))
302 return PTR_ERR(fp); 444 return PTR_ERR(fp);
303 445
304 init_waitqueue_head(&fp->attn_wait); 446 init_waitqueue_head(&fp->wait);
305 fp->fs_pid = current->pid; 447 fp->fs_pid = current->pid;
306 rc = raw3270_add_view(&fp->view, &fs3270_fn, minor); 448 rc = raw3270_add_view(&fp->view, &fs3270_fn, minor);
307 if (rc) { 449 if (rc) {
@@ -309,8 +451,18 @@ fs3270_open(struct inode *inode, struct file *filp)
309 return rc; 451 return rc;
310 } 452 }
311 453
454 /* Allocate idal-buffer. */
455 ib = idal_buffer_alloc(2*fp->view.rows*fp->view.cols + 5, 0);
456 if (IS_ERR(ib)) {
457 raw3270_put_view(&fp->view);
458 raw3270_del_view(&fp->view);
459 return PTR_ERR(fp);
460 }
461 fp->rdbuf = ib;
462
312 rc = raw3270_activate_view(&fp->view); 463 rc = raw3270_activate_view(&fp->view);
313 if (rc) { 464 if (rc) {
465 raw3270_put_view(&fp->view);
314 raw3270_del_view(&fp->view); 466 raw3270_del_view(&fp->view);
315 return rc; 467 return rc;
316 } 468 }
@@ -329,8 +481,12 @@ fs3270_close(struct inode *inode, struct file *filp)
329 481
330 fp = filp->private_data; 482 fp = filp->private_data;
331 filp->private_data = 0; 483 filp->private_data = 0;
332 if (fp) 484 if (fp) {
485 fp->fs_pid = 0;
486 raw3270_reset(&fp->view);
487 raw3270_put_view(&fp->view);
333 raw3270_del_view(&fp->view); 488 raw3270_del_view(&fp->view);
489 }
334 return 0; 490 return 0;
335} 491}
336 492
diff --git a/drivers/s390/char/raw3270.c b/drivers/s390/char/raw3270.c
index 328d9cbc56a3..d66946443dfc 100644
--- a/drivers/s390/char/raw3270.c
+++ b/drivers/s390/char/raw3270.c
@@ -25,6 +25,12 @@
25 25
26#include "raw3270.h" 26#include "raw3270.h"
27 27
28#include <linux/major.h>
29#include <linux/kdev_t.h>
30#include <linux/device.h>
31
32struct class *class3270;
33
28/* The main 3270 data structure. */ 34/* The main 3270 data structure. */
29struct raw3270 { 35struct raw3270 {
30 struct list_head list; 36 struct list_head list;
@@ -41,6 +47,8 @@ struct raw3270 {
41 struct timer_list timer; /* Device timer. */ 47 struct timer_list timer; /* Device timer. */
42 48
43 unsigned char *ascebc; /* ascii -> ebcdic table */ 49 unsigned char *ascebc; /* ascii -> ebcdic table */
50 struct class_device *clttydev; /* 3270-class tty device ptr */
51 struct class_device *cltubdev; /* 3270-class tub device ptr */
44}; 52};
45 53
46/* raw3270->flags */ 54/* raw3270->flags */
@@ -317,6 +325,22 @@ raw3270_start(struct raw3270_view *view, struct raw3270_request *rq)
317} 325}
318 326
319int 327int
328raw3270_start_locked(struct raw3270_view *view, struct raw3270_request *rq)
329{
330 struct raw3270 *rp;
331 int rc;
332
333 rp = view->dev;
334 if (!rp || rp->view != view)
335 rc = -EACCES;
336 else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
337 rc = -ENODEV;
338 else
339 rc = __raw3270_start(rp, view, rq);
340 return rc;
341}
342
343int
320raw3270_start_irq(struct raw3270_view *view, struct raw3270_request *rq) 344raw3270_start_irq(struct raw3270_view *view, struct raw3270_request *rq)
321{ 345{
322 struct raw3270 *rp; 346 struct raw3270 *rp;
@@ -744,6 +768,22 @@ raw3270_reset_device(struct raw3270 *rp)
744 return rc; 768 return rc;
745} 769}
746 770
771int
772raw3270_reset(struct raw3270_view *view)
773{
774 struct raw3270 *rp;
775 int rc;
776
777 rp = view->dev;
778 if (!rp || rp->view != view)
779 rc = -EACCES;
780 else if (!test_bit(RAW3270_FLAGS_READY, &rp->flags))
781 rc = -ENODEV;
782 else
783 rc = raw3270_reset_device(view->dev);
784 return rc;
785}
786
747/* 787/*
748 * Setup new 3270 device. 788 * Setup new 3270 device.
749 */ 789 */
@@ -774,11 +814,12 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
774 814
775 /* 815 /*
776 * Add device to list and find the smallest unused minor 816 * Add device to list and find the smallest unused minor
777 * number for it. 817 * number for it. Note: there is no device with minor 0,
818 * see special case for fs3270.c:fs3270_open().
778 */ 819 */
779 down(&raw3270_sem); 820 down(&raw3270_sem);
780 /* Keep the list sorted. */ 821 /* Keep the list sorted. */
781 minor = 0; 822 minor = RAW3270_FIRSTMINOR;
782 rp->minor = -1; 823 rp->minor = -1;
783 list_for_each(l, &raw3270_devices) { 824 list_for_each(l, &raw3270_devices) {
784 tmp = list_entry(l, struct raw3270, list); 825 tmp = list_entry(l, struct raw3270, list);
@@ -789,7 +830,7 @@ raw3270_setup_device(struct ccw_device *cdev, struct raw3270 *rp, char *ascebc)
789 } 830 }
790 minor++; 831 minor++;
791 } 832 }
792 if (rp->minor == -1 && minor < RAW3270_MAXDEVS) { 833 if (rp->minor == -1 && minor < RAW3270_MAXDEVS + RAW3270_FIRSTMINOR) {
793 rp->minor = minor; 834 rp->minor = minor;
794 list_add_tail(&rp->list, &raw3270_devices); 835 list_add_tail(&rp->list, &raw3270_devices);
795 } 836 }
@@ -941,11 +982,12 @@ raw3270_deactivate_view(struct raw3270_view *view)
941 list_add_tail(&view->list, &rp->view_list); 982 list_add_tail(&view->list, &rp->view_list);
942 /* Try to activate another view. */ 983 /* Try to activate another view. */
943 if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) { 984 if (test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
944 list_for_each_entry(view, &rp->view_list, list) 985 list_for_each_entry(view, &rp->view_list, list) {
945 if (view->fn->activate(view) == 0) { 986 rp->view = view;
946 rp->view = view; 987 if (view->fn->activate(view) == 0)
947 break; 988 break;
948 } 989 rp->view = 0;
990 }
949 } 991 }
950 } 992 }
951 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); 993 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
@@ -961,6 +1003,8 @@ raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor)
961 struct raw3270 *rp; 1003 struct raw3270 *rp;
962 int rc; 1004 int rc;
963 1005
1006 if (minor <= 0)
1007 return -ENODEV;
964 down(&raw3270_sem); 1008 down(&raw3270_sem);
965 rc = -ENODEV; 1009 rc = -ENODEV;
966 list_for_each_entry(rp, &raw3270_devices, list) { 1010 list_for_each_entry(rp, &raw3270_devices, list) {
@@ -976,7 +1020,7 @@ raw3270_add_view(struct raw3270_view *view, struct raw3270_fn *fn, int minor)
976 view->cols = rp->cols; 1020 view->cols = rp->cols;
977 view->ascebc = rp->ascebc; 1021 view->ascebc = rp->ascebc;
978 spin_lock_init(&view->lock); 1022 spin_lock_init(&view->lock);
979 list_add_tail(&view->list, &rp->view_list); 1023 list_add(&view->list, &rp->view_list);
980 rc = 0; 1024 rc = 0;
981 } 1025 }
982 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags); 1026 spin_unlock_irqrestore(get_ccwdev_lock(rp->cdev), flags);
@@ -1039,7 +1083,7 @@ raw3270_del_view(struct raw3270_view *view)
1039 if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags)) { 1083 if (!rp->view && test_bit(RAW3270_FLAGS_READY, &rp->flags)) {
1040 /* Try to activate another view. */ 1084 /* Try to activate another view. */
1041 list_for_each_entry(nv, &rp->view_list, list) { 1085 list_for_each_entry(nv, &rp->view_list, list) {
1042 if (nv->fn->activate(view) == 0) { 1086 if (nv->fn->activate(nv) == 0) {
1043 rp->view = nv; 1087 rp->view = nv;
1044 break; 1088 break;
1045 } 1089 }
@@ -1063,6 +1107,12 @@ raw3270_delete_device(struct raw3270 *rp)
1063 1107
1064 /* Remove from device chain. */ 1108 /* Remove from device chain. */
1065 down(&raw3270_sem); 1109 down(&raw3270_sem);
1110 if (rp->clttydev)
1111 class_device_destroy(class3270,
1112 MKDEV(IBM_TTY3270_MAJOR, rp->minor));
1113 if (rp->cltubdev)
1114 class_device_destroy(class3270,
1115 MKDEV(IBM_FS3270_MAJOR, rp->minor));
1066 list_del_init(&rp->list); 1116 list_del_init(&rp->list);
1067 up(&raw3270_sem); 1117 up(&raw3270_sem);
1068 1118
@@ -1129,6 +1179,16 @@ raw3270_create_attributes(struct raw3270 *rp)
1129{ 1179{
1130 //FIXME: check return code 1180 //FIXME: check return code
1131 sysfs_create_group(&rp->cdev->dev.kobj, &raw3270_attr_group); 1181 sysfs_create_group(&rp->cdev->dev.kobj, &raw3270_attr_group);
1182 rp->clttydev =
1183 class_device_create(class3270,
1184 MKDEV(IBM_TTY3270_MAJOR, rp->minor),
1185 &rp->cdev->dev, "tty%s",
1186 rp->cdev->dev.bus_id);
1187 rp->cltubdev =
1188 class_device_create(class3270,
1189 MKDEV(IBM_FS3270_MAJOR, rp->minor),
1190 &rp->cdev->dev, "tub%s",
1191 rp->cdev->dev.bus_id);
1132} 1192}
1133 1193
1134/* 1194/*
@@ -1189,13 +1249,13 @@ raw3270_set_online (struct ccw_device *cdev)
1189 return PTR_ERR(rp); 1249 return PTR_ERR(rp);
1190 rc = raw3270_reset_device(rp); 1250 rc = raw3270_reset_device(rp);
1191 if (rc) 1251 if (rc)
1192 return rc; 1252 goto failure;
1193 rc = raw3270_size_device(rp); 1253 rc = raw3270_size_device(rp);
1194 if (rc) 1254 if (rc)
1195 return rc; 1255 goto failure;
1196 rc = raw3270_reset_device(rp); 1256 rc = raw3270_reset_device(rp);
1197 if (rc) 1257 if (rc)
1198 return rc; 1258 goto failure;
1199 raw3270_create_attributes(rp); 1259 raw3270_create_attributes(rp);
1200 set_bit(RAW3270_FLAGS_READY, &rp->flags); 1260 set_bit(RAW3270_FLAGS_READY, &rp->flags);
1201 down(&raw3270_sem); 1261 down(&raw3270_sem);
@@ -1203,6 +1263,10 @@ raw3270_set_online (struct ccw_device *cdev)
1203 np->notifier(rp->minor, 1); 1263 np->notifier(rp->minor, 1);
1204 up(&raw3270_sem); 1264 up(&raw3270_sem);
1205 return 0; 1265 return 0;
1266
1267failure:
1268 raw3270_delete_device(rp);
1269 return rc;
1206} 1270}
1207 1271
1208/* 1272/*
@@ -1217,6 +1281,14 @@ raw3270_remove (struct ccw_device *cdev)
1217 struct raw3270_notifier *np; 1281 struct raw3270_notifier *np;
1218 1282
1219 rp = cdev->dev.driver_data; 1283 rp = cdev->dev.driver_data;
1284 /*
1285 * _remove is the opposite of _probe; it's probe that
1286 * should set up rp. raw3270_remove gets entered for
1287 * devices even if they haven't been varied online.
1288 * Thus, rp may validly be NULL here.
1289 */
1290 if (rp == NULL)
1291 return;
1220 clear_bit(RAW3270_FLAGS_READY, &rp->flags); 1292 clear_bit(RAW3270_FLAGS_READY, &rp->flags);
1221 1293
1222 sysfs_remove_group(&cdev->dev.kobj, &raw3270_attr_group); 1294 sysfs_remove_group(&cdev->dev.kobj, &raw3270_attr_group);
@@ -1301,6 +1373,7 @@ raw3270_init(void)
1301 if (rc == 0) { 1373 if (rc == 0) {
1302 /* Create attributes for early (= console) device. */ 1374 /* Create attributes for early (= console) device. */
1303 down(&raw3270_sem); 1375 down(&raw3270_sem);
1376 class3270 = class_create(THIS_MODULE, "3270");
1304 list_for_each_entry(rp, &raw3270_devices, list) { 1377 list_for_each_entry(rp, &raw3270_devices, list) {
1305 get_device(&rp->cdev->dev); 1378 get_device(&rp->cdev->dev);
1306 raw3270_create_attributes(rp); 1379 raw3270_create_attributes(rp);
@@ -1314,6 +1387,7 @@ static void
1314raw3270_exit(void) 1387raw3270_exit(void)
1315{ 1388{
1316 ccw_driver_unregister(&raw3270_ccw_driver); 1389 ccw_driver_unregister(&raw3270_ccw_driver);
1390 class_destroy(class3270);
1317} 1391}
1318 1392
1319MODULE_LICENSE("GPL"); 1393MODULE_LICENSE("GPL");
@@ -1335,7 +1409,9 @@ EXPORT_SYMBOL(raw3270_find_view);
1335EXPORT_SYMBOL(raw3270_activate_view); 1409EXPORT_SYMBOL(raw3270_activate_view);
1336EXPORT_SYMBOL(raw3270_deactivate_view); 1410EXPORT_SYMBOL(raw3270_deactivate_view);
1337EXPORT_SYMBOL(raw3270_start); 1411EXPORT_SYMBOL(raw3270_start);
1412EXPORT_SYMBOL(raw3270_start_locked);
1338EXPORT_SYMBOL(raw3270_start_irq); 1413EXPORT_SYMBOL(raw3270_start_irq);
1414EXPORT_SYMBOL(raw3270_reset);
1339EXPORT_SYMBOL(raw3270_register_notifier); 1415EXPORT_SYMBOL(raw3270_register_notifier);
1340EXPORT_SYMBOL(raw3270_unregister_notifier); 1416EXPORT_SYMBOL(raw3270_unregister_notifier);
1341EXPORT_SYMBOL(raw3270_wait_queue); 1417EXPORT_SYMBOL(raw3270_wait_queue);
diff --git a/drivers/s390/char/raw3270.h b/drivers/s390/char/raw3270.h
index ed5d4eb9f623..b635bf8e7775 100644
--- a/drivers/s390/char/raw3270.h
+++ b/drivers/s390/char/raw3270.h
@@ -21,6 +21,7 @@
21 21
22/* Local Channel Commands */ 22/* Local Channel Commands */
23#define TC_WRITE 0x01 /* Write */ 23#define TC_WRITE 0x01 /* Write */
24#define TC_RDBUF 0x02 /* Read Buffer */
24#define TC_EWRITE 0x05 /* Erase write */ 25#define TC_EWRITE 0x05 /* Erase write */
25#define TC_READMOD 0x06 /* Read modified */ 26#define TC_READMOD 0x06 /* Read modified */
26#define TC_EWRITEA 0x0d /* Erase write alternate */ 27#define TC_EWRITEA 0x0d /* Erase write alternate */
@@ -76,7 +77,8 @@
76#define TW_KR 0xc2 /* Keyboard restore */ 77#define TW_KR 0xc2 /* Keyboard restore */
77#define TW_PLUSALARM 0x04 /* Add this bit for alarm */ 78#define TW_PLUSALARM 0x04 /* Add this bit for alarm */
78 79
79#define RAW3270_MAXDEVS 256 80#define RAW3270_FIRSTMINOR 1 /* First minor number */
81#define RAW3270_MAXDEVS 255 /* Max number of 3270 devices */
80 82
81/* For TUBGETMOD and TUBSETMOD. Should include. */ 83/* For TUBGETMOD and TUBSETMOD. Should include. */
82struct raw3270_iocb { 84struct raw3270_iocb {
@@ -166,7 +168,10 @@ void raw3270_del_view(struct raw3270_view *);
166void raw3270_deactivate_view(struct raw3270_view *); 168void raw3270_deactivate_view(struct raw3270_view *);
167struct raw3270_view *raw3270_find_view(struct raw3270_fn *, int); 169struct raw3270_view *raw3270_find_view(struct raw3270_fn *, int);
168int raw3270_start(struct raw3270_view *, struct raw3270_request *); 170int raw3270_start(struct raw3270_view *, struct raw3270_request *);
171int raw3270_start_locked(struct raw3270_view *, struct raw3270_request *);
169int raw3270_start_irq(struct raw3270_view *, struct raw3270_request *); 172int raw3270_start_irq(struct raw3270_view *, struct raw3270_request *);
173int raw3270_reset(struct raw3270_view *);
174struct raw3270_view *raw3270_view(struct raw3270_view *);
170 175
171/* Reference count inliner for view structures. */ 176/* Reference count inliner for view structures. */
172static inline void 177static inline void
diff --git a/drivers/s390/char/tty3270.c b/drivers/s390/char/tty3270.c
index 7db5ebce7f0f..4b9069370388 100644
--- a/drivers/s390/char/tty3270.c
+++ b/drivers/s390/char/tty3270.c
@@ -653,18 +653,12 @@ tty3270_activate(struct raw3270_view *view)
653 tp->update_flags = TTY_UPDATE_ALL; 653 tp->update_flags = TTY_UPDATE_ALL;
654 tty3270_set_timer(tp, 1); 654 tty3270_set_timer(tp, 1);
655 spin_unlock_irqrestore(&tp->view.lock, flags); 655 spin_unlock_irqrestore(&tp->view.lock, flags);
656 start_tty(tp->tty);
657 return 0; 656 return 0;
658} 657}
659 658
660static void 659static void
661tty3270_deactivate(struct raw3270_view *view) 660tty3270_deactivate(struct raw3270_view *view)
662{ 661{
663 struct tty3270 *tp;
664
665 tp = (struct tty3270 *) view;
666 if (tp && tp->tty)
667 stop_tty(tp->tty);
668} 662}
669 663
670static int 664static int
@@ -716,13 +710,13 @@ tty3270_alloc_view(void)
716 tp->freemem_pages[pages], PAGE_SIZE); 710 tp->freemem_pages[pages], PAGE_SIZE);
717 } 711 }
718 tp->write = raw3270_request_alloc(TTY3270_OUTPUT_BUFFER_SIZE); 712 tp->write = raw3270_request_alloc(TTY3270_OUTPUT_BUFFER_SIZE);
719 if (!tp->write) 713 if (IS_ERR(tp->write))
720 goto out_pages; 714 goto out_pages;
721 tp->read = raw3270_request_alloc(0); 715 tp->read = raw3270_request_alloc(0);
722 if (!tp->read) 716 if (IS_ERR(tp->read))
723 goto out_write; 717 goto out_write;
724 tp->kreset = raw3270_request_alloc(1); 718 tp->kreset = raw3270_request_alloc(1);
725 if (!tp->kreset) 719 if (IS_ERR(tp->kreset))
726 goto out_read; 720 goto out_read;
727 tp->kbd = kbd_alloc(); 721 tp->kbd = kbd_alloc();
728 if (!tp->kbd) 722 if (!tp->kbd)
@@ -845,7 +839,8 @@ tty3270_del_views(void)
845 int i; 839 int i;
846 840
847 for (i = 0; i < tty3270_max_index; i++) { 841 for (i = 0; i < tty3270_max_index; i++) {
848 tp = (struct tty3270 *) raw3270_find_view(&tty3270_fn, i); 842 tp = (struct tty3270 *)
843 raw3270_find_view(&tty3270_fn, i + RAW3270_FIRSTMINOR);
849 if (!IS_ERR(tp)) 844 if (!IS_ERR(tp))
850 raw3270_del_view(&tp->view); 845 raw3270_del_view(&tp->view);
851 } 846 }
@@ -871,7 +866,9 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
871 if (tty->count > 1) 866 if (tty->count > 1)
872 return 0; 867 return 0;
873 /* Check if the tty3270 is already there. */ 868 /* Check if the tty3270 is already there. */
874 tp = (struct tty3270 *) raw3270_find_view(&tty3270_fn, tty->index); 869 tp = (struct tty3270 *)
870 raw3270_find_view(&tty3270_fn,
871 tty->index + RAW3270_FIRSTMINOR);
875 if (!IS_ERR(tp)) { 872 if (!IS_ERR(tp)) {
876 tty->driver_data = tp; 873 tty->driver_data = tp;
877 tty->winsize.ws_row = tp->view.rows - 2; 874 tty->winsize.ws_row = tp->view.rows - 2;
@@ -903,7 +900,8 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
903 (void (*)(unsigned long)) tty3270_read_tasklet, 900 (void (*)(unsigned long)) tty3270_read_tasklet,
904 (unsigned long) tp->read); 901 (unsigned long) tp->read);
905 902
906 rc = raw3270_add_view(&tp->view, &tty3270_fn, tty->index); 903 rc = raw3270_add_view(&tp->view, &tty3270_fn,
904 tty->index + RAW3270_FIRSTMINOR);
907 if (rc) { 905 if (rc) {
908 tty3270_free_view(tp); 906 tty3270_free_view(tp);
909 return rc; 907 return rc;
@@ -911,8 +909,8 @@ tty3270_open(struct tty_struct *tty, struct file * filp)
911 909
912 rc = tty3270_alloc_screen(tp); 910 rc = tty3270_alloc_screen(tp);
913 if (rc) { 911 if (rc) {
914 raw3270_del_view(&tp->view);
915 raw3270_put_view(&tp->view); 912 raw3270_put_view(&tp->view);
913 raw3270_del_view(&tp->view);
916 return rc; 914 return rc;
917 } 915 }
918 916
@@ -1780,7 +1778,7 @@ tty3270_init(void)
1780 struct tty_driver *driver; 1778 struct tty_driver *driver;
1781 int ret; 1779 int ret;
1782 1780
1783 driver = alloc_tty_driver(256); 1781 driver = alloc_tty_driver(RAW3270_MAXDEVS);
1784 if (!driver) 1782 if (!driver)
1785 return -ENOMEM; 1783 return -ENOMEM;
1786 1784
@@ -1794,6 +1792,7 @@ tty3270_init(void)
1794 driver->driver_name = "ttyTUB"; 1792 driver->driver_name = "ttyTUB";
1795 driver->name = "ttyTUB"; 1793 driver->name = "ttyTUB";
1796 driver->major = IBM_TTY3270_MAJOR; 1794 driver->major = IBM_TTY3270_MAJOR;
1795 driver->minor_start = RAW3270_FIRSTMINOR;
1797 driver->type = TTY_DRIVER_TYPE_SYSTEM; 1796 driver->type = TTY_DRIVER_TYPE_SYSTEM;
1798 driver->subtype = SYSTEM_TYPE_TTY; 1797 driver->subtype = SYSTEM_TYPE_TTY;
1799 driver->init_termios = tty_std_termios; 1798 driver->init_termios = tty_std_termios;