添加内核驱动模块(4)(mydriver.c+ Konfig+Makefile )
之前在注冊SPIDRIVER時,probe函數(shù)中,使用了
gpio_pmodoled_setup_cdev()
gpio_pmodoled_init_gpio()
gpio_pmodoled_disp_init()
我們現(xiàn)在來編寫這些函數(shù)。
先編寫gpio_pmodoled_setup_cdev()。
static int gpio_pmodoled_setup_cdev(struct gpio_pmodoled_device *dev, dev_t *dev_id, struct spi_device *spi) {int status = 0;struct device *device;cdev_init(&dev->cdev, &gpio_pmodoled_cdev_fops);dev->cdev.owner = THIS_MODULE;dev->cdev.ops = &gpio_pmodoled_cdev_fops;dev->spi = spi;*dev_id = MKDEV(MAJOR(gpio_pmodoled_dev_id), cur_minor++);status = cdev_add(&dev->cdev, *dev_id, 1);if(status < 0) {return status;}/* Add Device node in system */device = device_create(gpio_pmodoled_class, NULL,*dev_id, NULL,"%s", dev->name);if(IS_ERR(device)) {status = PTR_ERR(device);dev_err(&spi->dev, "failed to create device node %s, err %d\n",dev->name, status);cdev_del(&dev->cdev);}return status; }caller調(diào)用函數(shù)時,會傳遞一些參數(shù)。
dev是一個struct gpio_pmodoled_device型的指針,它執(zhí)行PMOD設(shè)備描述塊。
dev_id是一個dev_t型的指針,它指向一個DEVID描述塊。
spi是一個struct spi_device型的指針,它指向一個SPIDEVICE設(shè)備描述塊。
首先初始化CDEV描述塊。
PMOD描述塊中,內(nèi)含一個CDEV描述塊。我們要使用的,就是這個描述塊。
另外,要給CDEV關(guān)聯(lián)一個fops。
我么定義了一個全局變量gpio_pmodoled_cdev_fops,它是一個struct file_operations型的數(shù)據(jù)變量,不是指針。
cdev_init()負責對CDEV描述塊進行初始化,并注冊到內(nèi)核中。
填充CDEV描述塊,
cdev.owner,cdev.ops。
填充PMOD描述塊,
spi。
生成DEV_ID。
MAJOR()從dev_id中抽取MAJOR代碼。
MKDEV()負責將major代碼和minor代碼組合成dev_id。
注冊CDEV。
cdev_add()負責將CDEV描述塊和dev_id關(guān)聯(lián)起來,并注冊到內(nèi)核中。返回狀態(tài)值。
判斷返回的狀態(tài),
如果非法,則直接返回return.
如果合法,則繼續(xù)執(zhí)行。
在系統(tǒng)中生成device_node。
device_create()負責將DEV_ID所指向的設(shè)備,和一個CLASS描述塊關(guān)聯(lián)起來,注冊到內(nèi)核中。返回一個struct device型的指針,指向一個DEVICE描述塊。
將返回的指針賦值給device,這是一個struct device型的指針,指向DEVICE描述塊,后續(xù)用device作為句柄。
判斷device的指針合法性。
如果非法,則設(shè)置status,后面返回時需要使用。然后打印錯誤信息,然后從系統(tǒng)中注銷CDEV。
如果合法,則繼續(xù)執(zhí)行。
至此,全部完成。直接return status。
再來編寫gpio_pmodoled_init_gpio()
static int gpio_pmodoled_init_gpio(struct gpio_pmodoled_device *dev) {struct gpio gpio_pmodoled_ctrl[] = {{dev->iVBAT, GPIOF_OUT_INIT_HIGH, "OLED VBat"},{dev->iVDD, GPIOF_OUT_INIT_HIGH, "OLED VDD"},{dev->iRES, GPIOF_OUT_INIT_HIGH, "OLED_RESET"},{dev->iDC, GPIOF_OUT_INIT_HIGH, "OLED_D/C"},};int status;int i;for (i = 0; i < ARRAY_SIZE(gpio_pmodoled_ctrl); i++) {status = gpio_is_valid(gpio_pmodoled_ctrl[i].gpio);if(!status) {dev_err(&dev->spi->dev, "!! gpio_is_valid for GPIO %d, %s FAILED!, status: %d\n",gpio_pmodoled_ctrl[i].gpio, gpio_pmodoled_ctrl[i].label, status);goto gpio_invalid;}}status = gpio_request_array(gpio_pmodoled_ctrl, ARRAY_SIZE(gpio_pmodoled_ctrl));if(status) {dev_err(&dev->spi->dev, "!! gpio_request_array FAILED!\n");dev_err(&dev->spi->dev, " status is: %d\n", status);gpio_free_array(gpio_pmodoled_ctrl, 4);goto gpio_invalid;}gpio_invalid:return status; }caller調(diào)用該函數(shù)時,會傳遞一些參數(shù)。
dev是一個struct gpio_pmodoled_device型的指針,指向PMOD設(shè)備描述塊。
首先定義一個臨時數(shù)組gpio_pmodoled_ctrl,它是一個struct gpio型變量的數(shù)組。
判斷數(shù)組中的GPIO描述塊,所定義的GPIO的合法性。
采用循環(huán)結(jié)構(gòu),逐個進行檢查。
gpio_is_valid()負責檢查GPIO描述塊中給出的GPIO編號,是否有效。返回狀態(tài)值。
判斷返回的狀態(tài)是否合法。
如果非法,打印錯誤信息。跳出循環(huán)體,并進入退出處理棧gpio_invalid。
如果合法,則繼續(xù)執(zhí)行。
循環(huán)結(jié)束后,向內(nèi)核注冊GPIO。
gpio_request_array()負責向內(nèi)核中注冊GPIO,將GPIO_ARRAY中的GPIO描述塊,逐個注冊到系統(tǒng)中。返回狀態(tài)值。
判斷返回的狀態(tài)值,
如果非法,打印錯誤信息,并進入退出處理棧gpio_invalid。
如果合法,則繼續(xù)執(zhí)行。
至此,全部完成。直接return status。
再來編寫gpio_pmodoled_disp_init()
static void gpio_pmodoled_disp_init(struct gpio_pmodoled_device *dev) {int status;uint8_t wr_buf[20];// We are going to be sending commands// so clear the data/cmd bitgpio_set_value(dev->iDC, OLED_CONTROLLER_CMD);// Start by turning VDD on and wait for the power to come upgpio_set_value(dev->iVDD, 0);msleep(1);// Display off Commandwr_buf[0] = OLED_DISPLAY_OFF;status = spi_write(dev->spi, wr_buf, 1);/* Bring Reset Low and then High */gpio_set_value(dev->iRES, 1);msleep(1);gpio_set_value(dev->iRES, 0);msleep(1);gpio_set_value(dev->iRES, 1);// Send the set charge pump and set precharge period commandswr_buf[0] = 0x8D;wr_buf[1] = 0x14;wr_buf[2] = OLED_SET_PRECHARGE_PERIOD;wr_buf[3] = 0xF1;status = spi_write(dev->spi, wr_buf, 4);/* Turn on VCC and wait 100ms */gpio_set_value(dev->iVBAT, 0);msleep(100);/* Set Display COntrast */wr_buf[0] = OLED_CONTRAST_CTRL;wr_buf[1] = 0x0F;/* Invert the display */wr_buf[2] = OLED_SET_SEGMENT_REMAP; // Remap Columnswr_buf[3] = OLED_SET_COM_DIR; // Remap Rows// Select sequential COM configurationwr_buf[4] = OLED_SET_COM_PINS;wr_buf[5] = 0x00;wr_buf[6] = 0xC0;wr_buf[7] = 0x20;wr_buf[8] = 0x00;// Turn on Displaywr_buf[9] = OLED_DISPLAY_ON;status = spi_write(dev->spi, wr_buf, 10); }caller調(diào)用該函數(shù)時,會傳遞一些參數(shù)。
dev是一個struct gpio_pmodoled_device型的指針,它指向一個PMOD描述塊。
首先設(shè)置GPIO,把數(shù)據(jù)刷到硬件上。
gpio_set_value()負責把數(shù)據(jù)設(shè)置到指定的GPIO編號的硬件引腳上。
msleep(),睡眠等待。
然后配置wr_buf,利用SPIDEVICE,生成SPI寫時序,把數(shù)據(jù)刷到硬件上。
spi_write()負責將wr_buf中的數(shù)據(jù),逐個生成SPI寫時序,刷到硬件上。
設(shè)置GPIO,生成波形時序。
gpio_set_value()和msleep()配合,可以生成需要的波形。
然后配置wr_buf,利用SPIDEVICE,生成SPI寫時序,把數(shù)據(jù)刷到硬件上。
spi_write()負責將wr_buf中的數(shù)據(jù),逐個生成SPI寫時序,刷到硬件上。
設(shè)置GPIO,生成波形時序。
gpio_set_value()和msleep()配合,可以生成需要的波形。
然后配置wr_buf,利用SPIDEVICE,生成SPI寫時序,把數(shù)據(jù)刷到硬件上。
spi_write()負責將wr_buf中的數(shù)據(jù),逐個生成SPI寫時序,刷到硬件上。
總結(jié)
以上是生活随笔為你收集整理的添加内核驱动模块(4)(mydriver.c+ Konfig+Makefile )的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 批量下载ts文件
- 下一篇: 1.5多媒体技术的应用领域