Eine aufbereitete Darstellung der Quelle

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

Benutzer

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 in Prozent
C=98 H=94 G=95

¤ Dauer der Verarbeitung: 0.16 Sekunden  (vorverarbeitet am  2026-06-07) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

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

letze Version des Elbe Quellennavigators


Jenseits des Üblichen ....

Besucher

Besucher

Statistik
#Sources=434850
#Domains=655579