Register Guidelines E-Books Search Today's Posts Mark Forums Read

Go Back   MobileRead Forums > E-Book Readers > Kobo Reader > Kobo Developer's Corner

Notices

Reply
 
Thread Tools Search this Thread
Old 10-05-2017, 01:28 AM   #1
GeoffR
Wizard
GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.
 
GeoffR's Avatar
 
Posts: 3,406
Karma: 14134918
Join Date: Nov 2012
Location: Beneath the Long White Cloud
Device: Kobo Glo
Questions on how to create/update Metazoa patches, ARM assembler, objdump, etc.

In this thread I will try to pass on what I have learned about making patches for the Kobo e-ink ereaders. I have been meaning to do this for a while now, but I never know where to start, so if you have a specific question just ask and I'll try to answer here.

I am not an expert on any of this, so don't assume the way I do something is the only way or the best way. I have a bit of background programming in C and x86 assembly language for Linux, but I didn't know anything about ARM CPUs or modifying programs without access to source code until I started patching my Glo. I've just learned the bits I needed as I went along, there are big gaps in my knowledge.

I use the following programs in Debian 8 Linux, there are alternatives for other systems but I haven't used them, so any explanation I give will be based on these:

* Disassembler: objdump (binutils-multiarch package)
-- I use version 2.25, some older versions didn't show function names in disassembly.
* Hex editor: emacs [M-x hexl-open-file] (emacs24 package)
* Patcher: patch32lsb (included in tools/ directory of patch archives)
* A hexdecimal calculator can be handy, I have an old HP 42s.

I'll keep an index of topics in this first post and update it as different topics come up:

Post #2 Address vs. file offset
Post #3 Finding function addresses
Post #4 Patching compressed CSS strings
Post #8 Function call arguments

Last edited by GeoffR; 10-06-2017 at 04:10 AM. Reason: objdump version 2.25
GeoffR is offline   Reply With Quote
Advert
Old 10-05-2017, 01:31 AM   #2
GeoffR
Wizard
GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.
 
GeoffR's Avatar
 
Posts: 3,406
Karma: 14134918
Join Date: Nov 2012
Location: Beneath the Long White Cloud
Device: Kobo Glo
Address vs. file offset

In patch comments and the patch32lsb code I have used the term address as if it was the same thing as file offset, but that is not always true. For dynamic libraries such as libnickel.so.1.0.0 and librmsdk.so.1.0.0 they are the same, but for executables such as nickel and sickel they are different.

objdump works mainly with addresses, but the patch32lsb tool only deals with file offsets, so for some nickel and sickel patches it may be necessary to convert addresses to file offsets. If you use the -F switch with objdump it will show the file offsets along with the addresses. For example the objdump command:
Code:
$ objdump -dCF sickel | grep SickelService::Ping | grep ":$"
Output for firmware 4.5.9587:
Code:
0000b2bc <SickelService::Ping()> (File Offset: 0x32bc):
Output for firmware 4.6.9960:
Code:
000133d0 <SickelService::Ping()> (File Offset: 0x33d0):
So for sickel patches: in firmware 4.5.9587 add 0x8000 to the file offset to get the address, and in firmware 4.6.9660 add 0x10000 to the file offset to get the address.

Last edited by GeoffR; 10-05-2017 at 08:21 AM. Reason: spelling
GeoffR is offline   Reply With Quote
Old 10-05-2017, 02:09 AM   #3
GeoffR
Wizard
GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.
 
GeoffR's Avatar
 
Posts: 3,406
Karma: 14134918
Join Date: Nov 2012
Location: Beneath the Long White Cloud
Device: Kobo Glo
Finding function addresses

External functions are called indirectly via a jump table. Slots in the jump table are filled in by the linker when the program is loaded.

To find the C++ function ValueDisplaySlider::setStep
Code:
objdump -dC libnickel.so.1.0.0 | grep ValueDisplaySlider::setStep | grep ":$"
output for firmware 4.5.9587:
Code:
004d9d14 <ValueDisplaySlider::setStep(int)@plt>:
008214f0 <ValueDisplaySlider::setStep(int)>:
the first line with @plt shows the address of the jump slot, the second line shows the address of the function itself. If only the jump slot is present then the function itself will be located in another file.

To find where the function is called:
Code:
objdump -dC libnickel.so.1.0.0 | grep ValueDisplaySlider::setStep | grep @plt
output for firmware 4.5.9587:
Code:
004d9d14 <ValueDisplaySlider::setStep(int)@plt>:
  741dce:	f597 efa2 	blx	4d9d14 <ValueDisplaySlider::setStep(int)@plt>
  7420ee:	f597 ee12 	blx	4d9d14 <ValueDisplaySlider::setStep(int)@plt>
  7c692a:	f513 e9f4 	blx	4d9d14 <ValueDisplaySlider::setStep(int)@plt>
  7c69c2:	f513 e9a8 	blx	4d9d14 <ValueDisplaySlider::setStep(int)@plt>
  7c6a58:	f513 e95c 	blx	4d9d14 <ValueDisplaySlider::setStep(int)@plt>
  7c6af0:	f513 e910 	blx	4d9d14 <ValueDisplaySlider::setStep(int)@plt>
the first line is the address of the jump slot, the other lines are the addresses from where the function is called.

(The function could be called from other places too, via a pointer variable. I don't know of any easy way to find such calls.)

Last edited by GeoffR; 10-05-2017 at 02:23 AM. Reason: indirect calls via a pointer variable
GeoffR is offline   Reply With Quote
Old 10-05-2017, 07:43 AM   #4
oren64
I need a chapter break
oren64 ought to be getting tired of karma fortunes by now.oren64 ought to be getting tired of karma fortunes by now.oren64 ought to be getting tired of karma fortunes by now.oren64 ought to be getting tired of karma fortunes by now.oren64 ought to be getting tired of karma fortunes by now.oren64 ought to be getting tired of karma fortunes by now.oren64 ought to be getting tired of karma fortunes by now.oren64 ought to be getting tired of karma fortunes by now.oren64 ought to be getting tired of karma fortunes by now.oren64 ought to be getting tired of karma fortunes by now.oren64 ought to be getting tired of karma fortunes by now.
 
oren64's Avatar
 
Posts: 3,061
Karma: 41270662
Join Date: Mar 2015
Location: Israel
Device: kobo glo
Create patches form CSS string.

This is a easy way to make patches from CSS string.

From firmware 4.x the a lot of code moved from libnickel.so.1.0.0 to nickel have been compressed CSS string.

Tools:
CSS styles modifications inside nickel (Python 2 needed). By pipcat
makepatch program preferable makepatch-0.02.zip file, By GeoffR


Instructions:
  1. Download thepatch-nickel-css-v02.zip and extract as folder in your PC. Windows users can extract the files extract.bat and patch.bat from "bat files for windows.zip" to that folder.
  2. Open the file css_streams.py change the line
    Code:
    pos += 4 + len_stream
    to
    Code:
    pos += 3 + len_stream
    That way it can find all CSS streams contained in nickel (Thanks to jackie_w).
  3. Download the Firmware that you what to make patches from (See here) Extrcat the nickel file from the Kobo firmware kobo-update-4.x.xxxx.zip\koboroot.tgz\usr\local\kobo\nickel, to the folder.
  4. Execute python extract.py it will make "nickel-extracted.css" file with streams (Windows file extract.bat for easy access). For example in 4.6.9660 there 158 stream with 99 compressed.
    Click image for larger version

Name:	T1.PNG
Views:	26
Size:	41.3 KB
ID:	159309
  5. Open the file nickel-extracted.css and select witch stream you want to modify, In this method we work on only one stream at a time.
    for example I will show how I made the patch `New home screen increasing cover size` for firmware 4.6.9660. I select the stream 106 and copy it to the file nickel-modified.css, make sure file is empty before.
    Spoiler:
    Code:
    /* found: 106 (zlib) pos: 4c2e69 */ #mainContainer[qApp_deviceIsTrilogy=true] { qproperty-leftMargin: 26; qproperty-rightMargin: 26; qproperty-topMargin: 96; qproperty-bottomMargin: 26; qproperty-spacing: 10; } #mainContainer[qApp_deviceIsPhoenix=true] { qproperty-leftMargin: 36; qproperty-rightMargin: 36; qproperty-topMargin: 126; qproperty-bottomMargin: 36; qproperty-spacing: 14; } #mainContainer[qApp_deviceIsDragon=true] { qproperty-leftMargin: 50; qproperty-rightMargin: 50; qproperty-topMargin: 170; qproperty-bottomMargin: 50; qproperty-spacing: 20; } #mainContainer[qApp_deviceIsDaylight=true] { qproperty-leftMargin: 65; qproperty-rightMargin: 65; qproperty-topMargin: 220; qproperty-bottomMargin: 65; qproperty-spacing: 26; } #row1[qApp_deviceIsTrilogy=true], #row2[qApp_deviceIsTrilogy=true] { max-height: 280px; min-height: 280px; } #row1[qApp_deviceIsPhoenix=true], #row2[qApp_deviceIsPhoenix=true] { max-height: 346px; min-height: 346px; } #row1[qApp_deviceIsDragon=true], #row2[qApp_deviceIsDragon=true] { max-height: 488px; min-height: 488px; } #row1[qApp_deviceIsDaylight=true], #row2[qApp_deviceIsDaylight=true] { max-height: 634px; min-height: 634px; } [qApp_isFontScaleLarge=true] #row1[qApp_deviceIsTrilogy=true] { max-height: 392px; min-height: 392px; } [qApp_isFontScaleLarge=true] #row1[qApp_deviceIsPhoenix=true] { max-height: 484px; min-height: 484px; } [qApp_isFontScaleLarge=true] #row1[qApp_deviceIsDragon=true] { max-height: 683px; min-height: 683px; } [qApp_isFontScaleLarge=true] #row1[qApp_deviceIsDaylight=true] { max-height: 887px; min-height: 887px; } [qApp_isFontScaleLarge=true] #row2[qApp_deviceIsTrilogy=true] { max-height: 112px; min-height: 112px; } [qApp_isFontScaleLarge=true] #row2[qApp_deviceIsPhoenix=true] { max-height: 138px; min-height: 138px; } [qApp_isFontScaleLarge=true] #row2[qApp_deviceIsDragon=true] { max-height: 195px; min-height: 195px; } [qApp_isFontScaleLarge=true] #row2[qApp_deviceIsDaylight=true] { max-height: 253px; min-height: 253px; } [qApp_isFontScaleLarge=true] #row1col2 { qproperty-visible: false; }

  6. I edit the stream in nickel-modified.css file by reduces the left and right margin and save the file.
    Spoiler:
    Code:
    /* found: 106 (zlib) pos: 4c2e69 */ #mainContainer[qApp_deviceIsTrilogy=true] { qproperty-leftMargin: 10; qproperty-rightMargin: 10; qproperty-topMargin: 96; qproperty-bottomMargin: 26; qproperty-spacing: 10; } #mainContainer[qApp_deviceIsPhoenix=true] { qproperty-leftMargin: 12; qproperty-rightMargin: 12; qproperty-topMargin: 126; qproperty-bottomMargin: 36; qproperty-spacing: 14; } #mainContainer[qApp_deviceIsDragon=true] { qproperty-leftMargin: 16; qproperty-rightMargin: 16; qproperty-topMargin: 170; qproperty-bottomMargin: 50; qproperty-spacing: 20; } #mainContainer[qApp_deviceIsDaylight=true] { qproperty-leftMargin: 20; qproperty-rightMargin: 20; qproperty-topMargin: 220; qproperty-bottomMargin: 65; qproperty-spacing: 26; } #row1[qApp_deviceIsTrilogy=true], #row2[qApp_deviceIsTrilogy=true] { max-height: 280px; min-height: 280px; } #row1[qApp_deviceIsPhoenix=true], #row2[qApp_deviceIsPhoenix=true] { max-height: 346px; min-height: 346px; } #row1[qApp_deviceIsDragon=true], #row2[qApp_deviceIsDragon=true] { max-height: 488px; min-height: 488px; } #row1[qApp_deviceIsDaylight=true], #row2[qApp_deviceIsDaylight=true] { max-height: 634px; min-height: 634px; } [qApp_isFontScaleLarge=true] #row1[qApp_deviceIsTrilogy=true] { max-height: 392px; min-height: 392px; } [qApp_isFontScaleLarge=true] #row1[qApp_deviceIsPhoenix=true] { max-height: 484px; min-height: 484px; } [qApp_isFontScaleLarge=true] #row1[qApp_deviceIsDragon=true] { max-height: 683px; min-height: 683px; } [qApp_isFontScaleLarge=true] #row1[qApp_deviceIsDaylight=true] { max-height: 887px; min-height: 887px; } [qApp_isFontScaleLarge=true] #row2[qApp_deviceIsTrilogy=true] { max-height: 112px; min-height: 112px; } [qApp_isFontScaleLarge=true] #row2[qApp_deviceIsPhoenix=true] { max-height: 138px; min-height: 138px; } [qApp_isFontScaleLarge=true] #row2[qApp_deviceIsDragon=true] { max-height: 195px; min-height: 195px; } [qApp_isFontScaleLarge=true] #row2[qApp_deviceIsDaylight=true] { max-height: 253px; min-height: 253px; } [qApp_isFontScaleLarge=true] #row1col2 { qproperty-visible: false; }

  7. I execute python patch.py (Windows file patch.bat for easy access). It will generate a new nickel file with the changes I made in the name "nickel-modif".
    Click image for larger version

Name:	t2.PNG
Views:	26
Size:	36.8 KB
ID:	159310
  8. Download makepatch-0.02.zip and extract as folder in your PC. Windows users can extract the file makepa32.bat from "bat files for windows.zip" to that folder.
  9. I copy the files "nickel" and "nickel-modif" to that folder. Execute the file makepa32 (nickel=oldfile, nickel-modif=newfile). (Windows file makepa32.bat for easy access).
    It will create patch `New home screen increasing cover size`.
    Click image for larger version

Name:	T3.PNG
Views:	32
Size:	139.7 KB
ID:	159311
    To copy the patch in windows, right click frame > Edit > Mark, mark the patch, press enter to copy.
  10. The patch is ready, copy the patch to file nickel.patch.

To make a patch from the same nickel file repeat steps 5-10.
Attached Files
File Type: zip bat files for windows .zip (502 Bytes, 12 views)

Last edited by oren64; 10-06-2017 at 02:46 PM.
oren64 is offline   Reply With Quote
Old 10-05-2017, 07:43 AM   #5
geek1011
Kobo Tweaker & Linux User
geek1011 can program the VCR without an owner's manual.geek1011 can program the VCR without an owner's manual.geek1011 can program the VCR without an owner's manual.geek1011 can program the VCR without an owner's manual.geek1011 can program the VCR without an owner's manual.geek1011 can program the VCR without an owner's manual.geek1011 can program the VCR without an owner's manual.geek1011 can program the VCR without an owner's manual.geek1011 can program the VCR without an owner's manual.geek1011 can program the VCR without an owner's manual.geek1011 can program the VCR without an owner's manual.
 
Posts: 211
Karma: 197136
Join Date: May 2016
Device: Kobo Mini & Kobo Aura Edition 2
Thanks so much! This is quite useful.
geek1011 is offline   Reply With Quote
Advert
Old 10-05-2017, 08:33 AM   #6
Terisa de morgan
Wizard
Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.
 
Terisa de morgan's Avatar
 
Posts: 4,385
Karma: 4717596
Join Date: Jun 2009
Location: Madrid, Spain
Device: Kobo Aura, Kobo Aura One, XiaoMI 5, iPad, Huawei MediaPad, YotaPhone 2
Thank you very much both of you!
Terisa de morgan is offline   Reply With Quote
Old 10-05-2017, 09:11 AM   #7
Terisa de morgan
Wizard
Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.
 
Terisa de morgan's Avatar
 
Posts: 4,385
Karma: 4717596
Join Date: Jun 2009
Location: Madrid, Spain
Device: Kobo Aura, Kobo Aura One, XiaoMI 5, iPad, Huawei MediaPad, YotaPhone 2
Now, go looking for the other css
Terisa de morgan is offline   Reply With Quote
Old 10-06-2017, 02:37 AM   #8
GeoffR
Wizard
GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.GeoffR ought to be getting tired of karma fortunes by now.
 
GeoffR's Avatar
 
Posts: 3,406
Karma: 14134918
Join Date: Nov 2012
Location: Beneath the Long White Cloud
Device: Kobo Glo
Function call arguments

(Note that objdump refers to the 16 core registers as r0 - r9, sl, fp, ip, sp, lr, pc. Other tools might name them differently.)

The first 4 (non-float) arguments to a C/C++ function are passed in registers r0, r1, r2, r3, with any additional arguments passed on the stack. On return the result (if any) is in r0 - r3, and any of the registers r0 - r3 not used for the result contain junk. The contents of r4 - r9, sl, fp are preserved by the called function.

A standard C function takes a fixed number of arguments and returns a single result. In the C source, calling a function with 2 small integer arguments returning a small integer result could look something like:
Code:
result = fun(100, 23)
In assembly that function call might look something like:
Code:
movs r0, #100
movs r1, #23
blx  fun@plt
; now r0 contains result, r1 - r3 are junk
C++ function calls are similar, except that the compiler can insert some hidden arguments before the ones declared in the parameter list. A C++ source function call
Code:
result = obj.fun(100, 23)
might look something like this in assembly:
Code:
ldr  r0, [sp, #40] ; obj
movs r1, #100
movs r2, #23
blx  Class::fun(int,int)@plt
; now r0 contains result, r1 - r3 are junk
`Brightness fine control` for firmware 4.5.9587 is an example of a patch that modifies the declared argument to a C++ function taking one hidden and one declared argument:
Code:
<Patch>
patch_name = `Brightness fine control`
patch_enable = `yes`
#
## Sun symbols change the frontlight brightness in 2% instead of 1% steps.
#
# ValueDisplaySlider::setStep(1) --> ValueDisplaySlider::setStep(2)
replace_int = 741DCA, 1, 2
</Patch>
objdump command to show the relevant section of code in libnickel.so.1.0.0:
Code:
objdump -dC libnickel.so.1.0.0 --start-address=0x741dc6 | less
output before patching, firmware 4.5.9587 (trimmed):
Code:
  741dc6:       f8d4 308c       ldr.w   r3, [r4, #140]  ; 0x8c
  741dca:       2101            movs    r1, #1
  741dcc:       6a58            ldr     r0, [r3, #36]   ; 0x24
  741dce:       f597 efa2       blx     4d9d14 <ValueDisplaySlider::setStep(int)@plt>
output after patching, firmware 4.5.9587 (trimmed):
Code:
  741dc6:       f8d4 308c       ldr.w   r3, [r4, #140]  ; 0x8c
  741dca:       2102            movs    r1, #2
  741dcc:       6a58            ldr     r0, [r3, #36]   ; 0x24
  741dce:       f597 efa2       blx     4d9d14 <ValueDisplaySlider::setStep(int)@plt>
GeoffR is offline   Reply With Quote
Old 10-06-2017, 04:24 PM   #9
Terisa de morgan
Wizard
Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.Terisa de morgan ought to be getting tired of karma fortunes by now.
 
Terisa de morgan's Avatar
 
Posts: 4,385
Karma: 4717596
Join Date: Jun 2009
Location: Madrid, Spain
Device: Kobo Aura, Kobo Aura One, XiaoMI 5, iPad, Huawei MediaPad, YotaPhone 2
Quote:
Originally Posted by oren64 View Post
[*]I copy the files "nickel" and "nickel-modif" to that folder. Execute the file makepa32 (nickel=oldfile, nickel-modif=newfile). (Windows file makepa32.bat for easy access).
It will create patch `New home screen increasing cover size`.
Attachment 159311
To copy the patch in windows, right click frame > Edit > Mark, mark the patch, press enter to copy.
[*]The patch is ready, copy the patch to file nickel.patch.[/LIST]
To make a patch from the same nickel file repeat steps 5-10.

How do you adapt the absolut addresses to relative ones?

Pdta: Forget it, I found the option -b

Last edited by Terisa de morgan; 10-06-2017 at 04:26 PM. Reason: I found the answer
Terisa de morgan is offline   Reply With Quote
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search

Forum Jump

Similar Threads
Thread Thread Starter Forum Replies Last Post
Index to the Metazoa firmware patches GeoffR Kobo Developer's Corner 211 Yesterday 05:54 PM
Tools KindleTool: Create/Unpack Kindle update files NiLuJe Kindle Developer's Corner 183 04-19-2016 02:33 PM
Paperwhite 5.4.2 update questions joangolfing Amazon Kindle 11 11-25-2013 11:28 AM
Feature request: Update Patches kiwimonk Calibre 1 01-05-2011 01:09 PM
An update and a few questions... kressg23 HanLin eBook 9 03-10-2009 09:05 PM


All times are GMT -4. The time now is 05:20 PM.


MobileRead.com is a privately owned, operated and funded community.