Classic keyboard for Lenovo X230

Small background

Long time ago I was fan of Dell, but at some point in time where panoramic displays started appearing in laptops, Dell started to lag behind. Size of laptops also increased, so 14″ were no longer small one. Meantime resolution also dropped, so I could only dream about what I had earlier: small 14″ compact laptop with display resolution 1600×1200 and possibility to insert 2 batteries. About the same time I’ve changed company I worked for and I’ve got brand new tiny Lenovo ThinkPad X61s 12″ with 4:3 display (resolution wasn’t great, but I got used to it). I also needed to commute 1-2 times a week with it, so I started to love it for it’s size and weight 🙂 When X61s got old (and slow for my then-current requirements) I bought for myself next in line at still reasonable price: ThinkPad X201. After about 2 years prices of X220 and X230 dropped to level of X201, so I made another switch. This time to X220, not to X230 as former have still classic keyboard with lot of useful keys in right place.

Lenovo x220 and x230 are very alike

Meantime, I noted that X220 and X230 are almost the same laptops. Main difference is cpu and of course keyboard with different layout. I also found some X220i with newer keyboard, so I started thinking that maybe there is a possibility to replace keyboard between models. After some digging I found a discussion on reddit that it is really possible, but not as straightforward as I expected. It involved a bios modification and direct programming of memory chip. I ordered from China simple programmer based on CH340 chip and I forgot about it for few months.

Lenovo ThinkPad X230 before modification

I started watching auctions for every new ThinkPad X230 and finally I found one with good condition at very reasonable price (~500zł/$150). New problem arose: new or even used keyboard from X220 cost ~$35, plus palmrest another $15, so ‘upgrade kit’ at price 1/3 of laptop value was a little too expensive. Another month of checking new auctions every morning eventually payed off: ~$30 for keyboard, palmrest and as bonus I’ve got good motherboard for X220, wifi card and Windows sticker 🙂

During all these months people doing this mod made huge progress, everything was documented ( and EC firmware upgrade procedure was hacked, to there is no need for programmers – it’s easy now as casual bios upgrade.


The mod – hardware part

In ThinkWiki you could find 2 ways of making this mod:

  1. Modify keyboard and replace it with palmrest
  2. Modify keyboard and hack it physically to fit with original palmrest

I chose first option because is reversible. In second option you need to cut/file and bend some parts of keyboard.

Ok, keyboard to modify:

Keyboard from X220

First, I needed to isolate 3 contacts on connector inside keyboard, because it would make a short circuit in X230.


At the beginning it’s good to remove plastic panel on top of power and volume buttons. It’s best to apply little force toward center of keyboard and pry from outside to lift it.

Plastic panel to remove

Panel removed

Then unscrew two screws holding elastic pcb on the back of keyboard:

Back of X220 keyboard

Bar holding flexible pcb from the bottom

Bar removed

Then go back to front of keyboard and remove bar on the other side:

Upper bar also removed

Then remove elastic pcb from connector. I used sharp knife to pry it a little, then flat and long tweezers to lift it more:

Prying a little connector

Separate connectors using tweezers

When connector is free, it’s time to isolate 3 pins as described on ThinkWiki. I used kapton tape to do it. I tried to make strip of tape only a little wider that all 3 contacts as I read that some people had sometimes problems after isolating pins using tape. This elastic pcb is pushed to contacts on second pcb and it should have some room to bend to get good contacts for pins directly near the kapton tape.

Isolate 3 pins using kapton tape

Pins isolated

It’s time to put it back, once again I used knife to make some room:

Putting connector back

Connector in place

Now, put this part together and secure using screws, but didn’t put plastic cover yet because there is another small difference between X220 and X230:

Keyboard bezel in X220 vs X230

X230 don’t have a notch in keyboard bezel, so there are 3 options: make the same notch on X230, replace whole bezel (it involves much disassebly, disconnecting antennas, lcd connectors etc) or remove something in keyboard which goes into this place. I think it’s better to modify keyboard once again:-)

Nub to remove

At the beginning I thought that it would be easy to remove it using sharp knife, but plastic is hard and it took me more time than I expected. It’s definitely better to use Dremel-like tool to sand it down.

Adapting keyboard 🙂

X220 keyboard is now compatible mechanically with X230 bezel

Just put plastic cover back and keyboard is ready.

If you are owner of X220/X230 you should have somewhere “Hardware Maintenance Manual” with precise description which screws are needed to remove and how to replace keyboard and palmrest. I’ll skip this step and show what I’ve got:

ThinkPad X230 with classic keyboard from X220

The mod – software

Right now I have all hardware done, but not all keys are working as expected. Software of Embedded Controller (EC) should be modified to get all keys working. Thinkwiki describes this step in old and complicated way, but if you follow directly to, it would be very easy (if you are using Linux 🙂 ).

I found that thinpad-ec supported bios version 2.66, but my laptop had already 2.70 and downgrade would be problematic. Lucky for me, I found this issue and comment and I did search/replace as suggested. On Linux building was as easy as pie – script downloads by itself correct version of bios file, make necessary modifications and generate ready to use image. Then I put it on usb stick (image is only about 30MB, so even very old stick is good for it), booted, flashed, rebooted and everything works as in old good X220 🙂

Since this commit  flashing 2.70 it’s even easier 🙂


Good luck with your modding 🙂

Posted in Electronics | Leave a comment

Changes, changes ->

I’m moving from Tonga island to Saint Helena 🙂

The thing is that I realized is that my domain ‘‘ is quite valuable in Poland where I live (it translates to ‘we have it’), so I’m preparing to maybe sell it in some distant future. Old links should redirect to my new web site address as long as I own ‘‘ domain.
Nevertheless, I also thought that my blog deserves separate domain.

Why ‘‘? ‘.sh‘ is cool technical tld, one of today’s popular extensions as ‘.io‘, but it matches better my IT profile: servers, scripting (especially bash!) etc.


Yes, ‘‘ also uses encryption now.

Posted in Life | Leave a comment

Writing to internal FLASH on Arduino


In LCD88 I use internal flash as storage for model definitions. Of course, these should be editable without reflashing all firmware:-)

On AVR chips writing to flash is only possible from bootloader section, so I needed such feature in my bootloader.
I adapted my old X-MODEM bootloader to provide some entry points to functions writing flash. But because of using X-MODEM as communication protocol, using it was quite difficult for ordinary people. Then, I came up with idea that bootloader compatible with Arduino could solve this accessibility issue.
Nowadays, all things that can be invented, are invented and done by some people, so I started to find ready-made bootloader with all needed features. Most promising was Optiboot, but it lacked possibility to use it for writing flash by application.

Time was passing by and I was very surprised that I can’t find ready-made solution. More surprising was that on Arduino forum writing to flash by application was perceived as ‘mission impossible’. Every topic about it ended by failure or with getting external memory for storage (flash, fram or simply SD card), or advice to write your own bootloader:-)

My conclusion after all this research was: I must write my own bootloader or contribute to some other project to add such functionality. Then I gave a first look at the code of Optiboot, it’s issues and I found issue #52 with one promising patch at the end. But this patch didn’t fit to my needs, as I need fill-erase-write sequence to not using RAM as buffer, and it doesn’t do that that way.

A year passed by and I returned to Optiboot. This time I was going to do it by mysef. It was time of learning C, hacks used in avr-gcc, bugs in different verions of avr-gcc, learning Github flows, branching, merging, even writing in Arduino as I needed to provide some working example of using this feature. But finally I made it! 🙂

Writing to flash

Optiboot with possibility to write to flash by applications could be downloaded from my ‘supermaster’ branch (also with some fixes not available yet in upstream): It includes also example Arduino sketch (flash_program, heavily commented) writing to flash using new Optiboot.

So, feel free to use this long waited feature in Arduino world, and spread new, now better Optiboot bootloader.

Posted in Electronics | Tagged , , | 3 Comments

dm-cache in Slackware

bcache vs. dm-cache

I tested bcache about year ago on my spare/backup server and it worked quite fine. But since then every newer kernel had new issues, even on mailing list there were suggestions that bcache should be marked back as experimental. So, after some time I abandoned bcache and started to wait for something more stable and configuration friendly. In the same time dm-cache was also available, but it’s setup was quite challenging and dangerous (using dmsetup and raw calculated numbers – very easy way to make a horrible mistake). There was also quite friendly way to manage dm-cache using LVM2 tools, but only in plans 🙂

Right now, LVM2 have all promised featured for managing dm-cache, so I gave it a try 🙂

Just to sum up my experience:

  • bcache
    • + quite good documentation about cache policies, monitoring interface, disk format, disaster recovery etc.
    • + cache works on block device layer, so you can cache whole PV device regardless how many LV you have on top of it (one cache for all)
    • + no need for resize as you are caching whole physical device
    • + you can tweak cache parameters on the fly, including cache policy (writethrough/writeback)
    • – you can’t convert backing device on the fly to cached with data on it
    • – unstable
    • ~ doesn’t require LVM support
  • dm-cache
    • + stable
    • + easy to setup
    • + you can convert any LVM volume to use cache or not to use it, online, without any problem
    • – one cache for one LV, so if you have multiple LVs and you want to cache it all, you’d need to divide cache device (ssd disk) to many small chunks for every LV – space wasted
    • – very brief documentation – enough to set up things, but without any info about how to tune or monitor it
    • – resizing LVs must be done by uncaching, resizing and caching again, so you loose all cache contents
    • ~it’s part of LVM


It’s time to get back to Slackware. Current version is 14.1, so everything described here is based on this version.

Recent kernel

Stock 3.10.17 kernel is little too old for good dm-cache work, so I recommend to get something at least from 3.14 series. You could compile it yourself or grab from slackware-current tree which have currently 3.14.33.

Recent LVM2

LVM2 version shipped with Slackware 14.1 is almost last version without dm-cache support, so there is a need to grab latest version and compile it. For complete support you need also thin-provisioning-tools with fsck-like tools for dm-cache.

Hard way (compile everything yourself)

  1. Get sources of LVM2 package from
  2. Get more recent LVM2 sources from
  3. Get thin-provisioning-tools from and save it as thin-provisioning-tools-0.4.1.tar.gz
  4. Get my patch for SlackBuild from and apply it in lvm2 directory: patch -p0 < slackware-lvm2-dm-cache.patch
  5. Make package:sh lvm2.SlackBuild
  6. Upgrade lvm2 package with new one found in /tmp
  7. If you want cached root volume, you'd need also to patch mkinitrd and rebuild initrd.
    Patch: slackware-mkinitrd-dm-cache.patch.
    Apply:cd /sbin
    patch -p0 < /somewhere/slackware-mkinitrd-dm-cache.patch
  8. Use it :-)

Lazy way

Just get my lvm2 package and install it. You may also need mkinitrd patch (see above).


Start is easy and well documented in man lvmcache.
Just quick howto assuming that you have volume group named vg_group, your physical cache device (ssd) is /dev/sdb1 and you want to cache volume named lv_home.

  1. First, cache/ssd disk must be part of volume group:vgextend vg_group /dev/sdb1
  2. Create cache pool on fast device (default mode is writethrough - safer but slower, so for writeback, there is a need to add --cachemode option):lvcreate --type cache-pool --cachemode writeback -L 10G -n cacheX vg_group /dev/sdb1
  3. Attach cache to logical volume:lvconvert --type cache --cachepool vg_group/cacheX vg_group/lv_home
  4. Enjoy 🙂
Posted in Linux | Tagged | Leave a comment

Christmas tree lamps with Arduino and WS2811 leds :-)

Somewhere at the beginning of November I discovered RGB LEDs with embedded controller: WS2812 and others. Idea was so cool for me that I had to own one to play with it 🙂
These chips became so common, that there are even put inside LEDs, like on this WS2812 diode:


Considering time of the year, it was obvious to me to make whole string of lamps for Christmas tree. Then I found on Aliexpress ready made chains of such LEDs. 🙂
So, my LEDs aren’t with chips inside, but with small PCBs sealed with some kind of hard silicone – maybe not so elegant as chip integrated inside LED, but cheaper – which counts if you buy 50 of them :-):

WS2811 RGB LEDs on Christmas tree

Day before Christmas I still haven’t done anything with these light, so it was last chance to do something useful with it.

Connecting everything was quite easy as there are only 3 components: 5V power supply, Arduino Pro Mini board and LED chain.

Programming protocol for WS2811 was more challenging – generated waveform must be very accurate, with some time intervals taking only 8 cpu Atmega328 clocks (at 16MHz). So, I chose assembler to do it (as usual 🙂 ).
To be more hardcore, it was 3am when I started debugging 🙂 Honestly, without my new oscilloscope, finding these 3 mistakes I’ve made, could’ve took hours. Especially that Chinese guy who sells these LEDs described them as ‘we sent WS2811. Or we may sent UCS1903’ – two different possible chips (!) with two different protocols and no one knows which version I’ve got.
Luckily for me. it was WS2811, so first guess and code worked.

I added few simple routines to move light across whole chain of LEDs and put everything on Christmas tree.

All code for this ‘one night project’ you could find on my Github page:

This is how it looks like on my Christmas tree:

Posted in Electronics | Tagged , , , | 3 Comments