tubfs.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:11k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  IBM/3270 Driver -- Copyright (C) UTS Global LLC
  3.  *
  4.  *  tubfs.c -- Fullscreen driver
  5.  *
  6.  *
  7.  *
  8.  *
  9.  *
  10.  *  Author:  Richard Hitt
  11.  */
  12. #include "tubio.h"
  13. int fs3270_major = -1; /* init to impossible -1 */
  14. static int fs3270_open(struct inode *, struct file *);
  15. static int fs3270_close(struct inode *, struct file *);
  16. static int fs3270_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
  17. static ssize_t fs3270_read(struct file *, char *, size_t, loff_t *);
  18. static ssize_t fs3270_write(struct file *, const char *, size_t, loff_t *);
  19. static int fs3270_wait(tub_t *, long *);
  20. static void fs3270_int(tub_t *tubp, devstat_t *dsp);
  21. extern void tty3270_refresh(tub_t *);
  22. static struct file_operations fs3270_fops = {
  23. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
  24. owner: THIS_MODULE, /* owner */
  25. #endif
  26. read:  fs3270_read, /* read */
  27. write: fs3270_write, /* write */
  28. ioctl: fs3270_ioctl, /* ioctl */
  29. open:  fs3270_open, /* open */
  30. release:fs3270_close, /* release */
  31. };
  32. #ifdef CONFIG_DEVFS_FS
  33. devfs_handle_t fs3270_devfs_dir;
  34. devfs_handle_t fs3270_devfs_tub;
  35. extern struct file_operations tty_fops;
  36. void fs3270_devfs_register(tub_t *tubp)
  37. {
  38. char name[16];
  39. sprintf(name, "tub%.4x", tubp->devno);
  40. devfs_register(fs3270_devfs_dir, name, DEVFS_FL_DEFAULT,
  41.        IBM_FS3270_MAJOR, tubp->minor,
  42.        S_IFCHR | S_IRUSR | S_IWUSR, &fs3270_fops, NULL);
  43. sprintf(name, "tty%.4x", tubp->devno);
  44. tty_register_devfs_name(&tty3270_driver, 0, tubp->minor,
  45. fs3270_devfs_dir, name);
  46. }
  47. void fs3270_devfs_unregister(tub_t *tubp)
  48. {
  49. char name[16];
  50. devfs_handle_t handle;
  51. sprintf(name, "tub%.4x", tubp->devno);
  52. handle = devfs_find_handle (fs3270_devfs_dir, name,
  53.     IBM_FS3270_MAJOR, tubp->minor,
  54.     DEVFS_SPECIAL_CHR, 0);
  55. devfs_unregister (handle);
  56. sprintf(name, "tty%.4x", tubp->devno);
  57. handle = devfs_find_handle (fs3270_devfs_dir, name,
  58.     IBM_TTY3270_MAJOR, tubp->minor,
  59.     DEVFS_SPECIAL_CHR, 0);
  60. devfs_unregister(handle);
  61. }
  62. #endif
  63. /*
  64.  * fs3270_init() -- Initialize fullscreen tubes
  65.  */
  66. int
  67. fs3270_init(void)
  68. {
  69. int rc;
  70. #ifdef CONFIG_DEVFS_FS
  71. rc = devfs_register_chrdev (IBM_FS3270_MAJOR, "fs3270", &fs3270_fops);
  72. if (rc) {
  73. printk(KERN_ERR "tubmod can't get major nbr %d: error %dn",
  74. IBM_FS3270_MAJOR, rc);
  75. return -1;
  76. }
  77. fs3270_devfs_dir = devfs_mk_dir(NULL, "3270", NULL);
  78. fs3270_devfs_tub = 
  79. devfs_register(fs3270_devfs_dir, "tub", DEVFS_FL_DEFAULT,
  80.        IBM_FS3270_MAJOR, 0,
  81.        S_IFCHR | S_IRUGO | S_IWUGO, 
  82.        &fs3270_fops, NULL);
  83. #else
  84. rc = register_chrdev(IBM_FS3270_MAJOR, "fs3270", &fs3270_fops);
  85. if (rc) {
  86. printk(KERN_ERR "tubmod can't get major nbr %d: error %dn",
  87. IBM_FS3270_MAJOR, rc);
  88. return -1;
  89. }
  90. #endif
  91. fs3270_major = IBM_FS3270_MAJOR;
  92. return 0;
  93. }
  94. /*
  95.  * fs3270_fini() -- Uninitialize fullscreen tubes
  96.  */
  97. void
  98. fs3270_fini(void)
  99. {
  100. if (fs3270_major != -1) {
  101. #ifdef CONFIG_DEVFS_FS
  102. devfs_unregister(fs3270_devfs_tub);
  103. devfs_unregister(fs3270_devfs_dir);
  104. #endif
  105. unregister_chrdev(fs3270_major, "fs3270");
  106. fs3270_major = -1;
  107. }
  108. }
  109. /*
  110.  * fs3270_open
  111.  */
  112. static int
  113. fs3270_open(struct inode *ip, struct file *fp)
  114. {
  115. tub_t *tubp;
  116. long flags;
  117. /* See INODE2TUB(ip) for handling of "/dev/3270/tub" */
  118. if ((tubp = INODE2TUB(ip)) == NULL)
  119. return -ENOENT;
  120. TUBLOCK(tubp->irq, flags);
  121. if (tubp->mode == TBM_FS || tubp->mode == TBM_FSLN) {
  122. TUBUNLOCK(tubp->irq, flags);
  123. return -EBUSY;
  124. }
  125. tub_inc_use_count();
  126. fp->private_data = ip;
  127. tubp->mode = TBM_FS;
  128. tubp->intv = fs3270_int;
  129. tubp->dstat = 0;
  130. tubp->fs_pid = current->pid;
  131. tubp->fsopen = 1;
  132. TUBUNLOCK(tubp->irq, flags);
  133. return 0;
  134. }
  135. /*
  136.  * fs3270_close aka release:  free the irq
  137.  */
  138. static int
  139. fs3270_close(struct inode *ip, struct file *fp)
  140. {
  141. tub_t *tubp;
  142. long flags;
  143. if ((tubp = INODE2TUB(ip)) == NULL)
  144. return -ENODEV;
  145. fs3270_wait(tubp, &flags);
  146. tubp->fsopen = 0;
  147. tubp->fs_pid = 0;
  148. tub_dec_use_count();
  149. tubp->intv = NULL;
  150. tubp->mode = 0;
  151. tty3270_refresh(tubp);
  152. TUBUNLOCK(tubp->irq, flags);
  153. return 0;
  154. }
  155. /*
  156.  * fs3270_release() called from tty3270_hangup()
  157.  */
  158. void
  159. fs3270_release(tub_t *tubp)
  160. {
  161. long flags;
  162. if (tubp->mode != TBM_FS)
  163. return;
  164. fs3270_wait(tubp, &flags);
  165. tubp->fsopen = 0;
  166. tubp->fs_pid = 0;
  167. tub_dec_use_count();
  168. tubp->intv = NULL;
  169. tubp->mode = 0;
  170. /*tty3270_refresh(tubp);*/
  171. TUBUNLOCK(tubp->irq, flags);
  172. }
  173. /*
  174.  * fs3270_wait(tub_t *tubp, int *flags) -- Wait to use tube
  175.  * Entered without irq lock
  176.  * On return:
  177.  *      * Lock is held
  178.  *      * Value is 0 or -ERESTARTSYS
  179.  */
  180. static int
  181. fs3270_wait(tub_t *tubp, long *flags)
  182. {
  183. DECLARE_WAITQUEUE(wait, current);
  184. TUBLOCK(tubp->irq, *flags);
  185. add_wait_queue(&tubp->waitq, &wait);
  186. while (!signal_pending(current) &&
  187.     ((tubp->mode != TBM_FS) ||
  188.      (tubp->flags & (TUB_WORKING | TUB_RDPENDING)) != 0)) {
  189. current->state = TASK_INTERRUPTIBLE;
  190. TUBUNLOCK(tubp->irq, *flags);
  191. schedule();
  192. current->state = TASK_RUNNING;
  193. TUBLOCK(tubp->irq, *flags);
  194. }
  195. remove_wait_queue(&tubp->waitq, &wait);
  196. return signal_pending(current)? -ERESTARTSYS: 0;
  197. }
  198. /*
  199.  * fs3270_io(tubp, ccw1_t*) -- start I/O on the tube
  200.  * Entered with irq lock held, WORKING off
  201.  */
  202. static int
  203. fs3270_io(tub_t *tubp, ccw1_t *ccwp)
  204. {
  205. int rc;
  206. rc = do_IO(tubp->irq, ccwp, tubp->irq, 0, 0);
  207. tubp->flags |= TUB_WORKING;
  208. tubp->dstat = 0;
  209. return rc;
  210. }
  211. /*
  212.  * fs3270_bh(tubp) -- Perform back-half processing
  213.  */
  214. static void
  215. fs3270_bh(void *data)
  216. {
  217. long flags;
  218. tub_t *tubp;
  219. addr_t *ip;
  220. tubp = data;
  221. TUBLOCK(tubp->irq, flags);
  222. tubp->flags &= ~TUB_BHPENDING;
  223. if (tubp->wbuf) {       /* if we were writing */
  224. for (ip = tubp->wbuf; ip < tubp->wbuf+33; ip++) {
  225. if (*ip == 0)
  226. break;
  227. kfree(phys_to_virt(*ip));
  228. }
  229. kfree(tubp->wbuf);
  230. tubp->wbuf = NULL;
  231. }
  232. if ((tubp->flags & (TUB_ATTN | TUB_RDPENDING)) ==
  233.     (TUB_ATTN | TUB_RDPENDING)) {
  234. fs3270_io(tubp, &tubp->rccw);
  235. tubp->flags &= ~(TUB_ATTN | TUB_RDPENDING);
  236. }
  237. if ((tubp->flags & TUB_WORKING) == 0)
  238. wake_up_interruptible(&tubp->waitq);
  239. TUBUNLOCK(tubp->irq, flags);
  240. }
  241. /*
  242.  * fs3270_sched_bh(tubp) -- Schedule the back half
  243.  * Irq lock must be held on entry and remains held on exit.
  244.  */
  245. static void
  246. fs3270_sched_bh(tub_t *tubp)
  247. {
  248. if (tubp->flags & TUB_BHPENDING)
  249. return;
  250. tubp->flags |= TUB_BHPENDING;
  251. tubp->tqueue.routine = fs3270_bh;
  252. tubp->tqueue.data = tubp;
  253. queue_task(&tubp->tqueue, &tq_immediate);
  254. mark_bh(IMMEDIATE_BH);
  255. }
  256. /*
  257.  * fs3270_int(tubp, prp) -- Process interrupt from tube in FS mode
  258.  * This routine is entered with irq lock held (see do_IRQ in s390io.c)
  259.  */
  260. static void
  261. fs3270_int(tub_t *tubp, devstat_t *dsp)
  262. {
  263. #define DEV_UE_BUSY 
  264. (DEV_STAT_CHN_END | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP)
  265. #ifdef RBHNOTYET
  266. /* XXX needs more work; must save 2d arg to fs370_io() */
  267. /* Handle CE-DE-UE and subsequent UDE */
  268. if (dsp->dstat == DEV_UE_BUSY) {
  269. tubp->flags |= TUB_UE_BUSY;
  270. return;
  271. } else if (tubp->flags & TUB_UE_BUSY) {
  272. tubp->flags &= ~TUB_UE_BUSY;
  273. if (dsp->dstat == DEV_STAT_DEV_END &&
  274.     (tubp->flags & TUB_WORKING) != 0) {
  275. fs3270_io(tubp);
  276. return;
  277. }
  278. }
  279. #endif
  280. /* Handle ATTN */
  281. if (dsp->dstat & DEV_STAT_ATTENTION)
  282. tubp->flags |= TUB_ATTN;
  283. if (dsp->dstat & DEV_STAT_CHN_END) {
  284. tubp->cswl = dsp->rescnt;
  285. if ((dsp->dstat & DEV_STAT_DEV_END) == 0)
  286. tubp->flags |= TUB_EXPECT_DE;
  287. else
  288. tubp->flags &= ~TUB_EXPECT_DE;
  289. } else if (dsp->dstat & DEV_STAT_DEV_END) {
  290. if ((tubp->flags & TUB_EXPECT_DE) == 0)
  291. tubp->flags |= TUB_UNSOL_DE;
  292. tubp->flags &= ~TUB_EXPECT_DE;
  293. }
  294. if (dsp->dstat & DEV_STAT_DEV_END)
  295. tubp->flags &= ~TUB_WORKING;
  296. if ((tubp->flags & TUB_WORKING) == 0)
  297. fs3270_sched_bh(tubp);
  298. }
  299. /*
  300.  * process ioctl commands for the tube driver
  301.  */
  302. static int
  303. fs3270_ioctl(struct inode *ip, struct file *fp,
  304. unsigned int cmd, unsigned long arg)
  305. {
  306. tub_t *tubp;
  307. int rc = 0;
  308. long flags;
  309. if ((tubp = INODE2TUB(ip)) == NULL)
  310. return -ENODEV;
  311. if ((rc = fs3270_wait(tubp, &flags))) {
  312. TUBUNLOCK(tubp->irq, flags);
  313. return rc;
  314. }
  315. switch(cmd) {
  316. case TUBICMD: tubp->icmd = arg; break;
  317. case TUBOCMD: tubp->ocmd = arg; break;
  318. case TUBGETI: put_user(tubp->icmd, (char *)arg); break;
  319. case TUBGETO: put_user(tubp->ocmd, (char *)arg); break;
  320. case TUBGETMOD:
  321. if (copy_to_user((char *)arg, &tubp->tubiocb,
  322.     sizeof tubp->tubiocb))
  323. rc = -EFAULT;
  324. break;
  325. }
  326. TUBUNLOCK(tubp->irq, flags);
  327. return rc;
  328. }
  329. /*
  330.  * process read commands for the tube driver
  331.  */
  332. static ssize_t
  333. fs3270_read(struct file *fp, char *dp, size_t len, loff_t *off)
  334. {
  335. tub_t *tubp;
  336. char *kp;
  337. ccw1_t *cp;
  338. int rc;
  339. long flags;
  340. addr_t *idalp, *ip;
  341. char *tp;
  342. int count, piece;
  343. int size;
  344. if (len == 0 || len > 65535) {
  345. return -EINVAL;
  346. }
  347. if ((tubp = INODE2TUB((struct inode *)fp->private_data)) == NULL)
  348. return -ENODEV;
  349. if ((ip = idalp = idal_alloc(33)) == NULL)
  350. return -EFAULT;
  351. memset(idalp, 0, 33 * sizeof *idalp);
  352. count = len;
  353. while (count) {
  354. piece = MIN(count, 0x800);
  355. size = count == len? piece: 0x800;
  356. if ((kp = kmalloc(size, GFP_KERNEL|GFP_DMA)) == NULL) {
  357. len = -ENOMEM;
  358. goto do_cleanup;
  359. }
  360. *ip++ = virt_to_phys(kp);
  361. count -= piece;
  362. }
  363. if ((rc = fs3270_wait(tubp, &flags)) != 0) {
  364. TUBUNLOCK(tubp->irq, flags);
  365. len = rc;
  366. goto do_cleanup;
  367. }
  368. cp = &tubp->rccw;
  369. if (tubp->icmd == 0 && tubp->ocmd != 0)  tubp->icmd = 6;
  370. cp->cmd_code = tubp->icmd?:2;
  371. cp->flags = CCW_FLAG_SLI | CCW_FLAG_IDA;
  372. cp->count = len;
  373. cp->cda = virt_to_phys(idalp);
  374. tubp->flags |= TUB_RDPENDING;
  375. TUBUNLOCK(tubp->irq, flags);
  376. if ((rc = fs3270_wait(tubp, &flags)) != 0) {
  377. tubp->flags &= ~TUB_RDPENDING;
  378. len = rc;
  379. TUBUNLOCK(tubp->irq, flags);
  380. goto do_cleanup;
  381. }
  382. TUBUNLOCK(tubp->irq, flags);
  383. len -= tubp->cswl;
  384. count = len;
  385. tp = dp;
  386. ip = idalp;
  387. while (count) {
  388. piece = MIN(count, 0x800);
  389. if (copy_to_user(tp, phys_to_virt(*ip), piece) != 0) {
  390. len = -EFAULT;
  391. goto do_cleanup;
  392. }
  393. count -= piece;
  394. tp += piece;
  395. ip++;
  396. }
  397. do_cleanup:
  398. for (ip = idalp; ip < idalp+33; ip++) {
  399. if (*ip == 0)
  400. break;
  401. kfree(phys_to_virt(*ip));
  402. }
  403. idal_free(idalp);
  404. return len;
  405. }
  406. /*
  407.  * process write commands for the tube driver
  408.  */
  409. static ssize_t
  410. fs3270_write(struct file *fp, const char *dp, size_t len, loff_t *off)
  411. {
  412. tub_t *tubp;
  413. ccw1_t *cp;
  414. int rc;
  415. long flags;
  416. void *kb;
  417. addr_t *idalp, *ip;
  418. int count, piece;
  419. int index;
  420. int size;
  421. if (len > 65535 || len == 0)
  422. return -EINVAL;
  423. /* Locate the tube */
  424. if ((tubp = INODE2TUB((struct inode *)fp->private_data)) == NULL)
  425. return -ENODEV;
  426. if ((ip = idalp = idal_alloc(33)) == NULL)
  427. return -EFAULT;
  428. memset(idalp, 0, 33 * sizeof *idalp);
  429. count = len;
  430. index = 0;
  431. while (count) {
  432. piece = MIN(count, 0x800);
  433. size = count == len? piece: 0x800;
  434. if ((kb = kmalloc(size, GFP_KERNEL|GFP_DMA)) == NULL) {
  435. len = -ENOMEM;
  436. goto do_cleanup;
  437. }
  438. *ip++ = virt_to_phys(kb);
  439. if (copy_from_user(kb, &dp[index], piece) != 0) {
  440. len = -EFAULT;
  441. goto do_cleanup;
  442. }
  443. count -= piece;
  444. index += piece;
  445. }
  446. /* Wait till tube's not working or signal is pending */
  447. if ((rc = fs3270_wait(tubp, &flags))) {
  448. len = rc;
  449. TUBUNLOCK(tubp->irq, flags);
  450. goto do_cleanup;
  451. }
  452. /* Make CCW and start I/O.  Back end will free buffers & idal. */
  453. tubp->wbuf = idalp;
  454. cp = &tubp->wccw;
  455. cp->cmd_code = tubp->ocmd? tubp->ocmd == 5? 13: tubp->ocmd: 1;
  456. cp->flags = CCW_FLAG_SLI | CCW_FLAG_IDA;
  457. cp->count = len;
  458. cp->cda = virt_to_phys(tubp->wbuf);
  459. fs3270_io(tubp, cp);
  460. TUBUNLOCK(tubp->irq, flags);
  461. return len;
  462. do_cleanup:
  463. for (ip = idalp; ip < idalp+33; ip++) {
  464. if (*ip == 0)
  465. break;
  466. kfree(phys_to_virt(*ip));
  467. }
  468. idal_free(idalp);
  469. return len;
  470. }