| /** |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| #define _GNU_SOURCE |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <pthread.h> |
| #include <sched.h> |
| #include <signal.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/ioctl.h> |
| #include <sys/stat.h> |
| #include <sys/types.h> |
| #include <unistd.h> |
| |
| #define THREAD_NUM 300 |
| #define DEV "/dev/usf1" |
| |
| /* min, max array dimension */ |
| #define MIN_MAX_DIM 2 |
| |
| #define USF_MAX_PORT_NUM 8 |
| |
| static const unsigned short PortSamplesDataSize = 768; |
| |
| /* Encoder (TX), decoder (RX) supported US data formats */ |
| #define USF_POINT_EPOS_FORMAT 0 |
| #define USF_RAW_FORMAT 1 |
| |
| /* Indexes of event types, produced by the calculators */ |
| #define USF_TSC_EVENT_IND 0 |
| #define USF_TSC_PTR_EVENT_IND 1 |
| #define USF_MOUSE_EVENT_IND 2 |
| #define USF_KEYBOARD_EVENT_IND 3 |
| #define USF_TSC_EXT_EVENT_IND 4 |
| #define USF_MAX_EVENT_IND 5 |
| |
| /* Types of events, produced by the calculators */ |
| #define USF_NO_EVENT 0 |
| #define USF_TSC_EVENT (1 << USF_TSC_EVENT_IND) |
| #define USF_TSC_PTR_EVENT (1 << USF_TSC_PTR_EVENT_IND) |
| #define USF_MOUSE_EVENT (1 << USF_MOUSE_EVENT_IND) |
| #define USF_KEYBOARD_EVENT (1 << USF_KEYBOARD_EVENT_IND) |
| #define USF_TSC_EXT_EVENT (1 << USF_TSC_EXT_EVENT_IND) |
| #define USF_ALL_EVENTS \ |
| (USF_TSC_EVENT | USF_TSC_PTR_EVENT | USF_MOUSE_EVENT | USF_KEYBOARD_EVENT | \ |
| USF_TSC_EXT_EVENT) |
| void *child_ioctl_0(void *no_use); |
| void *child_ioctl_1(void *no_use); |
| |
| /* Info structure common for TX and RX */ |
| struct us_xx_info_type { |
| /* Input: general info */ |
| /* Name of the client - event calculator */ |
| const char __user *client_name; |
| /* Selected device identification, accepted in the kernel's CAD */ |
| uint32_t dev_id; |
| /* 0 - point_epos type; (e.g. 1 - gr_mmrd) */ |
| uint32_t stream_format; |
| /* Required sample rate in Hz */ |
| uint32_t sample_rate; |
| /* Size of a buffer (bytes) for US data transfer between the module and USF */ |
| uint32_t buf_size; |
| /* Number of the buffers for the US data transfer */ |
| uint16_t buf_num; |
| /* Number of the microphones (TX) or speakers(RX) */ |
| uint16_t port_cnt; |
| /* Microphones(TX) or speakers(RX) indexes in their enumeration */ |
| uint8_t port_id[USF_MAX_PORT_NUM]; |
| /* Bits per sample 16 or 32 */ |
| uint16_t bits_per_sample; |
| /* Input: Transparent info for encoder in the LPASS */ |
| /* Parameters data size in bytes */ |
| uint16_t params_data_size; |
| /* Pointer to the parameters */ |
| uint8_t __user *params_data; |
| /* Max size of buffer for get and set parameter */ |
| uint32_t max_get_set_param_buf_size; |
| }; |
| |
| struct us_input_info_type { |
| /* Touch screen dimensions: min & max;for input module */ |
| int tsc_x_dim[MIN_MAX_DIM]; |
| int tsc_y_dim[MIN_MAX_DIM]; |
| int tsc_z_dim[MIN_MAX_DIM]; |
| /* Touch screen tilt dimensions: min & max;for input module */ |
| int tsc_x_tilt[MIN_MAX_DIM]; |
| int tsc_y_tilt[MIN_MAX_DIM]; |
| /* Touch screen pressure limits: min & max; for input module */ |
| int tsc_pressure[MIN_MAX_DIM]; |
| /* The requested buttons bitmap */ |
| uint16_t req_buttons_bitmap; |
| /* Bitmap of types of events (USF_X_EVENT), produced by calculator */ |
| uint16_t event_types; |
| /* Bitmap of types of events from devs, conflicting with USF */ |
| uint16_t conflicting_event_types; |
| }; |
| |
| struct us_tx_info_type { |
| /* Common info */ |
| struct us_xx_info_type us_xx_info; |
| /* Info specific for TX*/ |
| struct us_input_info_type input_info; |
| }; |
| |
| struct us_rx_info_type { |
| /* Common info */ |
| struct us_xx_info_type us_xx_info; |
| /* Info specific for RX*/ |
| }; |
| |
| struct us_stream_param_type { |
| /* Id of module */ |
| uint32_t module_id; |
| /* Id of parameter */ |
| uint32_t param_id; |
| /* Size of memory of the parameter buffer */ |
| uint32_t buf_size; |
| /* Pointer to the memory of the parameter buffer */ |
| uint8_t __user *pbuf; |
| }; |
| |
| #define USF_IOCTL_MAGIC 'U' |
| |
| #define US_SET_TX_INFO _IOW(USF_IOCTL_MAGIC, 0, struct us_tx_info_type) |
| #define US_START_TX _IO(USF_IOCTL_MAGIC, 1) |
| #define US_GET_TX_UPDATE \ |
| _IOWR(USF_IOCTL_MAGIC, 2, struct us_tx_update_info_type) |
| #define US_SET_RX_INFO _IOW(USF_IOCTL_MAGIC, 3, struct us_rx_info_type) |
| #define US_SET_RX_UPDATE \ |
| _IOWR(USF_IOCTL_MAGIC, 4, struct us_rx_update_info_type) |
| #define US_START_RX _IO(USF_IOCTL_MAGIC, 5) |
| |
| #define US_STOP_TX _IO(USF_IOCTL_MAGIC, 6) |
| #define US_STOP_RX _IO(USF_IOCTL_MAGIC, 7) |
| |
| #define US_SET_TX_STREAM_PARAM \ |
| _IOW(USF_IOCTL_MAGIC, 10, struct us_stream_param_type) |
| #define US_GET_TX_STREAM_PARAM \ |
| _IOWR(USF_IOCTL_MAGIC, 11, struct us_stream_param_type) |
| #define US_SET_RX_STREAM_PARAM \ |
| _IOW(USF_IOCTL_MAGIC, 12, struct us_stream_param_type) |
| #define US_GET_RX_STREAM_PARAM \ |
| _IOWR(USF_IOCTL_MAGIC, 13, struct us_stream_param_type) |
| |
| int fd; |
| pthread_t thread_id[THREAD_NUM + 1] = {0}; |
| int thread_ret[THREAD_NUM] = {0}; |
| |
| // RX configuration |
| static struct us_rx_info_type s_rx_info; |
| static struct us_rx_info_type s_rx_info1; |
| |
| static void set_valid_rx_configuration(void); |
| static void set_valid_rx_configuration_for_fail(void); |
| |
| static void set_valid_rx_configuration() { |
| typedef struct { |
| unsigned short frameSize; |
| unsigned short groupFactor; |
| } TransparentDataRxType; |
| static TransparentDataRxType transparentRxData; |
| unsigned short frame_size = 0; |
| |
| transparentRxData.frameSize = PortSamplesDataSize; |
| transparentRxData.groupFactor = 1; |
| |
| s_rx_info.us_xx_info.client_name = "tester"; |
| s_rx_info.us_xx_info.dev_id = 0; |
| s_rx_info.us_xx_info.stream_format = USF_RAW_FORMAT; |
| s_rx_info.us_xx_info.sample_rate = 96000; |
| s_rx_info.us_xx_info.buf_num = 3; |
| s_rx_info.us_xx_info.port_cnt = 1; |
| s_rx_info.us_xx_info.port_id[0] = 1; |
| s_rx_info.us_xx_info.bits_per_sample = 16; |
| s_rx_info.us_xx_info.params_data_size = sizeof(TransparentDataRxType); |
| s_rx_info.us_xx_info.params_data = (unsigned char*)&transparentRxData; |
| |
| frame_size = PortSamplesDataSize * |
| (s_rx_info.us_xx_info.bits_per_sample / 8) * |
| s_rx_info.us_xx_info.port_cnt; |
| // group size |
| s_rx_info.us_xx_info.buf_size = frame_size * transparentRxData.groupFactor; |
| } // set_valid_rx_configuration |
| |
| static void set_valid_rx_configuration_for_fail() { |
| typedef struct { |
| unsigned short frameSize; |
| unsigned short groupFactor; |
| } TransparentDataRxType; |
| static TransparentDataRxType transparentRxData; |
| unsigned short frame_size = 0; |
| |
| transparentRxData.frameSize = PortSamplesDataSize; |
| transparentRxData.groupFactor = 1; |
| |
| s_rx_info1.us_xx_info.client_name = "tester"; |
| s_rx_info1.us_xx_info.dev_id = 0; |
| s_rx_info1.us_xx_info.stream_format = USF_RAW_FORMAT; |
| s_rx_info1.us_xx_info.sample_rate = 96000; |
| s_rx_info1.us_xx_info.buf_num = 3; |
| s_rx_info1.us_xx_info.port_cnt = 1; |
| s_rx_info1.us_xx_info.port_id[0] = 1; |
| s_rx_info1.us_xx_info.bits_per_sample = 16; |
| s_rx_info1.us_xx_info.params_data_size = sizeof(TransparentDataRxType); |
| |
| frame_size = PortSamplesDataSize * |
| (s_rx_info1.us_xx_info.bits_per_sample / 8) * |
| s_rx_info1.us_xx_info.port_cnt; |
| // group size |
| s_rx_info1.us_xx_info.buf_size = frame_size * transparentRxData.groupFactor; |
| // for fail |
| s_rx_info1.us_xx_info.max_get_set_param_buf_size = (uint32_t) 100000000000000; |
| } // set_valid_rx_configuration |
| |
| |
| static int set_affinity(int num) { |
| int ret = 0; |
| cpu_set_t mask; |
| CPU_ZERO(&mask); |
| CPU_SET(num, &mask); |
| ret = sched_setaffinity(0, sizeof(cpu_set_t), &mask); |
| if (ret == -1) { |
| printf("[-] set affinity failed: [%d]-%s\n", errno, strerror(errno)); |
| } |
| return ret; |
| } |
| |
| void *child_ioctl_0(void *no_use) { |
| int ret = 1; |
| set_affinity(1); |
| |
| while (1) { |
| ret = ioctl(fd, US_SET_RX_INFO, &s_rx_info1); |
| } |
| } |
| |
| void* child_ioctl_1(void* no_use) { |
| int ret = 1; |
| set_affinity(2); |
| |
| while (1) { |
| ret = ioctl(fd, US_SET_RX_INFO, &s_rx_info1); |
| } |
| } |
| |
| int main() { |
| int i, ret; |
| |
| /* bind_cpu */ |
| set_affinity(0); |
| |
| set_valid_rx_configuration(); |
| set_valid_rx_configuration_for_fail(); |
| |
| /* open dev */ |
| fd = open(DEV, O_RDONLY); |
| if (fd == -1) { |
| return 0; |
| } |
| |
| /* create thread */ |
| for (i = 0; i < THREAD_NUM; i = i + 2) { |
| thread_ret[i] = pthread_create(thread_id + i, NULL, child_ioctl_0, NULL); |
| thread_ret[i + 1] = |
| pthread_create(thread_id + i + 1, NULL, child_ioctl_1, NULL); |
| } |
| } |