| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * This test covers the functionality of userspace-driven ALSA timers. Such timers
- * are purely virtual (so they don't directly depend on the hardware), and they could be
- * created and triggered by userspace applications.
- *
- * Author: Ivan Orlov <ivan.orlov0322@gmail.com>
- */
- #include "kselftest_harness.h"
- #include <sound/asound.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <limits.h>
- #include <sys/ioctl.h>
- #include <stdlib.h>
- #include <pthread.h>
- #include <string.h>
- #define FRAME_RATE 8000
- #define PERIOD_SIZE 4410
- #define UTIMER_DEFAULT_ID -1
- #define UTIMER_DEFAULT_FD -1
- #define NANO 1000000000ULL
- #define TICKS_COUNT 10
- #define TICKS_RECORDING_DELTA 5
- #define TIMER_OUTPUT_BUF_LEN 1024
- #define TIMER_FREQ_SEC 1
- #define RESULT_PREFIX_LEN strlen("Total ticks count: ")
- enum timer_app_event {
- TIMER_APP_STARTED,
- TIMER_APP_RESULT,
- TIMER_NO_EVENT,
- };
- FIXTURE(timer_f) {
- struct snd_timer_uinfo *utimer_info;
- };
- FIXTURE_SETUP(timer_f) {
- int timer_dev_fd;
- if (geteuid())
- SKIP(return, "This test needs root to run!");
- self->utimer_info = calloc(1, sizeof(*self->utimer_info));
- ASSERT_NE(NULL, self->utimer_info);
- /* Resolution is the time the period of frames takes in nanoseconds */
- self->utimer_info->resolution = (NANO / FRAME_RATE * PERIOD_SIZE);
- timer_dev_fd = open("/dev/snd/timer", O_RDONLY);
- ASSERT_GE(timer_dev_fd, 0);
- ASSERT_EQ(ioctl(timer_dev_fd, SNDRV_TIMER_IOCTL_CREATE, self->utimer_info), 0);
- ASSERT_GE(self->utimer_info->fd, 0);
- close(timer_dev_fd);
- }
- FIXTURE_TEARDOWN(timer_f) {
- close(self->utimer_info->fd);
- free(self->utimer_info);
- }
- static void *ticking_func(void *data)
- {
- int i;
- int *fd = (int *)data;
- for (i = 0; i < TICKS_COUNT; i++) {
- /* Well, trigger the timer! */
- ioctl(*fd, SNDRV_TIMER_IOCTL_TRIGGER, NULL);
- sleep(TIMER_FREQ_SEC);
- }
- return NULL;
- }
- static enum timer_app_event parse_timer_output(const char *s)
- {
- if (strstr(s, "Timer has started"))
- return TIMER_APP_STARTED;
- if (strstr(s, "Total ticks count"))
- return TIMER_APP_RESULT;
- return TIMER_NO_EVENT;
- }
- static int parse_timer_result(const char *s)
- {
- char *end;
- long d;
- d = strtol(s + RESULT_PREFIX_LEN, &end, 10);
- if (end == s + RESULT_PREFIX_LEN)
- return -1;
- return d;
- }
- /*
- * This test triggers the timer and counts ticks at the same time. The amount
- * of the timer trigger calls should be equal to the amount of ticks received.
- */
- TEST_F(timer_f, utimer) {
- char command[64];
- pthread_t ticking_thread;
- int total_ticks = 0;
- FILE *rfp;
- char *buf = malloc(TIMER_OUTPUT_BUF_LEN);
- ASSERT_NE(buf, NULL);
- /* The timeout should be the ticks interval * count of ticks + some delta */
- sprintf(command, "./global-timer %d %d %d", SNDRV_TIMER_GLOBAL_UDRIVEN,
- self->utimer_info->id, TICKS_COUNT * TIMER_FREQ_SEC + TICKS_RECORDING_DELTA);
- rfp = popen(command, "r");
- while (fgets(buf, TIMER_OUTPUT_BUF_LEN, rfp)) {
- buf[TIMER_OUTPUT_BUF_LEN - 1] = 0;
- switch (parse_timer_output(buf)) {
- case TIMER_APP_STARTED:
- /* global-timer waits for timer to trigger, so start the ticking thread */
- pthread_create(&ticking_thread, NULL, ticking_func,
- &self->utimer_info->fd);
- break;
- case TIMER_APP_RESULT:
- total_ticks = parse_timer_result(buf);
- break;
- case TIMER_NO_EVENT:
- break;
- }
- }
- pthread_join(ticking_thread, NULL);
- ASSERT_EQ(total_ticks, TICKS_COUNT);
- pclose(rfp);
- free(buf);
- }
- TEST(wrong_timers_test) {
- int timer_dev_fd;
- int utimer_fd;
- struct snd_timer_uinfo wrong_timer = {
- .resolution = 0,
- .id = UTIMER_DEFAULT_ID,
- .fd = UTIMER_DEFAULT_FD,
- };
- timer_dev_fd = open("/dev/snd/timer", O_RDONLY);
- ASSERT_GE(timer_dev_fd, 0);
- utimer_fd = ioctl(timer_dev_fd, SNDRV_TIMER_IOCTL_CREATE, &wrong_timer);
- ASSERT_LT(utimer_fd, 0);
- /* Check that id was not updated */
- ASSERT_EQ(wrong_timer.id, UTIMER_DEFAULT_ID);
- /* Test the NULL as an argument is processed correctly */
- ASSERT_LT(ioctl(timer_dev_fd, SNDRV_TIMER_IOCTL_CREATE, NULL), 0);
- close(timer_dev_fd);
- }
- TEST_HARNESS_MAIN
|