0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include <linux/console.h>
0013 #include <linux/cpumask.h>
0014 #include <linux/init.h>
0015 #include <linux/kbd_kern.h>
0016 #include <linux/kernel.h>
0017 #include <linux/kthread.h>
0018 #include <linux/list.h>
0019 #include <linux/major.h>
0020 #include <linux/atomic.h>
0021 #include <linux/sysrq.h>
0022 #include <linux/tty.h>
0023 #include <linux/tty_flip.h>
0024 #include <linux/sched.h>
0025 #include <linux/spinlock.h>
0026 #include <linux/delay.h>
0027 #include <linux/freezer.h>
0028 #include <linux/slab.h>
0029 #include <linux/serial_core.h>
0030
0031 #include <linux/uaccess.h>
0032
0033 #include "hvc_console.h"
0034
0035 #define HVC_MAJOR 229
0036 #define HVC_MINOR 0
0037
0038
0039
0040
0041
0042 #define HVC_CLOSE_WAIT (HZ/100)
0043
0044
0045
0046
0047
0048
0049 #define N_OUTBUF 16
0050 #define N_INBUF 16
0051
0052 #define __ALIGNED__ __attribute__((__aligned__(L1_CACHE_BYTES)))
0053
0054 static struct tty_driver *hvc_driver;
0055 static struct task_struct *hvc_task;
0056
0057
0058 static int hvc_kicked;
0059
0060
0061 static atomic_t hvc_needs_init __read_mostly = ATOMIC_INIT(-1);
0062
0063 static int hvc_init(void);
0064
0065 #ifdef CONFIG_MAGIC_SYSRQ
0066 static int sysrq_pressed;
0067 #endif
0068
0069
0070 static LIST_HEAD(hvc_structs);
0071
0072
0073
0074
0075
0076 static DEFINE_MUTEX(hvc_structs_mutex);
0077
0078
0079
0080
0081
0082
0083 static int last_hvc = -1;
0084
0085
0086
0087
0088
0089
0090 static struct hvc_struct *hvc_get_by_index(int index)
0091 {
0092 struct hvc_struct *hp;
0093 unsigned long flags;
0094
0095 mutex_lock(&hvc_structs_mutex);
0096
0097 list_for_each_entry(hp, &hvc_structs, next) {
0098 spin_lock_irqsave(&hp->lock, flags);
0099 if (hp->index == index) {
0100 tty_port_get(&hp->port);
0101 spin_unlock_irqrestore(&hp->lock, flags);
0102 mutex_unlock(&hvc_structs_mutex);
0103 return hp;
0104 }
0105 spin_unlock_irqrestore(&hp->lock, flags);
0106 }
0107 hp = NULL;
0108 mutex_unlock(&hvc_structs_mutex);
0109
0110 return hp;
0111 }
0112
0113 static int __hvc_flush(const struct hv_ops *ops, uint32_t vtermno, bool wait)
0114 {
0115 if (wait)
0116 might_sleep();
0117
0118 if (ops->flush)
0119 return ops->flush(vtermno, wait);
0120 return 0;
0121 }
0122
0123 static int hvc_console_flush(const struct hv_ops *ops, uint32_t vtermno)
0124 {
0125 return __hvc_flush(ops, vtermno, false);
0126 }
0127
0128
0129
0130
0131 static int hvc_flush(struct hvc_struct *hp)
0132 {
0133 return __hvc_flush(hp->ops, hp->vtermno, true);
0134 }
0135
0136
0137
0138
0139
0140
0141
0142 static const struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES];
0143 static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] =
0144 {[0 ... MAX_NR_HVC_CONSOLES - 1] = -1};
0145
0146
0147
0148
0149
0150
0151 static void hvc_console_print(struct console *co, const char *b,
0152 unsigned count)
0153 {
0154 char c[N_OUTBUF] __ALIGNED__;
0155 unsigned i = 0, n = 0;
0156 int r, donecr = 0, index = co->index;
0157
0158
0159 if (index >= MAX_NR_HVC_CONSOLES)
0160 return;
0161
0162
0163 if (vtermnos[index] == -1)
0164 return;
0165
0166 while (count > 0 || i > 0) {
0167 if (count > 0 && i < sizeof(c)) {
0168 if (b[n] == '\n' && !donecr) {
0169 c[i++] = '\r';
0170 donecr = 1;
0171 } else {
0172 c[i++] = b[n++];
0173 donecr = 0;
0174 --count;
0175 }
0176 } else {
0177 r = cons_ops[index]->put_chars(vtermnos[index], c, i);
0178 if (r <= 0) {
0179
0180
0181 if (r != -EAGAIN) {
0182 i = 0;
0183 } else {
0184 hvc_console_flush(cons_ops[index],
0185 vtermnos[index]);
0186 }
0187 } else if (r > 0) {
0188 i -= r;
0189 if (i > 0)
0190 memmove(c, c+r, i);
0191 }
0192 }
0193 }
0194 hvc_console_flush(cons_ops[index], vtermnos[index]);
0195 }
0196
0197 static struct tty_driver *hvc_console_device(struct console *c, int *index)
0198 {
0199 if (vtermnos[c->index] == -1)
0200 return NULL;
0201
0202 *index = c->index;
0203 return hvc_driver;
0204 }
0205
0206 static int hvc_console_setup(struct console *co, char *options)
0207 {
0208 if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES)
0209 return -ENODEV;
0210
0211 if (vtermnos[co->index] == -1)
0212 return -ENODEV;
0213
0214 return 0;
0215 }
0216
0217 static struct console hvc_console = {
0218 .name = "hvc",
0219 .write = hvc_console_print,
0220 .device = hvc_console_device,
0221 .setup = hvc_console_setup,
0222 .flags = CON_PRINTBUFFER,
0223 .index = -1,
0224 };
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241 static int __init hvc_console_init(void)
0242 {
0243 register_console(&hvc_console);
0244 return 0;
0245 }
0246 console_initcall(hvc_console_init);
0247
0248
0249 static void hvc_port_destruct(struct tty_port *port)
0250 {
0251 struct hvc_struct *hp = container_of(port, struct hvc_struct, port);
0252 unsigned long flags;
0253
0254 mutex_lock(&hvc_structs_mutex);
0255
0256 spin_lock_irqsave(&hp->lock, flags);
0257 list_del(&(hp->next));
0258 spin_unlock_irqrestore(&hp->lock, flags);
0259
0260 mutex_unlock(&hvc_structs_mutex);
0261
0262 kfree(hp);
0263 }
0264
0265 static void hvc_check_console(int index)
0266 {
0267
0268 if (hvc_console.flags & CON_ENABLED)
0269 return;
0270
0271
0272
0273
0274
0275 if (index == hvc_console.index)
0276 register_console(&hvc_console);
0277 }
0278
0279
0280
0281
0282
0283
0284
0285 int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops)
0286 {
0287 struct hvc_struct *hp;
0288
0289 if (index < 0 || index >= MAX_NR_HVC_CONSOLES)
0290 return -1;
0291
0292 if (vtermnos[index] != -1)
0293 return -1;
0294
0295
0296 hp = hvc_get_by_index(index);
0297 if (hp) {
0298 tty_port_put(&hp->port);
0299 return -1;
0300 }
0301
0302 vtermnos[index] = vtermno;
0303 cons_ops[index] = ops;
0304
0305
0306 hvc_check_console(index);
0307
0308 return 0;
0309 }
0310 EXPORT_SYMBOL_GPL(hvc_instantiate);
0311
0312
0313 void hvc_kick(void)
0314 {
0315 hvc_kicked = 1;
0316 wake_up_process(hvc_task);
0317 }
0318 EXPORT_SYMBOL_GPL(hvc_kick);
0319
0320 static void hvc_unthrottle(struct tty_struct *tty)
0321 {
0322 hvc_kick();
0323 }
0324
0325 static int hvc_install(struct tty_driver *driver, struct tty_struct *tty)
0326 {
0327 struct hvc_struct *hp;
0328 int rc;
0329
0330
0331 hp = hvc_get_by_index(tty->index);
0332 if (!hp)
0333 return -ENODEV;
0334
0335 tty->driver_data = hp;
0336
0337 rc = tty_port_install(&hp->port, driver, tty);
0338 if (rc)
0339 tty_port_put(&hp->port);
0340 return rc;
0341 }
0342
0343
0344
0345
0346
0347 static int hvc_open(struct tty_struct *tty, struct file * filp)
0348 {
0349 struct hvc_struct *hp = tty->driver_data;
0350 unsigned long flags;
0351 int rc = 0;
0352
0353 spin_lock_irqsave(&hp->port.lock, flags);
0354
0355 if (hp->port.count++ > 0) {
0356 spin_unlock_irqrestore(&hp->port.lock, flags);
0357 hvc_kick();
0358 return 0;
0359 }
0360 spin_unlock_irqrestore(&hp->port.lock, flags);
0361
0362 tty_port_tty_set(&hp->port, tty);
0363
0364 if (hp->ops->notifier_add)
0365 rc = hp->ops->notifier_add(hp, hp->data);
0366
0367
0368
0369
0370
0371
0372
0373 if (rc) {
0374 printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc);
0375 } else {
0376
0377 if (C_BAUD(tty))
0378 if (hp->ops->dtr_rts)
0379 hp->ops->dtr_rts(hp, 1);
0380 tty_port_set_initialized(&hp->port, true);
0381 }
0382
0383
0384 hvc_kick();
0385
0386 return rc;
0387 }
0388
0389 static void hvc_close(struct tty_struct *tty, struct file * filp)
0390 {
0391 struct hvc_struct *hp = tty->driver_data;
0392 unsigned long flags;
0393
0394 if (tty_hung_up_p(filp))
0395 return;
0396
0397 spin_lock_irqsave(&hp->port.lock, flags);
0398
0399 if (--hp->port.count == 0) {
0400 spin_unlock_irqrestore(&hp->port.lock, flags);
0401
0402 tty_port_tty_set(&hp->port, NULL);
0403
0404 if (!tty_port_initialized(&hp->port))
0405 return;
0406
0407 if (C_HUPCL(tty))
0408 if (hp->ops->dtr_rts)
0409 hp->ops->dtr_rts(hp, 0);
0410
0411 if (hp->ops->notifier_del)
0412 hp->ops->notifier_del(hp, hp->data);
0413
0414
0415 cancel_work_sync(&hp->tty_resize);
0416
0417
0418
0419
0420
0421
0422 tty_wait_until_sent(tty, HVC_CLOSE_WAIT);
0423 tty_port_set_initialized(&hp->port, false);
0424 } else {
0425 if (hp->port.count < 0)
0426 printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
0427 hp->vtermno, hp->port.count);
0428 spin_unlock_irqrestore(&hp->port.lock, flags);
0429 }
0430 }
0431
0432 static void hvc_cleanup(struct tty_struct *tty)
0433 {
0434 struct hvc_struct *hp = tty->driver_data;
0435
0436 tty_port_put(&hp->port);
0437 }
0438
0439 static void hvc_hangup(struct tty_struct *tty)
0440 {
0441 struct hvc_struct *hp = tty->driver_data;
0442 unsigned long flags;
0443
0444 if (!hp)
0445 return;
0446
0447
0448 cancel_work_sync(&hp->tty_resize);
0449
0450 spin_lock_irqsave(&hp->port.lock, flags);
0451
0452
0453
0454
0455
0456
0457 if (hp->port.count <= 0) {
0458 spin_unlock_irqrestore(&hp->port.lock, flags);
0459 return;
0460 }
0461
0462 hp->port.count = 0;
0463 spin_unlock_irqrestore(&hp->port.lock, flags);
0464 tty_port_tty_set(&hp->port, NULL);
0465
0466 hp->n_outbuf = 0;
0467
0468 if (hp->ops->notifier_hangup)
0469 hp->ops->notifier_hangup(hp, hp->data);
0470 }
0471
0472
0473
0474
0475
0476 static int hvc_push(struct hvc_struct *hp)
0477 {
0478 int n;
0479
0480 n = hp->ops->put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf);
0481 if (n <= 0) {
0482 if (n == 0 || n == -EAGAIN) {
0483 hp->do_wakeup = 1;
0484 return 0;
0485 }
0486
0487
0488 hp->n_outbuf = 0;
0489 } else
0490 hp->n_outbuf -= n;
0491 if (hp->n_outbuf > 0)
0492 memmove(hp->outbuf, hp->outbuf + n, hp->n_outbuf);
0493 else
0494 hp->do_wakeup = 1;
0495
0496 return n;
0497 }
0498
0499 static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count)
0500 {
0501 struct hvc_struct *hp = tty->driver_data;
0502 unsigned long flags;
0503 int rsize, written = 0;
0504
0505
0506 if (!hp)
0507 return -EPIPE;
0508
0509
0510 if (hp->port.count <= 0)
0511 return -EIO;
0512
0513 while (count > 0) {
0514 int ret = 0;
0515
0516 spin_lock_irqsave(&hp->lock, flags);
0517
0518 rsize = hp->outbuf_size - hp->n_outbuf;
0519
0520 if (rsize) {
0521 if (rsize > count)
0522 rsize = count;
0523 memcpy(hp->outbuf + hp->n_outbuf, buf, rsize);
0524 count -= rsize;
0525 buf += rsize;
0526 hp->n_outbuf += rsize;
0527 written += rsize;
0528 }
0529
0530 if (hp->n_outbuf > 0)
0531 ret = hvc_push(hp);
0532
0533 spin_unlock_irqrestore(&hp->lock, flags);
0534
0535 if (!ret)
0536 break;
0537
0538 if (count) {
0539 if (hp->n_outbuf > 0)
0540 hvc_flush(hp);
0541 cond_resched();
0542 }
0543 }
0544
0545
0546
0547
0548 if (hp->n_outbuf)
0549 hvc_kick();
0550
0551 return written;
0552 }
0553
0554
0555
0556
0557
0558
0559
0560
0561
0562
0563 static void hvc_set_winsz(struct work_struct *work)
0564 {
0565 struct hvc_struct *hp;
0566 unsigned long hvc_flags;
0567 struct tty_struct *tty;
0568 struct winsize ws;
0569
0570 hp = container_of(work, struct hvc_struct, tty_resize);
0571
0572 tty = tty_port_tty_get(&hp->port);
0573 if (!tty)
0574 return;
0575
0576 spin_lock_irqsave(&hp->lock, hvc_flags);
0577 ws = hp->ws;
0578 spin_unlock_irqrestore(&hp->lock, hvc_flags);
0579
0580 tty_do_resize(tty, &ws);
0581 tty_kref_put(tty);
0582 }
0583
0584
0585
0586
0587
0588
0589 static unsigned int hvc_write_room(struct tty_struct *tty)
0590 {
0591 struct hvc_struct *hp = tty->driver_data;
0592
0593 if (!hp)
0594 return 0;
0595
0596 return hp->outbuf_size - hp->n_outbuf;
0597 }
0598
0599 static unsigned int hvc_chars_in_buffer(struct tty_struct *tty)
0600 {
0601 struct hvc_struct *hp = tty->driver_data;
0602
0603 if (!hp)
0604 return 0;
0605 return hp->n_outbuf;
0606 }
0607
0608
0609
0610
0611
0612
0613
0614
0615
0616 #define MIN_TIMEOUT (10)
0617 #define MAX_TIMEOUT (2000)
0618 static u32 timeout = MIN_TIMEOUT;
0619
0620
0621
0622
0623
0624
0625
0626
0627 #define HVC_ATOMIC_READ_MAX 128
0628
0629 #define HVC_POLL_READ 0x00000001
0630 #define HVC_POLL_WRITE 0x00000002
0631
0632 static int __hvc_poll(struct hvc_struct *hp, bool may_sleep)
0633 {
0634 struct tty_struct *tty;
0635 int i, n, count, poll_mask = 0;
0636 char buf[N_INBUF] __ALIGNED__;
0637 unsigned long flags;
0638 int read_total = 0;
0639 int written_total = 0;
0640
0641 spin_lock_irqsave(&hp->lock, flags);
0642
0643
0644 if (hp->n_outbuf > 0)
0645 written_total = hvc_push(hp);
0646
0647
0648 if (hp->n_outbuf > 0) {
0649 poll_mask |= HVC_POLL_WRITE;
0650
0651 timeout = (written_total) ? 0 : MIN_TIMEOUT;
0652 }
0653
0654 if (may_sleep) {
0655 spin_unlock_irqrestore(&hp->lock, flags);
0656 cond_resched();
0657 spin_lock_irqsave(&hp->lock, flags);
0658 }
0659
0660
0661 tty = tty_port_tty_get(&hp->port);
0662 if (tty == NULL)
0663 goto bail;
0664
0665
0666 if (tty_throttled(tty))
0667 goto out;
0668
0669
0670
0671
0672 if (!hp->irq_requested)
0673 poll_mask |= HVC_POLL_READ;
0674
0675 read_again:
0676
0677 count = tty_buffer_request_room(&hp->port, N_INBUF);
0678
0679
0680 if (count == 0) {
0681 poll_mask |= HVC_POLL_READ;
0682 goto out;
0683 }
0684
0685 n = hp->ops->get_chars(hp->vtermno, buf, count);
0686 if (n <= 0) {
0687
0688 if (n == -EPIPE) {
0689 spin_unlock_irqrestore(&hp->lock, flags);
0690 tty_hangup(tty);
0691 spin_lock_irqsave(&hp->lock, flags);
0692 } else if ( n == -EAGAIN ) {
0693
0694
0695
0696
0697
0698 poll_mask |= HVC_POLL_READ;
0699 }
0700 goto out;
0701 }
0702
0703 for (i = 0; i < n; ++i) {
0704 #ifdef CONFIG_MAGIC_SYSRQ
0705 if (hp->index == hvc_console.index) {
0706
0707
0708 if (buf[i] == '\x0f') {
0709
0710
0711 sysrq_pressed = !sysrq_pressed;
0712 if (sysrq_pressed)
0713 continue;
0714 } else if (sysrq_pressed) {
0715 handle_sysrq(buf[i]);
0716 sysrq_pressed = 0;
0717 continue;
0718 }
0719 }
0720 #endif
0721 tty_insert_flip_char(&hp->port, buf[i], 0);
0722 }
0723 read_total += n;
0724
0725 if (may_sleep) {
0726
0727 spin_unlock_irqrestore(&hp->lock, flags);
0728 cond_resched();
0729 spin_lock_irqsave(&hp->lock, flags);
0730 goto read_again;
0731 } else if (read_total < HVC_ATOMIC_READ_MAX) {
0732
0733 goto read_again;
0734 }
0735
0736
0737
0738
0739 poll_mask |= HVC_POLL_READ;
0740
0741 out:
0742
0743 if (hp->do_wakeup) {
0744 hp->do_wakeup = 0;
0745 tty_wakeup(tty);
0746 }
0747 bail:
0748 spin_unlock_irqrestore(&hp->lock, flags);
0749
0750 if (read_total) {
0751
0752
0753 timeout = MIN_TIMEOUT;
0754
0755 tty_flip_buffer_push(&hp->port);
0756 }
0757 tty_kref_put(tty);
0758
0759 return poll_mask;
0760 }
0761
0762 int hvc_poll(struct hvc_struct *hp)
0763 {
0764 return __hvc_poll(hp, false);
0765 }
0766 EXPORT_SYMBOL_GPL(hvc_poll);
0767
0768
0769
0770
0771
0772
0773
0774
0775
0776
0777
0778 void __hvc_resize(struct hvc_struct *hp, struct winsize ws)
0779 {
0780 hp->ws = ws;
0781 schedule_work(&hp->tty_resize);
0782 }
0783 EXPORT_SYMBOL_GPL(__hvc_resize);
0784
0785
0786
0787
0788
0789
0790 static int khvcd(void *unused)
0791 {
0792 int poll_mask;
0793 struct hvc_struct *hp;
0794
0795 set_freezable();
0796 do {
0797 poll_mask = 0;
0798 hvc_kicked = 0;
0799 try_to_freeze();
0800 wmb();
0801 if (!cpus_are_in_xmon()) {
0802 mutex_lock(&hvc_structs_mutex);
0803 list_for_each_entry(hp, &hvc_structs, next) {
0804 poll_mask |= __hvc_poll(hp, true);
0805 cond_resched();
0806 }
0807 mutex_unlock(&hvc_structs_mutex);
0808 } else
0809 poll_mask |= HVC_POLL_READ;
0810 if (hvc_kicked)
0811 continue;
0812 set_current_state(TASK_INTERRUPTIBLE);
0813 if (!hvc_kicked) {
0814 if (poll_mask == 0)
0815 schedule();
0816 else {
0817 unsigned long j_timeout;
0818
0819 if (timeout < MAX_TIMEOUT)
0820 timeout += (timeout >> 6) + 1;
0821
0822
0823
0824
0825
0826 j_timeout = msecs_to_jiffies(timeout) + 1;
0827 schedule_timeout_interruptible(j_timeout);
0828 }
0829 }
0830 __set_current_state(TASK_RUNNING);
0831 } while (!kthread_should_stop());
0832
0833 return 0;
0834 }
0835
0836 static int hvc_tiocmget(struct tty_struct *tty)
0837 {
0838 struct hvc_struct *hp = tty->driver_data;
0839
0840 if (!hp || !hp->ops->tiocmget)
0841 return -EINVAL;
0842 return hp->ops->tiocmget(hp);
0843 }
0844
0845 static int hvc_tiocmset(struct tty_struct *tty,
0846 unsigned int set, unsigned int clear)
0847 {
0848 struct hvc_struct *hp = tty->driver_data;
0849
0850 if (!hp || !hp->ops->tiocmset)
0851 return -EINVAL;
0852 return hp->ops->tiocmset(hp, set, clear);
0853 }
0854
0855 #ifdef CONFIG_CONSOLE_POLL
0856 static int hvc_poll_init(struct tty_driver *driver, int line, char *options)
0857 {
0858 return 0;
0859 }
0860
0861 static int hvc_poll_get_char(struct tty_driver *driver, int line)
0862 {
0863 struct tty_struct *tty = driver->ttys[0];
0864 struct hvc_struct *hp = tty->driver_data;
0865 int n;
0866 char ch;
0867
0868 n = hp->ops->get_chars(hp->vtermno, &ch, 1);
0869
0870 if (n <= 0)
0871 return NO_POLL_CHAR;
0872
0873 return ch;
0874 }
0875
0876 static void hvc_poll_put_char(struct tty_driver *driver, int line, char ch)
0877 {
0878 struct tty_struct *tty = driver->ttys[0];
0879 struct hvc_struct *hp = tty->driver_data;
0880 int n;
0881
0882 do {
0883 n = hp->ops->put_chars(hp->vtermno, &ch, 1);
0884 } while (n <= 0);
0885 }
0886 #endif
0887
0888 static const struct tty_operations hvc_ops = {
0889 .install = hvc_install,
0890 .open = hvc_open,
0891 .close = hvc_close,
0892 .cleanup = hvc_cleanup,
0893 .write = hvc_write,
0894 .hangup = hvc_hangup,
0895 .unthrottle = hvc_unthrottle,
0896 .write_room = hvc_write_room,
0897 .chars_in_buffer = hvc_chars_in_buffer,
0898 .tiocmget = hvc_tiocmget,
0899 .tiocmset = hvc_tiocmset,
0900 #ifdef CONFIG_CONSOLE_POLL
0901 .poll_init = hvc_poll_init,
0902 .poll_get_char = hvc_poll_get_char,
0903 .poll_put_char = hvc_poll_put_char,
0904 #endif
0905 };
0906
0907 static const struct tty_port_operations hvc_port_ops = {
0908 .destruct = hvc_port_destruct,
0909 };
0910
0911 struct hvc_struct *hvc_alloc(uint32_t vtermno, int data,
0912 const struct hv_ops *ops,
0913 int outbuf_size)
0914 {
0915 struct hvc_struct *hp;
0916 int i;
0917
0918
0919 if (atomic_inc_not_zero(&hvc_needs_init)) {
0920 int err = hvc_init();
0921 if (err)
0922 return ERR_PTR(err);
0923 }
0924
0925 hp = kzalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size,
0926 GFP_KERNEL);
0927 if (!hp)
0928 return ERR_PTR(-ENOMEM);
0929
0930 hp->vtermno = vtermno;
0931 hp->data = data;
0932 hp->ops = ops;
0933 hp->outbuf_size = outbuf_size;
0934 hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))];
0935
0936 tty_port_init(&hp->port);
0937 hp->port.ops = &hvc_port_ops;
0938
0939 INIT_WORK(&hp->tty_resize, hvc_set_winsz);
0940 spin_lock_init(&hp->lock);
0941 mutex_lock(&hvc_structs_mutex);
0942
0943
0944
0945
0946
0947 for (i=0; i < MAX_NR_HVC_CONSOLES; i++)
0948 if (vtermnos[i] == hp->vtermno &&
0949 cons_ops[i] == hp->ops)
0950 break;
0951
0952 if (i >= MAX_NR_HVC_CONSOLES) {
0953
0954
0955 for (i = 0; i < MAX_NR_HVC_CONSOLES && vtermnos[i] != -1; i++) {
0956 }
0957
0958
0959 if (i == MAX_NR_HVC_CONSOLES)
0960 i = ++last_hvc + MAX_NR_HVC_CONSOLES;
0961 }
0962
0963 hp->index = i;
0964 if (i < MAX_NR_HVC_CONSOLES) {
0965 cons_ops[i] = ops;
0966 vtermnos[i] = vtermno;
0967 }
0968
0969 list_add_tail(&(hp->next), &hvc_structs);
0970 mutex_unlock(&hvc_structs_mutex);
0971
0972
0973 hvc_check_console(i);
0974
0975 return hp;
0976 }
0977 EXPORT_SYMBOL_GPL(hvc_alloc);
0978
0979 int hvc_remove(struct hvc_struct *hp)
0980 {
0981 unsigned long flags;
0982 struct tty_struct *tty;
0983
0984 tty = tty_port_tty_get(&hp->port);
0985
0986 console_lock();
0987 spin_lock_irqsave(&hp->lock, flags);
0988 if (hp->index < MAX_NR_HVC_CONSOLES) {
0989 vtermnos[hp->index] = -1;
0990 cons_ops[hp->index] = NULL;
0991 }
0992
0993
0994
0995 spin_unlock_irqrestore(&hp->lock, flags);
0996 console_unlock();
0997
0998
0999
1000
1001
1002
1003
1004 tty_port_put(&hp->port);
1005
1006
1007
1008
1009 if (tty) {
1010 tty_vhangup(tty);
1011 tty_kref_put(tty);
1012 }
1013 return 0;
1014 }
1015 EXPORT_SYMBOL_GPL(hvc_remove);
1016
1017
1018 static int hvc_init(void)
1019 {
1020 struct tty_driver *drv;
1021 int err;
1022
1023
1024 drv = tty_alloc_driver(HVC_ALLOC_TTY_ADAPTERS, TTY_DRIVER_REAL_RAW |
1025 TTY_DRIVER_RESET_TERMIOS);
1026 if (IS_ERR(drv)) {
1027 err = PTR_ERR(drv);
1028 goto out;
1029 }
1030
1031 drv->driver_name = "hvc";
1032 drv->name = "hvc";
1033 drv->major = HVC_MAJOR;
1034 drv->minor_start = HVC_MINOR;
1035 drv->type = TTY_DRIVER_TYPE_SYSTEM;
1036 drv->init_termios = tty_std_termios;
1037 tty_set_operations(drv, &hvc_ops);
1038
1039
1040
1041 hvc_task = kthread_run(khvcd, NULL, "khvcd");
1042 if (IS_ERR(hvc_task)) {
1043 printk(KERN_ERR "Couldn't create kthread for console.\n");
1044 err = PTR_ERR(hvc_task);
1045 goto put_tty;
1046 }
1047
1048 err = tty_register_driver(drv);
1049 if (err) {
1050 printk(KERN_ERR "Couldn't register hvc console driver\n");
1051 goto stop_thread;
1052 }
1053
1054
1055
1056
1057
1058 smp_mb();
1059 hvc_driver = drv;
1060 return 0;
1061
1062 stop_thread:
1063 kthread_stop(hvc_task);
1064 hvc_task = NULL;
1065 put_tty:
1066 tty_driver_kref_put(drv);
1067 out:
1068 return err;
1069 }