Posts for year 2010




More impending beans

A few mornings ago I noticed that I now had a heap more flowers on the large bush out the front:

/images/2011/12/20101002_164228__MG_5452-1024x682.jpg/images/2011/12/20101103_075028__MG_5552-1024x682.jpg/images/2011/12/20101103_075220__MG_5557-682x1024.jpg

I’ve got a few buds starting to appear on the smaller bush just to the right (and out of shot), but its buds are nowhere near as large as those that you see above. I guess that means I’ll have beans growing for quite a long time.




More on the espresso machine frustration

Popped in to Brisbane Appliance Repairs at Moorooka this morning to see about getting the espresso machine fixed up. Sadly, the beast needs a new brew head because the screw hole is buggered. That part is $90, add in labour and we’re at $150. Then adding the cost of a replacement handle (which I managed to break last night :<) at $56 and it’s all rather bleak and frustrating. While I wait for my replacement to arrive (I’ve taken the easy way out and I’m redeeming flybuys points to get a new one), I’ll just have to use a plunger, or my Moka, or get off my behind and ride in to Cup at West End instead.




First flowers on the coffee hedge

About two years ago, J’s mum gave me 5 coffee plants. We put two at the front:

/images/2011/12/20101002_163809__MG_5440.jpg

and the rest along the side in the back yard. We’re not sure what species they are, but they’ve certainly produced decent coffee up in Gladstone. My long term cunning plan is to replace the mock orange hedge with these coffee plants. I know it will take a while, but we’re not moving!

I was really pleased to notice that the larger of the two has started to show a few flowers:

/images/2011/12/20101002_163938__MG_5443.jpg/images/2011/12/20101002_164017__MG_5446.jpg

I’m hopeful that all these buds will turn into flowers too:

/images/2011/12/20101002_164118__MG_5449.jpg

They will take quite a while to ripen (seven to nine months in ideal growing regions, according to Wikipedia) so who knows how long they’ll take in Brisbane. Anyway, at least I’ve got something growing. Could be another year before those two plants are big enough to justify chopping out anything else, so that gives me an idea about how long it’ll be before I can replace that mock orange entirely.




Frustration with El Espresso Machine

For a while now I’ve been meaning to descale my espresso machine and I’ve been faffing around trying to find the Approved(tm) descaler tablets. Sparky’s Small Appliance Repair at Toowong shut down, and their Albion store isn’t open on Fridays or weekends, weirdly. It turns out that you can use a tartaric acid solution, easily created by dumping a heaped tablespoon of cream of tartar into a full water reservoir and stirring.

So this afternoon I finally got around to actually doing the descaling. It seemed to work very well, especially after enough scale was removed from the boiler to make the steam wand go BLAM. Lots of steam came through the wand after that point, and the group head’s flow rate accelerated mightily also.

It was with great, great annoyance then that I found I was unable to re-install the screw which holds the filter cap on the brewing head. No amount of exerting pressure has been sufficient to get the screw to take to the threads in the block, so at this stage I am totally unable to get espresso.

I will have to make some calls in the morning, I guess. Sigh. At least I’ve got a plunger/French press to help tide me over.










Dell XPS M1530 Battery charging – bios downgrade to A09 can help

I took delivery of a Dell XPS M1530 laptop on 31 January 2008. Very pleased with it – ran OpenSolaris almost straight out of the box (sole exception being the Marvell Yukon ethernet, now supported by yge). Things went reasonably well until the SAGE-AU conference last year, when I noticed that the charging function wasn’t. Totally unchargable.

The battery and AC adapter, it turns out, were under a 1 year warranty, not 2 years like the rest of the system. Got a new 3rd party battery (from laptopbattery.net.au) and a new Dell AC adapter, and the battery lasted until about a fortnight ago.

Got another 3rd party battery, this time somewhat cheaper via a Melbourne-based EBay.com.au store. It arrived 60% charged, and seemed to charge up ok when I plugged it all in. Yay, I thought, problem solved.

Not so. As it happens, my laptop’s charging circuit inside the case (not the AC adapter) appears to be unable to recognise any sort of AC adapter, so I get the dreaded “AC Adapter – Unknown device installed” message in the bios, and under bios version A12, NO CHARGING TAKES PLACE WHATSOEVER.

None.

Rotating the power plug in the socket doesn’t help either, even though it’s a genuine Dell AC adapter.

A bunch of searching this evening turned up this thread, which said that it was worth trying to downgrade the bios to version A09, and perhaps run the bios flash program with “/forceit” as an option.

This is about the only reason that I keep the Vista partition hanging around. Though sadly, when you run the 1530_A09.exe program (even with /forceit and /forcetype) in Vista, with the battery at less than 10%, you get an error message telling you to charge the battery to at least 10% before trying again. Very frustrating!

Fortunately, one of the posters in that thread had a link to a Win98 rescue cd image which contains the bios flasher… pulled it down, burned it, booted it, flashed the bios (it’s on the logical D: drive) and now I’m sitting here watching the laptop bios battery screen increment the charge status every few minutes.

The AC Adapter is still “unknown” – but at least I’m getting charge in. And I don’t have to go out and buy a new laptop (at least, not just yet).

This is the sort of thing which really annoys the heck out of me. Not only is there no opportunity for me to get the bios flashed from OpenSolaris using fwflash but there’s clearly some “enhancement” in A12 which is actually a regression and serious functional misfeature compared to A09. Let’s not start on the hardware problems in the AC adapter, either.




An exercise in frustration

Or, what to do when you want to buy a printer.

Last year our trusty Lexmark Optra S 1855 (networked, extra paper tray and duplexer) got to the end of its cartridge, and we found to our annoyance that a replacement would set us back close to AUD450. Not keen to take that option, we decided to get a schmick multifunction inkjet.

It was unfortunate that I didn’t check www.linuxprinting.org first, because I bought the Canon Pixma MP620. Sure, it’s a nice printer with respectable photo and plain paper printing, good copying and scanning as well. BUT if you don’t want to run a WindowsXP/Vista/7 or Mac to be a print server, then your option is running linux and using Canon’s binary blob libraries linked in with their (imnsho) poorly written ps to Canon converter coupled with cups-bjnp, the reverse-engineered BubbleJet Network Protocol implementation.

I’m not opposed to running linux, not by any stretch. However, I really do prefer to run the OS that I actually help develop, as much as humanly possible.

With that in mind, I pulled down the source for the “linux drivers” from Canon ran a bunch of configure scripts (remembering to use gcc, and adding LDFLAGS=”-lnsl -lsocket” to the env) and got started. All proceeded reasonably well until I got to what turns out to be the actual kernel of the problem: cnijfilter. This utility is the one which takes ghostscript’s ppmraw output and turns it into Canon-specific control codes which you can then send across the wire using cups-bjnp.

To get this to compile (as distinct from linking, more on that shortly), I had to make these changes to cnijfilter/src/getipc.c:

44c44
<     struct sockaddr_un        sun;
-
>     struct sockaddr_un    cifsun;
55,57c55,57
<     sun.sun_family = AF_UNIX;
<     strncpy(sun.sun_path, sname, sizeof(sun.sun_path) );
<     sun.sun_path[sizeof(sun.sun_path) - 1] = ‘\0′;
-
>     cifsun.sun_family = AF_UNIX;
>     strncpy(cifsun.sun_path, sname, sizeof(cifsun.sun_path) );
>     cifsun.sun_path[sizeof(cifsun.sun_path) - 1] = ‘\0′;
59c59
<     adrlen = sizeof(sun.sun_family) + strlen(sun.sun_path);
-
>     adrlen = sizeof(cifsun.sun_family) + strlen(cifsun.sun_path);
61c61
<     if (bind(s, (struct sockaddr *)&sun, adrlen))
-
>     if (bind(s, (struct sockaddr *)&cifsun, adrlen))
67c67
<     while ((c = accept(s, (struct sockaddr *)&sun, &adrlen)) >= 0) {
-
>     while ((c = accept(s, (struct sockaddr *)&cifsun, &adrlen)) >= 0) {

which helped with some symbol name clashes (at least, it did prior to build 143).

That left me with the binary blob linking problems. Fortunately, Canon actually supplies libraries which do the real work of the translation. Unfortunately (for me), those libraries all seemed to need linux’ libc.so.6, libdl.so.2 and libpthread.so.0. There are two specific symbols which they required: __errno_location(), and stderr. Now this I could do something about.

The link phase for the binary throws up these errors:

$   /opt/SUNWspro/SS12/bin/cc -O2 -L../../319/libs_bin -o cif bjferror.o bjfilter.o bjfimage.o bjfoption.o bjfpos.o bjfrcaccess.o getipc.o bjflist.o -lcnbpcmcm319 -lcnbpess319 -lm -ldl -ltiff -lpng -lcnbpcnclapi319 -lcnbpcnclbjcmd319 -lcnbpcnclui319 -lpopt
ld: warning: file libc.so.6: required by ../../319/libs_bin/libcnbpcmcm319.so, not found
ld: warning: file libpthread.so.0: required by ../../319/libs_bin/libcnbpess319.so, not found
ld: warning: file libdl.so.2: required by ../../319/libs_bin/libcnbpess319.so, not found
Undefined   first referenced
symbol      in file
bind        getipc.o
accept      getipc.o
listen      getipc.o
socket      getipc.o
stderr      ../../319/libs_bin/libcnbpcnclapi319.so
__errno_location ../../319/libs_bin/libcnbpcmcm319.so
ld: fatal: symbol referencing errors. No output written to cif
gmake: *** [cif] Error 1

Which is annoying at best. To get past this problem, I crafted up this little file:

#include <stdio.h>
int *
__errno_location(void) {
    return (int *)NULL;
}

#define stdin           (&_iob[0])
#define stdout          (&_iob[1])
#define stderr          (&_iob[2])

which I called fakery.c. I also created this mapfile to use when linking it:

$mapfile_version 2
SYMBOL_SCOPE {
    global:
        __errno_location;
        stderr;
};
SYMBOL_VERSION GLIBC_2.3.2 {} GLIBC_2.1.3;
SYMBOL_VERSION GLIBC_2.1.3 {} GLIBC_2.1;
SYMBOL_VERSION GLIBC_2.1 {} GLIBC_2.0 ;
SYMBOL_VERSION GLIBC_2.0 {} GLIBC_PRIVATE;
SYMBOL_VERSION GLIBC_PRIVATE { local: *;};

I then compiled fakery.c using

cc -G -Kpic -M MAPFILE.libc -R/opt/local/lib/canon -o libc.so.6 fakery.c

Lo and behold, I now had a libc.so.6:

$ file libc.so.6
libc.so.6:    ELF 32-bit LSB dynamic lib 80386 Version 1, dynamically linked, not stripped

with the requisite symbols available:

$ nm libc.so.6 |egrep "WEAK|GLOB"
[55]    |      1632|        28|FUNC |GLOB |0    |8      |__errno_location
[53]    |     67268|         0|OBJT |GLOB |0    |13     |_DYNAMIC
[46]    |     67532|         0|OBJT |GLOB |0    |16     |_edata
[50]    |     67536|         0|OBJT |GLOB |0    |17     |_end
[52]    |

      1720|         0|OBJT |GLOB |0    |11     |_etext
[51]    |     67256|         0|OBJT |GLOB |3    |12     |_GLOBAL_OFFSET_TABLE_
[54]    |         0|         0|OBJT |GLOB |0    |ABS    |_PROCEDURE_LINKAGE_TABLE_
[47]    |         0|         0|OBJT |WEAK |0    |ABS    |GLIBC_2.0
[48]    |         0|         0|OBJT |WEAK |0    |ABS    |GLIBC_2.1
[49]    |         0|         0|OBJT |WEAK |0    |ABS    |GLIBC_2.1.3
[43]    |         0|         0|OBJT |WEAK |0    |ABS    |GLIBC_2.3.2
[44]    |         0|         0|OBJT |GLOB |0    |ABS    |GLIBC_PRIVATE
[45]    |     67532|         4|OBJT |GLOB |0    |17     |stderr

Yay. Now for lib_dl.c and lib_pthread.c (the same file), and their mapfile:

$mapfile_version 2
SYMBOL_VERSION GLIBC_2.3.2 {} GLIBC_2.1.3;
SYMBOL_VERSION GLIBC_2.1.3 {} GLIBC_2.1;
SYMBOL_VERSION GLIBC_2.1 {} GLIBC_2.0 ;
SYMBOL_VERSION GLIBC_2.0 {} GLIBC_PRIVATE;
SYMBOL_VERSION GLIBC_PRIVATE { local: *;};

So I could do the same trick to generate libdl.so.2 and libpthread.so.0:

cc -G -Kpic -M MAPFILE.libs -R/opt/local/lib/canon -o libdl.so.2 otherlibs.c

Then I re-ran the cnijfilter link stage again, by hand:

$ /opt/SUNWspro/SS12/bin/cc -lnsl -lsocket -O2 -L../../319/libs_bin \
    -o cif bjferror.o bjfilter.o bjfimage.o bjfoption.o bjfpos.o \
    bjfrcaccess.o getipc.o bjflist.o -lcnbpcmcm319 -lcnbpess319 \
    -lm -ldl -ltiff -lpng -lcnbpcnclapi319 -lcnbpcnclbjcmd319 \
    -lcnbpcnclui319 -lpopt **-R/opt/local/lib/canon -L../../FAKE/**

Note the last bit – I’m adding an rpath (runtime path) so the binary will search for the libraries in /opt/local/lib/canon, and I added the directory for these fake libraries to the linker search path. Now the bits compile and link, and with an LD_LIBRARY_PATH entry in my environment I can see all the required libraries being found:

$ LD_LIBRARY_PATH=/opt/local/lib/canon ldd cif
    libnsl.so.1 =>     /lib/libnsl.so.1
    libsocket.so.1 =>     /lib/libsocket.so.1
    libcnbpcmcm319.so =>     /opt/local/lib/canon/libcnbpcmcm319.so
    libcnbpess319.so =>     /opt/local/lib/canon/libcnbpess319.so
    libm.so.2 =>     /lib/libm.so.2
    libdl.so.1 =>     /lib/libdl.so.1
    libtiff.so.3 =>     /usr/lib/libtiff.so.3
    libpng12.so.0 =>     /usr/lib/libpng12.so.0
    libcnbpcnclapi319.so =>     /opt/local/lib/canon/libcnbpcnclapi319.so
    libcnbpcnclbjcmd319.so =>     /opt/local/lib/canon/libcnbpcnclbjcmd319.so
    libcnbpcnclui319.so =>     /opt/local/lib/canon/libcnbpcnclui319.so
    libpopt.so.0 =>     /usr/lib/libpopt.so.0
    libc.so.1 =>     /lib/libc.so.1
    libmp.so.2 =>     /lib/libmp.so.2
    libmd.so.1 =>     /lib/libmd.so.1
    libc.so.6 =>     /opt/local/lib/canon/libc.so.6
    libdl.so.2 =>     /opt/local/lib/canon/libdl.so.2
    libpthread.so.0 =>     /opt/local/lib/canon/libpthread.so.0
    libjpeg.so.62 =>     /usr/lib/libjpeg.so.62
    libz.so.1 =>     /lib/libz.so.1

Still needed a wrapper script with it otherwise those binary blob libraries in /opt/local/lib/canon would fail to find libc.so.6:

#!/bin/bash
LD_LIBRARY_PATH=/opt/local/lib/canon exec /opt/local/bin/cifmp610.bin $*

But otherwise it seemed to be a reasonable start. It took a few reads of the Linker and Libraries Guide, and some back-n-forth help from the linker aliens but now I had a working binary translator.

Next step – cups-bjnp, but this actually turned out to be the bit which stopped me in my tracks.

I could hack the source ok to make it compile using getifaddrs:

558a559
> #ifndef __sun
562a564,569
> #else
>     if ((interface->ifa_addr == NULL) || (interface->ifa_broadaddr == NULL) ||
>         (interface->ifa_addr->ss_family != AF_INET) ||
>         (((struct sockaddr_in *) interface->ifa_addr)->sin_addr.s_addr ==
>         htonl(INADDR_LOOPBACK)))
> #endif

But it turns out that the Solaris behaviour is different to the linux behaviour – and I just do not have the time or energy to actually go and figure out how the packets are being misinterpreted. Yes, I snooped a bunch of the network traffic, but I’m stumped.

So I’m giving up on this printer, and Canon’s “open source” linux bits (did I mention they ship under GPLv2?). Until I can get my bones together to get an Epson (tx810fw is in the linuxprinting.org fully supported list, and Epson’s source for their translator is all open), I’ll run up my archlinux vbox and print using that instead.

I’m not going to buy another Canon printer, and I strongly suggest that if you want to have a printer which works under an open source operating system (using CUPS, of course) then you check out what is listed at www.linuxprinting.org/printers before making a purchase.


I’d like to thank Rod Evans, Ali Bahrami and Enrico Perla for all their help and patience with trying to get this figured out. With their help I’ve learnt quite a bit more about our linker capabilities, and the utilities (elfedit, elfdump, lari, crle and moe amongst others) which they’ve written to make it possible for me to turn code into something that runs.




And now for those who prefer unified diffs…

Grumble!

cnijfilter/src/getipc.c:

$ diff -U 3 getipc.c getipc.c.j
--- getipc.c        Tue May  8 18:45:16 2007
+++ getipc.c.j      Tue Jul 13 23:48:04 2010
@@ -41,7 +41,7 @@
short GetIPCData(LPIPCU pipc, char *sname)
{
-   struct sockaddr_un              sun;
+   struct sockaddr_un      cifsun;
int                                         s, c;
char                                        buf[128];
size_t                                      adrlen;
@@ -52,19 +52,19 @@
unlink(sname);
-   sun.sun_family = AF_UNIX;
-   strncpy(sun.sun_path, sname, sizeof(sun.sun_path) );
-   sun.sun_path[sizeof(sun.sun_path) - 1] = '\0';
+   cifsun.sun_family = AF_UNIX;
+   strncpy(cifsun.sun_path, sname, sizeof(cifsun.sun_path) );
+   cifsun.sun_path[sizeof(cifsun.sun_path) - 1] = '\0';
-   adrlen = sizeof(sun.sun_family) + strlen(sun.sun_path);
+   adrlen = sizeof(cifsun.sun_family) + strlen(cifsun.sun_path);
-   if (bind(s, (struct sockaddr *)&sun, adrlen))
+   if (bind(s, (struct sockaddr *)&cifsun, adrlen))
return RET_ERROR;
if (listen(s, 5))
return RET_ERROR;
-   while ((c = accept(s, (struct sockaddr *)&sun, &adrlen)) >= 0) {
+   while ((c = accept(s, (struct sockaddr *)&cifsun, &adrlen)) >= 0) {
/* read command first */
read(c, buf, IPCCMDLEN);

And cups-bjnp-0.5.4/bjnp-io.c:

$ diff -U 3 bjnp-io.c bjnp-io.c.j
--- bjnp-io.c       Sun May 17 05:40:57 2009
+++ bjnp-io.c.j     Wed Jul 21 22:34:52 2010
@@ -556,10 +556,17 @@
{
/* send broadcast packet to each suitable  interface */
+#ifndef __sun
if ((interface->ifa_addr == NULL) || (interface->ifa_broadaddr == NULL) ||
(interface->ifa_addr->sa_family != AF_INET) ||
(((struct sockaddr_in *) interface->ifa_addr)->sin_addr.s_addr ==
htonl(INADDR_LOOPBACK)))
+#else
+   if ((interface->ifa_addr == NULL) || (interface->ifa_broadaddr == NULL) ||
+       (interface->ifa_addr->ss_family != AF_INET) ||
+       (((struct sockaddr_in *) interface->ifa_addr)->sin_addr.s_addr ==
+       htonl(INADDR_LOOPBACK)))
+#endif
{
/* not an IPv4 capable interface */