-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcandroid.patch
More file actions
2052 lines (1989 loc) · 57.3 KB
/
candroid.patch
File metadata and controls
2052 lines (1989 loc) · 57.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
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
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
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
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
From b90c81f1221a0152816d78e66c4248878cf210b0 Mon Sep 17 00:00:00 2001
From: Janne Grunau <j@jannau.net>
Date: Sat, 20 Jun 2015 20:19:10 +0200
Subject: [PATCH 1/6] flounder: support charging in host mode
Tegra usb phy driver is already prepared to charge the device over the
otg port in host mode.
There seems no way to pass the support_y_cable through the devicetree.
---
arch/arm64/boot/dts/tegra132-flounder-generic.dtsi | 4 ++++
drivers/usb/phy/tegra-otg.c | 2 +-
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/tegra132-flounder-generic.dtsi b/arch/arm64/boot/dts/tegra132-flounder-generic.dtsi
index 2be9991..dc16c6d 100644
--- a/arch/arm64/boot/dts/tegra132-flounder-generic.dtsi
+++ b/arch/arm64/boot/dts/tegra132-flounder-generic.dtsi
@@ -508,6 +508,10 @@
regulator-consumer-supply = "usb_bat_chg";
regulator-consumer-device = "tegra-udc.0";
};
+ c2 {
+ regulator-consumer-supply = "usb_bat_chg";
+ regulator-consumer-device = "tegra-otg";
+ };
};
};
diff --git a/drivers/usb/phy/tegra-otg.c b/drivers/usb/phy/tegra-otg.c
index b668799..d133eee 100644
--- a/drivers/usb/phy/tegra-otg.c
+++ b/drivers/usb/phy/tegra-otg.c
@@ -739,7 +739,7 @@ static int tegra_otg_conf(struct platform_device *pdev)
tegra->turn_off_vbus_on_lp0 =
pdata->ehci_pdata->u_data.host.turn_off_vbus_on_lp0;
tegra->support_y_cable =
- pdata->ehci_pdata->u_data.host.support_y_cable;
+ true;//pdata->ehci_pdata->u_data.host.support_y_cable;
tegra->y_cable_conn = false;
tegra->support_pmu_vbus = pdata->ehci_pdata->support_pmu_vbus;
tegra->id_det_gpio = pdata->id_det_gpio ? pdata->id_det_gpio : -1;
--
2.5.0
From 1a528bb672cb10d9916119b319e37fa5fa914f31 Mon Sep 17 00:00:00 2001
From: Yang Wang <wang701@purdue.edu>
Date: Mon, 26 Oct 2015 19:52:09 -0400
Subject: [PATCH 2/6] enable otg charging and loadable module support
---
arch/arm/mach-tegra/board-flounder.c | 1 +
drivers/hwmon/battery_system_voltage_monitor.c | 4 +-
drivers/power/battery-charger-gauge-comm.c | 2 +-
drivers/usb/phy/tegra-otg.c | 59 +++++++++++++++++++++++---
4 files changed, 57 insertions(+), 9 deletions(-)
diff --git a/arch/arm/mach-tegra/board-flounder.c b/arch/arm/mach-tegra/board-flounder.c
index 574f15a..7b837ba 100644
--- a/arch/arm/mach-tegra/board-flounder.c
+++ b/arch/arm/mach-tegra/board-flounder.c
@@ -779,6 +779,7 @@ static struct tegra_usb_platform_data tegra_ehci1_utmi_pdata = {
.hot_plug = false,
.remote_wakeup_supported = true,
.power_off_on_suspend = true,
+ .support_y_cable = true,
},
.u_cfg.utmi = {
.hssync_start_delay = 0,
diff --git a/drivers/hwmon/battery_system_voltage_monitor.c b/drivers/hwmon/battery_system_voltage_monitor.c
index 679faf9..c9bcd8d 100644
--- a/drivers/hwmon/battery_system_voltage_monitor.c
+++ b/drivers/hwmon/battery_system_voltage_monitor.c
@@ -148,7 +148,7 @@ int battery_voltage_monitor_on_once(unsigned int voltage)
{
return __voltage_monitor_on_once(true, voltage);
}
-EXPORT_SYMBOL_GPL(battery_voltage_monitor_on);
+EXPORT_SYMBOL_GPL(battery_voltage_monitor_on_once);
int battery_voltage_monitor_off(void)
{
@@ -180,7 +180,7 @@ int system_voltage_monitor_on_once(unsigned int voltage)
{
return __voltage_monitor_on_once(false, voltage);
}
-EXPORT_SYMBOL_GPL(system_voltage_monitor_on);
+EXPORT_SYMBOL_GPL(system_voltage_monitor_on_once);
int system_voltage_monitor_off(void)
{
diff --git a/drivers/power/battery-charger-gauge-comm.c b/drivers/power/battery-charger-gauge-comm.c
index 2f73dd0..93e290a 100644
--- a/drivers/power/battery-charger-gauge-comm.c
+++ b/drivers/power/battery-charger-gauge-comm.c
@@ -646,7 +646,7 @@ int battery_charger_batt_status_force_check(
mutex_unlock(&bc_dev->mutex);
return 0;
}
-EXPORT_SYMBOL_GPL(battery_charger_batt_status_monitor_force_check);
+EXPORT_SYMBOL_GPL(battery_charger_batt_status_force_check);
int battery_charger_get_batt_status_no_update_time_ms(
struct battery_charger_dev *bc_dev, s64 *time)
diff --git a/drivers/usb/phy/tegra-otg.c b/drivers/usb/phy/tegra-otg.c
index d133eee..fbd35ef 100644
--- a/drivers/usb/phy/tegra-otg.c
+++ b/drivers/usb/phy/tegra-otg.c
@@ -60,7 +60,7 @@
#define DBG(stuff...) do {} while (0)
#endif
-#define YCABLE_CHARGING_CURRENT_UA 500000u
+#define YCABLE_CHARGING_CURRENT_UA 1500000u
struct tegra_otg {
struct platform_device *pdev;
@@ -153,6 +153,8 @@ static int otg_notifications(struct notifier_block *nb,
spin_unlock_irqrestore(&tegra->lock, flags);
DBG("%s(%d) tegra->int_status = 0x%lx\n", __func__,
__LINE__, tegra->int_status);
+ pr_info("%s(%d) tegra->int_status=%lx\n", __func__,
+ __LINE__, tegra->int_status);
if (!tegra->suspended)
schedule_work(&tegra->work);
@@ -273,10 +275,14 @@ static void tegra_otg_vbus_enable(struct regulator *vbus_reg, int on)
if (vbus_reg == NULL)
return ;
- if (on && vbus_enable && !regulator_enable(vbus_reg))
+ if (on && vbus_enable && !regulator_enable(vbus_reg)) {
vbus_enable = 0;
- else if (!on && !vbus_enable && !regulator_disable(vbus_reg))
+ pr_info("%s(%d) vbus_enable=0\n", __func__, __LINE__);
+ }
+ else if (!on && !vbus_enable && !regulator_disable(vbus_reg)) {
vbus_enable = 1;
+ pr_info("%s(%d) vbus_enable=1\n", __func__, __LINE__);
+ }
}
static void tegra_start_host(struct tegra_otg *tegra)
@@ -357,9 +363,17 @@ static void tegra_otg_notify_event(struct tegra_otg *tegra, int event)
static int tegra_otg_start_host(struct tegra_otg *tegra, int on)
{
+ pr_info("%s(%d) support_y_cable=%d, int_status=%lx, USB_VBUS_STATUS=%d\n",
+ __func__, __LINE__, tegra->support_y_cable, tegra->int_status,
+ USB_VBUS_STATUS);
+
if (on) {
+ pr_info("%s(%d) on=%d\n", __func__, __LINE__, on);
if (tegra->support_y_cable &&
(tegra->int_status & USB_VBUS_STATUS)) {
+ pr_info("%s(%d) set current %dmA\n", __func__, __LINE__,
+ YCABLE_CHARGING_CURRENT_UA/1000);
+
DBG("%s(%d) set current %dmA\n", __func__, __LINE__,
YCABLE_CHARGING_CURRENT_UA/1000);
tegra_otg_set_current(tegra->vbus_bat_reg,
@@ -372,6 +386,7 @@ static int tegra_otg_start_host(struct tegra_otg *tegra, int on)
tegra_start_host(tegra);
tegra_otg_notify_event(tegra, USB_EVENT_ID);
} else {
+ pr_info("%s(%d) stop host now\n", __func__, __LINE__);
tegra_stop_host(tegra);
tegra_otg_notify_event(tegra, USB_EVENT_NONE);
tegra_otg_vbus_enable(tegra->vbus_reg, 0);
@@ -407,12 +422,16 @@ static void tegra_change_otg_state(struct tegra_otg *tegra,
return;
}
+ pr_info("%s(%d) requested otg state %s-->%s\n", __func__,
+ __LINE__, tegra_state_name(from), tegra_state_name(to));
+
DBG("%s(%d) requested otg state %s-->%s\n", __func__,
__LINE__, tegra_state_name(from), tegra_state_name(to));
if (to != OTG_STATE_UNDEFINED && from != to) {
otg->phy->state = to;
- pr_info("otg state changed: %s --> %s\n", tegra_state_name(from), tegra_state_name(to));
+ pr_info("%s(%d) otg state changed: %s --> %s\n", __func__, __LINE__,
+ tegra_state_name(from), tegra_state_name(to));
if (from == OTG_STATE_A_SUSPEND) {
if (to == OTG_STATE_B_PERIPHERAL && otg->gadget)
@@ -427,8 +446,12 @@ static void tegra_change_otg_state(struct tegra_otg *tegra,
}
if (tegra->support_y_cable && tegra->y_cable_conn &&
- from == to && from == OTG_STATE_A_HOST) {
+ from == to && from == OTG_STATE_A_HOST) {
+ pr_info("%s(%d) support_y_cable=%d, y_cable_conn=%d\n", __func__, __LINE__,
+ tegra->support_y_cable, tegra->y_cable_conn);
if (!(tegra->int_status & USB_VBUS_STATUS)) {
+ pr_info("%s(%d) tegra->int_status = 0x%lx\n", __func__,
+ __LINE__, tegra->int_status);
DBG("%s(%d) Charger disconnect\n", __func__, __LINE__);
tegra_otg_set_current(tegra->vbus_bat_reg, 0);
tegra_otg_vbus_enable(tegra->vbus_reg, 1);
@@ -457,6 +480,8 @@ static void irq_work(struct work_struct *work)
from = otg->phy->state;
status = tegra->int_status;
+ pr_info("%s(%d) from=%s\n", __func__, __LINE__, tegra_state_name(from));
+
/* Debug prints */
DBG("%s(%d) status = 0x%lx\n", __func__, __LINE__, status);
if ((status & USB_ID_INT_STATUS) &&
@@ -468,6 +493,9 @@ static void irq_work(struct work_struct *work)
if (status & USB_VBUS_INT_STATUS)
DBG("%s(%d) got vbus interrupt\n", __func__, __LINE__);
}
+
+ pr_info("%s(%d) status=%lx USB_ID_STATUS=%d USB_ID_INT_EN=%d\n",
+ __func__, __LINE__, status, USB_ID_STATUS, USB_ID_INT_EN);
if (!(status & USB_ID_STATUS) && (status & USB_ID_INT_EN))
to = OTG_STATE_A_HOST;
@@ -476,6 +504,20 @@ static void irq_work(struct work_struct *work)
else
to = OTG_STATE_A_SUSPEND;
+
+ // if (!(status & USB_ID_STATUS) && (status & USB_ID_INT_EN)){
+ // to = OTG_STATE_A_HOST;
+ // }
+ // else if (status & USB_VBUS_STATUS && from != OTG_STATE_A_HOST) {
+ // to = OTG_STATE_B_PERIPHERAL;
+ // if (from == OTG_STATE_A_SUSPEND) {
+ // to = OTG_STATE_A_HOST;
+ // }
+ // }
+ // else {
+ // to = OTG_STATE_A_SUSPEND;
+ // }
+
spin_unlock_irqrestore(&tegra->lock, flags);
tegra_change_otg_state(tegra, to);
mutex_unlock(&tegra->irq_work_mutex);
@@ -495,10 +537,12 @@ static irqreturn_t tegra_otg_irq(int irq, void *data)
if (val & (USB_VBUS_INT_EN | USB_ID_INT_EN)) {
DBG("%s(%d) PHY_WAKEUP = 0x%lx\n", __func__, __LINE__, val);
+ pr_info("%s(%d) PHY_WAKEUP = 0x%lx\n", __func__, __LINE__, val);
otg_writel(tegra, val, USB_PHY_WAKEUP);
if ((val & USB_ID_INT_STATUS) || (val & USB_VBUS_INT_STATUS)) {
tegra->int_status &= ~tegra->int_mask;
tegra->int_status |= val & tegra->int_mask;
+ pr_info("%s(%d) tegra->int_status=%lx\n", __func__, __LINE__, tegra->int_status);
schedule_work(&tegra->work);
}
}
@@ -543,6 +587,7 @@ static int tegra_otg_set_peripheral(struct usb_otg *otg,
if ((val & USB_ID_INT_STATUS) || (val & USB_VBUS_INT_STATUS)) {
tegra->int_status = val;
+ pr_info("%s(%d) tegra->int_status=%lx\n", __func__, __LINE__, tegra->int_status);
schedule_work(&tegra->work);
}
@@ -739,7 +784,7 @@ static int tegra_otg_conf(struct platform_device *pdev)
tegra->turn_off_vbus_on_lp0 =
pdata->ehci_pdata->u_data.host.turn_off_vbus_on_lp0;
tegra->support_y_cable =
- true;//pdata->ehci_pdata->u_data.host.support_y_cable;
+ pdata->ehci_pdata->u_data.host.support_y_cable;
tegra->y_cable_conn = false;
tegra->support_pmu_vbus = pdata->ehci_pdata->support_pmu_vbus;
tegra->id_det_gpio = pdata->id_det_gpio ? pdata->id_det_gpio : -1;
@@ -878,6 +923,7 @@ static int tegra_otg_start(struct platform_device *pdev)
}
if (tegra->support_y_cable) {
+ pr_info("%s(%d) support_y_cable=1\n", __func__, __LINE__);
tegra->vbus_bat_reg = regulator_get(&pdev->dev, "usb_bat_chg");
if (IS_ERR_OR_NULL(tegra->vbus_bat_reg)) {
pr_err("failed to get regulator usb_bat_chg: %ld\n",
@@ -1104,6 +1150,7 @@ static void tegra_otg_resume(struct device *dev)
if (!tegra->support_pmu_vbus)
val |= USB_VBUS_INT_EN | USB_VBUS_WAKEUP_EN;
tegra->int_status = val;
+ pr_info("%s(%d) tegra->int_status=%lx\n", __func__, __LINE__, tegra->int_status);
spin_unlock_irqrestore(&tegra->lock, flags);
}
--
2.5.0
From fe67623ba805aeaabb2b529116f96b8922bae2c0 Mon Sep 17 00:00:00 2001
From: Yang Wang <wang701@purdue.edu>
Date: Mon, 26 Oct 2015 22:49:08 -0400
Subject: [PATCH 3/6] patch can header for isobus
---
include/uapi/linux/can.h | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/include/uapi/linux/can.h b/include/uapi/linux/can.h
index e52958d..00c489a 100644
--- a/include/uapi/linux/can.h
+++ b/include/uapi/linux/can.h
@@ -118,10 +118,13 @@ struct canfd_frame {
#define CAN_TP20 4 /* VAG Transport Protocol v2.0 */
#define CAN_MCNET 5 /* Bosch MCNet */
#define CAN_ISOTP 6 /* ISO 15765-2 Transport Protocol */
-#define CAN_NPROTO 7
+#define CAN_ISOBUS 7 /* ISO 11783 Messages (ISOBUS) */
+#define CAN_NPROTO 8
#define SOL_CAN_BASE 100
+typedef unsigned short __kernel_sa_family_t;
+
/**
* struct sockaddr_can - the sockaddr structure for CAN sockets
* @can_family: address family number AF_CAN.
@@ -135,6 +138,8 @@ struct sockaddr_can {
/* transport protocol class address information (e.g. ISOTP) */
struct { canid_t rx_id, tx_id; } tp;
+ struct { __u8 addr; } isobus;
+
/* reserved for future CAN protocols address information */
} can_addr;
};
--
2.5.0
From 51b9dff64c89061b237c62c67e2611acef108473 Mon Sep 17 00:00:00 2001
From: Yang Wang <wang701@purdue.edu>
Date: Tue, 27 Oct 2015 22:45:00 -0400
Subject: [PATCH 4/6] add isobus protocol for kernel build
---
net/can/Kconfig | 8 +
net/can/Makefile | 3 +
net/can/isobus.c | 1421 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
net/can/isobus.h | 97 ++++
4 files changed, 1529 insertions(+)
create mode 100644 net/can/isobus.c
create mode 100644 net/can/isobus.h
diff --git a/net/can/Kconfig b/net/can/Kconfig
index a15c0e0..1ea596d 100644
--- a/net/can/Kconfig
+++ b/net/can/Kconfig
@@ -51,6 +51,14 @@ config CAN_GW
They can be modified with AND/OR/XOR/SET operations as configured
by the netlink configuration interface known e.g. from iptables.
+config CAN_ISOBUS
+ tristate "ISOBUS sockets for protocol family CAN"
+ default y
+ ---help---
+ ISO 11783 (commonly referred to as "ISO Bus" or "ISOBUS") is a
+ communication protocol for the agriculture industry based on the
+ SAE J1939 protocol (which includes CANbus).
+
source "drivers/net/can/Kconfig"
endif
diff --git a/net/can/Makefile b/net/can/Makefile
index cef49eb..7d78d75 100644
--- a/net/can/Makefile
+++ b/net/can/Makefile
@@ -13,3 +13,6 @@ can-bcm-y := bcm.o
obj-$(CONFIG_CAN_GW) += can-gw.o
can-gw-y := gw.o
+
+obj-$(CONFIG_CAN_ISOBUS) += can-isobus.o
+can-isobus-y := isobus.o
diff --git a/net/can/isobus.c b/net/can/isobus.c
new file mode 100644
index 0000000..51da08e
--- /dev/null
+++ b/net/can/isobus.c
@@ -0,0 +1,1421 @@
+/*
+ * isobus.c - ISOBUS sockets for protocol family CAN
+ *
+ * Copyright (c) 2002-2007 Volkswagen Group Electronic Research
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Volkswagen nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * Alternatively, provided that this notice is retained in full, this
+ * software may be distributed under the terms of the GNU General
+ * Public License ("GPL") version 2, in which case the provisions of the
+ * GPL apply INSTEAD OF those given above.
+ *
+ * The provided data structures and external interfaces from this code
+ * are not restricted to be used by modules with a GPL compatible license.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/hrtimer.h>
+#include <linux/wait.h>
+#include <linux/uio.h>
+#include <linux/net.h>
+#include <linux/slab.h>
+#include <linux/netdevice.h>
+#include <linux/socket.h>
+#include <linux/if_arp.h>
+#include <linux/skbuff.h>
+/* #include "patched/can.h" */
+#include <uapi/linux/can.h>
+#include <linux/can/core.h>
+#include "isobus.h" /* #include <linux/can/isobus.h> */
+#include <net/sock.h>
+#include <net/net_namespace.h>
+
+#define ISOBUS_VERSION CAN_VERSION
+static __initconst const char banner[] =
+ KERN_INFO "can: isobus protocol (rev " ISOBUS_VERSION ")\n";
+
+MODULE_DESCRIPTION("PF_CAN isobus 11783 protocol");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_AUTHOR("Alex Layton <alex@layton.in>, "
+ "Urs Thuermann <urs.thuermann@volkswagen.de>, "
+ "Oliver Hartkopp <oliver.hartkopp@volkswagen.de>");
+MODULE_ALIAS("can-proto-" __stringify(CAN_ISOBUS));
+#ifdef BUILD_NUM
+ MODULE_INFO(build, BUILD_NUM);
+#endif
+
+#define ISOBUS_MIN_SC_ADDR 128U
+#define ISOBUS_MAX_SC_ADDR 247U
+
+/* Macros for going between CAN IDs and PDU/PGN fields */
+#define ISOBUS_PRI_POS 26
+#define ISOBUS_PRI_MASK 0x07U
+#define ISOBUS_PGN_POS 8
+#define ISOBUS_PGN_MASK 0x03FFFFLU
+#define ISOBUS_PGN1_MASK 0x03FF00LU
+#define ISOBUS_PS_POS 8
+#define ISOBUS_PS_MASK 0xFFU
+#define ISOBUS_PF_POS 16
+#define ISOBUS_PF_MASK 0xFFU
+#define ISOBUS_SA_POS 0
+#define ISOBUS_SA_MASK 0xFFU
+#define ISOBUS_DP_POS 24
+#define ISOBUS_DP_MASK 0x01U
+#define ISOBUS_EDP_POS 25
+#define ISOBUS_EDP_MASK 0x01U
+#define CANID(pri, pgn, da, sa) ( \
+ CAN_EFF_FLAG | \
+ ((pri & ISOBUS_PRI_MASK) << ISOBUS_PRI_POS) | \
+ ((pgn & ISOBUS_PGN_MASK) << ISOBUS_PGN_POS) | \
+ ((da & ISOBUS_PS_MASK) << ISOBUS_PS_POS) | \
+ ((sa & ISOBUS_SA_MASK) << ISOBUS_SA_POS) )
+#define ID_FIELD(id, field) \
+ ((id >> ISOBUS_ ## field ## _POS) & ISOBUS_ ## field ## _MASK)
+#define PGN_FIELD(pgn, field) ID_FIELD(pgn << ISOBUS_PGN_POS, field)
+#define ISOBUS_MIN_PDU2 240
+#define ID_PDU_FMT(id) (ID_FIELD(id, PF) < ISOBUS_MIN_PDU2 ? 1 : 2)
+#define PGN_PDU_FMT(pgn) ID_PDU_FMT(pgn << ISOBUS_PGN_POS)
+
+/* Stuff for NAME fields */
+#define ISOBUS_NAME_ID_MASK 0x00000000001FFFFFLU
+#define ISOBUS_NAME_ID_POS 0
+#define ISOBUS_NAME_MAN_MASK 0x00000000FFE00000LU
+#define ISOBUS_NAME_MAN_POS 21
+#define ISOBUS_NAME_ECU_MASK 0x0000000700000000LU
+#define ISOBUS_NAME_ECU_POS 32
+#define ISOBUS_NAME_FINST_MASK 0x000000F800000000LU
+#define ISOBUS_NAME_FINST_POS 35
+#define ISOBUS_NAME_FUNC_MASK 0x0000FF0000000000LU
+#define ISOBUS_NAME_FUNC_POS 40
+#define ISOBUS_NAME_CLASS_MASK 0x00FE000000000000LU
+#define ISOBUS_NAME_CLASS_POS 49
+#define ISOBUS_NAME_CINST_MASK 0x0F00000000000000LU
+#define ISOBUS_NAME_CINST_POS 56
+#define ISOBUS_NAME_IG_MASK 0x7000000000000000LU
+#define ISOBUS_NAME_IG_POS 60
+
+/* Timeouts etc. (100's on ns) */
+#define ISOBUS_ADDR_CLAIM_TIMEOUT 2500L
+#define ISOBUS_RTXD_MULTIPLIER 6L
+
+/* Priority stuff */
+#define MIN_PRI 0
+#define MAX_PRI 7
+#define ISOBUS_PRIO(p) \
+ (MAX_PRI - ((p < MIN_PRI ? MIN_PRI : p) > MAX_PRI ? MAX_PRI : p) + MIN_PRI)
+#define SK_PRIO(p) (MAX_PRI - p + MIN_PRI)
+
+/*
+ * A isobus socket has a list of can_filters attached to it, each receiving
+ * the CAN frames matching that filter. If the filter list is empty,
+ * no CAN frames will be received by the socket. The default after
+ * opening the socket, is to have one filter which receives all frames.
+ * The filter list is allocated dynamically with the exception of the
+ * list containing only one item. This common case is optimized by
+ * storing the single filter in dfilter, to avoid using dynamic memory.
+ */
+struct isobus_sock {
+ struct sock sk;
+ bool bound;
+ int ifindex;
+ struct notifier_block notifier;
+ int loopback;
+ int recv_own_msgs;
+ int daddr_opt;
+ int count; /* number of active filters */
+ struct can_filter dfilter; /* default/single filter */
+ struct can_filter *filter; /* pointer to filter(s) */
+ can_err_mask_t err_mask;
+
+ __u8 pref_addr;
+ __u8 s_addr;
+ name_t name;
+ enum {
+ ISOBUS_IDLE = 0,
+ ISOBUS_WAIT_ADDR,
+ ISOBUS_WAIT_HAVE_ADDR,
+ ISOBUS_HAVE_ADDR,
+ ISOBUS_LOST_ADDR,
+ } state;
+ wait_queue_head_t wait;
+
+ bool sc_addrs[ISOBUS_MAX_SC_ADDR - ISOBUS_MIN_SC_ADDR + 1];
+ bool pref_avail;
+};
+
+/* Netowrk management messages */
+static const struct isobus_mesg req_addr_claimed_mesg = {
+ ISOBUS_PGN_REQUEST,
+ 3,
+ {(ISOBUS_PGN_ADDR_CLAIMED >> 16) & 0xFF,
+ (ISOBUS_PGN_ADDR_CLAIMED >> 8) & 0xFF,
+ ISOBUS_PGN_ADDR_CLAIMED & 0xFF},
+};
+static const struct isobus_mesg addr_claimed_mesg = {
+ ISOBUS_PGN_ADDR_CLAIMED,
+ 8,
+ {0, 0, 0, 0, 0, 0, 0, 0},
+};
+
+/*
+ * Return pointer to store the extra msg flags for isobus_recvmsg().
+ * We use the space of one unsigned int beyond the 'struct sockaddr_can'
+ * in skb->cb.
+ */
+static inline unsigned int *isobus_flags(struct sk_buff *skb)
+{
+ BUILD_BUG_ON(sizeof(skb->cb) <= (sizeof(struct sockaddr_can) +
+ sizeof(unsigned int)));
+
+ /* return pointer after struct sockaddr_can */
+ return (unsigned int *)(&((struct sockaddr_can *)skb->cb)[1]);
+}
+
+static inline struct isobus_sock *isobus_sk(const struct sock *sk)
+{
+ return (struct isobus_sock *)sk;
+}
+
+/* Genereates a random transmit delay (in 100's of ns) */
+static inline long isobus_rtxd(void)
+{
+ long l;
+
+ l = 0;
+ get_random_bytes(&l, 1);
+
+ return l * ISOBUS_RTXD_MULTIPLIER;
+}
+
+/* Determine the PGN of a CAN frame */
+static inline pgn_t get_pgn(canid_t id)
+{
+ pgn_t pgn;
+
+ /* PDU1 format */
+ if(ID_PDU_FMT(id) == 1) {
+ pgn = (id >> ISOBUS_PGN_POS) & ISOBUS_PGN1_MASK;
+ }
+ /* PDU2 format */
+ else {
+ pgn = (id >> ISOBUS_PGN_POS) & ISOBUS_PGN_MASK;
+ }
+
+ return pgn;
+}
+
+/* Called when a CAN frame is received */
+/* TODO: Add support for connections */
+static void isobus_rcv(struct sk_buff *oskb, void *data)
+{
+ struct sock *sk = (struct sock *)data;
+ struct isobus_sock *ro = isobus_sk(sk);
+ struct sockaddr_can *addr;
+ struct sk_buff *skb;
+ unsigned int *pflags;
+
+ struct can_frame *cf;
+ struct isobus_mesg *mesg;
+
+ /* check the received tx sock reference */
+ if (!ro->recv_own_msgs && oskb->sk == sk) {
+ return;
+ }
+
+ /* set pointer to received CAN frame */
+ cf = (struct can_frame *) oskb->data;
+
+ /* do not pass frames with DLC > 8 */
+ if (unlikely(cf->can_dlc > CAN_MAX_DLEN)) {
+ return;
+ }
+
+ /* Check for invalid PGNs */
+ if (unlikely(ID_FIELD(cf->can_id, EDP))) {
+ if (likely(ID_FIELD(cf->can_id, DP))) {
+ /*
+ * Check for ISO 15765-3 PGNs which can coexist with ISO 11783 PGNs
+ * but have a different format for the CAN identifier.
+ * TODO: Tell SocketCAN to filter these frames out for this module.
+ */
+ printk(KERN_NOTICE "can_isobus: ISO 15765-3 PGN encountered\n");
+ } else {
+ /*
+ * Check for ISO 11783 reserved PGNs which do not yet have a
+ * defined stucture, so nothing can be done with them yet.
+ * TODO: Tell SocketCAN to filter these frames out for this module.
+ */
+ printk(KERN_NOTICE "can_isobus: ISO 11783 reserved PGN encountered\n");
+ }
+ return;
+ }
+
+ /* Create skb to put ISOBUS message in */
+ skb = alloc_skb(sizeof(*mesg), gfp_any());
+ if (!skb) {
+ return;
+ }
+ skb->tstamp = oskb->tstamp;
+ skb->dev = oskb->dev;
+
+ /* Copy ISOBUS message into the skb */
+ mesg = (struct isobus_mesg *)skb_put(skb, sizeof(struct isobus_mesg));
+ if(!mesg) {
+ return;
+ }
+ mesg->pgn = get_pgn(cf->can_id);
+ mesg->dlen = cf->can_dlc;
+ memcpy(mesg->data, cf->data, mesg->dlen);
+
+ /*
+ * Put the datagram to the queue so that isobus_recvmsg() can
+ * get it from there. We need to pass the interface index to
+ * isobus_recvmsg(). We pass a whole struct sockaddr_can in skb->cb
+ * containing the interface index.
+ */
+
+ BUILD_BUG_ON(sizeof(skb->cb) < (2 * sizeof(struct sockaddr_can)));
+ addr = (struct sockaddr_can *)skb->cb;
+ memset(addr, 0, 2 * sizeof(*addr));
+ addr[0].can_family = AF_CAN;
+ addr[0].can_ifindex = skb->dev->ifindex;
+ addr[0].can_addr.isobus.addr = ID_FIELD(cf->can_id, SA);
+ addr[1].can_family = AF_CAN;
+ addr[1].can_ifindex = skb->dev->ifindex;
+ addr[1].can_addr.isobus.addr = ID_FIELD(cf->can_id, PS);
+
+ /* add CAN specific message flags for isobus_recvmsg() */
+ pflags = isobus_flags(skb);
+ *pflags = 0;
+ if (oskb->sk)
+ *pflags |= MSG_DONTROUTE;
+ if (oskb->sk == sk)
+ *pflags |= MSG_CONFIRM;
+
+ if (sock_queue_rcv_skb(sk, skb) < 0)
+ kfree_skb(skb);
+}
+
+/* Called when userland sends */
+/* TODO: Implement sending more than 8 bytes */
+static int isobus_sendmsg(struct kiocb *iocb, struct socket *sock,
+ struct msghdr *msg, size_t size)
+{
+ struct sock *sk = sock->sk;
+ struct isobus_sock *ro = isobus_sk(sk);
+ struct sk_buff *skb;
+ struct net_device *dev;
+ int ifindex;
+ int err;
+ struct isobus_mesg *mesg;
+ struct sockaddr_can *addr;
+ struct can_frame *cf;
+ __u8 da;
+
+ /* Check for being kicked off the bus */
+ if(ro->state != ISOBUS_HAVE_ADDR)
+ return -EADDRINUSE;
+
+ /* Find pointer to ISOBUS message to be sent */
+ mesg = (struct isobus_mesg *)msg->msg_iov->iov_base;
+
+ /*
+ * Get interface to send on and address to send to.
+ *
+ * If the socket was bound to a particular interface use that one,
+ * otherwise check for one passed in the message name.
+ *
+ * Get directed address if one was passed in.
+ */
+ ifindex = ro->ifindex;
+ da = 0;
+ addr = (struct sockaddr_can *)msg->msg_name;
+ if(addr) {
+ /* Only PDU 1 format should have a DA */
+ if(PGN_PDU_FMT(mesg->pgn) == 1) {
+ /* TODO: Resolve address from NAME */
+ da = addr->can_addr.isobus.addr;
+ }
+
+ if (!ro->ifindex) {
+ if (msg->msg_namelen < sizeof(*addr)) {
+ printk(KERN_ERR "can_isobus: address wrong size\n");
+ return -EINVAL;
+ }
+
+ if (addr->can_family != AF_CAN) {
+ printk(KERN_ERR "can_isobus: address not CAN address family\n");
+ return -EINVAL;
+ }
+
+ ifindex = addr->can_ifindex;
+ }
+ } else if(PGN_PDU_FMT(mesg->pgn) == 1) {
+ /* PDU 1 format needs a DA */
+ printk(KERN_ERR "can_isobus: no address given for PDU 1 PGN\n");
+ return -EINVAL;
+ }
+
+ if (unlikely(size != CAN_MTU))
+ return -EINVAL;
+
+ dev = dev_get_by_index(&init_net, ifindex);
+ if (!dev)
+ return -ENXIO;
+
+ /* Allocate an skb which will hold a can frame */
+ skb = sock_alloc_send_skb(sk, sizeof(*cf), msg->msg_flags & MSG_DONTWAIT,
+ &err);
+ if (!skb)
+ goto put_dev;
+
+ /* Place CAN frame in skbuff */
+ cf = (struct can_frame *)skb_put(skb, sizeof(struct can_frame));
+ if(!cf) {
+ goto free_skb;
+ }
+ /* Fill out CAN frame with ISOBUS message */
+ cf->can_id = CANID(ISOBUS_PRIO(sk->sk_priority), mesg->pgn, da, ro->s_addr);
+ memcpy(cf->data, mesg->data, cf->can_dlc = mesg->dlen);
+
+ sock_tx_timestamp(sk, &skb_shinfo(skb)->tx_flags);
+
+ skb->dev = dev;
+ skb->sk = sk;
+
+ err = can_send(skb, ro->loopback);
+
+ dev_put(dev);
+ if (err)
+ goto send_failed;
+
+ return size;
+
+free_skb:
+ kfree_skb(skb);
+put_dev:
+ dev_put(dev);
+send_failed:
+ return err;
+}
+
+/*
+ * Send an ISOBUS message (for use within this module)
+ */
+static int isobus_send(struct isobus_sock *ro, struct isobus_mesg *mesg,
+ __u8 addr)
+{
+ int err;
+ struct net_device *dev;
+ struct sk_buff *skb;
+ struct can_frame *cf;
+
+ dev = dev_get_by_index(&init_net, ro->ifindex);
+ if (!dev)
+ return -ENXIO;
+
+ skb = alloc_skb(sizeof(struct can_frame), gfp_any());
+ if(!skb) {
+ goto put_dev;
+ }
+
+ skb->dev = dev_get_by_index(&init_net, ro->ifindex);
+ if(!skb->dev) {
+ goto free_skb;
+ }
+
+ skb->sk = &ro->sk;
+
+ cf = (struct can_frame *)skb_put(skb, sizeof(*cf));
+ if(!cf) {
+ goto free_skb;
+ }
+
+ /* Fill out CAN frame with ISOBUS message */
+ cf->can_id = CANID(ISOBUS_PRIO(ro->sk.sk_priority), mesg->pgn,
+ addr, ro->s_addr);
+ memcpy(cf->data, mesg->data, cf->can_dlc = mesg->dlen);
+
+ err = can_send(skb, 1);
+
+ dev_put(dev);
+
+ return err;
+
+free_skb:
+ kfree_skb(skb);
+put_dev:
+ dev_put(dev);
+ return -1;
+}
+
+/* TODO: Check if this is really portable */
+#define DATA2NAME(data) le64_to_cpup((uint64_t *) data)
+#define NAME2DATA(name) cpu_to_le64((uint64_t) name)
+
+static inline int isobus_send_addr_claimed(struct isobus_sock *ro)
+{
+ struct isobus_mesg mesg;
+ int ret;
+
+ mesg = addr_claimed_mesg;
+ *(uint64_t *)mesg.data = NAME2DATA(ro->name);
+ ret = isobus_send(ro, &mesg, ISOBUS_GLOBAL_ADDR);
+
+ if(ro->s_addr == ISOBUS_NULL_ADDR)
+ printk(KERN_DEBUG "can_isobus:%p cannot claim address sent\n", ro);
+ else
+ printk(KERN_DEBUG "can_isobus:%p address claimed sent\n", ro);
+
+ return ret;
+}
+
+static inline void isobus_lose_addr(struct isobus_sock *ro)
+{
+ ro->bound = false;
+ ro->s_addr = ISOBUS_NULL_ADDR;
+ ro->state = ISOBUS_LOST_ADDR;
+
+ isobus_send_addr_claimed(ro);
+
+ wake_up_interruptible(&ro->wait);
+}
+
+/* Function for network management to process address claimed messages */
+static void isobus_addr_claimed_handler(struct sk_buff *skb, void *data)
+{
+ struct sock *sk = (struct sock *)data;
+ struct isobus_sock *ro = isobus_sk(sk);
+ struct can_frame *cf;
+ __u8 sa;
+
+ /* check the received tx sock reference */
+ if (skb->sk == sk) {
+ return;
+ }
+
+ printk(KERN_DEBUG "can_isobus:%p address claimed seen\n", ro);
+
+ /* set pointer to received CAN frame */
+ cf = (struct can_frame *) skb->data;
+
+ /* Get source address of message */
+ sa = ID_FIELD(cf->can_id, SA);
+
+ /* No action for cannot claim address messages */
+ if(sa == ISOBUS_NULL_ADDR)
+ return;
+
+ if(ro->state == ISOBUS_WAIT_ADDR) {
+ /* Record occupied addresses in the self-configurable range */
+ if(sa <= ISOBUS_MAX_SC_ADDR && sa >= ISOBUS_MIN_SC_ADDR) {
+ ro->sc_addrs[sa - ISOBUS_MIN_SC_ADDR] = false;
+ }
+
+ /* Determine whether or not preferred address is available */
+ if(sa == ro->pref_addr) {
+ if(ro->name < DATA2NAME(cf->data)) {
+ ro->state = ISOBUS_WAIT_HAVE_ADDR;
+ wake_up_interruptible(&ro->wait);
+ } else {
+ ro->pref_avail = false;
+ if(!(ro->name & ISOBUS_NAME_SC_BIT))
+ isobus_lose_addr(ro);
+ }
+ }
+ } else {
+ /* Determine if address must be given up */
+ if(sa == ro->s_addr) {
+ if(ro->name <= DATA2NAME(cf->data))
+ isobus_send_addr_claimed(ro);
+ else
+ isobus_lose_addr(ro);
+ }
+ }
+}
+
+/*
+ * Function for network management to process request for address claimed
+ * messages
+ */
+static void isobus_req_addr_claimed_handler(struct sk_buff *skb, void *data)
+{
+ struct sock *sk = (struct sock *)data;
+ struct isobus_sock *ro = isobus_sk(sk);
+ struct can_frame *cf;
+
+ /* check the received tx sock reference */
+ if (ro->state == ISOBUS_WAIT_ADDR && skb->sk == sk) {
+ return;
+ }
+
+ /* set pointer to received CAN frame */
+ cf = (struct can_frame *) skb->data;
+
+ /* Discard request for things besides address claimed */
+ if(cf->can_dlc != 3 || cf->data[0] != req_addr_claimed_mesg.data[0] ||
+ cf->data[1] != req_addr_claimed_mesg.data[1] ||
+ cf->data[2] != req_addr_claimed_mesg.data[2]) {
+ return;
+ }
+
+ /* Check if claimed address is mine */
+ /* TODO: Should this check be done with filters? */
+ if(ID_FIELD(cf->can_id, PS) == ro->s_addr ||
+ ID_FIELD(cf->can_id, PS) == ISOBUS_GLOBAL_ADDR) {
+ printk(KERN_DEBUG "can_isobus:%p request for address claimed seen\n",
+ ro);
+ isobus_send_addr_claimed(ro);
+ }
+}
+
+static int isobus_enable_filters(struct net_device *dev, struct sock *sk,
+ struct can_filter *filter, int count)
+{
+ int err = 0;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ err = can_rx_register(dev, filter[i].can_id,
+ filter[i].can_mask,
+ isobus_rcv, sk, "isobus");
+ if (err) {
+ /* clean up successfully registered filters */
+ while (--i >= 0)
+ can_rx_unregister(dev, filter[i].can_id,
+ filter[i].can_mask,
+ isobus_rcv, sk);
+ break;
+ }