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