NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/46870



The following reply was made to PR kern/46870; it has been noted by GNATS.

From: Nat Sloss <nathanialsloss%yahoo.com.au@localhost>
To: gnats-bugs%netbsd.org@localhost
Cc: 
Subject: Re: kern/46870
Date: Wed, 29 Aug 2012 18:40:38 +1000

 Hi.
 
 Here are the files:
 
 --- /dev/null  2012-08-29 17:38:04.000000000 +1000
 +++ ../../sys/dev/acpi/panasonic_acpi.c        2012-08-29 16:55:51.000000000 
+1000
 @@ -0,0 +1,626 @@
 +/*-
 + * Copyright (c) 2006-2012 Nathanial Sloss 
<nathanialsloss%yahoo.com.au@localhost>
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 LIMITED
 + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 + * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 + * POSSIBILITY OF SUCH DAMAGE.
 + */
 +
 +/*-
 + * Copyright (c) 2003 OGAWA Takaya <t-ogawa%triaez.kaisei.org@localhost>
 + * Copyright (c) 2004 Yoshihiro TAKAHASHI <nyan%FreeBSD.org@localhost>
 + * All rights Reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 + * SUCH DAMAGE.
 + *
 + */
 +
 +#include <sys/cdefs.h>
 +
 +#include <sys/types.h>
 +#include <sys/param.h>
 +#include <sys/buf.h>
 +#include <sys/callout.h>
 +#include <sys/device.h>
 +#include <sys/kernel.h>
 +#include <sys/malloc.h>
 +#include <sys/pmf.h>
 +#include <sys/sysctl.h>
 +
 +#include <dev/acpi/acpivar.h>
 +#include <dev/acpi/acpireg.h>
 +
 +#include <dev/sysmon/sysmonvar.h>
 +
 +#include <sys/fcntl.h>
 +
 +typedef struct panasonic_softc {
 +      device_t                sc_dev;
 +      struct acpi_devnode     *sc_node;
 +
 +      int                     sc_brightness;
 +      int                     sc_brightness_min;
 +      int                     sc_brightness_max;
 +
 +#define PANASONIC_PSW_SLEEP                   0
 +#define       PANASONIC_PSW_HIBERNATE                 1
 +#define       PANASONIC_PSW_DISPLAY_CYCLE             2
 +#define       PANASONIC_PSW_BATTERY_INFO              3
 +#define PANASONIC_PSW_LAST                    4
 +
 +      struct sysmon_pswitch   sc_smpsw[PANASONIC_PSW_LAST];
 +      bool                    sc_smpsw_valid;
 +
 +      struct sysctllog        *sc_log;
 +      int                     sc_brightness_mib;
 +
 +} panasonic_softc_t;
 +
 +/* Hotkey buttons (HKEY) */
 +#define PANASONIC_NOTIFY_BrightnessDownPRESSED        0x81
 +#define PANASONIC_NOTIFY_BrightnessDownRELEASED       0x01
 +
 +#define       PANASONIC_NOTIFY_BrightnessUpPRESSED    0x82
 +#define       PANASONIC_NOTIFY_BrightnessUpRELEASED   0x02
 +
 +#define PANASONIC_NOTIFY_DisplayCyclePRESSED  0x83
 +#define PANASONIC_NOTIFY_DisplayCycleRELEASED 0x03
 +
 +#define PANASONIC_NOTIFY_VolumeMutePRESSED    0x84
 +#define PANASONIC_NOTIFY_VolumeMuteRELEASED   0x04
 +
 +#define PANASONIC_NOTIFY_VolumeDownPRESSED    0x85
 +#define PANASONIC_NOTIFY_VolumeDownRELEASED   0x05
 +
 +#define PANASONIC_NOTIFY_VolumeUpPRESSED      0x86
 +#define PANASONIC_NOTIFY_VolumeUpRELEASED     0x06
 +
 +#define PANASONIC_NOTIFY_SuspendToRamPRESSED  0x07
 +
 +#define PANASONIC_NOTIFY_BatteryInfoPRESSED   0x89
 +#define PANASONIC_NOTIFY_BatteryInfoRELEASED  0x09
 +
 +#define PANASONIC_NOTIFY_SuspendToHddPRESSED  0x0A
 +
 +#define ACPI_SERIAL_BEGIN(x)
 +#define ACPI_SERIAL_END(x)
 +#define ACPI_SERIAL_ASSERT(x)
 +
 +#define HKEY_SET        0
 +#define HKEY_GET        1
 +
 +/* Registers */
 +#define HKEY_REG_LCD_BRIGHTNESS_MAX_AC  0x02
 +#define HKEY_REG_LCD_BRIGHTNESS_MIN_AC  0x03
 +#define HKEY_REG_LCD_BRIGHTNESS_AC      0x04
 +#define HKEY_REG_LCD_BRIGHTNESS_MAX_DC  0x05
 +#define HKEY_REG_LCD_BRIGHTNESS_MIN_DC  0x06
 +#define HKEY_REG_LCD_BRIGHTNESS_DC      0x07
 +#define HKEY_REG_SOUND_MUTE           0x08
 +
 +/* Field definitions */
 +#define HKEY_LCD_BRIGHTNESS_BITS        4
 +#define HKEY_LCD_BRIGHTNESS_DIV         ((1 << HKEY_LCD_BRIGHTNESS_BITS) - 1)
 +
 +#define LCD_BRIGHTNESS_DOWN           0
 +#define LCD_BRIGHTNESS_UP             1
 +
 +#define LCD_BRIGHTNESS_MIN            0
 +#define LCD_BRIGHTNESS_MAX            1
 +
 +#define HARDWARE_UNMUTE                       0
 +#define HARDWARE_MUTE                 1
 +
 +static int    panasonic_match(device_t, cfdata_t, void *);
 +static void   panasonic_attach(device_t, device_t, void *);
 +static int    panasonic_detach(device_t, int);
 +
 +static void   panasonic_notify_handler(ACPI_HANDLE, UINT32, void *);
 +
 +static void   panasonic_init(struct panasonic_softc *);
 +static void   panasonic_sysctl_setup(struct panasonic_softc *);
 +
 +static int
 +acpi_panasonic_hkey_event(device_t, ACPI_INTEGER *);
 +
 +static void
 +acpi_panasonic_hkey_action(device_t, ACPI_INTEGER);
 +
 +static void panasonic_acpi_brightness_up(device_t);
 +
 +static void panasonic_acpi_brightness_down(device_t);
 +
 +static void hkey_lcd_brightness_action(struct panasonic_softc *, int);
 +
 +static int
 +hkey_lcd_brightness(struct panasonic_softc *, int, ACPI_INTEGER *);
 +
 +static ACPI_INTEGER 
 +acpi_panasonic_sinf(ACPI_HANDLE, ACPI_INTEGER);
 +
 +static void
 +acpi_panasonic_sset(ACPI_HANDLE, ACPI_INTEGER, ACPI_INTEGER);
 +
 +static int
 +hkey_sound_mute(ACPI_HANDLE, int, ACPI_INTEGER *);
 +
 +CFATTACH_DECL_NEW(panasonic, sizeof(panasonic_softc_t),
 +    panasonic_match, panasonic_attach, panasonic_detach, NULL);
 +
 +static const char * const panasonic_ids[] = {
 +      "MAT0019",
 +      NULL
 +};
 +
 +static int
 +panasonic_match(device_t parent, cfdata_t match, void *opaque)
 +{
 +      struct acpi_attach_args *aa = opaque;
 +
 +      if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
 +              return 0;
 +
 +      return acpi_match_hid(aa->aa_node->ad_devinfo, panasonic_ids);
 +}
 +
 +static void
 +panasonic_attach(device_t parent, device_t self, void *opaque)
 +{
 +      panasonic_softc_t *sc = device_private(self);
 +      struct acpi_attach_args *aa = opaque;
 +      struct sysmon_pswitch *psw;
 +      ACPI_STATUS rv;
 +
 +      sc->sc_node = aa->aa_node;
 +      sc->sc_dev = self;
 +
 +      aprint_naive(": Panasonic Hotkeys\n");
 +      aprint_normal(": Panasonic Hotkeys\n");
 +
 +      rv = AcpiInstallNotifyHandler(sc->sc_node->ad_handle, ACPI_ALL_NOTIFY,
 +          panasonic_notify_handler, sc);
 +      if (ACPI_FAILURE(rv))
 +              aprint_error_dev(self, "couldn't install notify handler: %s\n",
 +                  AcpiFormatException(rv));
 +
 +      /* Register power switches with sysmon */
 +      psw = sc->sc_smpsw;
 +      sc->sc_smpsw_valid = true;
 +
 +      psw[PANASONIC_PSW_SLEEP].smpsw_name = device_xname(self);
 +      psw[PANASONIC_PSW_SLEEP].smpsw_type = PSWITCH_TYPE_SLEEP;
 +#if notyet
 +      psw[PANASONIC_PSW_HIBERNATE].smpsw_name = device_xname(self);
 +      mpsw[PANASONIC_PSW_HIBERNATE].smpsw_type = PSWITCH_TYPE_HIBERNATE;
 +#endif
 +      int i;
 +      for (i = PANASONIC_PSW_DISPLAY_CYCLE; i < PANASONIC_PSW_LAST; i++)
 +              psw[i].smpsw_type = PSWITCH_TYPE_HOTKEY;
 +      psw[PANASONIC_PSW_DISPLAY_CYCLE].smpsw_name = PSWITCH_HK_DISPLAY_CYCLE;
 +      psw[PANASONIC_PSW_BATTERY_INFO].smpsw_name = PSWITCH_HK_BATTERY_INFO;
 +
 +      for (i = 0; i < PANASONIC_PSW_LAST; i++) {
 +              if (sysmon_pswitch_register(&sc->sc_smpsw[i]) != 0) {
 +                      aprint_error_dev(self,
 +                          "couldn't register with sysmon\n");
 +                      sc->sc_smpsw_valid = false;
 +                      break;
 +              }
 +      }
 +      if (!pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_UP,
 +          panasonic_acpi_brightness_up, true))
 +              aprint_error_dev(self,
 +                  "couldn't register BRIGHTNESS UP handler\n");
 +
 +      if (!pmf_event_register(self, PMFE_DISPLAY_BRIGHTNESS_DOWN,
 +          panasonic_acpi_brightness_down, true))
 +              aprint_error_dev(self,
 +                  "couldn't register BRIGHTNESS DOWN handler\n");
 +
 +      if (!pmf_device_register(self, NULL, NULL))
 +              aprint_error_dev(self, "couldn't establish power handler\n");
 +
 +      panasonic_init(sc);
 +      panasonic_sysctl_setup(sc);
 +}
 +
 +static int
 +panasonic_detach(device_t self, int flags)
 +{
 +      struct panasonic_softc *sc = device_private(self);
 +      int i;
 +
 +      if (sc->sc_smpsw_valid)
 +              for (i = 0; i < PANASONIC_PSW_LAST; i++)
 +                      sysmon_pswitch_unregister(&sc->sc_smpsw[i]);
 +
 +      if (sc->sc_log)
 +              sysctl_teardown(&sc->sc_log);
 +      pmf_device_deregister(self);
 +
 +      return 0;
 +}
 +
 +static void
 +panasonic_notify_handler(ACPI_HANDLE hdl, UINT32 notify, void *opaque)
 +{
 +      panasonic_softc_t *sc = opaque;
 +
 +        ACPI_INTEGER key;
 +      key = 0;
 +
 +      switch (notify) {
 +      case 0x80:
 +              ACPI_SERIAL_BEGIN(panasonic);
 +                if (acpi_panasonic_hkey_event(sc->sc_dev, &key) == 0) {
 +                        acpi_panasonic_hkey_action(sc->sc_dev, key);
 +              }
 +
 +              ACPI_SERIAL_END(panasonic);
 +              break;
 +      default:
 +              aprint_debug_dev(sc->sc_dev, "unknown notify: %#x\n", notify);
 +              break;
 +      }
 +}
 +
 +static void
 +panasonic_init(struct panasonic_softc *sc)
 +{
 +      ACPI_INTEGER val;
 +      ACPI_HANDLE hdl;
 +
 +      hdl = sc->sc_node->ad_handle;
 +      val = HARDWARE_UNMUTE;
 +
 +      /* Unmute the speaker - Hardware */
 +      hkey_sound_mute(hdl, HKEY_SET, &val);
 +
 +      /* Initialise variables */
 +      sc->sc_brightness_min = acpi_panasonic_sinf(hdl,
 +          HKEY_REG_LCD_BRIGHTNESS_MIN_AC);
 +      sc->sc_brightness_max = acpi_panasonic_sinf(hdl,
 +          HKEY_REG_LCD_BRIGHTNESS_MAX_AC);
 +      if (sc->sc_brightness_max <= 0)
 +              sc->sc_brightness_max = 100;
 +      sc->sc_brightness = (acpi_panasonic_sinf(hdl,
 +          HKEY_REG_LCD_BRIGHTNESS_AC) * 100) / sc->sc_brightness_max;
 +}
 +
 +static int
 +panasonic_sysctl_verify(SYSCTLFN_ARGS)
 +{
 +      struct sysctlnode node;
 +      struct panasonic_softc *sc;
 +      ACPI_INTEGER val;
 +      int err, tmp;
 +
 +      node = *rnode;
 +      sc = rnode->sysctl_data;
 +
 +      if (node.sysctl_num == sc->sc_brightness_mib) { 
 +              err = hkey_lcd_brightness(sc, HKEY_GET, &val);
 +              if (err) 
 +                      val = sc->sc_brightness_min;
 +              tmp = (val * 100) / sc->sc_brightness_max;
 +              node.sysctl_data = &tmp;
 +              err = sysctl_lookup(SYSCTLFN_CALL(&node));
 +              if (err || newp == NULL)
 +                      return err;
 +
 +              if (tmp < 0 || tmp > 100)
 +                      return EINVAL;
 +              val = (tmp * sc->sc_brightness_max) / 100;
 +              if (val == 0)
 +                      val = sc->sc_brightness_min;
 +              err = hkey_lcd_brightness(sc, HKEY_SET, &val);
 +              if (err) 
 +                      return err;
 +              tmp = (val * 100) / sc->sc_brightness_max;
 +              sc->sc_brightness = tmp;
 +      }
 +
 +      return 0;
 +}
 +
 +static void
 +panasonic_sysctl_setup(struct panasonic_softc *sc)
 +{
 +      const struct sysctlnode *node, *node_brightness; 
 +      int err;
 +
 +      err = sysctl_createv(&sc->sc_log, 0, NULL, NULL, 0,
 +          CTLTYPE_NODE, "hw", NULL, NULL, 0, NULL, 0, CTL_HW, CTL_EOL);
 +      if (err)
 +              goto sysctl_err;
 +
 +      err = sysctl_createv(&sc->sc_log, 0, NULL, &node, 0,
 +          CTLTYPE_NODE, "panasonic",
 +          SYSCTL_DESCR("Toughbook controls"), NULL, 0,
 +          NULL, 0, CTL_HW, CTL_CREATE, CTL_EOL);
 +      if (err)
 +              goto sysctl_err;
 +
 +      err = sysctl_createv(&sc->sc_log, 0, &node, &node_brightness,
 +          CTLFLAG_READWRITE | CTLFLAG_ANYWRITE, CTLTYPE_INT, "brightness",
 +          SYSCTL_DESCR("Screen brightness (Percent)"),
 +          panasonic_sysctl_verify, 0, sc, 0,
 +          CTL_CREATE, CTL_EOL);
 +      if (err)
 +              goto sysctl_err;
 +      sc->sc_brightness_mib = node_brightness->sysctl_num;
 +
 +      return;
 +sysctl_err:
 +      aprint_error_dev(sc->sc_dev, "failed to add sysctl nodes. (%d)\n", err);
 +}
 +
 +static int
 +acpi_panasonic_hkey_event(device_t self, ACPI_INTEGER *arg) {
 +
 +      struct panasonic_softc *sc = device_private(self);
 +
 +        ACPI_BUFFER buf;
 +        ACPI_OBJECT *res;
 +        ACPI_INTEGER val;
 +        int status;
 +
 +        ACPI_SERIAL_ASSERT(panasonic);
 +        status = ENXIO;
 +
 +        buf.Length = ACPI_ALLOCATE_BUFFER;
 +        buf.Pointer = NULL;
 +        AcpiEvaluateObject(sc->sc_node->ad_handle, "HINF", NULL, &buf);
 +        res = (ACPI_OBJECT *)buf.Pointer;
 +        if (res->Type != ACPI_TYPE_INTEGER) {
 +                aprint_error_dev(self, "HINF returned non-integer\n");
 +                goto end;
 +        }
 +        val = res->Integer.Value;
 +
 +      *arg = val;
 +        status = 0;
 +end:
 +        if (buf.Pointer)
 +                AcpiOsFree(buf.Pointer);
 +
 +        return (status);
 +}
 +
 +static void
 +acpi_panasonic_hkey_action(device_t self, ACPI_INTEGER key)
 +{
 +
 +      struct panasonic_softc *sc = device_private(self);
 +
 +        ACPI_SERIAL_ASSERT(panasonic);
 +
 +        switch (key) {
 +        case PANASONIC_NOTIFY_BrightnessDownPRESSED:
 +              pmf_event_inject(NULL, PMFE_DISPLAY_BRIGHTNESS_DOWN);
 +                      break;
 +        case PANASONIC_NOTIFY_BrightnessDownRELEASED:
 +              break;
 +      case PANASONIC_NOTIFY_BrightnessUpPRESSED:
 +              pmf_event_inject(NULL, PMFE_DISPLAY_BRIGHTNESS_UP);
 +              break;
 +      case PANASONIC_NOTIFY_BrightnessUpRELEASED:
 +              break;
 +      case PANASONIC_NOTIFY_DisplayCyclePRESSED:
 +              if (sc->sc_smpsw_valid == false)
 +                      break;
 +              sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_DISPLAY_CYCLE],
 +                  PSWITCH_EVENT_PRESSED);
 +              break;
 +      case PANASONIC_NOTIFY_DisplayCycleRELEASED:
 +              if (sc->sc_smpsw_valid == false)
 +                      break;
 +              sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_DISPLAY_CYCLE],
 +                  PSWITCH_EVENT_RELEASED);
 +              break;
 +      case PANASONIC_NOTIFY_VolumeMutePRESSED:
 +              pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_TOGGLE);
 +              break;
 +      case PANASONIC_NOTIFY_VolumeMuteRELEASED:
 +              break;
 +      case PANASONIC_NOTIFY_VolumeDownPRESSED:
 +              pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_DOWN);
 +              break;
 +      case PANASONIC_NOTIFY_VolumeDownRELEASED:
 +              break;
 +      case PANASONIC_NOTIFY_VolumeUpPRESSED:
 +              pmf_event_inject(NULL, PMFE_AUDIO_VOLUME_UP);
 +              break;
 +      case PANASONIC_NOTIFY_VolumeUpRELEASED:
 +              break;
 +      case PANASONIC_NOTIFY_SuspendToRamPRESSED:
 +              /* Suspend. */
 +              if (sc->sc_smpsw_valid == false)
 +                      break;
 +              sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_SLEEP],
 +                  PSWITCH_EVENT_PRESSED);
 +              break;
 +      case PANASONIC_NOTIFY_BatteryInfoPRESSED:
 +              if (sc->sc_smpsw_valid == false)
 +                      break;
 +              sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_BATTERY_INFO],
 +                  PSWITCH_EVENT_PRESSED);
 +              break;
 +      case PANASONIC_NOTIFY_BatteryInfoRELEASED:
 +              if (sc->sc_smpsw_valid == false)
 +                      break;
 +              sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_BATTERY_INFO],
 +                  PSWITCH_EVENT_RELEASED);
 +              break;
 +      case PANASONIC_NOTIFY_SuspendToHddPRESSED:
 +#if notyet
 +              /* Hibernate. */
 +              if (sc->sc_smpsw_valid == false)
 +                      break;
 +              sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_HIBERNATE],
 +                  PSWITCH_EVENT_PRESSED);
 +#endif
 +              break;
 +      default:
 +              aprint_error_dev(sc->sc_dev, "Unknown Key 0x%X\n", (int)key);
 +              break;
 +        }
 +}
 +
 +static void
 +panasonic_acpi_brightness_up(device_t self){
 +
 +      struct panasonic_softc *sc = device_private(self);
 +
 +      hkey_lcd_brightness_action(sc, LCD_BRIGHTNESS_UP);
 +
 +}
 +
 +static void
 +panasonic_acpi_brightness_down(device_t self){
 +
 +      struct panasonic_softc *sc = device_private(self);
 +
 +      hkey_lcd_brightness_action(sc, LCD_BRIGHTNESS_DOWN);
 +
 +}
 +
 +static void
 +hkey_lcd_brightness_action(struct panasonic_softc *sc, int direction){
 +
 +      ACPI_INTEGER arg;
 + 
 +      hkey_lcd_brightness(sc, HKEY_GET, &arg);
 +
 +      if (direction == LCD_BRIGHTNESS_UP)
 +              arg += sc->sc_brightness_max / HKEY_LCD_BRIGHTNESS_DIV;
 +      else
 +              arg -= sc->sc_brightness_max / HKEY_LCD_BRIGHTNESS_DIV;
 +
 +      if (arg < sc->sc_brightness_min)
 +              arg = sc->sc_brightness_min;
 +      else if (arg > sc->sc_brightness_max)
 +              arg = sc->sc_brightness_max;
 +
 +      hkey_lcd_brightness(sc, HKEY_SET, &arg);
 +
 +}
 +
 +static int
 +hkey_lcd_brightness(struct panasonic_softc *sc, int op, ACPI_INTEGER *val)
 +{
 +      ACPI_HANDLE hdl;
 +      ACPI_INTEGER reg;
 +
 +      hdl = sc->sc_node->ad_handle;
 +
 +      reg = HKEY_REG_LCD_BRIGHTNESS_AC;
 +
 +      ACPI_SERIAL_ASSERT(panasonic);
 +        switch (op) {
 +        case HKEY_SET:
 +                if (*val < sc->sc_brightness_min ||
 +                  *val > sc->sc_brightness_max)
 +                        return (EINVAL);
 +                acpi_panasonic_sset(hdl, reg, *val);
 +                break;
 +        case HKEY_GET:
 +                *val = acpi_panasonic_sinf(hdl, reg);
 +                break;
 +        }
 +
 +      return (0);
 +}
 +
 +static ACPI_INTEGER
 +acpi_panasonic_sinf(ACPI_HANDLE hdl, ACPI_INTEGER index)
 +{
 +        ACPI_BUFFER buf;
 +        ACPI_OBJECT *res;
 +        ACPI_INTEGER ret;
 +
 +        ACPI_SERIAL_ASSERT(panasonic);
 +        ret = -1;
 +        buf.Length = ACPI_ALLOCATE_BUFFER;
 +        buf.Pointer = NULL;
 +        AcpiEvaluateObject(hdl, "SINF", NULL, &buf);
 +        res = (ACPI_OBJECT *)buf.Pointer;
 +        if (res->Type == ACPI_TYPE_PACKAGE)
 +                ret = res->Package.Elements[index].Integer.Value;
 +        AcpiOsFree(buf.Pointer);
 +
 +        return (ret);
 +}
 +
 +static void
 +acpi_panasonic_sset(ACPI_HANDLE hdl, ACPI_INTEGER index, ACPI_INTEGER val)
 +{
 +      ACPI_OBJECT_LIST args;
 +        ACPI_OBJECT obj[2];
 +
 +        ACPI_SERIAL_ASSERT(panasonic);
 +        obj[0].Type = ACPI_TYPE_INTEGER;
 +        obj[0].Integer.Value = index;
 +        obj[1].Type = ACPI_TYPE_INTEGER;
 +        obj[1].Integer.Value = val;
 +        args.Count = 2;
 +        args.Pointer = obj;
 +        AcpiEvaluateObject(hdl, "SSET", &args, NULL);
 +}
 +
 +static int
 +hkey_sound_mute(ACPI_HANDLE hdl, int op, ACPI_INTEGER *val)
 +{
 +
 +      ACPI_SERIAL_ASSERT(panasonic);
 +        switch (op) {
 +        case HKEY_SET:
 +              if (*val != 0 && *val != 1)
 +                      return (EINVAL);
 +              acpi_panasonic_sset(hdl, HKEY_REG_SOUND_MUTE, *val);
 +              break;
 +        case HKEY_GET:
 +              *val = acpi_panasonic_sinf(hdl, HKEY_REG_SOUND_MUTE);
 +              break;
 +        }
 +
 +       return (0);
 +}
 +
 --- /dev/null  2012-08-29 17:38:04.000000000 +1000
 +++ man4/panasonic.4   2012-08-29 18:04:06.000000000 +1000
 @@ -0,0 +1,74 @@
 +.\"
 +.\" Copyright (c) 2012 Nathanial Sloss <nathanialsloss%yahoo.com.au@localhost>
 +.\" All rights reserved.
 +.\"
 +.\" Redistribution and use in source and binary forms, with or without
 +.\" modification, are permitted provided that the following conditions
 +.\" are met:
 +.\" 1. Redistributions of source code must retain the above copyright
 +.\"    notice, this list of conditions and the following disclaimer.
 +.\" 2. Redistributions in binary form must reproduce the above copyright
 +.\"    notice, this list of conditions and the following disclaimer in the
 +.\"    documentation and/or other materials provided with the distribution.
 +.\"
 +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 LIMITED
 +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
 PARTICULAR
 +.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
 THE
 +.\" POSSIBILITY OF SUCH DAMAGE.
 +.\"
 +.Dd August 29, 2012
 +.Dt PANASONIC 4
 +.Os
 +.Sh NAME
 +.Nm panasonic
 +.Nd Panasonic TOUGHBOOK laptop features support
 +.Sh SYNOPSIS
 +.Cd "panasonic* at acpi?"
 +.Sh DESCRIPTION
 +The
 +.Nm
 +driver provides support for hotkey handling and screen brightness found on
 +Panasonic TOUGHBOOK laptop computers.
 +.Pp
 +The
 +.Nm
 +driver provides support for modifying the screen brightness via the
 +.Xr sysctl 8
 +interface.
 +.Pp
 +The following
 +.Xr sysctl 8
 +variables are available:
 +.Pp
 +.Bl -tag -width "hw.panasonic.brightness [R/W]" -compact
 +.It Em hw.panasonic.brightness Bq R/W
 +Controls current LCD brightness.
 +Range [0-100].
 +.El
 +.Sh SEE ALSO
 +.Xr acpi 4 ,
 +.Xr acpivga 4 ,
 +.Xr pmf 9 ,
 +.Xr sysmon_envsys 9 ,
 +.Xr toughbook_hbtn 4
 +.Sh HISTORY
 +The
 +.Nm
 +device driver appeared in FreeBSD and was extended and ported to
 +.Nx 3.0.1 by Nathanial Sloss.
 +.Sh AUTHORS
 +.An OGAWA Takaya Aq t-ogawa%triaez.kaisei.org@localhost
 +.An Yoshihiro TAKAHASHI Aq nyan%FreeBSD.org@localhost
 +.An Nathanial Sloss
 +.Sh BUGS
 +If the computer is fully supported by
 +.Xr acpivga 4 then a different method
 +for controlling the screen brightness is used and the above mentioned 
 +.Xr sysctl 8 variable may not work.
 --- /dev/null  2012-08-29 17:38:04.000000000 +1000
 +++ ../../sys/dev/acpi/toughbook_hbtn_acpi.c   2012-07-02 19:34:35.000000000 
 +1000
 @@ -0,0 +1,287 @@
 +/*-
 + * Copyright (c)2008 - 2012 Nathanial Sloss 
<nathanialsloss%yahoo.com.au@localhost>
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 LIMITED
 + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 + * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 + * POSSIBILITY OF SUCH DAMAGE.
 + */
 +
 +/* Panasonic Toughbook CF-18/19 (and possibly others) tablet button driver. 
 */
 +
 +#include <sys/cdefs.h>
 +
 +#include <sys/types.h>
 +#include <sys/param.h>
 +#include <sys/device.h>
 +#include <sys/kernel.h>
 +#include <sys/pmf.h>
 +
 +#include <dev/sysmon/sysmonvar.h>
 +
 +#include <dev/acpi/acpivar.h>
 +#include <dev/acpi/acpireg.h>
 +
 +typedef struct toughbook_hbtn_softc {
 +      device_t                sc_dev;
 +      struct acpi_devnode     *sc_node;
 +
 +#define       PANASONIC_PSW_SECURITY                  0
 +#define PANASONIC_PSW_ROTATION                        1
 +#define PANASONIC_PSW_ENTER                   2
 +#define PANASONIC_PSW_INPUT_PANEL             3
 +#define PANASONIC_PSW_LAST                    4
 +
 +      struct sysmon_pswitch   sc_smpsw[PANASONIC_PSW_LAST];
 +      bool                    sc_smpsw_valid;
 +
 +} toughbook_hbtn_softc_t;
 +
 +/* Tablet buttons (HBTN) */
 +#define PANASONIC_NOTIFY_SecurityPRESSED      0x34
 +#define PANASONIC_NOTIFY_SecurityRELEASED     0x35
 +
 +#define PANASONIC_NOTIFY_RotationPRESSED      0x36
 +#define PANASONIC_NOTIFY_RotationRELEASED     0x37
 +
 +#define PANASONIC_NOTIFY_EnterPRESSED         0x38
 +#define PANASONIC_NOTIFY_EnterRELEASED                0x39
 +
 +#define PANASONIC_NOTIFY_InputPanelPRESSED    0x3A
 +#define PANASONIC_NOTIFY_InputPanelRELEASED   0x3B
 +
 +#define ACPI_SERIAL_BEGIN(x)
 +#define ACPI_SERIAL_END(x)
 +#define ACPI_SERIAL_ASSERT(x)
 +
 +#define HKEY_SET        0
 +#define HKEY_GET        1
 +
 +static int    hbtn_match(device_t, cfdata_t, void *);
 +static void   hbtn_attach(device_t, device_t, void *);
 +static int    hbtn_detach(device_t, int);
 +
 +static void   hbtn_notify_handler(ACPI_HANDLE, UINT32, void *);
 +
 +static int
 +acpi_hbtn_event(device_t, ACPI_INTEGER *);
 +
 +static void
 +acpi_hbtn_action(device_t, ACPI_INTEGER);
 +
 +CFATTACH_DECL_NEW(toughbook_hbtn, sizeof(toughbook_hbtn_softc_t),
 +    hbtn_match, hbtn_attach, hbtn_detach, NULL);
 +
 +static const char * const toughbook_hbtn_ids[] = {
 +      "MAT001F",
 +      "MAT0020",
 +      NULL
 +};
 +
 +static int
 +hbtn_match(device_t parent, cfdata_t match, void *opaque)
 +{
 +      struct acpi_attach_args *aa = opaque;
 +
 +      if (aa->aa_node->ad_type != ACPI_TYPE_DEVICE)
 +              return 0;
 +
 +      return acpi_match_hid(aa->aa_node->ad_devinfo, toughbook_hbtn_ids);
 +}
 +
 +static void
 +hbtn_attach(device_t parent, device_t self, void *opaque)
 +{
 +      toughbook_hbtn_softc_t *sc = device_private(self);
 +      struct acpi_attach_args *aa = opaque;
 +      struct sysmon_pswitch *psw;
 +      ACPI_STATUS rv;
 +
 +      sc->sc_node = aa->aa_node;
 +      sc->sc_dev = self;
 +
 +      aprint_naive(": Toughbook tablet buttons\n");
 +      aprint_normal(": Toughbook tablet buttons\n");
 +
 +      rv = AcpiInstallNotifyHandler(sc->sc_node->ad_handle, ACPI_ALL_NOTIFY,
 +          hbtn_notify_handler, sc);
 +      if (ACPI_FAILURE(rv))
 +              aprint_error_dev(self, "couldn't install notify handler: %s\n",
 +                  AcpiFormatException(rv));
 +
 +      /* Register power switches with sysmon */
 +      psw = sc->sc_smpsw;
 +      sc->sc_smpsw_valid = true;
 +
 +      int i;
 +      for (i = PANASONIC_PSW_SECURITY; i < PANASONIC_PSW_LAST; i++)
 +              psw[i].smpsw_type = PSWITCH_TYPE_HOTKEY;
 +      psw[PANASONIC_PSW_SECURITY].smpsw_name = "security";
 +      psw[PANASONIC_PSW_ROTATION].smpsw_name = "rotation-button";
 +      psw[PANASONIC_PSW_ENTER].smpsw_name = "enter-button";
 +      psw[PANASONIC_PSW_INPUT_PANEL].smpsw_name = "input_panel-button";
 +
 +      for (i = 0; i < PANASONIC_PSW_LAST; i++) {
 +              if (sysmon_pswitch_register(&sc->sc_smpsw[i]) != 0) {
 +                      aprint_error_dev(self,
 +                          "couldn't register with sysmon\n");
 +                      sc->sc_smpsw_valid = false;
 +                      break;
 +              }
 +      }
 +
 +      if (!pmf_device_register(self, NULL, NULL))
 +              aprint_error_dev(self, "couldn't establish power handler\n");
 +
 +}
 +
 +static int
 +hbtn_detach(device_t self, int flags)
 +{
 +      toughbook_hbtn_softc_t *sc = device_private(self);
 +      int i;
 +
 +      if (sc->sc_smpsw_valid)
 +              for (i = 0; i < PANASONIC_PSW_LAST; i++)
 +                      sysmon_pswitch_unregister(&sc->sc_smpsw[i]);
 +
 +      pmf_device_deregister(self);
 +
 +      return 0;
 +}
 +
 +static void
 +hbtn_notify_handler(ACPI_HANDLE hdl, UINT32 notify, void *opaque)
 +{
 +      toughbook_hbtn_softc_t *sc = opaque;
 +
 +        ACPI_INTEGER key;
 +      key = 0;
 +
 +      switch (notify) {
 +      case 0x80:
 +              ACPI_SERIAL_BEGIN(panasonic);
 +                if (acpi_hbtn_event(sc->sc_dev, &key) == 0) {
 +                        acpi_hbtn_action(sc->sc_dev, key);
 +              }
 +
 +              ACPI_SERIAL_END(panasonic);
 +              break;
 +      default:
 +              aprint_debug_dev(sc->sc_dev, "unknown notify: %#x\n", notify);
 +              break;
 +      }
 +
 +}
 +
 +static int
 +acpi_hbtn_event(device_t self, ACPI_INTEGER *arg) {
 +
 +      toughbook_hbtn_softc_t *sc = device_private(self);
 +
 +        ACPI_BUFFER buf;
 +        ACPI_OBJECT *res;
 +        ACPI_INTEGER val;
 +        int status;
 +
 +        ACPI_SERIAL_ASSERT(panasonic);
 +        status = ENXIO;
 +
 +        buf.Length = ACPI_ALLOCATE_BUFFER;
 +        buf.Pointer = NULL;
 +        AcpiEvaluateObject(sc->sc_node->ad_handle, "HINF", NULL, &buf);
 +        res = (ACPI_OBJECT *)buf.Pointer;
 +        if (res->Type != ACPI_TYPE_INTEGER) {
 +                aprint_error_dev(self, "HINF returned non-integer\n");
 +                goto end;
 +        }
 +        val = res->Integer.Value;
 +
 +      *arg = val;
 +        status = 0;
 +end:
 +        if (buf.Pointer)
 +                AcpiOsFree(buf.Pointer);
 +
 +        return status;
 +}
 +
 +static void
 +acpi_hbtn_action(device_t self, ACPI_INTEGER key)
 +{
 +
 +      toughbook_hbtn_softc_t *sc = device_private(self);
 +
 +        ACPI_SERIAL_ASSERT(panasonic);
 +
 +        switch (key) {
 +      case PANASONIC_NOTIFY_SecurityPRESSED:
 +              if (sc->sc_smpsw_valid == false)
 +                      break;
 +              sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_SECURITY],
 +                  PSWITCH_EVENT_PRESSED);
 +              break;
 +      case PANASONIC_NOTIFY_SecurityRELEASED:
 +              if (sc->sc_smpsw_valid == false)
 +                      break;
 +              sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_SECURITY],
 +                  PSWITCH_EVENT_RELEASED);
 +              break;
 +      case PANASONIC_NOTIFY_RotationPRESSED:
 +              if (sc->sc_smpsw_valid == false)
 +                      break;
 +              sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_ROTATION],
 +                  PSWITCH_EVENT_PRESSED);
 +              break;
 +      case PANASONIC_NOTIFY_RotationRELEASED:
 +              if (sc->sc_smpsw_valid == false)
 +                      break;
 +              sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_ROTATION],
 +                  PSWITCH_EVENT_RELEASED);
 +              break;
 +      case PANASONIC_NOTIFY_EnterPRESSED:
 +              if (sc->sc_smpsw_valid == false)
 +                      break;
 +              sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_ENTER],
 +                  PSWITCH_EVENT_PRESSED);
 +              break;
 +      case PANASONIC_NOTIFY_EnterRELEASED:
 +              if (sc->sc_smpsw_valid == false)
 +                      break;
 +              sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_ENTER],
 +                  PSWITCH_EVENT_RELEASED);
 +              break;
 +      case PANASONIC_NOTIFY_InputPanelPRESSED:
 +              if (sc->sc_smpsw_valid == false)
 +                      break;
 +              sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_INPUT_PANEL],
 +                  PSWITCH_EVENT_PRESSED);
 +              break;
 +      case PANASONIC_NOTIFY_InputPanelRELEASED:
 +              if (sc->sc_smpsw_valid == false)
 +                      break;
 +              sysmon_pswitch_event(&sc->sc_smpsw[PANASONIC_PSW_INPUT_PANEL],
 +                  PSWITCH_EVENT_RELEASED);
 +              break;
 +      default:
 +              aprint_error_dev(sc->sc_dev, "Unknown Key 0x%X\n", (int)key);
 +        }
 +}
 +
 --- /dev/null  2012-08-29 17:38:04.000000000 +1000
 +++ ./man4/toughbook_hbtn.4    2012-07-02 20:39:29.000000000 +1000
 @@ -0,0 +1,63 @@
 +.\"
 +.\" Copyright (c) 2012 Nathanial Sloss <nathanialsloss%yahoo.com.au@localhost>
 +.\" All rights reserved.
 +.\"
 +.\" Redistribution and use in source and binary forms, with or without
 +.\" modification, are permitted provided that the following conditions
 +.\" are met:
 +.\" 1. Redistributions of source code must retain the above copyright
 +.\"    notice, this list of conditions and the following disclaimer.
 +.\" 2. Redistributions in binary form must reproduce the above copyright
 +.\"    notice, this list of conditions and the following disclaimer in the
 +.\"    documentation and/or other materials provided with the distribution.
 +.\"
 +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 LIMITED
 +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
 PARTICULAR
 +.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 
 THE
 +.\" POSSIBILITY OF SUCH DAMAGE.
 +.\"
 +.Dd July 2, 2012
 +.Dt TOUGHBOOK_HBTN 4
 +.Os
 +.Sh NAME
 +.Nm toughbook_hbtn
 +.Nd Panasonic Toughbook CF-18/19 Tablet Buttons
 +.Sh SYNOPSIS
 +.Cd "toughbook_hbtn* at acpi?"
 +.Sh DESCRIPTION
 +The
 +.Nm
 +driver supports the tablet buttons found on CF-18/19 Toughbook computers:
 +.Bl -column -offset indent "Button         " "/etc/powerd/actions/button"
 +.It Sy Button Ta Sy Script
 +.It Li Input (Keyboard) Ta Pa /etc/powerd/actions/input_panel-button
 +.It Li Enter (Target) Ta Pa /etc/powerd/actions/enter-button
 +.It Li Rotation Ta Pa /etc/powerd/actions/rotation-button
 +.It Li Security (Key) Ta Pa /etc/powerd/actions/security
 +.El
 +.Pp
 +When a button is pressed, the
 +.Xr powerd 8
 +daemon, if running,
 +will execute the corresponding script.
 +.Sh SEE ALSO
 +.Xr acpi 4 ,
 +.Xr panasonic 4 ,
 +.Xr powerd 8
 +.Sh AUTHORS
 +Software and manual page written by Nathanial Sloss
 +.Sh HISTORY
 +The
 +.Nm
 +driver
 +was an addition to
 +.Xr panasonic 4
 +which was ported to
 +.Nx 3.0.1 but was never released .
 
 
 I hope this software is useful.
 
 Regards,
 
 Nat.
 


Home | Main Index | Thread Index | Old Index