Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

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