Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/watchdog/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 5 kB image not shown  

Quelle  advantech_ec_wdt.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Advantech Embedded Controller Watchdog Driver
 *
 * This driver supports Advantech products with ITE based Embedded Controller.
 * It does not support Advantech products with other ECs or without EC.
 *
 * Copyright (C) 2022 Advantech Europe B.V.
 */


#include <linux/delay.h>
#include <linux/io.h>
#include <linux/isa.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/watchdog.h>

#define DRIVER_NAME  "advantech_ec_wdt"

/* EC IO region */
#define EC_BASE_ADDR  0x299
#define EC_ADDR_EXTENT  2

/* EC minimum IO access delay in ms */
#define EC_MIN_DELAY  10

/* EC interface definitions */
#define EC_ADDR_CMD  (EC_BASE_ADDR + 1)
#define EC_ADDR_DATA  EC_BASE_ADDR
#define EC_CMD_EC_PROBE  0x30
#define EC_CMD_COMM  0x89
#define EC_CMD_WDT_START 0x28
#define EC_CMD_WDT_STOP  0x29
#define EC_CMD_WDT_RESET 0x2A
#define EC_DAT_EN_DLY_H  0x58
#define EC_DAT_EN_DLY_L  0x59
#define EC_DAT_RST_DLY_H 0x5E
#define EC_DAT_RST_DLY_L 0x5F
#define EC_MAGIC  0x95

/* module parameters */
#define MIN_TIME  1
#define MAX_TIME  6000 /* 100 minutes */
#define DEFAULT_TIME  60

static unsigned int timeout;
static ktime_t ec_timestamp;

module_param(timeout, uint, 0);
MODULE_PARM_DESC(timeout,
   "Default Watchdog timer setting (" __MODULE_STRING(DEFAULT_TIME) "s). The range is from " __MODULE_STRING(MIN_TIME) " to " __MODULE_STRING(MAX_TIME) ".");

static void adv_ec_wdt_timing_gate(void)
{
 ktime_t time_cur, time_delta;

 /* ensure minimum delay between IO accesses*/
 time_cur = ktime_get();
 time_delta = ktime_to_ms(ktime_sub(time_cur, ec_timestamp));
 if (time_delta < EC_MIN_DELAY) {
  time_delta = EC_MIN_DELAY - time_delta;
  usleep_range(time_delta * 1000, (time_delta + 1) * 1000);
 }
 ec_timestamp = ktime_get();
}

static void adv_ec_wdt_outb(unsigned char value, unsigned short port)
{
 adv_ec_wdt_timing_gate();
 outb(value, port);
}

static unsigned char adv_ec_wdt_inb(unsigned short port)
{
 adv_ec_wdt_timing_gate();
 return inb(port);
}

static int adv_ec_wdt_ping(struct watchdog_device *wdd)
{
 adv_ec_wdt_outb(EC_CMD_WDT_RESET, EC_ADDR_CMD);
 return 0;
}

static int adv_ec_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t)
{
 unsigned int val;

 /* scale time to EC 100 ms base */
 val = t * 10;

 /* reset enable delay, just in case it was set by BIOS etc. */
 adv_ec_wdt_outb(EC_CMD_COMM, EC_ADDR_CMD);
 adv_ec_wdt_outb(EC_DAT_EN_DLY_H, EC_ADDR_DATA);
 adv_ec_wdt_outb(0, EC_ADDR_DATA);

 adv_ec_wdt_outb(EC_CMD_COMM, EC_ADDR_CMD);
 adv_ec_wdt_outb(EC_DAT_EN_DLY_L, EC_ADDR_DATA);
 adv_ec_wdt_outb(0, EC_ADDR_DATA);

 /* set reset delay */
 adv_ec_wdt_outb(EC_CMD_COMM, EC_ADDR_CMD);
 adv_ec_wdt_outb(EC_DAT_RST_DLY_H, EC_ADDR_DATA);
 adv_ec_wdt_outb(val >> 8, EC_ADDR_DATA);

 adv_ec_wdt_outb(EC_CMD_COMM, EC_ADDR_CMD);
 adv_ec_wdt_outb(EC_DAT_RST_DLY_L, EC_ADDR_DATA);
 adv_ec_wdt_outb(val & 0xFF, EC_ADDR_DATA);

 wdd->timeout = t;
 return 0;
}

static int adv_ec_wdt_start(struct watchdog_device *wdd)
{
 adv_ec_wdt_set_timeout(wdd, wdd->timeout);
 adv_ec_wdt_outb(EC_CMD_WDT_START, EC_ADDR_CMD);

 return 0;
}

static int adv_ec_wdt_stop(struct watchdog_device *wdd)
{
 adv_ec_wdt_outb(EC_CMD_WDT_STOP, EC_ADDR_CMD);

 return 0;
}

static const struct watchdog_info adv_ec_wdt_info = {
 .identity = DRIVER_NAME,
 .options = WDIOF_SETTIMEOUT |
   WDIOF_MAGICCLOSE |
   WDIOF_KEEPALIVEPING,
};

static const struct watchdog_ops adv_ec_wdt_ops = {
 .owner = THIS_MODULE,
 .start = adv_ec_wdt_start,
 .stop =  adv_ec_wdt_stop,
 .ping =  adv_ec_wdt_ping,
 .set_timeout = adv_ec_wdt_set_timeout,
};

static struct watchdog_device adv_ec_wdt_dev = {
 .info =  &adv_ec_wdt_info,
 .ops =  &adv_ec_wdt_ops,
 .min_timeout = MIN_TIME,
 .max_timeout = MAX_TIME,
 .timeout = DEFAULT_TIME,
};

static int adv_ec_wdt_probe(struct device *dev, unsigned int id)
{
 if (!devm_request_region(dev, EC_BASE_ADDR, EC_ADDR_EXTENT, dev_name(dev))) {
  dev_err(dev, "Unable to lock port addresses (0x%X-0x%X)\n",
   EC_BASE_ADDR, EC_BASE_ADDR + EC_ADDR_EXTENT);
  return -EBUSY;
 }

 watchdog_init_timeout(&adv_ec_wdt_dev, timeout, dev);
 watchdog_stop_on_reboot(&adv_ec_wdt_dev);
 watchdog_stop_on_unregister(&adv_ec_wdt_dev);

 return devm_watchdog_register_device(dev, &adv_ec_wdt_dev);
}

static struct isa_driver adv_ec_wdt_driver = {
 .probe  = adv_ec_wdt_probe,
 .driver  = {
 .name  = DRIVER_NAME,
 },
};

static int __init adv_ec_wdt_init(void)
{
 unsigned int val;

 /* quick probe for EC */
 if (!request_region(EC_BASE_ADDR, EC_ADDR_EXTENT, DRIVER_NAME))
  return -EBUSY;

 adv_ec_wdt_outb(EC_CMD_EC_PROBE, EC_ADDR_CMD);
 val = adv_ec_wdt_inb(EC_ADDR_DATA);
 release_region(EC_BASE_ADDR, EC_ADDR_EXTENT);

 if (val != EC_MAGIC)
  return -ENODEV;

 return isa_register_driver(&adv_ec_wdt_driver, 1);
}

static void __exit adv_ec_wdt_exit(void)
{
 isa_unregister_driver(&adv_ec_wdt_driver);
}

module_init(adv_ec_wdt_init);
module_exit(adv_ec_wdt_exit);

MODULE_AUTHOR("Thomas Kastner ");
MODULE_DESCRIPTION("Advantech Embedded Controller Watchdog Device Driver");
MODULE_LICENSE("GPL");
MODULE_VERSION("20221019");
MODULE_ALIAS("isa:" DRIVER_NAME);

Messung V0.5
C=97 H=94 G=95

¤ Dauer der Verarbeitung: 0.3 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.