Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  acpi.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
/* Copyright(c) 2021-2023  Realtek Corporation
 */


#include <linux/acpi.h>
#include <linux/uuid.h>

#include "acpi.h"
#include "debug.h"

static const guid_t rtw89_guid = GUID_INIT(0xD2A8C3E8, 0x4B69, 0x4F00,
        0x82, 0xBD, 0xFE, 0x86,
        0x07, 0x80, 0x3A, 0xA7);

static u32 rtw89_acpi_traversal_object(struct rtw89_dev *rtwdev,
           const union acpi_object *obj, u8 *pos)
{
 const union acpi_object *elm;
 unsigned int i;
 u32 sub_len;
 u32 len = 0;
 u8 *tmp;

 switch (obj->type) {
 case ACPI_TYPE_INTEGER:
  if (pos)
   pos[len] = obj->integer.value;

  len++;
  break;
 case ACPI_TYPE_BUFFER:
  if (unlikely(obj->buffer.length == 0)) {
   rtw89_debug(rtwdev, RTW89_DBG_ACPI,
        "%s: invalid buffer type\n", __func__);
   goto err;
  }

  if (pos)
   memcpy(pos, obj->buffer.pointer, obj->buffer.length);

  len += obj->buffer.length;
  break;
 case ACPI_TYPE_PACKAGE:
  if (unlikely(obj->package.count == 0)) {
   rtw89_debug(rtwdev, RTW89_DBG_ACPI,
        "%s: invalid package type\n", __func__);
   goto err;
  }

  for (i = 0; i < obj->package.count; i++) {
   elm = &obj->package.elements[i];
   tmp = pos ? pos + len : NULL;

   sub_len = rtw89_acpi_traversal_object(rtwdev, elm, tmp);
   if (unlikely(sub_len == 0))
    goto err;

   len += sub_len;
  }
  break;
 default:
  rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: unhandled type: %d\n",
       __func__, obj->type);
  goto err;
 }

 return len;

err:
 return 0;
}

static u32 rtw89_acpi_calculate_object_length(struct rtw89_dev *rtwdev,
           const union acpi_object *obj)
{
 return rtw89_acpi_traversal_object(rtwdev, obj, NULL);
}

static struct rtw89_acpi_data *
rtw89_acpi_evaluate_method(struct rtw89_dev *rtwdev, const char *method)
{
 struct acpi_buffer buf = {ACPI_ALLOCATE_BUFFER, NULL};
 struct rtw89_acpi_data *data = NULL;
 acpi_handle root, handle;
 union acpi_object *obj;
 acpi_status status;
 u32 len;

 root = ACPI_HANDLE(rtwdev->dev);
 if (!root) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI,
       "acpi (%s): failed to get root\n", method);
  return NULL;
 }

 status = acpi_get_handle(root, (acpi_string)method, &handle);
 if (ACPI_FAILURE(status)) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI,
       "acpi (%s): failed to get handle\n", method);
  return NULL;
 }

 status = acpi_evaluate_object(handle, NULL, NULL, &buf);
 if (ACPI_FAILURE(status)) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI,
       "acpi (%s): failed to evaluate object\n", method);
  return NULL;
 }

 obj = buf.pointer;
 len = rtw89_acpi_calculate_object_length(rtwdev, obj);
 if (unlikely(len == 0)) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI,
       "acpi (%s): failed to traversal obj len\n", method);
  goto out;
 }

 data = kzalloc(struct_size(data, buf, len), GFP_KERNEL);
 if (!data)
  goto out;

 data->len = len;
 rtw89_acpi_traversal_object(rtwdev, obj, data->buf);

out:
 ACPI_FREE(obj);
 return data;
}

static
int rtw89_acpi_dsm_get_value(struct rtw89_dev *rtwdev, union acpi_object *obj,
        u8 *value)
{
 if (obj->type != ACPI_TYPE_INTEGER) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI,
       "acpi: expect integer but type: %d\n", obj->type);
  return -EINVAL;
 }

 *value = (u8)obj->integer.value;
 return 0;
}

static bool chk_acpi_policy_6ghz_sig(const struct rtw89_acpi_policy_6ghz *p)
{
 return p->signature[0] == 0x00 &&
        p->signature[1] == 0xE0 &&
        p->signature[2] == 0x4C;
}

static
int rtw89_acpi_dsm_get_policy_6ghz(struct rtw89_dev *rtwdev,
       union acpi_object *obj,
       struct rtw89_acpi_policy_6ghz **policy_6ghz)
{
 const struct rtw89_acpi_policy_6ghz *ptr;
 u32 expect_len;
 u32 len;

 if (obj->type != ACPI_TYPE_BUFFER) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI,
       "acpi: expect buffer but type: %d\n", obj->type);
  return -EINVAL;
 }

 len = obj->buffer.length;
 if (len < sizeof(*ptr)) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n",
       __func__, len);
  return -EINVAL;
 }

 ptr = (typeof(ptr))obj->buffer.pointer;
 if (!chk_acpi_policy_6ghz_sig(ptr)) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__);
  return -EINVAL;
 }

 expect_len = struct_size(ptr, country_list, ptr->country_count);
 if (len < expect_len) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: expect %u but length: %u\n",
       __func__, expect_len, len);
  return -EINVAL;
 }

 *policy_6ghz = kmemdup(ptr, expect_len, GFP_KERNEL);
 if (!*policy_6ghz)
  return -ENOMEM;

 rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_6ghz: ", *policy_6ghz,
         expect_len);
 return 0;
}

static bool chk_acpi_policy_6ghz_sp_sig(const struct rtw89_acpi_policy_6ghz_sp *p)
{
 return p->signature[0] == 0x52 &&
        p->signature[1] == 0x54 &&
        p->signature[2] == 0x4B &&
        p->signature[3] == 0x07;
}

static
int rtw89_acpi_dsm_get_policy_6ghz_sp(struct rtw89_dev *rtwdev,
          union acpi_object *obj,
          struct rtw89_acpi_policy_6ghz_sp **policy)
{
 const struct rtw89_acpi_policy_6ghz_sp *ptr;
 u32 buf_len;

 if (obj->type != ACPI_TYPE_BUFFER) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI,
       "acpi: expect buffer but type: %d\n", obj->type);
  return -EINVAL;
 }

 buf_len = obj->buffer.length;
 if (buf_len < sizeof(*ptr)) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n",
       __func__, buf_len);
  return -EINVAL;
 }

 ptr = (typeof(ptr))obj->buffer.pointer;
 if (!chk_acpi_policy_6ghz_sp_sig(ptr)) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__);
  return -EINVAL;
 }

 *policy = kmemdup(ptr, sizeof(*ptr), GFP_KERNEL);
 if (!*policy)
  return -ENOMEM;

 rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_6ghz_sp: ", *policy,
         sizeof(*ptr));
 return 0;
}

static bool chk_acpi_policy_6ghz_vlp_sig(const struct rtw89_acpi_policy_6ghz_vlp *p)
{
 return p->signature[0] == 0x52 &&
        p->signature[1] == 0x54 &&
        p->signature[2] == 0x4B &&
        p->signature[3] == 0x0B;
}

static
int rtw89_acpi_dsm_get_policy_6ghz_vlp(struct rtw89_dev *rtwdev,
           union acpi_object *obj,
           struct rtw89_acpi_policy_6ghz_vlp **policy)
{
 const struct rtw89_acpi_policy_6ghz_vlp *ptr;
 u32 buf_len;

 if (obj->type != ACPI_TYPE_BUFFER) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI,
       "acpi: expect buffer but type: %d\n", obj->type);
  return -EINVAL;
 }

 buf_len = obj->buffer.length;
 if (buf_len < sizeof(*ptr)) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n",
       __func__, buf_len);
  return -EINVAL;
 }

 ptr = (typeof(ptr))obj->buffer.pointer;
 if (!chk_acpi_policy_6ghz_vlp_sig(ptr)) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__);
  return -EINVAL;
 }

 *policy = kmemdup(ptr, sizeof(*ptr), GFP_KERNEL);
 if (!*policy)
  return -ENOMEM;

 rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_6ghz_vlp: ", *policy,
         sizeof(*ptr));
 return 0;
}

static bool chk_acpi_policy_tas_sig(const struct rtw89_acpi_policy_tas *p)
{
 return p->signature[0] == 0x52 &&
        p->signature[1] == 0x54 &&
        p->signature[2] == 0x4B &&
        p->signature[3] == 0x05;
}

static int rtw89_acpi_dsm_get_policy_tas(struct rtw89_dev *rtwdev,
      union acpi_object *obj,
      struct rtw89_acpi_policy_tas **policy)
{
 const struct rtw89_acpi_policy_tas *ptr;
 u32 buf_len;

 if (obj->type != ACPI_TYPE_BUFFER) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI,
       "acpi: expect buffer but type: %d\n", obj->type);
  return -EINVAL;
 }

 buf_len = obj->buffer.length;
 if (buf_len < sizeof(*ptr)) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n",
       __func__, buf_len);
  return -EINVAL;
 }

 ptr = (typeof(ptr))obj->buffer.pointer;
 if (!chk_acpi_policy_tas_sig(ptr)) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__);
  return -EINVAL;
 }

 *policy = kmemdup(ptr, sizeof(*ptr), GFP_KERNEL);
 if (!*policy)
  return -ENOMEM;

 rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_tas: ", *policy,
         sizeof(*ptr));
 return 0;
}

static
bool chk_acpi_policy_reg_rules_sig(const struct rtw89_acpi_policy_reg_rules *p)
{
 return p->signature[0] == 0x52 &&
        p->signature[1] == 0x54 &&
        p->signature[2] == 0x4B &&
        p->signature[3] == 0x0A;
}

static
int rtw89_acpi_dsm_get_policy_reg_rules(struct rtw89_dev *rtwdev,
     union acpi_object *obj,
     struct rtw89_acpi_policy_reg_rules **policy)
{
 const struct rtw89_acpi_policy_reg_rules *ptr;
 u32 buf_len;

 if (obj->type != ACPI_TYPE_BUFFER) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI,
       "acpi: expect buffer but type: %d\n", obj->type);
  return -EINVAL;
 }

 buf_len = obj->buffer.length;
 if (buf_len < sizeof(*ptr)) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n",
       __func__, buf_len);
  return -EINVAL;
 }

 ptr = (typeof(ptr))obj->buffer.pointer;
 if (!chk_acpi_policy_reg_rules_sig(ptr)) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: bad signature\n", __func__);
  return -EINVAL;
 }

 *policy = kmemdup(ptr, sizeof(*ptr), GFP_KERNEL);
 if (!*policy)
  return -ENOMEM;

 rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "policy_reg_rules: ", *policy,
         sizeof(*ptr));
 return 0;
}

int rtw89_acpi_evaluate_dsm(struct rtw89_dev *rtwdev,
       enum rtw89_acpi_dsm_func func,
       struct rtw89_acpi_dsm_result *res)
{
 union acpi_object *obj;
 int ret;

 obj = acpi_evaluate_dsm(ACPI_HANDLE(rtwdev->dev), &rtw89_guid,
    0, func, NULL);
 if (!obj) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI,
       "acpi dsm fail to evaluate func: %d\n", func);
  return -ENOENT;
 }

 if (func == RTW89_ACPI_DSM_FUNC_6G_BP)
  ret = rtw89_acpi_dsm_get_policy_6ghz(rtwdev, obj,
           &res->u.policy_6ghz);
 else if (func == RTW89_ACPI_DSM_FUNC_6GHZ_SP_SUP)
  ret = rtw89_acpi_dsm_get_policy_6ghz_sp(rtwdev, obj,
       &res->u.policy_6ghz_sp);
 else if (func == RTW89_ACPI_DSM_FUNC_6GHZ_VLP_SUP)
  ret = rtw89_acpi_dsm_get_policy_6ghz_vlp(rtwdev, obj,
        &res->u.policy_6ghz_vlp);
 else if (func == RTW89_ACPI_DSM_FUNC_TAS_EN)
  ret = rtw89_acpi_dsm_get_policy_tas(rtwdev, obj, &res->u.policy_tas);
 else if (func == RTW89_ACPI_DSM_FUNC_REG_RULES_EN)
  ret = rtw89_acpi_dsm_get_policy_reg_rules(rtwdev, obj,
         &res->u.policy_reg_rules);
 else
  ret = rtw89_acpi_dsm_get_value(rtwdev, obj, &res->u.value);

 ACPI_FREE(obj);
 return ret;
}

int rtw89_acpi_evaluate_rtag(struct rtw89_dev *rtwdev,
        struct rtw89_acpi_rtag_result *res)
{
 const struct rtw89_acpi_data *data;
 u32 buf_len;
 int ret = 0;

 data = rtw89_acpi_evaluate_method(rtwdev, "RTAG");
 if (!data)
  return -EIO;

 buf_len = data->len;
 if (buf_len != sizeof(*res)) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI, "%s: invalid buffer length: %u\n",
       __func__, buf_len);
  ret = -EINVAL;
  goto out;
 }

 *res = *(struct rtw89_acpi_rtag_result *)data->buf;

 rtw89_hex_dump(rtwdev, RTW89_DBG_ACPI, "antenna_gain: ", res, sizeof(*res));

out:
 kfree(data);
 return ret;
}

enum rtw89_acpi_sar_subband rtw89_acpi_sar_get_subband(struct rtw89_dev *rtwdev,
             u32 center_freq)
{
 switch (center_freq) {
 default:
  rtw89_debug(rtwdev, RTW89_DBG_ACPI,
       "center freq %u to ACPI SAR subband is unhandled\n",
       center_freq);
  fallthrough;
 case 2412 ... 2484:
  return RTW89_ACPI_SAR_2GHZ_SUBBAND;
 case 5180 ... 5240:
  return RTW89_ACPI_SAR_5GHZ_SUBBAND_1;
 case 5250 ... 5320:
  return RTW89_ACPI_SAR_5GHZ_SUBBAND_2;
 case 5500 ... 5720:
  return RTW89_ACPI_SAR_5GHZ_SUBBAND_2E;
 case 5745 ... 5885:
  return RTW89_ACPI_SAR_5GHZ_SUBBAND_3_4;
 case 5955 ... 6155:
  return RTW89_ACPI_SAR_6GHZ_SUBBAND_5_L;
 case 6175 ... 6415:
  return RTW89_ACPI_SAR_6GHZ_SUBBAND_5_H;
 case 6435 ... 6515:
  return RTW89_ACPI_SAR_6GHZ_SUBBAND_6;
 case 6535 ... 6695:
  return RTW89_ACPI_SAR_6GHZ_SUBBAND_7_L;
 case 6715 ... 6855:
  return RTW89_ACPI_SAR_6GHZ_SUBBAND_7_H;

 /* freq 6875 (ch 185, 20MHz) spans RTW89_ACPI_SAR_6GHZ_SUBBAND_7_H
 * and RTW89_ACPI_SAR_6GHZ_SUBBAND_8, so directly describe it with
 * struct rtw89_6ghz_span.
 */


 case 6895 ... 7115:
  return RTW89_ACPI_SAR_6GHZ_SUBBAND_8;
 }
}

enum rtw89_band rtw89_acpi_sar_subband_to_band(struct rtw89_dev *rtwdev,
            enum rtw89_acpi_sar_subband subband)
{
 switch (subband) {
 default:
  rtw89_debug(rtwdev, RTW89_DBG_ACPI,
       "ACPI SAR subband %u to band is unhandled\n", subband);
  fallthrough;
 case RTW89_ACPI_SAR_2GHZ_SUBBAND:
  return RTW89_BAND_2G;
 case RTW89_ACPI_SAR_5GHZ_SUBBAND_1:
  return RTW89_BAND_5G;
 case RTW89_ACPI_SAR_5GHZ_SUBBAND_2:
  return RTW89_BAND_5G;
 case RTW89_ACPI_SAR_5GHZ_SUBBAND_2E:
  return RTW89_BAND_5G;
 case RTW89_ACPI_SAR_5GHZ_SUBBAND_3_4:
  return RTW89_BAND_5G;
 case RTW89_ACPI_SAR_6GHZ_SUBBAND_5_L:
  return RTW89_BAND_6G;
 case RTW89_ACPI_SAR_6GHZ_SUBBAND_5_H:
  return RTW89_BAND_6G;
 case RTW89_ACPI_SAR_6GHZ_SUBBAND_6:
  return RTW89_BAND_6G;
 case RTW89_ACPI_SAR_6GHZ_SUBBAND_7_L:
  return RTW89_BAND_6G;
 case RTW89_ACPI_SAR_6GHZ_SUBBAND_7_H:
  return RTW89_BAND_6G;
 case RTW89_ACPI_SAR_6GHZ_SUBBAND_8:
  return RTW89_BAND_6G;
 }
}

static u8 rtw89_acpi_sar_rfpath_to_hp_antidx(enum rtw89_rf_path rfpath)
{
 switch (rfpath) {
 default:
 case RF_PATH_B:
  return 0;
 case RF_PATH_A:
  return 1;
 }
}

static u8 rtw89_acpi_sar_rfpath_to_rt_antidx(enum rtw89_rf_path rfpath)
{
 switch (rfpath) {
 default:
 case RF_PATH_A:
  return 0;
 case RF_PATH_B:
  return 1;
 }
}

static s16 rtw89_acpi_sar_normalize_hp_val(u8 v)
{
 static const u8 bias = 10;
 static const u8 fct = 1;
 u16 res;

 BUILD_BUG_ON(fct > TXPWR_FACTOR_OF_RTW89_ACPI_SAR);

 res = (bias << TXPWR_FACTOR_OF_RTW89_ACPI_SAR) +
       (v << (TXPWR_FACTOR_OF_RTW89_ACPI_SAR - fct));

 return min_t(s32, res, MAX_VAL_OF_RTW89_ACPI_SAR);
}

static s16 rtw89_acpi_sar_normalize_rt_val(u8 v)
{
 static const u8 fct = 3;
 u16 res;

 BUILD_BUG_ON(fct > TXPWR_FACTOR_OF_RTW89_ACPI_SAR);

 res = v << (TXPWR_FACTOR_OF_RTW89_ACPI_SAR - fct);

 return min_t(s32, res, MAX_VAL_OF_RTW89_ACPI_SAR);
}

static
void rtw89_acpi_sar_load_std_legacy(struct rtw89_dev *rtwdev,
        const struct rtw89_acpi_sar_recognition *rec,
        const void *content,
        struct rtw89_sar_entry_from_acpi *ent)
{
 const struct rtw89_acpi_sar_std_legacy *ptr = content;
 enum rtw89_acpi_sar_subband subband;
 enum rtw89_rf_path path;

 for (subband = 0; subband < NUM_OF_RTW89_ACPI_SAR_SUBBAND; subband++) {
  for (path = 0; path < NUM_OF_RTW89_ACPI_SAR_RF_PATH; path++) {
   u8 antidx = rec->rfpath_to_antidx(path);

   if (subband < RTW89_ACPI_SAR_SUBBAND_NR_LEGACY)
    ent->v[subband][path] =
     rec->normalize(ptr->v[antidx][subband]);
   else
    ent->v[subband][path] = MAX_VAL_OF_RTW89_ACPI_SAR;
  }
 }
}

static
void rtw89_acpi_sar_load_std_has_6ghz(struct rtw89_dev *rtwdev,
          const struct rtw89_acpi_sar_recognition *rec,
          const void *content,
          struct rtw89_sar_entry_from_acpi *ent)
{
 const struct rtw89_acpi_sar_std_has_6ghz *ptr = content;
 enum rtw89_acpi_sar_subband subband;
 enum rtw89_rf_path path;

 BUILD_BUG_ON(RTW89_ACPI_SAR_SUBBAND_NR_HAS_6GHZ != NUM_OF_RTW89_ACPI_SAR_SUBBAND);

 for (subband = 0; subband < NUM_OF_RTW89_ACPI_SAR_SUBBAND; subband++) {
  for (path = 0; path < NUM_OF_RTW89_ACPI_SAR_RF_PATH; path++) {
   u8 antidx = rec->rfpath_to_antidx(path);

   ent->v[subband][path] = rec->normalize(ptr->v[antidx][subband]);
  }
 }
}

static
void rtw89_acpi_sar_load_sml_legacy(struct rtw89_dev *rtwdev,
        const struct rtw89_acpi_sar_recognition *rec,
        const void *content,
        struct rtw89_sar_entry_from_acpi *ent)
{
 const struct rtw89_acpi_sar_sml_legacy *ptr = content;
 enum rtw89_acpi_sar_subband subband;
 enum rtw89_rf_path path;

 for (subband = 0; subband < NUM_OF_RTW89_ACPI_SAR_SUBBAND; subband++) {
  for (path = 0; path < NUM_OF_RTW89_ACPI_SAR_RF_PATH; path++) {
   u8 antidx = rec->rfpath_to_antidx(path);

   if (subband < RTW89_ACPI_SAR_SUBBAND_NR_LEGACY)
    ent->v[subband][path] =
     rec->normalize(ptr->v[antidx][subband]);
   else
    ent->v[subband][path] = MAX_VAL_OF_RTW89_ACPI_SAR;
  }
 }
}

static
void rtw89_acpi_sar_load_sml_has_6ghz(struct rtw89_dev *rtwdev,
          const struct rtw89_acpi_sar_recognition *rec,
          const void *content,
          struct rtw89_sar_entry_from_acpi *ent)
{
 const struct rtw89_acpi_sar_sml_has_6ghz *ptr = content;
 enum rtw89_acpi_sar_subband subband;
 enum rtw89_rf_path path;

 BUILD_BUG_ON(RTW89_ACPI_SAR_SUBBAND_NR_HAS_6GHZ != NUM_OF_RTW89_ACPI_SAR_SUBBAND);

 for (subband = 0; subband < NUM_OF_RTW89_ACPI_SAR_SUBBAND; subband++) {
  for (path = 0; path < NUM_OF_RTW89_ACPI_SAR_RF_PATH; path++) {
   u8 antidx = rec->rfpath_to_antidx(path);

   ent->v[subband][path] = rec->normalize(ptr->v[antidx][subband]);
  }
 }
}

static s16 rtw89_acpi_geo_sar_normalize_delta(s8 delta)
{
 static const u8 fct = 1;

 BUILD_BUG_ON(fct > TXPWR_FACTOR_OF_RTW89_ACPI_SAR);

 return delta << (TXPWR_FACTOR_OF_RTW89_ACPI_SAR - fct);
}

static enum rtw89_acpi_geo_sar_regd_hp
rtw89_acpi_geo_sar_regd_convert_hp_idx(enum rtw89_regulation_type regd)
{
 switch (regd) {
 case RTW89_FCC:
 case RTW89_IC:
 case RTW89_NCC:
 case RTW89_CHILE:
 case RTW89_MEXICO:
  return RTW89_ACPI_GEO_SAR_REGD_HP_FCC;
 case RTW89_ETSI:
 case RTW89_MKK:
 case RTW89_ACMA:
  return RTW89_ACPI_GEO_SAR_REGD_HP_ETSI;
 default:
 case RTW89_WW:
 case RTW89_NA:
 case RTW89_KCC:
  return RTW89_ACPI_GEO_SAR_REGD_HP_WW;
 }
}

static enum rtw89_acpi_geo_sar_regd_rt
rtw89_acpi_geo_sar_regd_convert_rt_idx(enum rtw89_regulation_type regd)
{
 switch (regd) {
 case RTW89_FCC:
 case RTW89_NCC:
 case RTW89_CHILE:
 case RTW89_MEXICO:
  return RTW89_ACPI_GEO_SAR_REGD_RT_FCC;
 case RTW89_ETSI:
 case RTW89_ACMA:
  return RTW89_ACPI_GEO_SAR_REGD_RT_ETSI;
 case RTW89_MKK:
  return RTW89_ACPI_GEO_SAR_REGD_RT_MKK;
 case RTW89_IC:
  return RTW89_ACPI_GEO_SAR_REGD_RT_IC;
 case RTW89_KCC:
  return RTW89_ACPI_GEO_SAR_REGD_RT_KCC;
 default:
 case RTW89_WW:
 case RTW89_NA:
  return RTW89_ACPI_GEO_SAR_REGD_RT_WW;
 }
}

static
void rtw89_acpi_geo_sar_load_by_hp(struct rtw89_dev *rtwdev,
       const struct rtw89_acpi_geo_sar_hp_val *ptr,
       enum rtw89_rf_path path, s16 *val)
{
 u8 antidx = rtw89_acpi_sar_rfpath_to_hp_antidx(path);
 s16 delta = rtw89_acpi_geo_sar_normalize_delta(ptr->delta[antidx]);
 s16 max = rtw89_acpi_sar_normalize_hp_val(ptr->max);

 *val = clamp_t(s32, (*val) + delta, MIN_VAL_OF_RTW89_ACPI_SAR, max);
}

static
void rtw89_acpi_geo_sar_load_by_rt(struct rtw89_dev *rtwdev,
       const struct rtw89_acpi_geo_sar_rt_val *ptr,
       s16 *val)
{
 s16 delta = rtw89_acpi_geo_sar_normalize_delta(ptr->delta);
 s16 max = rtw89_acpi_sar_normalize_rt_val(ptr->max);

 *val = clamp_t(s32, (*val) + delta, MIN_VAL_OF_RTW89_ACPI_SAR, max);
}

static
void rtw89_acpi_geo_sar_load_hp_legacy(struct rtw89_dev *rtwdev,
           const void *content,
           enum rtw89_regulation_type regd,
           struct rtw89_sar_entry_from_acpi *ent)
{
 const struct rtw89_acpi_geo_sar_hp_legacy *ptr = content;
 const struct rtw89_acpi_geo_sar_hp_legacy_entry *ptr_ent;
 const struct rtw89_acpi_geo_sar_hp_val *ptr_ent_val;
 enum rtw89_acpi_geo_sar_regd_hp geo_idx =
  rtw89_acpi_geo_sar_regd_convert_hp_idx(regd);
 enum rtw89_acpi_sar_subband subband;
 enum rtw89_rf_path path;
 enum rtw89_band band;

 ptr_ent = &ptr->entries[geo_idx];

 for (subband = 0; subband < NUM_OF_RTW89_ACPI_SAR_SUBBAND; subband++) {
  band = rtw89_acpi_sar_subband_to_band(rtwdev, subband);
  switch (band) {
  case RTW89_BAND_2G:
   ptr_ent_val = &ptr_ent->val_2ghz;
   break;
  case RTW89_BAND_5G:
   ptr_ent_val = &ptr_ent->val_5ghz;
   break;
  default:
  case RTW89_BAND_6G:
   ptr_ent_val = NULL;
   break;
  }

  if (!ptr_ent_val)
   continue;

  for (path = 0; path < NUM_OF_RTW89_ACPI_SAR_RF_PATH; path++)
   rtw89_acpi_geo_sar_load_by_hp(rtwdev, ptr_ent_val, path,
            &ent->v[subband][path]);
 }
}

static
void rtw89_acpi_geo_sar_load_hp_has_6ghz(struct rtw89_dev *rtwdev,
      const void *content,
      enum rtw89_regulation_type regd,
      struct rtw89_sar_entry_from_acpi *ent)
{
 const struct rtw89_acpi_geo_sar_hp_has_6ghz *ptr = content;
 const struct rtw89_acpi_geo_sar_hp_has_6ghz_entry *ptr_ent;
 const struct rtw89_acpi_geo_sar_hp_val *ptr_ent_val;
 enum rtw89_acpi_geo_sar_regd_hp geo_idx =
  rtw89_acpi_geo_sar_regd_convert_hp_idx(regd);
 enum rtw89_acpi_sar_subband subband;
 enum rtw89_rf_path path;
 enum rtw89_band band;

 ptr_ent = &ptr->entries[geo_idx];

 for (subband = 0; subband < NUM_OF_RTW89_ACPI_SAR_SUBBAND; subband++) {
  band = rtw89_acpi_sar_subband_to_band(rtwdev, subband);
  switch (band) {
  case RTW89_BAND_2G:
   ptr_ent_val = &ptr_ent->val_2ghz;
   break;
  case RTW89_BAND_5G:
   ptr_ent_val = &ptr_ent->val_5ghz;
   break;
  case RTW89_BAND_6G:
   ptr_ent_val = &ptr_ent->val_6ghz;
   break;
  default:
   ptr_ent_val = NULL;
   break;
  }

  if (!ptr_ent_val)
   continue;

  for (path = 0; path < NUM_OF_RTW89_ACPI_SAR_RF_PATH; path++)
   rtw89_acpi_geo_sar_load_by_hp(rtwdev, ptr_ent_val, path,
            &ent->v[subband][path]);
 }
}

static
void rtw89_acpi_geo_sar_load_rt_legacy(struct rtw89_dev *rtwdev,
           const void *content,
           enum rtw89_regulation_type regd,
           struct rtw89_sar_entry_from_acpi *ent)
{
 const struct rtw89_acpi_geo_sar_rt_legacy *ptr = content;
 const struct rtw89_acpi_geo_sar_rt_legacy_entry *ptr_ent;
 const struct rtw89_acpi_geo_sar_rt_val *ptr_ent_val;
 enum rtw89_acpi_geo_sar_regd_rt geo_idx =
  rtw89_acpi_geo_sar_regd_convert_rt_idx(regd);
 enum rtw89_acpi_sar_subband subband;
 enum rtw89_rf_path path;
 enum rtw89_band band;

 ptr_ent = &ptr->entries[geo_idx];

 for (subband = 0; subband < NUM_OF_RTW89_ACPI_SAR_SUBBAND; subband++) {
  band = rtw89_acpi_sar_subband_to_band(rtwdev, subband);
  switch (band) {
  case RTW89_BAND_2G:
   ptr_ent_val = &ptr_ent->val_2ghz;
   break;
  case RTW89_BAND_5G:
   ptr_ent_val = &ptr_ent->val_5ghz;
   break;
  default:
  case RTW89_BAND_6G:
   ptr_ent_val = NULL;
   break;
  }

  if (!ptr_ent_val)
   continue;

  for (path = 0; path < NUM_OF_RTW89_ACPI_SAR_RF_PATH; path++)
   rtw89_acpi_geo_sar_load_by_rt(rtwdev, ptr_ent_val,
            &ent->v[subband][path]);
 }
}

static
void rtw89_acpi_geo_sar_load_rt_has_6ghz(struct rtw89_dev *rtwdev,
      const void *content,
      enum rtw89_regulation_type regd,
      struct rtw89_sar_entry_from_acpi *ent)
{
 const struct rtw89_acpi_geo_sar_rt_has_6ghz *ptr = content;
 const struct rtw89_acpi_geo_sar_rt_has_6ghz_entry *ptr_ent;
 const struct rtw89_acpi_geo_sar_rt_val *ptr_ent_val;
 enum rtw89_acpi_geo_sar_regd_rt geo_idx =
  rtw89_acpi_geo_sar_regd_convert_rt_idx(regd);
 enum rtw89_acpi_sar_subband subband;
 enum rtw89_rf_path path;
 enum rtw89_band band;

 ptr_ent = &ptr->entries[geo_idx];

 for (subband = 0; subband < NUM_OF_RTW89_ACPI_SAR_SUBBAND; subband++) {
  band = rtw89_acpi_sar_subband_to_band(rtwdev, subband);
  switch (band) {
  case RTW89_BAND_2G:
   ptr_ent_val = &ptr_ent->val_2ghz;
   break;
  case RTW89_BAND_5G:
   ptr_ent_val = &ptr_ent->val_5ghz;
   break;
  case RTW89_BAND_6G:
   ptr_ent_val = &ptr_ent->val_6ghz;
   break;
  default:
   ptr_ent_val = NULL;
   break;
  }

  if (!ptr_ent_val)
   continue;

  for (path = 0; path < NUM_OF_RTW89_ACPI_SAR_RF_PATH; path++)
   rtw89_acpi_geo_sar_load_by_rt(rtwdev, ptr_ent_val,
            &ent->v[subband][path]);
 }
}

#define RTW89_ACPI_GEO_SAR_DECL_HANDLER(type) \
static const struct rtw89_acpi_geo_sar_handler \
rtw89_acpi_geo_sar_handler_ ## type = { \
 .data_size = RTW89_ACPI_GEO_SAR_SIZE_OF(type), \
 .load = rtw89_acpi_geo_sar_load_ ## type, \
}

RTW89_ACPI_GEO_SAR_DECL_HANDLER(hp_legacy);
RTW89_ACPI_GEO_SAR_DECL_HANDLER(hp_has_6ghz);
RTW89_ACPI_GEO_SAR_DECL_HANDLER(rt_legacy);
RTW89_ACPI_GEO_SAR_DECL_HANDLER(rt_has_6ghz);

static const struct rtw89_acpi_sar_recognition rtw89_acpi_sar_recs[] = {
 {
  .id = {
   .cid = RTW89_ACPI_SAR_CID_HP,
   .rev = RTW89_ACPI_SAR_REV_LEGACY,
   .size = RTW89_ACPI_SAR_SIZE_OF(std_legacy),
  },
  .geo = &rtw89_acpi_geo_sar_handler_hp_legacy,

  .rfpath_to_antidx = rtw89_acpi_sar_rfpath_to_hp_antidx,
  .normalize = rtw89_acpi_sar_normalize_hp_val,
  .load = rtw89_acpi_sar_load_std_legacy,
 },
 {
  .id = {
   .cid = RTW89_ACPI_SAR_CID_HP,
   .rev = RTW89_ACPI_SAR_REV_HAS_6GHZ,
   .size = RTW89_ACPI_SAR_SIZE_OF(std_has_6ghz),
  },
  .geo = &rtw89_acpi_geo_sar_handler_hp_has_6ghz,

  .rfpath_to_antidx = rtw89_acpi_sar_rfpath_to_hp_antidx,
  .normalize = rtw89_acpi_sar_normalize_hp_val,
  .load = rtw89_acpi_sar_load_std_has_6ghz,
 },
 {
  .id = {
   .cid = RTW89_ACPI_SAR_CID_RT,
   .rev = RTW89_ACPI_SAR_REV_LEGACY,
   .size = RTW89_ACPI_SAR_SIZE_OF(std_legacy),
  },
  .geo = &rtw89_acpi_geo_sar_handler_rt_legacy,

  .rfpath_to_antidx = rtw89_acpi_sar_rfpath_to_rt_antidx,
  .normalize = rtw89_acpi_sar_normalize_rt_val,
  .load = rtw89_acpi_sar_load_std_legacy,
 },
 {
  .id = {
   .cid = RTW89_ACPI_SAR_CID_RT,
   .rev = RTW89_ACPI_SAR_REV_HAS_6GHZ,
   .size = RTW89_ACPI_SAR_SIZE_OF(std_has_6ghz),
  },
  .geo = &rtw89_acpi_geo_sar_handler_rt_has_6ghz,

  .rfpath_to_antidx = rtw89_acpi_sar_rfpath_to_rt_antidx,
  .normalize = rtw89_acpi_sar_normalize_rt_val,
  .load = rtw89_acpi_sar_load_std_has_6ghz,
 },
 {
  .id = {
   .cid = RTW89_ACPI_SAR_CID_RT,
   .rev = RTW89_ACPI_SAR_REV_LEGACY,
   .size = RTW89_ACPI_SAR_SIZE_OF(sml_legacy),
  },
  .geo = &rtw89_acpi_geo_sar_handler_rt_legacy,

  .rfpath_to_antidx = rtw89_acpi_sar_rfpath_to_rt_antidx,
  .normalize = rtw89_acpi_sar_normalize_rt_val,
  .load = rtw89_acpi_sar_load_sml_legacy,
 },
 {
  .id = {
   .cid = RTW89_ACPI_SAR_CID_RT,
   .rev = RTW89_ACPI_SAR_REV_HAS_6GHZ,
   .size = RTW89_ACPI_SAR_SIZE_OF(sml_has_6ghz),
  },
  .geo = &rtw89_acpi_geo_sar_handler_rt_has_6ghz,

  .rfpath_to_antidx = rtw89_acpi_sar_rfpath_to_rt_antidx,
  .normalize = rtw89_acpi_sar_normalize_rt_val,
  .load = rtw89_acpi_sar_load_sml_has_6ghz,
 },
};

struct rtw89_acpi_sar_rec_parm {
 u32 pld_len;
 u8 tbl_cnt;
 u16 cid;
 u8 rev;
};

static const struct rtw89_acpi_sar_recognition *
rtw89_acpi_sar_recognize(struct rtw89_dev *rtwdev,
    const struct rtw89_acpi_sar_rec_parm *parm)
{
 const u32 tbl_len = parm->pld_len / parm->tbl_cnt;
 const struct rtw89_acpi_sar_recognition *rec;
 struct rtw89_acpi_sar_identifier id = {};

 rtw89_debug(rtwdev, RTW89_DBG_ACPI,
      "%s: cid %u, rev %u, tbl len %u, tbl cnt %u\n",
      __func__, parm->cid, parm->rev, tbl_len, parm->tbl_cnt);

 if (unlikely(parm->pld_len % parm->tbl_cnt)) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI, "invalid pld len %u\n",
       parm->pld_len);
  return NULL;
 }

 if (unlikely(tbl_len > RTW89_ACPI_SAR_SIZE_MAX)) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI, "invalid tbl len %u\n",
       tbl_len);
  return NULL;
 }

 if (unlikely(parm->tbl_cnt > MAX_NUM_OF_RTW89_ACPI_SAR_TBL)) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI, "invalid tbl cnt %u\n",
       parm->tbl_cnt);
  return NULL;
 }

 switch (parm->cid) {
 case RTW89_ACPI_SAR_CID_HP:
 case RTW89_ACPI_SAR_CID_RT:
  id.cid = parm->cid;
  break;
 default:
  rtw89_debug(rtwdev, RTW89_DBG_ACPI, "invalid cid 0x%x\n",
       parm->cid);
  return NULL;
 }

 switch (parm->rev) {
 case RTW89_ACPI_SAR_REV_LEGACY:
 case RTW89_ACPI_SAR_REV_HAS_6GHZ:
  id.rev = parm->rev;
  break;
 default:
  rtw89_debug(rtwdev, RTW89_DBG_ACPI, "invalid rev %u\n",
       parm->rev);
  return NULL;
 }

 id.size = tbl_len;
 for (unsigned int i = 0; i < ARRAY_SIZE(rtw89_acpi_sar_recs); i++) {
  rec = &rtw89_acpi_sar_recs[i];
  if (memcmp(&rec->id, &id, sizeof(rec->id)) == 0)
   return rec;
 }

 rtw89_debug(rtwdev, RTW89_DBG_ACPI, "failed to recognize\n");
 return NULL;
}

static const struct rtw89_acpi_sar_recognition *
rtw89_acpi_evaluate_static_sar(struct rtw89_dev *rtwdev,
          struct rtw89_sar_cfg_acpi *cfg)
{
 const struct rtw89_acpi_sar_recognition *rec = NULL;
 const struct rtw89_acpi_static_sar_hdr *hdr;
 struct rtw89_sar_entry_from_acpi tmp = {};
 struct rtw89_acpi_sar_rec_parm parm = {};
 struct rtw89_sar_table_from_acpi *tbl;
 const struct rtw89_acpi_data *data;
 u32 len;

 data = rtw89_acpi_evaluate_method(rtwdev, RTW89_ACPI_METHOD_STATIC_SAR);
 if (!data)
  return NULL;

 rtw89_debug(rtwdev, RTW89_DBG_ACPI, "acpi load static sar\n");

 len = data->len;
 if (len <= sizeof(*hdr)) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI, "invalid buf len %u\n", len);
  goto out;
 }

 hdr = (typeof(hdr))data->buf;

 parm.cid = le16_to_cpu(hdr->cid);
 parm.rev = hdr->rev;
 parm.tbl_cnt = 1;
 parm.pld_len = len - sizeof(*hdr);

 rec = rtw89_acpi_sar_recognize(rtwdev, &parm);
 if (!rec)
  goto out;

 rec->load(rtwdev, rec, hdr->content, &tmp);

 tbl = &cfg->tables[0];
 for (u8 regd = 0; regd < RTW89_REGD_NUM; regd++)
  tbl->entries[regd] = tmp;

 cfg->valid_num = 1;

out:
 kfree(data);
 return rec;
}

static const struct rtw89_acpi_sar_recognition *
rtw89_acpi_evaluate_dynamic_sar(struct rtw89_dev *rtwdev,
    struct rtw89_sar_cfg_acpi *cfg)
{
 const struct rtw89_acpi_sar_recognition *rec = NULL;
 const struct rtw89_acpi_dynamic_sar_hdr *hdr;
 struct rtw89_acpi_sar_rec_parm parm = {};
 struct rtw89_sar_table_from_acpi *tbl;
 const struct rtw89_acpi_data *data;
 u32 len;

 data = rtw89_acpi_evaluate_method(rtwdev, RTW89_ACPI_METHOD_DYNAMIC_SAR);
 if (!data)
  return NULL;

 rtw89_debug(rtwdev, RTW89_DBG_ACPI, "acpi load dynamic sar\n");

 len = data->len;
 if (len <= sizeof(*hdr)) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI, "invalid buf len %u\n", len);
  goto out;
 }

 hdr = (typeof(hdr))data->buf;

 parm.cid = le16_to_cpu(hdr->cid);
 parm.rev = hdr->rev;
 parm.tbl_cnt = hdr->cnt;
 parm.pld_len = len - sizeof(*hdr);

 rec = rtw89_acpi_sar_recognize(rtwdev, &parm);
 if (!rec)
  goto out;

 for (unsigned int i = 0; i < hdr->cnt; i++) {
  const u8 *content = hdr->content + rec->id.size * i;
  struct rtw89_sar_entry_from_acpi tmp = {};

  rec->load(rtwdev, rec, content, &tmp);

  tbl = &cfg->tables[i];
  for (u8 regd = 0; regd < RTW89_REGD_NUM; regd++)
   tbl->entries[regd] = tmp;
 }

 cfg->valid_num = hdr->cnt;

out:
 kfree(data);
 return rec;
}

int rtw89_acpi_evaluate_dynamic_sar_indicator(struct rtw89_dev *rtwdev,
           struct rtw89_sar_cfg_acpi *cfg,
           bool *poll_changed)
{
 struct rtw89_sar_indicator_from_acpi *ind = &cfg->indicator;
 struct rtw89_sar_indicator_from_acpi tmp = *ind;
 const struct rtw89_acpi_data *data;
 const u8 *tbl_base1_by_ant;
 enum rtw89_rf_path path;
 int ret = 0;
 u32 len;

 data = rtw89_acpi_evaluate_method(rtwdev, RTW89_ACPI_METHOD_DYNAMIC_SAR_INDICATOR);
 if (!data)
  return -EFAULT;

 if (!poll_changed)
  rtw89_debug(rtwdev, RTW89_DBG_ACPI, "acpi load dynamic sar indicator\n");

 len = data->len;
 if (len != ind->fields) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI, "invalid buf len %u\n", len);
  ret = -EINVAL;
  goto out;
 }

 tbl_base1_by_ant = data->buf;

 for (path = 0; path < NUM_OF_RTW89_ACPI_SAR_RF_PATH; path++) {
  u8 antidx = ind->rfpath_to_antidx(path);
  u8 sel;

  if (antidx >= ind->fields)
   antidx = 0;

  /* convert the table index from 1-based to 0-based */
  sel = tbl_base1_by_ant[antidx] - 1;
  if (sel >= cfg->valid_num)
   sel = 0;

  tmp.tblsel[path] = sel;
 }

 if (memcmp(ind, &tmp, sizeof(*ind)) == 0) {
  if (poll_changed)
   *poll_changed = false;
 } else {
  if (poll_changed)
   *poll_changed = true;

  *ind = tmp;
 }

out:
 kfree(data);
 return ret;
}

static
void rtw89_acpi_evaluate_geo_sar(struct rtw89_dev *rtwdev,
     const struct rtw89_acpi_geo_sar_handler *hdl,
     struct rtw89_sar_cfg_acpi *cfg)
{
 const struct rtw89_acpi_data *data;
 u32 len;

 data = rtw89_acpi_evaluate_method(rtwdev, RTW89_ACPI_METHOD_GEO_SAR);
 if (!data)
  return;

 rtw89_debug(rtwdev, RTW89_DBG_ACPI, "acpi load geo sar\n");

 len = data->len;
 if (len != hdl->data_size) {
  rtw89_debug(rtwdev, RTW89_DBG_ACPI, "invalid buf len %u (expected %u)\n",
       len, hdl->data_size);
  goto out;
 }

 for (unsigned int i = 0; i < cfg->valid_num; i++)
  for (u8 regd = 0; regd < RTW89_REGD_NUM; regd++)
   hdl->load(rtwdev, data->buf, regd, &cfg->tables[i].entries[regd]);

out:
 kfree(data);
}

int rtw89_acpi_evaluate_sar(struct rtw89_dev *rtwdev,
       struct rtw89_sar_cfg_acpi *cfg)
{
 struct rtw89_sar_indicator_from_acpi *ind = &cfg->indicator;
 const struct rtw89_acpi_sar_recognition *rec;
 bool fetch_indicator = false;
 int ret;

 rec = rtw89_acpi_evaluate_static_sar(rtwdev, cfg);
 if (rec)
  goto recognized;

 rec = rtw89_acpi_evaluate_dynamic_sar(rtwdev, cfg);
 if (!rec)
  return -ENOENT;

 fetch_indicator = true;

recognized:
 rtw89_acpi_evaluate_geo_sar(rtwdev, rec->geo, cfg);

 switch (rec->id.cid) {
 case RTW89_ACPI_SAR_CID_HP:
  cfg->downgrade_2tx = 3 << TXPWR_FACTOR_OF_RTW89_ACPI_SAR;
  ind->fields = RTW89_ACPI_SAR_ANT_NR_STD;
  break;
 case RTW89_ACPI_SAR_CID_RT:
  cfg->downgrade_2tx = 0;
  ind->fields = 1;
  break;
 default:
  return -EFAULT;
 }

 if (fetch_indicator) {
  ind->rfpath_to_antidx = rec->rfpath_to_antidx;
  ret = rtw89_acpi_evaluate_dynamic_sar_indicator(rtwdev, cfg, NULL);
  if (ret)
   fetch_indicator = false;
 }

 if (!fetch_indicator)
  memset(ind->tblsel, 0, sizeof(ind->tblsel));

 ind->enable_sync = fetch_indicator;
 return 0;
}

Messung V0.5
C=96 H=92 G=93

¤ Dauer der Verarbeitung: 0.19 Sekunden  (vorverarbeitet)  ¤

*© 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge