asoc 音频驱动学习笔记1

2024-06-23 05:58
文章标签 音频 学习 驱动 笔记 asoc

本文主要是介绍asoc 音频驱动学习笔记1,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

linux音频驱动框架有3中,oss,alsa,asoc,其中asoc驱动框架是alsa框架为移动设备的改进版,asoc属于alsa音频驱动模块架构,是专门为嵌入式音频系统设计的,asoc结构中,驱动被分为3部分,codec driver部分,platform driver 部分和machine driver 部分,codec driver 主要负责实现声卡中的寄存器的配置功能,platform负责实现低特定的音频接口控制器和dma控制器的操作,machine driver 主要负责把codec driver 和platform driver 按照框架联系起来。 

下面进行代码分析,分析codec driver ,以wm8960声卡驱动为例

老规矩,从入口看,定义了一个i2c驱动,这个i2c的设备啥时候定义以后再找

 static struct i2c_driver wm8960_i2c_driver = {
.driver = {
.name = "wm8960-codec",
.owner = THIS_MODULE,
},
<span style="color:#ff6666;">.probe =    wm8960_i2c_probe,
</span>	.remove =   __devexit_p(wm8960_i2c_remove),
.id_table = wm8960_i2c_id,
};
#endif
static int __init wm8960_modinit(void)
{
int ret = 0;
#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
<span style="color:#ff6666;">ret = i2c_add_driver(&wm8960_i2c_driver);
</span>	if (ret != 0) {
printk(KERN_ERR "Failed to register WM8960 I2C driver: %d\n",
ret);
}
#endif
return ret;
}
module_init(wm8960_modinit);

查看probe函数

static __devinit int wm8960_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
<span style="color:#ff6666;">struct wm8960_priv *wm8960;
</span>	int ret;
wm8960 = kzalloc(sizeof(struct wm8960_priv), GFP_KERNEL);
if (wm8960 == NULL)
return -ENOMEM;
i2c_set_clientdata(i2c, wm8960);
wm8960->control_type = SND_SOC_I2C;
wm8960->control_data = i2c;
<span style="color:#ff6666;">ret = snd_soc_register_codec(&i2c->dev,
&soc_codec_dev_wm8960, &wm8960_dai, 1);
</span>	if (ret < 0)
kfree(wm8960);
return ret;
}

查看struct wm8960_priv *wm8960;

struct wm8960_priv {
enum snd_soc_control_type control_type;
void *control_data;
int (*set_bias_level)(struct snd_soc_codec *,
enum snd_soc_bias_level level);
struct snd_soc_dapm_widget *lout1;
struct snd_soc_dapm_widget *rout1;
struct snd_soc_dapm_widget *out3;
bool deemph;
int playback_fs;
};

这个结构定义了声卡芯片的i2c设备私有数据,probe时主要i2c_set_clientdata(i2c, wm8960);

wm8960->control_type = SND_SOC_I2C;

wm8960->control_data = i2c;,以后可能还会对这个结构进行操作,到时候可能会通过i2c_client对它进行操作

查看ret = snd_soc_register_codec(&i2c->dev,&soc_codec_dev_wm8960, &wm8960_dai, 1);

从传入的参数看,涉及到了两个结构

1.struct snd_soc_codec_driver soc_codec_dev_wm8960

static struct snd_soc_codec_driver soc_codec_dev_wm8960 = {
.probe =	wm8960_probe,
.remove =	wm8960_remove,
.suspend =	wm8960_suspend,
.resume =	wm8960_resume,
.set_bias_level = wm8960_set_bias_level,
.reg_cache_size = ARRAY_SIZE(wm8960_reg),
.reg_word_size = sizeof(u16),
.reg_cache_default = wm8960_reg,
};

这个结构体的定义为

/* codec driver */
struct snd_soc_codec_driver {
/* driver ops */
int (*probe)(struct snd_soc_codec *);
int (*remove)(struct snd_soc_codec *);
int (*suspend)(struct snd_soc_codec *,
pm_message_t state);
int (*resume)(struct snd_soc_codec *);
/* Default control and setup, added after probe() is run */
const struct snd_kcontrol_new *controls;
int num_controls;
const struct snd_soc_dapm_widget *dapm_widgets;
int num_dapm_widgets;
const struct snd_soc_dapm_route *dapm_routes;
int num_dapm_routes;
/* codec wide operations */
int (*set_sysclk)(struct snd_soc_codec *codec,
int clk_id, unsigned int freq, int dir);
int (*set_pll)(struct snd_soc_codec *codec, int pll_id, int source,
unsigned int freq_in, unsigned int freq_out);
/* codec IO */
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
int (*display_register)(struct snd_soc_codec *, char *,
size_t, unsigned int);
int (*volatile_register)(struct snd_soc_codec *, unsigned int);
int (*readable_register)(struct snd_soc_codec *, unsigned int);
int (*writable_register)(struct snd_soc_codec *, unsigned int);
short reg_cache_size;
short reg_cache_step;
short reg_word_size;
const void *reg_cache_default;
short reg_access_size;
const struct snd_soc_reg_access *reg_access_default;
enum snd_soc_compress_type compress_type;
/* codec bias level */
int (*set_bias_level)(struct snd_soc_codec *,
enum snd_soc_bias_level level);
void (*seq_notifier)(struct snd_soc_dapm_context *,
enum snd_soc_dapm_type, int);
};

 

2.struct snd_soc_dai_driver wm8960_dai 

static struct snd_soc_dai_driver wm8960_dai = {
.name = "wm8960-hifi",
.playback = {
.stream_name = "Playback",
.channels_min = 1,
.channels_max = 2,
.rates = WM8960_RATES,
.formats = WM8960_FORMATS,},
.capture = {
.stream_name = "Capture",
.channels_min = 1,
.channels_max = 2,
.rates = WM8960_RATES,
.formats = WM8960_FORMATS,},
.ops = &wm8960_dai_ops,
.symmetric_rates = 1,
};

这个结构体的定义为

struct snd_soc_dai_driver {
/* DAI description */
const char *name;
unsigned int id;
int ac97_control;
/* DAI driver callbacks */
int (*probe)(struct snd_soc_dai *dai);
int (*remove)(struct snd_soc_dai *dai);
int (*suspend)(struct snd_soc_dai *dai);
int (*resume)(struct snd_soc_dai *dai);
/* ops */
const struct snd_soc_dai_ops *ops;
/* DAI capabilities */
struct snd_soc_pcm_stream capture;
struct snd_soc_pcm_stream playback;
unsigned int symmetric_rates:1;
};

这个结构主要根据ALSA框架、dai和ac97操作和能力来描述数字音频接口,codec 和platform driver 将注册这个结构为每一个 dai

进入int snd_soc_register_codec(struct device *dev,  const struct snd_soc_codec_driver *codec_drv,  struct snd_soc_dai_driver *dai_drv,  int num_dai)函数

 

size_t reg_size;
<span style="color:#ff0000;">struct snd_soc_codec *codec;
</span>	int ret, i;
dev_dbg(dev, "codec register %s\n", dev_name(dev));
codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);
if (codec == NULL)
return -ENOMEM;

这里引入了一个新的结构 , 用来描述codec设备的,

/* SoC Audio Codec device */
struct snd_soc_codec {
const char *name;
const char *name_prefix;
int id;
struct device *dev;
const struct snd_soc_codec_driver *driver;
struct mutex mutex;
struct snd_soc_card *card;
struct list_head list;
struct list_head card_list;
int num_dai;
enum snd_soc_compress_type compress_type;
size_t reg_size;	/* reg_cache_size * reg_word_size */
int (*volatile_register)(struct snd_soc_codec *, unsigned int);
int (*readable_register)(struct snd_soc_codec *, unsigned int);
int (*writable_register)(struct snd_soc_codec *, unsigned int);
/* runtime */
struct snd_ac97 *ac97;  /* for ad-hoc ac97 devices */
unsigned int active;
unsigned int cache_bypass:1; /* Suppress access to the cache */
unsigned int suspended:1; /* Codec is in suspend PM state */
unsigned int probed:1; /* Codec has been probed */
unsigned int ac97_registered:1; /* Codec has been AC97 registered */
unsigned int ac97_created:1; /* Codec has been created by SoC */
unsigned int sysfs_registered:1; /* codec has been sysfs registered */
unsigned int cache_init:1; /* codec cache has been initialized */
u32 cache_only;  /* Suppress writes to hardware */
u32 cache_sync; /* Cache needs to be synced to hardware */
/* codec IO */
void *control_data; /* codec control (i2c/3wire) data */
enum snd_soc_control_type control_type;
hw_write_t hw_write;
unsigned int (*hw_read)(struct snd_soc_codec *, unsigned int);
unsigned int (*read)(struct snd_soc_codec *, unsigned int);
int (*write)(struct snd_soc_codec *, unsigned int, unsigned int);
int (*bulk_write_raw)(struct snd_soc_codec *, unsigned int, const void *, size_t);
void *reg_cache;
const void *reg_def_copy;
const struct snd_soc_cache_ops *cache_ops;
struct mutex cache_rw_mutex;
/* dapm */
struct snd_soc_dapm_context dapm;
#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs_codec_root;
struct dentry *debugfs_reg;
struct dentry *debugfs_dapm;
#endif
};

继续分析int snd_soc_register_codec

codec = kzalloc(sizeof(struct snd_soc_codec), GFP_KERNEL);

struct snd_soc_codec分配内存空间

/* create CODEC component name */创建codec部件名
codec->name = fmt_single_name(dev, &codec->id);
<p>  对<span style="font-family:Times New Roman;">codec</span><span style="font-family:宋体;">进行结构进行一些填充</span></p>
if (codec_drv->compress_type)
codec->compress_type = codec_drv->compress_type;
else
codec->compress_type = SND_SOC_FLAT_COMPRESSION;
codec->write = codec_drv->write;
codec->read = codec_drv->read;
codec->volatile_register = codec_drv->volatile_register;
codec->readable_register = codec_drv->readable_register;
codec->writable_register = codec_drv->writable_register;
codec->dapm.bias_level = SND_SOC_BIAS_OFF;
codec->dapm.dev = dev;
codec->dapm.codec = codec;
codec->dapm.seq_notifier = codec_drv->seq_notifier;
codec->dev = dev;
codec->driver = codec_drv;
codec->num_dai = num_dai;
mutex_init(&codec->mutex);

分配codec寄存器缓存

/* allocate CODEC register cache */
if (codec_drv->reg_cache_size && codec_drv->reg_word_size) {
reg_size = codec_drv->reg_cache_size * codec_drv->reg_word_size;
codec->reg_size = reg_size;
/* it is necessary to make a copy of the default register cache
* because in the case of using a compression type that requires
* the default register cache to be marked as __devinitconst the
* kernel might have freed the array by the time we initialize
* the cache.
*/
if (codec_drv->reg_cache_default) {
codec->reg_def_copy = kmemdup(codec_drv->reg_cache_default,
reg_size, GFP_KERNEL);
if (!codec->reg_def_copy) {
ret = -ENOMEM;
goto fail;
}
}
}

检查了dai_drv结构中的.playback .capture中的formats字段的格式,为格式加入了大端或者小端格式

for (i = 0; i < num_dai; i++) {
fixup_codec_formats(&dai_drv[i].playback);
fixup_codec_formats(&dai_drv[i].capture);
}
/* register any DAIs */
if (num_dai) {
<span style="color:#ff0000;">ret = snd_soc_register_dais(dev, dai_drv, num_dai);注册dai
</span>		if (ret < 0)
goto fail;
}

进入snd_soc_register_dais函数

int snd_soc_register_dais(struct device *dev,
struct snd_soc_dai_driver *dai_drv, size_t count)
{
struct snd_soc_dai *dai;
int i, ret = 0;
dev_dbg(dev, "dai register %s #%Zu\n", dev_name(dev), count);

里面涉及到一个重要结构

/*
* Digital Audio Interface runtime data.
*
* Holds runtime data for a DAI.
*/
struct snd_soc_dai {
const char *name;
int id;
struct device *dev;
void *ac97_pdata;	/* platform_data for the ac97 codec */
/* driver ops */
struct snd_soc_dai_driver *driver;
/* DAI runtime info */
unsigned int capture_active:1;		/* stream is in use */
unsigned int playback_active:1;		/* stream is in use */
unsigned int symmetric_rates:1;
struct snd_pcm_runtime *runtime;
unsigned int active;
unsigned char pop_wait:1;
unsigned char probed:1;
/* DAI DMA data */
void *playback_dma_data;
void *capture_dma_data;
/* parent platform/codec */
union {
struct snd_soc_platform *platform;
struct snd_soc_codec *codec;
};
struct snd_soc_card *card;
struct list_head list;
struct list_head card_list;
};

继续看这个函数

for (i = 0; i < count; i++) {
<span style="color:#ff0000;">dai = kzalloc(sizeof(struct snd_soc_dai), GFP_KERNEL);//分配内存
</span>		if (dai == NULL) {
ret = -ENOMEM;
goto err;
}
/* create DAI component name */
<span style="color:#ff0000;">dai->name = fmt_multiple_name(dev, &dai_drv[i]);名字
</span>		if (dai->name == NULL) {
kfree(dai);
ret = -EINVAL;
goto err;
}
dai->dev = dev;
dai->driver = &dai_drv[i];
if (dai->driver->id)
dai->id = dai->driver->id;
else
dai->id = i;
if (!dai->driver->ops)
dai->driver->ops = &null_dai_ops;
<span style="color:#ff0000;">mutex_lock(&client_mutex);使用一个互斥锁
list_add(&dai->list, &dai_list);把dai链表插入,想当于创建了一个链表
mutex_unlock(&client_mutex);
</span>		pr_debug("Registered DAI '%s'\n", dai->name);
}
<span style="color:#ff0000;">mutex_lock(&client_mutex);重要操作,要加互斥锁
snd_soc_instantiate_cards();
mutex_unlock(&client_mutex);
</span>	return 0;
err:
for (i--; i >= 0; i--)
snd_soc_unregister_dai(dev);
return ret;
}

/*努力去初始化没有初始化的card,进行snd_soc_instantiate_cards(void)函数的调用,一定要使用client mutex互斥锁

 * Attempt to initialise any uninitialised cards.  Must be called with
* client_mutex.
*/
static void snd_soc_instantiate_cards(void)
{
struct snd_soc_card *card;
<span style="color:#ff0000;">list_for_each_entry(card, &card_list, list)//遍历card_list中的card设备
</span>		<span style="color:#ff0000;">snd_soc_instantiate_card(card);
</span>}

分析snd_soc_instantiate_card这个函数吧,这个函数绝对重要

static void snd_soc_instantiate_card(struct snd_soc_card *card)
{
struct snd_soc_codec *codec;
struct snd_soc_codec_conf *codec_conf;
enum snd_soc_compress_type compress_type;
int ret, i;
mutex_lock(&card->mutex);
<span style="color:#ff0000;">if (card->instantiated) {如果遍历的这个card已经是初始化过的状态,那就直接解锁,返回
mutex_unlock(&card->mutex);
return;
}
</span>	/* bind DAIs */
for (i = 0; i < card->num_links; i++)
<span style="color:#ff0000;">	soc_bind_dai_link(card, i);绑定codec codec_dai cpu_dai 和 platform,这个函数挺关键的,以后的返回来再好好看看
</span>
<span style="color:#ff0000;">/* bind completed ? */判定是否绑定成功
if (card->num_rtd != card->num_links) {
</span>		mutex_unlock(&card->mutex);
return;
}
<span style="color:#ff0000;">/* initialize the register cache for each available codec */
初始化注册的寄存器缓存为可使用的codec
</span>	list_for_each_entry(codec, &codec_list, list) {
if (codec->cache_init)
continue;
/* by default we don't override the compress_type */
compress_type = 0;
/* check to see if we need to override the compress_type */
for (i = 0; i < card->num_configs; ++i) {
codec_conf = &card->codec_conf[i];
if (!strcmp(codec->name, codec_conf->dev_name)) {
compress_type = codec_conf->compress_type;
if (compress_type && compress_type
!= codec->compress_type)
break;
}
}
ret = snd_soc_init_codec_cache(codec, compress_type);
if (ret < 0) {
mutex_unlock(&card->mutex);
return;
}
}
<span style="color:#ff0000;">创建声卡
/* card bind complete so register a sound card */
ret = snd_card_create(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
card->owner, 0, &card->snd_card);
</span>	if (ret < 0) {
printk(KERN_ERR "asoc: can't create sound card for card %s\n",
card->name);
mutex_unlock(&card->mutex);
return;
}
card->snd_card->dev = card->dev;
card->dapm.bias_level = SND_SOC_BIAS_OFF;
card->dapm.dev = card->dev;
card->dapm.card = card;
list_add(&card->dapm.list, &card->dapm_list);
#ifdef CONFIG_DEBUG_FS
snd_soc_dapm_debugfs_init(&card->dapm, card->debugfs_card_root);
#endif
#ifdef CONFIG_PM_SLEEP
/* deferred resume work */
INIT_WORK(&card->deferred_resume_work, soc_resume_deferred);
#endif
<span style="color:#ff0000;">创建一个新的dapm control
if (card->dapm_widgets)
snd_soc_dapm_new_controls(&card->dapm, card->dapm_widgets,
card->num_dapm_widgets);
初始化声卡,执行声卡的prob函数,probe函数具体在哪,待会儿再找吧
/* initialise the sound card only once */
if (card->probe) {
ret = card->probe(card);
if (ret < 0)
goto card_probe_error;
</span>	}
for (i = 0; i < card->num_links; i++) {
<span style="color:#ff0000;">ret = soc_probe_dai_link(card, i);//执行相关的probe函数,然后创建pcm逻辑设备,关键函数啊,信息量很大,待会儿再好好看吧
</span>		if (ret < 0) {
pr_err("asoc: failed to instantiate card %s: %d\n",
card->name, ret);
goto probe_dai_err;
}
}
for (i = 0; i < card->num_aux_devs; i++) {
<span style="color:#ff0000;">ret = soc_probe_aux_dev(card, i);probe aux设备,aux是一个什么设备以后再看吧
</span>		if (ret < 0) {
pr_err("asoc: failed to add auxiliary devices %s: %d\n",
card->name, ret);
goto probe_aux_dev_err;
}
}
/* We should have a non-codec control add function but we don't */
if (card->controls)
snd_soc_add_controls(list_first_entry(&card->codec_dev_list,
struct snd_soc_codec,
card_list),
card->controls,
card->num_controls);
if (card->dapm_routes)
snd_soc_dapm_add_routes(&card->dapm, card->dapm_routes,
card->num_dapm_routes);
snprintf(card->snd_card->shortname, sizeof(card->snd_card->shortname),
"%s", card->name);
snprintf(card->snd_card->longname, sizeof(card->snd_card->longname),
"%s", card->long_name ? card->long_name : card->name);
if (card->driver_name)
strlcpy(card->snd_card->driver, card->driver_name,
sizeof(card->snd_card->driver));
if (card->late_probe) {
ret = card->late_probe(card);
if (ret < 0) {
dev_err(card->dev, "%s late_probe() failed: %d\n",
card->name, ret);
goto probe_aux_dev_err;
}
}
<span style="color:#ff0000;">声卡注册,,
ret = snd_card_register(card->snd_card);
</span>	if (ret < 0) {
printk(KERN_ERR "asoc: failed to register soundcard for %s\n", card->name);
goto probe_aux_dev_err;
}
#ifdef CONFIG_SND_SOC_AC97_BUS
/* register any AC97 codecs */
for (i = 0; i < card->num_rtd; i++) {
ret = soc_register_ac97_dai_link(&card->rtd[i]);
if (ret < 0) {
printk(KERN_ERR "asoc: failed to register AC97 %s\n", card->name);
while (--i >= 0)
soc_unregister_ac97_dai_link(card->rtd[i].codec);
goto probe_aux_dev_err;
}
}
#endif
card->instantiated = 1;
mutex_unlock(&card->mutex);
return;
probe_aux_dev_err:
for (i = 0; i < card->num_aux_devs; i++)
soc_remove_aux_dev(card, i);
probe_dai_err:
soc_remove_dai_links(card);
card_probe_error:
if (card->remove)
card->remove(card);
snd_card_free(card->snd_card);
mutex_unlock(&card->mutex);
}

返回到int snd_soc_register_codec(struct device *dev, const struct snd_soc_codec_driver *codec_drv,   struct snd_soc_dai_driver *dai_drv, int num_dai)中继续看

	<span style="color:#ff0000;">mutex_lock(&client_mutex);
list_add(&codec->list, &codec_list);
snd_soc_instantiate_cards();
mutex_unlock(&client_mutex);
</span>	<span style="color:#000000;">pr_debug("Registered codec '%s'\n", codec->name);
return 0;</span>

这部分代码和ret = snd_soc_register_dais(dev, dai_drv, num_dai);中的代码是相同的,都是进行了链表中的名字匹配,然后执行了相应的probe函数

这里主要介绍了codec的驱动程序的probe执行过程,asoc驱动充分应用了分块,少耦合的思想,声卡部分就管声卡部分,cpu平台部分就管cpu平台部分,这两部分可以方便的拿来任意用,不用做修改,程序员只要写asoc架构中的machine驱动就好






 

 

 

这篇关于asoc 音频驱动学习笔记1的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1086317

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

Linux_kernel驱动开发11

一、改回nfs方式挂载根文件系统         在产品将要上线之前,需要制作不同类型格式的根文件系统         在产品研发阶段,我们还是需要使用nfs的方式挂载根文件系统         优点:可以直接在上位机中修改文件系统内容,延长EMMC的寿命         【1】重启上位机nfs服务         sudo service nfs-kernel-server resta

线性代数|机器学习-P36在图中找聚类

文章目录 1. 常见图结构2. 谱聚类 感觉后面几节课的内容跨越太大,需要补充太多的知识点,教授讲得内容跨越较大,一般一节课的内容是书本上的一章节内容,所以看视频比较吃力,需要先预习课本内容后才能够很好的理解教授讲解的知识点。 1. 常见图结构 假设我们有如下图结构: Adjacency Matrix:行和列表示的是节点的位置,A[i,j]表示的第 i 个节点和第 j 个