1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24#include <linux/init.h>
25#include <linux/sched.h>
26#include <linux/interrupt.h>
27#include <linux/console.h>
28#include <linux/kernel.h>
29#include <linux/module.h>
30#include <linux/tty.h>
31#include <linux/tty_driver.h>
32#include <linux/pci.h>
33#include <linux/mutex.h>
34#include <linux/miscdevice.h>
35#include <linux/pti.h>
36#include <linux/slab.h>
37#include <linux/uaccess.h>
38
39#define DRIVERNAME "pti"
40#define PCINAME "pciPTI"
41#define TTYNAME "ttyPTI"
42#define CHARNAME "pti"
43#define PTITTY_MINOR_START 0
44#define PTITTY_MINOR_NUM 2
45#define MAX_APP_IDS 16
46#define MAX_OS_IDS 16
47#define MAX_MODEM_IDS 16
48#define MODEM_BASE_ID 71
49#define CONTROL_ID 72
50#define CONSOLE_ID 73
51#define OS_BASE_ID 74
52#define APP_BASE_ID 80
53#define CONTROL_FRAME_LEN 32
54#define USER_COPY_SIZE 8192
55#define APERTURE_14 0x3800000
56#define APERTURE_LEN 0x400000
57
58struct pti_tty {
59 struct pti_masterchannel *mc;
60};
61
62struct pti_dev {
63 struct tty_port port[PTITTY_MINOR_NUM];
64 unsigned long pti_addr;
65 unsigned long aperture_base;
66 void __iomem *pti_ioaddr;
67 u8 ia_app[MAX_APP_IDS];
68 u8 ia_os[MAX_OS_IDS];
69 u8 ia_modem[MAX_MODEM_IDS];
70};
71
72
73
74
75
76
77static DEFINE_MUTEX(alloclock);
78
79static const struct pci_device_id pci_ids[] = {
80 {PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x82B)},
81 {0}
82};
83
84static struct tty_driver *pti_tty_driver;
85static struct pti_dev *drv_data;
86
87static unsigned int pti_console_channel;
88static unsigned int pti_control_channel;
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107static void pti_write_to_aperture(struct pti_masterchannel *mc,
108 u8 *buf,
109 int len)
110{
111 int dwordcnt;
112 int final;
113 int i;
114 u32 ptiword;
115 u32 __iomem *aperture;
116 u8 *p = buf;
117
118
119
120
121
122 aperture = drv_data->pti_ioaddr + (mc->master << 15)
123 + (mc->channel << 8);
124
125 dwordcnt = len >> 2;
126 final = len - (dwordcnt << 2);
127 if (final == 0 && dwordcnt != 0) {
128 final += 4;
129 dwordcnt--;
130 }
131
132 for (i = 0; i < dwordcnt; i++) {
133 ptiword = be32_to_cpu(*(u32 *)p);
134 p += 4;
135 iowrite32(ptiword, aperture);
136 }
137
138 aperture += PTI_LASTDWORD_DTS;
139
140 ptiword = 0;
141 for (i = 0; i < final; i++)
142 ptiword |= *p++ << (24-(8*i));
143
144 iowrite32(ptiword, aperture);
145 return;
146}
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165static void pti_control_frame_built_and_sent(struct pti_masterchannel *mc,
166 const char *thread_name)
167{
168
169
170
171
172 char comm[TASK_COMM_LEN];
173 struct pti_masterchannel mccontrol = {.master = CONTROL_ID,
174 .channel = 0};
175 const char *thread_name_p;
176 const char *control_format = "%3d %3d %s";
177 u8 control_frame[CONTROL_FRAME_LEN];
178
179 if (!thread_name) {
180 if (!in_interrupt())
181 get_task_comm(comm, current);
182 else
183 strncpy(comm, "Interrupt", TASK_COMM_LEN);
184
185
186 comm[TASK_COMM_LEN-1] = 0;
187 thread_name_p = comm;
188 } else {
189 thread_name_p = thread_name;
190 }
191
192 mccontrol.channel = pti_control_channel;
193 pti_control_channel = (pti_control_channel + 1) & 0x7f;
194
195 snprintf(control_frame, CONTROL_FRAME_LEN, control_format, mc->master,
196 mc->channel, thread_name_p);
197 pti_write_to_aperture(&mccontrol, control_frame, strlen(control_frame));
198}
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214static void pti_write_full_frame_to_aperture(struct pti_masterchannel *mc,
215 const unsigned char *buf,
216 int len)
217{
218 pti_control_frame_built_and_sent(mc, NULL);
219 pti_write_to_aperture(mc, (u8 *)buf, len);
220}
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241static struct pti_masterchannel *get_id(u8 *id_array,
242 int max_ids,
243 int base_id,
244 const char *thread_name)
245{
246 struct pti_masterchannel *mc;
247 int i, j, mask;
248
249 mc = kmalloc(sizeof(struct pti_masterchannel), GFP_KERNEL);
250 if (mc == NULL)
251 return NULL;
252
253
254 for (i = 0; i < max_ids; i++)
255 if (id_array[i] != 0xff)
256 break;
257 if (i == max_ids) {
258 kfree(mc);
259 return NULL;
260 }
261
262 mask = 0x80;
263 for (j = 0; j < 8; j++) {
264 if ((id_array[i] & mask) == 0)
265 break;
266 mask >>= 1;
267 }
268
269
270 id_array[i] |= mask;
271 mc->master = base_id;
272 mc->channel = ((i & 0xf)<<3) + j;
273
274 pti_control_frame_built_and_sent(mc, thread_name);
275 return mc;
276}
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304struct pti_masterchannel *pti_request_masterchannel(u8 type,
305 const char *thread_name)
306{
307 struct pti_masterchannel *mc;
308
309 mutex_lock(&alloclock);
310
311 switch (type) {
312
313 case 0:
314 mc = get_id(drv_data->ia_app, MAX_APP_IDS,
315 APP_BASE_ID, thread_name);
316 break;
317
318 case 1:
319 mc = get_id(drv_data->ia_os, MAX_OS_IDS,
320 OS_BASE_ID, thread_name);
321 break;
322
323 case 2:
324 mc = get_id(drv_data->ia_modem, MAX_MODEM_IDS,
325 MODEM_BASE_ID, thread_name);
326 break;
327 default:
328 mc = NULL;
329 }
330
331 mutex_unlock(&alloclock);
332 return mc;
333}
334EXPORT_SYMBOL_GPL(pti_request_masterchannel);
335
336
337
338
339
340
341
342
343
344void pti_release_masterchannel(struct pti_masterchannel *mc)
345{
346 u8 master, channel, i;
347
348 mutex_lock(&alloclock);
349
350 if (mc) {
351 master = mc->master;
352 channel = mc->channel;
353
354 if (master == APP_BASE_ID) {
355 i = channel >> 3;
356 drv_data->ia_app[i] &= ~(0x80>>(channel & 0x7));
357 } else if (master == OS_BASE_ID) {
358 i = channel >> 3;
359 drv_data->ia_os[i] &= ~(0x80>>(channel & 0x7));
360 } else {
361 i = channel >> 3;
362 drv_data->ia_modem[i] &= ~(0x80>>(channel & 0x7));
363 }
364
365 kfree(mc);
366 }
367
368 mutex_unlock(&alloclock);
369}
370EXPORT_SYMBOL_GPL(pti_release_masterchannel);
371
372
373
374
375
376
377
378
379
380
381
382
383void pti_writedata(struct pti_masterchannel *mc, u8 *buf, int count)
384{
385
386
387
388
389
390 if ((mc != NULL) && (buf != NULL) && (count > 0))
391 pti_write_to_aperture(mc, buf, count);
392 return;
393}
394EXPORT_SYMBOL_GPL(pti_writedata);
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421static int pti_tty_driver_open(struct tty_struct *tty, struct file *filp)
422{
423
424
425
426
427
428
429
430 return tty_port_open(tty->port, tty, filp);
431}
432
433
434
435
436
437
438
439
440
441
442
443
444static void pti_tty_driver_close(struct tty_struct *tty, struct file *filp)
445{
446 tty_port_close(tty->port, tty, filp);
447}
448
449
450
451
452
453
454
455
456
457
458
459
460
461static int pti_tty_install(struct tty_driver *driver, struct tty_struct *tty)
462{
463 int idx = tty->index;
464 struct pti_tty *pti_tty_data;
465 int ret = tty_standard_install(driver, tty);
466
467 if (ret == 0) {
468 pti_tty_data = kmalloc(sizeof(struct pti_tty), GFP_KERNEL);
469 if (pti_tty_data == NULL)
470 return -ENOMEM;
471
472 if (idx == PTITTY_MINOR_START)
473 pti_tty_data->mc = pti_request_masterchannel(0, NULL);
474 else
475 pti_tty_data->mc = pti_request_masterchannel(2, NULL);
476
477 if (pti_tty_data->mc == NULL) {
478 kfree(pti_tty_data);
479 return -ENXIO;
480 }
481 tty->driver_data = pti_tty_data;
482 }
483
484 return ret;
485}
486
487
488
489
490
491
492
493static void pti_tty_cleanup(struct tty_struct *tty)
494{
495 struct pti_tty *pti_tty_data = tty->driver_data;
496 if (pti_tty_data == NULL)
497 return;
498 pti_release_masterchannel(pti_tty_data->mc);
499 kfree(pti_tty_data);
500 tty->driver_data = NULL;
501}
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516static int pti_tty_driver_write(struct tty_struct *tty,
517 const unsigned char *buf, int len)
518{
519 struct pti_tty *pti_tty_data = tty->driver_data;
520 if ((pti_tty_data != NULL) && (pti_tty_data->mc != NULL)) {
521 pti_write_to_aperture(pti_tty_data->mc, (u8 *)buf, len);
522 return len;
523 }
524
525
526
527
528 else
529 return -EFAULT;
530}
531
532
533
534
535
536
537static int pti_tty_write_room(struct tty_struct *tty)
538{
539 return 2048;
540}
541
542
543
544
545
546
547
548
549
550
551
552
553
554static int pti_char_open(struct inode *inode, struct file *filp)
555{
556 struct pti_masterchannel *mc;
557
558
559
560
561
562
563
564 mc = pti_request_masterchannel(0, NULL);
565 if (mc == NULL)
566 return -ENOMEM;
567 filp->private_data = mc;
568 return 0;
569}
570
571
572
573
574
575
576
577
578
579
580
581
582static int pti_char_release(struct inode *inode, struct file *filp)
583{
584 pti_release_masterchannel(filp->private_data);
585 filp->private_data = NULL;
586 return 0;
587}
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609static ssize_t pti_char_write(struct file *filp, const char __user *data,
610 size_t len, loff_t *ppose)
611{
612 struct pti_masterchannel *mc;
613 void *kbuf;
614 const char __user *tmp;
615 size_t size = USER_COPY_SIZE;
616 size_t n = 0;
617
618 tmp = data;
619 mc = filp->private_data;
620
621 kbuf = kmalloc(size, GFP_KERNEL);
622 if (kbuf == NULL) {
623 pr_err("%s(%d): buf allocation failed\n",
624 __func__, __LINE__);
625 return -ENOMEM;
626 }
627
628 do {
629 if (len - n > USER_COPY_SIZE)
630 size = USER_COPY_SIZE;
631 else
632 size = len - n;
633
634 if (copy_from_user(kbuf, tmp, size)) {
635 kfree(kbuf);
636 return n ? n : -EFAULT;
637 }
638
639 pti_write_to_aperture(mc, kbuf, size);
640 n += size;
641 tmp += size;
642
643 } while (len > n);
644
645 kfree(kbuf);
646 return len;
647}
648
649static const struct tty_operations pti_tty_driver_ops = {
650 .open = pti_tty_driver_open,
651 .close = pti_tty_driver_close,
652 .write = pti_tty_driver_write,
653 .write_room = pti_tty_write_room,
654 .install = pti_tty_install,
655 .cleanup = pti_tty_cleanup
656};
657
658static const struct file_operations pti_char_driver_ops = {
659 .owner = THIS_MODULE,
660 .write = pti_char_write,
661 .open = pti_char_open,
662 .release = pti_char_release,
663};
664
665static struct miscdevice pti_char_driver = {
666 .minor = MISC_DYNAMIC_MINOR,
667 .name = CHARNAME,
668 .fops = &pti_char_driver_ops
669};
670
671
672
673
674
675
676
677
678static void pti_console_write(struct console *c, const char *buf, unsigned len)
679{
680 static struct pti_masterchannel mc = {.master = CONSOLE_ID,
681 .channel = 0};
682
683 mc.channel = pti_console_channel;
684 pti_console_channel = (pti_console_channel + 1) & 0x7f;
685
686 pti_write_full_frame_to_aperture(&mc, buf, len);
687}
688
689
690
691
692
693
694
695
696
697
698
699
700static struct tty_driver *pti_console_device(struct console *c, int *index)
701{
702 *index = c->index;
703 return pti_tty_driver;
704}
705
706
707
708
709
710
711
712
713
714
715static int pti_console_setup(struct console *c, char *opts)
716{
717 pti_console_channel = 0;
718 pti_control_channel = 0;
719 return 0;
720}
721
722
723
724
725
726
727
728
729
730
731
732static struct console pti_console = {
733 .name = TTYNAME,
734 .write = pti_console_write,
735 .device = pti_console_device,
736 .setup = pti_console_setup,
737 .flags = CON_PRINTBUFFER,
738 .index = 0,
739};
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755static int pti_port_activate(struct tty_port *port, struct tty_struct *tty)
756{
757 if (port->tty->index == PTITTY_MINOR_START)
758 console_start(&pti_console);
759 return 0;
760}
761
762
763
764
765
766
767
768
769
770
771
772static void pti_port_shutdown(struct tty_port *port)
773{
774 if (port->tty->index == PTITTY_MINOR_START)
775 console_stop(&pti_console);
776}
777
778static const struct tty_port_operations tty_port_ops = {
779 .activate = pti_port_activate,
780 .shutdown = pti_port_shutdown,
781};
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799static int pti_pci_probe(struct pci_dev *pdev,
800 const struct pci_device_id *ent)
801{
802 unsigned int a;
803 int retval = -EINVAL;
804 int pci_bar = 1;
805
806 dev_dbg(&pdev->dev, "%s %s(%d): PTI PCI ID %04x:%04x\n", __FILE__,
807 __func__, __LINE__, pdev->vendor, pdev->device);
808
809 retval = misc_register(&pti_char_driver);
810 if (retval) {
811 pr_err("%s(%d): CHAR registration failed of pti driver\n",
812 __func__, __LINE__);
813 pr_err("%s(%d): Error value returned: %d\n",
814 __func__, __LINE__, retval);
815 goto err;
816 }
817
818 retval = pci_enable_device(pdev);
819 if (retval != 0) {
820 dev_err(&pdev->dev,
821 "%s: pci_enable_device() returned error %d\n",
822 __func__, retval);
823 goto err_unreg_misc;
824 }
825
826 drv_data = kzalloc(sizeof(*drv_data), GFP_KERNEL);
827 if (drv_data == NULL) {
828 retval = -ENOMEM;
829 dev_err(&pdev->dev,
830 "%s(%d): kmalloc() returned NULL memory.\n",
831 __func__, __LINE__);
832 goto err_disable_pci;
833 }
834 drv_data->pti_addr = pci_resource_start(pdev, pci_bar);
835
836 retval = pci_request_region(pdev, pci_bar, dev_name(&pdev->dev));
837 if (retval != 0) {
838 dev_err(&pdev->dev,
839 "%s(%d): pci_request_region() returned error %d\n",
840 __func__, __LINE__, retval);
841 goto err_free_dd;
842 }
843 drv_data->aperture_base = drv_data->pti_addr+APERTURE_14;
844 drv_data->pti_ioaddr =
845 ioremap_nocache((u32)drv_data->aperture_base,
846 APERTURE_LEN);
847 if (!drv_data->pti_ioaddr) {
848 retval = -ENOMEM;
849 goto err_rel_reg;
850 }
851
852 pci_set_drvdata(pdev, drv_data);
853
854 for (a = 0; a < PTITTY_MINOR_NUM; a++) {
855 struct tty_port *port = &drv_data->port[a];
856 tty_port_init(port);
857 port->ops = &tty_port_ops;
858
859 tty_port_register_device(port, pti_tty_driver, a, &pdev->dev);
860 }
861
862 register_console(&pti_console);
863
864 return 0;
865err_rel_reg:
866 pci_release_region(pdev, pci_bar);
867err_free_dd:
868 kfree(drv_data);
869err_disable_pci:
870 pci_disable_device(pdev);
871err_unreg_misc:
872 misc_deregister(&pti_char_driver);
873err:
874 return retval;
875}
876
877
878
879
880
881
882static void pti_pci_remove(struct pci_dev *pdev)
883{
884 struct pti_dev *drv_data = pci_get_drvdata(pdev);
885 unsigned int a;
886
887 unregister_console(&pti_console);
888
889 for (a = 0; a < PTITTY_MINOR_NUM; a++) {
890 tty_unregister_device(pti_tty_driver, a);
891 tty_port_destroy(&drv_data->port[a]);
892 }
893
894 iounmap(drv_data->pti_ioaddr);
895 kfree(drv_data);
896 pci_release_region(pdev, 1);
897 pci_disable_device(pdev);
898
899 misc_deregister(&pti_char_driver);
900}
901
902static struct pci_driver pti_pci_driver = {
903 .name = PCINAME,
904 .id_table = pci_ids,
905 .probe = pti_pci_probe,
906 .remove = pti_pci_remove,
907};
908
909
910
911
912
913
914
915
916
917
918
919static int __init pti_init(void)
920{
921 int retval = -EINVAL;
922
923
924
925 pti_tty_driver = alloc_tty_driver(PTITTY_MINOR_NUM);
926 if (pti_tty_driver == NULL) {
927 pr_err("%s(%d): Memory allocation failed for ptiTTY driver\n",
928 __func__, __LINE__);
929 return -ENOMEM;
930 }
931
932 pti_tty_driver->driver_name = DRIVERNAME;
933 pti_tty_driver->name = TTYNAME;
934 pti_tty_driver->major = 0;
935 pti_tty_driver->minor_start = PTITTY_MINOR_START;
936 pti_tty_driver->type = TTY_DRIVER_TYPE_SYSTEM;
937 pti_tty_driver->subtype = SYSTEM_TYPE_SYSCONS;
938 pti_tty_driver->flags = TTY_DRIVER_REAL_RAW |
939 TTY_DRIVER_DYNAMIC_DEV;
940 pti_tty_driver->init_termios = tty_std_termios;
941
942 tty_set_operations(pti_tty_driver, &pti_tty_driver_ops);
943
944 retval = tty_register_driver(pti_tty_driver);
945 if (retval) {
946 pr_err("%s(%d): TTY registration failed of pti driver\n",
947 __func__, __LINE__);
948 pr_err("%s(%d): Error value returned: %d\n",
949 __func__, __LINE__, retval);
950
951 goto put_tty;
952 }
953
954 retval = pci_register_driver(&pti_pci_driver);
955 if (retval) {
956 pr_err("%s(%d): PCI registration failed of pti driver\n",
957 __func__, __LINE__);
958 pr_err("%s(%d): Error value returned: %d\n",
959 __func__, __LINE__, retval);
960 goto unreg_tty;
961 }
962
963 return 0;
964unreg_tty:
965 tty_unregister_driver(pti_tty_driver);
966put_tty:
967 put_tty_driver(pti_tty_driver);
968 pti_tty_driver = NULL;
969 return retval;
970}
971
972
973
974
975static void __exit pti_exit(void)
976{
977 tty_unregister_driver(pti_tty_driver);
978 pci_unregister_driver(&pti_pci_driver);
979 put_tty_driver(pti_tty_driver);
980}
981
982module_init(pti_init);
983module_exit(pti_exit);
984
985MODULE_LICENSE("GPL");
986MODULE_AUTHOR("Ken Mills, Jay Freyensee");
987MODULE_DESCRIPTION("PTI Driver");
988
989