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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC
  3.  *
  4.  *  tuball.c -- Initialization, termination, irq lookup
  5.  *
  6.  *
  7.  *
  8.  *
  9.  *
  10.  *  Author:  Richard Hitt
  11.  */
  12. #include <linux/config.h>
  13. #include "tubio.h"
  14. #ifndef MODULE
  15. #include <linux/init.h>
  16. #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
  17. #include <asm/cpcmd.h>
  18. #include <linux/bootmem.h>
  19. #else
  20. #include "../../../../arch/s390/kernel/cpcmd.h"
  21. #endif
  22. #endif
  23. /* Module parameters */
  24. int tubdebug;
  25. int tubscrolltime = -1;
  26. int tubxcorrect = 1;            /* Do correct ebc<->asc tables */
  27. #ifdef MODULE
  28. MODULE_PARM(tubdebug, "i");
  29. MODULE_PARM(tubscrolltime, "i");
  30. MODULE_PARM(tubxcorrect, "i");
  31. #endif
  32. /*
  33.  * Values for tubdebug and their effects:
  34.  * 1 - print in hex on console the first 16 bytes received
  35.  * 2 - print address at which array tubminors is allocated
  36.  * 4 - attempt to register tty3270_driver
  37.  */
  38. int tubnummins;
  39. tub_t *(*tubminors)[TUBMAXMINS];
  40. tub_t *(*(*tubirqs)[256])[256];
  41. unsigned char tub_ascebc[256];
  42. unsigned char tub_ebcasc[256];
  43. int tubinitminors(void);
  44. void tubfiniminors(void);
  45. void tubint(int, void *, struct pt_regs *);
  46. /* Lookup-by-irq functions */
  47. int tubaddbyirq(tub_t *, int);
  48. tub_t *tubfindbyirq(int);
  49. void tubdelbyirq(tub_t *, int);
  50. void tubfiniirqs(void);
  51. extern int fs3270_init(void);
  52. extern void fs3270_fini(void);
  53. extern int tty3270_init(void);
  54. extern void tty3270_fini(void);
  55. unsigned char tub_ebcgraf[64] =
  56. { 0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
  57.   0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
  58.   0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
  59.   0xd8, 0xd9, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
  60.   0x60, 0x61, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
  61.   0xe8, 0xe9, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
  62.   0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
  63.   0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f };
  64. int tub3270_init(void);
  65. #ifndef MODULE
  66. /*
  67.  * Can't have this driver a module & support console at the same time
  68.  */
  69. #ifdef CONFIG_TN3270_CONSOLE
  70. static kdev_t tub3270_con_device(struct console *);
  71. static void tub3270_con_unblank(void);
  72. static void tub3270_con_write(struct console *, const char *,
  73. unsigned int);
  74. static struct console tub3270_con = {
  75. "tub3270", /* name */
  76. tub3270_con_write, /* write */
  77. NULL, /* read */
  78. tub3270_con_device, /* device */
  79. tub3270_con_unblank, /* unblank */
  80. NULL, /* setup */
  81. CON_PRINTBUFFER, /* flags */
  82. 0, /* index */
  83. 0, /* cflag */
  84. NULL /* next */
  85. };
  86. static bcb_t tub3270_con_bcb; /* Buffer that receives con writes */
  87. static spinlock_t tub3270_con_bcblock; /* Lock for the buffer */
  88. int tub3270_con_irq = -1; /* set nonneg by _activate() */
  89. tub_t *tub3270_con_tubp; /* set nonzero by _activate() */
  90. struct tty_driver tty3270_con_driver; /* for /dev/console at 4, 64 */
  91. #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
  92. int tub3270_con_devno = -1; /* set by tub3270_con_setup() */
  93. __initfunc(void tub3270_con_setup(char *str, int *ints))
  94. {
  95. int vdev;
  96. vdev = simple_strtoul(str, 0, 16);
  97. if (vdev >= 0 && vdev < 65536)
  98. tub3270_con_devno = vdev;
  99. return;
  100. }
  101. __initfunc (long tub3270_con_init(long kmem_start, long kmem_end))
  102. {
  103. tub3270_con_bcb.bc_len = 65536;
  104. if (!MACHINE_IS_VM && !MACHINE_IS_P390)
  105. return kmem_start;
  106. tub3270_con_bcb.bc_buf = (void *)kmem_start;
  107. kmem_start += tub3270_con_bcb.bc_len;
  108. register_console(&tub3270_con);
  109. return kmem_start;
  110. }
  111. #else
  112. #define tub3270_con_devno console_device
  113. void __init tub3270_con_init(void)
  114. {
  115. tub3270_con_bcb.bc_len = 65536;
  116. if (!CONSOLE_IS_3270)
  117. return;
  118. tub3270_con_bcb.bc_buf = (void *)alloc_bootmem_low(
  119. tub3270_con_bcb.bc_len);
  120. register_console(&tub3270_con);
  121. }
  122. #endif
  123. static kdev_t
  124. tub3270_con_device(struct console *conp)
  125. {
  126. return MKDEV(IBM_TTY3270_MAJOR, conp->index + 1);
  127. }
  128. static void
  129. tub3270_con_unblank(void)
  130. {
  131. /* flush everything:  panic has occurred */
  132. }
  133. int tub3270_con_write_deadlock_ct;
  134. int tub3270_con_write_deadlock_bytes;
  135. static void
  136. tub3270_con_write(struct console *conp,
  137. const char *buf, unsigned int count)
  138. {
  139. long flags;
  140. tub_t *tubp = tub3270_con_tubp;
  141. void tty3270_sched_bh(tub_t *);
  142. int rc;
  143. bcb_t obcb;
  144. obcb.bc_buf = (char *)buf;
  145. obcb.bc_len = obcb.bc_cnt = obcb.bc_wr =
  146. MIN(count, tub3270_con_bcb.bc_len);
  147. obcb.bc_rd = 0;
  148. spin_lock_irqsave(&tub3270_con_bcblock, flags);
  149. rc = tub3270_movedata(&obcb, &tub3270_con_bcb, 0);
  150. spin_unlock_irqrestore(&tub3270_con_bcblock, flags);
  151. if (tubp && rc && TUBTRYLOCK(tubp->irq, flags)) {
  152. tty3270_sched_bh(tubp);
  153. TUBUNLOCK(tubp->irq, flags);
  154. }
  155. }
  156. int tub3270_con_copy(tub_t *tubp)
  157. {
  158. long flags;
  159. int rc;
  160. spin_lock_irqsave(&tub3270_con_bcblock, flags);
  161. rc = tub3270_movedata(&tub3270_con_bcb, &tubp->tty_bcb, 0);
  162. spin_unlock_irqrestore(&tub3270_con_bcblock, flags);
  163. return rc;
  164. }
  165. #endif /* CONFIG_TN3270_CONSOLE */
  166. #else /* If generated as a MODULE */
  167. /*
  168.  * module init:  find tubes; get a major nbr
  169.  */
  170. int
  171. init_module(void)
  172. {
  173. if (tubnummins != 0) {
  174. printk(KERN_ERR "EEEK!!  Tube driver cobbigling!!n");
  175. return -1;
  176. }
  177. return tub3270_init();
  178. }
  179. /*
  180.  * remove driver:  unregister the major number
  181.  */
  182. void
  183. cleanup_module(void)
  184. {
  185. fs3270_fini();
  186. tty3270_fini();
  187. tubfiniminors();
  188. }
  189. #endif /* Not a MODULE or a MODULE */
  190. void
  191. tub_inc_use_count(void)
  192. {
  193. MOD_INC_USE_COUNT;
  194. }
  195. void
  196. tub_dec_use_count(void)
  197. {
  198. MOD_DEC_USE_COUNT;
  199. }
  200. static int
  201. tub3270_is_ours(s390_dev_info_t *dp)
  202. {
  203. if ((dp->sid_data.cu_type & 0xfff0) == 0x3270)
  204. return 1;
  205. if (dp->sid_data.cu_type == 0x3174)
  206. return 1;
  207. return 0;
  208. }
  209. /*
  210.  * tub3270_init() called by kernel or module initialization
  211.  */
  212. int
  213. tub3270_init(void)
  214. {
  215. s390_dev_info_t d;
  216. int i, rc;
  217. /*
  218.  * Copy and correct ebcdic - ascii translate tables
  219.  */
  220. memcpy(tub_ascebc, _ascebc, sizeof tub_ascebc);
  221. memcpy(tub_ebcasc, _ebcasc, sizeof tub_ebcasc);
  222. if (tubxcorrect) {
  223. /* correct brackets and circumflex */
  224. tub_ascebc['['] = 0xad;
  225. tub_ascebc[']'] = 0xbd;
  226. tub_ebcasc[0xad] = '[';
  227. tub_ebcasc[0xbd] = ']';
  228. tub_ascebc['^'] = 0xb0;
  229. tub_ebcasc[0x5f] = '^';
  230. }
  231. rc = tubinitminors();
  232. if (rc != 0)
  233. return rc;
  234. if (fs3270_init() || tty3270_init()) {
  235. printk(KERN_ERR "fs3270_init() or tty3270_init() failedn");
  236. fs3270_fini();
  237. tty3270_fini();
  238. tubfiniminors();
  239. return -1;
  240. }
  241. for (i = get_irq_first(); i >= 0; i = get_irq_next(i)) {
  242. if ((rc = get_dev_info_by_irq(i, &d)))
  243. continue;
  244. if (d.status)
  245. continue;
  246. #ifdef CONFIG_TN3270_CONSOLE
  247. #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
  248. if (d.sid_data.cu_type == 0x3215 && MACHINE_IS_VM) {
  249. cpcmd("TERM CONMODE 3270", NULL, 0);
  250. d.sid_data.cu_type = 0x3270;
  251. }
  252. #else
  253. if (d.sid_data.cu_type == 0x3215 && CONSOLE_IS_3270) {
  254. cpcmd("TERM CONMODE 3270", NULL, 0);
  255. d.sid_data.cu_type = 0x3270;
  256. }
  257. #endif /* LINUX_VERSION_CODE */
  258. #endif /* CONFIG_TN3270_CONSOLE */
  259. if (!tub3270_is_ours(&d))
  260. continue;
  261. rc = tubmakemin(i, &d);
  262. if (rc < 0) {
  263. printk(KERN_WARNING 
  264.        "3270 tube registration ran out of memory"
  265.        " after %d devicesn", tubnummins - 1);
  266. break;
  267. } else {
  268. printk(KERN_INFO "3270: %.4x on sch %d, minor %dn",
  269. d.devno, d.irq, rc);
  270. }
  271. }
  272. return 0;
  273. }
  274. /*
  275.  * tub3270_movedata(bcb_t *, bcb_t *) -- Move data stream
  276.  */
  277. int
  278. tub3270_movedata(bcb_t *ib, bcb_t *ob, int fromuser)
  279. {
  280. int count; /* Total move length */
  281. int rc;
  282. rc = count = MIN(ib->bc_cnt, ob->bc_len - ob->bc_cnt);
  283. while (count > 0) {
  284. int len1; /* Contig bytes avail in ib */
  285. if (ib->bc_wr > ib->bc_rd)
  286. len1 = ib->bc_wr - ib->bc_rd;
  287. else
  288. len1 = ib->bc_len - ib->bc_rd;
  289. if (len1 > count)
  290. len1 = count;
  291. while (len1 > 0) {
  292. int len2; /* Contig space avail in ob */
  293. if (ob->bc_rd > ob->bc_wr)
  294. len2 = ob->bc_rd - ob->bc_wr;
  295. else
  296. len2 = ob->bc_len - ob->bc_wr;
  297. if (len2 > len1)
  298. len2 = len1;
  299. if (fromuser) {
  300. len2 -= copy_from_user(ob->bc_buf + ob->bc_wr,
  301.        ib->bc_buf + ib->bc_rd,
  302.        len2);
  303. if (len2 == 0) {
  304. if (!rc)
  305. rc = -EFAULT;
  306. break;
  307. }
  308. } else
  309. memcpy(ob->bc_buf + ob->bc_wr,
  310.        ib->bc_buf + ib->bc_rd,
  311.        len2);
  312. ib->bc_rd += len2;
  313. if (ib->bc_rd == ib->bc_len)
  314. ib->bc_rd = 0;
  315. ib->bc_cnt -= len2;
  316. ob->bc_wr += len2;
  317. if (ob->bc_wr == ob->bc_len)
  318. ob->bc_wr = 0;
  319. ob->bc_cnt += len2;
  320. len1 -= len2;
  321. count -= len2;
  322. }
  323. }
  324. return rc;
  325. }
  326. /*
  327.  * receive an interrupt
  328.  */
  329. void
  330. tubint(int irq, void *ipp, struct pt_regs *prp)
  331. {
  332. devstat_t *dsp = ipp;
  333. tub_t *tubp;
  334. if ((tubp = IRQ2TUB(irq)) && (tubp->intv))
  335. (tubp->intv)(tubp, dsp);
  336. }
  337. /*
  338.  * Initialize array of pointers to minor structures tub_t.
  339.  * Returns 0 or -ENOMEM.
  340.  */
  341. int
  342. tubinitminors(void)
  343. {
  344. tubminors = (tub_t *(*)[TUBMAXMINS])kmalloc(sizeof *tubminors,
  345. GFP_KERNEL);
  346. if (tubminors == NULL)
  347. return -ENOMEM;
  348. memset(tubminors, 0, sizeof *tubminors);
  349. return 0;
  350. }
  351. /*
  352.  * Add a minor 327x device.  Argument is an irq value.
  353.  *
  354.  * Point elements of two arrays to the newly created tub_t:
  355.  * 1. (*tubminors)[minor]
  356.  * 2. (*(*tubirqs)[irqhi])[irqlo]
  357.  * The first looks up from minor number at context time; the second
  358.  * looks up from irq at interrupt time.
  359.  */
  360. int
  361. #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
  362. tubmakemin(int irq, dev_info_t *dp)
  363. #else
  364. tubmakemin(int irq, s390_dev_info_t *dp)
  365. #endif
  366. {
  367. tub_t *tubp;
  368. int minor;
  369. long flags;
  370. if ((minor = ++tubnummins) == TUBMAXMINS)
  371. return -ENODEV;
  372. tubp = kmalloc(sizeof(tub_t), GFP_KERNEL);
  373. if (tubp == NULL) {
  374. return -ENOMEM;
  375. }
  376. if (tubaddbyirq(tubp, irq) != 0) {
  377. kfree(tubp);
  378. return -ENOMEM;
  379. }
  380. memset(tubp, 0, sizeof(tub_t));
  381. tubp->minor = minor;
  382. tubp->irq = irq;
  383. TUBLOCK(tubp->irq, flags);
  384. tubp->devno = dp->devno;
  385. tubp->geom_rows = _GEOM_ROWS;
  386. tubp->geom_cols = _GEOM_COLS;
  387. init_waitqueue_head(&tubp->waitq);
  388. tubp->tty_bcb.bc_len = TTY_OUTPUT_SIZE;
  389. tubp->tty_bcb.bc_buf = (void *)kmalloc(tubp->tty_bcb.bc_len,
  390. GFP_KERNEL|GFP_DMA);
  391. if (tubp->tty_bcb.bc_buf == NULL) {
  392. TUBUNLOCK(tubp->irq, flags);
  393. tubdelbyirq(tubp, irq);
  394. kfree(tubp);
  395. return -ENOMEM;
  396. }
  397. tubp->tty_bcb.bc_cnt = 0;
  398. tubp->tty_bcb.bc_wr = 0;
  399. tubp->tty_bcb.bc_rd = 0;
  400. (*tubminors)[minor] = tubp;
  401. #ifdef CONFIG_TN3270_CONSOLE
  402. if (CONSOLE_IS_3270) {
  403. if (tub3270_con_tubp == NULL && 
  404.     tub3270_con_bcb.bc_buf != NULL &&
  405.     (tub3270_con_devno == -1 ||
  406.      tub3270_con_devno == dp->devno)) {
  407. extern void tty3270_int(tub_t *, devstat_t *);
  408. tub3270_con_devno = dp->devno;
  409. tubp->cmd = TBC_CONOPEN;
  410. tubp->flags |= TUB_OPEN_STET | TUB_INPUT_HACK;
  411. tty3270_size(tubp, &flags);
  412. tubp->tty_input = kmalloc(GEOM_INPLEN,
  413. GFP_KERNEL|GFP_DMA);
  414. tty3270_aid_init(tubp);
  415. tty3270_scl_init(tubp);
  416. tub3270_con_irq = tubp->irq;
  417. tub3270_con_tubp = tubp;
  418. tubp->intv = tty3270_int;
  419. tubp->cmd = TBC_UPDSTAT;
  420. tty3270_build(tubp);
  421. }
  422. }
  423. #endif /* CONFIG_TN3270_CONSOLE */
  424. #ifdef CONFIG_DEVFS_FS
  425. fs3270_devfs_register(tubp);
  426. #endif
  427. TUBUNLOCK(tubp->irq, flags);
  428. return minor;
  429. }
  430. /*
  431.  * Release array of pointers to minor structures tub_t, but first
  432.  * release any storage pointed to by them.
  433.  */
  434. void
  435. tubfiniminors(void)
  436. {
  437. int i;
  438. tub_t **tubpp, *tubp;
  439. if (tubminors == NULL)
  440. return;
  441. for (i = 0; i < TUBMAXMINS; i++) {
  442. tubpp = &(*tubminors)[i];
  443. if ((tubp = *tubpp)) {
  444. #ifdef CONFIG_DEVFS_FS
  445. fs3270_devfs_unregister(tubp);
  446. #endif
  447. tubdelbyirq(tubp, tubp->irq);
  448. tty3270_rcl_fini(tubp);
  449. kfree(tubp->tty_bcb.bc_buf);
  450. if (tubp->tty_input) {
  451. kfree(tubp->tty_input);
  452. tubp->tty_input = NULL;
  453. }
  454. tubp->tty_bcb.bc_buf = NULL;
  455. tubp->ttyscreen = NULL;
  456. kfree(tubp);
  457. *tubpp = NULL;
  458. }
  459. }
  460. kfree(tubminors);
  461. tubminors = NULL;
  462. tubfiniirqs();
  463. }
  464. /*
  465.  * tubaddbyirq() -- Add tub_t for irq lookup in tubint()
  466.  */
  467. int
  468. tubaddbyirq(tub_t *tubp, int irq)
  469. {
  470. int irqhi = (irq >> 8) & 255;
  471. int irqlo = irq & 255;
  472. tub_t *(*itubpp)[256];
  473. /* Allocate array (*tubirqs)[] if first time */
  474. if (tubirqs == NULL) {
  475. tubirqs = (tub_t *(*(*)[256])[256])
  476. kmalloc(sizeof *tubirqs, GFP_KERNEL);
  477. if (tubirqs == NULL)
  478. return -ENOMEM;
  479. memset(tubirqs, 0, sizeof *tubirqs);
  480. }
  481. /* Allocate subarray (*(*tubirqs)[])[] if first use */
  482. if ((itubpp = (*tubirqs)[irqhi]) == NULL) {
  483. itubpp = (tub_t *(*)[256])
  484. kmalloc(sizeof(*itubpp), GFP_KERNEL);
  485. if (itubpp == NULL) {
  486. if (tubnummins == 1) {  /* if first time */
  487. kfree(tubirqs);
  488. tubirqs = NULL;
  489. }
  490. return -ENOMEM;
  491. } else {
  492. memset(itubpp, 0, sizeof(*itubpp));
  493. (*tubirqs)[irqhi] = itubpp;
  494. }
  495. }
  496. /* Request interrupt service */
  497. if ((tubp->irqrc = request_irq(irq, tubint, SA_INTERRUPT,
  498.     "3270 tube driver", &tubp->devstat)) != 0)
  499. return tubp->irqrc;
  500. /* Fill in the proper subarray element */
  501. (*itubpp)[irqlo] = tubp;
  502. return 0;
  503. }
  504. /*
  505.  * tubfindbyirq(irq)
  506.  */
  507. tub_t *
  508. tubfindbyirq(int irq)
  509. {
  510. int irqhi = (irq >> 8) & 255;
  511. int irqlo = irq & 255;
  512. tub_t *tubp;
  513. if (tubirqs == NULL)
  514. return NULL;
  515. if ((*tubirqs)[irqhi] == NULL)
  516. return NULL;
  517. tubp = (*(*tubirqs)[irqhi])[irqlo];
  518. if (tubp->irq == irq)
  519. return tubp;
  520. return NULL;
  521. }
  522. /*
  523.  * tubdelbyirq(tub_t*, irq)
  524.  */
  525. void
  526. tubdelbyirq(tub_t *tubp, int irq)
  527. {
  528. int irqhi = (irq >> 8) & 255;
  529. int irqlo = irq & 255;
  530. tub_t *(*itubpp)[256], *itubp;
  531. if (tubirqs == NULL) {
  532. printk(KERN_ERR "tubirqs is NULLn");
  533. return;
  534. }
  535. itubpp = (*tubirqs)[irqhi];
  536. if (itubpp == NULL) {
  537. printk(KERN_ERR "tubirqs[%d] is NULLn", irqhi);
  538. return;
  539. }
  540. itubp = (*itubpp)[irqlo];
  541. if (itubp == NULL) {
  542. printk(KERN_ERR "tubirqs[%d][%d] is NULLn", irqhi, irqlo);
  543. return;
  544. }
  545. if (itubp->irqrc == 0)
  546. free_irq(irq, &itubp->devstat);
  547. (*itubpp)[irqlo] = NULL;
  548. }
  549. /*
  550.  * tubfiniirqs() -- clean up storage in tub_t *(*(*tubirqs)[256])[256]
  551.  */
  552. void
  553. tubfiniirqs(void)
  554. {
  555. int i;
  556. tub_t *(*itubpp)[256];
  557. if (tubirqs != NULL) {
  558. for (i = 0; i < 256; i++) {
  559. if ((itubpp = (*tubirqs)[i])) {
  560. kfree(itubpp);
  561. (*tubirqs)[i] = NULL;
  562. }
  563. }
  564. kfree(tubirqs);
  565. tubirqs = NULL;
  566. }
  567. }