添加内核驱动模块(3)(mydriver.c+ Konfig+Makefile )
之前在注冊SPIDRIVER時(shí),我們注冊了SPI的probe函數(shù)和remove函數(shù)。
我們來編寫這兩個(gè)函數(shù)。
當(dāng)syscall調(diào)用該函數(shù)時(shí),傳遞一個(gè)參數(shù),它是一個(gè)struct spi_device型的指針spi。
定義一系列指針,后續(xù)作為句柄使用。
判斷SPIMASTER的模式。
spi->master->flags & SPI_MASTER_HALF_DUPLEX
如果是SPI_MASTER_HALF_DUPLEX模式,那么不能使用,打印錯(cuò)誤信息,然后進(jìn)入退出處理?xiàng)pi_err。
如果不是SPI_MASTER_HALF_DUPLEX模式,那么可以使用,繼續(xù)執(zhí)行。
填充SPIDEVICE描述塊的成員。
mode,bits_per_word。
設(shè)置SPIDEVICE的配置信息。
spi_setup()負(fù)責(zé)對一個(gè)SPIDEVICE描述塊進(jìn)行設(shè)置,并返回狀態(tài)值。
判斷返回的狀態(tài)值。
如果非法,則打印錯(cuò)誤信息,并進(jìn)入退出處理?xiàng)pi_err
如果合法,則繼續(xù)執(zhí)行。
利用SPIDEVICE扎到對應(yīng)的PMOD設(shè)備描述塊。
將spi->dev.platform_data賦值給gpio_pmodoled_dev,它是一個(gè)struct gpio_pmodoled_device型的指針。關(guān)聯(lián)到PMOD的設(shè)備資源后,后續(xù)可以用gpio_pmodoled_dev作為句柄。
判斷gpio_pmodoled_dev指針的合法性。
如果為NULL,則非法。打印錯(cuò)誤信息,然后修改status,后面返回值需要使用status。然后進(jìn)入退出處理?xiàng)pi_platform_data_err。
如果不為NULL,則合法。那么繼續(xù)執(zhí)行。
配置CDEV設(shè)備資源。
gpio_pmodoled_setup_cdev()負(fù)責(zé)配置PMOD中內(nèi)含的CDEV設(shè)備資源,并關(guān)聯(lián)到SPIDEVICE上。返回狀態(tài)值。
判斷返回的狀態(tài)值。
如果非法,則打印錯(cuò)誤信息,并進(jìn)入退出處理?xiàng)dev_add_err。
如果合法,則繼續(xù)執(zhí)行。
初始化PMOD設(shè)備資源中的mutex系統(tǒng)資源。
mutex_init()負(fù)責(zé)初始化一個(gè)mutex描述塊。
初始化PMOD設(shè)備資源中用到的GPIO系統(tǒng)資源。
gpio_pmodoled_init_gpio()負(fù)責(zé)初始化PMOD設(shè)備描述塊中使用的GPIO系統(tǒng)資源。返回狀態(tài)值。
判斷返回的狀態(tài)值的合法性。
如果非法,則打印錯(cuò)誤信息,并進(jìn)入退出處理?xiàng)led_init_error。
如果合法,則繼續(xù)執(zhí)行。
初始化PMOD設(shè)備資源中用到的顯示緩沖資源。
gpio_pmodoled_disp_init()負(fù)責(zé)初始化PMOD設(shè)備描述塊中使用的顯示資源。
初始化緩沖區(qū)。
memset()負(fù)責(zé)將緩沖區(qū)清零。
把初始化好的顯示緩沖區(qū)刷到硬件上。
screen_buf_to_display()負(fù)責(zé)把緩沖區(qū)flush到硬件上。返回狀態(tài)值。
判斷返回的狀態(tài)值的合法性。
如果非法,則打印錯(cuò)誤信息,并進(jìn)入退出處理?xiàng)led_init_error。
如果合法,則繼續(xù)執(zhí)行。
至此,全部執(zhí)行完。正常退出,不需要進(jìn)入退出處理?xiàng)!K灾苯觬eturn。
再編寫remove函數(shù)。
static int __devexit gpio_pmodoled_spi_remove(struct spi_device *spi) {int status;struct gpio_pmodoled_device *dev;uint8_t wr_buf[10];dev = (struct gpio_pmodoled_device*) spi->dev.platform_data;if(dev == NULL) {dev_err(&spi->dev, "spi_remove: Error fetch gpio_pmodoled_device struct\n");return -EINVAL; }#ifdef CONFIG_PMODS_DEBUGprintk(KERN_INFO SPI_DRIVER_NAME " [%s] spi_remove: Clearing Display\n", dev->name); #endif /* Clear Display */memset(dev->disp_buf, 0, DISPLAY_BUF_SZ);status = screen_buf_to_display(dev->disp_buf, dev);/* Turn off display */wr_buf[0] = OLED_DISPLAY_OFF;status = spi_write(spi, wr_buf, 1);if(status) {dev_err(&spi->dev, "oled_spi_remove: Error writing to SPI device\n");}/* Turn off VCC (VBAT) */gpio_set_value(dev->iVBAT, 1);msleep(100);/* TUrn off VDD Power */gpio_set_value(dev->iVDD, 1); #ifdef CONFIG_PMODS_DEBUGprintk(KERN_INFO SPI_DRIVER_NAME " [%s] spi_remove: Free GPIOs\n", dev->name); #endif { 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"},};gpio_free_array(gpio_pmodoled_ctrl, 4); }if(&dev->cdev) { #ifdef CONFIG_PMODS_DEBUGprintk(KERN_INFO SPI_DRIVER_NAME " [%s] spi_remove: Destroy Char Device\n", dev->name); #endif device_destroy(gpio_pmodoled_class, dev->dev_id);cdev_del(&dev->cdev);}cur_minor--;printk(KERN_INFO SPI_DRIVER_NAME " [%s] spi_remove: Device Removed\n", dev->name);return status; }當(dāng)syscall調(diào)用remove函數(shù)時(shí),會(huì)傳遞一個(gè)參數(shù),它是一個(gè)struct spi_device型的指針。
首先定義一系列指針,后續(xù)作為句柄使用。
從SPIDEVICE設(shè)備描述塊中,找到PMOD的描述塊。
dev = (struct gpio_pmodoled_device*) spi->dev.platform_data;
將 dev.platform_data賦值給dev,它是一個(gè)struct gpio_pmodoled_device型的指針。我們用dev指向了PMOD的描述塊,后續(xù)用dev作為句柄。
判斷dev的指針合法性。
如果為NULL,則非法。打印錯(cuò)誤信息,并直接return.
如果不為NULL,則合法。繼續(xù)執(zhí)行。
初始化顯示緩沖區(qū),memset()完成。
將顯示緩沖區(qū)的內(nèi)容flush到硬件上。
screen_buf_to_display()負(fù)責(zé)將內(nèi)容flush到硬件上。
配置wr_buf,然后用SPI發(fā)送緩沖區(qū)字符。
spi_write()負(fù)責(zé)寫操作,它利用一個(gè)SPIDEVICE設(shè)備資源實(shí)現(xiàn)寫操作時(shí)序。返回狀態(tài)值。
判斷返回的狀態(tài)值。
如果非法,則打印錯(cuò)誤信息。由于不是致命錯(cuò)誤。所以打印錯(cuò)誤信息后,并不進(jìn)入退出處理?xiàng)!?br /> 如果合法,則繼續(xù)執(zhí)行。
設(shè)置GPIO。
gpio_set_value()負(fù)責(zé)將一個(gè)在系統(tǒng)中注冊的合法GPIO編號(hào),設(shè)置為配置值。
msleep(),睡眠等待。
定義一個(gè)臨時(shí)數(shù)組gpio_pmodoled_ctrl,它是一個(gè)struct gpio型的數(shù)組。
同是設(shè)置多個(gè)GPIO的狀態(tài)。
gpio_free_array()負(fù)責(zé)將一個(gè)GPIO_ARRAY中GPIO系統(tǒng)資源,同時(shí)釋放掉。
判斷PMOD的CDEV的指針合法性。
如果不為NULL,說明CDEV仍占有內(nèi)核資源,那么釋放掉CDEV的系統(tǒng)資源。
device_destroy()負(fù)責(zé)注銷CLASS描述塊。它根據(jù)dev_id注銷CDEV關(guān)聯(lián)的CLASS描述塊。
cdev_del()負(fù)責(zé)注銷CDEV設(shè)備資源。它根據(jù)傳入的CDEV的描述塊,在設(shè)備中進(jìn)行匹配查找,然后注銷掉系統(tǒng)資源,并取消內(nèi)核和CDEV描述塊之間的關(guān)聯(lián)。
我們定義了靜態(tài)變量cur_minor。它用來記錄當(dāng)前系統(tǒng)中存在的CDEV設(shè)備數(shù)量。
修改cur_minor。
cur_minor–;
至此,全部完成。直接return status.
總結(jié)
以上是生活随笔為你收集整理的添加内核驱动模块(3)(mydriver.c+ Konfig+Makefile )的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 费曼:“只要我不能创造的,我就还不理解”
- 下一篇: 数模算法:排队论模型