????platform_device_系列函數及其設備注冊的作用

platform_device_系列函數,實際上是注冊了一個叫platform的虛擬總線。使用約定是如果一個不屬于任何總線的設備,例如藍牙,串口等設備,都需要掛在這個虛擬總線上。

driver/base/platform.c

//platform設備聲明
struct device platform_bus = {
??? .bus_id??????? = "platform",
};
EXPORT_SYMBOL_GPL(platform_bus);

//platform總線設備聲明
struct bus_type platform_bus_type = {
??? .name??????? = "platform",
??? .dev_attrs??? = platform_dev_attrs,
??? .match??????? = platform_match,
??? .uevent??????? = platform_uevent,
??? .suspend??? = platform_suspend,
??? .suspend_late??? = platform_suspend_late,
??? .resume_early??? = platform_resume_early,
??? .resume??????? = platform_resume,
};
EXPORT_SYMBOL_GPL(platform_bus_type);

int __init platform_bus_init(void)
{
??? int error;

??? error = device_register(&platform_bus);//注冊了"platform"的設備
??? if (error)
??????? return error;
??? error = bus_register(&platform_bus_type);//注冊了叫"platform"的總線
??? if (error)
??????? device_unregister(&platform_bus);
??? return error;
}


//這里在platform總線上掛設備
int platform_device_add(struct platform_device *pdev)
{
??? int i, ret = 0;

??? if (!pdev)
??????? return -EINVAL;

??? if (!pdev->dev.parent)
??????? pdev->dev.parent = &platform_bus;//父設備設置為platform_bus

??? pdev->dev.bus = &platform_bus_type;//設置掛在platform總線上

??? if (pdev->id != -1)
??????? snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%d", pdev->name,
???????????? pdev->id);
??? else
??????? strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);

??? for (i = 0; i < pdev->num_resources; i++) {
??????? struct resource *p, *r = &pdev->resource[i];

??????? if (r->name == NULL)
??????????? r->name = pdev->dev.bus_id;

??????? p = r->parent;
??????? if (!p) {
??????????? if (r->flags & IORESOURCE_MEM)
??????????????? p = &iomem_resource;
??????????? else if (r->flags & IORESOURCE_IO)
??????????????? p = &ioport_resource;
??????? }

??????? if (p && insert_resource(p, r)) {
??????????? printk(KERN_ERR
?????????????????? "%s: failed to claim resource %d\n",
?????????????????? pdev->dev.bus_id, i);
??????????? ret = -EBUSY;
??????????? goto failed;
??????? }
??? }

??? pr_debug("Registering platform device '%s'. Parent at %s\n",
???????? pdev->dev.bus_id, pdev->dev.parent->bus_id);

??? ret = device_add(&pdev->dev);
??? if (ret == 0)
??????? return ret;

failed:
??? while (--i >= 0)
??????? if (pdev->resource[i].flags & (IORESOURCE_MEM|IORESOURCE_IO))
??????????? release_resource(&pdev->resource[i]);
??? return ret;
}
EXPORT_SYMBOL_GPL(platform_device_add);


//常用的platform_device_register,內部調用了platform_device_add,將設備掛在了platform總線上
/**
* platform_device_register - add a platform-level device
* @pdev: platform device we're adding
*/
int platform_device_register(struct platform_device *pdev)
{
??? device_initialize(&pdev->dev);
??? return platform_device_add(pdev);
}
EXPORT_SYMBOL_GPL(platform_device_register);

要用注冊一個platform驅動的步驟:
1,注冊設備platform_device_register
2,注冊驅動platform_driver_register
注冊時候的兩個名字必須一樣,才能match上,才能work,例如:
struct platform_device pxa3xx_device_nand = {
??? .name??????? = "pxa3xx-nand",
??? .id??????? = -1,
??? .dev??????? = {
??????? .dma_mask = &pxa3xx_nand_dma_mask,
??????? .coherent_dma_mask = DMA_BIT_MASK(32),
??? },
??? .resource??? = pxa3xx_resource_nand,
??? .num_resources??? = ARRAY_SIZE(pxa3xx_resource_nand),
};

static struct platform_driver pxa3xx_nand_driver = {
??? .driver = {
??????? .name??? = "pxa3xx-nand",
??? },
??? .probe??????? = pxa3xx_nand_probe,
??? .remove??????? = pxa3xx_nand_remove,
#ifdef CONFIG_PM
??? .suspend??? = pxa3xx_nand_suspend,
??? .resume??????? = pxa3xx_nand_resume,
#endif
};

而且device注冊的時候,可以給driver傳參數

struct device {
??? struct klist??????? klist_children;
??? struct klist_node??? knode_parent;??? /* node in sibling list */
??? struct klist_node??? knode_driver;
??? struct klist_node??? knode_bus;
??? struct device??????? *parent;

??? struct kobject kobj;
??? char??? bus_id[BUS_ID_SIZE];??? /* position on parent bus */
??? struct device_type??? *type;
??? unsigned??????? is_registered:1;
??? unsigned??????? uevent_suppress:1;

??? struct semaphore??? sem;??? /* semaphore to synchronize calls to
???????????????????? * its driver.
???????????????????? */

??? struct bus_type??? *bus;??????? /* type of bus device is on */
??? struct device_driver *driver;??? /* which driver has allocated this
?????????????????????? device */
??? void??????? *driver_data;??? /* data private to the driver */
??? void??????? *platform_data;??? /* Platform specific data, device
?????????????????????? core doesn't touch it */
??? struct dev_pm_info??? power;

#ifdef CONFIG_NUMA
??? int??????? numa_node;??? /* NUMA node this device is close to */
#endif
??? u64??????? *dma_mask;??? /* dma mask (if dma'able device) */
??? u64??????? coherent_dma_mask;/* Like dma_mask, but for
???????????????????????? alloc_coherent mappings as
???????????????????????? not all hardware supports
???????????????????????? 64 bit addresses for consistent
???????????????????????? allocations such descriptors. */

??? struct device_dma_parameters *dma_parms;

??? struct list_head??? dma_pools;??? /* dma pools (if dma'ble) */

??? struct dma_coherent_mem??? *dma_mem; /* internal for coherent mem
???????????????????????? override */
??? /* arch specific additions */
??? struct dev_archdata??? archdata;

??? spinlock_t??????? devres_lock;
??? struct list_head??? devres_head;

??? /* class_device migration path */
??? struct list_head??? node;
??? struct class??????? *class;
??? dev_t??????????? devt;??? /* dev_t, creates the sysfs "dev" */
??? struct attribute_group??? **groups;??? /* optional groups */

??? void??? (*release)(struct device *dev);
};
傳參數都是通過platform_data傳,所以定義為void *
??? void??????? *platform_data;??? /* Platform specific data, device




static struct pxa3xx_nand_platform_data XXX_nand_info = {
??? .parts??????????? = android_256m_v75_partitions,
??? .nr_parts??????? = ARRAY_SIZE(android_256m_v75_partitions),
};

static void __init XXX_init_nand(void)
{
??? pxa3xx_device_nand.dev.platform_data = &XXX_nand_info;
??? platform_device_register(&pxa3xx_device_nand);
}




static int __init pxa3xx_nand_probe(struct platform_device *pdev)
{
??? struct pxa3xx_nand_platform_data *pdata;
??? struct nand_chip *this;
??? struct pxa3xx_nand_info *info;
??? struct resource *res;
??? struct clk *clk = NULL, *smc_clk = NULL;
??? int status = -1;
??? struct mtd_partition *parts;
??? unsigned int data_buf_len;
#ifdef CONFIG_MTD_NAND_PXA3xx_DMA
??? unsigned int buf_len;
#endif
??? int i, ret = 0;
#ifdef CONFIG_MTD_PARTITIONS
??? int err;
#endif

??? pdata = pdev->dev.platform_data;
....
....
....
}

下面解釋一下pxa_register_device函數
??? pxa_set_ohci_info(&XXX_ohci_info);

void __init pxa_set_ohci_info(struct pxaohci_platform_data *info)
{
??? pxa_register_device(&pxa27x_device_ohci, info);
}

void __init pxa_register_device(struct platform_device *dev, void *data)
{
??? int ret;

??? dev->dev.platform_data = data;

??? ret = platform_device_register(dev);
??? if (ret)
??????? dev_err(&dev->dev, "unable to register device: %d\n", ret);
}

其實上,也就是給driver傳參數,通過dev.platform_data。

到這里,platform_device系列函數,基本算通了,系列函數還有一堆設置的函數,和device_register同級別的那些功能函數,用法基本差不多,只不過都將設備掛在了platform總線上。

?

?

platform_device_register向系統注冊設備

platform_driver_register向系統注冊驅動,過程中在系統尋找注冊的設備(根據.name),找到后運行.probe進行初始化。

?

?

***************************************************************

device_register()和platform_device_register()的區別(轉載)??


首先看device和platform_device區別
由struct platform_device {
const char * name; //NOTE:此處設備的命名應和相應驅動程序命名一致
u32 id;????????????//以實現driver binding
struct device dev;
u32 num_resources;
struct resource * resource;
};
可知:platform_device由device派生而來

內核中關于Platform devices的注釋
Platform devices
~~~~~~~~~~~~~~~~
Platform devices are devices that typically appear as autonomous
entities in the system. This includes legacy port-based devices and
host bridges to peripheral buses, and most controllers integrated
into system-on-chip platforms. What they usually have in common
is direct addressing from a CPU bus. Rarely, a platform_device will
be connected through a segment of some other kind of bus; but its
registers will still be directly addressable.

Platform devices are given a name, used in driver binding, and a
list of resources such as addresses and IRQs.
個人理解:Platform devices是相對獨立的設備,擁有各自獨自的資源(addresses and IRQs)

一個Platform devices實例:
static struct platform_device *smdk2410_devices[] __initdata = {
&s3c_device_usb, //片上的各個設備
&s3c_device_lcd, //下面以s3c_device_lcd為例
&s3c_device_wdt,
&s3c_device_i2c,
&s3c_device_iis,
};

/* LCD Controller */
static struct resource s3c_lcd_resource[] = { //LCD的兩個資源
[0] = {
.start = S3C2410_PA_LCD,
.end = S3C2410_PA_LCD + S3C2410_SZ_LCD,
.flags = IORESOURCE_MEM,
},
[1] = {
.start = IRQ_LCD,
.end = IRQ_LCD,
.flags = IORESOURCE_IRQ,
}

};

struct platform_device s3c_device_lcd = {//s3c_device_lcd設備
.name = "s3c2410-lcd",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_lcd_resource),
.resource = s3c_lcd_resource,
.dev = { //device實例
.dma_mask = &s3c_device_lcd_dmamask,
.coherent_dma_mask = 0xffffffffUL
}
};

s3c_device_lcd的resource中硬件地址:

#define S3C2410_LCDREG(x) ((x) + S3C2410_VA_LCD)

/* LCD control registers */
#define S3C2410_LCDCON1 S3C2410_LCDREG(0x00)
#define S3C2410_LCDCON2 S3C2410_LCDREG(0x04)
#define S3C2410_LCDCON3 S3C2410_LCDREG(0x08)
#define S3C2410_LCDCON4 S3C2410_LCDREG(0x0C)
#define S3C2410_LCDCON5 S3C2410_LCDREG(0x10)

#define S3C2410_LCDCON1_CLKVAL(x) ((x) << 8)
#define S3C2410_LCDCON1_MMODE (1<<7)
#define S3C2410_LCDCON1_DSCAN4 (0<<5)
#define S3C2410_LCDCON1_STN4 (1<<5)
#define S3C2410_LCDCON1_STN8 (2<<5)
#define S3C2410_LCDCON1_TFT (3<<5)
--------------------------
#define S3C2410_ADDR(x) (0xF0000000 + (x))

/* LCD controller */
#define S3C2410_VA_LCD S3C2410_ADDR(0x00600000)
#define S3C2410_PA_LCD (0x4D000000)
#define S3C2410_SZ_LCD SZ_1M

再分析device_register()和platform_device_register()的實現代碼:

device_register()------------------------

/**
* device_register - register a device with the system.
* @dev: pointer to the device structure
*
* This happens in two clean steps - initialize the device
* and add it to the system. The two steps can be called
* separately, but this is the easiest and most common.
* I.e. you should only call the two helpers separately if
* have a clearly defined need to use and refcount the device
* before it is added to the hierarchy.
*/

int device_register(struct device *dev)
{
device_initialize(dev); //初始化設備結構
return device_add(dev); //添加設備到設備層
}

platform_device_register()--------------------
/**
* platform_device_register - add a platform-level device
* @pdev: platform device we're adding
*
*/
int platform_device_register(struct platform_device * pdev)
{
device_initialize(&pdev->dev); //初始化設備結構
return platform_device_add(pdev); //添加一個片上的設備到設備層
}
由以上函數可知:device_register()和platform_device_register()都會首先初始化設備
區別在于第二步:其實platform_device_add()包括device_add(),只不過要先注冊resources


platform_device_add()----------------------
/**
* platform_device_add - add a platform device to device hierarchy
* @pdev: platform device we're adding
*
* This is part 2 of platform_device_register(), though may be called
* separately _iff_ pdev was allocated by platform_device_alloc().
*/
int platform_device_add(struct platform_device *pdev)
{
int i, ret = 0;
if (!pdev)
return -EINVAL;
if (!pdev->dev.parent)
pdev->dev.parent = &platform_bus;
pdev->dev.bus = &platform_bus_type;

/*++++++++++++++
The platform_device.dev.bus_id is the canonical name for the devices.
It's built from two components:

* platform_device.name ... which is also used to for driver matching.
* platform_device.id ... the device instance number, or else "-1"
to indicate there's only one.

These are concatenated, so name/id "serial"/0 indicates bus_id "serial.0", and
"serial/3" indicates bus_id "serial.3"; both would use the platform_driver
named "serial". While "my_rtc"/-1 would be bus_id "my_rtc" (no instance id)
and use the platform_driver called "my_rtc".
++++++++++++++*/

if (pdev->id != -1)
snprintf(pdev->dev.bus_id, BUS_ID_SIZE, "%s.%u", pdev->name, pdev->id);
else //"-1" indicate there's only one
strlcpy(pdev->dev.bus_id, pdev->name, BUS_ID_SIZE);
for (i = 0; i < pdev->num_resources; i++) { //遍歷設備資源個數,如LCD的兩個資源:控制器和IRQ
struct resource *p, *r = &pdev->resource[i];
if (r->name == NULL)
r->name = pdev->dev.bus_id;
p = r->parent;
if (!p) { //resources分為兩種IORESOURCE_MEM和IORESOURCE_IO
??????????//CPU對外設IO端口物理地址的編址方式有兩種:I/O映射方式和內存映射方式
if (r->flags & IORESOURCE_MEM)
p = &iomem_resource;
else if (r->flags & IORESOURCE_IO)
p = &ioport_resource;
}

if (p && insert_resource(p, r)) {
printk(KERN_ERR
"%s: failed to claim resource %d/n",
pdev->dev.bus_id, i);
ret = -EBUSY;
goto failed;
}
}
pr_debug("Registering platform device '%s'. Parent at %s/n",
pdev->dev.bus_id, pdev->dev.parent->bus_id);
ret = device_add(&pdev->dev);
if (ret == 0)
return ret;
failed:
while (--i >= 0)
if (pdev->resource[i].flags & (IORESOURCE_MEM|IORESOURCE_IO))
release_resource(&pdev->resource[i]);
return ret;
}

相關參考+++++++++++++++++++++++
device_initialize()------------------
/** </drivers/base/core.c>
* device_initialize - init device structure.
* @dev: device.
*
* This prepares the device for use by other layers,
* including adding it to the device hierarchy.
* It is the first half of device_register(), if called by
* that, though it can also be called separately, so one
* may use @dev's fields (e.g. the refcount).
*/

void device_initialize(struct device *dev)
{
kobj_set_kset_s(dev, devices_subsys);
kobject_init(&dev->kobj);
klist_init(&dev->klist_children, klist_children_get,
klist_children_put);
INIT_LIST_HEAD(&dev->dma_pools);
INIT_LIST_HEAD(&dev->node);
init_MUTEX(&dev->sem);
spin_lock_init(&dev->devres_lock);
INIT_LIST_HEAD(&dev->devres_head);
device_init_wakeup(dev, 0);
set_dev_node(dev, -1);
}
device_add(struct device *dev)-------------
/**
* device_add - add device to device hierarchy.
* @dev: device.
*
* This is part 2 of device_register(), though may be called
* separately _iff_ device_initialize() has been called separately.
*
* This adds it to the kobject hierarchy via kobject_add(), adds it
* to the global and sibling lists for the device, then
* adds it to the other relevant subsystems of the driver model.
*/
結構體resource----------------------
/* < /include/linux/ioport.h>
* Resources are tree-like, allowing
* nesting etc..
*/
struct resource {
resource_size_t start;
resource_size_t end;
const char *name;
unsigned long flags;
struct resource *parent, *sibling, *child;
};
---------------------------

原文地址:http://blog.chinaunix.net/u1/58968/showart_467998.html ,

在8250.c(driver/serial/8250.c)的初始化函數serial8250_init()中,給出了一個很簡單的例子

static struct platform_device *serial8250_isa_devs;

......

//create a platform_device

serial8250_isa_devs = platform_device_alloc("serial8250",PLAT8250_DEV_LEGACY);??????????????

??platform_device_add(serial8250_isa_devs);?? //add the platform_device to system

platform_driver_register(&serial8250_isa_driver);//then register the platform_driver????????

還有另外一個比較類似的比較,就是driver_register和platform_driver_register的比較
????platform_driver_register(&xx_driver) 會向系統注冊xx_driver這個驅動程序,這個函數會根據 xx_driver中的.name內容,搜索系統注冊的device中有沒有這個platform_device,如果有,就會執行 platform_driver(也就是xx_driver的類型)中的.probe函數。

?

????? 對只需要初始化運行一次的函數都加上__init屬性,__init 宏告訴編譯器如果這個模塊被編譯到內核則把這個函數放到(.init.text)段,module_exit的參數卸載時同__init類似,如果驅動被編譯進內核,則__exit宏會忽略清理函數,因為編譯進內核的模塊不需要做清理工作,顯然__init和__exit對動態加載的模塊是無效的,只支持完全編譯進內核。

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/253717.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/253717.shtml
英文地址,請注明出處:http://en.pswp.cn/news/253717.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

示例解讀 Python 2 和 Python 3 之間的主要差異

開發四年只會寫業務代碼&#xff0c;分布式高并發都不會還做程序員&#xff1f; 每門編程語言在發布更新之后&#xff0c;主要版本之間都會發生很大的變化。 在本文中&#xff0c;Vinodh Kumar 通過示例解釋了 Python 2 和 Python 3 之間的一些重大差異&#xff0c;以幫助說明…

數字后端——布局

由于I / O單元和模塊的布放已經在布圖規劃時完成&#xff0c;因此布局的剩余任務主要是對標準單元的布局。布局方案在布圖規劃時就已經做了決定&#xff0c;要么選擇展平式布局&#xff0c;要么就是層次化布局。 一、布局目標 布局的目標也即布局內容實施之后所要達到的預期值…

python基礎 函數 (四)

一 函數基本 def func1():print("hello world")return 1, "hello", ("wo", "ai"), ["ni", "da"], {"you": "xi"} # return 可以返回任意# 結果&#xff1a; (1, hello, (wo, ai), [ni, da…

c#注釋

c#的注釋分為&#xff1a;這里不能不說一下什么是注釋。 注釋本身不會執行&#xff0c;只是說明性文字&#xff0c;只供程序員閱讀。 注釋又分為&#xff1a;單行注釋&#xff0c;多行注釋&#xff0c;文檔注釋。 單行注釋&#xff1a;//開始 多行注釋&#xff1a;/*開始&#…

嵌入式linux字符設備驅動

1. 我們需要先調用register_chrdev_region()或 alloc_chrdev_region()來向系統申請設備號int register_chrdev_region( dev_t first, unsigned int count, char *name ); //函數通過已知的設備號first來注冊字符設備區域。 int alloc_chrdev_region( dev_t *dev, unsigned int…

數字后端——時鐘樹綜合

在數字集成電路設計中&#xff0c;時鐘信號是數據傳輸的基準&#xff0c;它對于同步數字系統的功能、性能和穩定性起決定性作用&#xff0c;所以時鐘信號的特性及其分配網絡尤被人們關注。時鐘信號通常是整個芯片中有最大扇出、通過最長距離、以最高速度運行的信號。時鐘信號必…

52次課(mysql用戶管理、常用sql語句、 mysql數據庫備份恢復)

MySQL創建用戶以及授權 默認用戶是root用戶&#xff0c;不可能所有人員都用root用戶&#xff0c;創建用戶防止誤刪除&#xff0c;因為mysql里邊有多個庫每個庫里有很多表&#xff0c;所以需要給單獨的用戶做一些授權我只需要它對某一個數據庫有權限&#xff0c;或者說對某個數據…

線程池的種類,區別和使用場景

newCachedThreadPool&#xff1a; 底層&#xff1a;返回ThreadPoolExecutor實例&#xff0c;corePoolSize為0&#xff1b;maximumPoolSize為Integer.MAX_VALUE&#xff1b;keepAliveTime為60L&#xff1b;unit為TimeUnit.SECONDS&#xff1b;workQueue為SynchronousQueue(同步隊…

20145225 《信息安全系統設計基礎》第14周學習總結

第九章 虛擬存儲器 虛擬存儲器是計算機系統最重要的概念之一&#xff0c;它是對主存的一個抽象 三個重要能力&#xff1a; 它將主存看成是一個存儲在磁盤上的地址空間的高速緩存&#xff0c;在主存中只保存活動區域&#xff0c;并根據需要在磁盤和主存之間來回傳送數據&#xf…

數字后端——布線

布線是繼布局和時鐘樹綜合之后的重要物理實施任務&#xff0c;其內容是將分布在芯片核內的模塊、標準單元和輸入輸出接口單元( I /O pad&#xff09;按邏輯關系進行互連&#xff0c;其要求是百分之百地完成它們之間的所有邏輯信號的互連&#xff0c;并為滿足各種約束條件進行優…

動態加載和靜態加載及其編譯步驟

在類unix操作系統中&#xff0c;驅動加載方式一般分為&#xff1a;動態加載和靜態加載&#xff0c;下面分別對其詳細論述。 一、動態加載 動態加載是將驅動模塊加載到內核中&#xff0c;而不能放入/lib/modules/下。 在2.4內核中&#xff0c;加載驅動命令為&#xff1a;ins…

streamsets 集成 minio s3測試

具體streamsets crate 集成可以參考 streamsets crate 以下文檔只關注minio 集成的配置 minio 服務 搭建 具體搭建參考&#xff1a; https://www.cnblogs.com/rongfengliang/p/9197315.html 創建bucket &#xff08;crate 集成使用&#xff09; 測試的csv 文件從https://www.s…

sqlite性能優化

1、數據庫性能上 1.1 批量事務插入&#xff0c;提升數據插入的性能 由于sqlite默認每次插入都是事務&#xff0c;需要對文件進行讀寫&#xff0c;那么減少事務次數就能簡書磁盤讀寫次數從而獲得性能提升。 1.2 單條sql優于多條sql 實測發現&#xff0c;對于幾十條sql插入當你替…

【codecombat】 試玩全攻略 第十四關 已知敵人

第十四關 已知敵人 在這一關里&#xff0c;我們的英雄獲得了一副可以看見敵人的眼鏡&#xff0c;所以他很強勢的學會了“發現敵人”的技能。 hero.findNearestEnemy()命令&#xff0c;單詞多了&#xff0c;首字母都要大寫了&#xff0c;不然分不出來。玩過wow的小伙伴用過 宏命…

數字后端——信號完整性分析

隨著光刻和集成電路制造工藝的不斷進步&#xff0c;以及芯片的特征尺寸從深亞微米到納米的迅速采用&#xff0c;人們一方面因為芯片的功能極大提高而受益&#xff0c;另一方面&#xff0c;當邏輯門的溝道長度減小時&#xff0c;門的開關時間會減小&#xff0c;這意味著輸出驅動…

新浪前端面試

1、什么是Html語義化&#xff1f; 語義化 div > section&#xff0c;div > nav(語言自己能解釋)&#xff0c; input/(關閉符號) br/相對于樣式標記&#xff0c;如 i&#xff08;樣式&#xff09;/ em&#xff08;語義&#xff09;&#xff1b;b&#xff08;樣式&#xff…

poj3278 【BFS】

Catch That CowTime Limit: 2000MS Memory Limit: 65536KTotal Submissions: 97240 Accepted: 30519Description Farmer John has been informed of the location of a fugitive cow and wants to catch her immediately. He starts at a point N (0 ≤ N ≤ 100,000) on a num…

表單高級

● 表單高級 ○ 表單字段集<fieldset></fieldset> ■ 功能&#xff1a;相當于一個方框&#xff0c;在字段集中可以包含文本和其他元素。該元素用于對表單中的元素進行分組并在文檔中區別標出文本。fieldset元素可以嵌套&#xff0c;在其內部可以在設置多個fieldset…

CMOS圖像傳感器——TDI CIS

一、面陣與線陣圖像傳感器 人們在日常生活中見到的相機大多基于普通的面陣圖像傳感器,這種相機多用來拍攝靜止的物體。即使用它們來拍攝運動的物體,也僅僅是縮短了相鄰兩次拍攝的時間間隔,無需對所拍攝圖像進行額外操作,對物體的運動方向和速度也沒有限定條件。 除此之外,…

gpio_request 原形代碼

其原型為 int gpio_request(unsigned gpio, const char *label) 先說說其參數&#xff0c;gpio則為你要申請的哪一個管腳&#xff0c;label則是為其取一個名字。其具體實現如下&#xff1a; [cpp] view plaincopyprint?int gpio_request(unsigned gpio, const char *label) …