分类:Linux驱动
下载:0
浏览:1627
时间:2018-09-07
Writing an ACPI driver Using Gpio as SCI to Nofity Application under LinuxSeptember 6, 2018This article was contributed by jason_tThe Advanced Configuration and Power Interface specification (ACPI) was introduced to replace the myriad of differing protocols for providing configuration data to the operating system. It additionally provided a new power control specification to replace APM, moving policy decisions out of the hard-coded BIOS and into the operating system. Since then it's had a number of extensions implementing all kinds of functionality, variously specified and unspecified. Hardware vendors have seized upon this to implement their own custom "value add" interfaces, taking advantage of the existing specified functionality while adding their own non-standard extensions.In this article we'll be looking at writing a driver to manage a user defined virtual asl device on x86 pc. According to the ACPI specification, the user defined virtual devices can be 7 characters like NSC1100, SMCF030, In this example we use TTS7205 as example:Scope(\_SB.PCI0.LPCB){ Device(TTST) { Name(_HID, EISAID("TTS7205")) Name(_UID, 0x00) Name(_STA, 0x0F) Method(FSTR, 0, Notserialized) { P8XH(0,0x77) Store(2, \_SB.PCI0.LPCB.G0RU) //route GPI0 to SCI Store(1, GPE0) //enable GPE0 } }}在ASL中将GPIO0的SCI handler中想驱动发送NofityScope(\_GPE){ Method(_L10) { //Store(0x10,P80D) //P8XH(0,0x10) Notify(\_SB.PCI0.LPCB.TTST, 0x80) }}At this point we can write a basic driver that does nothing other than bind to this ACPI device. It's only a few lines of code to do that, and it's consistent between all ACPI drivers. All we need to do is register an ACPI driver structure with add and remove functions. These will be called whenever the kernel finds an ACPI device with the TTS7205 ID, and we can do further setup there.#include #include #include #include #include #include #include #include #include #include #define MODULE_NAME "drvAcpi" /* module name */#define DEVICE_NAME "acpisci" /* device name */static const struct acpi_device_id bt_device_ids[] ={ { "TTS7205", 0}, { "", 0},};MODULE_DEVICE_TABLE(acpi, bt_device_ids);static struct acpi_driver acpi_sci_driver ={ .name = "DrvAcpi", .ids = bt_device_ids, .ops = { .add = acpi_sci_add, .remove = acpi_sci_remove, .notify = acpi_sci_notify, }, .owner = THIS_MODULE,};static int acpi_sci_add(struct acpi_device *device){ printk(KERN_DEBUG "%s: %s(): acpi_sci_add\n", MODULE_NAME, __func__); return toshiba_bluetooth_enable(device->handle);}#if 0 /* for support kernel 4.4.0-31 */static int acpi_sci_remove(struct acpi_device *device, int type)#elsestatic int acpi_sci_remove(struct acpi_device *device)#endif{ acpi_status result; acpi_integer status; printk(KERN_DEBUG "%s: %s(): acpi_sci_remove\n\r", MODULE_NAME, __func__); printk(KERN_DEBUG "%s: %s(): evaluate FSTP() acpi method.\n", MODULE_NAME, __func__); result = acpi_evaluate_integer(device->handle, "FSTP", NULL, &status); if (ACPI_FAILURE(result)) { printk(KERN_DEBUG "%s: %s(): error - FSTP() acpi method not found.\n", MODULE_NAME, __func__); return -EINVAL; } return 0;}static void acpi_sci_notify(struct acpi_device *device, u32 event){ DPRINTK(KERN_DEBUG "%s: %s(): received a notify. value = 0x%02X. count = %lld.\n", MODULE_NAME, __func__, event, ++count); ......}static struct file_operations acpi_drv_fops ={ .owner = THIS_MODULE, /* MACRO, point to __this_module Variable */ .open = acpi_drv_open, .read = acpi_drv_read, .release = acpi_drv_close, .poll = acpi_drv_poll, .fasync = acpi_drv_fasync,};On the other side, when we complete compiling acpi asl driver ko kernel module, we can operate this user device under linux os.#include #include #include #include #include #include #include #include #include /* fifthdrvtest */int fd;long long count = 0;//信号处理函数void my_signal_fun(int signum){ //unsigned char key_val; //read(fd, &key_val, 1); printf("key_val: hello - count = %lld.\n", ++count);}int main(int argc, char **argv){ unsigned char key_val; int ret; int Oflags; //在应用程序中捕捉SIGIO信号(由驱动程序发送) signal(SIGIO, my_signal_fun); fd = open("/dev/acpisci", O_RDWR); if (fd < 0) { printf("can't open!\n"); } //将当前进程PID设置为fd文件所对应驱动程序将要发送SIGIO,SIGUSR信号进程PID fcntl(fd, F_SETOWN, getpid()); //获取fd的打开方式 Oflags = fcntl(fd, F_GETFL); fcntl(fd, F_SETFL, Oflags | FASYNC); while (1) { sleep(1000); } return 0;}oops! complete!