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/config.h> 12 #include <linux/bootmem.h> 13 #include <linux/console.h> 14 #include <linux/init.h> 15 #include <linux/interrupt.h> 16 #include <linux/list.h> 17 #include <linux/types.h> 18 19 #include <asm/ccwdev.h> 20 #include <asm/cio.h> 21 #include <asm/cpcmd.h> 22 #include <asm/ebcdic.h> 23 #include <asm/idals.h> 24 25 #include "raw3270.h" 26 #include "ctrlchar.h" 27 28 struct raw3270_fn fs3270_fn; 29 30 struct fs3270 { 31 struct raw3270_view view; 32 pid_t fs_pid; /* Pid of controlling program. */ 33 int read_command; /* ccw command to use for reads. */ 34 int write_command; /* ccw command to use for writes. */ 35 int attention; /* Got attention. */ 36 struct raw3270_request *clear; /* single clear request. */ 37 wait_queue_head_t attn_wait; /* Attention wait queue. */ 38 }; 39 40 static void 41 fs3270_wake_up(struct raw3270_request *rq, void *data) 42 { 43 wake_up((wait_queue_head_t *) data); 44 } 45 46 static int 47 fs3270_do_io(struct raw3270_view *view, struct raw3270_request *rq) 48 { 49 wait_queue_head_t wq; 50 int rc; 51 52 init_waitqueue_head(&wq); 53 rq->callback = fs3270_wake_up; 54 rq->callback_data = &wq; 55 rc = raw3270_start(view, rq); 56 if (rc) 57 return rc; 58 /* Started sucessfully. Now wait for completion. */ 59 wait_event(wq, raw3270_request_final(rq)); 60 return rq->rc; 61 } 62 63 static void 64 fs3270_reset_callback(struct raw3270_request *rq, void *data) 65 { 66 raw3270_request_reset(rq); 67 } 68 69 /* 70 * Switch to the fullscreen view. 71 */ 72 static int 73 fs3270_activate(struct raw3270_view *view) 74 { 75 struct fs3270 *fp; 76 77 fp = (struct fs3270 *) view; 78 raw3270_request_set_cmd(fp->clear, TC_EWRITEA); 79 fp->clear->callback = fs3270_reset_callback; 80 return raw3270_start(view, fp->clear); 81 } 82 83 /* 84 * Shutdown fullscreen view. 85 */ 86 static void 87 fs3270_deactivate(struct raw3270_view *view) 88 { 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; 93 94 fp = (struct fs3270 *) view; 95 if (fp->fs_pid != 0) 96 kill_proc(fp->fs_pid, SIGHUP, 1); 97 fp->fs_pid = 0; 98 } 99 100 static int 101 fs3270_irq(struct fs3270 *fp, struct raw3270_request *rq, struct irb *irb) 102 { 103 /* Handle ATTN. Set indication and wake waiters for attention. */ 104 if (irb->scsw.dstat & DEV_STAT_ATTENTION) { 105 fp->attention = 1; 106 wake_up(&fp->attn_wait); 107 } 108 109 if (rq) { 110 if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK) 111 rq->rc = -EIO; 112 else 113 /* Normal end. Copy residual count. */ 114 rq->rescnt = irb->scsw.count; 115 } 116 return RAW3270_IO_DONE; 117 } 118 119 /* 120 * Process reads from fullscreen 3270. 121 */ 122 static ssize_t 123 fs3270_read(struct file *filp, char *data, size_t count, loff_t *off) 124 { 125 struct fs3270 *fp; 126 struct raw3270_request *rq; 127 struct idal_buffer *ib; 128 int rc; 129 130 if (count == 0 || count > 65535) 131 return -EINVAL; 132 fp = filp->private_data; 133 if (!fp) 134 return -ENODEV; 135 ib = idal_buffer_alloc(count, 0); 136 if (!ib) 137 return -ENOMEM; 138 rq = raw3270_request_alloc(0); 139 if (!IS_ERR(rq)) { 140 if (fp->read_command == 0 && fp->write_command != 0) 141 fp->read_command = 6; 142 raw3270_request_set_cmd(rq, fp->read_command ? : 2); 143 raw3270_request_set_idal(rq, ib); 144 wait_event(fp->attn_wait, fp->attention); 145 rc = fs3270_do_io(&fp->view, rq); 146 if (rc == 0 && idal_buffer_to_user(ib, data, count)) 147 rc = -EFAULT; 148 raw3270_request_free(rq); 149 } else 150 rc = PTR_ERR(rq); 151 idal_buffer_free(ib); 152 return rc; 153 } 154 155 /* 156 * Process writes to fullscreen 3270. 157 */ 158 static ssize_t 159 fs3270_write(struct file *filp, const char *data, size_t count, loff_t *off) 160 { 161 struct fs3270 *fp; 162 struct raw3270_request *rq; 163 struct idal_buffer *ib; 164 int write_command; 165 int rc; 166 167 fp = filp->private_data; 168 if (!fp) 169 return -ENODEV; 170 ib = idal_buffer_alloc(count, 0); 171 if (!ib) 172 return -ENOMEM; 173 rq = raw3270_request_alloc(0); 174 if (!IS_ERR(rq)) { 175 if (idal_buffer_from_user(ib, data, count) == 0) { 176 write_command = fp->write_command ? : 1; 177 if (write_command == 5) 178 write_command = 13; 179 raw3270_request_set_cmd(rq, write_command); 180 raw3270_request_set_idal(rq, ib); 181 rc = fs3270_do_io(&fp->view, rq); 182 } else 183 rc = -EFAULT; 184 raw3270_request_free(rq); 185 } else 186 rc = PTR_ERR(rq); 187 idal_buffer_free(ib); 188 return rc; 189 } 190 191 /* 192 * process ioctl commands for the tube driver 193 */ 194 static int 195 fs3270_ioctl(struct inode *inode, struct file *filp, 196 unsigned int cmd, unsigned long arg) 197 { 198 struct fs3270 *fp; 199 struct raw3270_iocb iocb; 200 int rc; 201 202 fp = filp->private_data; 203 if (!fp) 204 return -ENODEV; 205 rc = 0; 206 switch (cmd) { 207 case TUBICMD: 208 fp->read_command = arg; 209 break; 210 case TUBOCMD: 211 fp->write_command = arg; 212 break; 213 case TUBGETI: 214 rc = put_user(fp->read_command, (char *) arg); 215 break; 216 case TUBGETO: 217 rc = put_user(fp->write_command,(char *) arg); 218 break; 219 case TUBGETMOD: 220 iocb.model = fp->view.model; 221 iocb.line_cnt = fp->view.rows; 222 iocb.col_cnt = fp->view.cols; 223 iocb.pf_cnt = 24; 224 iocb.re_cnt = 20; 225 iocb.map = 0; 226 if (copy_to_user((char *) arg, &iocb, 227 sizeof(struct raw3270_iocb))) 228 rc = -EFAULT; 229 break; 230 } 231 return rc; 232 } 233 234 /* 235 * Allocate tty3270 structure. 236 */ 237 static struct fs3270 * 238 fs3270_alloc_view(void) 239 { 240 struct fs3270 *fp; 241 242 fp = (struct fs3270 *) kmalloc(sizeof(struct fs3270),GFP_KERNEL); 243 if (!fp) 244 return ERR_PTR(-ENOMEM); 245 memset(fp, 0, sizeof(struct fs3270)); 246 fp->clear = raw3270_request_alloc(0); 247 if (!IS_ERR(fp->clear)) { 248 kfree(fp); 249 return ERR_PTR(-ENOMEM); 250 } 251 return fp; 252 } 253 254 /* 255 * Free tty3270 structure. 256 */ 257 static void 258 fs3270_free_view(struct raw3270_view *view) 259 { 260 raw3270_request_free(((struct fs3270 *) view)->clear); 261 kfree(view); 262 } 263 264 /* 265 * Unlink fs3270 data structure from filp. 266 */ 267 static void 268 fs3270_release(struct raw3270_view *view) 269 { 270 } 271 272 /* View to a 3270 device. Can be console, tty or fullscreen. */ 273 struct raw3270_fn fs3270_fn = { 274 .activate = fs3270_activate, 275 .deactivate = fs3270_deactivate, 276 .intv = (void *) fs3270_irq, 277 .release = fs3270_release, 278 .free = fs3270_free_view 279 }; 280 281 /* 282 * This routine is called whenever a 3270 fullscreen device is opened. 283 */ 284 static int 285 fs3270_open(struct inode *inode, struct file *filp) 286 { 287 struct fs3270 *fp; 288 int minor, rc; 289 290 if (imajor(filp->f_dentry->d_inode) != IBM_FS3270_MAJOR) 291 return -ENODEV; 292 minor = iminor(filp->f_dentry->d_inode); 293 /* Check if some other program is already using fullscreen mode. */ 294 fp = (struct fs3270 *) raw3270_find_view(&fs3270_fn, minor); 295 if (!IS_ERR(fp)) { 296 raw3270_put_view(&fp->view); 297 return -EBUSY; 298 } 299 /* Allocate fullscreen view structure. */ 300 fp = fs3270_alloc_view(); 301 if (IS_ERR(fp)) 302 return PTR_ERR(fp); 303 304 init_waitqueue_head(&fp->attn_wait); 305 fp->fs_pid = current->pid; 306 rc = raw3270_add_view(&fp->view, &fs3270_fn, minor); 307 if (rc) { 308 fs3270_free_view(&fp->view); 309 return rc; 310 } 311 312 rc = raw3270_activate_view(&fp->view); 313 if (rc) { 314 raw3270_del_view(&fp->view); 315 return rc; 316 } 317 filp->private_data = fp; 318 return 0; 319 } 320 321 /* 322 * This routine is called when the 3270 tty is closed. We wait 323 * for the remaining request to be completed. Then we clean up. 324 */ 325 static int 326 fs3270_close(struct inode *inode, struct file *filp) 327 { 328 struct fs3270 *fp; 329 330 fp = filp->private_data; 331 filp->private_data = 0; 332 if (fp) 333 raw3270_del_view(&fp->view); 334 return 0; 335 } 336 337 static struct file_operations fs3270_fops = { 338 .owner = THIS_MODULE, /* owner */ 339 .read = fs3270_read, /* read */ 340 .write = fs3270_write, /* write */ 341 .ioctl = fs3270_ioctl, /* ioctl */ 342 .open = fs3270_open, /* open */ 343 .release = fs3270_close, /* release */ 344 }; 345 346 /* 347 * 3270 fullscreen driver initialization. 348 */ 349 static int __init 350 fs3270_init(void) 351 { 352 int rc; 353 354 rc = register_chrdev(IBM_FS3270_MAJOR, "fs3270", &fs3270_fops); 355 if (rc) { 356 printk(KERN_ERR "fs3270 can't get major number %d: errno %d\n", 357 IBM_FS3270_MAJOR, rc); 358 return rc; 359 } 360 return 0; 361 } 362 363 static void __exit 364 fs3270_exit(void) 365 { 366 unregister_chrdev(IBM_FS3270_MAJOR, "fs3270"); 367 } 368 369 MODULE_LICENSE("GPL"); 370 MODULE_ALIAS_CHARDEV_MAJOR(IBM_FS3270_MAJOR); 371 372 module_init(fs3270_init); 373 module_exit(fs3270_exit); 374