diff options
author | Richard Hitt <rbh00@utsglobal.com> | 2005-10-30 18:00:10 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-10-30 20:37:16 -0500 |
commit | ed3cb6f039bb296457bfd2877cba6ad0287d8d54 (patch) | |
tree | c65ff2b245f17ab7e1da6f279b9d004b447d23bc /drivers/s390 | |
parent | d89ea9b8bb4c4ad63122cd2d2ee5110a52da51b8 (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>
Diffstat (limited to 'drivers/s390')
-rw-r--r-- | drivers/s390/char/con3270.c | 7 | ||||
-rw-r--r-- | drivers/s390/char/fs3270.c | 234 | ||||
-rw-r--r-- | drivers/s390/char/raw3270.c | 100 | ||||
-rw-r--r-- | drivers/s390/char/raw3270.h | 7 | ||||
-rw-r--r-- | drivers/s390/char/tty3270.c | 27 |
5 files changed, 306 insertions, 69 deletions
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 | ||
40 | static void | 43 | static 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 | ||
49 | static inline int | ||
50 | fs3270_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 | |||
46 | static int | 59 | static int |
47 | fs3270_do_io(struct raw3270_view *view, struct raw3270_request *rq) | 60 | fs3270_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 | */ | ||
63 | static void | 89 | static void |
64 | fs3270_reset_callback(struct raw3270_request *rq, void *data) | 90 | fs3270_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 | |||
99 | static void | ||
100 | fs3270_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 | */ | ||
72 | static int | 114 | static int |
73 | fs3270_activate(struct raw3270_view *view) | 115 | fs3270_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 | */ |
86 | static void | 159 | static void |
160 | fs3270_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 | |||
186 | static void | ||
87 | fs3270_deactivate(struct raw3270_view *view) | 187 | fs3270_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 | ||
100 | static int | 217 | static 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 | */ |
237 | static struct fs3270 * | 365 | static struct fs3270 * |
238 | fs3270_alloc_view(void) | 366 | fs3270_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 | */ |
257 | static void | 385 | static void |
258 | fs3270_free_view(struct raw3270_view *view) | 386 | fs3270_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 | |||
285 | fs3270_open(struct inode *inode, struct file *filp) | 418 | fs3270_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 | |||
32 | struct class *class3270; | ||
33 | |||
28 | /* The main 3270 data structure. */ | 34 | /* The main 3270 data structure. */ |
29 | struct raw3270 { | 35 | struct 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 | ||
319 | int | 327 | int |
328 | raw3270_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 | |||
343 | int | ||
320 | raw3270_start_irq(struct raw3270_view *view, struct raw3270_request *rq) | 344 | raw3270_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 | ||
771 | int | ||
772 | raw3270_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 | |||
1267 | failure: | ||
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 | |||
1314 | raw3270_exit(void) | 1387 | raw3270_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 | ||
1319 | MODULE_LICENSE("GPL"); | 1393 | MODULE_LICENSE("GPL"); |
@@ -1335,7 +1409,9 @@ EXPORT_SYMBOL(raw3270_find_view); | |||
1335 | EXPORT_SYMBOL(raw3270_activate_view); | 1409 | EXPORT_SYMBOL(raw3270_activate_view); |
1336 | EXPORT_SYMBOL(raw3270_deactivate_view); | 1410 | EXPORT_SYMBOL(raw3270_deactivate_view); |
1337 | EXPORT_SYMBOL(raw3270_start); | 1411 | EXPORT_SYMBOL(raw3270_start); |
1412 | EXPORT_SYMBOL(raw3270_start_locked); | ||
1338 | EXPORT_SYMBOL(raw3270_start_irq); | 1413 | EXPORT_SYMBOL(raw3270_start_irq); |
1414 | EXPORT_SYMBOL(raw3270_reset); | ||
1339 | EXPORT_SYMBOL(raw3270_register_notifier); | 1415 | EXPORT_SYMBOL(raw3270_register_notifier); |
1340 | EXPORT_SYMBOL(raw3270_unregister_notifier); | 1416 | EXPORT_SYMBOL(raw3270_unregister_notifier); |
1341 | EXPORT_SYMBOL(raw3270_wait_queue); | 1417 | EXPORT_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. */ |
82 | struct raw3270_iocb { | 84 | struct raw3270_iocb { |
@@ -166,7 +168,10 @@ void raw3270_del_view(struct raw3270_view *); | |||
166 | void raw3270_deactivate_view(struct raw3270_view *); | 168 | void raw3270_deactivate_view(struct raw3270_view *); |
167 | struct raw3270_view *raw3270_find_view(struct raw3270_fn *, int); | 169 | struct raw3270_view *raw3270_find_view(struct raw3270_fn *, int); |
168 | int raw3270_start(struct raw3270_view *, struct raw3270_request *); | 170 | int raw3270_start(struct raw3270_view *, struct raw3270_request *); |
171 | int raw3270_start_locked(struct raw3270_view *, struct raw3270_request *); | ||
169 | int raw3270_start_irq(struct raw3270_view *, struct raw3270_request *); | 172 | int raw3270_start_irq(struct raw3270_view *, struct raw3270_request *); |
173 | int raw3270_reset(struct raw3270_view *); | ||
174 | struct raw3270_view *raw3270_view(struct raw3270_view *); | ||
170 | 175 | ||
171 | /* Reference count inliner for view structures. */ | 176 | /* Reference count inliner for view structures. */ |
172 | static inline void | 177 | static 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 | ||
660 | static void | 659 | static void |
661 | tty3270_deactivate(struct raw3270_view *view) | 660 | tty3270_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 | ||
670 | static int | 664 | static 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; |