TI 7×21 FlashMedia/SD Host Controller (104C:8033 & 104C:8034)

Update: TI 7x21 FlashMedia/SD Host Controller (104C:8033 & 104C:8034)

The Compaq R4100 series of laptops feature a 6-in-1 memory card reader based on the widely used Texas Instruments 7x21 chips. Although TI provides Windows drivers there is very little information available to assist in development of a free Linux device driver for it.

It appears that TI actually contracted another company (Everest) to write a Linux device driver, although the write-up on their work shows great potential there is no sign of the driver or its source code. There is however a binary version of the driver built for the 2.6.11 kernel available here - unfortunately it's useless for me since I am running a 64-bit kernel.

I found a few promising leads while Googling where reverse engineering the Windows driver was helping development of a native kernel driver for it.

http://tifmxx.berlios.de/
http://www.webcon.ca/~imorgan/tifm21/

Unfortunately there is no fully working driver as yet, however the Subversion repository at tifmxx.berlios.de is very active, I checked out the latest revision of the code to test it out

make
insmod tifmxx.ko

returned:

tifmxx: Unknown symbol scsi_remove_host
tifmxx: Unknown symbol pci_intx
tifmxx: Unknown symbol tifmxx_mmcsd_wait_for_ae
tifmxx: Unknown symbol scsi_host_put
tifmxx: Unknown symbol tifmxx_mmcsd_wait_for_brs
tifmxx: Unknown symbol tifmxx_mmcsd_wait_for_card
tifmxx: Unknown symbol scsi_add_host
tifmxx: Unknown symbol tifmxx_mmcsd_wait_for_af
tifmxx: Unknown symbol scsi_host_alloc
tifmxx: Unknown symbol __scsi_add_device
tifmxx: Unknown symbol scsi_remove_host
tifmxx: Unknown symbol pci_intx
tifmxx: Unknown symbol tifmxx_mmcsd_wait_for_ae
tifmxx: Unknown symbol scsi_host_put
tifmxx: Unknown symbol tifmxx_mmcsd_wait_for_brs
tifmxx: Unknown symbol tifmxx_mmcsd_wait_for_card
tifmxx: Unknown symbol scsi_add_host
tifmxx: Unknown symbol tifmxx_mmcsd_wait_for_af
tifmxx: Unknown symbol scsi_host_alloc
tifmxx: Unknown symbol __scsi_add_device

Trawling mailing-lists I found that "pci_intx" wasn't implemented by the kernel in version 2.6.11-1.1369 but it is in later releases like 2.6.14-1.1656 which I also tested with. To workaround this in 2.6.11-1.1369 the recommendation was to add the following code to the top of tifmxx_hw.c.

C++:
  1. static void pci_intx(struct pci_dev *pdev, int enable)
  2. {
  3.  u16 pci_command, new;
  4.  
  5.  pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
  6.  
  7.  if (enable)
  8.    new = pci_command & ~PCI_COMMAND_INTX_DISABLE;
  9.  else
  10.    new = pci_command | PCI_COMMAND_INTX_DISABLE;
  11.  
  12.  if (new != pci_command)
  13.    pci_write_config_word(pdev, PCI_COMMAND, pci_command);
  14. }

Although this avoided the pci_intx problem the others remained, *probably* down to SCSI not being enabled in the Fedora Core 4 standard kernel; the missing tifmxx_ symbols simply aren't implemented yet. Rebuilding it without the pci_intx hack on my 2.6.14-1.1659 kernel appeared to be a lot better, looks promising.

tifmxx: Unknown symbol scsi_remove_host
tifmxx: Unknown symbol scsi_add_device
tifmxx: Unknown symbol tifmxx_mmcsd_wait_for_ae
tifmxx: Unknown symbol scsi_host_put
tifmxx: Unknown symbol tifmxx_mmcsd_wait_for_brs
tifmxx: Unknown symbol tifmxx_mmcsd_wait_for_card
tifmxx: Unknown symbol scsi_add_host
tifmxx: Unknown symbol tifmxx_mmcsd_wait_for_af
tifmxx: Unknown symbol scsi_host_alloc

After my recent success with ndiswrapper I decided to give it a bash using some Windows x64 drivers I found while trawling the net. It appears to be an official release for Windows x64 labelled "TI 7x21 FlashMedia/SD Host controller driver -Win64", "version 2.0.0.0", "build id FBCRX02W" - but I found no mention of it on their website - download it here.

ndiswrapper -i tifm21.inf
modprobe ndiswrapper

returned:

ndiswrapper (import:239): unknown symbol: ntoskrnl.exe:'ExReleaseFastMutex'
ndiswrapper (import:239): unknown symbol: ntoskrnl.exe:'ExAcquireFastMutex'
ndiswrapper (import:239): unknown symbol: ntoskrnl.exe:'IoUnregisterPlugPlayNotification'
ndiswrapper (import:239): unknown symbol: ntoskrnl.exe:'IoGetDmaAdapter'
ndiswrapper (import:239): unknown symbol: ntoskrnl.exe:'KeLeaveCriticalRegion'
ndiswrapper (import:239): unknown symbol: ntoskrnl.exe:'KeEnterCriticalRegion'
ndiswrapper (import:239): unknown symbol: ntoskrnl.exe:'IoGetDeviceObjectPointer'
ndiswrapper (import:239): unknown symbol: ntoskrnl.exe:'IoRegisterPlugPlayNotification'
ndiswrapper (load_sys_files:218): couldn't prepare driver 'tifm21'
ndiswrapper (load_wrap_driver:112): loadndiswrapper failed (65280); check system log for messages from 'loadndisdriver'

Game Over... It was a long shot anyway...

I have emailed Everest and will try calling them tomorrow, failing that I might try give TI a call, the binary kernel module is labelled as GPL so the source must be available in some form. Other than that I will be keeping an eye on the progress over at tifmxx.berlios.de

One day... maybe it will all just work... Ah yes, just for completeness... Here is a lspci dump:

03:04.0 CardBus bridge: Texas Instruments PCIxx21/x515 Cardbus Controller
Subsystem: Hewlett-Packard Company: Unknown device 3085
Flags: bus master, medium devsel, latency 168, IRQ 185
Memory at b0209000 (32-bit, non-prefetchable) [size=4K]
Bus: primary=03, secondary=04, subordinate=07, sec-latency=176
Memory window 0: 30000000-31fff000 (prefetchable)
Memory window 1: 32000000-33fff000
I/O window 0: 0000a400-0000a4ff
I/O window 1: 0000a800-0000a8ff
16-bit legacy interface ports at 0001

03:04.3 Mass storage controller: Texas Instruments PCIxx21 Integrated FlashMedia Controller
Subsystem: Hewlett-Packard Company: Unknown device 3085
Flags: bus master, medium devsel, latency 64, IRQ 10
Memory at b0206000 (32-bit, non-prefetchable) [size=8K]
Capabilities: [44] Power Management version 2

03:04.4 Class 0805: Texas Instruments PCI6411, PCI6421, PCI6611, PCI6621, PCI7411, PCI7421, PCI7611, PCI7621 Secure Digital (SD) Controller
Subsystem: Hewlett-Packard Company: Unknown device 3085
Flags: bus master, medium devsel, latency 64, IRQ 10
Memory at b020a000 (32-bit, non-prefetchable) [size=256]
Memory at b0208c00 (32-bit, non-prefetchable) [size=256]
Memory at b0208800 (32-bit, non-prefetchable) [size=256]
Capabilities: [80] Power Management version 2

UPDATE: I just got a response from Everest

This is a custom project done for Texas instruments and not open source. Any queries regarding this driver should be addressed to TI.

Broadcom BCM4318 PCI id 14E4:4318 Wireless Adapter

In my previous post I mentioned that I got the wireless adapter in my Compaq R4100 series laptop working with ndiswrapper. It appears this was a total fluke, others have had to add "noapic" kernel parameters to get it working correctly. I found if I set this kernel parameter the wireless adapter wouldn't work at all; without it everything works normally.

Tested on Fedora Core 4 x86_64 (2.6.11-1.1369, 2.6.14-1.1656, 2.6.15-1.1830 & 2.6.15-1.1831)

lspci output:
03:02.0 Network controller: Broadcom Corporation BCM4318 [AirForce One 54g] 802.11g Wireless LAN Controller (rev 02)
Subsystem: Hewlett-Packard Company: Unknown device 1356
Flags: bus master, fast devsel, latency 64, IRQ 177
Memory at b0204000 (32-bit, non-prefetchable) [size=8K]

grub.conf:
default=0
timeout=5
splashimage=(hd0,1)/boot/grub/splash.xpm.gz
hiddenmenu
title Fedora Core (2.6.15-1.1831_FC4)
root (hd0,1)
kernel /boot/vmlinuz-2.6.15-1.1831_FC4 ro root=LABEL=/ rhgb no_timer_check quiet ignore_ff_buttons=PWRF
initrd /boot/initrd-2.6.15-1.1831_FC4.img

Wordpress Hack » Reading MySQL username & password from wp-config.php

A few months ago I was working on a prototype Wordpress plug-in that generated graphs using GNUPlot. To do this it had another script embedded at the end of the file which dumped data from the Wordpress database and produced graphs as images for the output.

The problem is that the GNUPlot section of the script is referred to directly my an "img" XHTML tag and is not loaded by Wordpress itself; it does not have access to the Wordpress database configuration.

To workaround this I wrote the following section of code, it opens the "wp-config.php" file and parses out anything matching the pattern "define( name, value )" into a $config variable. Immediately afterwards it attempts to connect to MySQL using these details.

Bit of a hack, but it was the only nice way I could see to do it and keep the plug-in simple & configuration free.

PHP:
  1. $config = array();
  2.    
  3.    // HACK Read wp-config.php for the Database username/password, including it wouldnt work
  4.    $handle = fopen( "../../wp-config.php", "r" );
  5.    if ( $handle ) {
  6.       $content = '';
  7.       while ( !feof($handle) ) {
  8.          $content .= fread( $handle, 1024 );
  9.       }
  10.       fclose( $handle );
  11.       if ( preg_match_all("/define\s*\(\s*'(.*?)'\s*,\s*'(.*?)'\s*\);/", $content, $matches, PREG_SET_ORDER) ) {
  12.          for ( $i = 0; $i <count($matches); $i++ ) {
  13.             $name = $matches[$i][1]; $value = $matches[$i][2];
  14.             $config[$name] = $value;
  15.          }
  16.       }
  17.    }
  18.  
  19.    
  20.    $link = mysql_connect( $config['DB_HOST'], $config['DB_USER'], $config['DB_PASSWORD']) or die ("Can't connect!");
  21.    mysql_select_db( $config['DB_NAME'] ) or die("Can't select database!");

Fedora Core 4 x86_64 Linux on Compaq R4000 Laptop

The majority of the hardware worked out of the box, the WXGA (1280 x 800) screen needs to be manually frigged into the X configuration. Only the wireless adapter and the memory-card reader are unsupported by the base install.

I got the wireless adapter (Broadcom BCM4318 PCI id 14E4:4318) working using ndiswrapper 1.8 from ndiswrapper.sourceforge.net, it built & installed cleanly into my 64-bit kernel. However, this means you must use 64-bit Windows Device Drivers. Thankfully the List mentions a similar attempt on a HP (HP/Compaq same thing) AMD64 laptop – it works!!

The memory-card reader seems to be harder to get working with mixed reports of success / failure. It appears to be a Texas Instruments PCIxx21, PCI device id 104C:8033 & 104C:8034.

And for my next trick...

Experimenting with Googlebot

In my previous post 'Blogs are fundamentally flawed…' I noted an observation that more often than not search results would direct a user to an index-style page containing the post instead of directly to the 'permalink' location of the post. This leads to a poor user-experience from the visitor’s point of view, on busy blogs the post has almost certainly moved since the page was spider'd. Google in particular appeared to be the worst for it.

Discussions on the subject with Gerry determined that this is most likely down to Google's PageRank technology; where index-style pages have a higher value than the post pages themselves. To get around this he suggested manipulating 'robots.txt' directives within the index-style pages.

On Google's "Information for Webmasters" help page I found they look for special 'robots.txt' directives and meta tags in documents when spidering specific to Googlebot only. This meant I could single out Googlebot for these directives and not affect other search engines (which don’t exhibit the problem so much).

I basically want Google to 'FOLLOW' links on all pages, but not to 'INDEX' the index-style pages like categories & archives by date. The desired effect being that Google can find all posts as before but simply ignore the index-style pages themselves. Implementing this is quite simple; I modified my theme's "header.php" file inserting the following code in the "head" section:

PHP:
  1. <?php
  2.     if ( !is_single() && !is_page() && !is_home() )
  3.         echo "  <meta name=\"GOOGLEBOT\" content=\"NOINDEX,FOLLOW\" />\n";
  4. ?>

This reads almost literally, if this is not a single post view, not a page view or the home page, add the following "meta..." tag. Although the home page is an index-style page I am reluctant to add 'NOINDEX' because I don't want it disappearing from search results. ;)

Now the long wait for the changes to reflect in Google's results.

Updated 24th January 2006 - Gerry pointed out this can be optimised using De Morgan's Law :P

PHP:
  1. <?php
  2.     if ( ! (is_single() || is_page() || is_home()) )
  3.         echo "  <meta name=\"GOOGLEBOT\" content=\"NOINDEX,FOLLOW\" />\n";
  4. ?>

WP Plugin » SpamKit Plugin 0.1 – Time-Based-Tokens to Fight Spam

This is a minor release of SpamKit Plugin to address an easy-to-fix problem where Trackbacks from the same blog or server get treated as spam because they don't include the time-based token. This is checked into Subversion over at WP-Plugins.org and you can download the new version here spamkit-plugin.php.

Changelog:

Added a check in spam_action_pre_comment_approved to compare the REMOTE_ADDR with the SERVER_ADDR, if they match it allows the comment to bypass time-based token checking. However this could be abused if another web application on the server is exploited allowing an attacker to post comments apparently from this server. Then again if someone goes to all the effort of expoiting a web application comment-spam is probably low on their priorities.

Blogs are fundamentally flawed for the typical Grandma-User

It may seem a little sad but I can honestly say that reading my access_log is far more interesting than any soap opera on TV; they are filled with exotic foreigners, futuristic robots, drama, intrigue and personal tragedy. The best thing about it is that it’s all real; these are (mostly) real people who stumble across your humble Blog in the hope to find the solution to their problems.

Over the Christmas period I have observed more people visiting an ancient post of mine than in the past six months. The post is about my experiences with an external hard drive enclosure; more accurately, the chip / controller a great deal of hard drive enclosures use. Based on this I would guess that a considerable number of people got hard drive enclosures for their Christmas and ran into the same problems I had. Anyway, I am wandering a little.

It was reading my access_log's that made me realise that Blogs are actually a really bad format for the Grandma user...

Picture this, imagine your Grandma is Google'ing and happens to get a result that points to your Blog. She see's a teaser in the search results that shows you've written something about what she is looking for. Grandma clicks your link and is presented with your last 10 posts about God knows what and no sign of the post she saw the snippet of. Grandma goes back to Google thoroughly disappointed and never to return...

I encounter this phenomenon frequently, but because I am familiar with the Blog format I think nothing of drilling down to the relevant category to find the post I wanted; or if I am lazy click Google’s cached copy of the page. However for the average internet surfer it presents a fundamental flaw in the usability of the Blog format.

The problem is quite simple; search engines can never be up to date with your content all the time. The more frequent you post the more the problem will occur and the harder the post will be to find. The way I see it there are two possible solutions.

Smarter search engines

Enhancing search engines so they can distinguish between an index-page of posts and individual posts. This could be done by identifying sections of text within a page as an extract from another URL using something like RDF [http://www.w3.org/RDF/] which can already be embedded within XHTML [http://internetalchemy.org/2005/10/introducing-embedded-rdf]. Enclosing the section of text between the ‘<rdf:RDF>’ tags would do the trick.

In the Blog format the index pages and category pages would all contain embedded RDF indicating that the enclosed section of text is actually from another URL – its permalink. However this idea is not just limited to the Blog format, it has huge potential for most modern website formats.

This wouldn’t be a trivial change for search engines to make, it would be time-consuming and therefore costly but I believe it would be worthwhile for the future of internet content.

Smarter websites

A more short-term solution I am looking at is improving my website [i.e. Wordpress] to detect that the visitor has come from a search engine, try and determine the query they used from the ‘Referer’ HTTP header, then find and present the best matches to that query before any other posts are displayed.

Obviously this method has quite a few shortfalls:

* The ‘Referer’ header may not be there (some people disable it within the browser or through third-party software)
* Although handling the query formats of the main players is quite easy, not all search engines can be catered for
* It requires an intensive search of all the site’s posts, the standard Wordpress search won’t cut it

I contemplated getting the site to pull a copy of the URL given in the ‘Referer’ header, scan for the result that led the visitor to your site then locate the correct post given the snippet text… Then I decided that was a reeeeeeaaally bad idea.

In the long-run I believe the content and therefore the search engines that index it have to improve to cater for the format of internet content today and I think embedded RDF might be the key; unfortunately this cannot happen overnight.

In the meantime making smarter websites will help the situation until the content and the search engines catch up.

SpamKit Plugin moved to WP-Plugins.org

This morning I moved SpamKit Plugin over to WP-Plugins.org.

You can always download the latest version directly from here.