活动介绍

static void usbdev_reset(void) { int fd; int ret = 0; int retry_count = 0; int i = 0; struct usbdevfs_ctrltransfer ctrl = { .bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE, .bRequest = USB_REQ_GET_DESCRIPTOR, .wValue = (USB_DT_DEVICE << 8), .wIndex = 0, .wLength = 18, .timeout = 1000, .data = malloc(18) }; if (!ctrl.data) { L("===== SNBC ===== Failed to allocate memory for descriptor\n"); return; } if (strlen(usbdev) == 0) { free(ctrl.data); return; } fd = open(usbdev, O_RDWR); if (fd < 0) { L("===== SNBC ===== tuouchlogd Failed to open USB device\n"); free(ctrl.data); return; } while (retry_count < 3) { ret = ioctl(fd, USBDEVFS_CONTROL, &ctrl); if (ret < 0){ L("===== SNBC ===== tuouchlogd Failed to send control transfer\n"); retry_count ++; sleep(1); } else { unsigned char tmp[18] = {0}; unsigned char* des = tmp; reset_usb_count = 0; L("report %d, desc = ", retry_count + 1); for(i = 0; i < 18; i++) { L("%02x ", ((unsigned char*)ctrl.data)[i]); } L("%s < \n", des); } break; } if (retry_count >= 3) { if(reset_usb_count > 3) { reboot_noftify(); } else { reset_usb_power(); } } else { L("===== snbc ===== touchlogd the touch is ok!"); } free(ctrl.data); close(fd); return; }这个函数代码有问题吗

时间: 2025-07-12 13:42:24 浏览: 12
<think>好的,我需要分析用户提供的`usbdev_reset`函数是否存在代码问题,以及改进空间。首先,用户提到的三个引用涉及USB接口结构体、pread/pwrite函数和驱动probe函数。虽然用户没有给出`usbdev_reset`的具体代码,但可以根据常见USB编程问题和引用内容来推断可能的问题点。 首先,内存分配方面,引用[1]提到`usb_host_interface`结构体包含端点数组,可能在分配或释放时需要注意是否正确处理这些资源。例如,是否有内存泄漏,是否检查了内存分配失败的情况。 其次,文件描述符操作方面,引用[2]中的pread/pwrite函数强调了偏移量的处理,但`usbdev_reset`可能涉及文件描述符的读写或ioctl调用。需要确认是否正确处理了错误返回,比如检查ioctl的返回值,是否在失败时关闭文件描述符,或者是否有竞态条件导致文件偏移错误。 再者,ioctl调用方面,USB设备通常使用特定的ioctl命令进行控制,如`USBDEVFS_RESET`。需要确认是否正确传递了参数,是否处理了可能的错误码,如EINTR或ENODEV,以及是否在设备断开后仍尝试调用ioctl导致的无效操作。 另外,引用[3]提到驱动匹配后的probe函数,可能涉及到设备状态的同步问题。如果在reset过程中设备被移除,需要确保代码正确处理了这种情况,避免访问已释放的资源。 可能的改进点包括增加错误处理逻辑,使用更安全的函数替代可能存在竞态的操作,以及添加日志信息帮助调试。此外,确保资源释放,如关闭文件描述符和释放分配的内存,也是关键。 需要验证这些假设,并针对常见的USB编程错误进行检查,比如未初始化的变量、重复释放内存、未正确处理信号中断等。如果函数涉及多次ioctl调用,是否在每次调用前都检查了设备状态,避免无效操作。</think>### 分析`usbdev_reset`函数的潜在问题与改进建议 #### 1. **内存分配与释放问题** - **潜在问题**: - 如果函数涉及动态分配内存(如引用[1]中的`usb_host_interface`结构体),需确保所有分配的内存均正确释放,避免内存泄漏。 - 未检查`malloc`/`calloc`返回值可能导致空指针解引用。例如: ```c struct usb_host_interface *iface = malloc(sizeof(struct usb_host_interface)); if (!iface) { // 错误处理缺失 } ``` - **改进建议**: - 添加内存分配失败检查,释放资源后返回错误码。 - 使用静态分析工具(如Valgrind)检测内存泄漏。 #### 2. **文件描述符操作** - **潜在问题**: - 若函数通过文件描述符操作设备(如`/dev/bus/usb`),需确保: - 文件描述符在错误时正确关闭(避免泄漏)。 - 使用`pread`/`pwrite`时(如引用[2]),需注意偏移量的原子性,避免多线程竞争。 - 未处理`ioctl`返回值可能导致静默失败。例如: ```c int ret = ioctl(fd, USBDEVFS_RESET); if (ret < 0) { // 未处理错误(如设备断开、权限不足) } ``` - **改进建议**: - 使用`do {...} while (retry)`循环处理`EINTR`(系统调用被信号中断)。 - 在`ioctl`后检查错误码,记录日志并关闭文件描述符。 #### 3. **`ioctl`调用的安全性** - **潜在问题**: - `USBDEVFS_RESET`等命令需确保设备状态有效。若设备已断开,`ioctl`可能返回`ENODEV`。 - 未同步设备状态(如引用[3]的`probe`函数),可能导致复位后设备未重新初始化。 - **改进建议**: - 在复位前检查设备是否在线(如通过`ioctl(fd, USBDEVFS_GET_CAPABILITIES)`)。 - 复位后重新读取设备描述符,确保驱动与硬件状态一致。 #### 4. **并发与竞态条件** - **潜在问题**: - 多线程环境下,若共享同一文件描述符,可能导致`ioctl`调用冲突。 - **改进建议**: - 对文件描述符操作加锁(如互斥锁)。 - 使用`O_EXCL`标志打开设备文件,确保独占访问。 #### 5. **日志与错误处理** - **潜在问题**: - 缺乏日志输出,难以调试复位失败的具体原因。 - **改进建议**: - 使用`syslog`或`perror`记录错误详情: ```c if (ioctl(fd, USBDEVFS_RESET) < 0) { perror("USB reset failed"); close(fd); return -errno; } ``` --- ### 示例代码改进对比 **原始代码(假设)**: ```c void usbdev_reset(int fd) { ioctl(fd, USBDEVFS_RESET); close(fd); } ``` **改进后代码**: ```c int usbdev_reset(int fd) { int ret; do { ret = ioctl(fd, USBDEVFS_RESET); } while (ret < 0 && errno == EINTR); if (ret < 0) { syslog(LOG_ERR, "USB reset failed: %s", strerror(errno)); close(fd); return -errno; } // 复位后重新初始化设备 if (reinit_device(fd) < 0) { close(fd); return -EIO; } close(fd); return 0; } ``` ---
阅读全文

相关推荐

#include <zephyr/kernel.h> #include <zephyr/device.h> #include <zephyr/devicetree.h> #include <zephyr/drivers/i2c.h> #include <zephyr/logging/log.h> #include <stdio.h> #include <math.h> #include "GVL.h" #include "data_preprocess.h" #define LOG_MODULE_NAME LSM6DSOWTR_thread LOG_MODULE_REGISTER(LOG_MODULE_NAME); // LSM6DSOWTR 寄存器定义 #define LSM6DSOWTR_REG_WHO_AM_I 0x0F #define LSM6DSOWTR_REG_CTRL1_XL 0x10 #define LSM6DSOWTR_REG_CTRL2_G 0x11 #define LSM6DSOWTR_REG_CTRL3_C 0x12 #define LSM6DSOWTR_REG_OUTX_L_G 0x22 #define LSM6DSOWTR_REG_OUTX_H_G 0x23 #define LSM6DSOWTR_REG_OUTY_L_G 0x24 #define LSM6DSOWTR_REG_OUTY_H_G 0x25 #define LSM6DSOWTR_REG_OUTZ_L_G 0x26 #define LSM6DSOWTR_REG_OUTZ_H_G 0x27 #define LSM6DSOWTR_REG_OUTX_L_XL 0x28 #define LSM6DSOWTR_REG_OUTX_H_XL 0x29 #define LSM6DSOWTR_REG_OUTY_L_XL 0x2A #define LSM6DSOWTR_REG_OUTY_H_XL 0x2B #define LSM6DSOWTR_REG_OUTZ_L_XL 0x2C #define LSM6DSOWTR_REG_OUTZ_H_XL 0x2D // 配置参数 #define LSM6DSOWTR_WHO_AM_I_VAL 0x6C #define LSM6DSOWTR_ODR_XL_104HZ 0x40 // 加速度计 104Hz #define LSM6DSOWTR_FS_XL_2G 0x00 // ±2g 量程 #define LSM6DSOWTR_ODR_G_104HZ 0x40 // 陀螺仪 104Hz #define LSM6DSOWTR_FS_G_245DPS 0x00 // ±245dps 量程 #define LSM6DSOWTR_REG_STATUS_REG 0x1E #define ACCEL_SENSITIVITY_2G 0.000061f #define GYRO_SENSITIVITY_245DPS 0.00875f // 8.75 mdps/LSB // 压力传感器LPS28DFW 寄存器定义 // LPS28DFW 寄存器定义 #define LPS28DFW_WHO_AM_I 0x0F #define LPS28DFW_CTRL_REG1 0x10 #define LPS28DFW_CTRL_REG2 0x11 #define LPS28DFW_CTRL_REG3 0x12 #define LPS28DFW_PRESS_OUT_XL 0x28 #define LPS28DFW_PRESS_OUT_L 0x29 #define LPS28DFW_PRESS_OUT_H 0x2A #define LPS28DFW_TEMP_OUT_L 0x2B #define LPS28DFW_TEMP_OUT_H 0x2C #define LPS28DFW_INTERRUPT_CFG 0x0B #define LPS28DFW_THS_P_L 0x0C #define LPS28DFW_THS_P_H 0x0D // 配置值 #define LPS28DFW_WHO_AM_I_VAL 0xB4 #define LPS28DFW_ODR_50HZ 0x50 // 50Hz输出数据率 #define LPS28DFW_LPF_ENABLE 0x08 // 启用低通滤波器 #define LPS28DFW_BDU_ENABLE 0x08 // 启用块数据更新 #define LPS28DFW_WATER_MODE 0x40 // 水压测量模式 #define SAMPLE_INTERVAL_MS 100 //MS5837压力传感器 #define MS5837_CMD_RESET 0x1E #define MS5837_CMD_CONVERT_D1_OSR1024 0x44 #define MS5837_CMD_CONVERT_D2_OSR1024 0x54 #define MS5837_CMD_ADC_READ 0x00 #define MS5837_PROM_READ_BASE 0xA0 struct ms5837_calib { uint16_t factory; // PROM word 0 (厂商数据) uint16_t c1; // 压力灵敏度 uint16_t c2; // 压力偏移 uint16_t c3; // 温度系数-压力灵敏度 uint16_t c4; // 温度系数-压力偏移 uint16_t c5; // 参考温度 uint16_t c6; // 温度系数 uint16_t crc; // CRC校验 }; // 等待数据就绪 static bool wait_for_data_ready(const struct i2c_dt_spec *dev_spec) { uint8_t status; int retries = 10; while (retries-- > 0) { if (i2c_reg_read_byte_dt(dev_spec, LSM6DSOWTR_REG_STATUS_REG, &status) == 0) { // 检查加速度计和陀螺仪数据就绪位 (bit0 & bit1) if ((status & 0x03) == 0x03) return true; } k_msleep(1); } return false; } static int init_LPS28DFW_water(const struct i2c_dt_spec *dev_spec) { const int max_retries = 5; uint8_t whoami; int ret; int retries = 0; LOG_INF("Starting LPS28DFW initialization..."); LOG_DBG("Verifying I2C connection to device at 0x%02X", dev_spec->addr); do { ret = i2c_reg_read_byte_dt(dev_spec, LPS28DFW_WHO_AM_I, &whoami); if (ret == 0 && whoami == LPS28DFW_WHO_AM_I_VAL) break; if (ret != 0) { LOG_WRN("I2C read error: %d (attempt %d)", ret, retries+1); } else { LOG_WRN("Unexpected WHO_AM_I: 0x%02X (expected 0x%02X) attempt %d", whoami, LPS28DFW_WHO_AM_I_VAL, retries+1); } i2c_recover_bus(dev_spec->bus); k_msleep(10); } while (++retries < max_retries); if (retries >= max_retries) { LOG_ERR("Device detection failed after %d attempts", max_retries); return -ENODEV; } uint8_t ctrl_reset=0x04; ret = i2c_reg_write_byte_dt(dev_spec, LPS28DFW_CTRL_REG2, ctrl_reset); k_msleep(10); if (ret) { LOG_ERR("ctrl_reg2 reset failed: %d", ret); return ret; } uint8_t ctrl_reset_value; ret = i2c_reg_read_byte_dt(dev_spec, LPS28DFW_CTRL_REG2, &ctrl_reset_value); if (ret == 0) { // 检查关键位 const uint8_t critical_bits_mask_reset = 0x04; if (ctrl_reset_value == critical_bits_mask_reset) { LOG_DBG("CTRL_REG2 reset verified: 0x%02X", ctrl_reset_value); } else{ LOG_WRN("CTRL_REG2 reset failed: read 0x%02X", ctrl_reset_value); } } uint8_t ctrl_reg1=0x50; ret = i2c_reg_write_byte_dt(dev_spec, LPS28DFW_CTRL_REG1, ctrl_reg1); if (ret) { LOG_ERR("ctrl_reg1 set failed: %d", ret); return ret; } uint8_t ctrl_reg2 =0x18; ret = i2c_reg_write_byte_dt(dev_spec, LPS28DFW_CTRL_REG2, ctrl_reg2); if (ret) { LOG_ERR("ctrl_reg1 set failed: %d", ret); return ret; } uint8_t reg_value1; uint8_t reg_value2; uint8_t reg_value3; ret = i2c_reg_read_byte_dt(dev_spec, LPS28DFW_CTRL_REG1, ®_value1); if (ret == 0) { // 检查关键位 const uint8_t critical_bits_mask1 = 0x50; if (reg_value1 == critical_bits_mask1) { LOG_DBG("CTRL_REG1 verified: 0x%02X", reg_value1); } else{ LOG_WRN("CTRL_REG1 failed: read 0x%02X", reg_value1); } } ret = i2c_reg_read_byte_dt(dev_spec, LPS28DFW_CTRL_REG2, ®_value2); if (ret == 0) { // 检查关键位 const uint8_t critical_bits_mask2 = 0x18; if (reg_value2 == critical_bits_mask2) { LOG_DBG("CTRL_REG2 verified: 0x%02X", reg_value2); } else{ LOG_WRN("CTRL_REG2 failed: read 0x%02X", reg_value2); } } uint8_t ctrl_reg3 =0x01; ret = i2c_reg_write_byte_dt(dev_spec, LPS28DFW_CTRL_REG3, ctrl_reg3); if (ret) { LOG_ERR("ctrl_reg3 set failed: %d", ret); return ret; } ret = i2c_reg_read_byte_dt(dev_spec, LPS28DFW_CTRL_REG3, ®_value3); if (ret == 0) { // 检查关键位 const uint8_t critical_bits_mask3 = 0x01; if (reg_value3 == critical_bits_mask3) { LOG_DBG("CTRL_REG3 verified: 0x%02X", reg_value3); } else{ LOG_WRN("CTRL_REG3 failed: read 0x%02X", reg_value3); } } LOG_INF("LPS28DFW initialized successfully"); return 0; } // 读取原始压力数据 (24位有符号整数) static int32_t read_raw_pressure(const struct i2c_dt_spec *dev_spec) { uint8_t press_data[3]; int ret; ret = i2c_burst_read_dt(dev_spec, LPS28DFW_PRESS_OUT_XL, press_data, sizeof(press_data)); if (ret != 0) { LOG_ERR("Pressure read failed: %d", ret); return 0; } int32_t raw_pressure = ((int32_t)press_data[2] << 16) | ((int32_t)press_data[1] << 8) | press_data[0]; if (raw_pressure & 0x00800000) { raw_pressure |= 0xFF000000; } return raw_pressure; } // 读取原始温度数据 (16位有符号整数) static int16_t read_raw_temperature(const struct i2c_dt_spec *dev_spec) { uint8_t temp_data[2]; int ret; ret = i2c_burst_read_dt(dev_spec, LPS28DFW_TEMP_OUT_L, temp_data, sizeof(temp_data)); if (ret != 0) { LOG_ERR("Temperature read failed: %d", ret); return 0; } // 组合16位有符号整数 (小端格式) return (int16_t)((temp_data[1] << 8) | temp_data[0]); } // 读取带温度补偿的水压 static double read_compensated_water_pressure(const struct i2c_dt_spec *dev_spec) { // 读取原始压力值 int32_t raw_pressure = read_raw_pressure(dev_spec); // 读取原始温度值 int16_t raw_temp = read_raw_temperature(dev_spec); // 转换为摄氏度 (100 LSB/°C) double temperature = (double)raw_temp / 100.0f; // 转换为hPa double pressure_hPa = (double)raw_pressure / 4096.0f; // 温度补偿因子 (根据数据手册的典型特性) // 实际应用中应根据传感器校准数据调整 double comp_factor = 1.0f + (0.0001f * temperature); // 应用温度补偿 pressure_hPa *= comp_factor; // 转换为米水柱 return pressure_hPa*100.0; } // 读取水深 (单位: 米) static double read_water_depth(const struct i2c_dt_spec *dev_spec) { // 读取补偿后的水压 double pressure_mH2O = read_compensated_water_pressure(dev_spec); // 水深 = 水压值 (忽略大气压影响) return pressure_mH2O; } static double read_compensated_water_depth(const struct i2c_dt_spec *dev_spec, double atmospheric_pressure) { // 读取补偿后的水压(单位:米水柱) //double absolute_pressure_mH2O = read_compensated_water_pressure(dev_spec); double raw_press = read_raw_pressure(dev_spec) / 0.4096f; double raw_temp = read_raw_temperature(dev_spec) / 100.0f; // double absolute_pressure_Pa = read_compensated_water_pressure(dev_spec); // 转换为Pa (1 mH2O = 9806.65 Pa) //double temp_depth = (absolute_pressure_Pa - atmospheric_pressure) / (1000.0 * 9.80665); //double temp_depth = (sensor_data_PWM.pressure/10.0f - atmospheric_pressure/10.0f) / (1000.0 * 9.80665); double temp_depth = (raw_press/10.0f - atmospheric_pressure/10.0f) / (1000.0 * 9.80665); LOG_INF("raw temp:%.2f raw pressure: %.2f atmospheric_pressure: %.2f kPa (%.4f mH2O)", raw_temp,raw_press/10.f,atmospheric_pressure/10.0f, temp_depth); // 水深 = (绝对压力 - 大气压) / (水密度 * 重力加速度) //return (absolute_pressure_Pa - atmospheric_pressure) / (1000.0f * 9.80665f); return (raw_press/10.0f - atmospheric_pressure/10.0f) / (1000.0f * 9.80665f); } // 初始化 LSM6DS0 传感器 static int init_lsm6dsowtr(const struct i2c_dt_spec *dev_spec) { uint8_t whoami; int ret; LOG_INF("Initializing LSM6DSOWTR sensor..."); // 读取 WHO_AM_I 寄存器 ret = i2c_reg_read_byte_dt(dev_spec, LSM6DSOWTR_REG_WHO_AM_I, &whoami); if (ret != 0) { LOG_ERR("Failed to read WHO_AM_I: %d", ret); return ret; } if (whoami != LSM6DSOWTR_WHO_AM_I_VAL) { LOG_ERR("Unexpected WHO_AM_I: 0x%02X (expected 0x%02X)", whoami, LSM6DSOWTR_WHO_AM_I_VAL); return -ENODEV; } LOG_INF("LSM6DSOWTR detected (WHO_AM_I=0x%02X)", whoami); // 配置加速度计 uint8_t ctrl1_xl = LSM6DSOWTR_ODR_XL_104HZ | LSM6DSOWTR_FS_XL_2G; ret = i2c_reg_write_byte_dt(dev_spec, LSM6DSOWTR_REG_CTRL1_XL, ctrl1_xl); if (ret != 0) { LOG_ERR("Failed to write CTRL1_XL: %d", ret); return ret; } // 配置陀螺仪 uint8_t ctrl2_g = LSM6DSOWTR_ODR_G_104HZ | LSM6DSOWTR_FS_G_245DPS; ret = i2c_reg_write_byte_dt(dev_spec, LSM6DSOWTR_REG_CTRL2_G, ctrl2_g); if (ret != 0) { LOG_ERR("Failed to write CTRL2_G: %d", ret); return ret; } uint8_t reg_val; ret = i2c_reg_read_byte_dt(dev_spec, LSM6DSOWTR_REG_CTRL1_XL, ®_val); if (ret != 0 || reg_val != ctrl1_xl) { LOG_ERR("CTRL1_XL verification failed: wrote 0x%02X, read 0x%02X", ctrl1_xl, reg_val); return -EIO; } ret = i2c_reg_read_byte_dt(dev_spec, LSM6DSOWTR_REG_CTRL2_G, ®_val); if (ret != 0 || reg_val != ctrl2_g) { LOG_ERR("CTRL2_G verification failed: wrote 0x%02X, read 0x%02X", ctrl2_g, reg_val); return -EIO; } // 配置控制寄存器3 ret = i2c_reg_write_byte_dt(dev_spec, LSM6DSOWTR_REG_CTRL3_C, 0x04); // BDU=1 (块数据更新) if (ret != 0) { LOG_ERR("Failed to write CTRL3_C: %d", ret); return ret; } LOG_INF("LSM6DSOWTR initialized successfully"); return 0; } // 读取加速度计数据 static void read_accelerometer(const struct i2c_dt_spec *dev_spec, double *x, double *y, double *z) { if (!wait_for_data_ready(dev_spec)) { LOG_WRN("Accel data not ready"); *x = *y = *z = NAN; return; } uint8_t data[6]; int ret = i2c_burst_read_dt(dev_spec, LSM6DSOWTR_REG_OUTX_L_XL, data, sizeof(data)); if (ret != 0) { LOG_ERR("Accelerometer read failed: %d", ret); *x = *y = *z = NAN; return; } // 组合16位数据(小端格式) int16_t raw_x = (int16_t)((data[1] << 8) | data[0]); int16_t raw_y = (int16_t)((data[3] << 8) | data[2]); int16_t raw_z = (int16_t)((data[5] << 8) | data[4]); // 转换为 g (重力加速度) - ±2g 量程,灵敏度 0.061 mg/LSB *x = raw_x * ACCEL_SENSITIVITY_2G; *y = raw_y * ACCEL_SENSITIVITY_2G; *z = raw_z * ACCEL_SENSITIVITY_2G; } // 读取陀螺仪数据 static void read_gyroscope(const struct i2c_dt_spec *dev_spec, double *x, double *y, double *z) { if (!wait_for_data_ready(dev_spec)) { LOG_WRN("Gyro data not ready"); *x = *y = *z = NAN; return; } uint8_t data[6]; int ret = i2c_burst_read_dt(dev_spec, LSM6DSOWTR_REG_OUTX_L_G, data, sizeof(data)); if (ret != 0) { LOG_ERR("Gyroscope read failed: %d", ret); *x = *y = *z = NAN; return; } // 组合16位数据(小端格式) int16_t raw_x = (int16_t)((data[1] << 8) | data[0]); int16_t raw_y = (int16_t)((data[3] << 8) | data[2]); int16_t raw_z = (int16_t)((data[5] << 8) | data[4]); // 转换为 dps (度/秒) - ±245dps 量程,灵敏度 8.75 mdps/LSB *x = raw_x * GYRO_SENSITIVITY_245DPS; *y = raw_y * GYRO_SENSITIVITY_245DPS; *z = raw_z * GYRO_SENSITIVITY_245DPS; } // 将浮点值转换为定点表示(用于存储) static int32_t sensor_value_to_int(double value, int scale_factor) { return (int32_t)(value * scale_factor); } // 主传感器线程 void lsm6dsowtr_thread(void) { LOG_INF("LSM6DSOWTR sensor thread started"); // 获取六轴传感器设备规范 static const struct i2c_dt_spec lsm6dsowtr_dev = I2C_DT_SPEC_GET(DT_NODELABEL(lsm6dsowtr)); if (!device_is_ready(lsm6dsowtr_dev.bus)) { LOG_ERR("I2C bus not ready: %s", lsm6dsowtr_dev.bus->name); return; } // 获取压力传感器设备规范 static const struct i2c_dt_spec pressure_dev = I2C_DT_SPEC_GET(DT_NODELABEL(mysensor)); if (!device_is_ready(pressure_dev.bus)) { LOG_ERR("I2C bus %s is not ready!", pressure_dev.bus->name); return; } // 初始化传感器 int init_result; // 初始化压力传感器 init_result = init_LPS28DFW_water(&pressure_dev); if (init_result != 0) { LOG_ERR("Pressure sensor initialization failed: %d", init_result); } else { LOG_INF("Pressure sensor initialized successfully"); } // struct ms5837_calib calib_data; // int ms5837_init_ret = init_MS5837(&pressure_dev, &calib_data); // if (ms5837_init_ret != 0) { // LOG_ERR("MS5837 initialization failed: %d", ms5837_init_ret); // // 非致命错误,继续运行其他传感器 // } else { // LOG_INF("MS5837 initialized successfully"); // } // 初始化六轴传感器 init_result = init_lsm6dsowtr(&lsm6dsowtr_dev); if (init_result != 0) { LOG_ERR("LSM6DSOWTR initialization failed: %d", init_result); } else { LOG_INF("LSM6DSOWTR initialized successfully"); } LOG_INF("Starting sensor data collection..."); // 主循环变量 int64_t last_sample_time = k_uptime_get(); int64_t last_batch_time = last_sample_time; static int datacount = 0; static double press_a = 0; static double depth_comp = 0; static int depth_count = 0; while (1) { double press = read_raw_pressure(&pressure_dev); double temp = read_raw_temperature(&pressure_dev); double compensated_depth; if(datacount < 20){ press_a = press_a + press/4096.0f; datacount++; // LOG_INF("press_a: %.4f Pa,datacount:%d", press_a,datacount); } else{ press_a = press_a/20.0f; // LOG_INF("press_a: %.4f Pa,datacount:%d", press_a,datacount); press_a = press_a*10000; // sensor_data_PWM.pressure = press_a*10000; compensated_depth = read_compensated_water_depth(&pressure_dev, press_a); if(depth_count < 20){ depth_comp = depth_comp + compensated_depth; depth_count++; // LOG_INF("press_a: %.4f Pa,datacount:%d", press_a,datacount); } else{ depth_comp = depth_comp/20.0f; LOG_INF("depth_comp: %.4f Pa,depth_count:%d", depth_comp,depth_count); depth_count = 0; depth_comp = 0; } datacount = 0; press_a = 0; } // if(depth_count < 20){ // depth_comp = depth_comp + compensated_depth/4096.0f; // datacount++; // // LOG_INF("press_a: %.4f Pa,datacount:%d", press_a,datacount); // } else{ // press_a = press_a/20.0f; // // LOG_INF("press_a: %.4f Pa,datacount:%d", press_a,datacount); // press_a = press_a*10000; // compensated_depth = read_compensated_water_depth(&pressure_dev, press_a); // datacount = 0; // press_a = 0; // } double accel_x, accel_y, accel_z; double gyro_x, gyro_y, gyro_z; read_accelerometer(&lsm6dsowtr_dev, &accel_x, &accel_y, &accel_z); read_gyroscope(&lsm6dsowtr_dev, &gyro_x, &gyro_y, &gyro_z); //float magnitude = calculate_acceleration_magnitude(accel_x, accel_y, accel_z); // LOG_INF("Accel: X=%.3f g, Y=%.3f g, Z=%.3f g", // accel_x, accel_y, accel_z); // LOG_INF("Gyro: X=%.2f dps, Y=%.2f dps, Z=%.2f dps", // gyro_x, gyro_y, gyro_z); // 获取当前时间戳 int64_t current_time = k_uptime_get(); // 准备数据点 // sensor_data_point_t data_point = { // .timestamp = current_time, // .pressure = sensor_value_to_int(press, 1000), // kPa * 1000 = milli-kPa // .temp = sensor_value_to_int(temp, 100), // °C * 100 = centi-°C // .acc_x = sensor_value_to_int(accel_x, 1000), // g * 1000 = milli-g // .acc_y = sensor_value_to_int(accel_y, 1000), // .acc_z = sensor_value_to_int(accel_z, 1000), // .gyro_x = sensor_value_to_int(gyro_x, 1000), // dps * 1000 = milli-dps // .gyro_y = sensor_value_to_int(gyro_y, 1000), // .gyro_z = sensor_value_to_int(gyro_z, 1000) // }; sensor_data_point_t data_point = { .timestamp = current_time, .pressure = sensor_value_to_int(press/4096.0f, 10000), // kPa * 1000 = milli-kPa .temp = sensor_value_to_int(temp, 100), // °C * 100 = centi-°C .acc_x = sensor_value_to_int(accel_x, 1000), // g * 1000 = milli-g .acc_y = sensor_value_to_int(accel_y, 1000), .acc_z = sensor_value_to_int(accel_z, 1000), .gyro_x = sensor_value_to_int(gyro_x, 1000), // dps * 1000 = milli-dps .gyro_y = sensor_value_to_int(gyro_y, 1000), .gyro_z = sensor_value_to_int(gyro_z, 1000) }; // LOG_INF("data filter"); data_point = filter_sensor_data(&data_point); atmospheric_pressure = data_point.pressure; //double compensated_depth = read_compensated_water_depth(&pressure_dev, atmospheric_pressure); // double compensated_depth = read_compensated_water_depth(&pressure_dev, press/4096.0f); // LOG_INF("Compensated Depth: %.4f m",compensated_depth); // // 安全地添加到批量缓冲区 // k_mutex_lock(&data_mutex, K_FOREVER); // // 检查当前批次缓冲区是否有效 // if (sensor_batch.count == 0) { // // 新批次,记录起始时间戳 // sensor_batch.start_timestamp = current_time; // } // // 添加数据点到批次 // if (sensor_batch.count < BATCH_SIZE) { // sensor_batch.data[sensor_batch.count] = data_point; // sensor_batch.count++; // // 检查批次是否已满 // if (sensor_batch.count >= BATCH_SIZE) { // // 批次已满,标记为就绪 // sensor_batch.ready = true; // LOG_DBG("Batch filled (%d points)", BATCH_SIZE); // } // } else { // LOG_WRN("Batch buffer full, discarding data point"); // } // // 检查是否超时(即使批次未满) // if ((current_time - sensor_batch.start_timestamp) >= (MAX_BATCH_TIMEOUT * 1000)) { // if (sensor_batch.count > 0) { // sensor_batch.ready = true; // LOG_DBG("Batch timeout with %d points", sensor_batch.count); // } // } // // 如果批次就绪,通知BLE线程 // if (sensor_batch.ready) { // k_sem_give(&batch_ready_sem); // LOG_DBG("Notified BLE thread of data ready"); // } // k_mutex_unlock(&data_mutex); // 计算下一个采样点的时间 int64_t elapsed = k_uptime_get() - last_sample_time; int32_t sleep_time = SAMPLE_INTERVAL_MS - elapsed; if (sleep_time > 0) { k_msleep(sleep_time); } else { LOG_WRN("Sampling behind schedule by %d ms", -sleep_time); } last_sample_time = k_uptime_get(); } } // 定义传感器线程 K_THREAD_DEFINE(lsm6dsowtr_thread_id, 4096, lsm6dsowtr_thread, NULL, NULL, NULL, 7, 0, 0);对原始压力值进行中值滤波

解释代码#define TP_PRIO configMAX_PRIORITIES - 5 static void ble_tp_connected(struct bt_conn *conn, u8_t err); static void ble_tp_disconnected(struct bt_conn *conn, u8_t reason); static int bl_tp_send_indicate(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *data, u16_t len); struct bt_conn *ble_tp_conn; struct bt_gatt_exchange_params exchg_mtu; TaskHandle_t ble_tp_task_h; int tx_mtu_size = 20; u8_t tp_start = 0; static u8_t created_tp_task = 0; static u8_t isRegister = 0; static struct bt_conn_cb ble_tp_conn_callbacks = { .connected = ble_tp_connected, .disconnected = ble_tp_disconnected, }; static void ble_tp_tx_mtu_size(struct bt_conn *conn, u8_t err, struct bt_gatt_exchange_params *params) { if(!err) { tx_mtu_size = bt_gatt_get_mtu(ble_tp_conn); BT_WARN("ble tp echange mtu size success, mtu size: %d", tx_mtu_size); } else { BT_WARN("ble tp echange mtu size failure, err: %d", err); } } static void ble_tp_connected(struct bt_conn *conn, u8_t err) { if(err || conn->type != BT_CONN_TYPE_LE) { return; } int tx_octets = 0x00fb; int tx_time = 0x0848; int ret = -1; BT_INFO("%s",__func__); ble_tp_conn = conn; . ret = bt_le_set_data_len(ble_tp_conn, tx_octets, tx_time); if(!ret) { BT_WARN("ble tp set data length success."); } else { BT_WARN("ble tp set data length failure, err: %d\n", ret); } exchg_mtu.func = ble_tp_tx_mtu_size; ret = bt_gatt_exchange_mtu(ble_tp_conn, &exchg_mtu); if (!ret) { BT_WARN("ble tp exchange mtu size pending."); } else { BT_WARN("ble tp exchange mtu size failure, err: %d", ret); } } static void ble_tp_disconnected(struct bt_conn *conn, u8_t reason) { if(conn->type != BT_CONN_TYPE_LE) { return; } BT_INFO("%s",__func__); ble_tp_conn = NULL; } static int ble_tp_recv_rd(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, u16_t len, u16_t offset) { int size = 9; char data[9] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09}; memcpy(buf, data, size); return size; }

注释以下代码#define TP_PRIO configMAX_PRIORITIES - 5 static void ble_tp_connected(struct bt_conn *conn, u8_t err); static void ble_tp_disconnected(struct bt_conn *conn, u8_t reason); static int bl_tp_send_indicate(struct bt_conn *conn, const struct bt_gatt_attr *attr, const void *data, u16_t len); struct bt_conn *ble_tp_conn; struct bt_gatt_exchange_params exchg_mtu; TaskHandle_t ble_tp_task_h; int tx_mtu_size = 20; u8_t tp_start = 0; static u8_t created_tp_task = 0; static u8_t isRegister = 0; static struct bt_conn_cb ble_tp_conn_callbacks = { .connected = ble_tp_connected, .disconnected = ble_tp_disconnected, }; static void ble_tp_tx_mtu_size(struct bt_conn *conn, u8_t err, struct bt_gatt_exchange_params *params) { if(!err) { tx_mtu_size = bt_gatt_get_mtu(ble_tp_conn); BT_WARN("ble tp echange mtu size success, mtu size: %d", tx_mtu_size); } else { BT_WARN("ble tp echange mtu size failure, err: %d", err); } } static void ble_tp_connected(struct bt_conn *conn, u8_t err) { if(err || conn->type != BT_CONN_TYPE_LE) { return; } int tx_octets = 0x00fb; int tx_time = 0x0848; int ret = -1; BT_INFO("%s",__func__); ble_tp_conn = conn; . ret = bt_le_set_data_len(ble_tp_conn, tx_octets, tx_time); if(!ret) { BT_WARN("ble tp set data length success."); } else { BT_WARN("ble tp set data length failure, err: %d\n", ret); } exchg_mtu.func = ble_tp_tx_mtu_size; ret = bt_gatt_exchange_mtu(ble_tp_conn, &exchg_mtu); if (!ret) { BT_WARN("ble tp exchange mtu size pending."); } else { BT_WARN("ble tp exchange mtu size failure, err: %d", ret); } } static void ble_tp_disconnected(struct bt_conn *conn, u8_t reason) { if(conn->type != BT_CONN_TYPE_LE) { return; } BT_INFO("%s",__func__); ble_tp_conn = NULL; } static int ble_tp_recv_rd(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, u16_t len, u16_t offset) { int size = 9; char data[9] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09}; memcpy(buf, data, size); return size; }

/* * SEMIDRIVE Copyright Statement * Copyright (c) SEMIDRIVE. All rights reserved * This software and all rights therein are owned by SEMIDRIVE, * and are protected by copyright law and other relevant laws, regulations and protection. * Without SEMIDRIVE’s prior written consent and /or related rights, * please do not use this software or any potion thereof in any form or by any means. * You may not reproduce, modify or distribute this software except in compliance with the License. * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTIES OF ANY KIND, either express or implied. * You should have received a copy of the License along with this program. * If not, see <http://www.semidrive.com/licenses/>. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include <asm/current.h> #ifdef CONFIG_OF #include #include #include #include #include #else #include #include #include #endif #include "sdrv_g2d.h" #include "g2d_common.h" static DEFINE_MUTEX(m_init); extern const struct g2d_ops g2d_normal_ops; extern const struct g2d_ops g2d_lite_ops; extern struct ops_entry spipe_g2d_entry; extern struct ops_entry gpipe_mid_g2d_entry; extern struct ops_entry gpipe_high_g2d_entry; extern int g2d_dump_registers(struct sdrv_g2d *dev); extern int g2d_post_config(struct sdrv_g2d *dev, struct g2d_input *ins); extern int g2d_fastcopy_set(struct sdrv_g2d *dev, addr_t iaddr, u32 width, u32 height, u32 istride, addr_t oaddr, u32 ostride); extern int g2d_fill_rect(struct sdrv_g2d *dev, struct g2d_bg_cfg *bgcfg, struct g2d_output_cfg *output); extern int g2d_set_coefficients_table(struct sdrv_g2d *gd, struct g2d_coeff_table *table); extern struct attribute *sdrv_g2d_attrs[]; static const struct attribute_group *sdrv_g2d_groups[]; ATTRIBUTE_GROUPS(sdrv_g2d); static int wait_timeout = 500; module_param(wait_timeout, int, 0660); MODULE_PARM_DESC(wait_timeout, "wait timeout (ms)"); static int dump_register_g2d = 0; module_param(dump_register_g2d, int, 0660); MODULE_PARM_DESC(dump_register_g2d, "dump register g2d 0:off 1:on"); int debug_g2d = 0; EXPORT_SYMBOL(debug_g2d); module_param(debug_g2d, int, 0660); MODULE_PARM_DESC(debug_g2d, "debug g2d 0:off 1:on"); static char *version = KO_VERSION; module_param(version, charp, S_IRUGO); LIST_HEAD(g2d_pipe_list_head); int g2d_major = 227; int g2d_minor = -1; static struct sdrv_g2d *g_g2d[G2D_NR_DEVS]; const char *PIPE_TYPE_STRING[] = { GP_ECHO_NAME, GP_MID_NAME, GP_HIGH_NAME, SPIPE_NAME }; struct sdrv_g2d_data g2d_data[] = { {.version = "g2dlite-r0p0", .ops = &g2d_lite_ops}, {.version = "g2d-r0p1", .ops = &g2d_normal_ops}, {}, }; static void dump_input(struct g2d_input *input) { struct g2d_output_cfg *output = &input->output; struct g2d_layer *layer; struct g2d_bg_cfg *bg = &input->bg_layer; int i = 0; if (bg->en) { G2D_ERROR("[dump bg layer] en:%d, color:0x%x, g_alpha:0x%x, zorder:%d, bpa:0x%x, \ astride:%d, rect(%d, %d, %d, %d), pd_type:%d, fd:%d \n", bg->en, bg->color, bg->g_alpha, bg->zorder, bg->bpa, bg->astride, bg->x, bg->y, bg->width, bg->height, bg->pd_type, bg->abufs.fd); } for (i = 0; i < input->layer_num; i++) { layer = &input->layer[i]; G2D_ERROR("[dumplayer] index = %d, *ENABLE = %d*, format: %c%c%c%c source (%d, %d, %d, %d) => dest (%d, %d, %d, %d)\n", layer->index, layer->enable, layer->format & 0xff, (layer->format >> 8) & 0xff, (layer->format >> 16) & 0xff, (layer->format >> 24) & 0xff, layer->src_x, layer->src_y, layer->src_w, layer->src_h, layer->dst_x, layer->dst_y, layer->dst_w, layer->dst_h); } G2D_ERROR("[dump output]: w,h(%d,%d) format:%c%c%c%c rota:%d nplanes:%d\n", output->width, output->height, output->fmt & 0xff, (output->fmt >> 8) & 0xff, (output->fmt >> 16) & 0xff, (output->fmt >> 24) & 0xff, output->rotation, output->nplanes); return; } struct sdrv_g2d *get_g2d_by_id(int id) { return g_g2d[id]; } int g2d_ops_register(struct ops_entry *entry, struct list_head *head) { struct ops_list *list; list = kzalloc(sizeof(struct ops_list), GFP_KERNEL); if (!list) return -ENOMEM; list->entry = entry; list_add(&list->head, head); return 0; } void *g2d_ops_attach(const char *str, struct list_head *head) { struct ops_list *list; const char *ver; list_for_each_entry(list, head, head) { ver = list->entry->ver; if (!strcmp(str, ver)) return list->entry->ops; } G2D_ERROR("attach disp ops %s failed\n", str); return NULL; } irqreturn_t sdrv_g2d_irq_handler(int irq, void *data) { struct sdrv_g2d *gd = data; uint32_t val; if (!gd->du_inited) { G2D_ERROR("g2d du_inited does not init\n"); return IRQ_HANDLED; } val = gd->ops->irq_handler(gd); if (val & G2D_INT_MASK_FRM_DONE) { G2D_DBG("frame done\n"); gd->frame_done = true; wake_up(&gd->wq); } return IRQ_HANDLED; } int g2d_choose_pipe(struct sdrv_g2d *gd, int hwid, int type, uint32_t offset) { struct g2d_pipe *p = NULL; p = devm_kzalloc(&gd->pdev->dev, sizeof(struct g2d_pipe), GFP_KERNEL); if (!p) return -ENOMEM; p->type = type; p->name = PIPE_TYPE_STRING[type]; p->ops = (struct pipe_operation*)g2d_pipe_ops_attach(p->name); if (!p->ops) { G2D_ERROR("error ops attached\n"); return -EINVAL; } p->regs = gd->regs + (ulong)offset; p->iomem_regs = gd->iomem_regs + (ulong)offset; p->reg_offset = offset; p->id = hwid; p->gd = gd; gd->pipes[gd->num_pipe] = p; gd->num_pipe++; p->ops->init(p); G2D_DBG("pipe %d name %s registered\n", p->id, p->name); return 0; } #ifdef CONFIG_OF int sdrv_g2d_init(struct sdrv_g2d *gd, struct device_node *np) { int i, ret; int irq_num; struct resource res; const char *str; const struct sdrv_g2d_data *data; static int g2d_cnt = 0; if (!np || !gd) return -ENODEV; if(!of_device_is_available(np)) { G2D_ERROR("OF node %s not available or match\n", np->name); return -ENODEV; } if (!of_property_read_string(np, "sdrv,ip", &str)) { gd->name = str; } else { G2D_ERROR("sdrv,ip can not found\n"); return -ENODEV; } if (of_address_to_resource(np, 0, &res)) { G2D_ERROR("parse dt base address failed\n"); return -ENODEV; } G2D_INFO("got %s res 0x%lx\n", gd->name, (unsigned long)res.start); gd->regs = (void *)res.start; gd->iomem_regs = devm_ioremap_nocache(&gd->pdev->dev, res.start, resource_size(&res)); if(IS_ERR(gd->iomem_regs)) { G2D_ERROR("Cannot find g2d regs 001\n"); return PTR_ERR(gd->regs); } irq_num = irq_of_parse_and_map(np, 0); if (!irq_num) { G2D_ERROR("error: g2d parse irq num failed\n"); return -EINVAL; } G2D_INFO("g2d irq_num = %d\n", irq_num); data = of_device_get_match_data(&gd->pdev->dev); for (i = 0; i < 3; i++) { if (!strcmp(gd->name, data[i].version)) { gd->ops = data[i].ops; G2D_INFO("%s ops[%d] attached\n", gd->name, i); break; } } if (gd->ops == NULL) { G2D_ERROR("core ops attach failed, have checked %d times\n", i); return -1; } gd->num_pipe = 0; // g2d init gd->ops->init(gd); gd->irq = irq_num; gd->cap.num_pipe = gd->num_pipe; for (i = 0; i < gd->num_pipe; i++) { memcpy(&gd->cap.pipe_caps[i], gd->pipes[i]->cap, sizeof(struct g2d_pipe_capability)); } gd->id = g2d_cnt; irq_set_status_flags(gd->irq, IRQ_NOAUTOEN); ret = devm_request_irq(&gd->pdev->dev, gd->irq, sdrv_g2d_irq_handler, 0, dev_name(&gd->pdev->dev), gd); //IRQF_SHARED if(ret) { G2D_ERROR("Failed to request DC IRQ: %d\n", gd->irq); return -ENODEV; } //wait queue init_waitqueue_head(&gd->wq); gd->frame_done = false; g2d_cnt++; return 0; } #else int sdrv_g2d_init(struct sdrv_g2d *gd, struct platform_device *pdev) { int i, ret; int irq_num; struct device *dev = &pdev->dev; struct resource *res; const char *str; const struct sdrv_g2d_data *data; struct g2d_platform_data *pdata; static int g2d_cnt = 0; if (!pdev || !gd) return -ENODEV; res = platform_get_resource(pdev, IORESOURCE_MEM, 0); gd->regs = (void *)res->start; gd->iomem_regs = devm_ioremap_nocache(&gd->pdev->dev, res->start, resource_size(res)); if(IS_ERR(gd->iomem_regs)) { G2D_ERROR("Cannot find g2d regs 001\n"); return PTR_ERR(gd->regs); } pdata = (struct g2d_platform_data *)platform_get_drvdata(pdev); gd->name = "g2d-r0p1"; if (!gd->name) { G2D_ERROR("sdrv,ip can not found\n"); return -ENODEV; } G2D_INFO("got %s res 0x%lx\n", gd->name, (unsigned long)gd->regs); res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); irq_num = (int) res->start; if (!irq_num) { G2D_ERROR("error: g2d parse irq num failed\n"); return -EINVAL; } G2D_INFO("g2d irq_num = %d\n", irq_num); data = g2d_data; for (i = 0; i < 16; i++) { if (!strcmp(gd->name, data[i].version)) { gd->ops = data[i].ops; G2D_DBG("%s ops[%d] attached\n", gd->name, i); break; } } if (gd->ops == NULL) { G2D_ERROR("core ops attach failed, have checked %d times\n", i); return -1; } gd->num_pipe = 0; // g2d init gd->ops->init(gd); gd->irq = irq_num; gd->cap.num_pipe = gd->num_pipe; for (i = 0; i < gd->num_pipe; i++) { memcpy(&gd->cap.pipe_caps[i], gd->pipes[i]->cap, sizeof(struct g2d_pipe_capability)); } gd->id = g2d_cnt; irq_set_status_flags(gd->irq, IRQ_NOAUTOEN); ret = devm_request_irq(&gd->pdev->dev, gd->irq, sdrv_g2d_irq_handler, 0, dev_name(&gd->pdev->dev), gd); //IRQF_SHARED if(ret) { G2D_ERROR("Failed to request DC IRQ: %d\n", gd->irq); return -ENODEV; } //wait queue init_waitqueue_head(&gd->wq); gd->frame_done = false; g2d_cnt++; return 0; } #endif static void sdrv_g2d_unit(struct sdrv_g2d *gd) { if (!gd) return; // if (gd->ops->uninit) // gd->ops->uninit(gd); } static int sdrv_g2d_open(struct inode *node, struct file *file) { int i; struct sdrv_g2d *gd = NULL; int num = MINOR(node->i_rdev); if (num < 0) return -ENODEV; for (i = 0; i < G2D_NR_DEVS; i++){ gd = get_g2d_by_id(i); if (gd->mdev.minor == num) break; } file->private_data = gd; G2D_DBG("open node %s\n", gd->name); return 0; } static int sdrv_init_iommu(struct sdrv_g2d *gd) { struct device *dev = &gd->pdev->dev; struct device_node *iommu = NULL; struct property *prop = NULL; struct iommu_domain_geometry *geometry; u64 start, end; int ret = 0; gd->iommu_enable = false; iommu = of_parse_phandle(dev->of_node, "iommus", 0); if(!iommu) { G2D_DBG("iommu not specified\n"); return ret; } if (!of_device_is_available(iommu)) { G2D_DBG("smmu disabled\n"); return ret; } prop = of_find_property(dev->of_node, "smmu", NULL); if(!prop) { G2D_DBG("smmu bypassed\n"); return ret; } gd->domain = iommu_get_domain_for_dev(dev); if(!gd->domain) { ret = -ENOMEM; goto err_free_mm;; } geometry = &gd->domain->geometry; start = geometry->aperture_start; end = GENMASK(37, 0);// 38 bits address for KUNLUN G2D rdma G2D_DBG("IOMMU context initialized: %#llx - %#llx\n", start, end); gd->iommu_enable = true; of_node_put(iommu); return ret; err_free_mm: of_node_put(iommu); return ret; } static void sdrv_iommu_cleanup(struct sdrv_g2d *gd) { if(!gd->iommu_enable) return; iommu_domain_free(gd->domain); } static unsigned long _get_contiguous_size(struct sg_table *sgt) { struct scatterlist *s; dma_addr_t expected = sg_dma_address(sgt->sgl); unsigned int i; unsigned long size = 0; for_each_sg(sgt->sgl, s, sgt->nents, i) { if (sg_dma_address(s) != expected) break; expected = sg_dma_address(s) + sg_dma_len(s); size += sg_dma_len(s); } return size; } static int g2d_dmabuf_import(struct sdrv_g2d *gd, struct g2d_buf *buf) { struct dma_buf_attachment *attach; struct sg_table *sgt; struct dma_buf *dmabuf; int ret = 0; if (buf->fd < 0) { G2D_ERROR("dmabuf handle invalid: %d\n", buf->fd); return -EINVAL; } buf->vaddr = (unsigned long)NULL; dmabuf = dma_buf_get(buf->fd); if (IS_ERR_OR_NULL(dmabuf)) { G2D_ERROR("g2d get dmabuf err from buf fd %d\n", buf->fd); return PTR_ERR(dmabuf); } attach = dma_buf_attach(dmabuf, &gd->pdev->dev); if (IS_ERR(attach)) { G2D_ERROR("dma buf attach devices faild\n"); goto out_put; } sgt = dma_buf_map_attachment(attach, DMA_BIDIRECTIONAL); if (IS_ERR(sgt)) { ret = PTR_ERR(sgt); G2D_ERROR("Error getting dmabuf scatterlist: errno %ld\n", PTR_ERR(sgt)); goto fail_detach; } buf->attach = attach; buf->size = _get_contiguous_size(sgt); buf->dma_addr = sg_dma_address(sgt->sgl); buf->sgt = sgt; buf->vaddr = (unsigned long)NULL; G2D_DBG("buf->size = 0x%llx \n", buf->size); if (!buf->size) { G2D_ERROR("dma buf map attachment faild, buf->size = %lld \n", buf->size); ret = -EINVAL; goto fail_unmap; } goto out_put; fail_unmap: dma_buf_unmap_attachment(attach, sgt, DMA_BIDIRECTIONAL); fail_detach: dma_buf_detach(dmabuf, attach); out_put: dma_buf_put(dmabuf); return ret; } static void g2d_dmabuf_release(struct sdrv_g2d *gd, struct g2d_buf *buf) { struct sg_table *sgt = buf->sgt; struct dma_buf *dmabuf; if (IS_ERR_OR_NULL(sgt)) { G2D_ERROR("dmabuf buffer is already unpinned \n"); return; } if (IS_ERR_OR_NULL(buf->attach)) { G2D_ERROR("trying to unpin a not attached buffer\n"); return; } dmabuf = dma_buf_get(buf->fd); if (IS_ERR_OR_NULL(dmabuf)) { G2D_ERROR("invalid dmabuf from dma_buf_get: %d", buf->fd); return; } G2D_DBG("buf->vaddr = 0x%ld\n", (unsigned long)buf->vaddr); if (buf->vaddr) { dma_buf_vunmap(dmabuf, (void *)buf->vaddr); buf->vaddr = (unsigned long)NULL; } dma_buf_unmap_attachment(buf->attach, sgt, 0); buf->dma_addr = 0; buf->sgt = NULL; dma_buf_detach(dmabuf, buf->attach); dma_buf_put(dmabuf); } static int g2d_alph_layer_mmap(struct sdrv_g2d *gd, struct g2d_bg_cfg *bgcfg) { int ret = 0; struct g2d_buf *buf = &bgcfg->abufs; if (buf->fd > 0) { ret = g2d_dmabuf_import(gd, buf); if (ret) { G2D_ERROR("g2d alph layer mmap faild \n"); return ret; } bgcfg->aaddr = buf->dma_addr; G2D_DBG("alph layer used, fd is valid: fd = %d , phy addr = 0x%llx\n", buf->fd, bgcfg->aaddr); } else { G2D_DBG("alph layer used, fd is invalid, aaddr = 0x%llx \n", bgcfg->aaddr); } return ret; } static int g2d_layer_mmap(struct sdrv_g2d *gd, struct g2d_layer *layer) { int ret, i, j; struct g2d_buf *buf = &layer->bufs[0]; uint32_t tmp_addr_h; uint32_t tmp_addr_l; if (buf->fd <= 0) { G2D_ERROR("input layer buf fd invaild, fd(%d) <= 0\n", buf->fd); return -EINVAL; } ret = g2d_dmabuf_import(gd, buf); if (ret) { G2D_ERROR("g2d input layer mmap faild \n"); return ret; } G2D_DBG("layer->nplanes = %d\n", layer->nplanes); for (i = 0; i < layer->nplanes; i++) { unsigned long addr = buf->dma_addr + layer->offsets[i]; layer->addr_l[i] = get_l_addr(addr); layer->addr_h[i] = get_h_addr(addr); G2D_DBG("layer[%d] addr_l[%d] = 0x%x addr_h[%d] = 0x%x\n", layer->index, i, layer->addr_l[i], i, layer->addr_h[i]); } if(layer->format == DRM_FORMAT_BGR888_PLANE) { if (layer->nplanes != 3) { G2D_ERROR("format set : DRM_FORMAT_BGR888_PLANE, but nplanes(%d) != 3 \n", layer->nplanes); return -1; } tmp_addr_l = layer->addr_l[0]; tmp_addr_h = layer->addr_h[0]; layer->addr_l[0] = layer->addr_l[2]; layer->addr_h[0] = layer->addr_h[2]; layer->addr_l[2] = tmp_addr_l; layer->addr_h[2] = tmp_addr_h; for (j = 0; j < layer->nplanes; j++) { G2D_DBG("layer[%d] addr_l[%d] = 0x%x addr_h[%d] = 0x%x\n", layer->index, j, layer->addr_l[j], j, layer->addr_h[j]); } } return 0; } int g2d_output_layer_mmap(struct sdrv_g2d *gd, struct g2d_output_cfg *layer) { int ret; int j; uint64_t tmp_addr; struct g2d_buf *buf = &layer->bufs[0]; if (buf->fd <= 0) { G2D_ERROR("output layer buf fd invaild, fd(%d) <= 0\n", buf->fd); return -EINVAL; } ret = g2d_dmabuf_import(gd, buf); if (ret) { G2D_ERROR("g2d output layer mmap faild \n"); return ret; } for (j = 0; j < layer->nplanes; j++) { layer->addr[j] = buf->dma_addr + layer->offsets[j]; G2D_DBG("layer->addr[%d] = 0x%llx \n", j, layer->addr[j]); } if(layer->fmt == DRM_FORMAT_BGR888_PLANE) { if (layer->nplanes != 3) { G2D_ERROR("fmt set : DRM_FORMAT_BGR888_PLANE, but nplanes(%d) != 3 \n", layer->nplanes); return -1; } tmp_addr = layer->addr[0]; layer->addr[0] = layer->addr[2]; layer->addr[2] = tmp_addr; for (j = 0; j < layer->nplanes; j++) { G2D_DBG("fmt == DRM_FORMAT_BGR888_PLANE : layer->addr[%d] = 0x%llx \n", j, layer->addr[j]); } } return 0; } void g2d_alph_layer_unmap(struct sdrv_g2d *gd, struct g2d_bg_cfg *bgcfg) { struct g2d_buf *buf = &bgcfg->abufs; G2D_DBG("g2d dmabuf:%d\n", buf->fd); if (buf->fd <= 0) return; g2d_dmabuf_release(gd, buf); } void g2d_layer_unmap(struct sdrv_g2d *gd, struct g2d_layer *layer) { struct g2d_buf *buf = &layer->bufs[0]; G2D_DBG("g2d dmabuf:%d\n", buf->fd); if (buf->fd <= 0) return; g2d_dmabuf_release(gd, buf); } void g2d_output_layer_unmap(struct sdrv_g2d *gd, struct g2d_output_cfg *layer) { struct g2d_buf *buf = &layer->bufs[0]; G2D_DBG("g2d dmabuf:%d\n", buf->fd); if (buf->fd <= 0) return; g2d_dmabuf_release(gd, buf); } static int g2d_ioctl_begin(struct sdrv_g2d *gd, struct g2d_input *input) { int i; int ret; set_user_nice(current, -12); /*bg layer*/ if (input->bg_layer.en) { ret = g2d_alph_layer_mmap(gd, &input->bg_layer); if (ret) { return ret; } } /*input layer*/ for (i = 0; i < input->layer_num; i++) { struct g2d_layer *l = &input->layer[i]; if (!l->enable) continue; ret = g2d_layer_mmap(gd, l); if (ret) { return ret; } } /*output layer*/ ret = g2d_output_layer_mmap(gd, &input->output); if (ret) { return ret; } return 0; } static void g2d_ioctl_finish(struct sdrv_g2d *gd, struct g2d_input *input) { int i; /*bg layer*/ if (input->bg_layer.en) { g2d_alph_layer_unmap(gd, &input->bg_layer); } /*input layer*/ for (i = 0; i < input->layer_num; i++) { struct g2d_layer *l = &input->layer[i]; if (!l->enable) continue; g2d_layer_unmap(gd, l); } /*output layer*/ g2d_output_layer_unmap(gd, &input->output); } static int g2d_wait(struct sdrv_g2d *gd) { int status = 0; int rc; //g2d_dump_registers(gd); /* wait for stop done interrupt wait_event_timeout */ rc = wait_event_timeout(gd->wq, (gd->frame_done == true), msecs_to_jiffies(wait_timeout)); gd->frame_done = false; if (!rc) { status = -1; G2D_ERROR("g2d operation wait timeout %d\n", wait_timeout); g2d_dump_registers(gd); } else { if (dump_register_g2d == 1) { g2d_dump_registers(gd); } G2D_DBG("wait time %d\n", rc); } if (gd->ops->reset) gd->ops->reset(gd); return status; } static int g2d_fill_rect_ioctl(struct sdrv_g2d *gd, struct g2d_input *input) { int ret; ret = g2d_fill_rect(gd, &input->bg_layer, &input->output); if (ret < 0) { G2D_ERROR("g2d fill rect set register err \n"); goto OUT; } ret = g2d_wait(gd); OUT: if (ret < 0) dump_input(input); return ret; } static int g2d_fastcopy_dmabuf(struct sdrv_g2d *gd, struct g2d_input *input) { int ret = -1; addr_t iaddr, oaddr; struct g2d_output_cfg *out_layer = &input->output; struct g2d_bg_cfg *bg_layer = &input->bg_layer; struct g2d_buf *buf; if (!bg_layer->en) { G2D_ERROR("bg_layer en is %d, fast copy cannot be used\n", bg_layer->en); return ret; } iaddr = bg_layer->aaddr; buf = &out_layer->bufs[0]; oaddr = buf->dma_addr + out_layer->offsets[0]; if (iaddr % 4) { G2D_ERROR("The phy-addr(0x%lx) of the input needs to be 4-byte aligned\n", iaddr); return ret; } if (oaddr % 4) { G2D_ERROR("The phy-addr(0x%lx) of the output needs to be 4-byte aligned\n", oaddr); return ret; } if ((iaddr <= 0) || (oaddr <= 0)) { G2D_ERROR("input iaddr(0x%lx) or oaddr(0x%lx) = null\n", iaddr, oaddr); return ret; } ret = g2d_fastcopy_set(gd, iaddr, out_layer->width, out_layer->height, bg_layer->astride, oaddr, out_layer->stride[0]); if (ret < 0) { G2D_ERROR("g2d_fastcopy set register err \n"); goto OUT; } ret = g2d_wait(gd); OUT: if (ret < 0) dump_input(input); return ret; } static int sdrv_g2d_post_config(struct sdrv_g2d *gd, struct g2d_input *input) { int ret = 0; ret = g2d_post_config(gd, input); if(ret < 0) goto OUT; ret = g2d_wait(gd); OUT: if (ret < 0) dump_input(input); return ret; } static int sdrv_g2d_tasks(struct sdrv_g2d *gd, unsigned int cmd, struct g2d_input *input) { int ret; mutex_lock(&gd->m_lock); if (gd->monitor.is_monitor) gd->monitor.g2d_on_task = true; if (input->tables.set_tables) {//set filter tables g2d_set_coefficients_table(gd, &input->tables); } switch (cmd) { case G2D_IOCTL_POST_CONFIG: ret = sdrv_g2d_post_config(gd, input); G2D_DBG(" G2D_IOCTL_POST_CONFIG ret = %d\n", ret); break; case G2D_IOCTL_FAST_COPY: ret = g2d_fastcopy_dmabuf(gd, input); G2D_DBG("G2D_IOCTL_FAST_COPY end ret = %d\n", ret); break; case G2D_IOCTL_FILL_RECT: ret = g2d_fill_rect_ioctl(gd, input); G2D_DBG("G2D_IOCTL_FILL_RECT end ret = %d\n", ret); break; default: G2D_ERROR("Invalid ioctl cmd: 0x%x\n", cmd); ret = -EINVAL; break; } if (input->tables.set_tables) {//reset filter tables input->tables.set_tables = false; g2d_set_coefficients_table(gd, &input->tables); } if (gd->monitor.is_monitor) gd->monitor.g2d_on_task = false; mutex_unlock(&gd->m_lock); return ret; } void sdrv_dpc_to_g2d_layer(struct dpc_layer *int_layer, struct g2d_layer *out_layer) { out_layer->index = int_layer->index; //plane index out_layer->enable = int_layer->enable; out_layer->nplanes = int_layer->nplanes; out_layer->src_x = int_layer->src_x; out_layer->src_y = int_layer->src_y; out_layer->src_w = int_layer->src_w; out_layer->src_h = int_layer->src_h; out_layer->dst_x = int_layer->dst_x; out_layer->dst_y = int_layer->dst_y; out_layer->dst_w = int_layer->dst_w; out_layer->dst_h = int_layer->dst_h; out_layer->format = int_layer->format; out_layer->alpha = int_layer->alpha; out_layer->blend_mode = int_layer->blend_mode; out_layer->rotation = int_layer->rotation; out_layer->zpos = int_layer->zpos; out_layer->xfbc = int_layer->xfbc; out_layer->modifier = int_layer->modifier; out_layer->width = int_layer->width; out_layer->height = int_layer->height; memcpy(out_layer->addr_l, int_layer->addr_l, sizeof(out_layer->addr_l)); memcpy(out_layer->addr_h, int_layer->addr_h, sizeof(out_layer->addr_h)); memcpy(out_layer->pitch, int_layer->pitch, sizeof(out_layer->pitch)); memcpy(&out_layer->comp, &int_layer->comp, sizeof(struct pix_g2dcomp)); memcpy(&out_layer->ctx, &int_layer->ctx, sizeof(struct tile_ctx)); } int sdrv_g2d_convert_format(struct dpc_layer *layer, uint32_t g2d_out_format) { int ret = 0, i = 0; struct sdrv_g2d *gd = g_g2d[0]; struct g2d_input *input = NULL; uint32_t size = 0; static dma_addr_t paddr[2]; static void *vaddr[2]; static uint8_t index = 0; if (!gd) { G2D_ERROR("g2d hasn't exist\n"); return -ENODEV; } input = kzalloc(sizeof(struct g2d_input), GFP_KERNEL); if (!input) { G2D_ERROR("alloc input error\n"); return -ENOMEM; } size = layer->src_w * layer->src_h * 2; size = round_up(size, PAGE_SIZE); if (!vaddr[0]) { for (i = 0; i < 2; i++) { vaddr[i] = dma_alloc_wc(&gd->pdev->dev, size, &paddr[i], GFP_KERNEL | __GFP_NOWARN); if(!vaddr[i]) { G2D_ERROR("failed to allocate buffer of size %u\n", size); goto alloc_dma_err; } pr_info("dma addr[%d]:0x%llx vaddr[%d]:0x%p\n", i ,paddr[i], i, vaddr[i]); } } input->layer_num = 1; memcpy(&input->layer[0], layer, sizeof(struct g2d_layer)); sdrv_dpc_to_g2d_layer(layer, &input->layer[0]); pr_debug("format:%x, w:%d, h:%d s:%d al:%x\n", layer->format, layer->src_w, layer->src_h, layer->pitch[0], layer->addr_l[0]); input->output.width = layer->dst_w; input->output.height = layer->dst_h; input->output.stride[0] = layer->dst_w * 2; input->output.fmt = g2d_out_format; input->output.nplanes = 1; input->output.addr[0] = paddr[index]; pr_debug("o format:%x, w:%d, h:%d s:%d a:%llx\n", input->output.fmt, input->output.width, input->output.height, input->output.stride[0], input->output.addr[0]); mutex_lock(&gd->m_lock); ret = sdrv_g2d_post_config(gd, input); if (ret) { mutex_unlock(&gd->m_lock); goto out; } mutex_unlock(&gd->m_lock); layer->addr_l[0] = get_l_addr(input->output.addr[0]); layer->addr_h[0] = get_h_addr(input->output.addr[0]); layer->src_h = input->output.height; layer->src_w = input->output.width; layer->dst_h = input->output.height; layer->dst_w = input->output.width; layer->pitch[0] = input->output.stride[0]; index ++; if (index >= 2) index = 0; out: kfree(input); return ret; alloc_dma_err: while (i) { dma_free_wc(&gd->pdev->dev, size, vaddr[i], paddr[i]); i--; } kfree(input); return -ENOMEM; } EXPORT_SYMBOL(sdrv_g2d_convert_format); static int sdrv_g2d_func_work(struct sdrv_g2d *gd, unsigned int cmd, struct g2d_input *input) { int ret; if (!gd || !input) { G2D_ERROR("dev or input isn't inited.[dev:%p, ins:%p]\n", gd, input); return -EINVAL; } if ((input->output.height <= 0) || (input->output.width <= 0)) { G2D_ERROR("output input->output.height = %d, input->output.width = %d\n", input->output.height, input->output.width); return -EINVAL; } G2D_DBG("\r\n"); ret = g2d_ioctl_begin(gd, input); if (ret) { G2D_ERROR("input parameter err\n"); goto finish_out; } ret = sdrv_g2d_tasks(gd, cmd, input); finish_out: g2d_ioctl_finish(gd, input); return ret; } int sdrv_g2d_dma_copy(dma_addr_t dst, dma_addr_t src, size_t data_size) { int ret = 0; struct g2d_input *input; struct sdrv_g2d *gd = g_g2d[0]; int width, height, stride; width = 32; stride = width * 4; height = (data_size / stride) + ((data_size % stride) ? 1 : 0); G2D_DBG("data_size, width, stride, height : (%ld, %d, %d, %d)\n", data_size, width, stride, height); input = kzalloc(sizeof(struct g2d_input), GFP_ATOMIC | GFP_DMA); if (!input) { G2D_ERROR("kzalloc input failed\n"); return -EFAULT; } input->bg_layer.en = 1; input->bg_layer.width = width; input->bg_layer.height = height; input->bg_layer.astride = stride; input->bg_layer.aaddr = (uint64_t)src; input->output.bufs[0].dma_addr = (uint64_t)dst; input->output.width = width; input->output.height = height; input->output.stride[0] = stride; ret = sdrv_g2d_tasks(gd, G2D_IOCTL_FAST_COPY, input); kfree(input); return ret; } EXPORT_SYMBOL(sdrv_g2d_dma_copy); static long sdrv_g2d_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int ret = -1; int i=0, n = 0; struct sdrv_g2d *gd = file->private_data; struct g2d_input *input; struct g2d_inputx *inputx; if (_IOC_TYPE(cmd) != G2D_IOCTL_BASE) return -EINVAL; if (_IOC_NR(cmd) > 4) return -EINVAL; if (_IOC_DIR(cmd) & _IOC_READ) { ret = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd)); if (ret) return -EFAULT; } if (_IOC_DIR(cmd) & _IOC_WRITE) { ret = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd)); if (ret) return -EFAULT; } inputx = kzalloc(sizeof(struct g2d_inputx), GFP_ATOMIC | GFP_DMA); if (!inputx) { G2D_ERROR("kzalloc input failed\n"); return -EFAULT; } input = kzalloc(sizeof(struct g2d_input), GFP_ATOMIC | GFP_DMA); if (!input) { G2D_ERROR("kzalloc input failed\n"); if (inputx) kfree(inputx); return -EFAULT; } memset(inputx,0,sizeof(struct g2d_inputx)); memset(input,0,sizeof(struct g2d_input)); if (cmd == G2D_IOCTL_GET_CAPABILITIES) { ret = copy_to_user((struct g2d_capability __user *)arg, &gd->cap, sizeof(struct g2d_capability)); if (ret) { G2D_ERROR("get capabilities err \n"); ret = -EFAULT; } } else { ret = copy_from_user(inputx, (struct g2d_inputx __user *)arg, sizeof(struct g2d_inputx)); if (ret) { G2D_ERROR("copy_from_user failed\n"); ret = -EFAULT; goto unlock_out; } //for 32bit and 64 bit capibility; input->layer_num = inputx->layer_num; memcpy((void *)(&input->bg_layer),(void *)(&inputx->bg_layer),sizeof(struct g2d_bg_cfg_x)); input->bg_layer.abufs.dma_addr = input->bg_layer.cfg_buf.dma_addr; input->bg_layer.abufs.fd = input->bg_layer.cfg_buf.fd; input->bg_layer.abufs.size = input->bg_layer.cfg_buf.size; input->bg_layer.abufs.vaddr = input->bg_layer.cfg_buf.vaddr; memcpy((void *)(&input->output), (void *)(&inputx->output),sizeof(struct g2d_output_cfg_x)); for (i = 0; i < 4; i++) { input->output.bufs[i].dma_addr = input->output.out_buf[i].dma_addr; input->output.bufs[i].fd = input->output.out_buf[i].fd; input->output.bufs[i].size = input->output.out_buf[i].size; input->output.bufs[i].vaddr = input->output.out_buf[i].vaddr; } memcpy((void *)(&input->tables), (void *)(&inputx->tables),sizeof(struct g2d_coeff_table)); for (n = 0; n < G2D_LAYER_MAX_NUM;n ++) { memcpy((void *)(&input->layer[n]),(void *)(&inputx->layer[n]),sizeof(struct g2d_layer_x)); for (i = 0; i < 4; i++) { input->layer[n].bufs[i].dma_addr = input->layer[n].in_buf[i].dma_addr; input->layer[n].bufs[i].fd = input->layer[n].in_buf[i].fd; input->layer[n].bufs[i].size = input->layer[n].in_buf[i].size; input->layer[n].bufs[i].vaddr = input->layer[n].in_buf[i].vaddr; } } ret = sdrv_g2d_func_work(gd, cmd, input); } unlock_out: if (input) kfree(input); if (inputx) kfree(inputx); return (long)ret; } #if defined(CONFIG_COMPAT) static long sdrv_g2d_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { return sdrv_g2d_ioctl(file, cmd, arg); } #endif /* defined(CONFIG_COMPAT) */ ssize_t sdrv_g2d_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) { struct sdrv_g2d *gd = file->private_data; char str[64] = {0}; ssize_t sz = sprintf(str, "read from %s\n", gd->name); if (copy_to_user(buf, str, sz)){ G2D_ERROR("copy to user failed: %s\n", gd->name); } return sz; } static const struct file_operations g2d_fops = { .owner = THIS_MODULE, .open = sdrv_g2d_open, .read = sdrv_g2d_read, .unlocked_ioctl = sdrv_g2d_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = sdrv_g2d_compat_ioctl, #endif }; static int g2d_misc_init(struct sdrv_g2d *gd) { int ret; struct miscdevice *m = &gd->mdev;; m->minor = MISC_DYNAMIC_MINOR; m->name = kasprintf(GFP_KERNEL, "g2d%d", gd->id); m->fops = &g2d_fops; m->parent = NULL; m->groups = sdrv_g2d_groups; ret = misc_register(m); if (ret) { G2D_ERROR("failed to register miscdev\n"); return ret; } G2D_INFO("%s misc register \n", m->name); return ret; } static int sdrv_g2d_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct sdrv_g2d *gd = NULL; static int pipe_registered = 0; dma_addr_t dma_handle; int ret = 0, i; mutex_lock(&m_init); G2D_INFO("G2D BUILD VERSION : %s \n", version); // 38 bits address for KUNLUN G2D rdma,use G2D_CPU_WRITE config 38bit; use G2D_CMD_WRITE config 32bit dma_set_mask(dev, DMA_BIT_MASK(32)); dma_set_coherent_mask(dev, DMA_BIT_MASK(32)); gd = devm_kzalloc(&pdev->dev, sizeof(struct sdrv_g2d), GFP_KERNEL); if (!gd) { G2D_ERROR("kalloc sdrv_g2d failed\n"); ret = -1; goto OUT; } gd->du_inited = false; gd->pdev = pdev; if (!pipe_registered) { pipe_registered++; g2d_pipe_ops_register(&spipe_g2d_entry); g2d_pipe_ops_register(&gpipe_high_g2d_entry); g2d_pipe_ops_register(&gpipe_mid_g2d_entry); } /*cmdfile init*/ gd->cmd_info[0].arg = (unsigned int*)dma_alloc_coherent(dev, G2D_CMDFILE_MAX_MEM * sizeof(unsigned int), &dma_handle, GFP_KERNEL); gd->dma_buf = (unsigned long)dma_handle; if (gd->cmd_info[0].arg == NULL) { G2D_ERROR("malloc cmd_info failed\n"); goto OUT; } G2D_INFO("gd->cmd_info[0].arg virtual address = 0x%lx, phy address 0x%lx,dma alloc coherent len = %ld\n", (unsigned long)gd->cmd_info[0].arg, gd->dma_buf, G2D_CMDFILE_MAX_MEM * sizeof(unsigned int)); for (i = 1 ; i < G2D_CMDFILE_MAX_NUM; i++) { gd->cmd_info[i].arg = gd->cmd_info[i - 1].arg + G2D_CMDFILE_MAX_MEM / G2D_CMDFILE_MAX_NUM; } #ifdef CONFIG_OF G2D_INFO("CONFIG_OF scope\n"); sdrv_init_iommu(gd); ret = sdrv_g2d_init(gd, dev->of_node); #else G2D_INFO("CONFIG_OF is closed\n"); ret = sdrv_g2d_init(gd, pdev); #endif if (ret) goto OUT; mutex_init(&gd->m_lock); gd->monitor.sampling_time = 5; ret = g2d_misc_init(gd); if (ret) goto OUT; else printk("%s : semidrive g2d driver registered.\n", __func__); platform_set_drvdata(pdev, gd); g_g2d[gd->id] = gd; gd->du_inited = true; enable_irq(gd->irq); ret = 0; OUT: mutex_unlock(&m_init); return ret; } static int sdrv_g2d_remove(struct platform_device *pdev) { struct sdrv_g2d *gd = platform_get_drvdata(pdev); G2D_DBG("remove g2d %s\n", gd->name); if (gd) { sdrv_iommu_cleanup(gd); sdrv_g2d_unit(gd); misc_deregister(&gd->mdev); } return 0; } #ifdef CONFIG_OF static const struct of_device_id g2d_of_table[] = { {.compatible = "semidrive,g2d", .data = g2d_data}, {.compatible = "semidrive,g2d_lite", .data = g2d_data}, {}, }; #endif static int sdrv_g2d_suspend(struct device *dev) { struct sdrv_g2d *gd = dev_get_drvdata(dev); G2D_INFO("%s start\n", __func__); gd->ops->reset(gd); G2D_INFO("gd->du_inited = %d, gd->num_pipe = %d\n", gd->du_inited, gd->num_pipe); G2D_INFO("%s end\n", __func__); return 0; } static int sdrv_g2d_resume(struct device *dev) { struct sdrv_g2d *gd = dev_get_drvdata(dev); struct g2d_pipe *p = NULL; int i; G2D_INFO("%s start\n", __func__); G2D_INFO("gd->du_inited = %d, gd->num_pipe = %d\n", gd->du_inited, gd->num_pipe); gd->ops->init(gd); for (i = 0; i < gd->num_pipe; i++) { p = gd->pipes[i]; if (p && p->ops->init) p->ops->init(p); else G2D_ERROR("p or p->ops->init is null\n"); } gd->ops->reset(gd); G2D_INFO("%s end\n", __func__); return 0; } static const struct dev_pm_ops sdrv_g2d_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(sdrv_g2d_suspend, sdrv_g2d_resume) }; static struct platform_driver g2d_driver = { .probe = sdrv_g2d_probe, .remove = sdrv_g2d_remove, .driver = { .name = "semidrive-g2d", .owner = THIS_MODULE, #ifdef CONFIG_OF .of_match_table = g2d_of_table, #endif .pm = &sdrv_g2d_pm_ops, }, }; module_platform_driver(g2d_driver); MODULE_AUTHOR("Semidrive Semiconductor"); MODULE_DESCRIPTION("Semidrive g2d"); MODULE_LICENSE("GPL"); 以上是linux内核g2d驱动文件sdrv_g2d.c #ifndef __SDRV_G2D_H__ #define __SDRV_G2D_H__ #include #include #include #include #include #include #include <asm/io.h> #include #include #include <uapi/drm/drm_fourcc.h> #include <uapi/drm/sdrv_g2d_cfg.h> #include "g2d_common.h" #define PR_INFO pr_info #define ERROR pr_err typedef unsigned long int addr_t; #ifndef ARRAY_SIZE #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #endif extern int debug_g2d; #define G2D_INFO(fmt, args...) do {\ PR_INFO("[g2d] [%20s] " fmt, __func__, ##args);\ }while(0) #define G2D_DBG(fmt, args...) do {\ if (debug_g2d >= 1) {\ PR_INFO("[g2d] <%d> [%20s] " fmt, __LINE__, __func__, ##args);}\ }while(0) #define G2D_ERROR(fmt, args...) ERROR("[g2d] <%d> [%20s] Error: " fmt, __LINE__, __func__, ##args) #define DDBG(x) G2D_DBG(#x " -> %d\n", x) #define XDBG(x) G2D_DBG(#x " -> 0x%x\n", x) #define PDBG(x) G2D_DBG(#x " -> %p\n", x) #define ENTRY() G2D_DBG("call <%d>\n", __LINE__) #define GP_ECHO_NAME "g2d_gpipe_echo" #define GP_MID_NAME "g2d_gpipe_mid" #define GP_HIGH_NAME "g2d_gpipe_high" #define SPIPE_NAME "g2d_spipe" #define G2D_NR_DEVS 4 /*Kunlun DP layer format TILE vsize*/ enum { TILE_VSIZE_1 = 0b000, TILE_VSIZE_2 = 0b001, TILE_VSIZE_4 = 0b010, TILE_VSIZE_8 = 0b011, TILE_VSIZE_16 = 0b100, }; /*Kunlun DP layer format TILE hsize*/ enum { TILE_HSIZE_1 = 0b000, TILE_HSIZE_8 = 0b001, TILE_HSIZE_16 = 0b010, TILE_HSIZE_32 = 0b011, TILE_HSIZE_64 = 0b100, TILE_HSIZE_128 = 0b101, }; /**/ enum { FBDC_U8U8U8U8 = 0xc, FBDC_U16 = 0x9, FBDC_R5G6B5 = 0x5, FBDC_U8 = 0x0, FBDC_NV21 = 0x37, FBDC_YUV420_16PACK = 0x65 }; enum kunlun_plane_property { PLANE_PROP_ALPHA, PLANE_PROP_BLEND_MODE, PLANE_PROP_FBDC_HSIZE_Y, PLANE_PROP_FBDC_HSIZE_UV, PLANE_PROP_CAP_MASK, PLANE_PROP_MAX_NUM }; enum { DRM_MODE_BLEND_PIXEL_NONE = 0, DRM_MODE_BLEND_PREMULTI, DRM_MODE_BLEND_COVERAGE }; enum { PLANE_DISABLE, PLANE_ENABLE }; enum { PROP_PLANE_CAP_RGB = 0, PROP_PLANE_CAP_YUV, PROP_PLANE_CAP_XFBC, PROP_PLANE_CAP_YUV_FBC, PROP_PLANE_CAP_ROTATION, PROP_PLANE_CAP_SCALING, }; enum { TYPE_GP_ECHO = 0, TYPE_GP_MID, TYPE_GP_HIGH, TYPE_SPIPE }; struct g2d_pipe; struct pipe_operation { int (*init)(struct g2d_pipe *); int (*set)(struct g2d_pipe *, int , struct g2d_layer *); void (*csc_coef_set)(struct g2d_pipe *, struct g2d_coeff_table *); }; struct g2d_pipe { void __iomem *iomem_regs; void __iomem *regs; unsigned long reg_offset; int id; // the ordered id from 0 struct sdrv_g2d *gd; const char *name; int type; struct pipe_operation *ops; struct g2d_pipe_capability *cap; struct g2d_pipe *next; }; struct g2d_monitor { int is_monitor; int is_init; ktime_t timeout; struct hrtimer timer; bool g2d_on_task; int occupancy_rate; int timer_count; int valid_times; int sampling_time; }; struct sdrv_g2d { struct platform_device *pdev; struct cdev cdev; struct miscdevice mdev; void __iomem *iomem_regs; void __iomem *regs; bool iommu_enable; struct iommu_domain *domain; struct mutex m_lock; struct wait_queue_head wq; bool frame_done; int id; const char *name; int irq; int write_mode; cmdfile_info cmd_info[G2D_CMDFILE_MAX_NUM]; unsigned long dma_buf; const struct g2d_ops *ops; struct g2d_capability cap; struct g2d_pipe *pipes[PIPE_MAX]; int num_pipe; int du_inited; struct g2d_monitor monitor; }; struct g2d_ops { int (*init)(struct sdrv_g2d *); int (*enable)(struct sdrv_g2d*, int); int (*reset)(struct sdrv_g2d *); int (*mlc_set)(struct sdrv_g2d *, int , struct g2d_input *); int (*fill_rect)(struct sdrv_g2d *, struct g2d_bg_cfg *, struct g2d_output_cfg *); int (*fastcopy)(struct sdrv_g2d *, addr_t , u32 , u32 , u32 , addr_t , u32); int (*config)(struct sdrv_g2d *); int (*irq_handler)(struct sdrv_g2d *); int (*rwdma)(struct sdrv_g2d *, struct g2d_input *); void (*close_fastcopy)(struct sdrv_g2d *); int (*wpipe_set)(struct sdrv_g2d *, int, struct g2d_output_cfg *); int (*check_stroke)(struct g2d_input *); int (*scaler_coef_set)(struct sdrv_g2d *, struct g2d_coeff_table *); }; struct sdrv_g2d_data { const char *version; const struct g2d_ops* ops; }; struct ops_entry { const char *ver; void *ops; }; int g2d_get_capability(struct g2d_capability *cap); unsigned int get_compval_from_comp(struct pix_g2dcomp *comp); unsigned int get_frm_ctrl_from_comp(struct pix_g2dcomp *comp); int sdrv_wpipe_pix_comp(uint32_t format, struct pix_g2dcomp *comp); int sdrv_pix_comp(uint32_t format, struct pix_g2dcomp *comp); bool g2d_format_is_yuv(uint32_t format); int g2d_format_wpipe_bypass(uint32_t format); struct ops_list { struct list_head head; struct ops_entry *entry; }; extern struct list_head g2d_pipe_list_head; int g2d_ops_register(struct ops_entry *entry, struct list_head *head); void *g2d_ops_attach(const char *str, struct list_head *head); #define g2d_pipe_ops_register(entry) g2d_ops_register(entry, &g2d_pipe_list_head) #define g2d_pipe_ops_attach(str) g2d_ops_attach(str, &g2d_pipe_list_head) int g2d_choose_pipe(struct sdrv_g2d *gd, int hwid, int type, uint32_t offset); struct sdrv_g2d *get_g2d_by_id(int id); extern struct ops_entry gpipe_mid_g2d_entry; extern struct ops_entry gpipe_high_g2d_entry; extern struct ops_entry spipe_g2d_entry; #endif //__SDRV_G2D_H__ 以上是linux内核的g2d驱动的头文件sdrv_g2d.h #ifndef __SDRV_G2D_CFG_H #define __SDRV_G2D_CFG_H #include "sdrv_drm.h" #ifdef __YOCTO_G2D_TEST__ typedef __u8 uint8_t; typedef __u16 uint16_t; typedef __u32 uint32_t; typedef unsigned long uint64_t; #endif #define G2D_LAYER_MAX_NUM 6 #ifndef G2DLITE_API_USE typedef enum { SWAP_A_RGB = 0b0000, SWAP_A_RBG = 0b0001, SWAP_A_GBR = 0b0010, SWAP_A_GRB = 0b0011, SWAP_A_BGR = 0b0100, SWAP_A_BRG = 0b0101, SWAP_B_ARG = 0b1000, SWAP_B_AGR = 0b1001, SWAP_B_RGA = 0b1010, SWAP_B_RAG = 0b1011, SWAP_B_GRA = 0b1100, SWAP_B_GAR = 0b1101 } COMP_SWAP_MODE; typedef enum { UV_YUV444_RGB = 0b00, UV_YUV422 = 0b01, UV_YUV440 = 0b10, UV_YUV420 = 0b11 } DATA_UV_MODE; typedef enum { LINEAR_MODE = 0b000, RLE_COMPR_MODE = 0b001, GPU_RAW_TILE_MODE = 0b010, GPU_CPS_TILE_MODE = 0b011, VPU_RAW_TILE_MODE = 0b100, VPU_CPS_TILE_MODE = 0b101, VPU_RAW_TILE_988_MODE = 0b110, } DATA_MODE; typedef enum { FMT_INTERLEAVED = 0b00, FMT_MONOTONIC = 0b01, FMT_SEMI_PLANAR = 0b10, FMT_PLANAR = 0b11 } FRM_BUF_STR_FMT; typedef enum { ROT_DEFAULT = 0b000, ROT_ROT = 0b001, ROT_VFLIP = 0b010, ROT_HFLIP = 0b100 } ROT_TYPE; #endif #ifndef G2DLITE_API_USE enum { BLEND_PIXEL_NONE = 0, BLEND_PIXEL_PREMULTI, BLEND_PIXEL_COVERAGE }; typedef enum { ROTATION_TYPE_NONE = 0b000, ROTATION_TYPE_ROT_90 = 0b001, ROTATION_TYPE_HFLIP = 0b010, ROTATION_TYPE_VFLIP = 0b100, ROTATION_TYPE_ROT_180 = ROTATION_TYPE_VFLIP | ROTATION_TYPE_HFLIP, ROTATION_TYPE_ROT_270 = ROTATION_TYPE_ROT_90 | ROTATION_TYPE_VFLIP | ROTATION_TYPE_HFLIP, ROTATION_TYPE_VF_90 = ROTATION_TYPE_VFLIP | ROTATION_TYPE_ROT_90, ROTATION_TYPE_HF_90 = ROTATION_TYPE_HFLIP | ROTATION_TYPE_ROT_90, } rotation_type; #endif typedef enum { PD_NONE = 0, PD_SRC = 0x1, PD_DST = 0x2 } PD_LAYER_TYPE; struct g2d_output_cfg{ uint32_t width; uint32_t height; uint32_t fmt; uint64_t addr[4]; uint32_t stride[4]; uint32_t rotation; uint32_t nplanes; uint32_t offsets[4]; struct tile_ctx out_ctx; struct g2d_buf_info out_buf[4]; struct g2d_buf bufs[4]; }; struct g2d_bg_cfg { uint32_t en; uint32_t color; uint8_t g_alpha; uint8_t zorder; uint64_t aaddr; uint8_t bpa; uint32_t astride; uint32_t x; uint32_t y; uint32_t width; uint32_t height; PD_LAYER_TYPE pd_type; struct g2d_buf_info cfg_buf; struct g2d_buf abufs; }; struct g2d_coeff_table { int set_tables; int hcoef_set; int hcoef[33][5]; int vcoef_set; int vcoef[33][4]; int csc_coef_set; int csc_coef[15]; }; struct g2d_input{ unsigned char layer_num; struct g2d_bg_cfg bg_layer; struct g2d_layer layer[G2D_LAYER_MAX_NUM]; struct g2d_output_cfg output; struct g2d_coeff_table tables; }; struct g2d_pipe_capability { uint32_t formats[100]; int nformats; int layer_type; int rotation; int scaling; int yuv; int yuv_fbc; int xfbc; }; struct g2d_capability { int num_pipe; struct g2d_pipe_capability pipe_caps[G2D_LAYER_MAX_NUM]; }; struct g2d_layer_x { __u8 index; //plane index __u8 enable; __u8 nplanes; __u32 addr_l[4]; __u32 addr_h[4]; __u32 pitch[4]; __u32 offsets[4]; __s16 src_x; __s16 src_y; __s16 src_w; __s16 src_h; __s16 dst_x; __s16 dst_y; __u16 dst_w; __u16 dst_h; __u32 format; struct pix_g2dcomp comp; struct tile_ctx ctx; __u32 alpha; __u32 blend_mode; __u32 rotation; __u32 zpos; __u32 xfbc; __u64 modifier; __u32 width; __u32 height; struct g2d_buf_info in_buf[4]; }; struct g2d_output_cfg_x{ uint32_t width; uint32_t height; uint32_t fmt; uint64_t addr[4]; uint32_t stride[4]; uint32_t rotation; uint32_t nplanes; uint32_t offsets[4]; struct tile_ctx out_ctx; struct g2d_buf_info out_buf[4]; }; struct g2d_bg_cfg_x { uint32_t en; uint32_t color; uint8_t g_alpha; uint8_t zorder; uint64_t aaddr; uint8_t bpa; uint32_t astride; uint32_t x; uint32_t y; uint32_t width; uint32_t height; PD_LAYER_TYPE pd_type; struct g2d_buf_info cfg_buf; }; struct g2d_inputx{ unsigned char layer_num; struct g2d_bg_cfg_x bg_layer; struct g2d_layer_x layer[G2D_LAYER_MAX_NUM]; struct g2d_output_cfg_x output; struct g2d_coeff_table tables; }; #define G2D_COMMAND_BASE 0x00 #define G2D_IOCTL_BASE 'g' #define G2D_IO(nr) _IO(G2D_IOCTL_BASE,nr) #define G2D_IOR(nr,type) _IOR(G2D_IOCTL_BASE,nr,type) #define G2D_IOW(nr,type) _IOW(G2D_IOCTL_BASE,nr,type) #define G2D_IOWR(nr,type) _IOWR(G2D_IOCTL_BASE,nr,type) #define G2D_IOCTL_GET_CAPABILITIES G2D_IOWR(G2D_COMMAND_BASE + 1, struct g2d_capability) #define G2D_IOCTL_POST_CONFIG G2D_IOWR(G2D_COMMAND_BASE + 2, struct g2d_inputx) #define G2D_IOCTL_FAST_COPY G2D_IOWR(G2D_COMMAND_BASE + 3, struct g2d_inputx) #define G2D_IOCTL_FILL_RECT G2D_IOWR(G2D_COMMAND_BASE + 4, struct g2d_inputx) #endif //__SDRV_G2D_CFG_H 以上是linux内核提供给linux应用层调用的头文件。 请提供所有文件的中文详细注释,并结合lvgl 9.2.2版版本源码和/dev/g2d0设备,实现调用g2d硬件资源进行图形绘制linux应用代码。

static int media_get_socket(void* handle) { MediaIOPriv* priv = handle; if (!priv || priv->socket <= 0) return -EINVAL; return priv->socket; } /**************************************************************************** * Public Functions ****************************************************************************/ int media_process_command(const char* target, const char* cmd, const char* arg, char* res, int res_len) { return media_proxy(MEDIA_ID_GRAPH, NULL, target, cmd, arg, 0, res, res_len); } void media_graph_dump(const char* options) { media_proxy(MEDIA_ID_GRAPH, NULL, NULL, "dump", options, 0, NULL, 0); } void* media_player_open(const char* params) { return media_open(MEDIA_ID_PLAYER, params); } int media_player_close(void* handle, int pending_stop) { return media_close(handle, pending_stop); } int media_player_set_event_callback(void* handle, void* cookie, media_event_callback event_cb) { return media_set_event_cb(handle, cookie, event_cb); } int media_player_prepare(void* handle, const char* url, const char* options) { return media_prepare(handle, url, options); } int media_player_reset(void* handle) { if (!handle) return -EINVAL; media_close_socket(handle); return media_proxy_once(handle, NULL, "reset", NULL, 0, NULL, 0); } ssize_t media_player_write_data(void* handle, const void* data, size_t len) { return media_process_data(handle, true, (void*)data, len); } int media_player_get_sockaddr(void* handle, struct sockaddr_storage* addr) { return media_get_sockaddr(handle, addr); } void media_player_close_socket(void* handle) { media_close_socket(handle); } int media_player_get_socket(void* handle) { return media_get_socket(handle); } int media_player_start(void* handle) { if (!handle) return -EINVAL; return media_proxy_once(handle, NULL, "start", NULL, 0, NULL, 0); } int media_player_stop(void* handle) { if (!handle) return -EINVAL; media_close_socket(handle); return media_proxy_once(handle, NULL, "stop", NULL, 0, NULL, 0); } int media_player_pause(void* handle) { return media_proxy_once(handle, NULL, "pause", NULL, 0, NULL, 0); } int media_player_seek(void* handle, unsigned int msec) { char tmp[32]; snprintf(tmp, sizeof(tmp), "%u", msec); return media_proxy_once(handle, NULL, "seek", tmp, 0, NULL, 0); } int media_player_set_looping(void* handle, int loop) { char tmp[32]; snprintf(tmp, sizeof(tmp), "%d", loop); return media_proxy_once(handle, NULL, "set_loop", tmp, 0, NULL, 0); } int media_player_is_playing(void* handle) { char tmp[32]; int ret; ret = media_proxy_once(handle, NULL, "get_playing", NULL, 0, tmp, sizeof(tmp)); return ret < 0 ? ret : !!atoi(tmp); } int media_player_get_position(void* handle, unsigned int* msec) { char tmp[32]; int ret; if (!msec) return -EINVAL; ret = media_proxy_once(handle, NULL, "get_position", NULL, 0, tmp, sizeof(tmp)); if (ret >= 0) *msec = strtoul(tmp, NULL, 0); return ret; } int media_player_get_duration(void* handle, unsigned int* msec) { char tmp[32]; int ret; if (!msec) return -EINVAL; ret = media_proxy_once(handle, NULL, "get_duration", NULL, 0, tmp, sizeof(tmp)); if (ret >= 0) *msec = strtoul(tmp, NULL, 0); return ret; } int media_player_get_latency(void* handle, unsigned int* latency) { char tmp[32]; int ret; if (!latency) return -EINVAL; ret = media_proxy_once(handle, NULL, "get_latency", NULL, 0, tmp, sizeof(tmp)); if (ret >= 0) *latency = strtoul(tmp, NULL, 0); return ret; } int media_player_set_volume(void* handle, float volume) { char tmp[32]; snprintf(tmp, sizeof(tmp), "%f", volume); return media_proxy_once(handle, NULL, "volume", tmp, 0, NULL, 0); } int media_player_get_volume(void* handle, float* volume) { char tmp[32]; int ret; if (!volume) return -EINVAL; ret = media_proxy_once(handle, NULL, "get_volume", NULL, 0, tmp, sizeof(tmp)); if (ret >= 0) { sscanf(tmp, "vol:%f", volume); ret = 0; } return ret; } int media_player_set_property(void* handle, const char* target, const char* key, const char* value) { return media_proxy_once(handle, target, key, value, 0, NULL, 0); } int media_player_get_property(void* handle, const char* target, const char* key, char* value, int value_len) { return media_proxy_once(handle, target, key, NULL, 0, value, value_len); } void* media_recorder_open(const char* params) { return media_open(MEDIA_ID_RECORDER, params); } int media_recorder_close(void* handle) { return media_close(handle, 0); } int media_recorder_set_event_callback(void* handle, void* cookie, media_event_callback event_cb) { return media_set_event_cb(handle, cookie, event_cb); } int media_recorder_prepare(void* handle, const char* url, const char* options) { return media_prepare(handle, url, options); } int media_recorder_reset(void* handle) { if (!handle) return -EINVAL; media_close_socket(handle); return media_proxy_once(handle, NULL, "reset", NULL, 0, NULL, 0); } ssize_t media_recorder_read_data(void* handle, void* data, size_t len) { return media_process_data(handle, false, data, len); } int media_recorder_get_sockaddr(void* handle, struct sockaddr_storage* addr) { return media_get_sockaddr(handle, addr); } int media_recorder_get_socket(void* handle) { return media_get_socket(handle); } void media_recorder_close_socket(void* handle) { media_close_socket(handle); } int media_recorder_start(void* handle) { return media_proxy_once(handle, NULL, "start", NULL, 0, NULL, 0); } int media_recorder_pause(void* handle) { return media_proxy_once(handle, NULL, "pause", NULL, 0, NULL, 0); } int media_recorder_stop(void* handle) { if (!handle) return -EINVAL; media_close_socket(handle); return media_proxy_once(handle, NULL, "stop", NULL, 0, NULL, 0); } int media_recorder_set_property(void* handle, const char* target, const char* key, const char* value) { return media_proxy_once(handle, target, key, value, 0, NULL, 0); } int media_recorder_get_property(void* handle, const char* target, const char* key, char* value, int value_len) { return media_proxy_once(handle, target, key, NULL, 0, value, value_len); } int media_recorder_take_picture(char* params, char* filename, size_t number) { int ret = 0; MediaIOPriv* priv; if (!number || number > INT_MAX) return -EINVAL; priv = calloc(1, sizeof(MediaIOPriv)); if (!priv) return -ENOMEM; sem_init(&priv->sem, 0, 0); priv->cookie = media_recorder_start_picture(params, filename, number, media_recorder_take_picture_cb, priv); if (!priv->cookie) { free(priv); return -EINVAL; } sem_wait(&priv->sem); sem_destroy(&priv->sem); ret = priv->result; free(priv); return ret; } void* media_recorder_start_picture(char* params, char* filename, size_t number, media_event_callback event_cb, void* cookie) { char option[32]; void* handle = NULL; int ret; if (!number || number > INT_MAX) return NULL; handle = media_recorder_open(params); if (!handle) return NULL; ret = media_recorder_set_event_callback(handle, cookie, event_cb); if (ret < 0) goto error; snprintf(option, sizeof(option), "total_number=%zu", number); ret = media_recorder_prepare(handle, filename, option); if (ret < 0) goto error; ret = media_recorder_start(handle); if (ret < 0) goto error; return handle; error: media_recorder_close(handle); return NULL; } int media_recorder_finish_picture(void* handle) { return media_recorder_close(handle); }

最新推荐

recommend-type

Comsol声子晶体能带计算:六角与三角晶格原胞选取及布里渊区高对称点选择 - 声子晶体 v1.0

内容概要:本文详细探讨了利用Comsol进行声子晶体能带计算过程中,六角晶格和三角晶格原胞选取的不同方法及其对简约布里渊区高对称点选择的影响。文中不仅介绍了两种晶格类型的基矢量定义方式,还强调了正确设置周期性边界条件(特别是相位补偿)的重要性,以避免计算误差如鬼带现象。同时,提供了具体的MATLAB代码片段用于演示关键步骤,并分享了一些实践经验,例如如何通过观察能带图中的狄拉克锥特征来验证路径设置的准确性。 适合人群:从事材料科学、物理学研究的专业人士,尤其是那些正在使用或计划使用Comsol软件进行声子晶体模拟的研究人员。 使用场景及目标:帮助研究人员更好地理解和掌握在Comsol环境中针对不同类型晶格进行精确的声子晶体能带计算的方法和技术要点,从而提高仿真精度并减少常见错误的发生。 其他说明:文章中提到的实际案例展示了因晶格类型混淆而导致的问题,提醒使用者注意细节差异,确保模型构建无误。此外,文中提供的代码片段可以直接应用于相关项目中作为参考模板。
recommend-type

springboot213大学生心理健康管理系统的设计与实现.zip

springboot213大学生心理健康管理系统的设计与实现
recommend-type

Web前端开发:CSS与HTML设计模式深入解析

《Pro CSS and HTML Design Patterns》是一本专注于Web前端设计模式的书籍,特别针对CSS(层叠样式表)和HTML(超文本标记语言)的高级应用进行了深入探讨。这本书籍属于Pro系列,旨在为专业Web开发人员提供实用的设计模式和实践指南,帮助他们构建高效、美观且可维护的网站和应用程序。 在介绍这本书的知识点之前,我们首先需要了解CSS和HTML的基础知识,以及它们在Web开发中的重要性。 HTML是用于创建网页和Web应用程序的标准标记语言。它允许开发者通过一系列的标签来定义网页的结构和内容,如段落、标题、链接、图片等。HTML5作为最新版本,不仅增强了网页的表现力,还引入了更多新的特性,例如视频和音频的内置支持、绘图API、离线存储等。 CSS是用于描述HTML文档的表现(即布局、颜色、字体等样式)的样式表语言。它能够让开发者将内容的表现从结构中分离出来,使得网页设计更加模块化和易于维护。随着Web技术的发展,CSS也经历了多个版本的更新,引入了如Flexbox、Grid布局、过渡、动画以及Sass和Less等预处理器技术。 现在让我们来详细探讨《Pro CSS and HTML Design Patterns》中可能包含的知识点: 1. CSS基础和选择器: 书中可能会涵盖CSS基本概念,如盒模型、边距、填充、边框、背景和定位等。同时还会介绍CSS选择器的高级用法,例如属性选择器、伪类选择器、伪元素选择器以及选择器的组合使用。 2. CSS布局技术: 布局是网页设计中的核心部分。本书可能会详细讲解各种CSS布局技术,包括传统的浮动(Floats)布局、定位(Positioning)布局,以及最新的布局模式如Flexbox和CSS Grid。此外,也会介绍响应式设计的媒体查询、视口(Viewport)单位等。 3. 高级CSS技巧: 这些技巧可能包括动画和过渡效果,以及如何优化性能和兼容性。例如,CSS3动画、关键帧动画、转换(Transforms)、滤镜(Filters)和混合模式(Blend Modes)。 4. HTML5特性: 书中可能会深入探讨HTML5的新标签和语义化元素,如`<article>`、`<section>`、`<nav>`等,以及如何使用它们来构建更加标准化和语义化的页面结构。还会涉及到Web表单的新特性,比如表单验证、新的输入类型等。 5. 可访问性(Accessibility): Web可访问性越来越受到重视。本书可能会介绍如何通过HTML和CSS来提升网站的无障碍访问性,比如使用ARIA标签(Accessible Rich Internet Applications)来增强屏幕阅读器的使用体验。 6. 前端性能优化: 性能优化是任何Web项目成功的关键。本书可能会涵盖如何通过优化CSS和HTML来提升网站的加载速度和运行效率。内容可能包括代码压缩、合并、避免重绘和回流、使用Web字体的最佳实践等。 7. JavaScript与CSS/HTML的交互: 在现代Web开发中,JavaScript与CSS及HTML的交云并用是不可或缺的。书中可能会讲解如何通过JavaScript动态地修改样式、操作DOM元素以及使用事件监听和响应用户交互。 8. Web框架和预处理器: 这本书可能会提到流行的Web开发框架和预处理器,比如Bootstrap、Foundation、Sass和Less等,它们是如何简化和加速开发流程的。 9. 测试和维护: 书中也可能包含关于如何测试网页以及如何持续优化和维护CSS和HTML代码的章节。例如,使用断言测试、自动化测试、性能分析工具等。 最后,鉴于文件名称列表中的“压缩包子文件”的表述,这可能是对“压缩包”文件的一种误译或误用,此处“压缩包”应该指的是包含该书籍PDF文件的压缩文件格式,如ZIP或RAR。而“Pro CSS and HTML Design Patterns.pdf”指的就是该书籍的PDF格式电子版文件。 以上所述,构成了《Pro CSS and HTML Design Patterns》一书可能包含的核心知识点。通过学习这些内容,Web前端开发者可以掌握更为高效和优雅的设计模式,从而在日常工作中更高效地解决实际问题。
recommend-type

Zotero 7数据同步:Attanger插件安装&设置,打造文献管理利器

/i.s3.glbimg.com/v1/AUTH_08fbf48bc0524877943fe86e43087e7a/internal_photos/bs/2018/L/j/ipKA8TRPyt4ptaG1DGww/t-m-01.png) # 1. Zotero 7数据同步简介 在数字时代,管理研究数据变得日益重要,而Zot
recommend-type

卷积神经网络的基础理论200字

<think>我们正在回答用户关于卷积神经网络(CNN)基础理论的询问。根据提供的引用资料,我们可以概述CNN的基本结构和工作原理。引用[1]提到CNN是一种前馈神经网络,信息从输入单向流动到输出。引用[2]指出CNN在图像处理等领域应用广泛,通过层次结构和参数调整实现模式识别。引用[3]说明CNN包含卷积层,使用卷积核提取局部特征,减少参数量,提高效率。引用[4]则提到了训练过程,包括前向传播、误差计算和反向传播(梯度下降)。因此,我们将从以下几个方面概述CNN:1.CNN的基本结构(卷积层、池化层、全连接层)2.卷积操作的工作原理(局部感受野、权重共享)3.训练过程(前向传播、损失函数、反
recommend-type

轻便实用的Java库类查询工具介绍

标题 "java2库类查询" 和描述表明,所提及的工具是一个专门用于查询Java库类的应用程序。此软件旨在帮助开发者快速地查找和引用Java的标准开发工具包(SDK)中包含的所有应用程序编程接口(API)类。通过这样的工具,开发者可以节省大量在官方文档或搜索引擎上寻找类定义和使用方法的时间。它被描述为轻巧且方便,这表明其占用的系统资源相对较少,同时提供直观的用户界面,使得查询过程简洁高效。 从描述中可以得出几个关键知识点: 1. Java SDK:Java的软件开发工具包(SDK)是Java平台的一部分,提供了一套用于开发Java应用软件的软件包和库。这些软件包通常被称为API,为开发者提供了编程界面,使他们能够使用Java语言编写各种类型的应用程序。 2. 库类查询:这个功能对于开发者来说非常关键,因为它提供了一个快速查找特定库类及其相关方法、属性和使用示例的途径。良好的库类查询工具可以帮助开发者提高工作效率,减少因查找文档而中断编程思路的时间。 3. 轻巧性:软件的轻巧性通常意味着它对计算机资源的要求较低。这样的特性对于资源受限的系统尤为重要,比如老旧的计算机、嵌入式设备或是当开发者希望最小化其开发环境占用空间时。 4. 方便性:软件的方便性通常关联于其用户界面设计,一个直观、易用的界面可以让用户快速上手,并减少在使用过程中遇到的障碍。 5. 包含所有API:一个优秀的Java库类查询软件应当能够覆盖Java所有标准API,这包括Java.lang、Java.util、Java.io等核心包,以及Java SE平台的所有其他标准扩展包。 从标签 "java 库 查询 类" 可知,这个软件紧密关联于Java编程语言的核心功能——库类的管理和查询。这些标签可以关联到以下知识点: - Java:一种广泛用于企业级应用、移动应用(如Android应用)、网站后端、大型系统和许多其他平台的编程语言。 - 库:在Java中,库是一组预打包的类和接口,它们可以被应用程序重复使用。Java提供了庞大的标准库,以支持各种常见的任务和功能。 - 查询:查询指的是利用软件工具搜索、定位和检索信息的过程。对于Java库类查询工具来说,这意味着可以通过类名、方法签名或其他标识符来查找特定的API条目。 最后,压缩包文件列表包含了两个文件:“java.dit”和“Java.exe”。其中“Java.exe”很可能是程序的可执行文件,而“java.dit”可能是一个数据文件,用于存储Java类的索引或数据。由于文件名后缀通常与文件类型相关联,但“dit”并不是一个常见的文件扩展名。这可能是一个特定于软件的自定义格式,或是一个打字错误。 总结来说,"java2库类查询" 是一个针对Java开发者的实用工具,它提供了一个轻量级、易用的平台来查询和定位Java标准库中的所有类和API。此工具对优化开发流程,减少查找Java类文档的时间大有裨益,尤其适合需要频繁查阅Java API的开发者使用。
recommend-type

【Zotero 7终极指南】:新手必备!Attanger插件全攻略与数据同步神技

# 1. Zotero 7与Attanger插件的介绍 在当今的学术研究和知识管理领域,高效的文献管理工具至关重要。Zotero 7作为一个流行的参考文献管理软件,因其强大的功能和用户友好的界面而受到专业人士的青睐。而Attanger插件则为Zotero 7带来了更多定制化和高级功能,极大地增强
recommend-type

MATLAB整段注释快捷键

<think>首先,用户的问题是:“MATLAB整段注释快捷键”,意思是“MATLAB整段注释快捷键”。我需要用中文回答。 根据规则: - 回答必须用中文。 - 回答完问题后,必须在末尾输出“§§相关问题§§”,然后提出3-5个相关问题。 - “§§相关问题§§”必须完整输出在第一行,禁止换行分散。 - 相关问题必须基于用户的问题和我的回答。 现在,回忆MATLAB的快捷键:在MATLAB中,整段注释通常使用快捷键Ctrl + R来注释选中的代码行,使用Ctrl + T来取消注释。用户问的是“整段注释”,所以我应该确认快捷键。 在MATLAB中: - 注释选中的行:Ctrl + R -
recommend-type

Eclipse Jad反编译插件:提升.class文件查看便捷性

反编译插件for Eclipse是一个专门设计用于在Eclipse集成开发环境中进行Java反编译的工具。通过此类插件,开发者可以在不直接访问源代码的情况下查看Java编译后的.class文件的源代码,这在开发、维护和学习使用Java技术的过程中具有重要的作用。 首先,我们需要了解Eclipse是一个跨平台的开源集成开发环境,主要用来开发Java应用程序,但也支持其他诸如C、C++、PHP等多种语言的开发。Eclipse通过安装不同的插件来扩展其功能。这些插件可以由社区开发或者官方提供,而jadclipse就是这样一个社区开发的插件,它利用jad.exe这个第三方命令行工具来实现反编译功能。 jad.exe是一个反编译Java字节码的命令行工具,它可以将Java编译后的.class文件还原成一个接近原始Java源代码的格式。这个工具非常受欢迎,原因在于其反编译速度快,并且能够生成相对清晰的Java代码。由于它是一个独立的命令行工具,直接使用命令行可以提供较强的灵活性,但是对于一些不熟悉命令行操作的用户来说,集成到Eclipse开发环境中将会极大提高开发效率。 使用jadclipse插件可以很方便地在Eclipse中打开任何.class文件,并且将反编译的结果显示在编辑器中。用户可以在查看反编译的源代码的同时,进行阅读、调试和学习。这样不仅可以帮助开发者快速理解第三方库的工作机制,还能在遇到.class文件丢失源代码时进行紧急修复工作。 对于Eclipse用户来说,安装jadclipse插件相当简单。一般步骤包括: 1. 下载并解压jadclipse插件的压缩包。 2. 在Eclipse中打开“Help”菜单,选择“Install New Software”。 3. 点击“Add”按钮,输入插件更新地址(通常是jadclipse的更新站点URL)。 4. 选择相应的插件(通常名为“JadClipse”),然后进行安装。 5. 安装完成后重启Eclipse,插件开始工作。 一旦插件安装好之后,用户只需在Eclipse中双击.class文件,或者右键点击文件并选择“Open With Jadclipse”,就能看到对应的Java源代码。如果出现反编译不准确或失败的情况,用户还可以直接在Eclipse中配置jad.exe的路径,或者调整jadclipse的高级设置来优化反编译效果。 需要指出的是,使用反编译工具虽然方便,但要注意反编译行为可能涉及到版权问题。在大多数国家和地区,反编译软件代码属于合法行为,但仅限于学习、研究、安全测试或兼容性开发等目的。如果用户意图通过反编译获取商业机密或进行非法复制,则可能违反相关法律法规。 总的来说,反编译插件for Eclipse是一个强大的工具,它极大地简化了Java反编译流程,提高了开发效率,使得开发者在没有源代码的情况下也能有效地维护和学习Java程序。但开发者在使用此类工具时应遵守法律与道德规范,避免不当使用。
recommend-type

【进阶Python绘图】:掌握matplotlib坐标轴刻度间隔的高级技巧,让你的图表脱颖而出

# 摘要 本文系统地探讨了matplotlib库中坐标轴刻度间隔的定制与优化技术。首先概述了matplotlib坐标轴刻度间隔的基本概念及其在图表中的重要性,接