Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/net/wireless/broadcom/brcm80211/brcmfmac/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 4 kB image not shown  

Quelle  fwvid.c   Sprache: C

 
// SPDX-License-Identifier: ISC
/*
 * Copyright (c) 2022 Broadcom Corporation
 */

#include <linux/errno.h>
#include <linux/export.h>
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/list.h>
#include <linux/completion.h>
#include <linux/mutex.h>
#include <linux/printk.h>
#include <linux/jiffies.h>
#include <linux/workqueue.h>

#include "core.h"
#include "bus.h"
#include "debug.h"
#include "fwvid.h"

#include "wcc/vops.h"
#include "cyw/vops.h"
#include "bca/vops.h"

struct brcmf_fwvid_entry {
 const char *name;
 const struct brcmf_fwvid_ops *vops;
 struct list_head drvr_list;
#if IS_MODULE(CONFIG_BRCMFMAC)
 struct module *vmod;
 struct completion reg_done;
#endif
};

static DEFINE_MUTEX(fwvid_list_lock);

#if IS_MODULE(CONFIG_BRCMFMAC)
#define FWVID_ENTRY_INIT(_vid, _name) \
 [BRCMF_FWVENDOR_ ## _vid] = { \
  .name = #_name, \
  .reg_done = COMPLETION_INITIALIZER(fwvid_list[BRCMF_FWVENDOR_ ## _vid].reg_done), \
  .drvr_list = LIST_HEAD_INIT(fwvid_list[BRCMF_FWVENDOR_ ## _vid].drvr_list), \
 }
#else
#define FWVID_ENTRY_INIT(_vid, _name) \
 [BRCMF_FWVENDOR_ ## _vid] = { \
  .name = #_name, \
  .drvr_list = LIST_HEAD_INIT(fwvid_list[BRCMF_FWVENDOR_ ## _vid].drvr_list), \
  .vops = _vid ## _VOPS \
 }
#endif /* IS_MODULE(CONFIG_BRCMFMAC) */

static struct brcmf_fwvid_entry fwvid_list[BRCMF_FWVENDOR_NUM] = {
 FWVID_ENTRY_INIT(WCC, wcc),
 FWVID_ENTRY_INIT(CYW, cyw),
 FWVID_ENTRY_INIT(BCA, bca),
};

#if IS_MODULE(CONFIG_BRCMFMAC)
static int brcmf_fwvid_request_module(enum brcmf_fwvendor fwvid)
{
 int ret;

 if (!fwvid_list[fwvid].vmod) {
  struct completion *reg_done = &fwvid_list[fwvid].reg_done;

  mutex_unlock(&fwvid_list_lock);

  ret = request_module("brcmfmac-%s", fwvid_list[fwvid].name);
  if (ret)
   goto fail;

  ret = wait_for_completion_interruptible(reg_done);
  if (ret)
   goto fail;

  mutex_lock(&fwvid_list_lock);
 }
 return 0;

fail:
 brcmf_err("mod=%s: failed %d\n", fwvid_list[fwvid].name, ret);
 return ret;
}

int brcmf_fwvid_register_vendor(enum brcmf_fwvendor fwvid, struct module *vmod,
    const struct brcmf_fwvid_ops *vops)
{
 if (fwvid >= BRCMF_FWVENDOR_NUM)
  return -ERANGE;

 if (WARN_ON(!vmod) || WARN_ON(!vops) ||
     WARN_ON(!vops->alloc_fweh_info))
  return -EINVAL;

 if (WARN_ON(fwvid_list[fwvid].vmod))
  return -EEXIST;

 brcmf_dbg(TRACE, "mod=%s: enter\n", fwvid_list[fwvid].name);

 mutex_lock(&fwvid_list_lock);

 fwvid_list[fwvid].vmod = vmod;
 fwvid_list[fwvid].vops = vops;

 mutex_unlock(&fwvid_list_lock);

 complete_all(&fwvid_list[fwvid].reg_done);

 return 0;
}
BRCMF_EXPORT_SYMBOL_GPL(brcmf_fwvid_register_vendor);

int brcmf_fwvid_unregister_vendor(enum brcmf_fwvendor fwvid, struct module *mod)
{
 struct brcmf_bus *bus, *tmp;

 if (fwvid >= BRCMF_FWVENDOR_NUM)
  return -ERANGE;

 if (WARN_ON(fwvid_list[fwvid].vmod != mod))
  return -ENOENT;

 mutex_lock(&fwvid_list_lock);

 list_for_each_entry_safe(bus, tmp, &fwvid_list[fwvid].drvr_list, list) {
  mutex_unlock(&fwvid_list_lock);

  brcmf_dbg(INFO, "mod=%s: removing %s\n", fwvid_list[fwvid].name,
     dev_name(bus->dev));
  brcmf_bus_remove(bus);

  mutex_lock(&fwvid_list_lock);
 }

 fwvid_list[fwvid].vmod = NULL;
 fwvid_list[fwvid].vops = NULL;
 reinit_completion(&fwvid_list[fwvid].reg_done);

 brcmf_dbg(TRACE, "mod=%s: exit\n", fwvid_list[fwvid].name);
 mutex_unlock(&fwvid_list_lock);

 return 0;
}
BRCMF_EXPORT_SYMBOL_GPL(brcmf_fwvid_unregister_vendor);
#else
static inline int brcmf_fwvid_request_module(enum brcmf_fwvendor fwvid)
{
 return 0;
}
#endif

int brcmf_fwvid_attach(struct brcmf_pub *drvr)
{
 enum brcmf_fwvendor fwvid = drvr->bus_if->fwvid;
 int ret;

 if (fwvid >= ARRAY_SIZE(fwvid_list))
  return -ERANGE;

 brcmf_dbg(TRACE, "mod=%s: enter: dev %s\n", fwvid_list[fwvid].name,
    dev_name(drvr->bus_if->dev));

 mutex_lock(&fwvid_list_lock);

 ret = brcmf_fwvid_request_module(fwvid);
 if (ret)
  return ret;

 drvr->vops = fwvid_list[fwvid].vops;
 list_add(&drvr->bus_if->list, &fwvid_list[fwvid].drvr_list);

 mutex_unlock(&fwvid_list_lock);

 return ret;
}

void brcmf_fwvid_detach(struct brcmf_pub *drvr)
{
 enum brcmf_fwvendor fwvid = drvr->bus_if->fwvid;

 if (fwvid >= ARRAY_SIZE(fwvid_list))
  return;

 brcmf_dbg(TRACE, "mod=%s: enter: dev %s\n", fwvid_list[fwvid].name,
    dev_name(drvr->bus_if->dev));

 mutex_lock(&fwvid_list_lock);

 if (drvr->vops) {
  drvr->vops = NULL;
  list_del(&drvr->bus_if->list);
 }
 mutex_unlock(&fwvid_list_lock);
}

const char *brcmf_fwvid_vendor_name(struct brcmf_pub *drvr)
{
 return fwvid_list[drvr->bus_if->fwvid].name;
}

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

¤ Dauer der Verarbeitung: 0.8 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.