~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/char/serial_21285.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.