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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * linux/drivers/char/serial_21285.c
  3.  *
  4.  * Driver for the serial port on the 21285 StrongArm-110 core logic chip.
  5.  *
  6.  * Based on drivers/char/serial.c
  7.  */
  8. #include <linux/config.h>
  9. #include <linux/module.h>
  10. #include <linux/errno.h>
  11. #include <linux/signal.h>
  12. #include <linux/sched.h>
  13. #include <linux/interrupt.h>
  14. #include <linux/tty.h>
  15. #include <linux/tty_flip.h>
  16. #include <linux/serial.h>
  17. #include <linux/major.h>
  18. #include <linux/ptrace.h>
  19. #include <linux/ioport.h>
  20. #include <linux/mm.h>
  21. #include <linux/slab.h>
  22. #include <linux/init.h>
  23. #include <linux/console.h>
  24. #include <asm/io.h>
  25. #include <asm/irq.h>
  26. #include <asm/uaccess.h>
  27. #include <asm/dec21285.h>
  28. #include <asm/hardware.h>
  29. #define BAUD_BASE (mem_fclk_21285/64)
  30. #define SERIAL_21285_NAME "ttyFB"
  31. #define SERIAL_21285_MAJOR 204
  32. #define SERIAL_21285_MINOR 4
  33. #define SERIAL_21285_AUXNAME "cuafb"
  34. #define SERIAL_21285_AUXMAJOR 205
  35. #define SERIAL_21285_AUXMINOR 4
  36. static struct tty_driver rs285_driver, callout_driver;
  37. static int rs285_refcount;
  38. static struct tty_struct *rs285_table[1];
  39. static struct termios *rs285_termios[1];
  40. static struct termios *rs285_termios_locked[1];
  41. static char wbuf[1000], *putp = wbuf, *getp = wbuf, x_char;
  42. static struct tty_struct *rs285_tty;
  43. static int rs285_use_count;
  44. static int rs285_write_room(struct tty_struct *tty)
  45. {
  46. return putp >= getp ? (sizeof(wbuf) - (long) putp + (long) getp) : ((long) getp - (long) putp - 1);
  47. }
  48. static void rs285_rx_int(int irq, void *dev_id, struct pt_regs *regs)
  49. {
  50. if (!rs285_tty) {
  51. disable_irq(IRQ_CONRX);
  52. return;
  53. }
  54. while (!(*CSR_UARTFLG & 0x10)) {
  55. int ch, flag;
  56. ch = *CSR_UARTDR;
  57. flag = *CSR_RXSTAT;
  58. if (flag & 4)
  59. tty_insert_flip_char(rs285_tty, 0, TTY_OVERRUN);
  60. if (flag & 2)
  61. flag = TTY_PARITY;
  62. else if (flag & 1)
  63. flag = TTY_FRAME;
  64. tty_insert_flip_char(rs285_tty, ch, flag);
  65. }
  66. tty_flip_buffer_push(rs285_tty);
  67. }
  68. static void rs285_send_xchar(struct tty_struct *tty, char ch)
  69. {
  70. x_char = ch;
  71. enable_irq(IRQ_CONTX);
  72. }
  73. static void rs285_throttle(struct tty_struct *tty)
  74. {
  75. if (I_IXOFF(tty))
  76. rs285_send_xchar(tty, STOP_CHAR(tty));
  77. }
  78. static void rs285_unthrottle(struct tty_struct *tty)
  79. {
  80. if (I_IXOFF(tty)) {
  81. if (x_char)
  82. x_char = 0;
  83. else
  84. rs285_send_xchar(tty, START_CHAR(tty));
  85. }
  86. }
  87. static void rs285_tx_int(int irq, void *dev_id, struct pt_regs *regs)
  88. {
  89. while (!(*CSR_UARTFLG & 0x20)) {
  90. if (x_char) {
  91. *CSR_UARTDR = x_char;
  92. x_char = 0;
  93. continue;
  94. }
  95. if (putp == getp) {
  96. disable_irq(IRQ_CONTX);
  97. break;
  98. }
  99. *CSR_UARTDR = *getp;
  100. if (++getp >= wbuf + sizeof(wbuf))
  101. getp = wbuf;
  102. }
  103. if (rs285_tty)
  104. wake_up_interruptible(&rs285_tty->write_wait);
  105. }
  106. static inline int rs285_xmit(int ch)
  107. {
  108. if (putp + 1 == getp || (putp + 1 == wbuf + sizeof(wbuf) && getp == wbuf))
  109. return 0;
  110. *putp = ch;
  111. if (++putp >= wbuf + sizeof(wbuf))
  112. putp = wbuf;
  113. enable_irq(IRQ_CONTX);
  114. return 1;
  115. }
  116. static int rs285_write(struct tty_struct *tty, int from_user,
  117.        const u_char * buf, int count)
  118. {
  119. int i;
  120. if (from_user && verify_area(VERIFY_READ, buf, count))
  121. return -EINVAL;
  122. for (i = 0; i < count; i++) {
  123. char ch;
  124. if (from_user)
  125. __get_user(ch, buf + i);
  126. else
  127. ch = buf[i];
  128. if (!rs285_xmit(ch))
  129. break;
  130. }
  131. return i;
  132. }
  133. static void rs285_put_char(struct tty_struct *tty, u_char ch)
  134. {
  135. rs285_xmit(ch);
  136. }
  137. static int rs285_chars_in_buffer(struct tty_struct *tty)
  138. {
  139. return sizeof(wbuf) - rs285_write_room(tty);
  140. }
  141. static void rs285_flush_buffer(struct tty_struct *tty)
  142. {
  143. disable_irq(IRQ_CONTX);
  144. putp = getp = wbuf;
  145. if (x_char)
  146. enable_irq(IRQ_CONTX);
  147. }
  148. static inline void rs285_set_cflag(int cflag)
  149. {
  150. int h_lcr, baud, quot;
  151. switch (cflag & CSIZE) {
  152. case CS5:
  153. h_lcr = 0x10;
  154. break;
  155. case CS6:
  156. h_lcr = 0x30;
  157. break;
  158. case CS7:
  159. h_lcr = 0x50;
  160. break;
  161. default: /* CS8 */
  162. h_lcr = 0x70;
  163. break;
  164. }
  165. if (cflag & CSTOPB)
  166. h_lcr |= 0x08;
  167. if (cflag & PARENB)
  168. h_lcr |= 0x02;
  169. if (!(cflag & PARODD))
  170. h_lcr |= 0x04;
  171. switch (cflag & CBAUD) {
  172. case B200: baud = 200; break;
  173. case B300: baud = 300; break;
  174. case B1200: baud = 1200; break;
  175. case B1800: baud = 1800; break;
  176. case B2400: baud = 2400; break;
  177. case B4800: baud = 4800; break;
  178. default:
  179. case B9600: baud = 9600; break;
  180. case B19200: baud = 19200; break;
  181. case B38400: baud = 38400; break;
  182. case B57600: baud = 57600; break;
  183. case B115200: baud = 115200; break;
  184. }
  185. /*
  186.  * The documented expression for selecting the divisor is:
  187.  *  BAUD_BASE / baud - 1
  188.  * However, typically BAUD_BASE is not divisible by baud, so
  189.  * we want to select the divisor that gives us the minimum
  190.  * error.  Therefore, we want:
  191.  *  int(BAUD_BASE / baud - 0.5) ->
  192.  *  int(BAUD_BASE / baud - (baud >> 1) / baud) ->
  193.  *  int((BAUD_BASE - (baud >> 1)) / baud)
  194.  */
  195. quot = (BAUD_BASE - (baud >> 1)) / baud;
  196. *CSR_UARTCON = 0;
  197. *CSR_L_UBRLCR = quot & 0xff;
  198. *CSR_M_UBRLCR = (quot >> 8) & 0x0f;
  199. *CSR_H_UBRLCR = h_lcr;
  200. *CSR_UARTCON = 1;
  201. }
  202. static void rs285_set_termios(struct tty_struct *tty, struct termios *old)
  203. {
  204. if (old && tty->termios->c_cflag == old->c_cflag)
  205. return;
  206. rs285_set_cflag(tty->termios->c_cflag);
  207. }
  208. static void rs285_stop(struct tty_struct *tty)
  209. {
  210. disable_irq(IRQ_CONTX);
  211. }
  212. static void rs285_start(struct tty_struct *tty)
  213. {
  214. enable_irq(IRQ_CONTX);
  215. }
  216. static void rs285_wait_until_sent(struct tty_struct *tty, int timeout)
  217. {
  218. int orig_jiffies = jiffies;
  219. while (*CSR_UARTFLG & 8) {
  220. current->state = TASK_INTERRUPTIBLE;
  221. schedule_timeout(1);
  222. if (signal_pending(current))
  223. break;
  224. if (timeout && time_after(jiffies, orig_jiffies + timeout))
  225. break;
  226. }
  227. current->state = TASK_RUNNING;
  228. }
  229. static int rs285_open(struct tty_struct *tty, struct file *filp)
  230. {
  231. int line;
  232. MOD_INC_USE_COUNT;
  233. line = MINOR(tty->device) - tty->driver.minor_start;
  234. if (line) {
  235. MOD_DEC_USE_COUNT;
  236. return -ENODEV;
  237. }
  238. tty->driver_data = NULL;
  239. if (!rs285_tty)
  240. rs285_tty = tty;
  241. enable_irq(IRQ_CONRX);
  242. rs285_use_count++;
  243. return 0;
  244. }
  245. static void rs285_close(struct tty_struct *tty, struct file *filp)
  246. {
  247. if (!--rs285_use_count) {
  248. rs285_wait_until_sent(tty, 0);
  249. disable_irq(IRQ_CONRX);
  250. disable_irq(IRQ_CONTX);
  251. rs285_tty = NULL;
  252. }
  253. MOD_DEC_USE_COUNT;
  254. }
  255. static int __init rs285_init(void)
  256. {
  257. int baud = B9600;
  258. if (machine_is_personal_server())
  259. baud = B57600;
  260. rs285_driver.magic = TTY_DRIVER_MAGIC;
  261. rs285_driver.driver_name = "serial_21285";
  262. rs285_driver.name = SERIAL_21285_NAME;
  263. rs285_driver.major = SERIAL_21285_MAJOR;
  264. rs285_driver.minor_start = SERIAL_21285_MINOR;
  265. rs285_driver.num = 1;
  266. rs285_driver.type = TTY_DRIVER_TYPE_SERIAL;
  267. rs285_driver.subtype = SERIAL_TYPE_NORMAL;
  268. rs285_driver.init_termios = tty_std_termios;
  269. rs285_driver.init_termios.c_cflag = baud | CS8 | CREAD | HUPCL | CLOCAL;
  270. rs285_driver.flags = TTY_DRIVER_REAL_RAW;
  271. rs285_driver.refcount = &rs285_refcount;
  272. rs285_driver.table = rs285_table;
  273. rs285_driver.termios = rs285_termios;
  274. rs285_driver.termios_locked = rs285_termios_locked;
  275. rs285_driver.open = rs285_open;
  276. rs285_driver.close = rs285_close;
  277. rs285_driver.write = rs285_write;
  278. rs285_driver.put_char = rs285_put_char;
  279. rs285_driver.write_room = rs285_write_room;
  280. rs285_driver.chars_in_buffer = rs285_chars_in_buffer;
  281. rs285_driver.flush_buffer = rs285_flush_buffer;
  282. rs285_driver.throttle = rs285_throttle;
  283. rs285_driver.unthrottle = rs285_unthrottle;
  284. rs285_driver.send_xchar = rs285_send_xchar;
  285. rs285_driver.set_termios = rs285_set_termios;
  286. rs285_driver.stop = rs285_stop;
  287. rs285_driver.start = rs285_start;
  288. rs285_driver.wait_until_sent = rs285_wait_until_sent;
  289. callout_driver = rs285_driver;
  290. callout_driver.name = SERIAL_21285_AUXNAME;
  291. callout_driver.major = SERIAL_21285_AUXMAJOR;
  292. callout_driver.subtype = SERIAL_TYPE_CALLOUT;
  293. if (request_irq(IRQ_CONRX, rs285_rx_int, 0, "rs285", NULL))
  294. panic("Couldn't get rx irq for rs285");
  295. if (request_irq(IRQ_CONTX, rs285_tx_int, 0, "rs285", NULL))
  296. panic("Couldn't get tx irq for rs285");
  297. if (tty_register_driver(&rs285_driver))
  298. printk(KERN_ERR "Couldn't register 21285 serial drivern");
  299. if (tty_register_driver(&callout_driver))
  300. printk(KERN_ERR "Couldn't register 21285 callout drivern");
  301. return 0;
  302. }
  303. static void __exit rs285_fini(void)
  304. {
  305. unsigned long flags;
  306. int ret;
  307. save_flags(flags);
  308. cli();
  309. ret = tty_unregister_driver(&callout_driver);
  310. if (ret)
  311. printk(KERN_ERR "Unable to unregister 21285 callout driver "
  312. "(%d)n", ret);
  313. ret = tty_unregister_driver(&rs285_driver);
  314. if (ret)
  315. printk(KERN_ERR "Unable to unregister 21285 driver (%d)n",
  316. ret);
  317. free_irq(IRQ_CONTX, NULL);
  318. free_irq(IRQ_CONRX, NULL);
  319. restore_flags(flags);
  320. }
  321. module_init(rs285_init);
  322. module_exit(rs285_fini);
  323. #ifdef CONFIG_SERIAL_21285_CONSOLE
  324. /************** console driver *****************/
  325. static void rs285_console_write(struct console *co, const char *s, u_int count)
  326. {
  327. int i;
  328. disable_irq(IRQ_CONTX);
  329. for (i = 0; i < count; i++) {
  330. while (*CSR_UARTFLG & 0x20);
  331. *CSR_UARTDR = s[i];
  332. if (s[i] == 'n') {
  333. while (*CSR_UARTFLG & 0x20);
  334. *CSR_UARTDR = 'r';
  335. }
  336. }
  337. enable_irq(IRQ_CONTX);
  338. }
  339. static kdev_t rs285_console_device(struct console *c)
  340. {
  341. return MKDEV(SERIAL_21285_MAJOR, SERIAL_21285_MINOR);
  342. }
  343. static int __init rs285_console_setup(struct console *co, char *options)
  344. {
  345. int baud = 9600;
  346. int bits = 8;
  347. int parity = 'n';
  348. int cflag = CREAD | HUPCL | CLOCAL;
  349. if (machine_is_personal_server())
  350. baud = 57600;
  351. if (options) {
  352. char *s = options;
  353. baud = simple_strtoul(options, NULL, 10);
  354. while (*s >= '0' && *s <= '9')
  355. s++;
  356. if (*s)
  357. parity = *s++;
  358. if (*s)
  359. bits = *s - '0';
  360. }
  361. /*
  362.  *    Now construct a cflag setting.
  363.  */
  364. switch (baud) {
  365. case 1200:
  366. cflag |= B1200;
  367. break;
  368. case 2400:
  369. cflag |= B2400;
  370. break;
  371. case 4800:
  372. cflag |= B4800;
  373. break;
  374. case 9600:
  375. cflag |= B9600;
  376. break;
  377. case 19200:
  378. cflag |= B19200;
  379. break;
  380. case 38400:
  381. cflag |= B38400;
  382. break;
  383. case 57600:
  384. cflag |= B57600;
  385. break;
  386. case 115200:
  387. cflag |= B115200;
  388. break;
  389. default:
  390. cflag |= B9600;
  391. break;
  392. }
  393. switch (bits) {
  394. case 7:
  395. cflag |= CS7;
  396. break;
  397. default:
  398. cflag |= CS8;
  399. break;
  400. }
  401. switch (parity) {
  402. case 'o':
  403. case 'O':
  404. cflag |= PARODD;
  405. break;
  406. case 'e':
  407. case 'E':
  408. cflag |= PARENB;
  409. break;
  410. }
  411. co->cflag = cflag;
  412. rs285_set_cflag(cflag);
  413. rs285_console_write(NULL, "e[2Je[Hboot ", 12);
  414. if (options)
  415. rs285_console_write(NULL, options, strlen(options));
  416. else
  417. rs285_console_write(NULL, "no options", 10);
  418. rs285_console_write(NULL, "n", 1);
  419. return 0;
  420. }
  421. static struct console rs285_cons =
  422. {
  423. name: SERIAL_21285_NAME,
  424. write: rs285_console_write,
  425. device: rs285_console_device,
  426. setup: rs285_console_setup,
  427. flags: CON_PRINTBUFFER,
  428. index: -1,
  429. };
  430. void __init rs285_console_init(void)
  431. {
  432. register_console(&rs285_cons);
  433. }
  434. #endif /* CONFIG_SERIAL_21285_CONSOLE */
  435. MODULE_LICENSE("GPL");
  436. EXPORT_NO_SYMBOLS;