#include #include #include // printk() #include // THIS_MODULE #include // struct kobject #include #include // error codes #include #include #include #include #include #include "kfile.h" #include "kspi.h" #include "sfsattrib.h" #define _TIMER_INTERVAL (jiffies + 3 * HZ) ///////////////////////////////////////////////////////////////////////////// MODULE_LICENSE("Dual BSD/GPL"); MODULE_AUTHOR("GfA"); ///////////////////////////////////////////////////////////////////////////// #define _SPI_DEVICE "/dev/spidev1.0" static void work_queue_func(struct work_struct *work); static struct kobject *g_pKoGfa = NULL, *g_pKoTiva = NULL; ///////////////////////////////////////////////////////////////////////////// // timer static struct workqueue_struct *g_pwq = NULL; static DECLARE_WORK(g_wo, work_queue_func); static volatile bool g_bTimerRunning = false; static struct timer_list g_jiq_timer; static void OnJigTimer(unsigned long ptr) { // printk(KERN_ALERT "%s, Ctx: \"%s\"-(%d)\n", __FUNCTION__, current->comm, current->pid); queue_work(g_pwq, &g_wo); } ///////////////////////////////////////////////////////////////////////////// // work queue // sysfs_notify // https://stackoverflow.com/questions/16367623/using-the-linux-sysfs-notify-call // static void work_queue_func(struct work_struct *work) { TIVA_ADC tadc; struct file *pfSpiDev = NULL; uint8_t mode = SPI_MODE_3; uint8_t bits = 8; uint32_t speed = 1000000; unsigned long start = jiffies; // printk(KERN_ALERT "%s, Ctx: \"%s\"-(%d)\n", __FUNCTION__, current->comm, current->pid); // CmdGetFirmwareVersion(pfSpiDev, &g_hw, &g_sw); // sysfs_notify(g_pKoTiva, NULL, "firmware"); if((pfSpiDev = kf_open(_SPI_DEVICE, O_RDWR, 0))) { if(kf_ioctl(pfSpiDev, SPI_IOC_WR_MODE, (unsigned long)&mode) < 0) { printk(KERN_ALERT "can't set spi mode\n"); // break; } if(kf_ioctl(pfSpiDev, SPI_IOC_RD_MODE, (unsigned long)&mode) < 0) { printk(KERN_ALERT "can't get spi mode\n"); // break; } ///////////////////////////////////////////////////////////////////// if(kf_ioctl(pfSpiDev, SPI_IOC_WR_BITS_PER_WORD, (unsigned long)&bits) < 0) { printk(KERN_ALERT "can't set bits per word\n"); // break; } if(kf_ioctl(pfSpiDev, SPI_IOC_RD_BITS_PER_WORD, (unsigned long)&bits) < 0) { printk(KERN_ALERT "can't get bits per word\n"); // break; } ///////////////////////////////////////////////////////////////////// if(kf_ioctl(pfSpiDev, SPI_IOC_WR_MAX_SPEED_HZ, (unsigned long)&speed) < 0) { printk(KERN_ALERT "can't set max speed hz\n"); // break; } if(kf_ioctl(pfSpiDev, SPI_IOC_RD_MAX_SPEED_HZ, (unsigned long)&speed) < 0) { printk(KERN_ALERT "can't get max speed hz\n"); // break; } if(CmdGetADC(pfSpiDev, &tadc) == 0) { if(g_tadc.UVers != tadc.UVers) { g_tadc.UVers = tadc.UVers; sysfs_notify(g_pKoTiva, NULL, "UVers"); // printk(KERN_ALERT "Update UVers.\n"); } if(g_tadc.UBatV3 != tadc.UBatV3) { g_tadc.UBatV3 = tadc.UBatV3; sysfs_notify(g_pKoTiva, NULL, "UBatV3"); // printk(KERN_ALERT "Update UBatV3.\n"); } if(g_tadc.Temp != tadc.Temp) { g_tadc.Temp = tadc.Temp; sysfs_notify(g_pKoTiva, NULL, "Temp"); // printk(KERN_ALERT "Update Temp.\n"); } if(g_tadc.UV5Vsys != tadc.UV5Vsys) { g_tadc.UV5Vsys = tadc.UV5Vsys; sysfs_notify(g_pKoTiva, NULL, "UV5Vsys"); // printk(KERN_ALERT "Update UV5Vsys.\n"); } if(g_tadc.UV3V6Bat != tadc.UV3V6Bat) { g_tadc.UV3V6Bat = tadc.UV3V6Bat; sysfs_notify(g_pKoTiva, NULL, "UV3V6Bat"); // printk(KERN_ALERT "Update UV3V6Bat.\n"); } if(g_tadc.TempTIVA != tadc.TempTIVA) { g_tadc.TempTIVA = tadc.TempTIVA; sysfs_notify(g_pKoTiva, NULL, "TempTIVA"); // printk(KERN_ALERT "Update TempTIVA.\n"); } } kf_close(pfSpiDev); } else { printk(KERN_ALERT "file_open failed\n"); } if(g_bTimerRunning) { mod_timer(&g_jiq_timer, _TIMER_INTERVAL); } printk(KERN_ALERT "Worker pass jiffies: %lu\n", ((long)jiffies - (long)start)); } ///////////////////////////////////////////////////////////////////////////// static int drv_init(void) { ///////////////////////////////////////////////////////////////////////// do { if(!(g_pKoGfa = kobject_create_and_add("gfa", NULL))) { printk(KERN_ALERT "kobject_create_and_add failed\n"); break; } if(!(g_pKoTiva = kobject_create_and_add("tiva", g_pKoGfa))) { printk(KERN_ALERT "kobject_create_and_add failed\n"); break; } ///////////////////////////////////////////////////////////////////// if(sysfs_create_file(g_pKoTiva, &g_tivaFirmwareAtt.attr)) { printk(KERN_ALERT "sysfs_create_file failed\n"); break; } if(sysfs_create_file(g_pKoTiva, &g_tivaUVersAtt.attr)) { printk(KERN_ALERT "sysfs_create_file failed\n"); break; } if(sysfs_create_file(g_pKoTiva, &g_tivaUBatV3Att.attr)) { printk(KERN_ALERT "sysfs_create_file failed\n"); break; } if(sysfs_create_file(g_pKoTiva, &g_tivaTempAtt.attr)) { printk(KERN_ALERT "sysfs_create_file failed\n"); break; } if(sysfs_create_file(g_pKoTiva, &g_tivaUV5VsysAtt.attr)) { printk(KERN_ALERT "sysfs_create_file failed\n"); break; } if(sysfs_create_file(g_pKoTiva, &g_tivaUV3V6BatAtt.attr)) { printk(KERN_ALERT "sysfs_create_file failed\n"); break; } if(sysfs_create_file(g_pKoTiva, &g_tivaTempTIVAAtt.attr)) { printk(KERN_ALERT "sysfs_create_file failed\n"); break; } ///////////////////////////////////////////////////////////////////// if(!(g_pwq = create_workqueue("GfaWrk"))) { printk(KERN_ALERT "create_workqueue failed!\n"); break; } ///////////////////////////////////////////////////////////////////// init_timer(&g_jiq_timer); g_jiq_timer.function = OnJigTimer; g_jiq_timer.data = 0; g_jiq_timer.expires = _TIMER_INTERVAL; add_timer(&g_jiq_timer); g_bTimerRunning = true; ///////////////////////////////////////////////////////////////////// if(!queue_work(g_pwq, &g_wo)) { printk(KERN_ALERT "queue_work failed\n"); break; } ///////////////////////////////////////////////////////////////////// printk(KERN_ALERT "%s, Ctx: \"%s\"-(%d)\n", __FUNCTION__, current->comm, current->pid); return 0; } while(0); ///////////////////////////////////////////////////////////////////////// if(g_bTimerRunning) { g_bTimerRunning = false; del_timer_sync(&g_jiq_timer); } if(g_pwq) destroy_workqueue(g_pwq); if(g_pKoTiva) { sysfs_remove_file(g_pKoTiva, &g_tivaFirmwareAtt.attr); sysfs_remove_file(g_pKoTiva, &g_tivaUVersAtt.attr); sysfs_remove_file(g_pKoTiva, &g_tivaUBatV3Att.attr); sysfs_remove_file(g_pKoTiva, &g_tivaTempAtt.attr); sysfs_remove_file(g_pKoTiva, &g_tivaUV5VsysAtt.attr); sysfs_remove_file(g_pKoTiva, &g_tivaUV3V6BatAtt.attr); sysfs_remove_file(g_pKoTiva, &g_tivaTempTIVAAtt.attr); kobject_put(g_pKoTiva); g_pKoTiva = NULL; } if(g_pKoGfa) { kobject_put(g_pKoGfa); g_pKoGfa = NULL; } return -ENOMEM; } ///////////////////////////////////////////////////////////////////////////// static void drv_exit(void) { g_bTimerRunning = false; del_timer_sync(&g_jiq_timer); if(g_pwq) destroy_workqueue(g_pwq); if(g_pKoTiva) { sysfs_remove_file(g_pKoTiva, &g_tivaFirmwareAtt.attr); sysfs_remove_file(g_pKoTiva, &g_tivaUVersAtt.attr); sysfs_remove_file(g_pKoTiva, &g_tivaUBatV3Att.attr); sysfs_remove_file(g_pKoTiva, &g_tivaTempAtt.attr); sysfs_remove_file(g_pKoTiva, &g_tivaUV5VsysAtt.attr); sysfs_remove_file(g_pKoTiva, &g_tivaUV3V6BatAtt.attr); sysfs_remove_file(g_pKoTiva, &g_tivaTempTIVAAtt.attr); kobject_put(g_pKoTiva); } if(g_pKoGfa) kobject_put(g_pKoGfa); printk(KERN_ALERT "%s, Ctx: \"%s\"-(%d)\n", __FUNCTION__, current->comm, current->pid); } ///////////////////////////////////////////////////////////////////////////// module_init(drv_init); module_exit(drv_exit);