Blame view

drivers/s390/char/fs3270.c 12.7 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
4b214a0c7   Martin Schwidefsky   [S390] pm: con327...
2
   * IBM/3270 Driver - fullscreen driver.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
   *
4b214a0c7   Martin Schwidefsky   [S390] pm: con327...
4
5
6
7
   * Author(s):
   *   Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
   *   Rewritten for 2.5/2.6 by Martin Schwidefsky <schwidefsky@de.ibm.com>
   *     Copyright IBM Corp. 2003, 2009
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
8
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
12
  #include <linux/bootmem.h>
  #include <linux/console.h>
  #include <linux/init.h>
  #include <linux/interrupt.h>
048cd4e51   Heiko Carstens   compat: fix compi...
13
  #include <linux/compat.h>
3a4c5d596   Heiko Carstens   s390: add missing...
14
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
  #include <linux/list.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
16
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
  #include <linux/types.h>
16e1a5776   Heiko Carstens   [S390] fs3270: ad...
18
  #include <asm/compat.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
  #include <asm/ccwdev.h>
  #include <asm/cio.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
23
24
25
  #include <asm/ebcdic.h>
  #include <asm/idals.h>
  
  #include "raw3270.h"
  #include "ctrlchar.h"
2b67fc460   Heiko Carstens   [S390] Get rid of...
26
  static struct raw3270_fn fs3270_fn;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
27
28
29
  
  struct fs3270 {
  	struct raw3270_view view;
782237a24   Cedric Le Goater   [PATCH] s390: upd...
30
  	struct pid *fs_pid;		/* Pid of controlling program. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
31
32
33
  	int read_command;		/* ccw command to use for reads. */
  	int write_command;		/* ccw command to use for writes. */
  	int attention;			/* Got attention. */
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
34
35
36
37
38
  	int active;			/* Fullscreen view is active. */
  	struct raw3270_request *init;	/* single init request. */
  	wait_queue_head_t wait;		/* Init & attention wait queue. */
  	struct idal_buffer *rdbuf;	/* full-screen-deactivate buffer */
  	size_t rdbuf_size;		/* size of data returned by RDBUF */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
  };
5cbb5f579   Martin Schwidefsky   [S390] 3270: remo...
40
  static DEFINE_MUTEX(fs3270_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
44
45
  static void
  fs3270_wake_up(struct raw3270_request *rq, void *data)
  {
  	wake_up((wait_queue_head_t *) data);
  }
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
46
47
48
49
50
51
52
53
54
  static inline int
  fs3270_working(struct fs3270 *fp)
  {
  	/*
  	 * The fullscreen view is in working order if the view
  	 * has been activated AND the initial request is finished.
  	 */
  	return fp->active && raw3270_request_final(fp->init);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
  static int
  fs3270_do_io(struct raw3270_view *view, struct raw3270_request *rq)
  {
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
58
  	struct fs3270 *fp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
  	int rc;
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
60
  	fp = (struct fs3270 *) view;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
  	rq->callback = fs3270_wake_up;
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
62
63
64
65
66
67
68
69
70
71
72
73
  	rq->callback_data = &fp->wait;
  
  	do {
  		if (!fs3270_working(fp)) {
  			/* Fullscreen view isn't ready yet. */
  			rc = wait_event_interruptible(fp->wait,
  						      fs3270_working(fp));
  			if (rc != 0)
  				break;
  		}
  		rc = raw3270_start(view, rq);
  		if (rc == 0) {
af901ca18   AndrĂ© Goddard Rosa   tree-wide: fix as...
74
  			/* Started successfully. Now wait for completion. */
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
75
76
77
78
  			wait_event(fp->wait, raw3270_request_final(rq));
  		}
  	} while (rc == -EACCES);
  	return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
  }
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
80
81
82
  /*
   * Switch to the fullscreen view.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
85
  static void
  fs3270_reset_callback(struct raw3270_request *rq, void *data)
  {
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
86
87
88
  	struct fs3270 *fp;
  
  	fp = (struct fs3270 *) rq->view;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
  	raw3270_request_reset(rq);
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
90
91
92
93
94
95
96
97
98
99
100
  	wake_up(&fp->wait);
  }
  
  static void
  fs3270_restore_callback(struct raw3270_request *rq, void *data)
  {
  	struct fs3270 *fp;
  
  	fp = (struct fs3270 *) rq->view;
  	if (rq->rc != 0 || rq->rescnt != 0) {
  		if (fp->fs_pid)
782237a24   Cedric Le Goater   [PATCH] s390: upd...
101
  			kill_pid(fp->fs_pid, SIGHUP, 1);
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
102
103
104
105
  	}
  	fp->rdbuf_size = 0;
  	raw3270_request_reset(rq);
  	wake_up(&fp->wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
107
108
109
110
  static int
  fs3270_activate(struct raw3270_view *view)
  {
  	struct fs3270 *fp;
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
111
112
  	char *cp;
  	int rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
  
  	fp = (struct fs3270 *) view;
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
  
  	/* If an old init command is still running just return. */
  	if (!raw3270_request_final(fp->init))
  		return 0;
  
  	if (fp->rdbuf_size == 0) {
  		/* No saved buffer. Just clear the screen. */
  		raw3270_request_set_cmd(fp->init, TC_EWRITEA);
  		fp->init->callback = fs3270_reset_callback;
  	} else {
  		/* Restore fullscreen buffer saved by fs3270_deactivate. */
  		raw3270_request_set_cmd(fp->init, TC_EWRITEA);
  		raw3270_request_set_idal(fp->init, fp->rdbuf);
  		fp->init->ccw.count = fp->rdbuf_size;
  		cp = fp->rdbuf->data[0];
  		cp[0] = TW_KR;
  		cp[1] = TO_SBA;
  		cp[2] = cp[6];
  		cp[3] = cp[7];
  		cp[4] = TO_IC;
  		cp[5] = TO_SBA;
  		cp[6] = 0x40;
  		cp[7] = 0x40;
  		fp->init->rescnt = 0;
  		fp->init->callback = fs3270_restore_callback;
  	}
  	rc = fp->init->rc = raw3270_start_locked(view, fp->init);
  	if (rc)
  		fp->init->callback(fp->init, NULL);
  	else
  		fp->active = 1;
  	return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
149
150
151
152
  }
  
  /*
   * Shutdown fullscreen view.
   */
  static void
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
  fs3270_save_callback(struct raw3270_request *rq, void *data)
  {
  	struct fs3270 *fp;
  
  	fp = (struct fs3270 *) rq->view;
  
  	/* Correct idal buffer element 0 address. */
  	fp->rdbuf->data[0] -= 5;
  	fp->rdbuf->size += 5;
  
  	/*
  	 * If the rdbuf command failed or the idal buffer is
  	 * to small for the amount of data returned by the
  	 * rdbuf command, then we have no choice but to send
  	 * a SIGHUP to the application.
  	 */
  	if (rq->rc != 0 || rq->rescnt == 0) {
  		if (fp->fs_pid)
782237a24   Cedric Le Goater   [PATCH] s390: upd...
171
  			kill_pid(fp->fs_pid, SIGHUP, 1);
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
172
173
174
175
176
177
178
179
  		fp->rdbuf_size = 0;
  	} else
  		fp->rdbuf_size = fp->rdbuf->size - rq->rescnt;
  	raw3270_request_reset(rq);
  	wake_up(&fp->wait);
  }
  
  static void
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
  fs3270_deactivate(struct raw3270_view *view)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
183
184
  	struct fs3270 *fp;
  
  	fp = (struct fs3270 *) view;
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
  	fp->active = 0;
  
  	/* If an old init command is still running just return. */
  	if (!raw3270_request_final(fp->init))
  		return;
  
  	/* Prepare read-buffer request. */
  	raw3270_request_set_cmd(fp->init, TC_RDBUF);
  	/*
  	 * Hackish: skip first 5 bytes of the idal buffer to make
  	 * room for the TW_KR/TO_SBA/<address>/<address>/TO_IC sequence
  	 * in the activation command.
  	 */
  	fp->rdbuf->data[0] += 5;
  	fp->rdbuf->size -= 5;
  	raw3270_request_set_idal(fp->init, fp->rdbuf);
  	fp->init->rescnt = 0;
  	fp->init->callback = fs3270_save_callback;
  
  	/* Start I/O to read in the 3270 buffer. */
  	fp->init->rc = raw3270_start_locked(view, fp->init);
  	if (fp->init->rc)
  		fp->init->callback(fp->init, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
210
211
212
213
  }
  
  static int
  fs3270_irq(struct fs3270 *fp, struct raw3270_request *rq, struct irb *irb)
  {
  	/* Handle ATTN. Set indication and wake waiters for attention. */
23d805b64   Peter Oberparleiter   [S390] cio: intro...
214
  	if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
215
  		fp->attention = 1;
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
216
  		wake_up(&fp->wait);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
218
219
  	}
  
  	if (rq) {
23d805b64   Peter Oberparleiter   [S390] cio: intro...
220
  		if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
221
222
223
  			rq->rc = -EIO;
  		else
  			/* Normal end. Copy residual count. */
23d805b64   Peter Oberparleiter   [S390] cio: intro...
224
  			rq->rescnt = irb->scsw.cmd.count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
226
227
228
229
230
231
232
  	}
  	return RAW3270_IO_DONE;
  }
  
  /*
   * Process reads from fullscreen 3270.
   */
  static ssize_t
d2c993d84   Heiko Carstens   [S390] Fix sparse...
233
  fs3270_read(struct file *filp, char __user *data, size_t count, loff_t *off)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
234
235
236
237
  {
  	struct fs3270 *fp;
  	struct raw3270_request *rq;
  	struct idal_buffer *ib;
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
238
  	ssize_t rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
239
240
241
242
243
244
245
  	
  	if (count == 0 || count > 65535)
  		return -EINVAL;
  	fp = filp->private_data;
  	if (!fp)
  		return -ENODEV;
  	ib = idal_buffer_alloc(count, 0);
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
246
  	if (IS_ERR(ib))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
249
250
251
252
253
  		return -ENOMEM;
  	rq = raw3270_request_alloc(0);
  	if (!IS_ERR(rq)) {
  		if (fp->read_command == 0 && fp->write_command != 0)
  			fp->read_command = 6;
  		raw3270_request_set_cmd(rq, fp->read_command ? : 2);
  		raw3270_request_set_idal(rq, ib);
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
254
255
256
257
258
259
260
261
262
263
264
265
266
  		rc = wait_event_interruptible(fp->wait, fp->attention);
  		fp->attention = 0;
  		if (rc == 0) {
  			rc = fs3270_do_io(&fp->view, rq);
  			if (rc == 0) {
  				count -= rq->rescnt;
  				if (idal_buffer_to_user(ib, data, count) != 0)
  					rc = -EFAULT;
  				else
  					rc = count;
  
  			}
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
267
268
269
270
271
272
273
274
275
276
277
  		raw3270_request_free(rq);
  	} else
  		rc = PTR_ERR(rq);
  	idal_buffer_free(ib);
  	return rc;
  }
  
  /*
   * Process writes to fullscreen 3270.
   */
  static ssize_t
d2c993d84   Heiko Carstens   [S390] Fix sparse...
278
  fs3270_write(struct file *filp, const char __user *data, size_t count, loff_t *off)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
280
281
282
283
  {
  	struct fs3270 *fp;
  	struct raw3270_request *rq;
  	struct idal_buffer *ib;
  	int write_command;
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
284
  	ssize_t rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
286
287
288
289
  
  	fp = filp->private_data;
  	if (!fp)
  		return -ENODEV;
  	ib = idal_buffer_alloc(count, 0);
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
290
  	if (IS_ERR(ib))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
292
293
294
295
296
297
298
299
300
  		return -ENOMEM;
  	rq = raw3270_request_alloc(0);
  	if (!IS_ERR(rq)) {
  		if (idal_buffer_from_user(ib, data, count) == 0) {
  			write_command = fp->write_command ? : 1;
  			if (write_command == 5)
  				write_command = 13;
  			raw3270_request_set_cmd(rq, write_command);
  			raw3270_request_set_idal(rq, ib);
  			rc = fs3270_do_io(&fp->view, rq);
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
301
302
  			if (rc == 0)
  				rc = count - rq->rescnt;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
304
305
306
307
308
309
310
311
312
313
314
  		} else
  			rc = -EFAULT;
  		raw3270_request_free(rq);
  	} else
  		rc = PTR_ERR(rq);
  	idal_buffer_free(ib);
  	return rc;
  }
  
  /*
   * process ioctl commands for the tube driver
   */
0f75e00c9   Christoph Hellwig   [PATCH] switch fs...
315
316
  static long
  fs3270_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
317
  {
16e1a5776   Heiko Carstens   [S390] fs3270: ad...
318
  	char __user *argp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
319
320
321
322
323
324
325
  	struct fs3270 *fp;
  	struct raw3270_iocb iocb;
  	int rc;
  
  	fp = filp->private_data;
  	if (!fp)
  		return -ENODEV;
16e1a5776   Heiko Carstens   [S390] fs3270: ad...
326
327
328
329
  	if (is_compat_task())
  		argp = compat_ptr(arg);
  	else
  		argp = (char __user *)arg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
  	rc = 0;
5cbb5f579   Martin Schwidefsky   [S390] 3270: remo...
331
  	mutex_lock(&fs3270_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
332
333
334
335
336
337
338
339
  	switch (cmd) {
  	case TUBICMD:
  		fp->read_command = arg;
  		break;
  	case TUBOCMD:
  		fp->write_command = arg;
  		break;
  	case TUBGETI:
16e1a5776   Heiko Carstens   [S390] fs3270: ad...
340
  		rc = put_user(fp->read_command, argp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
342
  		break;
  	case TUBGETO:
16e1a5776   Heiko Carstens   [S390] fs3270: ad...
343
  		rc = put_user(fp->write_command, argp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
344
345
346
347
348
349
350
351
  		break;
  	case TUBGETMOD:
  		iocb.model = fp->view.model;
  		iocb.line_cnt = fp->view.rows;
  		iocb.col_cnt = fp->view.cols;
  		iocb.pf_cnt = 24;
  		iocb.re_cnt = 20;
  		iocb.map = 0;
16e1a5776   Heiko Carstens   [S390] fs3270: ad...
352
  		if (copy_to_user(argp, &iocb, sizeof(struct raw3270_iocb)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
355
  			rc = -EFAULT;
  		break;
  	}
5cbb5f579   Martin Schwidefsky   [S390] 3270: remo...
356
  	mutex_unlock(&fs3270_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
357
358
359
360
  	return rc;
  }
  
  /*
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
361
   * Allocate fs3270 structure.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
365
366
   */
  static struct fs3270 *
  fs3270_alloc_view(void)
  {
  	struct fs3270 *fp;
88abaab4f   Eric Sesterhenn   [PATCH] s390: kza...
367
  	fp = kzalloc(sizeof(struct fs3270),GFP_KERNEL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
369
  	if (!fp)
  		return ERR_PTR(-ENOMEM);
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
370
371
  	fp->init = raw3270_request_alloc(0);
  	if (IS_ERR(fp->init)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
372
373
374
375
376
377
378
  		kfree(fp);
  		return ERR_PTR(-ENOMEM);
  	}
  	return fp;
  }
  
  /*
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
379
   * Free fs3270 structure.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
381
382
383
   */
  static void
  fs3270_free_view(struct raw3270_view *view)
  {
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
384
385
386
387
388
389
  	struct fs3270 *fp;
  
  	fp = (struct fs3270 *) view;
  	if (fp->rdbuf)
  		idal_buffer_free(fp->rdbuf);
  	raw3270_request_free(((struct fs3270 *) view)->init);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390
391
392
393
394
395
396
397
398
  	kfree(view);
  }
  
  /*
   * Unlink fs3270 data structure from filp.
   */
  static void
  fs3270_release(struct raw3270_view *view)
  {
4b214a0c7   Martin Schwidefsky   [S390] pm: con327...
399
400
401
402
403
  	struct fs3270 *fp;
  
  	fp = (struct fs3270 *) view;
  	if (fp->fs_pid)
  		kill_pid(fp->fs_pid, SIGHUP, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
405
406
  }
  
  /* View to a 3270 device. Can be console, tty or fullscreen. */
2b67fc460   Heiko Carstens   [S390] Get rid of...
407
  static struct raw3270_fn fs3270_fn = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
409
410
411
412
413
414
415
416
417
418
419
420
421
  	.activate = fs3270_activate,
  	.deactivate = fs3270_deactivate,
  	.intv = (void *) fs3270_irq,
  	.release = fs3270_release,
  	.free = fs3270_free_view
  };
  
  /*
   * This routine is called whenever a 3270 fullscreen device is opened.
   */
  static int
  fs3270_open(struct inode *inode, struct file *filp)
  {
  	struct fs3270 *fp;
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
422
  	struct idal_buffer *ib;
a18992d46   Alan Cox   fs3270: Correct e...
423
  	int minor, rc = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
424

496ad9aa8   Al Viro   new helper: file_...
425
  	if (imajor(file_inode(filp)) != IBM_FS3270_MAJOR)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
  		return -ENODEV;
496ad9aa8   Al Viro   new helper: file_...
427
  	minor = iminor(file_inode(filp));
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
428
429
  	/* Check for minor 0 multiplexer. */
  	if (minor == 0) {
a90610e50   Alan Cox   fs3270: remove ex...
430
  		struct tty_struct *tty = get_current_tty();
24ec839c4   Peter Zijlstra   [PATCH] tty: ->si...
431
  		if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) {
452a00d2e   Alan Cox   tty: Make get_cur...
432
  			tty_kref_put(tty);
a18992d46   Alan Cox   fs3270: Correct e...
433
  			return -ENODEV;
24ec839c4   Peter Zijlstra   [PATCH] tty: ->si...
434
  		}
c95571e68   Martin Schwidefsky   s390/3270: introd...
435
  		minor = tty->index;
452a00d2e   Alan Cox   tty: Make get_cur...
436
  		tty_kref_put(tty);
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
437
  	}
5cbb5f579   Martin Schwidefsky   [S390] 3270: remo...
438
  	mutex_lock(&fs3270_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
441
442
  	/* Check if some other program is already using fullscreen mode. */
  	fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor);
  	if (!IS_ERR(fp)) {
  		raw3270_put_view(&fp->view);
764a4a8e5   Jonathan Corbet   drivers/s390: cde...
443
444
  		rc = -EBUSY;
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
447
  	}
  	/* Allocate fullscreen view structure. */
  	fp = fs3270_alloc_view();
764a4a8e5   Jonathan Corbet   drivers/s390: cde...
448
449
450
451
  	if (IS_ERR(fp)) {
  		rc = PTR_ERR(fp);
  		goto out;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452

ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
453
  	init_waitqueue_head(&fp->wait);
782237a24   Cedric Le Goater   [PATCH] s390: upd...
454
  	fp->fs_pid = get_pid(task_pid(current));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
455
456
457
  	rc = raw3270_add_view(&fp->view, &fs3270_fn, minor);
  	if (rc) {
  		fs3270_free_view(&fp->view);
764a4a8e5   Jonathan Corbet   drivers/s390: cde...
458
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
  	}
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
460
461
462
463
464
  	/* Allocate idal-buffer. */
  	ib = idal_buffer_alloc(2*fp->view.rows*fp->view.cols + 5, 0);
  	if (IS_ERR(ib)) {
  		raw3270_put_view(&fp->view);
  		raw3270_del_view(&fp->view);
2b31001d3   Roel Kluin   [S390] tty: PTR_E...
465
  		rc = PTR_ERR(ib);
764a4a8e5   Jonathan Corbet   drivers/s390: cde...
466
  		goto out;
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
467
468
  	}
  	fp->rdbuf = ib;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
469
470
  	rc = raw3270_activate_view(&fp->view);
  	if (rc) {
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
471
  		raw3270_put_view(&fp->view);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
472
  		raw3270_del_view(&fp->view);
764a4a8e5   Jonathan Corbet   drivers/s390: cde...
473
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
  	}
58ea91c05   Martin Schwidefsky   [S390] avoid defa...
475
  	nonseekable_open(inode, filp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
476
  	filp->private_data = fp;
764a4a8e5   Jonathan Corbet   drivers/s390: cde...
477
  out:
5cbb5f579   Martin Schwidefsky   [S390] 3270: remo...
478
  	mutex_unlock(&fs3270_mutex);
a18992d46   Alan Cox   fs3270: Correct e...
479
  	return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
480
481
482
483
484
485
486
487
488
489
490
491
  }
  
  /*
   * This routine is called when the 3270 tty is closed. We wait
   * for the remaining request to be completed. Then we clean up.
   */
  static int
  fs3270_close(struct inode *inode, struct file *filp)
  {
  	struct fs3270 *fp;
  
  	fp = filp->private_data;
d2c993d84   Heiko Carstens   [S390] Fix sparse...
492
  	filp->private_data = NULL;
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
493
  	if (fp) {
782237a24   Cedric Le Goater   [PATCH] s390: upd...
494
495
  		put_pid(fp->fs_pid);
  		fp->fs_pid = NULL;
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
496
497
  		raw3270_reset(&fp->view);
  		raw3270_put_view(&fp->view);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
498
  		raw3270_del_view(&fp->view);
ed3cb6f03   Richard Hitt   [PATCH] s390: 327...
499
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
500
501
  	return 0;
  }
d54b1fdb1   Arjan van de Ven   [PATCH] mark stru...
502
  static const struct file_operations fs3270_fops = {
0f75e00c9   Christoph Hellwig   [PATCH] switch fs...
503
504
505
506
507
  	.owner		 = THIS_MODULE,		/* owner */
  	.read		 = fs3270_read,		/* read */
  	.write		 = fs3270_write,	/* write */
  	.unlocked_ioctl	 = fs3270_ioctl,	/* ioctl */
  	.compat_ioctl	 = fs3270_ioctl,	/* ioctl */
16e1a5776   Heiko Carstens   [S390] fs3270: ad...
508
509
  	.open		 = fs3270_open,		/* open */
  	.release	 = fs3270_close,	/* release */
6038f373a   Arnd Bergmann   llseek: automatic...
510
  	.llseek		= no_llseek,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
511
  };
63df41d66   Heiko Carstens   s390: make variou...
512
  static void fs3270_create_cb(int minor)
c95571e68   Martin Schwidefsky   s390/3270: introd...
513
514
515
516
517
  {
  	__register_chrdev(IBM_FS3270_MAJOR, minor, 1, "tub", &fs3270_fops);
  	device_create(class3270, NULL, MKDEV(IBM_FS3270_MAJOR, minor),
  		      NULL, "3270/tub%d", minor);
  }
63df41d66   Heiko Carstens   s390: make variou...
518
  static void fs3270_destroy_cb(int minor)
c95571e68   Martin Schwidefsky   s390/3270: introd...
519
520
521
522
  {
  	device_destroy(class3270, MKDEV(IBM_FS3270_MAJOR, minor));
  	__unregister_chrdev(IBM_FS3270_MAJOR, minor, 1, "tub");
  }
63df41d66   Heiko Carstens   s390: make variou...
523
  static struct raw3270_notifier fs3270_notifier =
c95571e68   Martin Schwidefsky   s390/3270: introd...
524
525
526
527
  {
  	.create = fs3270_create_cb,
  	.destroy = fs3270_destroy_cb,
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
528
529
530
531
532
533
534
  /*
   * 3270 fullscreen driver initialization.
   */
  static int __init
  fs3270_init(void)
  {
  	int rc;
c95571e68   Martin Schwidefsky   s390/3270: introd...
535
  	rc = __register_chrdev(IBM_FS3270_MAJOR, 0, 1, "fs3270", &fs3270_fops);
a26182ed7   Martin Schwidefsky   [S390] Cleanup 32...
536
  	if (rc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
  		return rc;
c95571e68   Martin Schwidefsky   s390/3270: introd...
538
539
540
  	device_create(class3270, NULL, MKDEV(IBM_FS3270_MAJOR, 0),
  		      NULL, "3270/tub");
  	raw3270_register_notifier(&fs3270_notifier);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
542
543
544
545
546
  	return 0;
  }
  
  static void __exit
  fs3270_exit(void)
  {
c95571e68   Martin Schwidefsky   s390/3270: introd...
547
  	raw3270_unregister_notifier(&fs3270_notifier);
d1e61fe49   Hendrik Brueckner   s390/3270: fix mi...
548
  	device_destroy(class3270, MKDEV(IBM_FS3270_MAJOR, 0));
c95571e68   Martin Schwidefsky   s390/3270: introd...
549
  	__unregister_chrdev(IBM_FS3270_MAJOR, 0, 1, "fs3270");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
551
552
553
554
555
556
  }
  
  MODULE_LICENSE("GPL");
  MODULE_ALIAS_CHARDEV_MAJOR(IBM_FS3270_MAJOR);
  
  module_init(fs3270_init);
  module_exit(fs3270_exit);