| 1 | #include <mem/alloc.h> |
| 2 | #include <string.h> |
| 3 | #include <structures/locked_list.h> |
| 4 | #include <time/clock.h> |
| 5 | #include <time/names.h> |
| 6 | |
| 7 | #include "internal.h" |
| 8 | |
| 9 | struct clock_globals clock_global = {0}; |
| 10 | |
| 11 | void clocks_init(void) { |
| 12 | locked_list_init(ll: &clock_global.clock_evdevs, LOCKED_LIST_INIT_NORMAL); |
| 13 | locked_list_init(ll: &clock_global.clock_evdev_groups, LOCKED_LIST_INIT_NORMAL); |
| 14 | locked_list_init(ll: &clock_global.clocks, LOCKED_LIST_INIT_NORMAL); |
| 15 | } |
| 16 | |
| 17 | struct clock *clock_create(const char *fmt, ...) { |
| 18 | struct clock *clock = kmalloc(sizeof(struct clock), ALLOC_FLAGS_ZERO); |
| 19 | if (!clock) |
| 20 | return NULL; |
| 21 | |
| 22 | va_list args; |
| 23 | va_start(args, fmt); |
| 24 | int ret = ERR_GUARD(vasprintf(&clock->name, fmt, args), ERR_NO_MEM); |
| 25 | va_end(args); |
| 26 | |
| 27 | if (ret == ERR_NO_MEM) { |
| 28 | kfree(clock); |
| 29 | return NULL; |
| 30 | } |
| 31 | |
| 32 | return clock; |
| 33 | } |
| 34 | |
| 35 | void clock_register(struct clock *c) { |
| 36 | locked_list_add(ll: &clock_global.clocks, lh: &c->list_internal); |
| 37 | } |
| 38 | |
| 39 | void clock_unregister(struct clock *c) { |
| 40 | locked_list_del(ll: &clock_global.clocks, lh: &c->list_internal); |
| 41 | } |
| 42 | |
| 43 | /* TODO: If/When we start we start getting actual callers that use dynamic |
| 44 | * lock registration, we'll need to refcount the clocks */ |
| 45 | struct clock *clock_get_best(void) { |
| 46 | struct clock *best = NULL; |
| 47 | enum clock_rating best_rating = CLOCK_RATING_UNSUITABLE; |
| 48 | |
| 49 | struct list_head *pos; |
| 50 | enum irql irql = spin_lock(&clock_global.clocks.lock); |
| 51 | list_for_each(pos, &clock_global.clocks.list) { |
| 52 | struct clock *c = container_of(pos, struct clock, list_internal); |
| 53 | if (c->state == CLOCK_STATE_ON && !(c->flags & CLOCK_FLAG_UNSTABLE)) { |
| 54 | if (c->rating > best_rating) { |
| 55 | best_rating = c->rating; |
| 56 | best = c; |
| 57 | } |
| 58 | } |
| 59 | } |
| 60 | spin_unlock(&clock_global.clocks.lock, irql); |
| 61 | |
| 62 | return best; |
| 63 | } |
| 64 | |
| 65 | struct clock *clock_get_by_name(const char *name) { |
| 66 | struct clock *found = NULL; |
| 67 | struct list_head *pos; |
| 68 | enum irql irql = spin_lock(&clock_global.clocks.lock); |
| 69 | list_for_each(pos, &clock_global.clocks.list) { |
| 70 | struct clock *c = container_of(pos, struct clock, list_internal); |
| 71 | if (strcmp(str1: c->name, str2: name) == 0) { |
| 72 | found = c; |
| 73 | break; |
| 74 | } |
| 75 | } |
| 76 | spin_unlock(&clock_global.clocks.lock, irql); |
| 77 | return found; |
| 78 | } |
| 79 | |