# [SOLVED] Undocking Lenovo Thinkpad

## schiotz

I have a Lenovo Thinkpad T60.  Does anybody know how to undock it from

the "Advanced Mini-Dock" when using Linux?  In Windows, I press the

undock button on the dock, Windows does something, a light changes on

the dock, and I press the key that ejects the computer.

Is there a program I should run under Linux before ejecting the

computer?  I have been told that some electrical connections need to

be broken before it is safe to undock the computer, but on the other

hand nothing seems to be disconnected when Windows reacts to the

undock button.  The external flatscreen does blank for a few seconds,

but it comes back on; the USB devices and the ehternet on the dock

still work.

Perhaps I can just eject the computer under linux?  Should I run a

special program?  Is it OK just to suspend it, and then eject (the "do

not eject" lamp remains lid when suspending)?

Your experiences are welcome!

JakobLast edited by schiotz on Thu Mar 19, 2009 1:32 pm; edited 1 time in total

----------

## asturm

would be of interest for me to since I'm about to get an X200s + docking station. The Lenovo woman on my university though assured me that the dock would run completely without software driver needs.

----------

## DirtyHairy

There's support for this in the kernel thinkpad-acpi driver; see /usr/src/linux/Documentation//laptops/thinkpad-acpi.txt

----------

## asturm

Ok, dock support still seems to be a mixed bag. But it works, I found that in the docs:

```
Docking / undocking -- /proc/acpi/ibm/dock

------------------------------------------

Docking and undocking (e.g. with the X4 UltraBase) requires some

actions to be taken by the operating system to safely make or break

the electrical connections with the dock.

The docking feature of this driver generates the following ACPI events:

   ibm/dock GDCK 00000003 00000001 -- eject request

   ibm/dock GDCK 00000003 00000002 -- undocked

   ibm/dock GDCK 00000000 00000003 -- docked

NOTE: These events will only be generated if the laptop was docked

when originally booted. This is due to the current lack of support for

hot plugging of devices in the Linux ACPI framework. If the laptop was

booted while not in the dock, the following message is shown in the

logs:

   Mar 17 01:42:34 aero kernel: thinkpad_acpi: dock device not present

In this case, no dock-related events are generated but the dock and

undock commands described below still work. They can be executed

manually or triggered by Fn key combinations (see the example acpid

configuration files included in the driver tarball package available

on the web site).

When the eject request button on the dock is pressed, the first event

above is generated. The handler for this event should issue the

following command:

   echo undock > /proc/acpi/ibm/dock

After the LED on the dock goes off, it is safe to eject the laptop.

Note: if you pressed this key by mistake, go ahead and eject the

laptop, then dock it back in. Otherwise, the dock may not function as

expected.
```

No information about my X200s there at http://ibm-acpi.sourceforge.net/  :Confused:  I guess I'll need to pioneer there.

----------

## schiotz

Thank you very much for your comments!

The thinkpad-acpi script apparently does the undocking stuff itself

when the button is pressed.  The the light switches on the dock, an

(unlike in windows!) the ethernet and usb ports of the docking station

are switched off.

 *genstorm wrote:*   

> 
> 
> The docking feature of this driver generates the following ACPI events:
> 
> 	ibm/dock GDCK 00000003 00000001 -- eject request
> ...

 

Unfortunately, these events are *not* generated, instead these lines

appear in the log:

```

Mar 19 14:04:50 demokrit ACPI: \_SB_.GDCK - undocking

Mar 19 14:04:50 demokrit usb 1-6: USB disconnect, address 12

Mar 19 14:04:50 demokrit usb 1-6.1: USB disconnect, address 13

Mar 19 14:04:50 demokrit usb 1-6.1.4: USB disconnect, address 15

Mar 19 14:04:51 demokrit usb 1-6.2: USB disconnect, address 14

```

but I cannot catch this with acpid, and therefore I cannot run a

script using xrandr to switch to the internal panel.

 *Quote:*   

> 
> 
> When the eject request button on the dock is pressed, the first event
> 
> above is generated. The handler for this event should issue the
> ...

 

The kernel docs are out of date here, /proc/acpi/ibm/dock does not

exist.  Instead I found that

```

    echo 1 > /sys/bus/platform/drivers/thinkpad_acpi/thinkpad_acpi/subsystem/devices/dock.0/undock

```

does the same thing.

This is good!  :Smile: 

Now I can write a small script that I can execute on the command line

to properly undock.

Thanks for your help!

/Jakob

----------

## schiotz

OK, here are the scripts that I am using.

/usr/local/sbin/undock.sh switches the display to the panel, and then

undocks.  I use an alias to call it through sudo when logged in as a

normal user.

/usr/local/bin/toggle-video.py is used to switch displays.  It is

called when Fn-F7 is called to enable or disable an external

projector.  In addition, it is called with the --sane argument from

/usr/kde/3.5/share/config/kdm/Xsetup to switch of the panel if docked

(otherwise the resolution is wrong), and is called the same way when

waking up from suspend/hibernate.  Finally, I call it from undock.sh

with the --panel option to force the panel on and all other displays

off.

toggle-video.py does not work with the closed-source ATI driver

(ati-drivers).  I use the open source drivers (radeon or radeonhd).

The only thing missing is to find a way to call toggle-video.py --sane

when docking again.  But I assume that I will usually dock a sleeping

laptop, and then the wakeup should handle that part.

/usr/local/sbin/undock.sh

```

#!/bin/bash

/usr/local/bin/toggle-video.py --root --panel

echo 1 > /sys/bus/platform/drivers/thinkpad_acpi/thinkpad_acpi/subsystem/devices/dock.0/undock

```

/usr/local/bin/toggle-video.py

```

#!/usr/bin/python

import sys

import os

import commands

import re

from syslog import syslog, openlog

tristate = True

def get_output_state(line):

    words = line.split()

    if words[1] == "disconnected":

        conn = False

    elif  words[1] == "connected":

        conn = True

    else:

        syslog("Cannot parse line: " + line)

        sys.exit(1)

    #active = (len(words) > 2)

    active = (re.search("\d+x\d+\+\d+\+\d+", line) is not None)

    return (words[0], conn, active)

def activate(device, special=False):

    syslog('Activating output device '+device)

    if special:

        cmd = 'xrandr --output '+device+' --mode 1024x768 --rate 60'

    else:

        cmd = 'xrandr --output '+device+' --auto'

    syslog('Running "%s"' % (cmd,))

    (stat, info) = commands.getstatusoutput(cmd)

    if stat:

        syslog("Activating %s failed:" % (device,))

        syslog(info)

        sys.exit(1)

def deactivate(device):

    syslog('Deactivating output device '+device)

    cmd = 'xrandr --output '+device+' --off'

    (stat, info) = commands.getstatusoutput(cmd)

    if stat:

        syslog("Deactivating %s failed:" % (device,))

        syslog(info)

        sys.exit(1)

# Write to syslog under the script name

openlog(os.path.basename(sys.argv[0]))

# The --root argument is a special first argument

if len(sys.argv) >= 2 and sys.argv[1] == "--root":

    del sys.argv[1]  # Process remaining args without this one

    # Now we need to find out who is logged on to :0 and use that users

    # DISPLAY and .Xauthority

    query = "/usr/bin/who"

    (stat, info) = commands.getstatusoutput(query)

    if stat:

        syslog('Command failed: '+query)

        syslog(info)

        sys.exit(1)

    for line in info.split('\n'):

        words = line.split()

        if words[1] == ":0":

            user = words[0]

            os.environ["DISPLAY"] = ":0"

            xauth = "/home/%s/.Xauthority" % (user,)

            os.environ["XAUTHORITY"] = xauth

            syslog('Root mode: Using %s' % (xauth,))

        

sanearg = panelarg = extarg = False

if (len(sys.argv) >= 2):

    sanearg = (sys.argv[1] == '--sane')

    extarg = (sys.argv[1] == '--ext')

    panelarg = (sys.argv[1] == '--panel')

    if not (sanearg or extarg or panelarg):

        syslog("Unknown command line argument.")

        print >> sys.stderr, "Unknown command line argument."

        sys.exit(1)

query = 'xrandr -q'

(stat, info) = commands.getstatusoutput(query)

if stat:

    syslog('Command failed: '+query)

    syslog(info)

    sys.exit(1)

connected = {}

turnedon = {}

for line in info.split('\n'):

    if line.startswith('Screen 0:'):

        pass

    elif line.startswith('Screen'):

        syslog('Giving up: xrandr reports more than one screen: '+line)

        sys.exit(1)

    elif line.startswith('VGA'):

        (name, conn, on) = get_output_state(line)

        projector = name

        connected[name] = conn

        turnedon[name] = on

    elif line.startswith('DVI'):

        (name, conn, on) = get_output_state(line)

        extscreen = name

        connected[name] = conn

        turnedon[name] = on

    elif line.startswith('PANEL') or line.startswith('LVDS'):

        (name, conn, on) = get_output_state(line)

        panel = name

        connected[name] = conn

        turnedon[name] = on

    elif line.startswith(' '):

        pass

    else:

        syslog('Giving up: unknown line from xrandr: '+line)

        sys.exit(1)

syslog("Projector:    Connected: %s  Active: %s" % (connected[projector],

                                                    turnedon[projector]))

syslog("Ext. display: Connected: %s  Active: %s" % (connected[extscreen],

                                                    turnedon[extscreen]))

syslog("Panel:        Connected: %s  Active: %s" % (connected[panel],

                                                    turnedon[panel]))

if (sanearg):

    # Set a sane system: ext. screen if connected, otherwise panel

    if connected[extscreen]:

        if not turnedon[extscreen]:

            activate(extscreen)

        if turnedon[panel]:

            deactivate(panel)

    else:

        if not turnedon[panel]:

            activate(panel)

    if connected[projector] and not turnedon[projector]:

        activate(projector, special=True)

elif (panelarg):

    activate(panel)

    if turnedon[extscreen]:

        deactivate(extscreen)

    if turnedon[projector]:

        deactivate(projector)

elif (extarg):

    if not connected[projector]:

        syslog("Cannot turn on the projector: it is not connected")

    else:

        # Always activate projector: We may need to change resolution.

        activate(projector, special=True)

        if turnedon[extscreen]:

            deactivate(extscreen)

        if turnedon[panel]:

            deactivate(panel)        

else:

    # Toggle projector if connected

    if connected[extscreen] and turnedon[extscreen]:

        normal = extscreen

    else:

        normal = panel

    

    if connected[projector]:

        # Cycle throug (normal) -> (normal+projector) -> (projector)

        if tristate and (turnedon[normal] and not turnedon[projector]):

            syslog("Desired state: normal+projector")

            activate(normal, special=True)  # Change resolution

            activate(projector, special=True)

        elif turnedon[normal] and not turnedon[projector]:

            syslog("Desired state: projector")

            activate(projector, special=True)

            deactivate(normal)

        elif turnedon[normal] and turnedon[projector]:

            syslog("Desired state: projector")

            deactivate(normal)

        else:

            # Presumably only the projector is active, but who knows...

            syslog("Desired state: normal")

            if not turnedon[normal]:

                activate(normal)

            if turnedon[projector]:

                deactivate(projector)

    else:

        # Projector is not connected.  Turn on ext. screen or panel

        if connected[extscreen]:

            if not turnedon[extscreen]:

                activate(extscreen)

            if turnedon[panel]:

                deactivate(panel)

        else:

            if not turnedon[panel]:

                activate(panel)

        if turnedon[projector]:

            deactivate(projector)

```

----------

## asturm

This is great. Bookmarking this thread.  :Wink: 

*now impatiently waiting for his X200s*

I'll also have to look for an automated backup script, when docking it to rsync (or similar) to the Ultraslim-HDD.  :Smile: 

----------

