Compare commits

..

1 Commits

Author SHA1 Message Date
Markus Koch 5226513971 display:kernel-driver: commit old work-in-progress code
Originally, I intended to do everything over SPI.
The new hardware, however, uses UART for the keyboard
and the printer, so this code is obsolete and the
display driver is pretty much complete the way it is
in the last commit.
2019-10-26 16:58:31 +02:00
47 changed files with 3197 additions and 2785 deletions

26
.gitignore vendored
View File

@ -1,25 +1 @@
# AVR temp files
*.srec
*.s
*.o
*.map
*.lst
*.hex
*.elf
*.bin
*.obj
# Linux kernel driver temp files
.cache.mk
*.cmd
.tmp_versions/*
*.a
*.mod
# Qt files
build-*
# CMake
**/CMakeFiles/**
CMakeCache.txt
cmake_install.cmake
doc

View File

@ -1,10 +1,4 @@
# Brother LW-35 Modernization
Drivers, firmware and tools used in my LW-35 electronic typewriter modernization.
For documentation, see my Vlog series:
* [Part 1: LCD](https://notsyncing.net/?p=blog&b=2018.lw35-vlog-1)
* [Part 2: Keyboard](https://notsyncing.net/?p=blog&b=2018.lw35-vlog-2)
* [Part 3: Printer preparation](https://notsyncing.net/?p=blog&b=2018.lw35-vlog-3)
* [Part 4: Printer](https://notsyncing.net/?p=blog&b=2018.lw35-vlog-4)
* [Part 5: Bringing it all together](https://notsyncing.net/?p=blog&b=2020.lw35-vlog-5)
Documentation coming soon-ish.

View File

@ -2,7 +2,7 @@
<BaliProject version="3.2" title="lmg6202" device="LCMXO2-1200HC-5SG32C" default_implementation="impl1">
<Options/>
<Implementation title="impl1" dir="impl1" description="impl1" synthesis="synplify" default_strategy="Strategy1">
<Options def_top="design.top" lib="design" top="design.top"/>
<Options def_top="design.top" top="design.top"/>
<Source name="../ip/gram0/gram0.ipx" type="IPX_Module" type_short="IPX">
<Options/>
</Source>
@ -18,12 +18,6 @@
<Source name="../design/spi_if.vhd" type="VHDL" type_short="VHDL">
<Options lib="design"/>
</Source>
<Source name="../ip/pll0/pll0.vhd" type="VHDL" type_short="VHDL">
<Options lib="ip"/>
</Source>
<Source name="../generics/synchronizer.vhd" type="VHDL" type_short="VHDL">
<Options lib="generics"/>
</Source>
<Source name="impl1/impl1.xcf" type="Programming Project File" type_short="Programming">
<Options/>
</Source>

View File

@ -190,7 +190,7 @@
<Property name="PROP_SYN_ResolvedMixedDrivers" value="False" time="0"/>
<Property name="PROP_SYN_UpdateCompilePtTimData" value="False" time="0"/>
<Property name="PROP_SYN_UseLPF" value="True" time="0"/>
<Property name="PROP_SYN_VHDL2008" value="True" time="0"/>
<Property name="PROP_SYN_VHDL2008" value="False" time="0"/>
<Property name="PROP_THERMAL_DefaultFreq" value="0" time="0"/>
<Property name="PROP_TIM_MaxDelSimDes" value="" time="0"/>
<Property name="PROP_TIM_MinSpeedGrade" value="False" time="0"/>

View File

@ -0,0 +1,3 @@
Date=04/22/2018
Time=17:34:06

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<DiamondModule name="gram0" module="gram0" VendorName="Lattice Semiconductor Corporation" generator="IPexpress" date="2020 05 10 12:58:23.793" version="7.5" type="Module" synthesis="synplify" source_format="VHDL">
<DiamondModule name="gram0" module="gram0" VendorName="Lattice Semiconductor Corporation" generator="IPexpress" date="2018 04 22 11:42:01.314" version="7.5" type="Module" synthesis="synplify" source_format="VHDL">
<Package>
<File name="/home/markus/projects/cross-discipline/lw35-upgrade/display/tools/splash.mem" type="mem" modified="2020 05 10 12:46:45.000"/>
<File name="gram0.lpc" type="lpc" modified="2020 05 10 12:58:21.000"/>
<File name="gram0.vhd" type="top_level_vhdl" modified="2020 05 10 12:58:21.000"/>
<File name="gram0_tmpl.vhd" type="template_vhdl" modified="2020 05 10 12:58:21.000"/>
<File name="tb_gram0_tmpl.vhd" type="testbench_vhdl" modified="2020 05 10 12:58:21.000"/>
<File name="" type="mem" modified="2018 04 22 11:42:01.000"/>
<File name="gram0.lpc" type="lpc" modified="2018 04 22 11:42:00.000"/>
<File name="gram0.vhd" type="top_level_vhdl" modified="2018 04 22 11:42:00.000"/>
<File name="gram0_tmpl.vhd" type="template_vhdl" modified="2018 04 22 11:42:00.000"/>
<File name="tb_gram0_tmpl.vhd" type="testbench_vhdl" modified="2018 04 22 11:42:00.000"/>
</Package>
</DiamondModule>

View File

@ -16,8 +16,8 @@ CoreRevision=7.5
ModuleName=gram0
SourceFormat=VHDL
ParameterFileVersion=1.0
Date=05/10/2020
Time=13:18:44
Date=04/22/2018
Time=17:34:06
[Parameters]
Verilog=0
@ -41,7 +41,7 @@ Optimization=Speed
Reset=Sync
Reset1=Sync
Init=mem
MemFile=/home/markus/projects/cross-discipline/lw35-upgrade/display/tools/splash.mem
MemFile=/home/markus/projects/workspaceSigasi/lmg6202/bin/gram_init.mem
MemFormat=bin
EnECC=0
Pipeline=0
@ -50,7 +50,7 @@ WriteB=Normal
init_data=0
[FilesGenerated]
/home/markus/projects/cross-discipline/lw35-upgrade/display/tools/splash.mem=mem
/home/markus/projects/workspaceSigasi/lmg6202/bin/gram_init.mem=mem
[Command]
cmd_line= -w -n gram0 -lang vhdl -synth synplify -bus_exp 7 -bb -arch xo2c00 -type ramdp -device LCMXO2-1200HC -aaddr_width 13 -widtha 9 -baddr_width 13 -widthb 9 -anum_words 7000 -bnum_words 7000 -outdataA REGISTERED -outdataB REGISTERED -cascade -1 -resetmode SYNC -sync_reset -memfile /home/markus/projects/cross-discipline/lw35-upgrade/display/tools/splash.mem -memformat bin -writemodeA NORMAL -writemodeB NORMAL
cmd_line= -w -n gram0 -lang vhdl -synth synplify -bus_exp 7 -bb -arch xo2c00 -type ramdp -device LCMXO2-1200HC -aaddr_width 13 -widtha 9 -baddr_width 13 -widthb 9 -anum_words 7000 -bnum_words 7000 -outdataA REGISTERED -outdataB REGISTERED -cascade -1 -resetmode SYNC -sync_reset -memfile /home/markus/projects/workspaceSigasi/lmg6202/bin/gram_init.mem -memformat bin -writemodeA NORMAL -writemodeB NORMAL

View File

@ -1,5 +1,5 @@
SCUBA, Version Diamond (64-bit) 3.10.0.111.2
Sun May 10 13:18:44 2020
Sun Apr 22 17:34:06 2018
Copyright (c) 1991-1994 by NeoCAD Inc. All rights reserved.
Copyright (c) 1995 AT&T Corp. All rights reserved.
@ -7,7 +7,7 @@ Copyright (c) 1995-2001 Lucent Technologies Inc. All rights reserved.
Copyright (c) 2001 Agere Systems All rights reserved.
Copyright (c) 2002-2017 Lattice Semiconductor Corporation, All rights reserved.
Issued command : /usr/local/diamond/3.10_x64/ispfpga/bin/lin64/scuba -w -n gram0 -lang vhdl -synth synplify -bus_exp 7 -bb -arch xo2c00 -type ramdp -device LCMXO2-1200HC -aaddr_width 13 -widtha 9 -baddr_width 13 -widthb 9 -anum_words 7000 -bnum_words 7000 -outdataA REGISTERED -outdataB REGISTERED -cascade -1 -resetmode SYNC -sync_reset -memfile /home/markus/projects/cross-discipline/lw35-upgrade/display/tools/splash.mem -memformat bin -writemodeA NORMAL -writemodeB NORMAL
Issued command : /usr/local/diamond/3.10_x64/ispfpga/bin/lin64/scuba -w -n gram0 -lang vhdl -synth synplify -bus_exp 7 -bb -arch xo2c00 -type ramdp -device LCMXO2-1200HC -aaddr_width 13 -widtha 9 -baddr_width 13 -widthb 9 -anum_words 7000 -bnum_words 7000 -outdataA REGISTERED -outdataB REGISTERED -cascade -1 -resetmode SYNC -sync_reset -memfile /home/markus/projects/workspaceSigasi/lmg6202/bin/gram_init.mem -memformat bin -writemodeA NORMAL -writemodeB NORMAL
Circuit name : gram0
Module type : RAM_DP_TRUE
Module Version : 7.5
@ -15,7 +15,7 @@ Copyright (c) 2002-2017 Lattice Semiconductor Corporation, All rights reserved.
Inputs : DataInA[8:0], DataInB[8:0], AddressA[12:0], AddressB[12:0], ClockA, ClockB, ClockEnA, ClockEnB, WrA, WrB, ResetA, ResetB
Outputs : QA[8:0], QB[8:0]
I/O buffer : not inserted
Memory file : /home/markus/projects/cross-discipline/lw35-upgrade/display/tools/splash.mem
Memory file : /home/markus/projects/workspaceSigasi/lmg6202/bin/gram_init.mem
EDIF output : gram0.edn
VHDL output : gram0.vhd
VHDL template : gram0_tmpl.vhd

View File

@ -1,8 +1,8 @@
-- VHDL netlist generated by SCUBA Diamond (64-bit) 3.10.0.111.2
-- Module Version: 7.5
--/usr/local/diamond/3.10_x64/ispfpga/bin/lin64/scuba -w -n gram0 -lang vhdl -synth synplify -bus_exp 7 -bb -arch xo2c00 -type bram -wp 11 -rp 1010 -data_width 9 -rdata_width 9 -num_rows 7000 -outdataA REGISTERED -outdataB REGISTERED -cascade -1 -resetmode SYNC -sync_reset -memfile /home/markus/projects/cross-discipline/lw35-upgrade/display/tools/splash.mem -memformat bin -writemodeA NORMAL -writemodeB NORMAL
--/usr/local/diamond/3.10_x64/ispfpga/bin/lin64/scuba -w -n gram0 -lang vhdl -synth synplify -bus_exp 7 -bb -arch xo2c00 -type bram -wp 11 -rp 1010 -data_width 9 -rdata_width 9 -num_rows 7000 -outdataA REGISTERED -outdataB REGISTERED -cascade -1 -resetmode SYNC -sync_reset -memfile /home/markus/projects/workspaceSigasi/lmg6202/bin/gram_init.mem -memformat bin -writemodeA NORMAL -writemodeB NORMAL
-- Sun May 10 13:18:44 2020
-- Sun Apr 22 17:34:06 2018
library IEEE;
use IEEE.std_logic_1164.all;
@ -265,19 +265,19 @@ architecture Structure of gram0 is
attribute MEM_INIT_FILE : string;
attribute GSR : string;
attribute MEM_LPC_FILE of gram0_0_0_6 : label is "gram0.lpc";
attribute MEM_INIT_FILE of gram0_0_0_6 : label is "splash.mem";
attribute MEM_INIT_FILE of gram0_0_0_6 : label is "gram_init.mem";
attribute MEM_LPC_FILE of gram0_1_0_5 : label is "gram0.lpc";
attribute MEM_INIT_FILE of gram0_1_0_5 : label is "splash.mem";
attribute MEM_INIT_FILE of gram0_1_0_5 : label is "gram_init.mem";
attribute MEM_LPC_FILE of gram0_2_0_4 : label is "gram0.lpc";
attribute MEM_INIT_FILE of gram0_2_0_4 : label is "splash.mem";
attribute MEM_INIT_FILE of gram0_2_0_4 : label is "gram_init.mem";
attribute MEM_LPC_FILE of gram0_3_0_3 : label is "gram0.lpc";
attribute MEM_INIT_FILE of gram0_3_0_3 : label is "splash.mem";
attribute MEM_INIT_FILE of gram0_3_0_3 : label is "gram_init.mem";
attribute MEM_LPC_FILE of gram0_4_0_2 : label is "gram0.lpc";
attribute MEM_INIT_FILE of gram0_4_0_2 : label is "splash.mem";
attribute MEM_INIT_FILE of gram0_4_0_2 : label is "gram_init.mem";
attribute MEM_LPC_FILE of gram0_5_0_1 : label is "gram0.lpc";
attribute MEM_INIT_FILE of gram0_5_0_1 : label is "splash.mem";
attribute MEM_INIT_FILE of gram0_5_0_1 : label is "gram_init.mem";
attribute MEM_LPC_FILE of gram0_6_0_0 : label is "gram0.lpc";
attribute MEM_INIT_FILE of gram0_6_0_0 : label is "splash.mem";
attribute MEM_INIT_FILE of gram0_6_0_0 : label is "gram_init.mem";
attribute GSR of FF_11 : label is "ENABLED";
attribute GSR of FF_10 : label is "ENABLED";
attribute GSR of FF_9 : label is "ENABLED";
@ -309,15 +309,15 @@ begin
gram0_0_0_6: DP8KC
generic map (INIT_DATA=> "STATIC", ASYNC_RESET_RELEASE=> "SYNC",
INITVAL_1F=> "0x0F800000003E00000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1E=> "0x000000000000000000000000000000000000000000000000000010007C00001E000C000000000000",
INITVAL_1F=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1E=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1D=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1C=> "0x000000000000000000000000000180006013821F0000000000000000000000000000000000000000",
INITVAL_1C=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1B=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1A=> "0x001FC03DF80060100201000000000000000000000000000000000000000000000000000000000000",
INITVAL_19=> "0x0000000000000000000000000000000000000000000000000000000001FE3FE03002010000000000",
INITVAL_1A=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_19=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_18=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_17=> "0x000000000000000000000000000000200FE000000000000000000000000000000000000000000000",
INITVAL_17=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_16=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_15=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_14=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
@ -374,37 +374,37 @@ begin
gram0_1_0_5: DP8KC
generic map (INIT_DATA=> "STATIC", ASYNC_RESET_RELEASE=> "SYNC",
INITVAL_1F=> "0x01E013F2FB201DE01C0000000303871C10000C18002011C2010000000000200FE000003E00E00000",
INITVAL_1E=> "0x3F0063FC063F80E380FE301FE001FE003F101DFC003F903E003FC7E001801FE013E2FD0003800000",
INITVAL_1D=> "0x30383007E10187C000000020100000000003E00E001001FDC03FFFF0FFC103FF10FE013FC033FE0F",
INITVAL_1C=> "0x3F9FE3FCFE3F03E3C0FE001E03FC02301FE00D001FA0120207300063E01E3007E2000E2000600000",
INITVAL_1B=> "0x000000010001E01003F1383FF3FFFE303FF3FDFE003F83FDFE00FC13FFFF1FF013FFFF0FE01003FF",
INITVAL_1A=> "0x006013F27F201FE01C0000C000FC00004013820307C00060000000000000200FE000003E00E3FDFE",
INITVAL_19=> "0x3FE073F3FF3FE01203FF3FE3F003F93FFFF01FF13FFFF006013F81E0018007E013E2FF000E0000F0",
INITVAL_18=> "0x0020100200001F801D800020000000000003E006001000FDE03FFFF07E013FFFF01E013FDFE3FC00",
INITVAL_17=> "0x3E1FE3FC7E381FE3FC1E001C03FC00301FE005000FE010020D0781C0000000000381E23020000000",
INITVAL_16=> "0x000000018000E01003F93C3FF3FDFE003FC3FC3E001803FDFE002013F9FE0FE013F3FF00E01003FD",
INITVAL_15=> "0x002013FA1E201FE00C00038F03000200000000003020701A0000000000003007E000003F0063FDFE",
INITVAL_14=> "0x3FE03203FF01E01003F13FE01002013FFFF00E013FE1F002013F80E001C003E013E27F0018038006",
INITVAL_13=> "0x01C0000001200063C0E000000000000000000000000000000000000000003F01E00000201FE00400",
INITVAL_12=> "0x0000000000001F007C0000000000000000000000000000003000FC10060100000079000CE0100201",
INITVAL_11=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_10=> "0x000000000000000000003E0E60007800000001F0301F200C00000000000000000000000000000000",
INITVAL_0F=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000007C1C",
INITVAL_0E=> "0x3C000000000F8000383C000000000000000000000000000000000000000000000000000000000000",
INITVAL_0D=> "0x000000000000000000000000000000000000000000000000E0070001F000001F0001E00600000000",
INITVAL_1F=> "0x0020100201000003F07E001F83FDFE3FBFE3FDC03FEFF00201000000000000000000003FC1E00000",
INITVAL_1E=> "0x001F03FC3E3F87E000003E0FE00000000003C1FE00000001FC3FE0F0020100000001C00FE01303FF",
INITVAL_1D=> "0x3FFC13FFFF3C3FF3FE0F00000000000000000000001F03FC00000003F1FE03FC13FE07001803FC0E",
INITVAL_1C=> "0x00000001003FE01002013F9FE0FC000000000000381FE00C003FDFF03FFD3FE0F3FFFF00E0100201",
INITVAL_1B=> "0x00000001FC3FFFF3FFFF303FF3FFFF3FEFF003FD207FF3FFFF3FFFF07FFF3FFFF3FFFF00F813FFFF",
INITVAL_1A=> "0x0020100000000003F83E001FC3FDFE3FDFE1FDE03FE7F0020100000000003FDFE3FDFE3FE1F3F3FF",
INITVAL_19=> "0x3FFFF3FE033F83E3F1FE3FFFF3FFFF3FFFF3FDFF3FEFF003F93FE030020100000001C007E01383FF",
INITVAL_18=> "0x3FFE13FFFF3C3FF3FE060000000000001E03FDFE3FFFF1FF813FFFF3FFFF003E13FF833FFFF3FFFF",
INITVAL_17=> "0x3FFF73FFFF3FFFF3FE0F3F1FE03C0000000000003C1FE004003FDFF01FFF3FF0F3FFFF00E0100201",
INITVAL_16=> "0x00000001FE3FFFF3FFFF383FF3FFFE3FE0F003FF307FF3FFFF3FFFF27FFF3FFFF3FFFF00F013FEFF",
INITVAL_15=> "0x0000000000000003FC1E001FE3FCFE3FDFE0FDF03FE3F0020100000000003FDFE3FDFF3FE0F3FBFF",
INITVAL_14=> "0x3FFFF07E013FC1E3F1FE3FFFF3FFFF3FFFE3FDFF3FE7F003F10FE010020100000001E003E013C3FF",
INITVAL_13=> "0x1FFF13FFFF3F3FF3FC020000000000001F03FDFE3FFFF0FFC13FFFF3FEFF001E03FDC03FFFF3FFFF",
INITVAL_12=> "0x3FFFB3FFFF3FFFF3FE073E1FE00C0000000000003C1FE000003FFFF21FFF3FF873FFFF0060100201",
INITVAL_11=> "0x00000201FE3FFFF3FFFF383FF3FDFE03E01203FF383FF3FFFF3FFFF37FFF3FFFF3FFFF00F013FE3F",
INITVAL_10=> "0x0000000000001003FC1E001FE3FC7E3FDFE0FDF93FE3F0020100000000003FDFE3FDFF3FE073FBFF",
INITVAL_0F=> "0x3FE3F002013FC1E3F9FF3FFFF3FFFF3FDFE3FFFF3FE3F003E103E010020100000001F001E013C3FF",
INITVAL_0E=> "0x0FFF13FFFF3F3FE3FC000000000000001F03FDFE3FFFF07FC13FFFF07E01001E01FD803FFFF3FFFF",
INITVAL_0D=> "0x3FFF13FFFF3FFFF3FE033C0FE0000000000000003C0FE000003FDFF007FF3FF013FFFF0020100200",
INITVAL_0C=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_0B=> "0x000000000000000000000010000C0000E013E2070E00000000000000000000000000000000000000",
INITVAL_0A=> "0x000000000000000000000000000000000000000000000000000000000000000000000000000001E0",
INITVAL_09=> "0x001F83FDFE0038100600000000000000000000000000000000000000000000000000000000000000",
INITVAL_08=> "0x0000000000000000000000000000000000000000000000000038002001F83FE010021F0000000000",
INITVAL_0B=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_0A=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_09=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_08=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_07=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_06=> "0x00000000000000000000000001E0000003E0000001C0000001000000000000000000000000000000",
INITVAL_06=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_05=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_04=> "0x00201002010003C00000000000000000000000000000000000000000000000000000000000000000",
INITVAL_03=> "0x000000000000000000000000000000000000000000000000000007800000000003E0000000000000",
INITVAL_04=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_03=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_02=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_01=> "0x00000000000000000000000002001E00000001C00020100000000000000000000000000000000000",
INITVAL_01=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_00=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
CSDECODE_B=> "0b001", CSDECODE_A=> "0b001", WRITEMODE_B=> "NORMAL",
WRITEMODE_A=> "NORMAL", GSR=> "ENABLED", RESETMODE=> "SYNC",
@ -439,38 +439,38 @@ begin
gram0_2_0_4: DP8KC
generic map (INIT_DATA=> "STATIC", ASYNC_RESET_RELEASE=> "SYNC",
INITVAL_1F=> "0x003FE001F02020F003C0007FD3FFFF007F9207DF3C20F000062000324202000670020F0040600001",
INITVAL_1E=> "0x00000000001FC000010101E010038100E310020103FFD006013F8023C01E3E00E0C0003803E381FE",
INITVAL_1D=> "0x3FE3F3023F3BC0E1FE0100C0C1C10000E000C00400C380C0010000000000001F001C00200FE00000",
INITVAL_1C=> "0x3007E00000001FE3803E001C007C0007D011FE01000003F8023FDFF3FE0107CF81FBE10026118200",
INITVAL_1B=> "0x200430030101A1C301000020100000000002007E000003E006000003F002000003C01E03E01003FD",
INITVAL_1A=> "0x003FC005F000201001C0007FD3FFFF003F9387CF3C20700206060F10220C200C01E0602000200201",
INITVAL_19=> "0x00000000000FC000038100E01003C1006010020103FFF002013F802301FE3FE07002013803E381FE",
INITVAL_18=> "0x3FE0F3821F38D0F0FE0100D9C00DFC03000031F83E218060000000000000001F800C003007E00000",
INITVAL_17=> "0x3803E00000001FE3C01E001C007C003FDFF0FE01000003F80207D000FE0103C7F1FBF1002E13007E",
INITVAL_16=> "0x3C186000C00FD003FD000020000000000003007E000003F0063FDFF3FE03000003C11E03E01003FD",
INITVAL_15=> "0x303FE3FDFE00201001C0007F9007F9003FD3C1C23E2070020C1CC003F27F3C1FE001382020300201",
INITVAL_14=> "0x00000000000FC000038100FFD3FFFF006010020123EFF002013F8023FDFE3FE07002013803E3003E",
INITVAL_13=> "0x3F0023811E3070F0FE010183E018803FDFE0FC100303C060000000000000001F8004003003E381FE",
INITVAL_12=> "0x3FE1F00201001FE3E00E001C007DF03FFFF07E01000003F80207DC007E0123C1F1F3F1002C01E1C0",
INITVAL_11=> "0x1800001C30021C03018E0000000000000003803E000003F8023FDFF3FE01000003C11E01E01003FD",
INITVAL_10=> "0x3F3FE3FDFE00200001C0007F9007FD000FE3F1803F203003DC30200018C0031000040E33C0000000",
INITVAL_0F=> "0x000000000007C01003C1007FD3FFFF002010020123EFF002013F9C21FC003F802000003803E3003E",
INITVAL_0E=> "0x3FC003C18E3038F07E013F000060C0301800003000D8003C000000000000001FC004003803E3C1FE",
INITVAL_0D=> "0x3FE1F00201001FE3E00E001C007DFE003C007C00000003F8020FDE001C0139E0F3F3F9003C000D00",
INITVAL_0C=> "0x082010600C06070001E00000000000000003803E000003F802000003FC00000003E10E01E01003FF",
INITVAL_0B=> "0x3FC00001FC00200001E0003F120EFF000FE1F9803F2030021F000060080000F01204023800600000",
INITVAL_0A=> "0x000000000007C01003C100601003E1002010030121EFF002013FDE003C003F800000003C01E2007E",
INITVAL_09=> "0x0FC003C1EF3039F07C0000C001C2410003E00030004001E2010000000000001FE000003C01E00000",
INITVAL_08=> "0x3C00E00000200FE3E00E001E003CFE001E003C00000003FC000FDF8005013CE073F3FD0003E00000",
INITVAL_07=> "0x080013820006018000000040100201000003C01E000003FC00001001FC00000003F10601E01202FF",
INITVAL_06=> "0x1FC00001FF00000001F0003F130E3E2017E07D803FA011C2010001C0080000501186010003800000",
INITVAL_05=> "0x000000000003E01003E100201003F12020F003C020FFF002011FDF001E013FC0003C003F00E2007E",
INITVAL_04=> "0x03C013E3F7303DE03C000020130240000760003000201302020000000000001FE000003C01E00000",
INITVAL_03=> "0x3E10E1FC003803E3C01E001F820CFE001E003DFE001800FC001FDFC001003EE013E3FD0000C00000",
INITVAL_02=> "0x184000600F06006000000000000201000003C01E000003FC00001001FDE0002013FE0307E013827F",
INITVAL_01=> "0x3FC00001FE3F802001FC003E13DC0E201FE03D003FA013820100070019C0031000E0000001C00000",
INITVAL_00=> "0x000000000001E01003E100201003F03C23F001F0003FF0060107FE107E011FDC00FC003FC02000FE",
INITVAL_1F=> "0x00000000003F83E000003FFFF3FFFF01E0100201001F01FC003E1FE3FD823FFFF387FF1FE0100201",
INITVAL_1E=> "0x000000000000000001C007E0100201001E03FD801FE01002013FE0100201001C03FC02001FE3FDFE",
INITVAL_1D=> "0x3FEFF0020100000301FE003813FFFE307FF3FE1F3FDFF01E0100000000000000000000381FE00400",
INITVAL_1C=> "0x00000001FE303FF01E01201FE03C0000000001FE006013C3FF3FFFF3FE0700000000003FC0E003F9",
INITVAL_1B=> "0x3FE3F3FBFF03FFD3FEFF000000000000000381FE3FFFF3FE3F00000000003FC1E3F07E000003E1FE",
INITVAL_1A=> "0x00000000003FC3E000003FDFF3FFFF0060100201001F80FC003F1FE3FDC23FFFF383FF1FE0100201",
INITVAL_19=> "0x00000000003FFFF3FFFF07E0100201001E03FD800FE01003011FE0100201001E03FC00001FC0FC00",
INITVAL_18=> "0x3FC1E0020100000301FE003813FDFE383FF3FE1F3FDFF00E010000000000001FE3FDFE3FFFF00201",
INITVAL_17=> "0x00000201FE383FF00E01201FE01C0000000001FE00201383FF003F91FC0000000000003FC07003F1",
INITVAL_16=> "0x3FE0F3F3FF01E01002010000000000000003E1FE3FFFF3FE1F00000000003FC1E3F87F000003F0FE",
INITVAL_15=> "0x00000000003FC1E000013FC06383FF0020100200001FC07C00000000000000000000000000000000",
INITVAL_14=> "0x00000001003FFFF3FFFF03E0100201001F01FDC007E01003811FE0100201001F03FC00001F81FC00",
INITVAL_13=> "0x3FE070020100000381FE0020000000000000000000000000000000000000201FE3FDFE3FEFF00201",
INITVAL_12=> "0x00000201FE383FF00600301FE00C0000000201FE00201303FE203FF07E0000000000003FC0300201",
INITVAL_11=> "0x000000000000000000000000000000000003E1FE3FFFF3FE0F00000000003FC0E3FE3F000003F07E",
INITVAL_10=> "0x00000000003FC0E000013FC0E3E3FF0000000000001FE07C00000000000000000000000000000000",
INITVAL_0F=> "0x00000001003FFFF3FFFF01E0100201001F80FDE007E01003C10FE0100201001F81FC00001F01FD80",
INITVAL_0E=> "0x1FE0100201000003C1FE001C03FDFE3C3FF3FC023FEFF002010000000000201FE3FDFE3FEFF00201",
INITVAL_0D=> "0x00000381FE3C3FF00000381FE0040000000301FE00201203FE383FF01E0100000000003FE01003FF",
INITVAL_0C=> "0x3FF073FFFF20FFF3FE1F00000000000000000000001803FC0600000000003FD073FE1F000003F83E",
INITVAL_0B=> "0x00000000003FC06002013FC1E3FC7F0000000000201FE03C003FDFE0FDF03FE7F3F3FF03E0100201",
INITVAL_0A=> "0x000000000000000001F800E0100201001FE07DF003E01003C107E0100201001F80FC00001F03FDF0",
INITVAL_09=> "0x07E0100201000003E1FE001F03FDFE3E3FF3FD823FFFF00201000000000000000000003F87E00000",
INITVAL_08=> "0x000003E1FE3E3FE000003C1FE0040000000381FE00201001FE3E3FF0020100000001001FE01203FF",
INITVAL_07=> "0x3FF873FFFF307FF3FE1F00000000000000000000001C03FC0600000001003FF013FE0F000003FC1E",
INITVAL_06=> "0x00000000003FC03002013FD9E3FC0E0000000000201FE01C003FDFE0FDF93FE3F3F3FF03E0100201",
INITVAL_05=> "0x000000000000000001FC0060100201301FE03DF801E01003E103E0100201001FC07C00001E03FDFE",
INITVAL_04=> "0x01E0100201000003F0FE001F03FDFE3F3FE3FDC23FFFF00201000000000000000000003F83E00000",
INITVAL_03=> "0x000003F8FE3F0FE000003E1FE0000000000381FE00200001FE3FE7F0020100000001801FE01303FF",
INITVAL_02=> "0x3FF833FFFF383FF3FE0F00000000000000000000001E03FC0200000001F00FF813FE0F001003FC1E",
INITVAL_01=> "0x00000000003FE03002013F9FE3FC020000000000301FE00C003FDFE07FFD3FE1F3FBFF01E0100201",
INITVAL_00=> "0x000000000000000001FE00601002013F9FE005F800E01003F101E0100201001FE03C00001C03FDFE",
CSDECODE_B=> "0b010", CSDECODE_A=> "0b010", WRITEMODE_B=> "NORMAL",
WRITEMODE_A=> "NORMAL", GSR=> "ENABLED", RESETMODE=> "SYNC",
REGMODE_B=> "OUTREG", REGMODE_A=> "OUTREG", DATA_WIDTH_B=> 9,
@ -504,38 +504,38 @@ begin
gram0_3_0_3: DP8KC
generic map (INIT_DATA=> "STATIC", ASYNC_RESET_RELEASE=> "SYNC",
INITVAL_1F=> "0x00000000000000000000000000000000000000000000000000000000000000000000000018000006",
INITVAL_1E=> "0x080000600C060000C1C0000000000000000000000000000000000000000000000000000000000000",
INITVAL_1D=> "0x0000000000000000000000000000000000000000000000001800C000198103100004003020100000",
INITVAL_1C=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1B=> "0x0000000000000000000003830000C018100004100000E03000000000000000000000000000000000",
INITVAL_1A=> "0x0000000000000000000000000000000000000000000000000000000000000000000000000C020002",
INITVAL_19=> "0x1800031C700200018180000000000000000000000000000000000000000000000000000000000000",
INITVAL_18=> "0x0000000000000000000000000000000000000000000000000C00000213FF3FF8F002012000300200",
INITVAL_17=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_16=> "0x0000000000000000000001818001C007E013FE1F0001C06000000000000000000000000000000000",
INITVAL_15=> "0x00000000000000000000000000000000000000000000000000000000000000000000000006030000",
INITVAL_14=> "0x3E182000C00F80030100002000000000000000000000000000000000000000000000000000000000",
INITVAL_13=> "0x00000000000000000000000000000000000000000000000006001E1036193008007C002000200201",
INITVAL_12=> "0x000000000000000000000000000000000003E03E00000001FE002010000000000001E000E0100201",
INITVAL_11=> "0x0000000000000000000000C0C30106018000610C002190620000000001C03FFFF07FFD3FFFF307FF",
INITVAL_10=> "0x3FFFF003E13FE01002013FE3F003F1002013FA033F9FE0050001E01202FF1FC0007D800066118201",
INITVAL_0F=> "0x200630030101A3C301000020100000381FE3FDFE3FBFE3FC3E3FDFF3FE1F3F1FE0FC00301FE3FC0E",
INITVAL_0E=> "0x3E01E001C0007F13FEFF200FE000000FDE001FF13023F00006000070620600046200060040600201",
INITVAL_0D=> "0x000003F9FE3FFC33FFFF07FFD3FFFF03FE13FFFF002013FBFE03E013FE013803E381FE3FE013E20F",
INITVAL_0C=> "0x001F800CFE3E0063F00200C0C060000063C0C007018300C00000000001C03FFFF03FFD3FFFF383FF",
INITVAL_0B=> "0x3FEFF203FF3FE1F003F13FFFF007E1006013FA013FFFF07E0101E013823F1FD800FDC00026118381",
INITVAL_0A=> "0x000363E006005812020200201000003C1FE3FDFE3FDFE3FC1E3FDFF3FE0F3FDFE3FE033F1FE3FC7E",
INITVAL_09=> "0x3803E001E0203FF3FFFF002FF0000007DF100FF93821F00006100013830001E3D002190040600001",
INITVAL_08=> "0x000003FDFE3FFE13FFFF03FFD3FFFF01FFD03FF100FC13FE031FE013FA073C01E3F03E3FC0E3C00E",
INITVAL_07=> "0x001FE2007E3F8063F80000C0C01800300FF30203020300C0000000000000001E003C00001FE00000",
INITVAL_06=> "0x200FE3C07E380FE001FE003F901D8000E013FFC101F813FE0103E013C20F0FDC00FDC100261182C1",
INITVAL_05=> "0x0000C3F00E0010020203002010000000000001FE000003C01E000003E00E03E013F20F3FC02201FF",
INITVAL_04=> "0x300FE001E03823F003F1003FF0030101FF100FFF3821F00006180013830001E39002110040600001",
INITVAL_03=> "0x00000000001FC000000001E010030120EFF0030101FF103E013FC003E00E3C00E3FC003C01E3C01E",
INITVAL_02=> "0x3007E2007E3FC061F80000C0C01000200FF38203030300C0000000000000001F001C00200FE00000",
INITVAL_01=> "0x3007E3C00E201FE300FE001E007D0001F011FFC1002013FE033FDFF3FE0707DF00FFE10026118380",
INITVAL_00=> "0x000363C00600CC120202002010000000000200FE000003E00E000003F00600C003C21F0FC00003FD",
INITVAL_1F=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1E=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1D=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1C=> "0x00000000003FDFE3FDFF3FE013FBFF0FE01002013FC06000003F80E00000000003F01E381FE00000",
INITVAL_1B=> "0x000003FD063FFFF3FFFF00E0100201000000000000000000000000000000001F83FDFE3FFFF07FE1",
INITVAL_1A=> "0x3FFFF1FE01001F01FC00001E03FC0000000001C007E013FE3F00000001F021FFF3FFFF3FEFF00201",
INITVAL_19=> "0x00000000000000000000000000000000000381FE3FFFF3FFFF3C3FE3FDFE00E01203FF00201003FE",
INITVAL_18=> "0x0020100201381FE005E007E01002013F0FE3F1FE3FFFF3FE0F201FE3FC1E3FDFE01FF93FE0700201",
INITVAL_17=> "0x00000000003FDFF3FFFF3FE033FFFF3FFFF002013FC0E002013FC1E00000000003F83E3C1FE00400",
INITVAL_16=> "0x001C03FD8E3FFFF3FFFF01E013F3FF07FFD3FFFF3F9FE1FC000000000000001FC3FDFE3FFFF07FF1",
INITVAL_15=> "0x3FFFF3FE7F001F81FC00001F03FC0000000001E007E013FA3F00000001FE30FFF3FFFF3FE7F00381",
INITVAL_14=> "0x3FFFF387FF3FFC13FFFF002010020000000381FE3FFFF3FFFF3E3FE3FDFE1FE01303FF00201201FE",
INITVAL_13=> "0x00201002003C1FE005C00FE01002013FC3E3F9FF3FFFF3FE07301FE3FC1E3FDFF03FFF3FE0700201",
INITVAL_12=> "0x00000000003FFFF3FFFF3FF013FFFF3FFFF03E013FC07002013FC0E00001000003FC1E381FE00C00",
INITVAL_11=> "0x001F03FDC03FFFF3FFFF00E013FBFF03FFD3FEFF3FDFE0FC000000000000001FE3FDFE3FFFF03FF1",
INITVAL_10=> "0x3FFFF3FFFF003FC0FC00001F01FC0000000001E003E013FA7F00000301FE383FF3FFFF3FE7F003C1",
INITVAL_0F=> "0x3FFFF3C3FF1FFE13FFFF0020100000000003C1FE3FFFF3FFFF3E1FE3FDFE3FE07383FF00201301FE",
INITVAL_0E=> "0x00201002003E1FE001800FE01002013FC0F3FBFF3FFFF3FE03381FE3FC1E3FFFF01FFF3FE0700201",
INITVAL_0D=> "0x00000000003FDFE3FFFF3FE013FFFF3FFFF0FE013FC03002013FC0600201001003FC0E301FE01C00",
INITVAL_0C=> "0x001FE0FD003FFFF3FFFF006013FBFF01FFF3FEFF3FDFE07C0100000000000000000000201FE01C00",
INITVAL_0B=> "0x000003F1FE003FF07E00001F80FC0000000001F001E013F2FF000003E1FE00200000003FC3E001E0",
INITVAL_0A=> "0x3FEFF3C3FF0FFF13FFFF00200000000000000000000003E0FE00000000003FE0F3C3FF00200381FE",
INITVAL_09=> "0x00201000003E0FE001801FE01003013FE0100201001E03FC023C1FE3FD0E3FFFF20FFF3FE0300201",
INITVAL_08=> "0x000000000000000001801FE0100201001F81FC003FE03002013FC0700201001803FC0E201FE3FDFE",
INITVAL_07=> "0x3FFFF03E0100000001FE002013FFFF21FFF3FE7F3FDFE07C0100000000000000000000301FE01C00",
INITVAL_06=> "0x00000201FE003FF03E01001FC07C0000000001F800E013E3FF3FFFF3FEFF00000000003FC1E001E0",
INITVAL_05=> "0x3FE7F3E3FF0FFF93FFFF00000000000000000000000003F07E00000000003FC1E3E1FF00000381FE",
INITVAL_04=> "0x00200000003F07E001003FFFF3FFFF0FE0100201001F03FC003E1FE3FD063FFFF307FF3FE0100201",
INITVAL_03=> "0x000000000000000001800FE0100201001E03FD003FE01002013FE0300201001C03FC06201FE3FDFE",
INITVAL_02=> "0x3FFFF0060100000201FE003013FFFF30FFF3FE3F3FDFE03E0100000000000000000000381FE00C00",
INITVAL_01=> "0x00000001FE203FF01E01001FE07C0000000001FC00E013C3FF3FFFF3FE1F00000000003FC0E001F1",
INITVAL_00=> "0x3FE7F3F3FF07FF93FFFF00000000000000000000000003F87E00000000003FC1E3E0FE000003C1FE",
CSDECODE_B=> "0b011", CSDECODE_A=> "0b011", WRITEMODE_B=> "NORMAL",
WRITEMODE_A=> "NORMAL", GSR=> "ENABLED", RESETMODE=> "SYNC",
REGMODE_B=> "OUTREG", REGMODE_A=> "OUTREG", DATA_WIDTH_B=> 9,
@ -569,38 +569,38 @@ begin
gram0_4_0_2: DP8KC
generic map (INIT_DATA=> "STATIC", ASYNC_RESET_RELEASE=> "SYNC",
INITVAL_1F=> "0x000002007E200060C0003F00000030180000E000000013820F30006060000020F302000001C20006",
INITVAL_1E=> "0x3E0060000000C003000200180005C001A012301E380000000000000000003FC010C201003F10FC00",
INITVAL_1D=> "0x06000039000023C0018007E010F3010021E1C000000003020100DC03FC010006000000004000021D",
INITVAL_1C=> "0x3E0C0001800F8000700000000000000000E0780000207303060030100780300023C0023818200D80",
INITVAL_1B=> "0x202033C2000021900200004302020F0040100207000380000001D8000C0C3010003D000020100000",
INITVAL_1A=> "0x000000E1800021C0C0000001D0023130002030000060101CE13001C060000060F300010003030002",
INITVAL_19=> "0x004700000100C0030002000700001E03800031C00020E00000000000010020206300000021D30002",
INITVAL_18=> "0x06000061C000076000E03800037100002761C0000000020207000300020F00060000000040030203",
INITVAL_17=> "0x01DC03FDFF200061800000000000002000200000004061820100500007013FE010E2070C00003980",
INITVAL_16=> "0x206020C20700219002003FC1E2000301C0000006000380000000039003FD3FE013C2010000100201",
INITVAL_15=> "0x000000E000000700C0000023100230201FE01D0001F0000D80300320600001E0F30000001E03FC00",
INITVAL_14=> "0x004C00000100C00300020000C3800000000000000043900201000000000000201203FE0020F20006",
INITVAL_13=> "0x060000C0E0200C2000703000207106003C61C000000000020F001F100E0C3C07E001FE006011C201",
INITVAL_12=> "0x002010020000070200060000000000000FC000003FC070C20100D00004000C2010720C0600006180",
INITVAL_11=> "0x21E020C01800219002000180E2007E019803FC063FC3E0010020207380060003E0000E00C0000000",
INITVAL_10=> "0x000002007E0000E0C00000261000300000C00D800390000500302C2060000720F30000000C00C000",
INITVAL_0F=> "0x000C00003C00C0030002200020710003E013F20F038E00000000000000003F0000C0000020F20006",
INITVAL_0E=> "0x060001807038180000703000207118003061C400000000021D002010000C038600000000400033C1",
INITVAL_0D=> "0x3018000CE0039800041C00000000000000003900002071C00000500004010600101A390E00003180",
INITVAL_0C=> "0x272020C06000219002002300600000018C00000600038001C01C000010E00E180000300300000000",
INITVAL_0B=> "0x0000000180202060C000002390023000198004C00710000DC030102064001C20F300000018006000",
INITVAL_0A=> "0x000E00000C00C00300021800000CC0301C0000100E180004000000000000300020E0000021D30002",
INITVAL_09=> "0x06000300181C100004E03800007170002061D8000000000331002600000E01860000000040001E31",
INITVAL_08=> "0x180000600E0600001C3000000000000000607100002073800000101006010340000E711C00001D80",
INITVAL_07=> "0x3C2020C1800001900200360002000600DC0000070003800060070000080000F01006C10E00000000",
INITVAL_06=> "0x000001C1C00000E0C00000C0E00231001F0000700C0000787030002078003020F300000010003C00",
INITVAL_05=> "0x03C380003C00C00300020E180000400003C000303800000C0000000000001FC01383FF003F10FC00",
INITVAL_04=> "0x3FC1F2020F0E00001D8007E01073C1002061E00000000003E1001C03FC003F07E001FE007010061D",
INITVAL_03=> "0x080003800006000030600000000000001F800C003FC06003FD001FC3FC0001D00004E0000FE00180",
INITVAL_02=> "0x302020C10000219002001C000001F0002013FC063FC3E00030018000080000701007011820000000",
INITVAL_1F=> "0x00000000003C40101E013FE0F003E1001F03FC003F8FE001C01FE013E303003F13FE0E3E0FE001E0",
INITVAL_1E=> "0x0011E03C0E3E1FE005E01FE01003FF3FE0F3FFFF20FFF3FE3F00000000000001C078F02000E1E000",
INITVAL_1D=> "0x1C00000000003C10061F3C10001D002060F3020F01C002001F3C0001C1F801E000001D1E00000000",
INITVAL_1C=> "0x3FDFE0FDF03FE7F3E3FF07E010020100000001801E2010F0000020101E010003C0001E03D0001CF0",
INITVAL_1B=> "0x2007E0E00000CE00020103C0001C003FAF3002000390001C00001E03FDFE3E3FF3FD823FFFF00201",
INITVAL_1A=> "0x0000000000301FE00D800021E000F0000003800201DE0000701E0003E10E0023D0000E001E0000E0",
INITVAL_19=> "0x201CE27006001E0000F000000001FE3FF073FFFF307FF3FE1F0000000000000003FC7E380023C000",
INITVAL_18=> "0x1E00000000004F10020F0F10000D8031E073800101C000001E1E0001E18E00F003FC1F3E0FE00000",
INITVAL_17=> "0x3FDFE0FDF13FE3F3F3FF03E010020100000001F00FE0103A010030100E000001C2000E01D8000478",
INITVAL_16=> "0x301E607000000F10020103D0001D0031E7F003F901E013FE3F001F03FDFE3F3FE3FD823FFFF00201",
INITVAL_15=> "0x00000000000F180005C02000E00070000003C00000CF0000390F0000719C0021E2000E000E000070",
INITVAL_14=> "0x2007E3F0023F0FE0018007E01203FF3FF833FFFF383FF3FE0F00000000000018000438380001E000",
INITVAL_13=> "0x0F00000000002712020F07180005803FA023C00000C002000F0E0003F102006012020F0018000400",
INITVAL_12=> "0x3FDFE07DF93FE1F3FBFF01E0100201000000003C07800039800038100C002000E3000600D8000439",
INITVAL_11=> "0x3818207C00002790020100D8000F812023F0020101C0000039001F83FDFE3F3FE3FDC03FEFF00201",
INITVAL_10=> "0x0000000000079C0005C03820200038000000F80000C700027907800039F80003C3C0020003C00078",
INITVAL_0F=> "0x3001E3E002000700000007800301FE3FFC13FFFF383FF3FE0F0000000000001803FC1E301FE03C00",
INITVAL_0E=> "0x3FE0F3C3FF00238300063F1FE005C03E000381FE003E13FE01070001F100003E13FE073F1FE00000",
INITVAL_0D=> "0x3FDFE03FFD3FE0F3FFFF00E010020100000001F003E013E2FF201FE1FC001FE013020300C003FE1F",
INITVAL_0C=> "0x3810003C003FC06203FF003C1007C02021F001FE00F813FE0F001F83FDFE3F9FE1FDE03FE7F00201",
INITVAL_0B=> "0x0000000000300FE0000001C013C3FF003FD00000000300030103E0101AC1001C001C001FC0000018",
INITVAL_0A=> "0x300021C0003FC3E001F800201383FE3FFC13FFFF3C3FF3FE06000000000000000000000000000000",
INITVAL_09=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_08=> "0x3FDFF01FFF3FE0F3FFFF00E010020100000000000000000000000000000000000000000000000000",
INITVAL_07=> "0x00000000000000000000000000000000000000000000000000001FC3FCFE3FDFE0FDF03FE3F00201",
INITVAL_06=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_05=> "0x0000000000000000000000000381FE1FFE13FFFF3E3FF3FC02000000000000000000000000000000",
INITVAL_04=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_03=> "0x3FDFF01FFF3FF073FFFF006010020100000000000000000000000000000000000000000000000000",
INITVAL_02=> "0x00000000000000000000000000000000000000000000000000001FC3FC7E3FDFE07DF03FE3F00201",
INITVAL_01=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_00=> "0x00000000000000000000070600004020066000302000201800000000000000000000000000000000",
INITVAL_00=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
CSDECODE_B=> "0b100", CSDECODE_A=> "0b100", WRITEMODE_B=> "NORMAL",
WRITEMODE_A=> "NORMAL", GSR=> "ENABLED", RESETMODE=> "SYNC",
REGMODE_B=> "OUTREG", REGMODE_A=> "OUTREG", DATA_WIDTH_B=> 9,
@ -635,37 +635,37 @@ begin
gram0_5_0_1: DP8KC
generic map (INIT_DATA=> "STATIC", ASYNC_RESET_RELEASE=> "SYNC",
INITVAL_1F=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1E=> "0x0000000000000000000000000000000000000000000000000000000001FC3FE01002010000000000",
INITVAL_1E=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1D=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1C=> "0x0000000000000000000000000000003F9FE03C000000000000000000000000000000000000000000",
INITVAL_1C=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1B=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_1A=> "0x001C0001800000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_19=> "0x00000000000000000000000000000000000000000000000000000000000C30000000000000000000",
INITVAL_1A=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_19=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_18=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_17=> "0x00000000000000000000000000000001800030000000000000000000000000000000000000000000",
INITVAL_17=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_16=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_15=> "0x000C0001800000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_14=> "0x00000000000000000000000000000000000000000000000000000000000C30000000000000000000",
INITVAL_15=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_14=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_13=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_12=> "0x00000000000000000000000000000001C000F0010000000000000000000000000000000000000000",
INITVAL_12=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_11=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_10=> "0x000FE0018000E0100201000000000000000000000000000000000000000000000000000000000000",
INITVAL_0F=> "0x00000000000000000000000000000000000000000000000000000003F80C301FE000000000000000",
INITVAL_10=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_0F=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_0E=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_0D=> "0x0000000000000000000000000001F001A00030FC0000000000000000000000000000000000000000",
INITVAL_0D=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_0C=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_0B=> "0x0F8C0001803C00200000000000000000000000000000000000000000000000000000000000000000",
INITVAL_0A=> "0x00000000000000000000000000000000000000000000000000001F00000C300001F0000000000000",
INITVAL_0B=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_0A=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_09=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_08=> "0x00000000000000000000000003800601800030000020100201000000000000000000000000000000",
INITVAL_08=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_07=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_06=> "0x002C1003810007800000000000000000000000000000000000000000000000000000000000000000",
INITVAL_05=> "0x00000000000000000000000000000000000000000000000000300060000C300002000E0000000000",
INITVAL_06=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_05=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_04=> "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000",
INITVAL_03=> "0x00000000000000000000000000780001800070000380000000000000000000000000000000000000",
INITVAL_02=> "0x000000000000000000000000000000000000000000000000000000000000000000000000000000E0",
INITVAL_01=> "0x000F8001800038100E01000000000000000000000000000000000000000000000000000000000000",
INITVAL_00=> "0x000000000000000000000000000000000000000000000000000E0003E00E3007E000F00000000000",
INITVAL_03=> "0x0000000000000000000000000000000000000000000000000000000000000000001CE0001E003C00",
INITVAL_02=> "0x38000001FE000003F802001FC01C000020F003E0003011FE0038000381C001D003FC3E001FE01C00",
INITVAL_01=> "0x3F1FE0FDC03FE3F3C3FF03E010020100000381E01C000381FE0020103C003FC0E001F101E013F3FF",
INITVAL_00=> "0x0001E1C0003F87E001F800E0103A013C2E1003F907E013FAFF001C03FDFE3C3FF3FF063FFFF00601",
CSDECODE_B=> "0b101", CSDECODE_A=> "0b101", WRITEMODE_B=> "NORMAL",
WRITEMODE_A=> "NORMAL", GSR=> "ENABLED", RESETMODE=> "SYNC",
REGMODE_B=> "OUTREG", REGMODE_A=> "OUTREG", DATA_WIDTH_B=> 9,

View File

@ -3,7 +3,7 @@ Starting process: Module
Starting process:
SCUBA, Version Diamond (64-bit) 3.10.0.111.2
Sun May 10 13:18:44 2020
Sun Apr 22 17:34:06 2018
Copyright (c) 1991-1994 by NeoCAD Inc. All rights reserved.
Copyright (c) 1995 AT&T Corp. All rights reserved.
@ -13,7 +13,7 @@ Copyright (c) 2002-2017 Lattice Semiconductor Corporation, All rights reserved.
BEGIN SCUBA Module Synthesis
Issued command : /usr/local/diamond/3.10_x64/ispfpga/bin/lin64/scuba -w -n gram0 -lang vhdl -synth synplify -bus_exp 7 -bb -arch xo2c00 -type ramdp -device LCMXO2-1200HC -aaddr_width 13 -widtha 9 -baddr_width 13 -widthb 9 -anum_words 7000 -bnum_words 7000 -outdataA REGISTERED -outdataB REGISTERED -cascade -1 -resetmode SYNC -sync_reset -memfile /home/markus/projects/cross-discipline/lw35-upgrade/display/tools/splash.mem -memformat bin -writemodeA NORMAL -writemodeB NORMAL
Issued command : /usr/local/diamond/3.10_x64/ispfpga/bin/lin64/scuba -w -n gram0 -lang vhdl -synth synplify -bus_exp 7 -bb -arch xo2c00 -type ramdp -device LCMXO2-1200HC -aaddr_width 13 -widtha 9 -baddr_width 13 -widthb 9 -anum_words 7000 -bnum_words 7000 -outdataA REGISTERED -outdataB REGISTERED -cascade -1 -resetmode SYNC -sync_reset -memfile /home/markus/projects/workspaceSigasi/lmg6202/bin/gram_init.mem -memformat bin -writemodeA NORMAL -writemodeB NORMAL
Circuit name : gram0
Module type : RAM_DP_TRUE
Module Version : 7.5
@ -21,7 +21,7 @@ BEGIN SCUBA Module Synthesis
Inputs : DataInA[8:0], DataInB[8:0], AddressA[12:0], AddressB[12:0], ClockA, ClockB, ClockEnA, ClockEnB, WrA, WrB, ResetA, ResetB
Outputs : QA[8:0], QB[8:0]
I/O buffer : not inserted
Memory file : /home/markus/projects/cross-discipline/lw35-upgrade/display/tools/splash.mem
Memory file : /home/markus/projects/workspaceSigasi/lmg6202/bin/gram_init.mem
EDIF output : gram0.edn
VHDL output : gram0.vhd
VHDL template : gram0_tmpl.vhd

View File

@ -1,6 +1,6 @@
-- VHDL module instantiation generated by SCUBA Diamond (64-bit) 3.10.0.111.2
-- Module Version: 7.5
-- Sun May 10 13:18:44 2020
-- Sun Apr 22 17:34:06 2018
-- parameterized module component declaration
component gram0

View File

@ -1,5 +1,5 @@
SCUBA, Version Diamond (64-bit) 3.10.0.111.2
Sun May 10 13:18:44 2020
Sun Apr 22 17:34:06 2018
Copyright (c) 1991-1994 by NeoCAD Inc. All rights reserved.
Copyright (c) 1995 AT&T Corp. All rights reserved.
@ -9,7 +9,7 @@ Copyright (c) 2002-2017 Lattice Semiconductor Corporation, All rights reserved.
BEGIN SCUBA Module Synthesis
Issued command : /usr/local/diamond/3.10_x64/ispfpga/bin/lin64/scuba -w -n gram0 -lang vhdl -synth synplify -bus_exp 7 -bb -arch xo2c00 -type ramdp -device LCMXO2-1200HC -aaddr_width 13 -widtha 9 -baddr_width 13 -widthb 9 -anum_words 7000 -bnum_words 7000 -outdataA REGISTERED -outdataB REGISTERED -cascade -1 -resetmode SYNC -sync_reset -memfile /home/markus/projects/cross-discipline/lw35-upgrade/display/tools/splash.mem -memformat bin -writemodeA NORMAL -writemodeB NORMAL
Issued command : /usr/local/diamond/3.10_x64/ispfpga/bin/lin64/scuba -w -n gram0 -lang vhdl -synth synplify -bus_exp 7 -bb -arch xo2c00 -type ramdp -device LCMXO2-1200HC -aaddr_width 13 -widtha 9 -baddr_width 13 -widthb 9 -anum_words 7000 -bnum_words 7000 -outdataA REGISTERED -outdataB REGISTERED -cascade -1 -resetmode SYNC -sync_reset -memfile /home/markus/projects/workspaceSigasi/lmg6202/bin/gram_init.mem -memformat bin -writemodeA NORMAL -writemodeB NORMAL
Circuit name : gram0
Module type : RAM_DP_TRUE
Module Version : 7.5
@ -17,7 +17,7 @@ BEGIN SCUBA Module Synthesis
Inputs : DataInA[8:0], DataInB[8:0], AddressA[12:0], AddressB[12:0], ClockA, ClockB, ClockEnA, ClockEnB, WrA, WrB, ResetA, ResetB
Outputs : QA[8:0], QB[8:0]
I/O buffer : not inserted
Memory file : /home/markus/projects/cross-discipline/lw35-upgrade/display/tools/splash.mem
Memory file : /home/markus/projects/workspaceSigasi/lmg6202/bin/gram_init.mem
EDIF output : gram0.edn
VHDL output : gram0.vhd
VHDL template : gram0_tmpl.vhd

View File

@ -1,12 +1,12 @@
obj-m := lmg6202ulyt.o
KDIR := ~/projects/linux/opi-current
KDIR := ~/projects/arm-linux/current
PWD := $(shell pwd)
default: lmg6202ulyt.ko
lmg6202ulyt.ko: lmg6202ulyt.c
$(MAKE) -C $(KDIR) M=$(PWD)
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
deploy: lmg6202ulyt.ko
scp $< markus@opi:/home/markus/projects/lw35/deploy/
scp $< markus@opi:/home/markus/lmg6202ulyt/deploy
clean:
rm -f ./*.o ./*.ko ./*.mod.c modules.order Module.symvers

View File

@ -0,0 +1,30 @@
&pio {
leds_opc: led_pins {
pins = "PA15";
function = "gpio_out";
};
lmg6202ulyt_opc: lmg6202ulyt_pins {
pins = "PA12", "PA3";
function = "gpio_in"; /* initial configuration */
#gpio-cells = <3>;
interrupt-controller;
#interrupt-cells = <3>;
};
};
&spi0 {
status = "okay";
lmg6202ulyt@0 {
compatible = "hitachi,lmg6202ulyt";
reg = <0x0>;
spi-max-frequency = <2000000>;
cs-gpios = <0>, <&pio 0 3 GPIO_ACTIVE_LOW>;
pinctrl-names = "default";
pinctrl-0 = <&lmg6202ulyt_opc>;
irq-gpios = <&pio 0 12 GPIO_ACTIVE_LOW>;
interrupt-parent = <&pio>;
/*interrupts = <GIC_SPI 12 IRQ_TYPE_EDGE_FALLING>;*/
};
};

View File

@ -5,10 +5,14 @@
#include <linux/delay.h>
#include <linux/spi/spi.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/fb.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#define BPP 16
#define BPP 8 // 8
#define PIX_THRESHOLD 0
#define LMGE_GPIO 100
#define LMGE_OTHER 99
@ -20,9 +24,9 @@ MODULE_AUTHOR("Markus Koch");
MODULE_DESCRIPTION("lmg6202ulyt display driver");
MODULE_VERSION("0.1");
static int pix_threshold = 0;
module_param(pix_threshold, int, 0);
MODULE_PARM_DESC(pix_threshold, "Black / White threshold. 0-255");
static char *testparam = "param";
module_param(testparam, charp, S_IRUGO);
MODULE_PARM_DESC(testparam, "A test parameter");
static struct of_device_id lmg6202ulyt_dt_ids[] = {
{ .compatible = "hitachi,lmg6202ulyt", },
@ -30,6 +34,20 @@ static struct of_device_id lmg6202ulyt_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, lmg6202ulyt_dt_ids);
/* IOC Declerations */
//static int device_open(struct inode *, struct file *);
//static int device_release(struct inode *, struct file *);
//static ssize_t device_read(struct file *, char *, size_t, loff_t *);
//static ssize_t device_write(struct file *, const char *, size_t, loff_t *);
//static struct file_operations fops = {
// .read = device_read,
// .write = device_write,
// .open = device_open,
// .release = device_release
//};
/* VIDEO DRIVER Declarations */
static const struct fb_videomode default_mode = {
NULL, 30, 480, 128, /* name, refresh, xres, yres */
39300, /* pixclk */
@ -39,14 +57,208 @@ static const struct fb_videomode default_mode = {
};
struct lmg6202ulyt_priv {
/* SPI dev */
struct spi_device *spi;
struct fb_info info;
/* FB dev */
struct fb_info info;
dma_addr_t fb_phys;
void __iomem *fb_virt;
u32 pseudo_palette[PALETTE_SIZE];
/* IOC */
struct gpio_desc *ioc_irq;
int ioc_irq_number;
struct work_struct ioc_work;
struct gpio_desc *gpio_ioc_cs;
u32 deferred_instructions;
};
/* IOC Code */
#define IOC_DEFERRED_INSTRUCTION_GETKEY (1 << 0)
static irqreturn_t ioc_irq_handler(int irq, void* user_data)
{
struct lmg6202ulyt_priv *priv = user_data;
priv->deferred_instructions |= IOC_DEFERRED_INSTRUCTION_GETKEY;
schedule_work(&priv->ioc_work);
return IRQ_HANDLED;
}
#define SPI_SELECT_IOC(PRIV) {PRIV->spi->chip_select = 1; PRIV->spi->cs_gpio = desc_to_gpio(PRIV->gpio_ioc_cs);}
#define SPI_SELECT_DISPLAY(PRIV) {PRIV->spi->chip_select = 0; PRIV->spi->cs_gpio = -2;}
#define SPI_COMMAND_KEYBOARD_GETKEY 0x20 /* ret: KEY, ... */
/* Bits of the IOC status byte */
#define IOC_STATUS_KEYPRESSES_AVAILABLE (1 << 0)
#define IOC_STATUS_PRINTER_PAUSED (1 << 1)
#define GETKEY_AMOUNT 2
#define SPI_SPEED_READWRITE 10000
#define SPI_SPEED_WRITEONLY 100000
void spi_test_transaction(struct lmg6202ulyt_priv *priv)
{
char tx_buf[256] = "\x01The quick brown fox jumps over the lazy dog.\n"
"abcdefghijklmnopqrstuvwxyz 0123456789\n"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ\n"
"!\"#$%&'()*+,-./:;=?_`|\n\n"
;//{0x01, 0x10, 0x20, 0x30};
char rx_buf[256];
int i;
struct spi_transfer t = {
.tx_buf = tx_buf,
.rx_buf = rx_buf,
.len = strlen(tx_buf),
.speed_hz = SPI_SPEED_WRITEONLY,
};
tx_buf[0] = 0x01;
// for (i =1; i < 120; ++i) {
// tx_buf[i] = (i % 12) + '0';
// if (tx_buf[i] == '9'+1)
// tx_buf[i] = '\r';
// if (tx_buf[i] == '9'+2)
// tx_buf[i] = '\n';
// }
spi_sync_transfer(priv->spi, &t, 1);
printk(KERN_INFO "test done.\n");
}
/* https://linux-kernel-labs.github.io/master/labs/deferred_work.html */
void ioc_defio(struct work_struct *work)
{
#define ioc_status rx_buf[0]
struct lmg6202ulyt_priv *priv;
int i;
char rx_buf[8] = {0, 0, 0, 0}; // Minimum size: GETKEY_AMOUNT + 2
char tx_buf[8] = {0, 0x10, 0x20, 0x30}; // Minimum size: GETKEY_AMOUNT + 2
struct spi_transfer t = {
.tx_buf = tx_buf,
.rx_buf = rx_buf,
.len = 0,
.speed_hz = SPI_SPEED_READWRITE,
};
priv = container_of(work, struct lmg6202ulyt_priv, ioc_work);
//printk(KERN_INFO "lmg: workpriv=%p\n", priv);
//SPI_SELECT_DISPLAY(priv);
priv->spi->chip_select = 1;
priv->spi->cs_gpio = desc_to_gpio(priv->gpio_ioc_cs);
// if (priv->deferred_instructions & IOC_DEFERRED_INSTRUCTION_GETKEY) {
// // Get status + n keys
// tx_buf[0] = SPI_COMMAND_KEYBOARD_GETKEY;
// t.len = GETKEY_AMOUNT + 2;
// if (spi_sync_transfer(priv->spi, &t, 1))
// goto SPI_ERR;
// for (i = 2; (i < GETKEY_AMOUNT + 2) && rx_buf[i]; ++i) {
// printk(KERN_INFO "lmg: Report key: %x\n", rx_buf[i]);
// }
// if (i < GETKEY_AMOUNT + 2) {
// printk(KERN_INFO "lmg: getkey finished.\n");
// ioc_status &= ~IOC_STATUS_KEYPRESSES_AVAILABLE;
// } else {
// printk(KERN_INFO "lmg: Want more keys!!\n");
// }
// }
spi_test_transaction(priv);
if (ioc_status) {
// TODO: Handle non-zero IOC status
// schedule_work(&priv->ioc_work);
}
// struct spi_transfer t = {
// .tx_buf = "HELLO\r\n",
// .len = 7,
// .speed_hz = 1000000,
// };
// if (evil) {
// SPI_SELECT_IOC(priv);
// } else {
// SPI_SELECT_DISPLAY(priv);
// }
// evil = !evil;
// printk(KERN_INFO "cs %d/%d", priv->spi->chip_select, priv->spi->cs_gpio);
// spi_sync_transfer(priv->spi, &t, 1);
// printk(KERN_INFO "lmg: SPI transaction done: %d\n", ret);
return;
SPI_ERR:
printk(KERN_ERR "lmg: IOC SPI transaction failed!\n");
}
static int ioc_probe(struct spi_device *spi,
struct lmg6202ulyt_priv *priv)
{
priv->ioc_irq_number = -1;
printk(KERN_INFO "probe priv=%p", priv);
// priv->ioc_work = devm_kzalloc(&spi->dev, sizeof(struct work_struct),
// GFP_KERNEL);
// if (!priv->ioc_work) {
// dev_err(&spi->dev,
// "IOC defio memory allocation failed\n");
// return -ENOMEM;
// }
INIT_WORK(&priv->ioc_work, ioc_defio);
printk(KERN_INFO "lmg: ioc defio init complete");
priv->gpio_ioc_cs = gpiod_get_index(&spi->dev,
"cs",
1,
GPIOD_OUT_LOW);
priv->ioc_irq = gpiod_get_index(&spi->dev,
"irq",
0,
GPIOD_IN);
if (IS_ERR(priv->ioc_irq)) {
printk(KERN_ERR "lmg: Error obtaining IRQ GPIO");
return -EIO;
}
priv->ioc_irq_number = gpiod_to_irq(priv->ioc_irq);
if (priv->ioc_irq_number < 0) {
printk(KERN_ERR "lmg: Error retrieving IRQ number for GPIO. ret=%d\n", priv->ioc_irq_number);
return -EIO;
}
printk(KERN_INFO "Found IRQ number: %d\n", priv->ioc_irq_number);
if (request_irq(priv->ioc_irq_number, ioc_irq_handler, 0, "ioc", (void*) priv)) {
printk(KERN_ERR "lmg: Can't allocate irq %d\n", priv->ioc_irq_number);
priv->ioc_irq_number = -1;
return -EBUSY;
}
printk(KERN_INFO "IRQ configuration complete\n");
priv->deferred_instructions = 0;
return 0;
}
/* VIDEO DRIVER CODE */
static int lmg6202ulyt_init_var(struct lmg6202ulyt_priv *priv)
{
struct fb_var_screeninfo *var = &priv->info.var;
@ -121,9 +333,7 @@ static int lmg6202ulyt_init_fix(struct lmg6202ulyt_priv *priv)
else
fix->visual = FB_VISUAL_TRUECOLOR;
printk(KERN_INFO "lmg6202ulyt: Using %d bpp (%s).\n",
var->bits_per_pixel,
(var->grayscale ? "grayscale" : "truecolor"));
printk(KERN_INFO "lmg6202ulyt: Using %d bpp.\n", var->bits_per_pixel);
return 0;
}
@ -210,7 +420,6 @@ void lmg6202ulyt_deferred_io(struct fb_info *info, struct list_head *pagelist)
int i;
int blk;
char __iomem *pixel;
char pixval;
int txsz;
spi_write(priv->spi, buf, 5);
@ -221,13 +430,7 @@ void lmg6202ulyt_deferred_io(struct fb_info *info, struct list_head *pagelist)
buf[0] = 1;
for (i = 0; i < BLOCKSIZE * 8; i++) {
#if BPP == 8
pixval = *(pixel);
#else
pixval = *(pixel + 1);
// TODO: We should have more cases here for higher BPPs
#endif
if (pixval > pix_threshold) {
if (*pixel > PIX_THRESHOLD) {
buf[(i / 8) + 1] |= (1 << (7 - (i % 8)));
}
if (pixel >= info->screen_base + info->screen_size - ((info->var.bits_per_pixel) / 8))
@ -248,6 +451,7 @@ static int lmg6202ulyt_probe(struct spi_device *spi)
{
struct lmg6202ulyt_priv *priv = NULL;
struct fb_deferred_io *fbdefio = NULL;
int fbsize;
int ret;
@ -266,6 +470,10 @@ static int lmg6202ulyt_probe(struct spi_device *spi)
priv->info.device = &spi->dev;
priv->info.par = priv;
ioc_probe(spi, priv); // TODO: Handle return value
printk(KERN_INFO "lmg6202ulyt: DEBUG: SKIP DISPLAY INIT\n");
return 0;
printk(KERN_INFO "lmg6202ulyt: vmode\n");
@ -354,7 +562,16 @@ static int lmg6202ulyt_remove(struct spi_device *spi)
struct lmg6202ulyt_priv *priv = spi_get_drvdata(spi);
//unregister_framebuffer(&priv->info);
fb_dealloc_cmap(&priv->info.cmap);
printk(KERN_INFO "DEBUG: SKIPPING framebuffer dealloc");
//fb_dealloc_cmap(&priv->info.cmap); // TODO: reenable
if (priv->ioc_irq_number >= 0)
free_irq(priv->ioc_irq_number, priv);
gpiod_put(priv->ioc_irq);
gpiod_put(priv->gpio_ioc_cs);
return 0;
}

View File

@ -1,2 +1,3 @@
*.raw
*.mem
*.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

View File

@ -1,12 +0,0 @@
# IOC
## Firmware
### General
* All serial links run at 19200 baud
### Bootloader
* The bootloader is a standard Arduino bootloader with the following additions
* Use ASCII command 'X' to enable byass mode. Everything received on UART RX will be forwarded to UART TX until the next reset.
* Use ASCII command 'Y' to set the next unit in the chain into bypass mode.
* Use ASCII command 'Z' to immediately launch into the user firmware
* Use the following avrdude command to program: `avrdude -p m8 -P /dev/ttyUSBx -c arduino -b 19200 -U flash:w:$(TARGET).hex`

View File

@ -1,8 +0,0 @@
*.srec
*.s
*.o
*.map
*.lst
*.hex
*.elf
*.bin

View File

@ -1,440 +0,0 @@
/**********************************************************/
/* Serial Bootloader for Atmel mega8 AVR Controller */
/* */
/* ATmegaBOOT.c */
/* */
/* Copyright (c) 2003, Jason P. Kyle */
/* */
/* Hacked by DojoCorp - ZGZ - MMX - IVR */
/* Hacked by David A. Mellis */
/* Hacked by Markus Koch */
/* */
/* This program is free software; you can redistribute it */
/* and/or modify it under the terms of the GNU General */
/* Public License as published by the Free Software */
/* Foundation; either version 2 of the License, or */
/* (at your option) any later version. */
/* */
/* This program is distributed in the hope that it will */
/* be useful, but WITHOUT ANY WARRANTY; without even the */
/* implied warranty of MERCHANTABILITY or FITNESS FOR A */
/* PARTICULAR PURPOSE. See the GNU General Public */
/* License for more details. */
/* */
/* You should have received a copy of the GNU General */
/* Public License along with this program; if not, write */
/* to the Free Software Foundation, Inc., */
/* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* */
/* Licence can be viewed at */
/* http://www.fsf.org/licenses/gpl.txt */
/* */
/* Target = Atmel AVR m8 */
/**********************************************************/
#include <inttypes.h>
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/eeprom.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#define MAX_TIME_COUNT (F_CPU>>4)
/* SW_MAJOR and MINOR needs to be updated from time to time to avoid warning message from AVR Studio */
#define HW_VER 0x02
#define SW_MAJOR 0x01
#define SW_MINOR 0x12
// AVR-GCC compiler compatibility
// avr-gcc compiler v3.1.x and older doesn't support outb() and inb()
// if necessary, convert outb and inb to outp and inp
#ifndef outb
#define outb(sfr,val) (_SFR_BYTE(sfr) = (val))
#endif
#ifndef inb
#define inb(sfr) _SFR_BYTE(sfr)
#endif
/* defines for future compatibility */
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif
/* Adjust to suit whatever pin your hardware uses to enter the bootloader */
#define eeprom_rb(addr) eeprom_read_byte ((uint8_t *)(addr))
#define eeprom_rw(addr) eeprom_read_word ((uint16_t *)(addr))
#define eeprom_wb(addr, val) eeprom_write_byte ((uint8_t *)(addr), (uint8_t)(val))
#define SIG1 0x1E // Yep, Atmel is the only manufacturer of AVR micros. Single source :(
#define SIG2 0x93
#define SIG3 0x07
#define PAGE_SIZE 0x20U //32 words
void putch(char);
char getch(void);
void getNch(uint8_t);
void byte_response(uint8_t);
void nothing_response(void);
union address_union {
uint16_t word;
uint8_t byte[2];
} address;
union length_union {
uint16_t word;
uint8_t byte[2];
} length;
struct flags_struct {
unsigned eeprom : 1;
unsigned rampz : 1;
} flags;
uint8_t buff[256];
//uint8_t address_high;
uint8_t pagesz=0x80;
uint8_t i;
//uint8_t bootuart0=0,bootuart1=0;
void (*app_start)(void) = 0x0000;
int main(void)
{
uint8_t ch,ch2;
uint16_t w;
/* Disable interrupts */
cli();
/* Pre-init I/O */
DDRB = 0;
DDRC = 0;
DDRD = 0;
PORTB = 0;
PORTC = 0;
PORTD = 0;
asm volatile("nop\n\t");
/* initialize UART(s) depending on CPU defined */
/* m8 */
UBRRH = (((F_CPU/BAUD_RATE)/16)-1)>>8; // set baud rate
UBRRL = (((F_CPU/BAUD_RATE)/16)-1);
UCSRB = (1<<RXEN)|(1<<TXEN); // enable Rx & Tx
UCSRC = (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0); // config USART; 8N1
/*for (i = 0; i < 16; i++) {
_delay_loop_2(0);
}*/
/* forever */
for (;;) {
//if ((inb(UCSRA) & _BV(RXC))){
/* get character from UART */
ch = getch();
/* A bunch of if...else if... gives smaller code than switch...case ! */
/* Hello is anyone home ? */
if (ch == '0') {
nothing_response();
}
/* Request programmer ID */
/* Not using PROGMEM string due to boot block in m128 being beyond 64kB boundry */
/* Would need to selectively manipulate RAMPZ, and it's only 9 characters anyway so who cares. */
else if (ch == '1') {
if (getch() == ' ') {
putch(0x14);
putch('A');
putch('V');
putch('R');
putch(' ');
putch('I');
putch('S');
putch('P');
putch(0x10);
}
}
/* AVR ISP/STK500 board commands DON'T CARE so default nothing_response */
else if (ch == '@') {
ch2 = getch();
if (ch2>0x85) getch();
nothing_response();
}
/* AVR ISP/STK500 board requests */
else if (ch == 'A') {
ch2 = getch();
if (ch2==0x80) byte_response(HW_VER); // Hardware version
else if (ch2==0x81) byte_response(SW_MAJOR); // Software major version
else if (ch2==0x82) byte_response(SW_MINOR); // Software minor version
//else if (ch2==0x98) byte_response(0x03); // Unknown but seems to be required by avr studio 3.56
else byte_response(0x00); // Covers various unnecessary responses we don't care about
}
/* Device Parameters DON'T CARE, DEVICE IS FIXED */
else if (ch == 'B') {
getNch(20);
nothing_response();
}
/* Parallel programming stuff DON'T CARE */
else if (ch == 'E') {
getNch(5);
nothing_response();
}
/* Enter programming mode */
else if (ch == 'P') {
nothing_response();
// FIXME: modified only here by DojoCorp, Mumbai, India, 20050626
//time_count=0; // exted the delay once entered prog.mode
}
/* Leave programming mode */
else if (ch == 'Q') {
nothing_response();
//time_count=MAX_TIME_COUNT_MORATORY; // once the programming is done,
// we should start the application
// but uisp has problems with this,
// therefore we just change the times
// and give the programmer 1 sec to react
}
/* Set to bypass until restart */
else if (ch == 'X') {
while (1) {
if (UCSRA & (1 << RXC)) {
UDR = UDR;
}
}
}
/* Send 'X' via UART TX (set next unit to bypass) */
else if (ch == 'Y') {
putch('X');
continue;
}
/* Start user code NOW */
else if (ch == 'Z') {
app_start();
}
/* Erase device, don't care as we will erase one page at a time anyway. */
else if (ch == 'R') {
nothing_response();
}
/* Set address, little endian. EEPROM in bytes, FLASH in words */
/* Perhaps extra address bytes may be added in future to support > 128kB FLASH. */
/* This might explain why little endian was used here, big endian used everywhere else. */
else if (ch == 'U') {
address.byte[0] = getch();
address.byte[1] = getch();
nothing_response();
}
/* Universal SPI programming command, disabled. Would be used for fuses and lock bits. */
else if (ch == 'V') {
getNch(4);
byte_response(0x00);
}
/* Write memory, length is big endian and is in bytes */
else if (ch == 'd') {
length.byte[1] = getch();
length.byte[0] = getch();
flags.eeprom = 0;
if (getch() == 'E') flags.eeprom = 1;
for (w=0; w<length.word; w++) {
buff[w] = getch(); // Store data in buffer, can't keep up with serial data stream whilst programming pages
}
if (getch() == ' ') {
if (flags.eeprom) { //Write to EEPROM one byte at a time
for(w=0;w<length.word;w++) {
eeprom_wb(address.word,buff[w]);
address.word++;
}
} else { //Write to FLASH one page at a time
cli(); //Disable interrupts, just to be sure
while(bit_is_set(EECR,EEWE)); //Wait for previous EEPROM writes to complete
asm volatile(
"clr r17 \n\t" //page_word_count
"lds r30,address \n\t" //Address of FLASH location (in words)
"lds r31,address+1 \n\t"
"lsl r30 \n\t" //address * 2 -> byte location
"rol r31 \n\t"
"ldi r28,lo8(buff) \n\t" //Start of buffer array in RAM
"ldi r29,hi8(buff) \n\t"
"lds r24,length \n\t" //Length of data to be written (in bytes)
"lds r25,length+1 \n\t"
"sbrs r24,0 \n\t" //Even up an odd number of bytes
"rjmp length_loop \n\t"
"adiw r24,1 \n\t"
"length_loop: \n\t" //Main loop, repeat for number of words in block
"cpi r17,0x00 \n\t" //If page_word_count=0 then erase page
"brne no_page_erase \n\t"
"rcall wait_spm \n\t"
"ldi r16,0x03 \n\t" //Erase page pointed to by Z
"sts %0,r16 \n\t"
"spm \n\t"
"rcall wait_spm \n\t"
"ldi r16,0x11 \n\t" //Re-enable RWW section
"sts %0,r16 \n\t"
"spm \n\t"
"no_page_erase: \n\t"
"ld r0,Y+ \n\t" //Write 2 bytes into page buffer
"ld r1,Y+ \n\t"
"rcall wait_spm \n\t"
"ldi r16,0x01 \n\t" //Load r0,r1 into FLASH page buffer
"sts %0,r16 \n\t"
"spm \n\t"
"inc r17 \n\t" //page_word_count++
"cpi r17,%1 \n\t"
"brlo same_page \n\t" //Still same page in FLASH
"write_page: \n\t"
"clr r17 \n\t" //New page, write current one first
"rcall wait_spm \n\t"
"ldi r16,0x05 \n\t" //Write page pointed to by Z
"sts %0,r16 \n\t"
"spm \n\t"
"rcall wait_spm \n\t"
"ldi r16,0x11 \n\t" //Re-enable RWW section
"sts %0,r16 \n\t"
"spm \n\t"
"same_page: \n\t"
"adiw r30,2 \n\t" //Next word in FLASH
"sbiw r24,2 \n\t" //length-2
"breq final_write \n\t" //Finished
"rjmp length_loop \n\t"
"wait_spm: \n\t"
"lds r16,%0 \n\t" //Wait for previous spm to complete
"andi r16,1 \n\t"
"cpi r16,1 \n\t"
"breq wait_spm \n\t"
"ret \n\t"
"final_write: \n\t"
"cpi r17,0 \n\t"
"breq block_done \n\t"
"adiw r24,2 \n\t" //length+2, fool above check on length after short page write
"rjmp write_page \n\t"
"block_done: \n\t"
"clr __zero_reg__ \n\t" //restore zero register
: "=m" (SPMCR) : "M" (PAGE_SIZE) : "r0","r16","r17","r24","r25","r28","r29","r30","r31");
/* Should really add a wait for RWW section to be enabled, don't actually need it since we never */
/* exit the bootloader without a power cycle anyhow */
}
putch(0x14);
putch(0x10);
}
}
/* Read memory block mode, length is big endian. */
else if (ch == 't') {
length.byte[1] = getch();
length.byte[0] = getch();
if (getch() == 'E') flags.eeprom = 1;
else {
flags.eeprom = 0;
address.word = address.word << 1; // address * 2 -> byte location
}
if (getch() == ' ') { // Command terminator
putch(0x14);
for (w=0; w < length.word; w++) { // Can handle odd and even lengths okay
if (flags.eeprom) { // Byte access EEPROM read
putch(eeprom_rb(address.word));
address.word++;
} else {
if (!flags.rampz) putch(pgm_read_byte_near(address.word));
address.word++;
}
}
putch(0x10);
}
}
/* Get device signature bytes */
else if (ch == 'u') {
if (getch() == ' ') {
putch(0x14);
putch(SIG1);
putch(SIG2);
putch(SIG3);
putch(0x10);
}
}
/* Read oscillator calibration byte */
else if (ch == 'v') {
byte_response(0x00);
}
} /* end of forever loop */
}
void putch(char ch)
{
/* m8 */
while (!(inb(UCSRA) & _BV(UDRE)));
outb(UDR,ch);
}
char getch(void)
{
/* m8 */
uint32_t count = 0;
while(!(inb(UCSRA) & _BV(RXC))) {
/* HACKME:: here is a good place to count times*/
count++;
if (count > MAX_TIME_COUNT)
app_start();
}
return (inb(UDR));
}
void getNch(uint8_t count)
{
uint8_t i;
for(i=0;i<count;i++) {
getch(); // need to handle time out
}
}
void byte_response(uint8_t val)
{
if (getch() == ' ') {
putch(0x14);
putch(val);
putch(0x10);
}
}
void nothing_response(void)
{
if (getch() == ' ') {
putch(0x14);
putch(0x10);
}
}

View File

@ -4,5 +4,3 @@
modules.order
Module.symvers
*.pro.user
.*
*.a

View File

@ -1,12 +1,12 @@
obj-m := lw35ioc.o
KDIR := ~/projects/linux/opi-current
obj-m := lw35-ioc.o
KDIR := ~/projects/arm-linux/current
PWD := $(shell pwd)
default: lw35ioc.ko
lw35ioc.ko: lw35ioc.c
$(MAKE) -C $(KDIR) M=$(PWD)
default: lw35-ioc.ko
lw35-ioc.ko: lw35-ioc.c
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
deploy: lw35ioc.ko
scp $< markus@opi:/home/markus/projects/lw35/deploy/
deploy: lw35-ioc.ko
scp $< markus@opi:/home/markus/lw35-ioc/deploy
clean:
rm -f ./*.o ./*.ko ./*.mod.c modules.order Module.symvers

View File

@ -0,0 +1,28 @@
/*
Reading: https://www.kernel.org/doc/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
*/
&spi1 {
status = "okay";
lw35ioc@0 {
compatible = "brother,lw35ioc";
reg = <0x0>;
spi-max-frequency = <2000000>;
pinctrl-names = "default";
pinctrl-0 = <&lw35ioc>;
data-gpios = <&pio 0 7 GPIO_ACTIVE_HIGH>; /* TODO: get real IO num */
interrupt-parent = <&pio>;
interrupts = <52 2>;
};
};
&pio {
lmg6202ulyt_opc: lmg6202ulyt_pins {
pins = "PA7";
function = "gpio_out";
interrupt-controller;
#interrupt-cells = <1>;
};
};

View File

@ -1,41 +0,0 @@
diff --git a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
index c8201e79dff3..5407742acad6 100644
--- a/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
+++ b/arch/arm/boot/dts/sun8i-h3-orangepi-pc.dts
@@ -210,12 +210,22 @@ &uart0 {
status = "okay";
};
+&pio {
+ lw35ioc_pins: lw35ioc-pins {
+ pins = "PA10";
+ function = "gpio_out";
+ };
+};
+
&uart1 {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&uart1_pins>;
lw35ioc@0 {
compatible = "brother,lw35";
+ pinctrl-names = "default";
+ pinctrl-0 = <&lw35ioc_pins>;
+ rst-gpios = <&pio 0 10 GPIO_ACTIVE_LOW>;
};
};
@@ -242,3 +252,13 @@ &usbphy {
/* VBUS on USB host ports are always on */
status = "okay";
};
+
+&spi0 {
+ status = "okay";
+ lmg6202ulyt@0 {
+ compatible = "hitachi,lmg6202ulyt";
+ reg = <0x0>;
+ spi-max-frequency = <2000000>;
+ cs-gpios = <0>, <&pio 0 3 GPIO_ACTIVE_LOW>;
+ };
+};

View File

@ -0,0 +1,78 @@
#include <linux/init.h>
#include <linux/dma-mapping.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/spi/spi.h>
#include <linux/of_device.h>
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
/*
* irq in general: https://notes.shichao.io/lkd/ch7/
* raspi irqs: http://morethanuser.blogspot.com/2013/04/raspberry-pi-gpio-interrupts-in-kernel.html
* kdoc devtree irq: https://www.kernel.org/doc/Documentation/devicetree/bindings/interrupt-controller/interrupts.txt
* GPIOD doc (including irq): https://www.kernel.org/doc/Documentation/gpio/consumer.txt
*/
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Markus Koch");
MODULE_DESCRIPTION("LW35 I/O Controller Driver");
MODULE_VERSION("0.1");
static char *testparam = "param";
module_param(testparam, charp, S_IRUGO);
MODULE_PARM_DESC(testparam, "A test parameter");
static struct of_device_id lw35ioc_dt_ids[] = {
{ .compatible = "brother,lw35", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, lw35ioc_dt_ids);
struct lw35ioc_priv {
struct spi_device *spi;
// USER VARS HERE
};
static int lw35ioc_probe(struct spi_device *spi)
{
struct lw35ioc_priv *priv = NULL;
printk(KERN_INFO "lw35ioc: probe\n");
priv = devm_kzalloc(&spi->dev,
sizeof(struct lw35ioc_priv),
GFP_KERNEL);
if (!priv)
return -ENOMEM;
spi_set_drvdata(spi, priv);
priv->spi = spi;
printk(KERN_INFO "lw35ioc: Loaded driver\n");
return 0;
// Error handlers go here
}
static int lw35ioc_remove(struct spi_device *spi)
{
struct lw35ioc_priv *priv = spi_get_drvdata(spi);
return 0;
}
static struct spi_driver lw35ioc_driver = {
.probe = lw35ioc_probe,
.remove = lw35ioc_remove,
.driver = {
.name = "lw35ioc",
.owner = THIS_MODULE,
.of_match_table = lw35ioc_dt_ids,
},
};
module_spi_driver(lw35ioc_driver);

View File

@ -6,4 +6,4 @@ CONFIG -= qt
INCLUDEPATH += /home/markus/projects/arm-linux/current/include
SOURCES += \
lw35ioc.c
lw35-ioc.c

View File

@ -1,744 +0,0 @@
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/serdev.h>
#include <linux/types.h>
#include <linux/input.h>
#include <linux/gpio/consumer.h>
#include <linux/uaccess.h>
#include <linux/sched.h>
#include <linux/poll.h>
#include <linux/circ_buf.h>
// #define ENABLE_DEBUG ENABLE_DEBUG
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Markus Koch");
MODULE_DESCRIPTION("LW-35 I/O Controller Driver");
MODULE_VERSION("0.1");
static int debug_level = 0;
module_param(debug_level, int, 0);
MODULE_PARM_DESC(debug_level, "Debug level");
/* Only for chrdev... man they really suck! */
static struct serdev_device *static_serdev = NULL;
static DECLARE_WAIT_QUEUE_HEAD(wq);
void pbuf_work_handler(struct work_struct *work);
DECLARE_WORK(pbuf_work, pbuf_work_handler);
static DEFINE_SPINLOCK(printer_status_lock);
static struct of_device_id lw35ioc_dt_ids[] = {
{ .compatible = "brother,lw35", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, lw35ioc_dt_ids);
/* Chardev */
#define DEVICE_NAME "lw35"
#define CLASS_NAME "lw35ioc"
/* Only used for initialization, not for actual keycode mapping */
static int keycode_map[] = {
KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J,
KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T,
KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z,
KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9,
KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9,
KEY_F10, KEY_F11, KEY_F12,
KEY_UP, KEY_DOWN, KEY_RIGHT, KEY_LEFT, KEY_PAGEUP, KEY_PAGEDOWN,
KEY_102ND, KEY_INSERT, KEY_HOME, KEY_END, KEY_PRINT,
KEY_CAPSLOCK, KEY_LEFTCTRL, KEY_LEFTSHIFT, KEY_LEFTALT, KEY_TAB,
KEY_MINUS, KEY_COMMA, KEY_SEMICOLON, KEY_RIGHTBRACE, KEY_LEFTBRACE,
KEY_GRAVE, KEY_SPACE, KEY_EQUAL, KEY_DOT, KEY_SLASH, KEY_APOSTROPHE,
KEY_BACKSLASH,
KEY_DELETE, KEY_ESC, KEY_ENTER, KEY_BACKSPACE,
KEY_SYSRQ
};
enum lw35ioc_state {PASSIVE = 0, INIT, PROG_KBD, PROG_PRI, BYPASS, ACTIVE, STATE_COUNT};
enum lw35ioc_packet_state {SYNC, TYPE, KEYBOARD, PRINTER};
struct lw35ioc_packet {
enum lw35ioc_packet_state state;
int payload_offset;
};
struct lw35ioc_chardev {
int major_number;
struct class* class;
struct device* device;
int open_count;
};
struct lw35ioc_printer_status{
int buffer_free;
int status;
int rx_count;
int reserved1;
};
#define UART_BUF_SIZE 256
#define PBUF_SIZE 256
struct lw35ioc_priv {
struct serdev_device *serdev;
struct input_dev *input_dev;
struct gpio_desc *gpio_rst; /* GPIO to reset both AVRs */
struct lw35ioc_chardev chardev;
struct lw35ioc_printer_status printer_status_temp;
struct lw35ioc_printer_status printer_status;
char uart_buf_rx[UART_BUF_SIZE];
char *uart_buf_rx_rd;
char *uart_buf_rx_wr;
char pbuf[PBUF_SIZE];
unsigned long pbuf_tail;
unsigned long pbuf_head;
enum lw35ioc_state state;
struct lw35ioc_packet packet;
u8 tx_count;
u8 tx_count_resync;
};
static int lw35ioc_process_buf(struct serdev_device *serdev,
const unsigned char *data,
size_t count)
{
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
unsigned char c;
int ev;
int i;
unsigned long lock_flags;
#ifdef ENABLE_DEBUG
dev_info(&serdev->dev, "IRQ.\n");
#endif
for (i = 0; i < count; ++i) {
c = data[i];
#ifdef ENABLE_DEBUG
dev_info(&serdev->dev, " RX [%d]: %02x\n", priv->packet.state, c);
#endif
switch (priv->packet.state) {
case SYNC:
if (c == 0xFF)
priv->packet.state = TYPE;
break;
case TYPE:
if (c == 0x55)
priv->packet.state = KEYBOARD;
else if (c == 0xAA)
priv->packet.state = PRINTER;
else
priv->packet.state = SYNC;
priv->packet.payload_offset = 0;
break;
case KEYBOARD:
if (c > 127) {
c -= 128;
ev = 1;
} else {
ev = 0;
}
input_report_key(priv->input_dev, c, ev);
input_sync(priv->input_dev);
priv->packet.state = SYNC;
break;
case PRINTER:
switch (priv->packet.payload_offset) {
case 0: /* Status */
priv->printer_status_temp.status = (int)c;
break;
case 1: /* Buffer status */
priv->printer_status_temp.buffer_free = (int)c;
break;
case 2: /* Reserved */
priv->printer_status_temp.rx_count = (int)c;
break;
case 3: /* Reserved */
priv->printer_status_temp.reserved1 = (int)c;
dev_info(&serdev->dev,
"New printer status. status=0x%02X buffer_free=0x%02X rx_count=0x%02X reserved=0x%02X.\n",
priv->printer_status_temp.status,
priv->printer_status_temp.buffer_free,
priv->printer_status_temp.rx_count,
priv->printer_status_temp.reserved1);
if (priv->printer_status_temp.status == 0xFF) {
dev_err(&serdev->dev,
"HARDFAULT in printer firmware! Reset required.\n");
}
spin_lock_irqsave(&printer_status_lock, lock_flags);
memcpy(&priv->printer_status,
&priv->printer_status_temp,
sizeof(priv->printer_status));
spin_unlock_irqrestore(&printer_status_lock, lock_flags);
if (priv->printer_status_temp.buffer_free > 0)
schedule_work(&pbuf_work);
priv->packet.state = SYNC;
break;
default:
break;
}
priv->packet.payload_offset++;
break;
}
}
return i;
}
static int lw35ioc_receive_buf(struct serdev_device *serdev,
const unsigned char *data,
size_t count)
{
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
int i;
switch (priv->state) {
case ACTIVE:
return lw35ioc_process_buf(serdev, data, count);
break;
case PASSIVE:
break;
default:
/* Pass data directly to chardev */
for (i = 0; i < count; ++i) {
#ifdef ENABLE_DEBUG
dev_info(&serdev->dev, " RX [PSV]: %02x\n", data[i]);
#endif
*(priv->uart_buf_rx_wr) = data[i];
if (priv->uart_buf_rx_wr == priv->uart_buf_rx + UART_BUF_SIZE - 1)
priv->uart_buf_rx_wr = priv->uart_buf_rx;
else
priv->uart_buf_rx_wr++;
if (priv->uart_buf_rx_rd == priv->uart_buf_rx_wr) {
dev_err(&serdev->dev, "UART RX buffer overflow.\n");
}
}
wake_up_interruptible(&wq);
}
return count; /* Pretend we read all data */
}
static void lw35ioc_write_wakeup(struct serdev_device *serdev)
{
// schedule work here
}
static struct serdev_device_ops lw35ioc_serdev_ops = {
.receive_buf = lw35ioc_receive_buf,
.write_wakeup = lw35ioc_write_wakeup,
};
static void lw35ioc_set_hw_reset(struct serdev_device *serdev,
int reset_active)
{
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
gpiod_set_value(priv->gpio_rst, !!reset_active);
}
static void lw35ioc_reset_ioc_hw(struct serdev_device *serdev)
{
dev_info(&serdev->dev, "Resetting IOC...\n");
lw35ioc_set_hw_reset(serdev, 1);
usleep_range(90000, 100000);
lw35ioc_set_hw_reset(serdev, 0);
usleep_range(90000, 100000);
}
/* Chardev */
static int lw35ioc_chardev_open(struct inode *inodep, struct file *filep) {
struct serdev_device *serdev = static_serdev;
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
filep->private_data = serdev;
if (!priv->chardev.open_count) {
dev_info(&serdev->dev, "Opened chardev.\n");
switch (priv->state) {
case PROG_KBD:
lw35ioc_reset_ioc_hw(serdev);
serdev_device_write(serdev, "X", 1, 0);
dev_info(&serdev->dev, "Put ioc into programming mode: keyboard.\n");
break;
case PROG_PRI:
lw35ioc_reset_ioc_hw(serdev);
serdev_device_write(serdev, "Y", 1, 0);
dev_info(&serdev->dev, "Put ioc into programming mode: printer.\n");
break;
case BYPASS:
lw35ioc_reset_ioc_hw(serdev);
serdev_device_write(serdev, "XX", 2, 0);
dev_info(&serdev->dev, "Put ioc into bypass mode.\n");
break;
case INIT:
case PASSIVE:
// TODO: locks
priv->pbuf_tail = 0;
priv->pbuf_head = 0;
lw35ioc_reset_ioc_hw(serdev);
usleep_range(2100000, 2210000);
dev_info(&serdev->dev, "Put ioc into active mode.\n");
if (priv->state == INIT) {
serdev_device_write(serdev, "\xFF", 1, 0);
priv->state = ACTIVE;
}
break;
case ACTIVE:
/* Don't do anything when active */
break;
default:
break;
}
} else {
dev_err(&serdev->dev, "Rejected. Device may only be opened once.\n");
//return -EBUSY; // TODO
}
priv->tx_count_resync = 1;
priv->chardev.open_count++;
return 0;
}
static ssize_t lw35ioc_chardev_read(struct file *filep, char *buffer, size_t len, loff_t *offset) {
struct serdev_device *serdev = filep->private_data;
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
int error_count;
int available;
available = priv->uart_buf_rx_wr - priv->uart_buf_rx_rd;
if (available < 0)
available = 1;
if (!available) { /* Wait for data to become available */
wait_event_interruptible(wq, priv->uart_buf_rx_rd != priv->uart_buf_rx_wr);
available = priv->uart_buf_rx_wr - priv->uart_buf_rx_rd;
if (available < 0)
available = 1; /* TODO: We should calculate the remaining block until wraparound here... */
if (!available)
return -EAGAIN;
}
if (available < len)
len = available;
error_count = copy_to_user(buffer, priv->uart_buf_rx_rd, len);
len -= error_count;
priv->uart_buf_rx_rd += len;
if (priv->uart_buf_rx_rd >= priv->uart_buf_rx + UART_BUF_SIZE) {
priv->uart_buf_rx_rd -= UART_BUF_SIZE;
}
if (error_count == 0) {
return len;
} else {
dev_err(&serdev->dev, "Failed to read %d characters to chardev.\n",
error_count);
return -EFAULT;
}
}
char msg[256]; // TODO
static ssize_t lw35ioc_chardev_write(struct file *filep, const char *buffer, size_t len, loff_t *offset) {
struct serdev_device *serdev = filep->private_data;
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
unsigned long tail;
int i;
int ret;
switch (priv->state) {
case ACTIVE:
/* Put data into pbuf */
// TODO: spinlock
if (CIRC_SPACE(priv->pbuf_head, READ_ONCE(priv->pbuf_tail), PBUF_SIZE) < 1) {
dev_err(&serdev->dev, "chdev write: Waiting for space...\n");
if (ret = (wait_event_interruptible(wq, CIRC_SPACE(priv->pbuf_head, priv->pbuf_tail, PBUF_SIZE) >= 1))) { // TODO: Accessing pbuf_tail without any protection... this might be bad?
dev_err(&serdev->dev,
"chdev write: device closed while waiting. ret: %d\n",
ret);
// TODO: This is not proper handling of this I guess...
return len;
}
dev_err(&serdev->dev, "chdev write: done waiting...\n");
}
tail = READ_ONCE(priv->pbuf_tail);
for (i = 0; i < len; ++i) { // TODO: Block copy would be faster...
if (CIRC_SPACE(priv->pbuf_head, tail, PBUF_SIZE) >= 1) {
ret = copy_from_user(priv->pbuf + priv->pbuf_head,
buffer + i,
1);
if (ret) {
dev_err(&serdev->dev, "chdev write: copy_from_user failed (%d).\n",
ret);
i = len - 1;
}
smp_store_release(&(priv->pbuf_head),
(priv->pbuf_head + 1) & (PBUF_SIZE - 1));
} else {
dev_warn(&serdev->dev, "chdev write: ring buffer full.\n");
break;
}
}
len = i;
schedule_work(&pbuf_work);
dev_info(&serdev->dev,
"Copied %d bytes to FIFO (FIFO free: %d)",
len, CIRC_SPACE(priv->pbuf_head, tail, PBUF_SIZE));
break;
case PASSIVE:
len = -EBUSY; // TODO: Can I do this?
break;
default: /* Pass-through */
if (len > 256) {
len = 256;
}
copy_from_user(msg, buffer, len); // TODO: Return value
serdev_device_write_buf(serdev, msg, len);
}
return len;
}
static int lw35ioc_chardev_release(struct inode *inodep, struct file *filep){
struct serdev_device *serdev = filep->private_data;
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
priv->chardev.open_count--;
dev_info(&serdev->dev, "Device successfully closed\n");
return 0;
}
#define IOCTL_SET_MODE 42
static long lw35ioc_chardev_ioctl(struct file *filep, unsigned int cmd,
unsigned long arg)
{
struct serdev_device *serdev = filep->private_data;
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
switch (cmd) {
case IOCTL_SET_MODE:
if (arg >= STATE_COUNT || arg < 0) {
dev_err(&serdev->dev, "Invalid driver mode: %lu", arg);
return -1;
}
priv->state = arg;
dev_info(&serdev->dev, "Switched driver mode to: %lu. Will be applied with next open().\n", arg);
break;
default:
dev_info(&serdev->dev, "Ignoring IOCTL %u(%lu)\n", cmd, arg);
break;
}
return 0;
}
__poll_t poll(struct file *filep, struct poll_table_struct *ptab)
{
struct serdev_device *serdev = filep->private_data;
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
poll_wait(filep, &wq, ptab);
if (priv->uart_buf_rx_wr != priv->uart_buf_rx_rd)
return EPOLLIN | EPOLLRDNORM;
return 0;
}
#define PRINTER_READY_MASK (0b00011111)
int printer_ready_for_data(struct lw35ioc_printer_status printer_status)
{
return ((printer_status.status & PRINTER_READY_MASK) == PRINTER_READY_MASK);
}
void pbuf_work_handler(struct work_struct *work)
{
// TODO: get private data using container_of(): https://linux-kernel-labs.github.io/master/labs/deferred_work.html
struct serdev_device *serdev = static_serdev; // Not cool, but whatever...
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
unsigned long head;
unsigned long tail;
unsigned long lock_flags;
int bsize = 0;
int i;
int locked = 0;
while (1) {
// TODO: We are the only consumer, so we should be fine without a spinlock, right?
head = smp_load_acquire(&priv->pbuf_head);
tail = priv->pbuf_tail;
bsize = CIRC_CNT(head, tail, PBUF_SIZE);
//dev_info(&serdev->dev, "CIRC CNT=%d\n", bsize);
if (bsize == 0)
break;
spin_lock_irqsave(&printer_status_lock, lock_flags);
locked = 1;
if (!printer_ready_for_data(priv->printer_status)) {
dev_warn(&serdev->dev, "Cannot transmit data to device. Device is not ready.\n");
break;
}
if (priv->tx_count_resync) {
priv->tx_count = priv->printer_status.rx_count;
priv->tx_count_resync = 0;
}
if (priv->printer_status.rx_count != priv->tx_count) {
dev_info(&serdev->dev, "Not transmitting any data to device because rx is unconfirmed [tx=%d, rx=%d].\n",
priv->tx_count, priv->printer_status.rx_count);
break;
}
if (bsize > priv->printer_status.buffer_free)
bsize = priv->printer_status.buffer_free;
if (bsize > CIRC_CNT_TO_END(head, tail, PBUF_SIZE))
bsize = CIRC_CNT_TO_END(head, tail, PBUF_SIZE);
if (bsize > priv->printer_status.buffer_free - 20)
bsize = priv->printer_status.buffer_free - 20; // TODO: Bug workaround
dev_info(&serdev->dev, "TX %d of %d bytes [%d bytes free on device].\n",
bsize,
CIRC_CNT(head, tail, PBUF_SIZE),
priv->printer_status.buffer_free);
priv->printer_status.buffer_free-=bsize;
spin_unlock_irqrestore(&printer_status_lock, lock_flags);
locked = 0;
if (bsize == 0) {
dev_warn(&serdev->dev, "Cannot transmit data to device. Device buffer is full.\n");
break;
}
priv->tx_count += bsize;
serdev_device_write_buf(serdev,
priv->pbuf + tail,
bsize);
#ifdef ENABLE_DEBUG
for (i=0; i<bsize; ++i) {
dev_info(&serdev->dev,
"UART TX: %c\n",
priv->pbuf[tail + i]);
}
#endif
smp_store_release(&priv->pbuf_tail,
(tail + bsize) & (PBUF_SIZE - 1));
}
if (locked)
spin_unlock_irqrestore(&printer_status_lock, lock_flags);
wake_up_interruptible(&wq); // There's some space available in the FIFO now, so wake up chardev write
}
static struct file_operations fops =
{
.open = lw35ioc_chardev_open,
.read = lw35ioc_chardev_read,
.write = lw35ioc_chardev_write,
.release = lw35ioc_chardev_release,
.unlocked_ioctl = lw35ioc_chardev_ioctl,
.poll = poll,
};
static int lw35ioc_cdev_init(struct serdev_device *serdev)
{
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
priv->chardev.open_count = 0;
// Try to dynamically allocate a major number for the device
priv->chardev.major_number = register_chrdev(0, DEVICE_NAME, &fops);
if (priv->chardev.major_number < 0) {
dev_err(&serdev->dev, "Failed to register a major number\n");
return priv->chardev.major_number;
}
dev_info(&serdev->dev, "Registered correctly with major number %d\n", priv->chardev.major_number);
// Register the device class
priv->chardev.class = class_create(THIS_MODULE, CLASS_NAME);
if (IS_ERR(priv->chardev.class)) {
unregister_chrdev(priv->chardev.major_number, DEVICE_NAME);
dev_err(&serdev->dev, "Failed to register device class\n");
return PTR_ERR(priv->chardev.class);
}
dev_info(&serdev->dev, "Device class registered correctly\n");
// Register the device driver
priv->chardev.device = device_create(priv->chardev.class, NULL, MKDEV(priv->chardev.major_number, 0), NULL, DEVICE_NAME);
if (IS_ERR(priv->chardev.device)) {
class_destroy(priv->chardev.class);
unregister_chrdev(priv->chardev.major_number, DEVICE_NAME);
dev_err(&serdev->dev, "Failed to create the device\n");
return PTR_ERR(priv->chardev.device);
}
dev_info(&serdev->dev, "Device class created correctly\n");
return 0;
}
static int lw35ioc_probe(struct serdev_device *serdev)
{
struct lw35ioc_priv *priv = NULL;
int ret = 0;
int i;
u32 speed = 19200;
struct input_dev *input_dev;
printk(KERN_INFO "lw35ioc: probe\n");
if (static_serdev) {
printk(KERN_ERR "lw35ioc: Can only be loaded once.\n");
goto fail_multicheck;
}
/* Allocate memory */
priv = devm_kzalloc(&serdev->dev,
sizeof(struct lw35ioc_priv),
GFP_KERNEL);
if (!priv) {
printk(KERN_ERR "lw35ioc: Not enough memory.\n");
return -ENOMEM;
}
priv->state = ACTIVE; // TODO: This should be passive
priv->uart_buf_rx_rd = priv->uart_buf_rx;
priv->uart_buf_rx_wr = priv->uart_buf_rx;
priv->pbuf_tail = 0;
priv->pbuf_head = 0;
priv->printer_status.buffer_free = 0;
priv->printer_status.status = 0;
priv->tx_count = 0;
priv->tx_count_resync = 1;
priv->serdev = serdev;
static_serdev = serdev;
priv->packet.state = SYNC;
serdev_device_set_drvdata(serdev, priv);
/* Register input device */
input_dev = devm_input_allocate_device(&serdev->dev);
if (!input_dev) {
dev_err(&serdev->dev, "Unable to allocate input device.\n");
return -ENOMEM;
}
priv->input_dev = input_dev;
input_dev->name = "lw35ioc";
input_dev->phys = "lw35ioc/input1";
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(EV_REP, input_dev->evbit);
for (i = 0; i < ARRAY_SIZE(keycode_map); i++)
__set_bit(keycode_map[i], input_dev->keybit);
ret = input_register_device(input_dev);
if (ret) {
dev_err(&serdev->dev, "Unable to register input device.\n");
goto fail_input;
}
serdev_device_set_client_ops(serdev, &lw35ioc_serdev_ops);
ret = serdev_device_open(serdev);
if (ret) {
dev_err(&serdev->dev, "Unable to open device.\n");
goto fail_serdev;
}
speed = serdev_device_set_baudrate(serdev, speed);
dev_info(&serdev->dev, "Using baudrate: %u\n", speed);
/* Register GPIO */
priv->gpio_rst = gpiod_get_index(&serdev->dev,
"rst",
0,
GPIOD_OUT_HIGH);
/* Register character device */
ret = lw35ioc_cdev_init(serdev);
if (ret) {
dev_err(&serdev->dev, "Unable to initialize character device.\n");
goto fail_gpio;
}
if (IS_ERR(priv->gpio_rst)) {
dev_err(&serdev->dev, "Unable to get reset GPIO.\n");
ret = -ENODEV; /* TODO */
goto fail_gpio;
}
lw35ioc_reset_ioc_hw(serdev);
dev_info(&serdev->dev, "Loaded driver.\n");
return 0;
fail_gpio:
fail_serdev:
input_unregister_device(input_dev);
fail_input:
devm_kfree(&serdev->dev, input_dev);
fail_multicheck:
return ret;
}
static void lw35ioc_remove(struct serdev_device *serdev)
{
struct lw35ioc_priv *priv = serdev_device_get_drvdata(serdev);
dev_info(&serdev->dev, "remove\n");
dev_info(&serdev->dev, " cdev class: %p\n", priv->chardev.class);
device_destroy(priv->chardev.class, MKDEV(priv->chardev.major_number, 0));
dev_info(&serdev->dev, "unreg\n");
class_unregister(priv->chardev.class);
dev_info(&serdev->dev, "destroy: SKIP\n");
//class_destroy(priv->chardev.class);
dev_info(&serdev->dev, "unreg-dev\n");
unregister_chrdev(priv->chardev.major_number, DEVICE_NAME);
dev_info(&serdev->dev, " gpio rst: %p\n", priv->gpio_rst);
dev_info(&serdev->dev, " serdev: %p\n", priv->serdev);
dev_info(&serdev->dev, " input dev: %p\n", priv->input_dev);
lw35ioc_set_hw_reset(serdev, 1);
usleep_range(90000, 100000); // Make sure the reset actually happens
gpiod_put(priv->gpio_rst);
serdev_device_close(priv->serdev);
input_unregister_device(priv->input_dev);
dev_info(&serdev->dev, "done.\n");
return;
}
static struct serdev_device_driver lw35ioc_driver = {
.probe = lw35ioc_probe,
.remove = lw35ioc_remove,
.driver = {
.name = "lw35ioc",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(lw35ioc_dt_ids),
},
};
module_serdev_device_driver(lw35ioc_driver);

View File

@ -1,5 +0,0 @@
cmake_minimum_required(VERSION 3.5)
project(lw35-tool LANGUAGES C)
add_executable(lw35-tool main.c)

View File

@ -1,78 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <stropts.h>
#include <sys/stat.h>
#include <fcntl.h>
#define IOCTL_SET_MODE 42
enum lw35ioc_state {PASSIVE = 0, INIT, PROG_KBD, PROG_PRI, BYPASS, ACTIVE, STATE_COUNT};
int f;
static void help(int argc, char *argv[])
{
fprintf(stderr,
"usage: %s <command>\n\n"
" command: set-mode <mode>\n"
" mode: passive, active, rfu-kbd, rfu-pri, bypass\n",
argv[0]);
}
static int set_mode(int argc, char *argv[])
{
int mode = -1;
if (argc < 3) {
help(argc, argv);
return 10;
}
if (!strcmp(argv[2], "passive"))
mode = PASSIVE;
else if (!strcmp(argv[2], "rfu-kbd"))
mode = PROG_KBD;
else if (!strcmp(argv[2], "rfu-pri"))
mode = PROG_PRI;
else if (!strcmp(argv[2], "bypass"))
mode = BYPASS;
else if (!strcmp(argv[2], "active"))
mode = ACTIVE;
else if (!strcmp(argv[2], "init"))
mode = INIT;
if (mode == -1) {
fprintf(stderr, "Error: Invalid mode.\n");
return 10;
}
ioctl(f, IOCTL_SET_MODE, mode);
return 0;
}
int main(int argc, char *argv[])
{
int ret;
if (argc < 2) {
help(argc, argv);
return 1;
}
f = open("/dev/lw35", O_RDWR);
if (f == -1) {
fprintf(stderr, "Error opening lw35ioc device.\n");
return 3;
}
if (!strcmp(argv[1], "set-mode")) {
ret = set_mode(argc, argv);
} else {
fprintf(stderr, "Unknown command.\n");
ret = 2;
}
close(f);
return ret;
}

View File

@ -1,8 +0,0 @@
*.srec
*.s
*.o
*.map
*.lst
*.hex
*.elf
*.bin

View File

@ -1,88 +0,0 @@
# Makefile for ATmegaBOOT
# E.Lins, 2004-10-14
# program name should not be changed...
PROGRAM = main
PRODUCT=atmega8
# enter the parameters for the UISP isp tool
ISPPARAMS = -dprog=stk500 -dserial=$(SERIAL) -dspeed=115200
#DIRAVR = /usr/local/avr
DIRAVRBIN = $(DIRAVR)/bin
DIRAVRUTILS = $(DIRAVR)/utils/bin
DIRINC = $(DIRAVR)/include
DIRLIB = $(DIRAVR)/avr/lib
MCU_TARGET = atmega8
LDSECTION = --section-start=.text=0x1c00
FUSE_L = 0xdf
FUSE_H = 0xca
ISPFUSES = $(DIRAVRBIN)/uisp -dpart=ATmega8 $(ISPPARAMS) --wr_fuse_l=$(FUSE_L) --wr_fuse_h=$(FUSE_H)
ISPFLASH = $(DIRAVRBIN)/uisp -dpart=ATmega8 $(ISPPARAMS) --erase --upload if=$(PROGRAM).hex -v
OBJ = $(PROGRAM).o
OPTIMIZE = -Os -funsigned-char -funsigned-bitfields -fno-inline-small-functions
DEFS = -DF_CPU=8000000 -DBAUD_RATE=19200
LIBS =
CC = $(DIRAVRBIN)/avr-gcc
# Override is only needed by avr-lib build system.
override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) -D$(PRODUCT) $(DEFS) -I$(DIRINC)
override LDFLAGS = -Wl,-Map,$(PROGRAM).map,$(LDSECTION)
OBJCOPY = $(DIRAVRBIN)/avr-objcopy
OBJDUMP = $(DIRAVRBIN)/avr-objdump
SIZE = $(DIRAVRBIN)/avr-size
all: $(PROGRAM).elf lst text asm size
isp: $(PROGRAM).hex
$(ISPFUSES)
$(ISPFLASH)
$(PROGRAM).elf: $(OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
clean:
rm -rf *.s
rm -rf *.o *.elf
rm -rf *.lst *.map
asm: $(PROGRAM).s
%.s: %.c
$(CC) -S $(CFLAGS) -g1 $^
lst: $(PROGRAM).lst
%.lst: %.elf
$(OBJDUMP) -h -S $< > $@
size: $(PROGRAM).hex
$(SIZE) $^
# Rules for building the .text rom images
text: hex bin srec
hex: $(PROGRAM).hex
bin: $(PROGRAM).bin
srec: $(PROGRAM).srec
%.hex: %.elf
$(OBJCOPY) -j .text -j .data -O ihex $< $@
%.srec: %.elf
$(OBJCOPY) -j .text -j .data -O srec $< $@
%.bin: %.elf
$(OBJCOPY) -j .text -j .data -O binary $< $@

View File

@ -1 +0,0 @@
../../ioc/avr-bootloader/main.c

View File

@ -1,9 +1,8 @@
MCU=atmega8
PDEV=/dev/ttyUSB1
CFLAGS=-g -Wall -mcall-prologues -mmcu=$(MCU) -Os -DF_CPU=8000000
LDFLAGS=-Wl,-gc-sections -Wl,-relax
CC=avr-gcc
TARGET=fw_keyboard
TARGET=main
OBJECT_FILES=main.o
all: $(TARGET).hex
@ -17,12 +16,9 @@ clean:
%.obj: $(OBJECT_FILES)
$(CC) $(CFLAGS) $(OBJECT_FILES) $(LDFLAGS) -o $@
rfu: $(TARGET).hex
scp $< markus@opi:/home/markus/projects/lw35/deploy/
ssh root@opi 'lw35-tool set-mode rfu-kbd; avrdude -p atmega8 -P /dev/lw35 -c arduino -b 19200 -U flash:w:/home/markus/projects/lw35/deploy/$<'
program: $(TARGET).hex
avrdude -p $(MCU) -P $(PDEV) -c arduino -b 19200 -U flash:w:$(TARGET).hex
avrdude -p $(MCU) -c usbasp -U flash:w:$(TARGET).hex
#avrdude -p $(MCU) -P /dev/ttyUSB1 -c arduino -b 57600 -U flash:w:$(TARGET).hex
fuse:
avrdude -p m8 -c usbasp -U lfuse:w:0xe4:m -U hfuse:w:0xd9:m

View File

@ -7,5 +7,3 @@ INCLUDEPATH += /usr/avr/include
SOURCES += \
main.c
DEFINES += __AVR_ATmega8__

View File

@ -1,6 +1,5 @@
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#define MATRIX_X(t) t##B
#define MATRIX_Y1(t) t##C
@ -12,9 +11,8 @@
#define DELAY_ROW_SWITCH() _delay_ms(1) //_delay_us(1)
#define BAUDRATE 19200
#define PRINTER_PACKET_SIZE 6
#define BAUDRATE 9600
#define UBRR 51 // (F_CPU / BAUDRATE) / 32
/* Keycode from include/linux/input.h */
#define KEY_RESERVED 0
@ -149,46 +147,30 @@
#define KEY_COMPOSE 127
#define SKEY_FN 255
// #define KEYCODE_FN 127
#define KEYCODE_FN 127
/*
* Special keys:
* * Control : Code
* * Alt : Del
* * FN : Delword
* * Del : Inhalt
* * ` : SM
* * Escape : Storno
* * Print : Menu
* * Pause : GS End
*
* FN Keymap:
* * F-Keys : Number keys for F1-F10, and ? and ` for F11-F12
* * Home / End / PGUP / PGDN : Arrow keys
* * Sys rq : Print
*/
static uint8_t keycode_translation_matrix[2][9][8] = {
{ /* Standard keymap */
{KEY_5, KEY_6, KEY_R, KEY_T, KEY_C, KEY_F, KEY_UP, 0},
{KEY_8, KEY_7, KEY_Y, KEY_H, KEY_G, KEY_V, KEY_PAUSE, 0},
{KEY_1, KEY_2, KEY_Q, KEY_Z, KEY_A, KEY_S, KEY_CAPSLOCK, 0},
{KEY_9, KEY_J, KEY_I, KEY_U, KEY_B, KEY_N, KEY_RIGHT, 0},
{KEY_MINUS, KEY_0, KEY_P, KEY_O, KEY_M, KEY_COMMA, KEY_SYSRQ, 0},
{KEY_DELETE, KEY_SEMICOLON, KEY_RIGHTBRACE, KEY_LEFTBRACE, KEY_LEFT, KEY_DOWN, 0, KEY_LEFTCTRL},
{KEY_4, KEY_3, KEY_W, KEY_E, KEY_D, KEY_X, KEY_TAB, 0},
{KEY_GRAVE, KEY_ESC, KEY_ENTER, KEY_BACKSPACE, KEY_LEFTALT, SKEY_FN, KEY_LEFTSHIFT, KEY_SPACE},
{KEY_EQUAL, KEY_L, KEY_BACKSLASH, KEY_K, KEY_DOT, KEY_SLASH, 0, KEY_APOSTROPHE}
{KEY_4, KEY_3, 3, 4, 5, 6, 7, 8},
{KEY_5, KEY_6, 13, 14, 15, 16, 17, 18},
{KEY_8, KEY_7, 23, 24, 25, 26, 27, 28},
{KEY_1, KEY_2, 33, 34, 35, 36, 37, 38},
{KEY_9, 42, 43, 44, 45, 46, 47, 48},
{51, KEY_0, 53, 54, 55, 56, 57, 58},
{61, 62, 63, 64, 65, 66, 67, 68},
{71, 72, 73, 74, 75, SKEY_FN, 77, 78},
{81, 82, 83, 84, 85, 86, 87, 88}
},
{ /* FN keymap */
{KEY_F5, KEY_F6, KEY_R, KEY_T, KEY_C, KEY_F, KEY_PAGEUP, 0},
{KEY_F8, KEY_F7, KEY_Z, KEY_H, KEY_G, KEY_V, KEY_PAUSE, 0},
{KEY_F1, KEY_F2, KEY_Q, KEY_102ND, KEY_A, KEY_S, KEY_CAPSLOCK, 0},
{KEY_F9, KEY_J, KEY_I, KEY_U, KEY_B, KEY_N, KEY_END, 0},
{KEY_F11, KEY_F10, KEY_P, KEY_O, KEY_M, KEY_COMMA, KEY_SYSRQ, 0},
{KEY_DELETE, KEY_SEMICOLON, KEY_RIGHTBRACE, KEY_LEFTBRACE, KEY_HOME, KEY_PAGEDOWN, 0, KEY_LEFTCTRL},
{KEY_F4, KEY_F3, KEY_W, KEY_E, KEY_D, KEY_X, KEY_TAB, 0},
{KEY_GRAVE, KEY_ESC, KEY_ENTER, KEY_BACKSPACE, KEY_LEFTALT, SKEY_FN, KEY_LEFTSHIFT, KEY_SPACE},
{KEY_F12, KEY_L, KEY_BACKSLASH, KEY_K, KEY_DOT, KEY_SLASH, 0, KEY_APOSTROPHE}
{ 1, 2, 3, 4, 5, 6, 7, 8},
{11, 12, 13, 14, 15, 16, 17, 18},
{21, 22, 23, 24, 25, 26, 27, 28},
{31, 32, 33, 34, 35, 36, 37, 38},
{41, 42, 43, 44, 45, 46, 47, 48},
{51, 52, 53, 54, 55, 56, 57, 58},
{61, 62, 63, 64, 65, 66, 67, 68},
{71, 72, 73, 74, 75, SKEY_FN, 77, 78},
{81, 82, 83, 84, 85, 86, 87, 88}
}
};
@ -196,81 +178,26 @@ uint8_t matrix_state_last_vector[9] = {0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF,
0xFF};
uint8_t fn_active = 0;
/* UART forwarding */
#define RING_BUFFER_SIZE 256 // Important: must be 256 atm, when changed, you need to change code handling print_buffer_*.
volatile char ring_buffer[RING_BUFFER_SIZE];
volatile uint8_t ring_buffer_wr = 0;
volatile uint8_t ring_buffer_rd = 0;
#define UART_BYTE_READY (UCSRA & (1 << RXC))
void uart_putc(char c)
{
while (!(UCSRA & (1 << UDRE)));
UDR = c;
}
ISR(USART_RXC_vect)
{
if (UCSRA & (1 << RXC)) {
ring_buffer[ring_buffer_wr] = UDR;
ring_buffer_wr++; // WARNING: No overflow protection
// Will auto wrap at 256; print_buffer_wr = print_buffer_wr % PRINT_BUFFER_SIZE;
}
}
void uart_forward_packets()
{
uint8_t size;
uint8_t i;
if (ring_buffer_wr > ring_buffer_rd)
size = ring_buffer_wr - ring_buffer_rd;
else
size = ring_buffer_rd - ring_buffer_wr;
if (size >= PRINTER_PACKET_SIZE) {
/* check sync */
if (ring_buffer[ring_buffer_rd] != ((char)0xFF)) {
ring_buffer_rd++; /* Drop wrong sync header */
return;
}
if (ring_buffer[ring_buffer_rd + 1] != ((char)0xAA)) {
ring_buffer_rd += 1; /* Drop wrong app header */
return;
}
for (i = 0; i < PRINTER_PACKET_SIZE; ++i) {
uart_putc(ring_buffer[ring_buffer_rd]); // Will auto wrap at 256
ring_buffer_rd++;
}
}
}
void process_key_event(uint8_t col, uint8_t row, uint8_t state)
{
char c;
uint8_t keycode;
int event = 0;
keycode = keycode_translation_matrix[fn_active][col][row];
if (keycode == SKEY_FN) {
fn_active = state;
#ifdef KEYCODE_FN
c = KEYCODE_FN | (state << 7);
event = 1;
while (!(UCSRA & (1 << UDRE)));
UDR = KEYCODE_FN | (state << 7);
#endif
} else {
c = keycode | (state << 7);
event = 1;
}
if (event) {
uart_putc(0xFF);
uart_putc(0x55);
uart_putc(c);
while (!(UCSRA & (1 << UDRE)));
UDR = c;
}
}
@ -315,23 +242,16 @@ int main()
MATRIX_Y2(DDR) &= ~MASK_Y2; /* Disable rows */
MATRIX_Y1(PORT) &= ~MASK_Y1; /* Pull row low when selected */
MATRIX_Y2(PORT) &= ~MASK_Y2; /* Pull row low when selected */
/* Set up UART */
UCSRA = 0;
UCSRB = (1 << TXEN) | (1 << RXEN) | (1 << RXCIE);
UCSRC = 0;
UBRRH = ((((F_CPU / BAUDRATE) / 16) - 1) >> 8);
UBRRL = (((F_CPU / BAUDRATE) / 16) - 1);
UCSRB = (1 << TXEN);
UBRRH = (UBRR >> 8) & 0xFF;
UBRRL = UBRR & 0xFF;
fn_active = 0;
sei();
/* Continuously scan matrix */
while (1) {
for (col = 0; col < 9; ++col) {
matrix_scan_col(col);
}
uart_forward_packets();
}
}

View File

@ -1,88 +0,0 @@
# Makefile for ATmegaBOOT
# E.Lins, 2004-10-14
# program name should not be changed...
PROGRAM = main
PRODUCT=atmega8
# enter the parameters for the UISP isp tool
ISPPARAMS = -dprog=stk500 -dserial=$(SERIAL) -dspeed=115200
#DIRAVR = /usr/local/avr
DIRAVRBIN = $(DIRAVR)/bin
DIRAVRUTILS = $(DIRAVR)/utils/bin
DIRINC = $(DIRAVR)/include
DIRLIB = $(DIRAVR)/avr/lib
MCU_TARGET = atmega8
LDSECTION = --section-start=.text=0x1c00
FUSE_L = 0xdf
FUSE_H = 0xca
ISPFUSES = $(DIRAVRBIN)/uisp -dpart=ATmega8 $(ISPPARAMS) --wr_fuse_l=$(FUSE_L) --wr_fuse_h=$(FUSE_H)
ISPFLASH = $(DIRAVRBIN)/uisp -dpart=ATmega8 $(ISPPARAMS) --erase --upload if=$(PROGRAM).hex -v
OBJ = $(PROGRAM).o
OPTIMIZE = -Os -funsigned-char -funsigned-bitfields -fno-inline-small-functions
DEFS = -DF_CPU=16000000 -DBAUD_RATE=19200
LIBS =
CC = $(DIRAVRBIN)/avr-gcc
# Override is only needed by avr-lib build system.
override CFLAGS = -g -Wall $(OPTIMIZE) -mmcu=$(MCU_TARGET) -D$(PRODUCT) $(DEFS) -I$(DIRINC)
override LDFLAGS = -Wl,-Map,$(PROGRAM).map,$(LDSECTION)
OBJCOPY = $(DIRAVRBIN)/avr-objcopy
OBJDUMP = $(DIRAVRBIN)/avr-objdump
SIZE = $(DIRAVRBIN)/avr-size
all: $(PROGRAM).elf lst text asm size
isp: $(PROGRAM).hex
$(ISPFUSES)
$(ISPFLASH)
$(PROGRAM).elf: $(OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS)
clean:
rm -rf *.s
rm -rf *.o *.elf
rm -rf *.lst *.map
asm: $(PROGRAM).s
%.s: %.c
$(CC) -S $(CFLAGS) -g1 $^
lst: $(PROGRAM).lst
%.lst: %.elf
$(OBJDUMP) -h -S $< > $@
size: $(PROGRAM).hex
$(SIZE) $^
# Rules for building the .text rom images
text: hex bin srec
hex: $(PROGRAM).hex
bin: $(PROGRAM).bin
srec: $(PROGRAM).srec
%.hex: %.elf
$(OBJCOPY) -j .text -j .data -O ihex $< $@
%.srec: %.elf
$(OBJCOPY) -j .text -j .data -O srec $< $@
%.bin: %.elf
$(OBJCOPY) -j .text -j .data -O binary $< $@

View File

@ -1 +0,0 @@
../../ioc/avr-bootloader/main.c

View File

@ -1,9 +1,8 @@
MCU=atmega8
PDEV=/dev/ttyUSB0
CFLAGS=-g -Wall -mcall-prologues -mmcu=$(MCU) -O2 -DF_CPU=16000000
CFLAGS=-g -Wall -mcall-prologues -mmcu=$(MCU) -Os -DF_CPU=8000000
LDFLAGS=-Wl,-gc-sections -Wl,-relax
CC=avr-gcc
TARGET=fw_printer
TARGET=main
OBJECT_FILES=main.o
all: $(TARGET).hex
@ -16,14 +15,10 @@ clean:
%.obj: $(OBJECT_FILES)
$(CC) $(CFLAGS) $(OBJECT_FILES) $(LDFLAGS) -o $@
avr-size -C --mcu=atmega8 main.obj
rfu: $(TARGET).hex
scp $< markus@opi:/home/markus/projects/lw35/deploy/
ssh root@opi 'lw35-tool set-mode rfu-pri; avrdude -p atmega8 -P /dev/lw35 -c arduino -b 19200 -U flash:w:/home/markus/projects/lw35/deploy/$<'
program: $(TARGET).obj
avrdude -p $(MCU) -P $(PDEV) -c arduino -b 19200 -U flash:w:$(TARGET).hex
avrdude -p $(MCU) -c usbasp -U flash:w:$(TARGET).hex
#avrdude -p $(MCU) -P /dev/ttyUSB1 -c arduino -b 57600 -U flash:w:$(TARGET).hex
fuse:
avrdude -p m8 -c usbasp -U lfuse:w:0xe4:m -U hfuse:w:0xd9:m

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -7,5 +7,3 @@ INCLUDEPATH += /usr/avr/include
SOURCES += \
main.c
DEFINES += __AVR_ATmega8__

View File

@ -1,29 +0,0 @@
#!/bin/bash
source shared.sh
if [ "$1" == "" ]; then
echo "usage: $0 <file>"
exit;
fi
mkdir -p out
rm out/*
echo ".ll $LL" > out/header
cat "$1" | sed 's/\./\\\&./g' > out/text
echo ".sp 0" > out/footer
cat out/header out/text out/footer | nroff -Tascii > out/render
cline=0
page=1
while IFS="" read -r p || [ -n "$p" ]
do
cline=$(($cline + 1))
if [ $cline -eq $PL ]; then
page=$(($page + 1))
cline=0
fi
printf '%s\n' "$p" >> "out/out$page.txt"
done < out/render
echo "Created $page pages."

View File

@ -1,39 +0,0 @@
#!/bin/bash
source shared.sh
ML=$(( (110-$LL) / 2))
MT=$(( (64 - $PL) / 2 ))
echo "Margin left: $ML"
echo "Margin top : $MT"
echo "Page width : $LL"
echo "Page length: $PL"
if [ $MT -gt 127 ]; then
echo "Margin top > 127 not supported because I am lazy. Is $MT."
exit
fi
MT=$(( $MT + 128 )) # Set "move by n line bit"
#exit
echo -ne $(printf "\\\\x%02x\\\\x%02x" 224 $ML) > /dev/lw35
MR=$((ML + $LL + 2)); # Plus 2 because bug in FW in conjunction with manual newlines
echo -ne $(printf "\\\\x%02x\\\\x%02x" 225 $MR) > /dev/lw35
for file in ./out/out*; do
foo=""
while [ true ]; do
echo "Insert a piece of paper and press enter. When you're done, enter y."
read foo
if [ "$foo" == "y" ]; then
break;
fi
echo -ne "\xE3\x8C" > /dev/lw35 # Draw in until at top of paper
echo -ne $(printf "\\\\x%02x\\\\x%02x" 0xE3 $MT) > /dev/lw35 # Move over margin top
done
echo "Printing part $file..."
cat $file > /dev/lw35
echo "Part done."
done
echo "Done."

View File

@ -1,6 +0,0 @@
#!/bin/bash
# Limits for A4 vertical
LL=80 # Max 90
PL=58 # Max 64