#! /bin/bash

# TC1000 Tablet PC  serial port (pen) enabler script. 
#
# Version 1.0
#
# Author: David Kuehling <dvdkhlng@gmx.de>
# 
# You may use this script under the terms of the GPL.  Note that there is 
# absolutely no warranty of any kind.  If this damages your hardware don't
# blame me.

# abort on error
set -e

bridge_id=1106:0686
superio_index_port=0x3f0
superio_data_port=0x3f1

abort () 
{
    exec false
}

# bridge_read <addr> -- read from config space of VIA VT82C686 bridge
bridge_read ()
{
    # note that numbers passed to setpci are implicetely hexadecimal
    addr=$1
    val=$(setpci -d $bridge_id $(printf %x $addr).b)
    echo -n "0x$val"
    echo "bridge_read $addr = 0x$val" 1>&2
}

# bridge_read <addr> <val> -- write to config space of VIA VT82C686 bridge
bridge_write ()
{
    # note that numbers passed to setpci are implicetely hexadecimal
    addr=$1
    val=$2
    setpci -v -d $bridge_id $(printf %x $addr).b=$(printf %x $val) 1>&2
}

# inb <port>  -- read from port and print decimal unsigned value to stdout
inb()
{
    port=$1
    dd if=/dev/port bs=1 skip=$(printf %i $port) | \
	od -j $port -N 1 -tuC | (
	read addr val; echo -n $val
	echo "read port $port = $val" 1>&2
    )

}

# outb <val> <port>  -- write value to port
outb ()
{
    val=$1
    port=$2
    echo -en \\$(printf %03o $val) | \
	dd of=/dev/port bs=1 seek=$(printf %i $port) count=1
    echo "wrote port $port = $val" 1>&2
}

superio_config_enable ()
{
    val=$(bridge_read 0x85)
    let 'val = val & ~0x02' || true

    if let $1; then
	let 'val = val | 0x02' || true
    fi

    bridge_write 0x85 $val
}

# superio_config_read <index>  -- write unsigned value to stdout
superio_config_read ()
{
    index=$1
    outb $index $superio_index_port
    inb $superio_data_port

    echo "superio config read $index" 1&>2
}

# superio_config_write <index> <data> 
superio_config_write ()
{
    index=$1
    data=$2
    outb $index $superio_index_port
    outb $data $superio_data_port
    echo "superio config wrote $index=$data" 1&>2
}

uart_enable ()
{
    superio_config_enable 1

    # Super-I/O function select: if serial port was enabled, disable it now
    val=$(superio_config_read 0xE2)
    let 'val = val & ~0x4' || true 
    superio_config_write 0xE2 $val

    # set serial port 1 I/O base address to the usual 0x3F8 */
    let 'val = 0x3f8 >> 2' || true
    superio_config_write 0xE7 $val

    # set the IRQ of serial port 1 to IRQ4.  IRQ routing is controlled from
    # the PCI configuration space of the VIA82C686 at offset 0x52 ("PNP IRQ
    # Routing 2"), the lower nibble sets serial port 1 IRQ, the higher
    # nibble set serial port 2 IRQ.  
    val=$(bridge_read 0x52)
    let 'val = (val & 0xF0) | 0x04' || true
    bridge_write 0x52 $val

    # now we can enable serial port
    val=$(superio_config_read 0xE2)
    let 'val = val | 0x04' || true
    superio_config_write 0xE2 $val

    # end of Super-I/O configuration
    superio_config_enable 0
}

if test $(whoami) != root; then
    echo "You must be root to run that shell script." 1>&2
    abort
fi

uart_enable
