日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

添加内核驱动模块(3)(mydriver.c+ Konfig+Makefile )

發(fā)布時(shí)間:2024/8/1 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 添加内核驱动模块(3)(mydriver.c+ Konfig+Makefile ) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

之前在注冊SPIDRIVER時(shí),我們注冊了SPI的probe函數(shù)和remove函數(shù)。
我們來編寫這兩個(gè)函數(shù)。

static int gpio_pmodoled_spi_probe(struct spi_device *spi) {int status = 0;struct gpio_pmodoled_device *gpio_pmodoled_dev;/* We rely on full duplex transfers, mostly to reduce* per transfer overheads (by making few transfers).*/if (spi->master->flags & SPI_MASTER_HALF_DUPLEX) {status = -EINVAL;dev_err(&spi->dev, "SPI settings incorrect: %d\n", status);goto spi_err;}/* We must use SPI_MODE_0 */spi->mode = SPI_MODE_0;spi->bits_per_word = 8;status = spi_setup(spi);if(status < 0) {dev_err(&spi->dev, "needs SPI mode %02x, %d KHz; %d\n",spi->mode, spi->max_speed_hz / 1000,status);goto spi_err;}/* Get gpio_pmodoled_device structure */gpio_pmodoled_dev = (struct gpio_pmodoled_device*) spi->dev.platform_data;if(gpio_pmodoled_dev == NULL) {dev_err(&spi->dev, "Cannot get gpio_pmodoled_device.\n");status = -EINVAL;goto spi_platform_data_err;}printk(KERN_INFO SPI_DRIVER_NAME " [%s] SPI Probing\n", gpio_pmodoled_dev->name);#ifdef CONFIG_PMODS_DEBUGprintk(KERN_INFO SPI_DRIVER_NAME " [%s] spi_probe: setup char device\n", gpio_pmodoled_dev->name); #endif/* Setup char driver */status = gpio_pmodoled_setup_cdev(gpio_pmodoled_dev, &(gpio_pmodoled_dev->dev_id), spi); if (status) {dev_err(&spi->dev, "spi_probe: Error adding %s device: %d\n", SPI_DRIVER_NAME, status);goto cdev_add_err;}/* Initialize Mutex */mutex_init(&gpio_pmodoled_dev->mutex);/*** It is important to the OLED's longevity that the lines that * control it's power are carefully controlled. This is a good* time to ensure that the device is ot turned on until it is* instructed to do so.*/ #ifdef CONFIG_PMODS_DEBUGprintk(KERN_INFO SPI_DRIVER_NAME " [%s] spi_probe: initialize device\n", gpio_pmodoled_dev->name); #endifstatus = gpio_pmodoled_init_gpio(gpio_pmodoled_dev);if(status) {dev_err(&spi->dev, "spi_probe: Error initializing GPIO\n");goto oled_init_error;}gpio_pmodoled_disp_init(gpio_pmodoled_dev);memset(gpio_pmodoled_dev->disp_buf, 0x00, DISPLAY_BUF_SZ);status = screen_buf_to_display(gpio_pmodoled_dev->disp_buf, gpio_pmodoled_dev);if(status) {dev_err(&spi->dev, "spi_probe: Error sending initial Display String\n");goto oled_init_error;}return status;oled_init_error:if (&gpio_pmodoled_dev->cdev)cdev_del(&gpio_pmodoled_dev->cdev); cdev_add_err: spi_platform_data_err: spi_err:return(status); }

當(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)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。