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  * IBM/3270 Driver - fullscreen driver.
  3  *
  4  * Author(s):
  5  *   Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
  6  *   Rewritten for 2.5/2.6 by Martin Schwidefsky <schwidefsky@de.ibm.com>
  7  *     Copyright IBM Corp. 2003, 2009
  8  */
  9 
 10 #include <linux/bootmem.h>
 11 #include <linux/console.h>
 12 #include <linux/init.h>
 13 #include <linux/interrupt.h>
 14 #include <linux/list.h>
 15 #include <linux/types.h>
 16 #include <linux/smp_lock.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.cmd.dstat & DEV_STAT_ATTENTION) {
220                 fp->attention = 1;
221                 wake_up(&fp->wait);
222         }
223 
224         if (rq) {
225                 if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK)
226                         rq->rc = -EIO;
227                 else
228                         /* Normal end. Copy residual count. */
229                         rq->rescnt = irb->scsw.cmd.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         struct fs3270 *fp;
402 
403         fp = (struct fs3270 *) view;
404         if (fp->fs_pid)
405                 kill_pid(fp->fs_pid, SIGHUP, 1);
406 }
407 
408 /* View to a 3270 device. Can be console, tty or fullscreen. */
409 static struct raw3270_fn fs3270_fn = {
410         .activate = fs3270_activate,
411         .deactivate = fs3270_deactivate,
412         .intv = (void *) fs3270_irq,
413         .release = fs3270_release,
414         .free = fs3270_free_view
415 };
416 
417 /*
418  * This routine is called whenever a 3270 fullscreen device is opened.
419  */
420 static int
421 fs3270_open(struct inode *inode, struct file *filp)
422 {
423         struct fs3270 *fp;
424         struct idal_buffer *ib;
425         int minor, rc = 0;
426 
427         if (imajor(filp->f_path.dentry->d_inode) != IBM_FS3270_MAJOR)
428                 return -ENODEV;
429         minor = iminor(filp->f_path.dentry->d_inode);
430         /* Check for minor 0 multiplexer. */
431         if (minor == 0) {
432                 struct tty_struct *tty = get_current_tty();
433                 if (!tty || tty->driver->major != IBM_TTY3270_MAJOR) {
434                         tty_kref_put(tty);
435                         return -ENODEV;
436                 }
437                 minor = tty->index + RAW3270_FIRSTMINOR;
438                 tty_kref_put(tty);
439         }
440         lock_kernel();
441         /* Check if some other program is already using fullscreen mode. */
442         fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor);
443         if (!IS_ERR(fp)) {
444                 raw3270_put_view(&fp->view);
445                 rc = -EBUSY;
446                 goto out;
447         }
448         /* Allocate fullscreen view structure. */
449         fp = fs3270_alloc_view();
450         if (IS_ERR(fp)) {
451                 rc = PTR_ERR(fp);
452                 goto out;
453         }
454 
455         init_waitqueue_head(&fp->wait);
456         fp->fs_pid = get_pid(task_pid(current));
457         rc = raw3270_add_view(&fp->view, &fs3270_fn, minor);
458         if (rc) {
459                 fs3270_free_view(&fp->view);
460                 goto out;
461         }
462 
463         /* Allocate idal-buffer. */
464         ib = idal_buffer_alloc(2*fp->view.rows*fp->view.cols + 5, 0);
465         if (IS_ERR(ib)) {
466                 raw3270_put_view(&fp->view);
467                 raw3270_del_view(&fp->view);
468                 rc = PTR_ERR(fp);
469                 goto out;
470         }
471         fp->rdbuf = ib;
472 
473         rc = raw3270_activate_view(&fp->view);
474         if (rc) {
475                 raw3270_put_view(&fp->view);
476                 raw3270_del_view(&fp->view);
477                 goto out;
478         }
479         filp->private_data = fp;
480 out:
481         unlock_kernel();
482         return rc;
483 }
484 
485 /*
486  * This routine is called when the 3270 tty is closed. We wait
487  * for the remaining request to be completed. Then we clean up.
488  */
489 static int
490 fs3270_close(struct inode *inode, struct file *filp)
491 {
492         struct fs3270 *fp;
493 
494         fp = filp->private_data;
495         filp->private_data = NULL;
496         if (fp) {
497                 put_pid(fp->fs_pid);
498                 fp->fs_pid = NULL;
499                 raw3270_reset(&fp->view);
500                 raw3270_put_view(&fp->view);
501                 raw3270_del_view(&fp->view);
502         }
503         return 0;
504 }
505 
506 static const struct file_operations fs3270_fops = {
507         .owner           = THIS_MODULE,         /* owner */
508         .read            = fs3270_read,         /* read */
509         .write           = fs3270_write,        /* write */
510         .unlocked_ioctl  = fs3270_ioctl,        /* ioctl */
511         .compat_ioctl    = fs3270_ioctl,        /* ioctl */
512         .open           = fs3270_open,          /* open */
513         .release        = fs3270_close,         /* release */
514 };
515 
516 /*
517  * 3270 fullscreen driver initialization.
518  */
519 static int __init
520 fs3270_init(void)
521 {
522         int rc;
523 
524         rc = register_chrdev(IBM_FS3270_MAJOR, "fs3270", &fs3270_fops);
525         if (rc)
526                 return rc;
527         return 0;
528 }
529 
530 static void __exit
531 fs3270_exit(void)
532 {
533         unregister_chrdev(IBM_FS3270_MAJOR, "fs3270");
534 }
535 
536 MODULE_LICENSE("GPL");
537 MODULE_ALIAS_CHARDEV_MAJOR(IBM_FS3270_MAJOR);
538 
539 module_init(fs3270_init);
540 module_exit(fs3270_exit);
541 
  This page was automatically generated by the LXR engine.