18
18
#include <linux/overflow.h>
19
19
#include <linux/printk.h>
20
20
#include <linux/types.h>
21
+ #include <linux/utsname.h>
22
+ #include <linux/zlib.h>
21
23
22
24
#include <drm/drm_drv.h>
23
25
#include <drm/drm_fourcc.h>
26
28
#include <drm/drm_panic.h>
27
29
#include <drm/drm_plane.h>
28
30
#include <drm/drm_print.h>
31
+ #include <drm/drm_rect.h>
29
32
30
33
#include "drm_crtc_internal.h"
31
34
@@ -627,6 +630,233 @@ static void draw_panic_static_kmsg(struct drm_scanout_buffer *sb)
627
630
}
628
631
}
629
632
633
+ #if defined(CONFIG_DRM_PANIC_SCREEN_QR_CODE )
634
+ /*
635
+ * It is unwise to allocate memory in the panic callback, so the buffers are
636
+ * pre-allocated. Only 2 buffers and the zlib workspace are needed.
637
+ * Two buffers are enough, using the following buffer usage:
638
+ * 1) kmsg messages are dumped in buffer1
639
+ * 2) kmsg is zlib-compressed into buffer2
640
+ * 3) compressed kmsg is encoded as QR-code Numeric stream in buffer1
641
+ * 4) QR-code image is generated in buffer2
642
+ * The Max QR code size is V40, 177x177, 4071 bytes for image, 2956 bytes for
643
+ * data segments.
644
+ *
645
+ * Typically, ~7500 bytes of kmsg, are compressed into 2800 bytes, which fits in
646
+ * a V40 QR-code (177x177).
647
+ *
648
+ * If CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL is not set, the kmsg data will be put
649
+ * directly in the QR code.
650
+ * 1) kmsg messages are dumped in buffer1
651
+ * 2) kmsg message is encoded as byte stream in buffer2
652
+ * 3) QR-code image is generated in buffer1
653
+ */
654
+
655
+ static uint panic_qr_version = CONFIG_DRM_PANIC_SCREEN_QR_VERSION ;
656
+ module_param (panic_qr_version , uint , 0644 );
657
+ MODULE_PARM_DESC (panic_qr_version , "maximum version (size) of the QR code" );
658
+
659
+ #define MAX_QR_DATA 2956
660
+ #define MAX_ZLIB_RATIO 3
661
+ #define QR_BUFFER1_SIZE (MAX_ZLIB_RATIO * MAX_QR_DATA) /* Must also be > 4071 */
662
+ #define QR_BUFFER2_SIZE 4096
663
+ #define QR_MARGIN 4 /* 4 modules of foreground color around the qr code */
664
+
665
+ /* Compression parameters */
666
+ #define COMPR_LEVEL 6
667
+ #define WINDOW_BITS 12
668
+ #define MEM_LEVEL 4
669
+
670
+ static char * qrbuf1 ;
671
+ static char * qrbuf2 ;
672
+ static struct z_stream_s stream ;
673
+
674
+ static void __init drm_panic_qr_init (void )
675
+ {
676
+ qrbuf1 = kmalloc (QR_BUFFER1_SIZE , GFP_KERNEL );
677
+ qrbuf2 = kmalloc (QR_BUFFER2_SIZE , GFP_KERNEL );
678
+ stream .workspace = kmalloc (zlib_deflate_workspacesize (WINDOW_BITS , MEM_LEVEL ),
679
+ GFP_KERNEL );
680
+ }
681
+
682
+ static void drm_panic_qr_exit (void )
683
+ {
684
+ kfree (qrbuf1 );
685
+ qrbuf1 = NULL ;
686
+ kfree (qrbuf2 );
687
+ qrbuf2 = NULL ;
688
+ kfree (stream .workspace );
689
+ stream .workspace = NULL ;
690
+ }
691
+
692
+ extern size_t drm_panic_qr_max_data_size (u8 version , size_t url_len );
693
+
694
+ extern u8 drm_panic_qr_generate (const char * url , u8 * data , size_t data_len , size_t data_size ,
695
+ u8 * tmp , size_t tmp_size );
696
+
697
+ static int drm_panic_get_qr_code_url (u8 * * qr_image )
698
+ {
699
+ struct kmsg_dump_iter iter ;
700
+ char url [256 ];
701
+ size_t kmsg_len , max_kmsg_size ;
702
+ char * kmsg ;
703
+ int max_qr_data_size , url_len ;
704
+
705
+ url_len = snprintf (url , sizeof (url ), CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL "?a=%s&v=%s&zl=" ,
706
+ utsname ()-> machine , utsname ()-> release );
707
+
708
+ max_qr_data_size = drm_panic_qr_max_data_size (panic_qr_version , url_len );
709
+ max_kmsg_size = min (MAX_ZLIB_RATIO * max_qr_data_size , QR_BUFFER1_SIZE );
710
+
711
+ /* get kmsg to buffer 1 */
712
+ kmsg_dump_rewind (& iter );
713
+ kmsg_dump_get_buffer (& iter , false, qrbuf1 , max_kmsg_size , & kmsg_len );
714
+
715
+ if (!kmsg_len )
716
+ return - ENODATA ;
717
+ kmsg = qrbuf1 ;
718
+
719
+ try_again :
720
+ if (zlib_deflateInit2 (& stream , COMPR_LEVEL , Z_DEFLATED , WINDOW_BITS ,
721
+ MEM_LEVEL , Z_DEFAULT_STRATEGY ) != Z_OK )
722
+ return - EINVAL ;
723
+
724
+ stream .next_in = kmsg ;
725
+ stream .avail_in = kmsg_len ;
726
+ stream .total_in = 0 ;
727
+ stream .next_out = qrbuf2 ;
728
+ stream .avail_out = QR_BUFFER2_SIZE ;
729
+ stream .total_out = 0 ;
730
+
731
+ if (zlib_deflate (& stream , Z_FINISH ) != Z_STREAM_END )
732
+ return - EINVAL ;
733
+
734
+ if (zlib_deflateEnd (& stream ) != Z_OK )
735
+ return - EINVAL ;
736
+
737
+ if (stream .total_out > max_qr_data_size ) {
738
+ /* too much data for the QR code, so skip the first line and try again */
739
+ kmsg = strchr (kmsg , '\n' );
740
+ if (!kmsg )
741
+ return - EINVAL ;
742
+ /* skip the first \n */
743
+ kmsg += 1 ;
744
+ kmsg_len = strlen (kmsg );
745
+ goto try_again ;
746
+ }
747
+ * qr_image = qrbuf2 ;
748
+
749
+ /* generate qr code image in buffer2 */
750
+ return drm_panic_qr_generate (url , qrbuf2 , stream .total_out , QR_BUFFER2_SIZE ,
751
+ qrbuf1 , QR_BUFFER1_SIZE );
752
+ }
753
+
754
+ static int drm_panic_get_qr_code_raw (u8 * * qr_image )
755
+ {
756
+ struct kmsg_dump_iter iter ;
757
+ size_t kmsg_len ;
758
+ size_t max_kmsg_size = min (drm_panic_qr_max_data_size (panic_qr_version , 0 ),
759
+ QR_BUFFER1_SIZE );
760
+
761
+ kmsg_dump_rewind (& iter );
762
+ kmsg_dump_get_buffer (& iter , false, qrbuf1 , max_kmsg_size , & kmsg_len );
763
+ if (!kmsg_len )
764
+ return - ENODATA ;
765
+
766
+ * qr_image = qrbuf1 ;
767
+ return drm_panic_qr_generate (NULL , qrbuf1 , kmsg_len , QR_BUFFER1_SIZE ,
768
+ qrbuf2 , QR_BUFFER2_SIZE );
769
+ }
770
+
771
+ static int drm_panic_get_qr_code (u8 * * qr_image )
772
+ {
773
+ if (strlen (CONFIG_DRM_PANIC_SCREEN_QR_CODE_URL ) > 0 )
774
+ return drm_panic_get_qr_code_url (qr_image );
775
+ else
776
+ return drm_panic_get_qr_code_raw (qr_image );
777
+ }
778
+
779
+ /*
780
+ * Draw the panic message at the center of the screen, with a QR Code
781
+ */
782
+ static int _draw_panic_static_qr_code (struct drm_scanout_buffer * sb )
783
+ {
784
+ u32 fg_color = convert_from_xrgb8888 (CONFIG_DRM_PANIC_FOREGROUND_COLOR , sb -> format -> format );
785
+ u32 bg_color = convert_from_xrgb8888 (CONFIG_DRM_PANIC_BACKGROUND_COLOR , sb -> format -> format );
786
+ const struct font_desc * font = get_default_font (sb -> width , sb -> height , NULL , NULL );
787
+ struct drm_rect r_screen , r_logo , r_msg , r_qr , r_qr_canvas ;
788
+ unsigned int max_qr_size , scale ;
789
+ unsigned int msg_width , msg_height ;
790
+ int qr_width , qr_canvas_width , qr_pitch , v_margin ;
791
+ u8 * qr_image ;
792
+
793
+ if (!font || !qrbuf1 || !qrbuf2 || !stream .workspace )
794
+ return - ENOMEM ;
795
+
796
+ r_screen = DRM_RECT_INIT (0 , 0 , sb -> width , sb -> height );
797
+
798
+ drm_panic_logo_rect (& r_logo , font );
799
+
800
+ msg_width = min (get_max_line_len (panic_msg , panic_msg_lines ) * font -> width , sb -> width );
801
+ msg_height = min (panic_msg_lines * font -> height , sb -> height );
802
+ r_msg = DRM_RECT_INIT (0 , 0 , msg_width , msg_height );
803
+
804
+ max_qr_size = min (3 * sb -> width / 4 , 3 * sb -> height / 4 );
805
+
806
+ qr_width = drm_panic_get_qr_code (& qr_image );
807
+ if (qr_width <= 0 )
808
+ return - ENOSPC ;
809
+
810
+ qr_canvas_width = qr_width + QR_MARGIN * 2 ;
811
+ scale = max_qr_size / qr_canvas_width ;
812
+ /* QR code is not readable if not scaled at least by 2 */
813
+ if (scale < 2 )
814
+ return - ENOSPC ;
815
+
816
+ pr_debug ("QR width %d and scale %d\n" , qr_width , scale );
817
+ r_qr_canvas = DRM_RECT_INIT (0 , 0 , qr_canvas_width * scale , qr_canvas_width * scale );
818
+
819
+ v_margin = (sb -> height - drm_rect_height (& r_qr_canvas ) - drm_rect_height (& r_msg )) / 5 ;
820
+
821
+ drm_rect_translate (& r_qr_canvas , (sb -> width - r_qr_canvas .x2 ) / 2 , 2 * v_margin );
822
+ r_qr = DRM_RECT_INIT (r_qr_canvas .x1 + QR_MARGIN * scale , r_qr_canvas .y1 + QR_MARGIN * scale ,
823
+ qr_width * scale , qr_width * scale );
824
+
825
+ /* Center the panic message */
826
+ drm_rect_translate (& r_msg , (sb -> width - r_msg .x2 ) / 2 ,
827
+ 3 * v_margin + drm_rect_height (& r_qr_canvas ));
828
+
829
+ /* Fill with the background color, and draw text on top */
830
+ drm_panic_fill (sb , & r_screen , bg_color );
831
+
832
+ if (!drm_rect_overlap (& r_logo , & r_msg ) && !drm_rect_overlap (& r_logo , & r_qr ))
833
+ drm_panic_logo_draw (sb , & r_logo , font , fg_color );
834
+
835
+ draw_txt_rectangle (sb , font , panic_msg , panic_msg_lines , true, & r_msg , fg_color );
836
+
837
+ /* Draw the qr code */
838
+ qr_pitch = DIV_ROUND_UP (qr_width , 8 );
839
+ drm_panic_fill (sb , & r_qr_canvas , fg_color );
840
+ drm_panic_fill (sb , & r_qr , bg_color );
841
+ drm_panic_blit (sb , & r_qr , qr_image , qr_pitch , scale , fg_color );
842
+ return 0 ;
843
+ }
844
+
845
+ static void draw_panic_static_qr_code (struct drm_scanout_buffer * sb )
846
+ {
847
+ if (_draw_panic_static_qr_code (sb ))
848
+ draw_panic_static_user (sb );
849
+ }
850
+ #else
851
+ static void draw_panic_static_qr_code (struct drm_scanout_buffer * sb )
852
+ {
853
+ draw_panic_static_user (sb );
854
+ }
855
+
856
+ static void drm_panic_qr_init (void ) {};
857
+ static void drm_panic_qr_exit (void ) {};
858
+ #endif
859
+
630
860
/*
631
861
* drm_panic_is_format_supported()
632
862
* @format: a fourcc color code
@@ -645,6 +875,8 @@ static void draw_panic_dispatch(struct drm_scanout_buffer *sb)
645
875
{
646
876
if (!strcmp (drm_panic_screen , "kmsg" )) {
647
877
draw_panic_static_kmsg (sb );
878
+ } else if (!strcmp (drm_panic_screen , "qr_code" )) {
879
+ draw_panic_static_qr_code (sb );
648
880
} else {
649
881
draw_panic_static_user (sb );
650
882
}
@@ -814,3 +1046,19 @@ void drm_panic_unregister(struct drm_device *dev)
814
1046
kmsg_dump_unregister (& plane -> kmsg_panic );
815
1047
}
816
1048
}
1049
+
1050
+ /**
1051
+ * drm_panic_init() - initialize DRM panic.
1052
+ */
1053
+ void __init drm_panic_init (void )
1054
+ {
1055
+ drm_panic_qr_init ();
1056
+ }
1057
+
1058
+ /**
1059
+ * drm_panic_exit() - Free the resources taken by drm_panic_exit()
1060
+ */
1061
+ void drm_panic_exit (void )
1062
+ {
1063
+ drm_panic_qr_exit ();
1064
+ }
0 commit comments