tubfs.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:10k
源码类别:

嵌入式Linux

开发平台:

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%.3x", 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%.3x", 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%.3x", 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%.3x", 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. tubp = data;
  220. TUBLOCK(tubp->irq, flags);
  221. tubp->flags &= ~TUB_BHPENDING;
  222. if (tubp->wbuf) {       /* if we were writing */
  223. kfree(tubp->wbuf);
  224. tubp->wbuf = NULL;
  225. }
  226. if ((tubp->flags & (TUB_ATTN | TUB_RDPENDING)) ==
  227.     (TUB_ATTN | TUB_RDPENDING)) {
  228. fs3270_io(tubp, &tubp->rccw);
  229. tubp->flags &= ~(TUB_ATTN | TUB_RDPENDING);
  230. }
  231. if ((tubp->flags & TUB_WORKING) == 0)
  232. wake_up_interruptible(&tubp->waitq);
  233. TUBUNLOCK(tubp->irq, flags);
  234. }
  235. /*
  236.  * fs3270_sched_bh(tubp) -- Schedule the back half
  237.  * Irq lock must be held on entry and remains held on exit.
  238.  */
  239. static void
  240. fs3270_sched_bh(tub_t *tubp)
  241. {
  242. if (tubp->flags & TUB_BHPENDING)
  243. return;
  244. tubp->flags |= TUB_BHPENDING;
  245. tubp->tqueue.routine = fs3270_bh;
  246. tubp->tqueue.data = tubp;
  247. queue_task(&tubp->tqueue, &tq_immediate);
  248. mark_bh(IMMEDIATE_BH);
  249. }
  250. /*
  251.  * fs3270_int(tubp, prp) -- Process interrupt from tube in FS mode
  252.  * This routine is entered with irq lock held (see do_IRQ in s390io.c)
  253.  */
  254. static void
  255. fs3270_int(tub_t *tubp, devstat_t *dsp)
  256. {
  257. #define DEV_UE_BUSY 
  258. (DEV_STAT_CHN_END | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP)
  259. tubp->dstat = dsp->dstat;
  260. #ifdef RBHNOTYET
  261. /* XXX needs more work; must save 2d arg to fs370_io() */
  262. /* Handle CE-DE-UE and subsequent UDE */
  263. if (dsp->dstat == DEV_UE_BUSY) {
  264. tubp->flags |= TUB_UE_BUSY;
  265. return;
  266. } else if (tubp->flags & TUB_UE_BUSY) {
  267. tubp->flags &= ~TUB_UE_BUSY;
  268. if (dsp->dstat == DEV_STAT_DEV_END &&
  269.     (tubp->flags & TUB_WORKING) != 0) {
  270. fs3270_io(tubp);
  271. return;
  272. }
  273. }
  274. #endif
  275. /* Handle ATTN */
  276. if (dsp->dstat & DEV_STAT_ATTENTION)
  277. tubp->flags |= TUB_ATTN;
  278. if (dsp->dstat & DEV_STAT_CHN_END) {
  279. tubp->cswl = dsp->rescnt;
  280. if ((dsp->dstat & DEV_STAT_DEV_END) == 0)
  281. tubp->flags |= TUB_EXPECT_DE;
  282. else
  283. tubp->flags &= ~TUB_EXPECT_DE;
  284. } else if (dsp->dstat & DEV_STAT_DEV_END) {
  285. if ((tubp->flags & TUB_EXPECT_DE) == 0)
  286. tubp->flags |= TUB_UNSOL_DE;
  287. tubp->flags &= ~TUB_EXPECT_DE;
  288. }
  289. if (dsp->dstat & DEV_STAT_DEV_END)
  290. tubp->flags &= ~TUB_WORKING;
  291. if ((tubp->flags & TUB_WORKING) == 0)
  292. fs3270_sched_bh(tubp);
  293. }
  294. /*
  295.  * process ioctl commands for the tube driver
  296.  */
  297. static int
  298. fs3270_ioctl(struct inode *ip, struct file *fp,
  299. unsigned int cmd, unsigned long arg)
  300. {
  301. tub_t *tubp;
  302. int rc = 0;
  303. long flags;
  304. if ((tubp = INODE2TUB(ip)) == NULL)
  305. return -ENODEV;
  306. if ((rc = fs3270_wait(tubp, &flags))) {
  307. TUBUNLOCK(tubp->irq, flags);
  308. return rc;
  309. }
  310. switch(cmd) {
  311. case TUBICMD: tubp->icmd = arg; break;
  312. case TUBOCMD: tubp->ocmd = arg; break;
  313. case TUBGETI: put_user(tubp->icmd, (char *)arg); break;
  314. case TUBGETO: put_user(tubp->ocmd, (char *)arg); break;
  315. case TUBGETMOD:
  316. if (copy_to_user((char *)arg, &tubp->tubiocb,
  317.     sizeof tubp->tubiocb))
  318. rc = -EFAULT;
  319. break;
  320. }
  321. TUBUNLOCK(tubp->irq, flags);
  322. return rc;
  323. }
  324. /*
  325.  * process read commands for the tube driver
  326.  */
  327. static ssize_t
  328. fs3270_read(struct file *fp, char *dp, size_t len, loff_t *off)
  329. {
  330. tub_t *tubp;
  331. char *kp;
  332. ccw1_t *cp;
  333. int rc;
  334. long flags;
  335. if ((tubp = INODE2TUB((struct inode *)fp->private_data)) == NULL)
  336. return -ENODEV;
  337. if ((rc = fs3270_wait(tubp, &flags)) != 0) {
  338. TUBUNLOCK(tubp->irq, flags);
  339. return rc;
  340. }
  341. kp = kmalloc(len, GFP_KERNEL|GFP_DMA);
  342. if (kp == NULL) {
  343. TUBUNLOCK(tubp->irq, flags);
  344. return -ENOMEM;
  345. }
  346. cp = &tubp->rccw;
  347. if (tubp->icmd == 0 && tubp->ocmd != 0)  tubp->icmd = 6;
  348. cp->cmd_code = tubp->icmd?:2;
  349. cp->flags = CCW_FLAG_SLI;
  350. cp->count = len;
  351. cp->cda = virt_to_phys(kp);
  352. tubp->flags |= TUB_RDPENDING;
  353. TUBUNLOCK(tubp->irq, flags);
  354. if ((rc = fs3270_wait(tubp, &flags)) != 0) {
  355. tubp->flags &= ~TUB_RDPENDING;
  356. TUBUNLOCK(tubp->irq, flags);
  357. kfree(kp);
  358. return rc;
  359. }
  360. len -= tubp->cswl;
  361. TUBUNLOCK(tubp->irq, flags);
  362. if (tubdebug & 1)
  363. printk(KERN_DEBUG "minor %d: %.8x %.8x %.8x %.8xn",
  364. tubp->minor,
  365. *(int*)((long)kp + 0),
  366. *(int*)((long)kp + 4),
  367. *(int*)((long)kp + 8),
  368. *(int*)((long)kp + 12));
  369. copy_to_user(dp, kp, len);
  370. kfree(kp);
  371. return len;
  372. }
  373. /*
  374.  * process write commands for the tube driver
  375.  */
  376. static ssize_t
  377. fs3270_write(struct file *fp, const char *dp, size_t len, loff_t *off)
  378. {
  379. tub_t *tubp;
  380. ccw1_t *cp;
  381. int rc;
  382. long flags;
  383. void *kb;
  384. /* Locate the tube */
  385. if ((tubp = INODE2TUB((struct inode *)fp->private_data)) == NULL)
  386. return -ENODEV;
  387. /* Copy data to write from user address space */
  388. if ((kb = kmalloc(len, GFP_KERNEL|GFP_DMA)) == NULL)
  389. return -ENOMEM;
  390. if (copy_from_user(kb, dp, len) != 0) {
  391. kfree(kb);
  392. return -EFAULT;
  393. }
  394. /* Wait till tube's not working or signal is pending */
  395. if ((rc = fs3270_wait(tubp, &flags))) {
  396. TUBUNLOCK(tubp->irq, flags);
  397. kfree(kb);
  398. return rc;
  399. }
  400. /* Make CCW and start I/O.  Back end will free buffer. */
  401. tubp->wbuf = kb;
  402. cp = &tubp->wccw;
  403. cp->cmd_code = tubp->ocmd? tubp->ocmd == 5? 13: tubp->ocmd: 1;
  404. cp->flags = CCW_FLAG_SLI;
  405. cp->count = len;
  406. cp->cda = virt_to_phys(tubp->wbuf);
  407. fs3270_io(tubp, cp);
  408. TUBUNLOCK(tubp->irq, flags);
  409. return len;
  410. }