diff --git a/.test/lint.sh b/.test/lint.sh index c445865..71f334b 100755 --- a/.test/lint.sh +++ b/.test/lint.sh @@ -6,7 +6,11 @@ SRC_DIR=$(cd $(dirname ${BASH_SOURCE:-$0}); cd ../; pwd) lint_driver () { pushd $SRC_DIR/src/drivers - python3 $SRC_DIR/.test/bin/run-clang-format.py rtmouse.c + python3 $SRC_DIR/.test/bin/run-clang-format.py rtmouse_main.c + python3 $SRC_DIR/.test/bin/run-clang-format.py rtmouse_dev.c + python3 $SRC_DIR/.test/bin/run-clang-format.py rtmouse_spi.c + python3 $SRC_DIR/.test/bin/run-clang-format.py rtmouse_i2c.c + python3 $SRC_DIR/.test/bin/run-clang-format.py rtmouse_gpio.c python3 $SRC_DIR/.test/bin/run-clang-format.py rtmouse.h popd } diff --git a/src/drivers/Makefile.header_from_apt b/src/drivers/Makefile.header_from_apt index c43215a..e471aa1 100644 --- a/src/drivers/Makefile.header_from_apt +++ b/src/drivers/Makefile.header_from_apt @@ -1,17 +1,18 @@ MODULE:= rtmouse obj-m:= $(MODULE).o +$(MODULE)-y:= $(MODULE)_main.o $(MODULE)_dev.o $(MODULE)_spi.o $(MODULE)_i2c.o $(MODULE)_gpio.o clean-files:= *.o *.ko *.mod.[co] *~ LINUX_SRC_DIR:=/usr/src/linux-headers-$(shell uname -r) VERBOSE:=0 -rtmouse.ko: rtmouse.c rtmouse.h +$(MODULE).ko: $(MODULE)_main.c $(MODULE)_dev.c $(MODULE)_spi.c $(MODULE)_i2c.c $(MODULE)_gpio.c $(MODULE).h make -C $(LINUX_SRC_DIR) M=$(shell pwd) V=$(VERBOSE) modules clean: make -C $(LINUX_SRC_DIR) M=$(shell pwd) V=$(VERBOSE) clean -install: rtmouse.ko +install: $(MODULE).ko cp ../../50-rtmouse.rules /etc/udev/rules.d/ uninstall: diff --git a/src/drivers/Makefile.header_from_source b/src/drivers/Makefile.header_from_source index 8d43e03..75798f1 100644 --- a/src/drivers/Makefile.header_from_source +++ b/src/drivers/Makefile.header_from_source @@ -1,11 +1,12 @@ MODULE:= rtmouse obj-m:= $(MODULE).o +$(MODULE)-y:= $(MODULE)_main.o $(MODULE)_dev.o $(MODULE)_spi.o $(MODULE)_i2c.o $(MODULE)_gpio.o clean-files:= *.o *.ko *.mod.[co] *~ LINUX_SRC_DIR:=/usr/src/linux VERBOSE:=0 -rtmouse.ko: rtmouse.c rtmouse.h +$(MODULE).ko: $(MODULE)_main.c $(MODULE)_dev.c $(MODULE)_spi.c $(MODULE)_i2c.c $(MODULE)_gpio.c $(MODULE).h make -C $(LINUX_SRC_DIR) M=$(shell pwd) V=$(VERBOSE) modules clean: diff --git a/src/drivers/rtmouse.c b/src/drivers/rtmouse.c deleted file mode 100644 index 5b2d447..0000000 --- a/src/drivers/rtmouse.c +++ /dev/null @@ -1,1800 +0,0 @@ -/* - * - * rtmouse.c - * Raspberry Pi Mouse device driver - * - * Version: 3.3.2 - * - * Copyright (C) 2015-2024 RT Corporation - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301, USA. - */ - -#include "rtmouse.h" - -MODULE_AUTHOR("RT Corporation"); -MODULE_LICENSE("GPL"); -MODULE_VERSION("3.3.2"); -MODULE_DESCRIPTION("Raspberry Pi Mouse device driver"); - -static int _major_dev[ID_DEV_SIZE] = { - [ID_DEV_LED] = DEV_MAJOR, [ID_DEV_SWITCH] = DEV_MAJOR, - [ID_DEV_SENSOR] = DEV_MAJOR, [ID_DEV_BUZZER] = DEV_MAJOR, - [ID_DEV_MOTORRAWR] = DEV_MAJOR, [ID_DEV_MOTORRAWL] = DEV_MAJOR, - [ID_DEV_MOTOREN] = DEV_MAJOR, [ID_DEV_MOTOR] = DEV_MAJOR}; - -static int _minor_dev[ID_DEV_SIZE] = { - [ID_DEV_LED] = DEV_MINOR, [ID_DEV_SWITCH] = DEV_MINOR, - [ID_DEV_SENSOR] = DEV_MINOR, [ID_DEV_BUZZER] = DEV_MINOR, - [ID_DEV_MOTORRAWR] = DEV_MINOR, [ID_DEV_MOTORRAWL] = DEV_MINOR, - [ID_DEV_MOTOREN] = DEV_MINOR, [ID_DEV_MOTOR] = DEV_MINOR}; - -/* --- General Options --- */ -static struct cdev *cdev_array = NULL; -static struct class *class_dev[ID_DEV_SIZE] = { - [ID_DEV_LED] = NULL, [ID_DEV_SWITCH] = NULL, - [ID_DEV_SENSOR] = NULL, [ID_DEV_BUZZER] = NULL, - [ID_DEV_MOTORRAWR] = NULL, [ID_DEV_MOTORRAWL] = NULL, - [ID_DEV_MOTOREN] = NULL, [ID_DEV_MOTOR] = NULL}; - -static volatile void __iomem *pwm_base; -static volatile void __iomem *clk_base; -static volatile uint32_t *gpio_base; - -static volatile int cdev_index = 0; - -static struct mutex lock; - -/* --- Function Declarations --- */ -static void set_motor_r_freq(int freq); -static void set_motor_l_freq(int freq); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) -static int mcp3204_remove(struct spi_device *spi); -#else -static void mcp3204_remove(struct spi_device *spi); -#endif - -static int mcp3204_probe(struct spi_device *spi); -static unsigned int mcp3204_get_value(int channel); - -#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0) -static int rtcnt_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id); -#else -static int rtcnt_i2c_probe(struct i2c_client *client); -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0) -static int rtcnt_i2c_remove(struct i2c_client *client); -#else -static void rtcnt_i2c_remove(struct i2c_client *client); -#endif - -/* --- Variable Type definitions --- */ -/* SPI */ -struct mcp3204_drvdata { - struct spi_device *spi; - struct mutex lock; - unsigned char tx[MCP320X_PACKET_SIZE] ____cacheline_aligned; - unsigned char rx[MCP320X_PACKET_SIZE] ____cacheline_aligned; - struct spi_transfer xfer ____cacheline_aligned; - struct spi_message msg ____cacheline_aligned; -}; - -/* --- Static variables --- */ -/* SPI device ID */ -static struct spi_device_id mcp3204_id[] = { - {"mcp3204", 0}, - {}, -}; - -/* SPI Info */ -static struct spi_board_info mcp3204_info = { - .modalias = "mcp3204", - .max_speed_hz = 100000, - .bus_num = 0, - .chip_select = 0, - .mode = SPI_MODE_3, -}; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0) -static struct device *mcp320x_dev; -#endif - -/* SPI Dirver Info */ -static struct spi_driver mcp3204_driver = { - .driver = - { - .name = DEVNAME_SENSOR, - .owner = THIS_MODULE, - }, - .id_table = mcp3204_id, - .probe = mcp3204_probe, - .remove = mcp3204_remove, -}; - -/* I2C */ -struct rtcnt_device_info { - struct cdev cdev; - unsigned int device_major; - unsigned int device_minor; - struct class *device_class; - struct i2c_client *client; - struct mutex lock; - int signed_pulse_count; - int raw_pulse_count; -}; - -static struct i2c_client *i2c_client_r = NULL; -static struct i2c_client *i2c_client_l = NULL; -static unsigned int motor_l_freq_is_positive = 1; -static unsigned int motor_r_freq_is_positive = 1; - -/* I2C Device ID */ -static struct i2c_device_id i2c_counter_id[] = { - {DEVNAME_CNTL, 0}, - {DEVNAME_CNTR, 1}, - {}, -}; - -/* I2C Dirver Info */ -static struct i2c_driver i2c_counter_driver = { - .driver = - { - .name = "rtcounter", - .owner = THIS_MODULE, - }, - .id_table = i2c_counter_id, - .probe = rtcnt_i2c_probe, - .remove = rtcnt_i2c_remove, -}; - -/* -- Device Addition -- */ -MODULE_DEVICE_TABLE(spi, mcp3204_id); -MODULE_DEVICE_TABLE(i2c, i2c_counter_id); - -/* --- GPIO Operation --- */ -/* getPWMCount function for GPIO Operation */ -static int getPWMCount(int freq) -{ - if (freq < 1) - return PWM_BASECLK; - if (freq > 10000) - return PWM_BASECLK / 10000; - - return PWM_BASECLK / freq; -} - -/* set function */ -static int rpi_gpio_function_set(int pin, uint32_t func) -{ - int index = RPI_GPFSEL0_INDEX + pin / 10; - uint32_t mask = ~(0x7 << ((pin % 10) * 3)); - - gpio_base[index] = - (gpio_base[index] & mask) | ((func & 0x7) << ((pin % 10) * 3)); - - return 1; -} - -/*set mask and value */ -static void rpi_gpio_set32(uint32_t mask, uint32_t val) -{ - gpio_base[RPI_GPSET0_INDEX] = val & mask; -} - -/* clear mask and value */ -static void rpi_gpio_clear32(uint32_t mask, uint32_t val) -{ - gpio_base[RPI_GPCLR0_INDEX] = val & mask; -} - -/* pwm set function */ -static void rpi_pwm_write32(uint32_t offset, uint32_t val) -{ - iowrite32(val, pwm_base + offset); -} - -/* left motor function */ -static void set_motor_l_freq(int freq) -{ - int dat; - - rpi_gpio_function_set(BUZZER_BASE, RPI_GPF_OUTPUT); - - // Reset uncontrollable frequency to zero. - if (abs(freq) < MOTOR_UNCONTROLLABLE_FREQ) { - freq = 0; - } - - if (freq == 0) { - rpi_gpio_function_set(MOTCLK_L_BASE, RPI_GPF_OUTPUT); - return; - } else { - rpi_gpio_function_set(MOTCLK_L_BASE, RPI_GPF_ALT0); - } - - if (freq > 0) { - motor_l_freq_is_positive = 1; - rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << MOTDIR_L_BASE); - } else { - motor_l_freq_is_positive = 0; - rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << MOTDIR_L_BASE); - freq = -freq; - } - - dat = getPWMCount(freq); - - rpi_pwm_write32(RPI_PWM_RNG1, dat); - rpi_pwm_write32(RPI_PWM_DAT1, dat >> 1); - - return; -} - -/* right motor function */ -static void set_motor_r_freq(int freq) -{ - int dat; - - rpi_gpio_function_set(BUZZER_BASE, RPI_GPF_OUTPUT); - - // Reset uncontrollable frequency to zero. - if (abs(freq) < MOTOR_UNCONTROLLABLE_FREQ) { - freq = 0; - } - - if (freq == 0) { - rpi_gpio_function_set(MOTCLK_R_BASE, RPI_GPF_OUTPUT); - return; - } else { - rpi_gpio_function_set(MOTCLK_R_BASE, RPI_GPF_ALT0); - } - - if (freq > 0) { - motor_r_freq_is_positive = 1; - rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << MOTDIR_R_BASE); - } else { - motor_r_freq_is_positive = 0; - rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << MOTDIR_R_BASE); - freq = -freq; - } - - dat = getPWMCount(freq); - - rpi_pwm_write32(RPI_PWM_RNG2, dat); - rpi_pwm_write32(RPI_PWM_DAT2, dat >> 1); - - return; -} - -/* --- Function for device file operations --- */ -/* - * Read Push Switches - * return 0 : device close - */ -static ssize_t sw_read(struct file *filep, char __user *buf, size_t count, - loff_t *f_pos) -{ - int buflen = 0; - unsigned char rw_buf[MAX_BUFLEN]; - unsigned int ret = 0; - int len; - int index; - unsigned int pin = SW1_PIN; - uint32_t mask; - int minor = *((int *)filep->private_data); -#if RASPBERRYPI == 4 - int pullreg = GPPUPPDN1 + (pin >> 4); // SW1, 2, 3 is between GPIO16-31 - int pullshift = (pin & 0xf) << 1; - unsigned int pullbits; - unsigned int pull; -#endif - - switch (minor) { - case 0: - pin = SW1_PIN; - break; - case 1: - pin = SW2_PIN; - break; - case 2: - pin = SW3_PIN; - break; - default: - return 0; - break; - } - - if (*f_pos > 0) - return 0; /* End of file */ - -#if RASPBERRYPI == 4 - pull = GPIO_PULLUP; - pullbits = *(gpio_base + pullreg); - pullbits &= ~(3 << pullshift); - pullbits |= (pull << pullshift); - *(gpio_base + pullreg) = pullbits; -#else - // プルモード (2bit)を書き込む NONE/DOWN/UP - gpio_base[37] = GPIO_PULLUP & 0x3; // GPPUD - // ピンにクロックを供給(前後にウェイト) - msleep(1); - gpio_base[38] = 0x1 << pin; // GPPUDCLK0 - msleep(1); - // プルモード・クロック状態をクリアして終了 - gpio_base[37] = 0; - gpio_base[38] = 0; -#endif - - index = RPI_GPFSEL0_INDEX + pin / 10; - mask = ~(0x7 << ((pin % 10) * 3)); - - ret = ((gpio_base[13] & (0x01 << pin)) != 0); - sprintf(rw_buf, "%d\n", ret); - - buflen = strlen(rw_buf); - count = buflen; - len = buflen; - - if (copy_to_user((void *)buf, &rw_buf, count)) { - printk(KERN_INFO "err read buffer from ret %d\n", ret); - printk(KERN_INFO "err read buffer from %s\n", rw_buf); - printk(KERN_INFO "err sample_char_read size(%zu)\n", count); - printk(KERN_INFO "sample_char_read size err(%d)\n", -EFAULT); - return 0; - } - *f_pos += count; - - return count; -} - -/* - * Read Sensor information - * return 0 : device close - */ -static ssize_t sensor_read(struct file *filep, char __user *buf, size_t count, - loff_t *f_pos) -{ - int buflen = 0; - unsigned char rw_buf[MAX_BUFLEN]; - unsigned int ret = 0; - int len; - - // printk(KERN_INFO "new\n"); - - int usecs = 30; - int rf = 0, lf = 0, r = 0, l = 0; - int orf = 0, olf = 0, or = 0, ol = 0; - - if (*f_pos > 0) - return 0; /* End of file */ - - /* get values through MCP3204 */ - /* Right side */ - or = mcp3204_get_value(R_AD_CH); - rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << R_LED_BASE); - udelay(usecs); - r = mcp3204_get_value(R_AD_CH); - rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << R_LED_BASE); - udelay(usecs); - /* Left side */ - ol = mcp3204_get_value(L_AD_CH); - rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << L_LED_BASE); - udelay(usecs); - l = mcp3204_get_value(L_AD_CH); - rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << L_LED_BASE); - udelay(usecs); - /* Right front side */ - orf = mcp3204_get_value(RF_AD_CH); - rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << RF_LED_BASE); - udelay(usecs); - rf = mcp3204_get_value(RF_AD_CH); - rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << RF_LED_BASE); - udelay(usecs); - /* Left front side */ - olf = mcp3204_get_value(LF_AD_CH); - rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << LF_LED_BASE); - udelay(usecs); - lf = mcp3204_get_value(LF_AD_CH); - rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << LF_LED_BASE); - udelay(usecs); - - /* set sensor data to rw_buf(static buffer) */ - snprintf(rw_buf, sizeof(rw_buf), "%d %d %d %d\n", rf - orf, r - or, - l - ol, lf - olf); - buflen = strlen(rw_buf); - count = buflen; - len = buflen; - - /* copy data to user area */ - if (copy_to_user((void *)buf, &rw_buf, count)) { - printk(KERN_INFO "err read buffer from ret %d\n", ret); - printk(KERN_INFO "err read buffer from %s\n", rw_buf); - printk(KERN_INFO "err sample_char_read size(%zu)\n", count); - printk(KERN_INFO "sample_char_read size err(%d)\n", -EFAULT); - return 0; - } - - *f_pos += count; - - return count; -} - -/* - * Turn On LEDs - * return 0 : device close - */ -static int led_put(int ledno) -{ - switch (ledno) { - case 0: - rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << LED0_BASE); - break; - case 1: - rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << LED1_BASE); - break; - case 2: - rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << LED2_BASE); - break; - case 3: - rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << LED3_BASE); - break; - } - return 0; -} - -/* - * Turn Off LEDs - * return 0 : device close - */ -static int led_del(int ledno) -{ - switch (ledno) { - case 0: - rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << LED0_BASE); - break; - case 1: - rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << LED1_BASE); - break; - case 2: - rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << LED2_BASE); - break; - case 3: - rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << LED3_BASE); - break; - } - - return 0; -} - -/* - * Initialize buzzer - * return 0 : device close - */ -static int buzzer_init(void) -{ - - rpi_gpio_function_set(BUZZER_BASE, RPI_GPF_OUTPUT); // io is pwm out - rpi_pwm_write32(RPI_PWM_CTRL, 0x00000000); - udelay(1000); - rpi_pwm_write32(RPI_PWM_CTRL, 0x00008181); // PWM1,2 enable - - // printk(KERN_DEBUG "%s: rpi_pwm_ctrl:%08X\n", DRIVER_NAME, - // ioread32(pwm_base + RPI_PWM_CTRL)); - - return 0; -} - -/* --- GPIO mapping for Device Open/Close --- */ -/* - * Get gpio addresses and set them to global variables. - * - gpio_base - * - pwm_base - * - clk_base - * - clk_status - */ -static int gpio_map(void) -{ - static int clk_status = 1; - -#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 0, 0) - if (gpio_base == NULL) { - gpio_base = ioremap_nocache(RPI_GPIO_BASE, RPI_GPIO_SIZE); - } - - if (pwm_base == NULL) { - pwm_base = ioremap_nocache(RPI_PWM_BASE, RPI_PWM_SIZE); - } - - if (clk_base == NULL) { - clk_base = ioremap_nocache(RPI_CLK_BASE, RPI_CLK_SIZE); - } -#else - if (gpio_base == NULL) { - gpio_base = ioremap(RPI_GPIO_BASE, RPI_GPIO_SIZE); - } - - if (pwm_base == NULL) { - pwm_base = ioremap(RPI_PWM_BASE, RPI_PWM_SIZE); - } - - if (clk_base == NULL) { - clk_base = ioremap(RPI_CLK_BASE, RPI_CLK_SIZE); - } -#endif - - /* kill */ - if (clk_status == 1) { - iowrite32(0x5a000000 | (1 << 5), clk_base + CLK_PWM_INDEX); - udelay(1000); - - /* clk set */ - iowrite32(0x5a000000 | (2 << 12), clk_base + CLK_PWMDIV_INDEX); - iowrite32(0x5a000011, clk_base + CLK_PWM_INDEX); - - udelay(1000); /* wait for 1msec */ - - clk_status = 0; - } - - return 0; -} - -/* Unmap GPIO addresses */ -static int gpio_unmap(void) -{ - iounmap(gpio_base); - iounmap(pwm_base); - iounmap(clk_base); - - gpio_base = NULL; - pwm_base = NULL; - clk_base = NULL; - return 0; -} - -/* --- Device File Operation --- */ -/* Open Device */ -static int dev_open(struct inode *inode, struct file *filep) -{ - int *minor = (int *)kmalloc(sizeof(int), GFP_KERNEL); - int major = MAJOR(inode->i_rdev); - *minor = MINOR(inode->i_rdev); - - filep->private_data = (void *)minor; - - const char *dev_name = filep->f_path.dentry->d_name.name; - printk(KERN_INFO "Device opened: %s, Major: %d\n", dev_name, major); - - return 0; -} - -/* Close device */ -static int dev_release(struct inode *inode, struct file *filep) -{ - kfree(filep->private_data); - return 0; -} - -static int i2c_dev_open(struct inode *inode, struct file *filep) -{ - struct rtcnt_device_info *dev_info; - dev_info = container_of(inode->i_cdev, struct rtcnt_device_info, cdev); - if (dev_info == NULL || dev_info->client == NULL) { - printk(KERN_ERR "%s: i2c dev_open failed.\n", DRIVER_NAME); - } - dev_info->device_minor = MINOR(inode->i_rdev); - filep->private_data = dev_info; - return 0; -} - -static int i2c_dev_release(struct inode *inode, struct file *filep) -{ - return 0; -} - -/* Parse motor command */ -static int parseMotorCmd(const char __user *buf, size_t count, int *ret) -{ - int r_motor_val, l_motor_val, time_val; - char *newbuf = kmalloc(sizeof(char) * count, GFP_KERNEL); - - if (copy_from_user(newbuf, buf, sizeof(char) * count)) { - kfree(newbuf); - return -EFAULT; - } - - sscanf(newbuf, "%d%d%d\n", &l_motor_val, &r_motor_val, &time_val); - - kfree(newbuf); - - mutex_lock(&lock); - - set_motor_l_freq(l_motor_val); - set_motor_r_freq(r_motor_val); - - msleep_interruptible(time_val); - - set_motor_l_freq(0); - set_motor_r_freq(0); - - mutex_unlock(&lock); - - return count; -} - -/* - * led_write - Trun ON/OFF LEDs - * Write function of /dev/rtled - */ -static ssize_t led_write(struct file *filep, const char __user *buf, - size_t count, loff_t *f_pos) -{ - char cval; - int ret; - int minor = *((int *)filep->private_data); - - if (count > 0) { - if (copy_from_user(&cval, buf, sizeof(char))) { - return -EFAULT; - } - switch (cval) { - case '1': - ret = led_put(minor); - break; - case '0': - ret = led_del(minor); - break; - } - return sizeof(char); - } - return 0; -} - -/* - * buzzer_write - Write buzzer frequency - * Write function of /dev/rtbuzzer - */ -static ssize_t buzzer_write(struct file *filep, const char __user *buf, - size_t count, loff_t *f_pos) -{ - int ret; - int freq, dat; - - ret = kstrtoint_from_user(buf, count, 10, &freq); - if (ret) { - printk(KERN_ERR "%s: error parsing string to int in %s()\n", - DRIVER_NAME, __func__); - return ret; - } - - if (freq != 0) { - if (freq < 1) { - freq = 1; - } - - if (freq > 20000) { - freq = 20000; - } - - rpi_gpio_function_set(BUZZER_BASE, - RPI_GPF_ALT5); // io is pwm out - dat = PWM_BASECLK / freq; - rpi_pwm_write32(RPI_PWM_RNG2, dat); - rpi_pwm_write32(RPI_PWM_DAT2, dat >> 1); - } else { - rpi_gpio_function_set(BUZZER_BASE, - RPI_GPF_OUTPUT); // io is pwm out - } - - return count; -} - -/* - * rawmotor_l_write - Output frequency to the left motor - * Write function of /dev/rtmotor_raw_l - */ -static ssize_t rawmotor_l_write(struct file *filep, const char __user *buf, - size_t count, loff_t *f_pos) -{ - int freq, ret; - - ret = kstrtoint_from_user(buf, count, 10, &freq); - if (ret) { - printk(KERN_ERR "%s: error parsing string to int in %s()\n", - DRIVER_NAME, __func__); - return ret; - } - set_motor_l_freq(freq); - - return count; -} - -/* - * rawmotor_r_write - Output frequency to the right motor - * Write function of /dev/rtmotor_raw_r - */ -static ssize_t rawmotor_r_write(struct file *filep, const char __user *buf, - size_t count, loff_t *f_pos) -{ - int freq, ret; - - ret = kstrtoint_from_user(buf, count, 10, &freq); - if (ret) { - printk(KERN_ERR "%s: error parsing string to int in %s()\n", - DRIVER_NAME, __func__); - return ret; - } - - set_motor_r_freq(freq); - - return count; -} - -/* - * motoren_write - Turn ON/OFF SteppingMotor Power - * Write function of /dev/rtmotoren - */ -static ssize_t motoren_write(struct file *filep, const char __user *buf, - size_t count, loff_t *f_pos) -{ - char cval; - - if (count > 0) { - if (copy_from_user(&cval, buf, sizeof(char))) { - return -EFAULT; - } - - switch (cval) { - case '1': - rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << MOTEN_BASE); - break; - case '0': - rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << MOTEN_BASE); - break; - } - return sizeof(char); - } - return 0; -} - -/* - * motor_write - Output frequency to right and left both motors - * Write function of /dev/rtmotor - */ -static ssize_t motor_write(struct file *filep, const char __user *buf, - size_t count, loff_t *f_pos) -{ - int tmp; - int bufcnt; - bufcnt = parseMotorCmd(buf, count, &tmp); - - return bufcnt; -} - -/* - * i2c_counter_set - set value to I2C pulse counter - * called by cntr_write() and cntl_write() - */ -static int i2c_counter_set(struct rtcnt_device_info *dev_info, int setval) -{ - int ret = 0; - int lsb = 0, msb = 0; - struct i2c_client *client = dev_info->client; - - // printk(KERN_INFO "set 0x%x = 0x%x\n", client->addr, setval); - msb = (setval >> 8) & 0xFF; - lsb = setval & 0xFF; - mutex_lock(&dev_info->lock); - // printk(KERN_INFO "set 0x%x msb = 0x%x\n", client->addr, msb); - ret = i2c_smbus_write_byte_data(client, 0x10, msb); - if (ret < 0) { - printk(KERN_ERR - "%s: Failed writing to i2c counter device, addr=0x%x\n", - __func__, client->addr); - return -ENODEV; - } - // printk(KERN_INFO "set 0x%x lsb = 0x%x\n", client->addr, lsb); - ret = i2c_smbus_write_byte_data(client, 0x11, lsb); - if (ret < 0) { - printk(KERN_ERR - "%s: Failed writing to i2c counter device, addr=0x%x\n", - __func__, client->addr); - return -ENODEV; - } - mutex_unlock(&dev_info->lock); - return ret; -} - -/* - * i2c_counter_read - get value from I2C pulse counter - * called by rtcnt_read() - */ -static int i2c_counter_read(struct rtcnt_device_info *dev_info, int *ret) -{ - int lsb = 0, msb = 0; - // printk(KERN_INFO "read 0x%x\n", client->addr); - struct i2c_client *client = dev_info->client; - mutex_lock(&dev_info->lock); - - lsb = i2c_smbus_read_byte_data(client, CNT_ADDR_LSB); - if (lsb < 0) { - printk( - KERN_ERR - "%s: Failed reading from i2c counter device, addr=0x%x\n", - __func__, client->addr); - return -ENODEV; - } - msb = i2c_smbus_read_byte_data(client, CNT_ADDR_MSB); - if (msb < 0) { - printk( - KERN_ERR - "%s: Failed reading from i2c counter device, addr=0x%x\n", - __func__, client->addr); - return -ENODEV; - } - mutex_unlock(&dev_info->lock); - - *ret = ((msb << 8) & 0xFF00) + (lsb & 0xFF); - - // printk(KERN_INFO "0x%x == 0x%x\n", client->addr, *ret); - return 0; -} - -/* - * update_signed_count - update signed pulse count of dev_info - * called by rtcnt_read() - */ -void update_signed_count(struct rtcnt_device_info *dev_info, int rtcnt_count) -{ - int diff_count = rtcnt_count - dev_info->raw_pulse_count; - - // カウントがMAX_PULSE_COUNTから0に変わる場合の処理 - // ただし、それ以外でもdiffが負の値になることがある - // そのため、diffが十分に大きな負の値の場合に処理する - // if(diff_count < 0) では正常に動作しない - if (diff_count < -SIGNED_COUNT_SIZE) { - diff_count += MAX_PULSE_COUNT; - } - - if (dev_info->client->addr == DEV_ADDR_CNTL) { - if (motor_l_freq_is_positive) { - dev_info->signed_pulse_count += diff_count; - } else { - dev_info->signed_pulse_count -= diff_count; - } - } else { - if (motor_r_freq_is_positive) { - dev_info->signed_pulse_count += diff_count; - } else { - dev_info->signed_pulse_count -= diff_count; - } - } - - if (dev_info->signed_pulse_count > SIGNED_COUNT_SIZE || - dev_info->signed_pulse_count < -SIGNED_COUNT_SIZE) { - dev_info->signed_pulse_count = 0; - } -} - -/* - * reset_signed_count - reset signed pulse count of dev_info - * called by rtcnt_write() - */ -void reset_signed_count(struct rtcnt_device_info *dev_info, int rtcnt_count) -{ - int raw_count; - - if (rtcnt_count > SIGNED_COUNT_SIZE) { - rtcnt_count = SIGNED_COUNT_SIZE; - } else if (rtcnt_count < -SIGNED_COUNT_SIZE) { - rtcnt_count = -SIGNED_COUNT_SIZE; - } - dev_info->signed_pulse_count = rtcnt_count; - i2c_counter_read(dev_info, &raw_count); - dev_info->raw_pulse_count = raw_count; -} - -/* - * rtcnt_read - Read value from right/left pulse counter - * Read function of /dev/rtcounter_* - */ -static ssize_t rtcnt_read(struct file *filep, char __user *buf, size_t count, - loff_t *f_pos) -{ - struct rtcnt_device_info *dev_info = filep->private_data; - - unsigned char rw_buf[64]; - int buflen; - - int rtcnt_count = 0; - if (*f_pos > 0) - return 0; /* close device */ - i2c_counter_read(dev_info, &rtcnt_count); - - if (dev_info->device_minor == 1) { - update_signed_count(dev_info, rtcnt_count); - dev_info->raw_pulse_count = rtcnt_count; - rtcnt_count = dev_info->signed_pulse_count; - } else { - dev_info->raw_pulse_count = rtcnt_count; - } - - /* set sensor data to rw_buf(static buffer) */ - sprintf(rw_buf, "%d\n", rtcnt_count); - buflen = strlen(rw_buf); - count = buflen; - - /* copy data to user area */ - if (copy_to_user((void *)buf, &rw_buf, count)) { - printk(KERN_INFO "err read buffer from %s\n", rw_buf); - printk(KERN_INFO "err sample_char_read size(%zu)\n", count); - printk(KERN_INFO "sample_char_read size err(%d)\n", -EFAULT); - return -EFAULT; - } - *f_pos += count; - return count; -} - -/* - * cnt_write - Set value to right/left pulse counter - * Write function of /dev/rtcounter - */ -static ssize_t rtcnt_write(struct file *filep, const char __user *buf, - size_t count, loff_t *pos) -{ - struct rtcnt_device_info *dev_info = filep->private_data; - - int rtcnt_count = 0; - int ret; - - ret = kstrtoint_from_user(buf, count, 10, &rtcnt_count); - if (ret) { - printk(KERN_ERR "%s: error parsing string to int in %s()\n", - DRIVER_NAME, __func__); - return ret; - } - - i2c_counter_set(dev_info, rtcnt_count); - - if (dev_info->device_minor == 1) { - reset_signed_count(dev_info, rtcnt_count); - } - - printk(KERN_INFO "%s: set pulse counter value %d\n", DRIVER_NAME, - rtcnt_count); - return count; -} - -/* --- Device File Operations --- */ -static struct file_operations dev_fops[ID_DEV_SIZE] = { - [ID_DEV_LED].open = dev_open, - [ID_DEV_LED].release = dev_release, - [ID_DEV_LED].write = led_write, - [ID_DEV_SWITCH].open = dev_open, - [ID_DEV_SWITCH].read = sw_read, - [ID_DEV_SWITCH].release = dev_release, - [ID_DEV_SENSOR].open = dev_open, - [ID_DEV_SENSOR].read = sensor_read, - [ID_DEV_SENSOR].release = dev_release, - [ID_DEV_BUZZER].open = dev_open, - [ID_DEV_BUZZER].release = dev_release, - [ID_DEV_BUZZER].write = buzzer_write, - [ID_DEV_MOTORRAWR].open = dev_open, - [ID_DEV_MOTORRAWR].release = dev_release, - [ID_DEV_MOTORRAWR].write = rawmotor_r_write, - [ID_DEV_MOTORRAWL].open = dev_open, - [ID_DEV_MOTORRAWL].release = dev_release, - [ID_DEV_MOTORRAWL].write = rawmotor_l_write, - [ID_DEV_MOTOREN].open = dev_open, - [ID_DEV_MOTOREN].release = dev_release, - [ID_DEV_MOTOREN].write = motoren_write, - [ID_DEV_MOTOR].open = dev_open, - [ID_DEV_MOTOR].release = dev_release, - [ID_DEV_MOTOR].write = motor_write, - [ID_DEV_CNT].open = i2c_dev_open, - [ID_DEV_CNT].release = i2c_dev_release, - [ID_DEV_CNT].read = rtcnt_read, - [ID_DEV_CNT].write = rtcnt_write}; - -/* --- Device Driver Registration and Device File Creation --- */ -static int register_dev(int id_dev) -{ - int retval; - dev_t dev; - dev_t devno; - int i; - - /* 空いているメジャー番号を使ってメジャー& - マイナー番号をカーネルに登録する */ - retval = - alloc_chrdev_region(&dev, /* 結果を格納するdev_t構造体 */ - DEV_MINOR, /* ベースマイナー番号 */ - NUM_DEV[id_dev], /* デバイスの数 */ - NAME_DEV[id_dev] /* デバイスドライバの名前 */ - ); - - if (retval < 0) { - printk(KERN_ERR "alloc_chrdev_region failed.\n"); - return retval; - } - _major_dev[id_dev] = MAJOR(dev); - - /* デバイスクラスを作成する */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) - class_dev[id_dev] = class_create(THIS_MODULE, NAME_DEV[id_dev]); -#else - class_dev[id_dev] = class_create(NAME_DEV[id_dev]); -#endif - - if (IS_ERR(class_dev[id_dev])) { - return PTR_ERR(class_dev[id_dev]); - } - - for (i = 0; i < NUM_DEV[id_dev]; i++) { - /* デバイスの数だけキャラクタデバイスを登録する */ - devno = MKDEV(_major_dev[id_dev], _minor_dev[id_dev] + i); - - /* キャラクタデバイスとしてこのモジュールをカーネルに登録する */ - cdev_init(&(cdev_array[cdev_index]), &dev_fops[id_dev]); - cdev_array[cdev_index].owner = THIS_MODULE; - if (cdev_add(&(cdev_array[cdev_index]), devno, 1) < 0) { - /* 登録に失敗した */ - printk(KERN_ERR "cdev_add failed minor = %d\n", - _minor_dev[id_dev] + i); - } else { - /* デバイスノードの作成 */ - struct device *dev_ret; - dev_ret = device_create(class_dev[id_dev], NULL, devno, - NULL, NAME_DEV_U[id_dev], - _minor_dev[id_dev] + i); - - /* デバイスファイル作成の可否を判定 */ - if (IS_ERR(dev_ret)) { - /* デバイスファイルの作成に失敗した */ - printk(KERN_ERR - "device_create failed minor = %d\n", - _minor_dev[id_dev] + i); - /* リソースリークを避けるために登録された状態cdevを削除する - */ - cdev_del(&(cdev_array[cdev_index])); - return PTR_ERR(dev_ret); - } - } - cdev_index++; - } - return 0; -} - -/* mcp3204_remove - remove function lined with spi_dirver */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) -static int mcp3204_remove(struct spi_device *spi) -{ - struct mcp3204_drvdata *data; - /* get drvdata */ - data = (struct mcp3204_drvdata *)spi_get_drvdata(spi); - /* free kernel memory */ - kfree(data); - printk(KERN_INFO "%s: mcp3204 removed\n", DRIVER_NAME); - return 0; -} -#else -static void mcp3204_remove(struct spi_device *spi) -{ - struct mcp3204_drvdata *data; - /* get drvdata */ - data = (struct mcp3204_drvdata *)spi_get_drvdata(spi); - /* free kernel memory */ - kfree(data); - printk(KERN_INFO "%s: mcp3204 removed\n", DRIVER_NAME); -} -#endif - -/* mcp3204_probe - probe function lined with spi_dirver */ -static int mcp3204_probe(struct spi_device *spi) -{ - struct mcp3204_drvdata *data; - - spi->max_speed_hz = mcp3204_info.max_speed_hz; - spi->mode = mcp3204_info.mode; - spi->bits_per_word = 8; - - if (spi_setup(spi)) { - printk(KERN_ERR "%s:spi_setup failed!\n", __func__); - return -ENODEV; - } - - /* alloc kernel memory */ - data = kzalloc(sizeof(struct mcp3204_drvdata), GFP_KERNEL); - if (data == NULL) { - printk(KERN_ERR "%s:kzalloc() failed!\n", __func__); - return -ENODEV; - } - - data->spi = spi; - - mutex_init(&data->lock); - - // memset(data->tx, 0, MCP320X_PACKET_SIZE); - // memset(data->rx, 0, MCP320X_PACKET_SIZE); - - data->xfer.tx_buf = data->tx; - data->xfer.rx_buf = data->rx; - data->xfer.bits_per_word = 8; - data->xfer.len = MCP320X_PACKET_SIZE; - data->xfer.cs_change = 0; - data->xfer.speed_hz = 100000; - - spi_message_init_with_transfers(&data->msg, &data->xfer, 1); - - /* set drvdata */ - spi_set_drvdata(spi, data); - - printk(KERN_INFO "%s: mcp3204 probed", DRIVER_NAME); - - return 0; -} - -/* - * mcp3204_get_value - get sensor data from MCP3204 - * called by 'sensor_read' - */ -static unsigned int mcp3204_get_value(int channel) -{ - struct device *dev; - struct mcp3204_drvdata *data; - struct spi_device *spi; - char str[128]; - - unsigned int r = 0; - unsigned char c = channel & 0x03; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0) - - if (mcp320x_dev == NULL) - return 0; - dev = mcp320x_dev; - -#else - struct spi_master *master; - master = spi_busnum_to_master(mcp3204_info.bus_num); - snprintf(str, sizeof(str), "%s.%u", dev_name(&master->dev), - mcp3204_info.chip_select); - dev = bus_find_device_by_name(&spi_bus_type, NULL, str); -#endif - - spi = to_spi_device(dev); - data = (struct mcp3204_drvdata *)spi_get_drvdata(spi); - mutex_lock(&data->lock); - data->tx[0] = 1 << 2; // start bit - data->tx[0] |= 1 << 1; // Single - data->tx[1] = c << 6; // channel - data->tx[2] = 0; - - if (spi_sync(data->spi, &data->msg)) { - printk(KERN_INFO "%s: spi_sync_transfer returned non zero\n", - __func__); - } - - mutex_unlock(&data->lock); - - r = (data->rx[1] & 0xf) << 8; - r |= data->rx[2]; - - // printk(KERN_INFO "%s: get result on ch[%d] : %04d\n", __func__, - // channel, r); - - return r; -} - -/* - * spi_remove_device - remove SPI device - * called by mcp3204_init and mcp3204_exit - */ -static void spi_remove_device(struct spi_master *master, unsigned int cs) -{ - struct device *dev; - char str[128]; - - snprintf(str, sizeof(str), "%s.%u", dev_name(&master->dev), cs); - - dev = bus_find_device_by_name(&spi_bus_type, NULL, str); - // ここを参考にspi_deviceを取得するプログラムを作成する - if (dev) { - device_del(dev); - } -} - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0) -/* spiをサーチする関数 */ -static int __callback_find_mcp3204(struct device *dev, void *data) -{ - printk(KERN_INFO " device_name: %s\n", dev->driver->name); - if (mcp320x_dev == NULL && strcmp(dev->driver->name, "mcp320x") == 0) { - mcp320x_dev = dev; - mcp3204_probe(to_spi_device(dev)); - } - return 0; -} -#endif - -/* - * mcp3204_init - initialize MCP3204 - * called by 'dev_init_module' - */ -static int mcp3204_init(void) -{ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0) - bus_for_each_dev(&spi_bus_type, NULL, NULL, __callback_find_mcp3204); -#else - struct spi_master *master; - struct spi_device *spi_device; - - spi_register_driver(&mcp3204_driver); - - mcp3204_info.bus_num = SPI_BUS_NUM; - mcp3204_info.chip_select = SPI_CHIP_SELECT; - - master = spi_busnum_to_master(mcp3204_info.bus_num); - - if (!master) { - printk(KERN_ERR "%s: spi_busnum_to_master returned NULL\n", - __func__); - spi_unregister_driver(&mcp3204_driver); - return -ENODEV; - } - - spi_remove_device(master, mcp3204_info.chip_select); - - spi_device = spi_new_device(master, &mcp3204_info); - if (!spi_device) { - printk(KERN_ERR "%s: spi_new_device returned NULL\n", __func__); - spi_unregister_driver(&mcp3204_driver); - return -ENODEV; - } -#endif - - return 0; -} - -/* - * mcp3204_exit - cleanup MCP3204 - * called by dev_cleanup_module() - */ -static void mcp3204_exit(void) -{ - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0) - printk(KERN_INFO " mcp3204_exit\n"); - if (mcp320x_dev) { - mcp3204_remove(to_spi_device(mcp320x_dev)); - } -#else - struct spi_master *master; - master = spi_busnum_to_master(mcp3204_info.bus_num); - - if (master) { - spi_remove_device(master, mcp3204_info.chip_select); - } else { - printk(KERN_ERR "mcp3204 remove error\n"); - } - - spi_unregister_driver(&mcp3204_driver); -#endif -} - -static int rtcntr_i2c_create_cdev(struct rtcnt_device_info *dev_info) -{ - int minor; - int alloc_ret = 0; - int cdev_err = 0; - dev_t dev; - - /* 空いているメジャー番号を確保する */ - alloc_ret = alloc_chrdev_region(&dev, DEV_MINOR, NUM_DEV[ID_DEV_CNT], - DEVNAME_CNTR); - if (alloc_ret != 0) { - printk(KERN_ERR "alloc_chrdev_region = %d\n", alloc_ret); - return -1; - } - - /* 取得したdev( = メジャー番号 + マイナー番号) - * からメジャー番号を取得して保持しておく */ - dev_info->device_major = MAJOR(dev); - dev = MKDEV(dev_info->device_major, DEV_MINOR); - - /* cdev構造体の初期化とシステムコールハンドラテーブルの登録 */ - cdev_init(&dev_info->cdev, &dev_fops[ID_DEV_CNT]); - dev_info->cdev.owner = THIS_MODULE; - - /* このデバイスドライバ(cdev)をカーネルに登録する */ - cdev_err = cdev_add(&dev_info->cdev, dev, NUM_DEV[ID_DEV_CNT]); - if (cdev_err != 0) { - printk(KERN_ERR "cdev_add = %d\n", alloc_ret); - unregister_chrdev_region(dev, NUM_DEV[ID_DEV_CNT]); - return -1; - } - - /* このデバイスのクラス登録をする(/sys/class/mydevice/ を作る) */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) - dev_info->device_class = class_create(THIS_MODULE, DEVNAME_CNTR); -#else - dev_info->device_class = class_create(DEVNAME_CNTR); -#endif - - if (IS_ERR(dev_info->device_class)) { - printk(KERN_ERR "class_create\n"); - cdev_del(&dev_info->cdev); - unregister_chrdev_region(dev, NUM_DEV[ID_DEV_CNT]); - return -1; - } - - for (minor = DEV_MINOR; minor < DEV_MINOR + NUM_DEV[ID_DEV_CNT]; - minor++) { - - struct device *dev_ret; - dev_ret = device_create(dev_info->device_class, NULL, - MKDEV(dev_info->device_major, minor), - NULL, "rtcounter_r%d", minor); - - /* デバイスファイル作成の可否を判定 */ - if (IS_ERR(dev_ret)) { - /* デバイスファイルの作成に失敗した */ - printk(KERN_ERR "device_create failed minor = %d\n", - minor); - /* リソースリークを避けるために登録された状態cdevを削除する - */ - cdev_del(&(cdev_array[cdev_index])); - return PTR_ERR(dev_ret); - } - } - - return 0; -} - -static int rtcntl_i2c_create_cdev(struct rtcnt_device_info *dev_info) -{ - int minor; - int alloc_ret = 0; - int cdev_err = 0; - dev_t dev; - - /* 空いているメジャー番号を確保する */ - alloc_ret = alloc_chrdev_region(&dev, DEV_MINOR, NUM_DEV[ID_DEV_CNT], - DEVNAME_CNTL); - if (alloc_ret != 0) { - printk(KERN_ERR "alloc_chrdev_region = %d\n", alloc_ret); - return -1; - } - - /* 取得したdev( = メジャー番号 + マイナー番号) - * からメジャー番号を取得して保持しておく */ - dev_info->device_major = MAJOR(dev); - dev = MKDEV(dev_info->device_major, DEV_MINOR); - - /* cdev構造体の初期化とシステムコールハンドラテーブルの登録 */ - cdev_init(&dev_info->cdev, &dev_fops[ID_DEV_CNT]); - dev_info->cdev.owner = THIS_MODULE; - - /* このデバイスドライバ(cdev)をカーネルに登録する */ - cdev_err = cdev_add(&dev_info->cdev, dev, NUM_DEV[ID_DEV_CNT]); - if (cdev_err != 0) { - printk(KERN_ERR "cdev_add = %d\n", alloc_ret); - unregister_chrdev_region(dev, NUM_DEV[ID_DEV_CNT]); - return -1; - } - -/* このデバイスのクラス登録をする(/sys/class/mydevice/ を作る) */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) - dev_info->device_class = class_create(THIS_MODULE, DEVNAME_CNTL); -#else - dev_info->device_class = class_create(DEVNAME_CNTL); -#endif - - if (IS_ERR(dev_info->device_class)) { - printk(KERN_ERR "class_create\n"); - cdev_del(&dev_info->cdev); - unregister_chrdev_region(dev, NUM_DEV[ID_DEV_CNT]); - return -1; - } - - /* /sys/class/mydevice/mydevice* を作る */ - for (minor = DEV_MINOR; minor < DEV_MINOR + NUM_DEV[ID_DEV_CNT]; - minor++) { - - struct device *dev_ret; - dev_ret = device_create(dev_info->device_class, NULL, - MKDEV(dev_info->device_major, minor), - NULL, "rtcounter_l%d", minor); - - /* デバイスファイル作成の可否を判定 */ - if (IS_ERR(dev_ret)) { - /* デバイスファイルの作成に失敗した */ - printk(KERN_ERR "device_create failed minor = %d\n", - minor); - /* リソースリークを避けるために登録された状態cdevを削除する - */ - cdev_del(&(cdev_array[cdev_index])); - return PTR_ERR(dev_ret); - } - } - - return 0; -} - -#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0) -static int rtcnt_i2c_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct rtcnt_device_info *dev_info; - int msb = 0, lsb = 0; - // printk(KERN_DEBUG "%s: probing i2c device", __func__); - - /* check i2c device */ - // printk(KERN_DEBUG "%s: checking i2c device", __func__); - msb = i2c_smbus_read_byte_data(client, CNT_ADDR_MSB); - lsb = i2c_smbus_read_byte_data(client, CNT_ADDR_LSB); - if ((msb < 0) || (lsb < 0)) { - printk(KERN_INFO - "%s: rtcounter not found, or wrong i2c device probed", - DRIVER_NAME); - // printk(KERN_DEBUG "%s: addr 0x%x, msb %d, lsb %d", __func__, - // client->addr, msb, lsb); - return -ENODEV; - } - printk(KERN_INFO "%s: new i2c device probed, id.name=%s, " - "id.driver_data=%d, addr=0x%x\n", - DRIVER_NAME, id->name, (int)(id->driver_data), client->addr); - - dev_info = (struct rtcnt_device_info *)devm_kzalloc( - &client->dev, sizeof(struct rtcnt_device_info), GFP_KERNEL); - dev_info->client = client; - i2c_set_clientdata(client, dev_info); - mutex_init(&dev_info->lock); - - /* create character device */ - if ((int)(id->driver_data) == 0) { - if (rtcntl_i2c_create_cdev(dev_info)) - return -ENOMEM; - } else if ((int)(id->driver_data) == 1) { - if (rtcntr_i2c_create_cdev(dev_info)) - return -ENOMEM; - } - - return 0; -} -#else -static int rtcnt_i2c_probe(struct i2c_client *client) -{ - const struct i2c_device_id *id = i2c_client_get_device_id(client); - struct rtcnt_device_info *dev_info; - int msb = 0, lsb = 0; - // printk(KERN_DEBUG "%s: probing i2c device", __func__); - - /* check i2c device */ - // printk(KERN_DEBUG "%s: checking i2c device", __func__); - msb = i2c_smbus_read_byte_data(client, CNT_ADDR_MSB); - lsb = i2c_smbus_read_byte_data(client, CNT_ADDR_LSB); - if ((msb < 0) || (lsb < 0)) { - printk(KERN_INFO - "%s: rtcounter not found, or wrong i2c device probed", - DRIVER_NAME); - // printk(KERN_DEBUG "%s: addr 0x%x, msb %d, lsb %d", __func__, - // client->addr, msb, lsb); - return -ENODEV; - } - printk(KERN_INFO "%s: new i2c device probed, id.name=%s, " - "id.driver_data=%d, addr=0x%x\n", - DRIVER_NAME, id->name, (int)(id->driver_data), client->addr); - - dev_info = (struct rtcnt_device_info *)devm_kzalloc( - &client->dev, sizeof(struct rtcnt_device_info), GFP_KERNEL); - dev_info->client = client; - i2c_set_clientdata(client, dev_info); - mutex_init(&dev_info->lock); - - /* create character device */ - if ((int)(id->driver_data) == 0) { - if (rtcntl_i2c_create_cdev(dev_info)) - return -ENOMEM; - } else if ((int)(id->driver_data) == 1) { - if (rtcntr_i2c_create_cdev(dev_info)) - return -ENOMEM; - } - - return 0; -} -#endif - -/* - * i2c_counter_init - initialize I2C counter - * called by dev_init_module() - */ -static int i2c_counter_init(void) -{ - int retval = 0; - struct i2c_adapter *i2c_adap_l; - struct i2c_adapter *i2c_adap_r; - struct i2c_board_info i2c_board_info_l = { - I2C_BOARD_INFO(DEVNAME_CNTL, DEV_ADDR_CNTL)}; - struct i2c_board_info i2c_board_info_r = { - I2C_BOARD_INFO(DEVNAME_CNTR, DEV_ADDR_CNTR)}; - - // printk(KERN_DEBUG "%s: initializing i2c device", __func__); - retval = i2c_add_driver(&i2c_counter_driver); - if (retval != 0) { - printk(KERN_INFO "%s: failed adding i2c device", DRIVER_NAME); - return retval; - } - - /* - * 動的にデバイス実体を作成 - * (https://www.kernel.org/doc/Documentation/i2c/instantiating-devices) - */ -#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 0, 0) - // printk(KERN_DEBUG "%s: adding i2c device", __func__); - i2c_adap_l = i2c_get_adapter(1); - i2c_client_l = i2c_new_device(i2c_adap_l, &i2c_board_info_l); - i2c_put_adapter(i2c_adap_l); - // printk(KERN_DEBUG "%s: added i2c device rtcntl", __func__); - - // printk(KERN_DEBUG "%s: adding i2c device", __func__); - i2c_adap_r = i2c_get_adapter(1); - i2c_client_r = i2c_new_device(i2c_adap_r, &i2c_board_info_r); - i2c_put_adapter(i2c_adap_r); - // printk(KERN_DEBUG "%s: added i2c device rtcntr", __func__); -#else - // printk(KERN_DEBUG "%s: adding i2c device", __func__); - i2c_adap_l = i2c_get_adapter(1); - i2c_client_l = i2c_new_client_device(i2c_adap_l, &i2c_board_info_l); - i2c_put_adapter(i2c_adap_l); - // printk(KERN_DEBUG "%s: added i2c device rtcntl", __func__); - - // printk(KERN_DEBUG "%s: adding i2c device", __func__); - i2c_adap_r = i2c_get_adapter(1); - i2c_client_r = i2c_new_client_device(i2c_adap_r, &i2c_board_info_r); - i2c_put_adapter(i2c_adap_r); - // printk(KERN_DEBUG "%s: added i2c device rtcntr", __func__); -#endif - - return retval; -} - -/* - * i2c_counter_exit - cleanup I2C device - * called by dev_cleanup_module() - */ -static void i2c_counter_exit(void) -{ - /* delete I2C driver */ - i2c_del_driver(&i2c_counter_driver); - /* free memory */ - if (i2c_client_r) - i2c_unregister_device(i2c_client_r); - if (i2c_client_l) - i2c_unregister_device(i2c_client_l); -} - -static void rtcnt_i2c_delete_cdev(struct rtcnt_device_info *dev_info) -{ - dev_t dev = MKDEV(dev_info->device_major, DEV_MINOR); - int minor; - /* /sys/class/mydevice/mydevice* を削除する */ - for (minor = DEV_MINOR; minor < DEV_MINOR + NUM_DEV[ID_DEV_CNT]; - minor++) { - device_destroy(dev_info->device_class, - MKDEV(dev_info->device_major, minor)); - } - /* このデバイスのクラス登録を取り除く(/sys/class/mydevice/を削除する) */ - class_destroy(dev_info->device_class); - /* このデバイスドライバ(cdev)をカーネルから取り除く */ - cdev_del(&dev_info->cdev); - /* このデバイスドライバで使用していたメジャー番号の登録を取り除く */ - unregister_chrdev_region(dev, NUM_DEV[ID_DEV_CNT]); -} - -/* - * i2c_counter_remove - I2C pulse counter - * called when I2C pulse counter removed - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0) -static int rtcnt_i2c_remove(struct i2c_client *client) -{ - struct rtcnt_device_info *dev_info; - // printk(KERN_DEBUG "%s: removing i2c device 0x%x\n", __func__, - // client->addr); - dev_info = i2c_get_clientdata(client); - rtcnt_i2c_delete_cdev(dev_info); - printk(KERN_INFO "%s: i2c device 0x%x removed\n", DRIVER_NAME, - client->addr); - return 0; -} -#else -static void rtcnt_i2c_remove(struct i2c_client *client) -{ - struct rtcnt_device_info *dev_info; - // printk(KERN_DEBUG "%s: removing i2c device 0x%x\n", __func__, - // client->addr); - dev_info = i2c_get_clientdata(client); - rtcnt_i2c_delete_cdev(dev_info); - printk(KERN_INFO "%s: i2c device 0x%x removed\n", DRIVER_NAME, - client->addr); -} -#endif - -/* - * dev_init_module - register driver module - * called by module_init(dev_init_module) - */ -int dev_init_module(void) -{ - int retval, i; - int registered_devices = 0; - size_t size; - - /* log loding message */ - printk(KERN_INFO "%s: loading driver...\n", DRIVER_NAME); - - /* Initialize mutex lock */ - mutex_init(&lock); - - retval = i2c_counter_init(); - if (retval == 0) { - registered_devices += 2 * NUM_DEV[ID_DEV_CNT]; - } else { - printk(KERN_ALERT - "%s: i2c counter device driver register failed.\n", - DRIVER_NAME); - return retval; - } - - /* GPIOレジスタがマップ可能か調べる */ - retval = gpio_map(); - if (retval != 0) { - printk(KERN_ALERT "%s on %s: cannot use GPIO registers.\n", - __func__, DRIVER_NAME); - return -EBUSY; - } - - /* GPIO初期化 */ - // printk(KERN_DEBUG "%s: gpio initializing...\n", __func__); - rpi_gpio_function_set(LED0_BASE, RPI_GPF_OUTPUT); - rpi_gpio_function_set(LED1_BASE, RPI_GPF_OUTPUT); - rpi_gpio_function_set(LED2_BASE, RPI_GPF_OUTPUT); - rpi_gpio_function_set(LED3_BASE, RPI_GPF_OUTPUT); - - rpi_gpio_function_set(R_LED_BASE, RPI_GPF_OUTPUT); - rpi_gpio_function_set(L_LED_BASE, RPI_GPF_OUTPUT); - rpi_gpio_function_set(RF_LED_BASE, RPI_GPF_OUTPUT); - rpi_gpio_function_set(LF_LED_BASE, RPI_GPF_OUTPUT); - - rpi_gpio_function_set(BUZZER_BASE, RPI_GPF_OUTPUT); - rpi_gpio_function_set(MOTDIR_L_BASE, RPI_GPF_OUTPUT); - rpi_gpio_function_set(MOTDIR_R_BASE, RPI_GPF_OUTPUT); - rpi_gpio_function_set(MOTEN_BASE, RPI_GPF_OUTPUT); - rpi_gpio_function_set(MOTCLK_L_BASE, RPI_GPF_OUTPUT); - rpi_gpio_function_set(MOTCLK_L_BASE, RPI_GPF_OUTPUT); - - rpi_gpio_function_set(SW1_PIN, RPI_GPF_INPUT); - rpi_gpio_function_set(SW2_PIN, RPI_GPF_INPUT); - rpi_gpio_function_set(SW3_PIN, RPI_GPF_INPUT); - - rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << MOTEN_BASE); - rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << MOTDIR_L_BASE); - - rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << R_LED_BASE); - rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << L_LED_BASE); - rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << RF_LED_BASE); - rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << LF_LED_BASE); - - for (i = 0; i < 100; i++) { - rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << BUZZER_BASE); - udelay(500); - rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << BUZZER_BASE); - udelay(500); - } - - buzzer_init(); - - rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << R_LED_BASE); - rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << L_LED_BASE); - rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << RF_LED_BASE); - rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << LF_LED_BASE); - - // printk(KERN_DEBUG "%s: gpio initialized\n", __func__); - - /* cdev構造体の用意 */ - size = sizeof(struct cdev) * NUM_DEV_TOTAL; - cdev_array = (struct cdev *)kmalloc(size, GFP_KERNEL); - - /* デバイスドライバをカーネルに登録 */ - for (i = 0; i < ID_DEV_SIZE - 1; i++) { - retval = register_dev(i); - if (retval != 0) { - printk(KERN_ALERT "%s: %s register failed.\n", - DRIVER_NAME, NAME_DEV[i]); - return retval; - } - } - - retval = mcp3204_init(); - if (retval != 0) { - printk(KERN_ALERT - "%s: optical sensor driver register failed.\n", - DRIVER_NAME); - return retval; - } - - printk(KERN_INFO "%s: %d devices loaded.\n", DRIVER_NAME, - registered_devices + NUM_DEV_TOTAL); - - printk(KERN_INFO "%s: module installed at %lu\n", DRIVER_NAME, jiffies); - return 0; -} - -/* - * dev_cleanup_module - cleanup driver module - * called by module_exit(dev_cleanup_module) - */ -void cleanup_each_dev(int id_dev) -{ - int i; - dev_t devno; - dev_t devno_top; - - devno_top = MKDEV(_major_dev[id_dev], _minor_dev[id_dev]); - for (i = 0; i < NUM_DEV[id_dev]; i++) { - devno = MKDEV(_major_dev[id_dev], _minor_dev[id_dev] + i); - device_destroy(class_dev[id_dev], devno); - } - unregister_chrdev_region(devno_top, NUM_DEV[id_dev]); -} - -void dev_cleanup_module(void) -{ - int i; - - /* --- remove char device --- */ - for (i = 0; i < NUM_DEV_TOTAL; i++) { - cdev_del(&(cdev_array[i])); - } - - /* --- free device num. and remove device --- */ - for (i = 0; i < ID_DEV_SIZE - 1; i++) { - cleanup_each_dev(i); - } - - /* --- remove device node --- */ - for (i = 0; i < ID_DEV_SIZE - 1; i++) { - class_destroy(class_dev[i]); - } - - /* remove MCP3204 */ - mcp3204_exit(); - - /* remove I2C device */ - i2c_counter_exit(); - - /* free cdev memory */ - kfree(cdev_array); - gpio_unmap(); - printk(KERN_INFO "%s: module removed at %lu\n", DRIVER_NAME, jiffies); -} - -/* --- MAIN PROCESS --- */ -module_init(dev_init_module); -module_exit(dev_cleanup_module); diff --git a/src/drivers/rtmouse.h b/src/drivers/rtmouse.h index 573e762..a11c390 100644 --- a/src/drivers/rtmouse.h +++ b/src/drivers/rtmouse.h @@ -52,7 +52,7 @@ // Raspberry Pi 2 B : 2 // Raspberry Pi 3 B/A+/B+ : 2 // Raspberry Pi 4 B : 4 -#define RASPBERRYPI 4 +#define RASPBERRYPI 2 /* --- Device ID --- */ #define ID_DEV_LED 0 @@ -66,31 +66,6 @@ #define ID_DEV_CNT 8 #define ID_DEV_SIZE 9 -/* --- Device Numbers --- */ -const unsigned int NUM_DEV[ID_DEV_SIZE] = { - [ID_DEV_LED] = 4, [ID_DEV_SWITCH] = 3, [ID_DEV_SENSOR] = 1, - [ID_DEV_BUZZER] = 1, [ID_DEV_MOTORRAWR] = 1, [ID_DEV_MOTORRAWL] = 1, - [ID_DEV_MOTOREN] = 1, [ID_DEV_MOTOR] = 1, [ID_DEV_CNT] = 2}; - -/* --- Device Names --- */ -const char *NAME_DEV[ID_DEV_SIZE] = {[ID_DEV_LED] = "rtled", - [ID_DEV_SWITCH] = "rtswitch", - [ID_DEV_SENSOR] = "rtlightsensor", - [ID_DEV_BUZZER] = "rtbuzzer", - [ID_DEV_MOTORRAWR] = "rtmotor_raw_r", - [ID_DEV_MOTORRAWL] = "rtmotor_raw_l", - [ID_DEV_MOTOREN] = "rtmotoren", - [ID_DEV_MOTOR] = "rtmotor"}; - -const char *NAME_DEV_U[ID_DEV_SIZE] = {[ID_DEV_LED] = "rtled%u", - [ID_DEV_SWITCH] = "rtswitch%u", - [ID_DEV_SENSOR] = "rtlightsensor%u", - [ID_DEV_BUZZER] = "rtbuzzer%u", - [ID_DEV_MOTORRAWR] = "rtmotor_raw_r%u", - [ID_DEV_MOTORRAWL] = "rtmotor_raw_l%u", - [ID_DEV_MOTOREN] = "rtmotoren%u", - [ID_DEV_MOTOR] = "rtmotor%u"}; - #define NUM_DEV_TOTAL \ (NUM_DEV[ID_DEV_LED] + NUM_DEV[ID_DEV_SWITCH] + \ NUM_DEV[ID_DEV_SENSOR] + NUM_DEV[ID_DEV_BUZZER] + \ @@ -251,7 +226,65 @@ const char *NAME_DEV_U[ID_DEV_SIZE] = {[ID_DEV_LED] = "rtled%u", #define SIGNED_COUNT_SIZE 32767 #define MAX_PULSE_COUNT 65535 -/* -- Buffer -- */ +/* --- Buffer --- */ #define MAX_BUFLEN 64 +/* --- Variable Type definitions --- */ +/* SPI */ +struct mcp3204_drvdata { + struct spi_device *spi; + struct mutex lock; + unsigned char tx[MCP320X_PACKET_SIZE] ____cacheline_aligned; + unsigned char rx[MCP320X_PACKET_SIZE] ____cacheline_aligned; + struct spi_transfer xfer ____cacheline_aligned; + struct spi_message msg ____cacheline_aligned; +}; + +/* I2C */ +struct rtcnt_device_info { + struct cdev cdev; + unsigned int device_major; + unsigned int device_minor; + struct class *device_class; + struct i2c_client *client; + struct mutex lock; + int signed_pulse_count; + int raw_pulse_count; +}; + +/* --- used in rtmouse_dev.c --- */ +extern const char *NAME_DEV[ID_DEV_SIZE]; +extern int _major_dev[ID_DEV_SIZE]; +extern int _minor_dev[ID_DEV_SIZE]; +extern struct class *class_dev[ID_DEV_SIZE]; +extern volatile void __iomem *pwm_base; +extern volatile uint32_t *gpio_base; +extern struct mutex lock; +extern struct spi_board_info mcp3204_info; +extern struct file_operations dev_fops[ID_DEV_SIZE]; +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0) +extern struct device *mcp320x_dev; +#endif +int buzzer_init(void); +int register_dev(int id_dev); + +/* --- used in rtmouse_spi.c --- */ +int mcp3204_init(void); +void mcp3204_exit(void); + +/* --- used in rtmouse_i2c.c --- */ +extern const unsigned int NUM_DEV[ID_DEV_SIZE]; +extern struct cdev *cdev_array; +extern volatile int cdev_index; +int i2c_counter_init(void); +void i2c_counter_exit(void); + +/* --- used in rtmouse_gpio.c --- */ +int rpi_gpio_function_set(int pin, uint32_t func); +void rpi_gpio_set32(uint32_t mask, uint32_t val); +void rpi_gpio_clear32(uint32_t mask, uint32_t val); +void rpi_pwm_write32(uint32_t offset, uint32_t val); +int gpio_map(void); +int gpio_unmap(void); + #endif // RTMOUSE_H diff --git a/src/drivers/rtmouse_dev.c b/src/drivers/rtmouse_dev.c new file mode 100644 index 0000000..d124d64 --- /dev/null +++ b/src/drivers/rtmouse_dev.c @@ -0,0 +1,923 @@ +/* + * + * rtmouse_dev.c + * Define device file operations and register device + * + * Copyright (C) 2024 RT Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "rtmouse.h" + +static unsigned int motor_l_freq_is_positive = 1; +static unsigned int motor_r_freq_is_positive = 1; + +/* + * --- Device Names(+%u) --- + * used in register_dev() + */ +static const char *NAME_DEV_U[ID_DEV_SIZE] = { + [ID_DEV_LED] = "rtled%u", + [ID_DEV_SWITCH] = "rtswitch%u", + [ID_DEV_SENSOR] = "rtlightsensor%u", + [ID_DEV_BUZZER] = "rtbuzzer%u", + [ID_DEV_MOTORRAWR] = "rtmotor_raw_r%u", + [ID_DEV_MOTORRAWL] = "rtmotor_raw_l%u", + [ID_DEV_MOTOREN] = "rtmotoren%u", + [ID_DEV_MOTOR] = "rtmotor%u"}; + +/* + * i2c_counter_set - set value to I2C pulse counter + * called by rtcnt_write() + */ +static int i2c_counter_set(struct rtcnt_device_info *dev_info, int setval) +{ + int ret = 0; + int lsb = 0, msb = 0; + struct i2c_client *client = dev_info->client; + + // printk(KERN_INFO "set 0x%x = 0x%x\n", client->addr, setval); + msb = (setval >> 8) & 0xFF; + lsb = setval & 0xFF; + mutex_lock(&dev_info->lock); + // printk(KERN_INFO "set 0x%x msb = 0x%x\n", client->addr, msb); + ret = i2c_smbus_write_byte_data(client, 0x10, msb); + if (ret < 0) { + printk(KERN_ERR + "%s: Failed writing to i2c counter device, addr=0x%x\n", + __func__, client->addr); + return -ENODEV; + } + // printk(KERN_INFO "set 0x%x lsb = 0x%x\n", client->addr, lsb); + ret = i2c_smbus_write_byte_data(client, 0x11, lsb); + if (ret < 0) { + printk(KERN_ERR + "%s: Failed writing to i2c counter device, addr=0x%x\n", + __func__, client->addr); + return -ENODEV; + } + mutex_unlock(&dev_info->lock); + return ret; +} + +/* + * i2c_counter_read - get value from I2C pulse counter + * called by rtcnt_read() + */ +static int i2c_counter_read(struct rtcnt_device_info *dev_info, int *ret) +{ + int lsb = 0, msb = 0; + // printk(KERN_INFO "read 0x%x\n", client->addr); + struct i2c_client *client = dev_info->client; + mutex_lock(&dev_info->lock); + + lsb = i2c_smbus_read_byte_data(client, CNT_ADDR_LSB); + if (lsb < 0) { + printk( + KERN_ERR + "%s: Failed reading from i2c counter device, addr=0x%x\n", + __func__, client->addr); + return -ENODEV; + } + msb = i2c_smbus_read_byte_data(client, CNT_ADDR_MSB); + if (msb < 0) { + printk( + KERN_ERR + "%s: Failed reading from i2c counter device, addr=0x%x\n", + __func__, client->addr); + return -ENODEV; + } + mutex_unlock(&dev_info->lock); + + *ret = ((msb << 8) & 0xFF00) + (lsb & 0xFF); + + // printk(KERN_INFO "0x%x == 0x%x\n", client->addr, *ret); + return 0; +} + +/* + * update_signed_count - update signed pulse count of dev_info + * called by rtcnt_read() + */ +static void update_signed_count(struct rtcnt_device_info *dev_info, + int rtcnt_count) +{ + int diff_count = rtcnt_count - dev_info->raw_pulse_count; + + // カウントがMAX_PULSE_COUNTから0に変わる場合の処理 + // ただし、それ以外でもdiffが負の値になることがある + // そのため、diffが十分に大きな負の値の場合に処理する + // if(diff_count < 0) では正常に動作しない + if (diff_count < -SIGNED_COUNT_SIZE) { + diff_count += MAX_PULSE_COUNT; + } + + if (dev_info->client->addr == DEV_ADDR_CNTL) { + if (motor_l_freq_is_positive) { + dev_info->signed_pulse_count += diff_count; + } else { + dev_info->signed_pulse_count -= diff_count; + } + } else { + if (motor_r_freq_is_positive) { + dev_info->signed_pulse_count += diff_count; + } else { + dev_info->signed_pulse_count -= diff_count; + } + } + + if (dev_info->signed_pulse_count > SIGNED_COUNT_SIZE || + dev_info->signed_pulse_count < -SIGNED_COUNT_SIZE) { + dev_info->signed_pulse_count = 0; + } +} + +/* + * reset_signed_count - reset signed pulse count of dev_info + * called by rtcnt_write() + */ +static void reset_signed_count(struct rtcnt_device_info *dev_info, + int rtcnt_count) +{ + int raw_count; + + if (rtcnt_count > SIGNED_COUNT_SIZE) { + rtcnt_count = SIGNED_COUNT_SIZE; + } else if (rtcnt_count < -SIGNED_COUNT_SIZE) { + rtcnt_count = -SIGNED_COUNT_SIZE; + } + dev_info->signed_pulse_count = rtcnt_count; + i2c_counter_read(dev_info, &raw_count); + dev_info->raw_pulse_count = raw_count; +} + +/* + * mcp3204_get_value - get sensor data from MCP3204 + * called by sensor_read() + */ +static unsigned int mcp3204_get_value(int channel) +{ + struct device *dev; + struct mcp3204_drvdata *data; + struct spi_device *spi; + char str[128]; + + unsigned int r = 0; + unsigned char c = channel & 0x03; + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0) + + if (mcp320x_dev == NULL) + return 0; + dev = mcp320x_dev; + +#else + struct spi_master *master; + master = spi_busnum_to_master(mcp3204_info.bus_num); + snprintf(str, sizeof(str), "%s.%u", dev_name(&master->dev), + mcp3204_info.chip_select); + dev = bus_find_device_by_name(&spi_bus_type, NULL, str); +#endif + + spi = to_spi_device(dev); + data = (struct mcp3204_drvdata *)spi_get_drvdata(spi); + mutex_lock(&data->lock); + data->tx[0] = 1 << 2; // start bit + data->tx[0] |= 1 << 1; // Single + data->tx[1] = c << 6; // channel + data->tx[2] = 0; + + if (spi_sync(data->spi, &data->msg)) { + printk(KERN_INFO "%s: spi_sync_transfer returned non zero\n", + __func__); + } + + mutex_unlock(&data->lock); + + r = (data->rx[1] & 0xf) << 8; + r |= data->rx[2]; + + // printk(KERN_INFO "%s: get result on ch[%d] : %04d\n", __func__, + // channel, r); + + return r; +} + +/* --- GPIO Operation --- */ +/* getPWMCount function for GPIO Operation */ +static int getPWMCount(int freq) +{ + if (freq < 1) + return PWM_BASECLK; + if (freq > 10000) + return PWM_BASECLK / 10000; + + return PWM_BASECLK / freq; +} + +/* + * left motor function + * called by parseMotorCmd() and rawmotor_l_write() + */ +static void set_motor_l_freq(int freq) +{ + int dat; + + rpi_gpio_function_set(BUZZER_BASE, RPI_GPF_OUTPUT); + + // Reset uncontrollable frequency to zero. + if (abs(freq) < MOTOR_UNCONTROLLABLE_FREQ) { + freq = 0; + } + + if (freq == 0) { + rpi_gpio_function_set(MOTCLK_L_BASE, RPI_GPF_OUTPUT); + return; + } else { + rpi_gpio_function_set(MOTCLK_L_BASE, RPI_GPF_ALT0); + } + + if (freq > 0) { + motor_l_freq_is_positive = 1; + rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << MOTDIR_L_BASE); + } else { + motor_l_freq_is_positive = 0; + rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << MOTDIR_L_BASE); + freq = -freq; + } + + dat = getPWMCount(freq); + + rpi_pwm_write32(RPI_PWM_RNG1, dat); + rpi_pwm_write32(RPI_PWM_DAT1, dat >> 1); + + return; +} + +/* + * right motor function + * called by parseMotorCmd() and rawmotor_r_write() + */ +static void set_motor_r_freq(int freq) +{ + int dat; + + rpi_gpio_function_set(BUZZER_BASE, RPI_GPF_OUTPUT); + + // Reset uncontrollable frequency to zero. + if (abs(freq) < MOTOR_UNCONTROLLABLE_FREQ) { + freq = 0; + } + + if (freq == 0) { + rpi_gpio_function_set(MOTCLK_R_BASE, RPI_GPF_OUTPUT); + return; + } else { + rpi_gpio_function_set(MOTCLK_R_BASE, RPI_GPF_ALT0); + } + + if (freq > 0) { + motor_r_freq_is_positive = 1; + rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << MOTDIR_R_BASE); + } else { + motor_r_freq_is_positive = 0; + rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << MOTDIR_R_BASE); + freq = -freq; + } + + dat = getPWMCount(freq); + + rpi_pwm_write32(RPI_PWM_RNG2, dat); + rpi_pwm_write32(RPI_PWM_DAT2, dat >> 1); + + return; +} + +/* + * Parse motor command + * called by motor_write() + */ +static int parseMotorCmd(const char __user *buf, size_t count, int *ret) +{ + int r_motor_val, l_motor_val, time_val; + char *newbuf = kmalloc(sizeof(char) * count, GFP_KERNEL); + + if (copy_from_user(newbuf, buf, sizeof(char) * count)) { + kfree(newbuf); + return -EFAULT; + } + + sscanf(newbuf, "%d%d%d\n", &l_motor_val, &r_motor_val, &time_val); + + kfree(newbuf); + + mutex_lock(&lock); + + set_motor_l_freq(l_motor_val); + set_motor_r_freq(r_motor_val); + + msleep_interruptible(time_val); + + set_motor_l_freq(0); + set_motor_r_freq(0); + + mutex_unlock(&lock); + + return count; +} + +/* + * Turn On LEDs + * return 0 : device close + * called by led_write() + */ +static int led_put(int ledno) +{ + switch (ledno) { + case 0: + rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << LED0_BASE); + break; + case 1: + rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << LED1_BASE); + break; + case 2: + rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << LED2_BASE); + break; + case 3: + rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << LED3_BASE); + break; + } + return 0; +} + +/* + * Turn Off LEDs + * return 0 : device close + * called by led_write() + */ +static int led_del(int ledno) +{ + switch (ledno) { + case 0: + rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << LED0_BASE); + break; + case 1: + rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << LED1_BASE); + break; + case 2: + rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << LED2_BASE); + break; + case 3: + rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << LED3_BASE); + break; + } + + return 0; +} + +/* + * rtcnt_read - Read value from right/left pulse counter + * Read function of /dev/rtcounter_* + */ +static ssize_t rtcnt_read(struct file *filep, char __user *buf, size_t count, + loff_t *f_pos) +{ + struct rtcnt_device_info *dev_info = filep->private_data; + + unsigned char rw_buf[64]; + int buflen; + + int rtcnt_count = 0; + if (*f_pos > 0) + return 0; /* close device */ + i2c_counter_read(dev_info, &rtcnt_count); + + if (dev_info->device_minor == 1) { + update_signed_count(dev_info, rtcnt_count); + dev_info->raw_pulse_count = rtcnt_count; + rtcnt_count = dev_info->signed_pulse_count; + } else { + dev_info->raw_pulse_count = rtcnt_count; + } + + /* set sensor data to rw_buf(static buffer) */ + sprintf(rw_buf, "%d\n", rtcnt_count); + buflen = strlen(rw_buf); + count = buflen; + + /* copy data to user area */ + if (copy_to_user((void *)buf, &rw_buf, count)) { + printk(KERN_INFO "err read buffer from %s\n", rw_buf); + printk(KERN_INFO "err sample_char_read size(%zu)\n", count); + printk(KERN_INFO "sample_char_read size err(%d)\n", -EFAULT); + return -EFAULT; + } + *f_pos += count; + return count; +} + +/* + * cnt_write - Set value to right/left pulse counter + * Write function of /dev/rtcounter + */ +static ssize_t rtcnt_write(struct file *filep, const char __user *buf, + size_t count, loff_t *pos) +{ + struct rtcnt_device_info *dev_info = filep->private_data; + + int rtcnt_count = 0; + int ret; + + ret = kstrtoint_from_user(buf, count, 10, &rtcnt_count); + if (ret) { + printk(KERN_ERR "%s: error parsing string to int in %s()\n", + DRIVER_NAME, __func__); + return ret; + } + + i2c_counter_set(dev_info, rtcnt_count); + + if (dev_info->device_minor == 1) { + reset_signed_count(dev_info, rtcnt_count); + } + + printk(KERN_INFO "%s: set pulse counter value %d\n", DRIVER_NAME, + rtcnt_count); + return count; +} + +/* + * Read Push Switches + * return 0 : device close + */ +static ssize_t sw_read(struct file *filep, char __user *buf, size_t count, + loff_t *f_pos) +{ + int buflen = 0; + unsigned char rw_buf[MAX_BUFLEN]; + unsigned int ret = 0; + int len; + int index; + unsigned int pin = SW1_PIN; + uint32_t mask; + int minor = *((int *)filep->private_data); +#if RASPBERRYPI == 4 + int pullreg = GPPUPPDN1 + (pin >> 4); // SW1, 2, 3 is between GPIO16-31 + int pullshift = (pin & 0xf) << 1; + unsigned int pullbits; + unsigned int pull; +#endif + + switch (minor) { + case 0: + pin = SW1_PIN; + break; + case 1: + pin = SW2_PIN; + break; + case 2: + pin = SW3_PIN; + break; + default: + return 0; + break; + } + + if (*f_pos > 0) + return 0; /* End of file */ + +#if RASPBERRYPI == 4 + pull = GPIO_PULLUP; + pullbits = *(gpio_base + pullreg); + pullbits &= ~(3 << pullshift); + pullbits |= (pull << pullshift); + *(gpio_base + pullreg) = pullbits; +#else + // プルモード (2bit)を書き込む NONE/DOWN/UP + gpio_base[37] = GPIO_PULLUP & 0x3; // GPPUD + // ピンにクロックを供給(前後にウェイト) + msleep(1); + gpio_base[38] = 0x1 << pin; // GPPUDCLK0 + msleep(1); + // プルモード・クロック状態をクリアして終了 + gpio_base[37] = 0; + gpio_base[38] = 0; +#endif + + index = RPI_GPFSEL0_INDEX + pin / 10; + mask = ~(0x7 << ((pin % 10) * 3)); + + ret = ((gpio_base[13] & (0x01 << pin)) != 0); + sprintf(rw_buf, "%d\n", ret); + + buflen = strlen(rw_buf); + count = buflen; + len = buflen; + + if (copy_to_user((void *)buf, &rw_buf, count)) { + printk(KERN_INFO "err read buffer from ret %d\n", ret); + printk(KERN_INFO "err read buffer from %s\n", rw_buf); + printk(KERN_INFO "err sample_char_read size(%zu)\n", count); + printk(KERN_INFO "sample_char_read size err(%d)\n", -EFAULT); + return 0; + } + *f_pos += count; + + return count; +} + +/* + * Read Sensor information + * return 0 : device close + */ +static ssize_t sensor_read(struct file *filep, char __user *buf, size_t count, + loff_t *f_pos) +{ + int buflen = 0; + unsigned char rw_buf[MAX_BUFLEN]; + unsigned int ret = 0; + int len; + + // printk(KERN_INFO "new\n"); + + int usecs = 30; + int rf = 0, lf = 0, r = 0, l = 0; + int orf = 0, olf = 0, or = 0, ol = 0; + + if (*f_pos > 0) + return 0; /* End of file */ + + /* get values through MCP3204 */ + /* Right side */ + or = mcp3204_get_value(R_AD_CH); + rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << R_LED_BASE); + udelay(usecs); + r = mcp3204_get_value(R_AD_CH); + rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << R_LED_BASE); + udelay(usecs); + /* Left side */ + ol = mcp3204_get_value(L_AD_CH); + rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << L_LED_BASE); + udelay(usecs); + l = mcp3204_get_value(L_AD_CH); + rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << L_LED_BASE); + udelay(usecs); + /* Right front side */ + orf = mcp3204_get_value(RF_AD_CH); + rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << RF_LED_BASE); + udelay(usecs); + rf = mcp3204_get_value(RF_AD_CH); + rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << RF_LED_BASE); + udelay(usecs); + /* Left front side */ + olf = mcp3204_get_value(LF_AD_CH); + rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << LF_LED_BASE); + udelay(usecs); + lf = mcp3204_get_value(LF_AD_CH); + rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << LF_LED_BASE); + udelay(usecs); + + /* set sensor data to rw_buf(static buffer) */ + snprintf(rw_buf, sizeof(rw_buf), "%d %d %d %d\n", rf - orf, r - or, + l - ol, lf - olf); + buflen = strlen(rw_buf); + count = buflen; + len = buflen; + + /* copy data to user area */ + if (copy_to_user((void *)buf, &rw_buf, count)) { + printk(KERN_INFO "err read buffer from ret %d\n", ret); + printk(KERN_INFO "err read buffer from %s\n", rw_buf); + printk(KERN_INFO "err sample_char_read size(%zu)\n", count); + printk(KERN_INFO "sample_char_read size err(%d)\n", -EFAULT); + return 0; + } + + *f_pos += count; + + return count; +} + +/* --- Device File Operation --- */ +/* Open Device */ +static int dev_open(struct inode *inode, struct file *filep) +{ + int *minor = (int *)kmalloc(sizeof(int), GFP_KERNEL); + int major = MAJOR(inode->i_rdev); + *minor = MINOR(inode->i_rdev); + + filep->private_data = (void *)minor; + + const char *dev_name = filep->f_path.dentry->d_name.name; + printk(KERN_INFO "Device opened: %s, Major: %d\n", dev_name, major); + + return 0; +} + +/* Close device */ +static int dev_release(struct inode *inode, struct file *filep) +{ + kfree(filep->private_data); + return 0; +} + +static int i2c_dev_open(struct inode *inode, struct file *filep) +{ + struct rtcnt_device_info *dev_info; + dev_info = container_of(inode->i_cdev, struct rtcnt_device_info, cdev); + if (dev_info == NULL || dev_info->client == NULL) { + printk(KERN_ERR "%s: i2c dev_open failed.\n", DRIVER_NAME); + } + dev_info->device_minor = MINOR(inode->i_rdev); + filep->private_data = dev_info; + return 0; +} + +static int i2c_dev_release(struct inode *inode, struct file *filep) +{ + return 0; +} + +/* + * led_write - Trun ON/OFF LEDs + * Write function of /dev/rtled + */ +static ssize_t led_write(struct file *filep, const char __user *buf, + size_t count, loff_t *f_pos) +{ + char cval; + int ret; + int minor = *((int *)filep->private_data); + + if (count > 0) { + if (copy_from_user(&cval, buf, sizeof(char))) { + return -EFAULT; + } + switch (cval) { + case '1': + ret = led_put(minor); + break; + case '0': + ret = led_del(minor); + break; + } + return sizeof(char); + } + return 0; +} + +/* + * buzzer_write - Write buzzer frequency + * Write function of /dev/rtbuzzer + */ +static ssize_t buzzer_write(struct file *filep, const char __user *buf, + size_t count, loff_t *f_pos) +{ + int ret; + int freq, dat; + + ret = kstrtoint_from_user(buf, count, 10, &freq); + if (ret) { + printk(KERN_ERR "%s: error parsing string to int in %s()\n", + DRIVER_NAME, __func__); + return ret; + } + + if (freq != 0) { + if (freq < 1) { + freq = 1; + } + + if (freq > 20000) { + freq = 20000; + } + + rpi_gpio_function_set(BUZZER_BASE, + RPI_GPF_ALT5); // io is pwm out + dat = PWM_BASECLK / freq; + rpi_pwm_write32(RPI_PWM_RNG2, dat); + rpi_pwm_write32(RPI_PWM_DAT2, dat >> 1); + } else { + rpi_gpio_function_set(BUZZER_BASE, + RPI_GPF_OUTPUT); // io is pwm out + } + + return count; +} + +/* + * Initialize buzzer + * return 0 : device close + */ +int buzzer_init(void) +{ + + rpi_gpio_function_set(BUZZER_BASE, RPI_GPF_OUTPUT); // io is pwm out + rpi_pwm_write32(RPI_PWM_CTRL, 0x00000000); + udelay(1000); + rpi_pwm_write32(RPI_PWM_CTRL, 0x00008181); // PWM1,2 enable + + // printk(KERN_DEBUG "%s: rpi_pwm_ctrl:%08X\n", DRIVER_NAME, + // ioread32(pwm_base + RPI_PWM_CTRL)); + + return 0; +} + +/* + * rawmotor_l_write - Output frequency to the left motor + * Write function of /dev/rtmotor_raw_l + */ +static ssize_t rawmotor_l_write(struct file *filep, const char __user *buf, + size_t count, loff_t *f_pos) +{ + int freq, ret; + + ret = kstrtoint_from_user(buf, count, 10, &freq); + if (ret) { + printk(KERN_ERR "%s: error parsing string to int in %s()\n", + DRIVER_NAME, __func__); + return ret; + } + set_motor_l_freq(freq); + + return count; +} + +/* + * rawmotor_r_write - Output frequency to the right motor + * Write function of /dev/rtmotor_raw_r + */ +static ssize_t rawmotor_r_write(struct file *filep, const char __user *buf, + size_t count, loff_t *f_pos) +{ + int freq, ret; + + ret = kstrtoint_from_user(buf, count, 10, &freq); + if (ret) { + printk(KERN_ERR "%s: error parsing string to int in %s()\n", + DRIVER_NAME, __func__); + return ret; + } + + set_motor_r_freq(freq); + + return count; +} + +/* + * motoren_write - Turn ON/OFF SteppingMotor Power + * Write function of /dev/rtmotoren + */ +static ssize_t motoren_write(struct file *filep, const char __user *buf, + size_t count, loff_t *f_pos) +{ + char cval; + + if (count > 0) { + if (copy_from_user(&cval, buf, sizeof(char))) { + return -EFAULT; + } + + switch (cval) { + case '1': + rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << MOTEN_BASE); + break; + case '0': + rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << MOTEN_BASE); + break; + } + return sizeof(char); + } + return 0; +} + +/* + * motor_write - Output frequency to right and left both motors + * Write function of /dev/rtmotor + */ +static ssize_t motor_write(struct file *filep, const char __user *buf, + size_t count, loff_t *f_pos) +{ + int tmp; + int bufcnt; + bufcnt = parseMotorCmd(buf, count, &tmp); + + return bufcnt; +} + +/* + * Device File Operations + * used in register_dev(), rtcntr_i2c_create_cdev() + * and rtcntl_i2c_create_cdev() + */ +struct file_operations dev_fops[ID_DEV_SIZE] = { + [ID_DEV_LED].open = dev_open, + [ID_DEV_LED].release = dev_release, + [ID_DEV_LED].write = led_write, + [ID_DEV_SWITCH].open = dev_open, + [ID_DEV_SWITCH].read = sw_read, + [ID_DEV_SWITCH].release = dev_release, + [ID_DEV_SENSOR].open = dev_open, + [ID_DEV_SENSOR].read = sensor_read, + [ID_DEV_SENSOR].release = dev_release, + [ID_DEV_BUZZER].open = dev_open, + [ID_DEV_BUZZER].release = dev_release, + [ID_DEV_BUZZER].write = buzzer_write, + [ID_DEV_MOTORRAWR].open = dev_open, + [ID_DEV_MOTORRAWR].release = dev_release, + [ID_DEV_MOTORRAWR].write = rawmotor_r_write, + [ID_DEV_MOTORRAWL].open = dev_open, + [ID_DEV_MOTORRAWL].release = dev_release, + [ID_DEV_MOTORRAWL].write = rawmotor_l_write, + [ID_DEV_MOTOREN].open = dev_open, + [ID_DEV_MOTOREN].release = dev_release, + [ID_DEV_MOTOREN].write = motoren_write, + [ID_DEV_MOTOR].open = dev_open, + [ID_DEV_MOTOR].release = dev_release, + [ID_DEV_MOTOR].write = motor_write, + [ID_DEV_CNT].open = i2c_dev_open, + [ID_DEV_CNT].release = i2c_dev_release, + [ID_DEV_CNT].read = rtcnt_read, + [ID_DEV_CNT].write = rtcnt_write}; + +/* --- Device Driver Registration and Device File Creation --- */ +int register_dev(int id_dev) +{ + int retval; + dev_t dev; + dev_t devno; + int i; + + /* 空いているメジャー番号を使ってメジャー& + マイナー番号をカーネルに登録する */ + retval = + alloc_chrdev_region(&dev, /* 結果を格納するdev_t構造体 */ + DEV_MINOR, /* ベースマイナー番号 */ + NUM_DEV[id_dev], /* デバイスの数 */ + NAME_DEV[id_dev] /* デバイスドライバの名前 */ + ); + + if (retval < 0) { + printk(KERN_ERR "alloc_chrdev_region failed.\n"); + return retval; + } + _major_dev[id_dev] = MAJOR(dev); + + /* デバイスクラスを作成する */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) + class_dev[id_dev] = class_create(THIS_MODULE, NAME_DEV[id_dev]); +#else + class_dev[id_dev] = class_create(NAME_DEV[id_dev]); +#endif + + if (IS_ERR(class_dev[id_dev])) { + return PTR_ERR(class_dev[id_dev]); + } + + for (i = 0; i < NUM_DEV[id_dev]; i++) { + /* デバイスの数だけキャラクタデバイスを登録する */ + devno = MKDEV(_major_dev[id_dev], _minor_dev[id_dev] + i); + + /* キャラクタデバイスとしてこのモジュールをカーネルに登録する */ + cdev_init(&(cdev_array[cdev_index]), &dev_fops[id_dev]); + cdev_array[cdev_index].owner = THIS_MODULE; + if (cdev_add(&(cdev_array[cdev_index]), devno, 1) < 0) { + /* 登録に失敗した */ + printk(KERN_ERR "cdev_add failed minor = %d\n", + _minor_dev[id_dev] + i); + } else { + /* デバイスノードの作成 */ + struct device *dev_ret; + dev_ret = device_create(class_dev[id_dev], NULL, devno, + NULL, NAME_DEV_U[id_dev], + _minor_dev[id_dev] + i); + + /* デバイスファイル作成の可否を判定 */ + if (IS_ERR(dev_ret)) { + /* デバイスファイルの作成に失敗した */ + printk(KERN_ERR + "device_create failed minor = %d\n", + _minor_dev[id_dev] + i); + /* リソースリークを避けるために登録された状態cdevを削除する + */ + cdev_del(&(cdev_array[cdev_index])); + return PTR_ERR(dev_ret); + } + } + cdev_index++; + } + return 0; +} diff --git a/src/drivers/rtmouse_gpio.c b/src/drivers/rtmouse_gpio.c new file mode 100644 index 0000000..a6446e1 --- /dev/null +++ b/src/drivers/rtmouse_gpio.c @@ -0,0 +1,139 @@ +/* + * + * rtmouse_gpio.c + * GPIO driver + * + * Copyright (C) 2024 RT Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "rtmouse.h" + +static volatile void __iomem *clk_base; + +/* + * set function + * called by buzzer_init(), set_motor_l_freq(), set_motor_r_freq() and + * buzzer_write() + */ +int rpi_gpio_function_set(int pin, uint32_t func) +{ + int index = RPI_GPFSEL0_INDEX + pin / 10; + uint32_t mask = ~(0x7 << ((pin % 10) * 3)); + + gpio_base[index] = + (gpio_base[index] & mask) | ((func & 0x7) << ((pin % 10) * 3)); + + return 1; +} + +/* + * set mask and value + * called by sensor_read(), set_motor_l_freq(), set_motor_r_freq(), led_put() + * and motoren_write() + */ +void rpi_gpio_set32(uint32_t mask, uint32_t val) +{ + gpio_base[RPI_GPSET0_INDEX] = val & mask; +} + +/* + * clear mask and value + * called by sensor_read(), set_motor_l_freq(), set_motor_r_freq(), led_del() + * and motoren_write() + */ +void rpi_gpio_clear32(uint32_t mask, uint32_t val) +{ + gpio_base[RPI_GPCLR0_INDEX] = val & mask; +} + +/* + * pwm set function + * called by buzzer_init(), set_motor_l_freq(), set_motor_r_freq() + * and buzzer_write() + */ +void rpi_pwm_write32(uint32_t offset, uint32_t val) +{ + iowrite32(val, pwm_base + offset); +} + +/* --- GPIO mapping for Device Open/Close --- */ +/* + * Get gpio addresses and set them to global variables. + * - gpio_base + * - pwm_base + * - clk_base + * - clk_status + */ +int gpio_map(void) +{ + static int clk_status = 1; + +#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 0, 0) + if (gpio_base == NULL) { + gpio_base = ioremap_nocache(RPI_GPIO_BASE, RPI_GPIO_SIZE); + } + + if (pwm_base == NULL) { + pwm_base = ioremap_nocache(RPI_PWM_BASE, RPI_PWM_SIZE); + } + + if (clk_base == NULL) { + clk_base = ioremap_nocache(RPI_CLK_BASE, RPI_CLK_SIZE); + } +#else + if (gpio_base == NULL) { + gpio_base = ioremap(RPI_GPIO_BASE, RPI_GPIO_SIZE); + } + + if (pwm_base == NULL) { + pwm_base = ioremap(RPI_PWM_BASE, RPI_PWM_SIZE); + } + + if (clk_base == NULL) { + clk_base = ioremap(RPI_CLK_BASE, RPI_CLK_SIZE); + } +#endif + + /* kill */ + if (clk_status == 1) { + iowrite32(0x5a000000 | (1 << 5), clk_base + CLK_PWM_INDEX); + udelay(1000); + + /* clk set */ + iowrite32(0x5a000000 | (2 << 12), clk_base + CLK_PWMDIV_INDEX); + iowrite32(0x5a000011, clk_base + CLK_PWM_INDEX); + + udelay(1000); /* wait for 1msec */ + + clk_status = 0; + } + + return 0; +} + +/* Unmap GPIO addresses */ +int gpio_unmap(void) +{ + iounmap(gpio_base); + iounmap(pwm_base); + iounmap(clk_base); + + gpio_base = NULL; + pwm_base = NULL; + clk_base = NULL; + return 0; +} diff --git a/src/drivers/rtmouse_i2c.c b/src/drivers/rtmouse_i2c.c new file mode 100644 index 0000000..a63acee --- /dev/null +++ b/src/drivers/rtmouse_i2c.c @@ -0,0 +1,412 @@ +/* + * + * rtmouse_i2c.c + * I2C driver + * + * Copyright (C) 2024 RT Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "rtmouse.h" + +/* --- Function Declarations --- */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0) +static int rtcnt_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id); +#else +static int rtcnt_i2c_probe(struct i2c_client *client); +#endif + +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0) +static int rtcnt_i2c_remove(struct i2c_client *client); +#else +static void rtcnt_i2c_remove(struct i2c_client *client); +#endif + +// used in i2c_counter_init() and i2c_counter_exit() +static struct i2c_client *i2c_client_r = NULL; +static struct i2c_client *i2c_client_l = NULL; + +/* + * I2C Device ID + * used in i2c_counter_driver + */ +static struct i2c_device_id i2c_counter_id[] = { + {DEVNAME_CNTL, 0}, + {DEVNAME_CNTR, 1}, + {}, +}; + +/* + * I2C Dirver Info + * used in i2c_counter_init() and i2c_counter_exit() + */ +static struct i2c_driver i2c_counter_driver = { + .driver = + { + .name = "rtcounter", + .owner = THIS_MODULE, + }, + .id_table = i2c_counter_id, + .probe = rtcnt_i2c_probe, + .remove = rtcnt_i2c_remove, +}; + +/* -- Device Addition -- */ +MODULE_DEVICE_TABLE(i2c, i2c_counter_id); + +static int rtcntr_i2c_create_cdev(struct rtcnt_device_info *dev_info) +{ + int minor; + int alloc_ret = 0; + int cdev_err = 0; + dev_t dev; + + /* 空いているメジャー番号を確保する */ + alloc_ret = alloc_chrdev_region(&dev, DEV_MINOR, NUM_DEV[ID_DEV_CNT], + DEVNAME_CNTR); + if (alloc_ret != 0) { + printk(KERN_ERR "alloc_chrdev_region = %d\n", alloc_ret); + return -1; + } + + /* 取得したdev( = メジャー番号 + マイナー番号) + * からメジャー番号を取得して保持しておく */ + dev_info->device_major = MAJOR(dev); + dev = MKDEV(dev_info->device_major, DEV_MINOR); + + /* cdev構造体の初期化とシステムコールハンドラテーブルの登録 */ + cdev_init(&dev_info->cdev, &dev_fops[ID_DEV_CNT]); + dev_info->cdev.owner = THIS_MODULE; + + /* このデバイスドライバ(cdev)をカーネルに登録する */ + cdev_err = cdev_add(&dev_info->cdev, dev, NUM_DEV[ID_DEV_CNT]); + if (cdev_err != 0) { + printk(KERN_ERR "cdev_add = %d\n", alloc_ret); + unregister_chrdev_region(dev, NUM_DEV[ID_DEV_CNT]); + return -1; + } + + /* このデバイスのクラス登録をする(/sys/class/mydevice/ を作る) */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) + dev_info->device_class = class_create(THIS_MODULE, DEVNAME_CNTR); +#else + dev_info->device_class = class_create(DEVNAME_CNTR); +#endif + + if (IS_ERR(dev_info->device_class)) { + printk(KERN_ERR "class_create\n"); + cdev_del(&dev_info->cdev); + unregister_chrdev_region(dev, NUM_DEV[ID_DEV_CNT]); + return -1; + } + + for (minor = DEV_MINOR; minor < DEV_MINOR + NUM_DEV[ID_DEV_CNT]; + minor++) { + + struct device *dev_ret; + dev_ret = device_create(dev_info->device_class, NULL, + MKDEV(dev_info->device_major, minor), + NULL, "rtcounter_r%d", minor); + + /* デバイスファイル作成の可否を判定 */ + if (IS_ERR(dev_ret)) { + /* デバイスファイルの作成に失敗した */ + printk(KERN_ERR "device_create failed minor = %d\n", + minor); + /* リソースリークを避けるために登録された状態cdevを削除する + */ + cdev_del(&(cdev_array[cdev_index])); + return PTR_ERR(dev_ret); + } + } + + return 0; +} + +// called by rtcnt_i2c_probe() +static int rtcntl_i2c_create_cdev(struct rtcnt_device_info *dev_info) +{ + int minor; + int alloc_ret = 0; + int cdev_err = 0; + dev_t dev; + + /* 空いているメジャー番号を確保する */ + alloc_ret = alloc_chrdev_region(&dev, DEV_MINOR, NUM_DEV[ID_DEV_CNT], + DEVNAME_CNTL); + if (alloc_ret != 0) { + printk(KERN_ERR "alloc_chrdev_region = %d\n", alloc_ret); + return -1; + } + + /* 取得したdev( = メジャー番号 + マイナー番号) + * からメジャー番号を取得して保持しておく */ + dev_info->device_major = MAJOR(dev); + dev = MKDEV(dev_info->device_major, DEV_MINOR); + + /* cdev構造体の初期化とシステムコールハンドラテーブルの登録 */ + cdev_init(&dev_info->cdev, &dev_fops[ID_DEV_CNT]); + dev_info->cdev.owner = THIS_MODULE; + + /* このデバイスドライバ(cdev)をカーネルに登録する */ + cdev_err = cdev_add(&dev_info->cdev, dev, NUM_DEV[ID_DEV_CNT]); + if (cdev_err != 0) { + printk(KERN_ERR "cdev_add = %d\n", alloc_ret); + unregister_chrdev_region(dev, NUM_DEV[ID_DEV_CNT]); + return -1; + } + +/* このデバイスのクラス登録をする(/sys/class/mydevice/ を作る) */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) + dev_info->device_class = class_create(THIS_MODULE, DEVNAME_CNTL); +#else + dev_info->device_class = class_create(DEVNAME_CNTL); +#endif + + if (IS_ERR(dev_info->device_class)) { + printk(KERN_ERR "class_create\n"); + cdev_del(&dev_info->cdev); + unregister_chrdev_region(dev, NUM_DEV[ID_DEV_CNT]); + return -1; + } + + /* /sys/class/mydevice/mydevice* を作る */ + for (minor = DEV_MINOR; minor < DEV_MINOR + NUM_DEV[ID_DEV_CNT]; + minor++) { + + struct device *dev_ret; + dev_ret = device_create(dev_info->device_class, NULL, + MKDEV(dev_info->device_major, minor), + NULL, "rtcounter_l%d", minor); + + /* デバイスファイル作成の可否を判定 */ + if (IS_ERR(dev_ret)) { + /* デバイスファイルの作成に失敗した */ + printk(KERN_ERR "device_create failed minor = %d\n", + minor); + /* リソースリークを避けるために登録された状態cdevを削除する + */ + cdev_del(&(cdev_array[cdev_index])); + return PTR_ERR(dev_ret); + } + } + + return 0; +} + +// called by rtcnt_i2c_remove() +static void rtcnt_i2c_delete_cdev(struct rtcnt_device_info *dev_info) +{ + dev_t dev = MKDEV(dev_info->device_major, DEV_MINOR); + int minor; + /* /sys/class/mydevice/mydevice* を削除する */ + for (minor = DEV_MINOR; minor < DEV_MINOR + NUM_DEV[ID_DEV_CNT]; + minor++) { + device_destroy(dev_info->device_class, + MKDEV(dev_info->device_major, minor)); + } + /* このデバイスのクラス登録を取り除く(/sys/class/mydevice/を削除する) */ + class_destroy(dev_info->device_class); + /* このデバイスドライバ(cdev)をカーネルから取り除く */ + cdev_del(&dev_info->cdev); + /* このデバイスドライバで使用していたメジャー番号の登録を取り除く */ + unregister_chrdev_region(dev, NUM_DEV[ID_DEV_CNT]); +} + +// called by i2c_counter_driver() +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 2, 0) +static int rtcnt_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct rtcnt_device_info *dev_info; + int msb = 0, lsb = 0; + // printk(KERN_DEBUG "%s: probing i2c device", __func__); + + /* check i2c device */ + // printk(KERN_DEBUG "%s: checking i2c device", __func__); + msb = i2c_smbus_read_byte_data(client, CNT_ADDR_MSB); + lsb = i2c_smbus_read_byte_data(client, CNT_ADDR_LSB); + if ((msb < 0) || (lsb < 0)) { + printk(KERN_INFO + "%s: rtcounter not found, or wrong i2c device probed", + DRIVER_NAME); + // printk(KERN_DEBUG "%s: addr 0x%x, msb %d, lsb %d", __func__, + // client->addr, msb, lsb); + return -ENODEV; + } + printk(KERN_INFO "%s: new i2c device probed, id.name=%s, " + "id.driver_data=%d, addr=0x%x\n", + DRIVER_NAME, id->name, (int)(id->driver_data), client->addr); + + dev_info = (struct rtcnt_device_info *)devm_kzalloc( + &client->dev, sizeof(struct rtcnt_device_info), GFP_KERNEL); + dev_info->client = client; + i2c_set_clientdata(client, dev_info); + mutex_init(&dev_info->lock); + + /* create character device */ + if ((int)(id->driver_data) == 0) { + if (rtcntl_i2c_create_cdev(dev_info)) + return -ENOMEM; + } else if ((int)(id->driver_data) == 1) { + if (rtcntr_i2c_create_cdev(dev_info)) + return -ENOMEM; + } + + return 0; +} +#else +static int rtcnt_i2c_probe(struct i2c_client *client) +{ + const struct i2c_device_id *id = i2c_client_get_device_id(client); + struct rtcnt_device_info *dev_info; + int msb = 0, lsb = 0; + // printk(KERN_DEBUG "%s: probing i2c device", __func__); + + /* check i2c device */ + // printk(KERN_DEBUG "%s: checking i2c device", __func__); + msb = i2c_smbus_read_byte_data(client, CNT_ADDR_MSB); + lsb = i2c_smbus_read_byte_data(client, CNT_ADDR_LSB); + if ((msb < 0) || (lsb < 0)) { + printk(KERN_INFO + "%s: rtcounter not found, or wrong i2c device probed", + DRIVER_NAME); + // printk(KERN_DEBUG "%s: addr 0x%x, msb %d, lsb %d", __func__, + // client->addr, msb, lsb); + return -ENODEV; + } + printk(KERN_INFO "%s: new i2c device probed, id.name=%s, " + "id.driver_data=%d, addr=0x%x\n", + DRIVER_NAME, id->name, (int)(id->driver_data), client->addr); + + dev_info = (struct rtcnt_device_info *)devm_kzalloc( + &client->dev, sizeof(struct rtcnt_device_info), GFP_KERNEL); + dev_info->client = client; + i2c_set_clientdata(client, dev_info); + mutex_init(&dev_info->lock); + + /* create character device */ + if ((int)(id->driver_data) == 0) { + if (rtcntl_i2c_create_cdev(dev_info)) + return -ENOMEM; + } else if ((int)(id->driver_data) == 1) { + if (rtcntr_i2c_create_cdev(dev_info)) + return -ENOMEM; + } + + return 0; +} +#endif + +/* + * i2c_counter_remove - I2C pulse counter + * called when I2C pulse counter removed + * called by i2c_counter_driver() + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 1, 0) +static int rtcnt_i2c_remove(struct i2c_client *client) +{ + struct rtcnt_device_info *dev_info; + // printk(KERN_DEBUG "%s: removing i2c device 0x%x\n", __func__, + // client->addr); + dev_info = i2c_get_clientdata(client); + rtcnt_i2c_delete_cdev(dev_info); + printk(KERN_INFO "%s: i2c device 0x%x removed\n", DRIVER_NAME, + client->addr); + return 0; +} +#else +static void rtcnt_i2c_remove(struct i2c_client *client) +{ + struct rtcnt_device_info *dev_info; + // printk(KERN_DEBUG "%s: removing i2c device 0x%x\n", __func__, + // client->addr); + dev_info = i2c_get_clientdata(client); + rtcnt_i2c_delete_cdev(dev_info); + printk(KERN_INFO "%s: i2c device 0x%x removed\n", DRIVER_NAME, + client->addr); +} +#endif + +/* + * i2c_counter_init - initialize I2C counter + * called by dev_init_module() + */ +int i2c_counter_init(void) +{ + int retval = 0; + struct i2c_adapter *i2c_adap_l; + struct i2c_adapter *i2c_adap_r; + struct i2c_board_info i2c_board_info_l = { + I2C_BOARD_INFO(DEVNAME_CNTL, DEV_ADDR_CNTL)}; + struct i2c_board_info i2c_board_info_r = { + I2C_BOARD_INFO(DEVNAME_CNTR, DEV_ADDR_CNTR)}; + + // printk(KERN_DEBUG "%s: initializing i2c device", __func__); + retval = i2c_add_driver(&i2c_counter_driver); + if (retval != 0) { + printk(KERN_INFO "%s: failed adding i2c device", DRIVER_NAME); + return retval; + } + + /* + * 動的にデバイス実体を作成 + * (https://www.kernel.org/doc/Documentation/i2c/instantiating-devices) + */ +#if LINUX_VERSION_CODE <= KERNEL_VERSION(5, 0, 0) + // printk(KERN_DEBUG "%s: adding i2c device", __func__); + i2c_adap_l = i2c_get_adapter(1); + i2c_client_l = i2c_new_device(i2c_adap_l, &i2c_board_info_l); + i2c_put_adapter(i2c_adap_l); + // printk(KERN_DEBUG "%s: added i2c device rtcntl", __func__); + + // printk(KERN_DEBUG "%s: adding i2c device", __func__); + i2c_adap_r = i2c_get_adapter(1); + i2c_client_r = i2c_new_device(i2c_adap_r, &i2c_board_info_r); + i2c_put_adapter(i2c_adap_r); + // printk(KERN_DEBUG "%s: added i2c device rtcntr", __func__); +#else + // printk(KERN_DEBUG "%s: adding i2c device", __func__); + i2c_adap_l = i2c_get_adapter(1); + i2c_client_l = i2c_new_client_device(i2c_adap_l, &i2c_board_info_l); + i2c_put_adapter(i2c_adap_l); + // printk(KERN_DEBUG "%s: added i2c device rtcntl", __func__); + + // printk(KERN_DEBUG "%s: adding i2c device", __func__); + i2c_adap_r = i2c_get_adapter(1); + i2c_client_r = i2c_new_client_device(i2c_adap_r, &i2c_board_info_r); + i2c_put_adapter(i2c_adap_r); + // printk(KERN_DEBUG "%s: added i2c device rtcntr", __func__); +#endif + + return retval; +} + +/* + * i2c_counter_exit - cleanup I2C device + * called by dev_cleanup_module() + */ +void i2c_counter_exit(void) +{ + /* delete I2C driver */ + i2c_del_driver(&i2c_counter_driver); + /* free memory */ + if (i2c_client_r) + i2c_unregister_device(i2c_client_r); + if (i2c_client_l) + i2c_unregister_device(i2c_client_l); +} diff --git a/src/drivers/rtmouse_main.c b/src/drivers/rtmouse_main.c new file mode 100644 index 0000000..df071f5 --- /dev/null +++ b/src/drivers/rtmouse_main.c @@ -0,0 +1,259 @@ +/* + * + * rtmouse_main.c + * Raspberry Pi Mouse device driver + * + * Version: 3.3.3 + * + * Copyright (C) 2015-2024 RT Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "rtmouse.h" + +MODULE_AUTHOR("RT Corporation"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("3.3.3"); +MODULE_DESCRIPTION("Raspberry Pi Mouse device driver"); + +/* + * --- Device Numbers --- + * used in rtmouse_i2c.c, dev_init_module() + * and cleanup_each_dev() + */ +const unsigned int NUM_DEV[ID_DEV_SIZE] = { + [ID_DEV_LED] = 4, [ID_DEV_SWITCH] = 3, [ID_DEV_SENSOR] = 1, + [ID_DEV_BUZZER] = 1, [ID_DEV_MOTORRAWR] = 1, [ID_DEV_MOTORRAWL] = 1, + [ID_DEV_MOTOREN] = 1, [ID_DEV_MOTOR] = 1, [ID_DEV_CNT] = 2}; + +/* + * --- Device Names --- + * used in rtmouse_dev.c and dev_init_module() + */ +const char *NAME_DEV[ID_DEV_SIZE] = {[ID_DEV_LED] = "rtled", + [ID_DEV_SWITCH] = "rtswitch", + [ID_DEV_SENSOR] = "rtlightsensor", + [ID_DEV_BUZZER] = "rtbuzzer", + [ID_DEV_MOTORRAWR] = "rtmotor_raw_r", + [ID_DEV_MOTORRAWL] = "rtmotor_raw_l", + [ID_DEV_MOTOREN] = "rtmotoren", + [ID_DEV_MOTOR] = "rtmotor"}; + +// used in by rtmouse_dev.c and cleanup_each_dev() +int _major_dev[ID_DEV_SIZE] = { + [ID_DEV_LED] = DEV_MAJOR, [ID_DEV_SWITCH] = DEV_MAJOR, + [ID_DEV_SENSOR] = DEV_MAJOR, [ID_DEV_BUZZER] = DEV_MAJOR, + [ID_DEV_MOTORRAWR] = DEV_MAJOR, [ID_DEV_MOTORRAWL] = DEV_MAJOR, + [ID_DEV_MOTOREN] = DEV_MAJOR, [ID_DEV_MOTOR] = DEV_MAJOR}; + +// used in rtmouse_dev.c and cleanup_each_dev() +int _minor_dev[ID_DEV_SIZE] = { + [ID_DEV_LED] = DEV_MINOR, [ID_DEV_SWITCH] = DEV_MINOR, + [ID_DEV_SENSOR] = DEV_MINOR, [ID_DEV_BUZZER] = DEV_MINOR, + [ID_DEV_MOTORRAWR] = DEV_MINOR, [ID_DEV_MOTORRAWL] = DEV_MINOR, + [ID_DEV_MOTOREN] = DEV_MINOR, [ID_DEV_MOTOR] = DEV_MINOR}; + +/* + * --- General Options --- + * used in rtmouse_dev.c and dev_cleanup_module() + */ +struct class *class_dev[ID_DEV_SIZE] = { + [ID_DEV_LED] = NULL, [ID_DEV_SWITCH] = NULL, + [ID_DEV_SENSOR] = NULL, [ID_DEV_BUZZER] = NULL, + [ID_DEV_MOTORRAWR] = NULL, [ID_DEV_MOTORRAWL] = NULL, + [ID_DEV_MOTOREN] = NULL, [ID_DEV_MOTOR] = NULL}; + +// used in rtmouse_i2c.c and dev_cleanup_module() +struct cdev *cdev_array = NULL; + +// used in rtmouse_i2c.c +volatile int cdev_index = 0; + +// used in rtmouse_dev.c and rtmouse_gpio.c +volatile void __iomem *pwm_base; +volatile uint32_t *gpio_base; + +// used in rtmouse_dev.c, rtmouse_i2c.c and rtmouse_spi.c +struct mutex lock; + +/* --- Static variables --- */ +// used in rtmouse_dev.c and rtmouse_spi.c +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0) +struct device *mcp320x_dev; +#endif + +/* + * dev_init_module - register driver module + * called by module_init(dev_init_module) + */ +static int dev_init_module(void) +{ + int retval, i; + int registered_devices = 0; + size_t size; + + /* log loding message */ + printk(KERN_INFO "%s: loading driver...\n", DRIVER_NAME); + + /* Initialize mutex lock */ + mutex_init(&lock); + + retval = i2c_counter_init(); + if (retval == 0) { + registered_devices += 2 * NUM_DEV[ID_DEV_CNT]; + } else { + printk(KERN_ALERT + "%s: i2c counter device driver register failed.\n", + DRIVER_NAME); + return retval; + } + + /* GPIOレジスタがマップ可能か調べる */ + retval = gpio_map(); + if (retval != 0) { + printk(KERN_ALERT "%s on %s: cannot use GPIO registers.\n", + __func__, DRIVER_NAME); + return -EBUSY; + } + + /* GPIO初期化 */ + // printk(KERN_DEBUG "%s: gpio initializing...\n", __func__); + rpi_gpio_function_set(LED0_BASE, RPI_GPF_OUTPUT); + rpi_gpio_function_set(LED1_BASE, RPI_GPF_OUTPUT); + rpi_gpio_function_set(LED2_BASE, RPI_GPF_OUTPUT); + rpi_gpio_function_set(LED3_BASE, RPI_GPF_OUTPUT); + + rpi_gpio_function_set(R_LED_BASE, RPI_GPF_OUTPUT); + rpi_gpio_function_set(L_LED_BASE, RPI_GPF_OUTPUT); + rpi_gpio_function_set(RF_LED_BASE, RPI_GPF_OUTPUT); + rpi_gpio_function_set(LF_LED_BASE, RPI_GPF_OUTPUT); + + rpi_gpio_function_set(BUZZER_BASE, RPI_GPF_OUTPUT); + rpi_gpio_function_set(MOTDIR_L_BASE, RPI_GPF_OUTPUT); + rpi_gpio_function_set(MOTDIR_R_BASE, RPI_GPF_OUTPUT); + rpi_gpio_function_set(MOTEN_BASE, RPI_GPF_OUTPUT); + rpi_gpio_function_set(MOTCLK_L_BASE, RPI_GPF_OUTPUT); + rpi_gpio_function_set(MOTCLK_L_BASE, RPI_GPF_OUTPUT); + + rpi_gpio_function_set(SW1_PIN, RPI_GPF_INPUT); + rpi_gpio_function_set(SW2_PIN, RPI_GPF_INPUT); + rpi_gpio_function_set(SW3_PIN, RPI_GPF_INPUT); + + rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << MOTEN_BASE); + rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << MOTDIR_L_BASE); + + rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << R_LED_BASE); + rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << L_LED_BASE); + rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << RF_LED_BASE); + rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << LF_LED_BASE); + + for (i = 0; i < 100; i++) { + rpi_gpio_set32(RPI_GPIO_P2MASK, 1 << BUZZER_BASE); + udelay(500); + rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << BUZZER_BASE); + udelay(500); + } + + buzzer_init(); + + rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << R_LED_BASE); + rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << L_LED_BASE); + rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << RF_LED_BASE); + rpi_gpio_clear32(RPI_GPIO_P2MASK, 1 << LF_LED_BASE); + + // printk(KERN_DEBUG "%s: gpio initialized\n", __func__); + + /* cdev構造体の用意 */ + size = sizeof(struct cdev) * NUM_DEV_TOTAL; + cdev_array = (struct cdev *)kmalloc(size, GFP_KERNEL); + + /* デバイスドライバをカーネルに登録 */ + for (i = 0; i < ID_DEV_SIZE - 1; i++) { + retval = register_dev(i); + if (retval != 0) { + printk(KERN_ALERT "%s: %s register failed.\n", + DRIVER_NAME, NAME_DEV[i]); + return retval; + } + } + + retval = mcp3204_init(); + if (retval != 0) { + printk(KERN_ALERT + "%s: optical sensor driver register failed.\n", + DRIVER_NAME); + return retval; + } + + printk(KERN_INFO "%s: %d devices loaded.\n", DRIVER_NAME, + registered_devices + NUM_DEV_TOTAL); + + printk(KERN_INFO "%s: module installed at %lu\n", DRIVER_NAME, jiffies); + return 0; +} + +/* + * dev_cleanup_module - cleanup driver module + * called by module_exit(dev_cleanup_module) + */ +static void cleanup_each_dev(int id_dev) +{ + int i; + dev_t devno; + dev_t devno_top; + + devno_top = MKDEV(_major_dev[id_dev], _minor_dev[id_dev]); + for (i = 0; i < NUM_DEV[id_dev]; i++) { + devno = MKDEV(_major_dev[id_dev], _minor_dev[id_dev] + i); + device_destroy(class_dev[id_dev], devno); + } + unregister_chrdev_region(devno_top, NUM_DEV[id_dev]); +} + +static void dev_cleanup_module(void) +{ + int i; + + /* --- remove char device --- */ + for (i = 0; i < NUM_DEV_TOTAL; i++) { + cdev_del(&(cdev_array[i])); + } + + /* --- free device num. and remove device --- */ + for (i = 0; i < ID_DEV_SIZE - 1; i++) { + cleanup_each_dev(i); + } + + /* --- remove device node --- */ + for (i = 0; i < ID_DEV_SIZE - 1; i++) { + class_destroy(class_dev[i]); + } + + /* remove MCP3204 */ + mcp3204_exit(); + + /* remove I2C device */ + i2c_counter_exit(); + + /* free cdev memory */ + kfree(cdev_array); + gpio_unmap(); + printk(KERN_INFO "%s: module removed at %lu\n", DRIVER_NAME, jiffies); +} + +/* --- MAIN PROCESS --- */ +module_init(dev_init_module); +module_exit(dev_cleanup_module); diff --git a/src/drivers/rtmouse_spi.c b/src/drivers/rtmouse_spi.c new file mode 100644 index 0000000..e5f8db2 --- /dev/null +++ b/src/drivers/rtmouse_spi.c @@ -0,0 +1,245 @@ +/* + * + * rtmouse_spi.c + * SPI driver + * + * Copyright (C) 2024 RT Corporation + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301, USA. + */ + +#include "rtmouse.h" + +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) +static int mcp3204_remove(struct spi_device *spi); +#else +static void mcp3204_remove(struct spi_device *spi); +#endif +static int mcp3204_probe(struct spi_device *spi); + +/* + * SPI device ID + * used in mcp3204_driver + */ +static struct spi_device_id mcp3204_id[] = { + {"mcp3204", 0}, + {}, +}; + +/* + * SPI Info + * used in mcp3204_probe(), mcp3204_init(), mcp3204_exit() + * and mcp3204_get_value() + */ +struct spi_board_info mcp3204_info = { + .modalias = "mcp3204", + .max_speed_hz = 100000, + .bus_num = 0, + .chip_select = 0, + .mode = SPI_MODE_3, +}; + +/* + * SPI Dirver Info + * used in mcp3204_init() and mcp3204_exit() + */ +static struct spi_driver mcp3204_driver = { + .driver = + { + .name = DEVNAME_SENSOR, + .owner = THIS_MODULE, + }, + .id_table = mcp3204_id, + .probe = mcp3204_probe, + .remove = mcp3204_remove, +}; + +/* -- Device Addition -- */ +MODULE_DEVICE_TABLE(spi, mcp3204_id); + +/* + * mcp3204_remove - remove function lined with spi_dirver + * used in mcp3204_driver and mcp3204_exit() + */ +#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 18, 0) +static int mcp3204_remove(struct spi_device *spi) +{ + struct mcp3204_drvdata *data; + /* get drvdata */ + data = (struct mcp3204_drvdata *)spi_get_drvdata(spi); + /* free kernel memory */ + kfree(data); + printk(KERN_INFO "%s: mcp3204 removed\n", DRIVER_NAME); + return 0; +} +#else +static void mcp3204_remove(struct spi_device *spi) +{ + struct mcp3204_drvdata *data; + /* get drvdata */ + data = (struct mcp3204_drvdata *)spi_get_drvdata(spi); + /* free kernel memory */ + kfree(data); + printk(KERN_INFO "%s: mcp3204 removed\n", DRIVER_NAME); +} +#endif + +/* + * mcp3204_probe - probe function lined with spi_dirver + * used in mcp3204_driver and __callback_find_mcp3204() + */ +static int mcp3204_probe(struct spi_device *spi) +{ + struct mcp3204_drvdata *data; + + spi->max_speed_hz = mcp3204_info.max_speed_hz; + spi->mode = mcp3204_info.mode; + spi->bits_per_word = 8; + + if (spi_setup(spi)) { + printk(KERN_ERR "%s:spi_setup failed!\n", __func__); + return -ENODEV; + } + + /* alloc kernel memory */ + data = kzalloc(sizeof(struct mcp3204_drvdata), GFP_KERNEL); + if (data == NULL) { + printk(KERN_ERR "%s:kzalloc() failed!\n", __func__); + return -ENODEV; + } + + data->spi = spi; + + mutex_init(&data->lock); + + // memset(data->tx, 0, MCP320X_PACKET_SIZE); + // memset(data->rx, 0, MCP320X_PACKET_SIZE); + + data->xfer.tx_buf = data->tx; + data->xfer.rx_buf = data->rx; + data->xfer.bits_per_word = 8; + data->xfer.len = MCP320X_PACKET_SIZE; + data->xfer.cs_change = 0; + data->xfer.speed_hz = 100000; + + spi_message_init_with_transfers(&data->msg, &data->xfer, 1); + + /* set drvdata */ + spi_set_drvdata(spi, data); + + printk(KERN_INFO "%s: mcp3204 probed", DRIVER_NAME); + + return 0; +} + +/* + * spi_remove_device - remove SPI device + * called by mcp3204_init() and mcp3204_exit() + */ +static void spi_remove_device(struct spi_master *master, unsigned int cs) +{ + struct device *dev; + char str[128]; + + snprintf(str, sizeof(str), "%s.%u", dev_name(&master->dev), cs); + + dev = bus_find_device_by_name(&spi_bus_type, NULL, str); + // ここを参考にspi_deviceを取得するプログラムを作成する + if (dev) { + device_del(dev); + } +} + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0) +/* + * spiをサーチする関数 + * used in mcp3204_init() + */ +static int __callback_find_mcp3204(struct device *dev, void *data) +{ + printk(KERN_INFO " device_name: %s\n", dev->driver->name); + if (mcp320x_dev == NULL && strcmp(dev->driver->name, "mcp320x") == 0) { + mcp320x_dev = dev; + mcp3204_probe(to_spi_device(dev)); + } + return 0; +} +#endif + +/* + * mcp3204_init - initialize MCP3204 + * called by dev_init_module() + */ +int mcp3204_init(void) +{ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0) + bus_for_each_dev(&spi_bus_type, NULL, NULL, __callback_find_mcp3204); +#else + struct spi_master *master; + struct spi_device *spi_device; + + spi_register_driver(&mcp3204_driver); + + mcp3204_info.bus_num = SPI_BUS_NUM; + mcp3204_info.chip_select = SPI_CHIP_SELECT; + + master = spi_busnum_to_master(mcp3204_info.bus_num); + + if (!master) { + printk(KERN_ERR "%s: spi_busnum_to_master returned NULL\n", + __func__); + spi_unregister_driver(&mcp3204_driver); + return -ENODEV; + } + + spi_remove_device(master, mcp3204_info.chip_select); + + spi_device = spi_new_device(master, &mcp3204_info); + if (!spi_device) { + printk(KERN_ERR "%s: spi_new_device returned NULL\n", __func__); + spi_unregister_driver(&mcp3204_driver); + return -ENODEV; + } +#endif + + return 0; +} + +/* + * mcp3204_exit - cleanup MCP3204 + * called by dev_cleanup_module() + */ +void mcp3204_exit(void) +{ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 16, 0) + printk(KERN_INFO " mcp3204_exit\n"); + if (mcp320x_dev) { + mcp3204_remove(to_spi_device(mcp320x_dev)); + } +#else + struct spi_master *master; + master = spi_busnum_to_master(mcp3204_info.bus_num); + + if (master) { + spi_remove_device(master, mcp3204_info.chip_select); + } else { + printk(KERN_ERR "mcp3204 remove error\n"); + } + + spi_unregister_driver(&mcp3204_driver); +#endif +} pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy