**
拿到乙個裝置驅動,首先要看的是裝置初始化函式。
static int __init mcp251x_init(void)
return spi_register_driver(&mcp251x_driver);
} class_create()用於自動建立裝置節點,我們可以暫時不看,有興趣的可以看看linux原始碼。alloc_chrdev_region()自動為driver_name分配裝置號。在這裡,我們真正關心的是spi_register_driver()函式和mcp251x_driver結構體的內容。
我們先看spi_register_driver()的內容。
/**
* spi_register_driver - register a spi driver
* @sdrv: the driver to register
* context: can sleep
*/
int spi_register_driver(struct spi_driver *sdrv)
spi_register_driver()完成了驅動在匯流排的掛載以及spi驅動函式probe, remove, shutdown的賦值。那mcp251x_driver是什麼樣的結構體,裡面又儲存了什麼內容呢?
static struct spi_driver mcp251x_driver = ,
.probe = mcp251x_probe,
.remove = __devexit_p(mcp251x_remove),
#ifdef config_pm
.suspend = mcp251x_suspend,
.resume = mcp251x_resume,
#endif
};
mcp251x_driver是結構體spi_driver的例項,在mcp251x_driver裡面完成了mcp251x驅動函式probe, remove, suspend, resume的賦值。
在進入mcp251x的驅動函式之前,我們還是先看看mcp251x的結構吧!
struct mcp251x
; 其中的很多結構體,我們暫時不管。下面開始進入正題。
static int __devinit mcp251x_probe(struct spi_device *spi)
/* 將mcp251x的裝置資訊儲存到spi的裝置結構體中 */
dev_set_drvdata(&spi->dev, chip);
/* mcp251x結構體初始化 */
chip->txbin = chip->txbout = 0;
chip->rxbin = chip->rxbout = 0;
chip->count = 0;
chip->spi = spi;
init_mutex(&chip->lock);
init_mutex(&chip->txblock);
init_mutex(&chip->rxblock);
init_waitqueue_head(&chip->wq);
#if (linux_version_code >= kernel_version(2,6,20))
init_work(&chip->irq_work, mcp251x_irq_handler);
#else
init_work(&chip->irq_work, mcp251x_irq_handler, spi);
#endif
/* 為spi的buf分配空間 */
chip->spi_transfer_buf = kmalloc(spi_transfer_buf_len, gfp_kernel);
if (!chip->spi_transfer_buf)
/* 輸入模式,不使用內部上拉電阻 */
at91_set_gpio_input(spi->irq, 0);
/* 繫結輸入函式mcp251x_irq,傳遞引數spi */
/* mcp251x_irq函式我們等下再看,先放一放 */
ret = request_irq(spi->irq, mcp251x_irq, irqf_sample_random, driver_name, spi);
if (ret < 0)
if (can_minor > can_dev_max)
goto error_register;
if (can_major)
else
if (ret < 0)
/* 字元裝置的初始化以及新增到核心 */
cdev_init(&chip->cdev, &mcp251x_fops);
chip->cdev.owner = this_module;
ret = cdev_add(&chip->cdev, devid, 1);
if (ret < 0)
dev_info(&spi->dev, "device register at dev(%d:%d)\n", major(devid), minor(devid));
/* 自動建立裝置檔案 */
chip->class_dev = device_create(can_class, null,
mkdev(major(devid), can_minor), &spi->dev, "can%d", can_minor);
if (is_err(chip->class_dev))
/* mcp251x初始化設定 */
mcp251x_hw_init(spi);
mcp251x_set_bit_rate(spi, 125000); /* a reasonable default */
mcp251x_hw_sleep(spi);
return 0;
error_class_reg:
cdev_del(&chip->cdev);
error_devadd:
unregister_chrdev_region(devid, 0);
error_register:
free_irq(spi->irq, spi);
error_irq:
kfree(chip->spi_transfer_buf);
error_buf:
kfree(chip);
error_alloc:
return ret;
裝置驅動例項 字元裝置驅動
在整個linux裝置驅動學習中,字元裝置驅動較為基礎。通過對它的學習,對裝置驅動進一步加深了解 cdev 結構體struct cdev 講下比較重要的成員變數 dev t dev 定義了32位的裝置號,其中12位是主裝置號,20位是從裝置號。獲取主裝置號 major dev t dev 獲取從裝置號...
驅動 linux裝置驅動 字元裝置驅動開發
preface 前面對linux裝置驅動的相應知識點進行了總結,現在進入實踐階段!linux 裝置驅動入門篇 linux 裝置驅動掃盲篇 fedora下的字元裝置驅動開發 開發乙個基本的字元裝置驅動 在linux核心驅動中,字元裝置是最基本的裝置驅動。字元裝置包括了裝置最基本的操作,如開啟裝置 關閉...
Linux裝置驅動之《字元裝置驅動》
linux裝置中最大的特點就是裝置操作猶如檔案操作一般,在應用層看來,硬體裝置只是乙個裝置檔案。應用程式可以像操作檔案一樣對硬體裝置進行操作,如open close read write 等。下面是乙個字元裝置驅動程式的簡單實現test.c 模組分析 1.初始化裝置驅動的結構體 struct fil...