diff options
-rw-r--r-- | include/linux/posix-clock.h | 150 | ||||
-rw-r--r-- | include/linux/posix-timers.h | 6 | ||||
-rw-r--r-- | kernel/posix-timers.c | 4 | ||||
-rw-r--r-- | kernel/time/Makefile | 3 | ||||
-rw-r--r-- | kernel/time/posix-clock.c | 441 |
5 files changed, 601 insertions, 3 deletions
diff --git a/include/linux/posix-clock.h b/include/linux/posix-clock.h new file mode 100644 index 000000000000..369e19d3750b --- /dev/null +++ b/include/linux/posix-clock.h | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | * posix-clock.h - support for dynamic clock devices | ||
3 | * | ||
4 | * Copyright (C) 2010 OMICRON electronics GmbH | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | #ifndef _LINUX_POSIX_CLOCK_H_ | ||
21 | #define _LINUX_POSIX_CLOCK_H_ | ||
22 | |||
23 | #include <linux/cdev.h> | ||
24 | #include <linux/fs.h> | ||
25 | #include <linux/poll.h> | ||
26 | #include <linux/posix-timers.h> | ||
27 | |||
28 | struct posix_clock; | ||
29 | |||
30 | /** | ||
31 | * struct posix_clock_operations - functional interface to the clock | ||
32 | * | ||
33 | * Every posix clock is represented by a character device. Drivers may | ||
34 | * optionally offer extended capabilities by implementing the | ||
35 | * character device methods. The character device file operations are | ||
36 | * first handled by the clock device layer, then passed on to the | ||
37 | * driver by calling these functions. | ||
38 | * | ||
39 | * @owner: The clock driver should set to THIS_MODULE | ||
40 | * @clock_adjtime: Adjust the clock | ||
41 | * @clock_gettime: Read the current time | ||
42 | * @clock_getres: Get the clock resolution | ||
43 | * @clock_settime: Set the current time value | ||
44 | * @timer_create: Create a new timer | ||
45 | * @timer_delete: Remove a previously created timer | ||
46 | * @timer_gettime: Get remaining time and interval of a timer | ||
47 | * @timer_setttime: Set a timer's initial expiration and interval | ||
48 | * @fasync: Optional character device fasync method | ||
49 | * @mmap: Optional character device mmap method | ||
50 | * @open: Optional character device open method | ||
51 | * @release: Optional character device release method | ||
52 | * @ioctl: Optional character device ioctl method | ||
53 | * @read: Optional character device read method | ||
54 | * @poll: Optional character device poll method | ||
55 | */ | ||
56 | struct posix_clock_operations { | ||
57 | struct module *owner; | ||
58 | |||
59 | int (*clock_adjtime)(struct posix_clock *pc, struct timex *tx); | ||
60 | |||
61 | int (*clock_gettime)(struct posix_clock *pc, struct timespec *ts); | ||
62 | |||
63 | int (*clock_getres) (struct posix_clock *pc, struct timespec *ts); | ||
64 | |||
65 | int (*clock_settime)(struct posix_clock *pc, | ||
66 | const struct timespec *ts); | ||
67 | |||
68 | int (*timer_create) (struct posix_clock *pc, struct k_itimer *kit); | ||
69 | |||
70 | int (*timer_delete) (struct posix_clock *pc, struct k_itimer *kit); | ||
71 | |||
72 | void (*timer_gettime)(struct posix_clock *pc, | ||
73 | struct k_itimer *kit, struct itimerspec *tsp); | ||
74 | |||
75 | int (*timer_settime)(struct posix_clock *pc, | ||
76 | struct k_itimer *kit, int flags, | ||
77 | struct itimerspec *tsp, struct itimerspec *old); | ||
78 | /* | ||
79 | * Optional character device methods: | ||
80 | */ | ||
81 | int (*fasync) (struct posix_clock *pc, | ||
82 | int fd, struct file *file, int on); | ||
83 | |||
84 | long (*ioctl) (struct posix_clock *pc, | ||
85 | unsigned int cmd, unsigned long arg); | ||
86 | |||
87 | int (*mmap) (struct posix_clock *pc, | ||
88 | struct vm_area_struct *vma); | ||
89 | |||
90 | int (*open) (struct posix_clock *pc, fmode_t f_mode); | ||
91 | |||
92 | uint (*poll) (struct posix_clock *pc, | ||
93 | struct file *file, poll_table *wait); | ||
94 | |||
95 | int (*release) (struct posix_clock *pc); | ||
96 | |||
97 | ssize_t (*read) (struct posix_clock *pc, | ||
98 | uint flags, char __user *buf, size_t cnt); | ||
99 | }; | ||
100 | |||
101 | /** | ||
102 | * struct posix_clock - represents a dynamic posix clock | ||
103 | * | ||
104 | * @ops: Functional interface to the clock | ||
105 | * @cdev: Character device instance for this clock | ||
106 | * @kref: Reference count. | ||
107 | * @mutex: Protects the 'zombie' field from concurrent access. | ||
108 | * @zombie: If 'zombie' is true, then the hardware has disappeared. | ||
109 | * @release: A function to free the structure when the reference count reaches | ||
110 | * zero. May be NULL if structure is statically allocated. | ||
111 | * | ||
112 | * Drivers should embed their struct posix_clock within a private | ||
113 | * structure, obtaining a reference to it during callbacks using | ||
114 | * container_of(). | ||
115 | */ | ||
116 | struct posix_clock { | ||
117 | struct posix_clock_operations ops; | ||
118 | struct cdev cdev; | ||
119 | struct kref kref; | ||
120 | struct mutex mutex; | ||
121 | bool zombie; | ||
122 | void (*release)(struct posix_clock *clk); | ||
123 | }; | ||
124 | |||
125 | /** | ||
126 | * posix_clock_register() - register a new clock | ||
127 | * @clk: Pointer to the clock. Caller must provide 'ops' and 'release' | ||
128 | * @devid: Allocated device id | ||
129 | * | ||
130 | * A clock driver calls this function to register itself with the | ||
131 | * clock device subsystem. If 'clk' points to dynamically allocated | ||
132 | * memory, then the caller must provide a 'release' function to free | ||
133 | * that memory. | ||
134 | * | ||
135 | * Returns zero on success, non-zero otherwise. | ||
136 | */ | ||
137 | int posix_clock_register(struct posix_clock *clk, dev_t devid); | ||
138 | |||
139 | /** | ||
140 | * posix_clock_unregister() - unregister a clock | ||
141 | * @clk: Clock instance previously registered via posix_clock_register() | ||
142 | * | ||
143 | * A clock driver calls this function to remove itself from the clock | ||
144 | * device subsystem. The posix_clock itself will remain (in an | ||
145 | * inactive state) until its reference count drops to zero, at which | ||
146 | * point it will be deallocated with its 'release' method. | ||
147 | */ | ||
148 | void posix_clock_unregister(struct posix_clock *clk); | ||
149 | |||
150 | #endif | ||
diff --git a/include/linux/posix-timers.h b/include/linux/posix-timers.h index 9d6ffe2c92e5..d51243ae0726 100644 --- a/include/linux/posix-timers.h +++ b/include/linux/posix-timers.h | |||
@@ -32,7 +32,7 @@ struct cpu_timer_list { | |||
32 | #define CPUCLOCK_PID(clock) ((pid_t) ~((clock) >> 3)) | 32 | #define CPUCLOCK_PID(clock) ((pid_t) ~((clock) >> 3)) |
33 | #define CPUCLOCK_PERTHREAD(clock) \ | 33 | #define CPUCLOCK_PERTHREAD(clock) \ |
34 | (((clock) & (clockid_t) CPUCLOCK_PERTHREAD_MASK) != 0) | 34 | (((clock) & (clockid_t) CPUCLOCK_PERTHREAD_MASK) != 0) |
35 | #define CPUCLOCK_PID_MASK 7 | 35 | |
36 | #define CPUCLOCK_PERTHREAD_MASK 4 | 36 | #define CPUCLOCK_PERTHREAD_MASK 4 |
37 | #define CPUCLOCK_WHICH(clock) ((clock) & (clockid_t) CPUCLOCK_CLOCK_MASK) | 37 | #define CPUCLOCK_WHICH(clock) ((clock) & (clockid_t) CPUCLOCK_CLOCK_MASK) |
38 | #define CPUCLOCK_CLOCK_MASK 3 | 38 | #define CPUCLOCK_CLOCK_MASK 3 |
@@ -48,6 +48,9 @@ struct cpu_timer_list { | |||
48 | #define MAKE_THREAD_CPUCLOCK(tid, clock) \ | 48 | #define MAKE_THREAD_CPUCLOCK(tid, clock) \ |
49 | MAKE_PROCESS_CPUCLOCK((tid), (clock) | CPUCLOCK_PERTHREAD_MASK) | 49 | MAKE_PROCESS_CPUCLOCK((tid), (clock) | CPUCLOCK_PERTHREAD_MASK) |
50 | 50 | ||
51 | #define FD_TO_CLOCKID(fd) ((~(clockid_t) (fd) << 3) | CLOCKFD) | ||
52 | #define CLOCKID_TO_FD(clk) ((unsigned int) ~((clk) >> 3)) | ||
53 | |||
51 | /* POSIX.1b interval timer structure. */ | 54 | /* POSIX.1b interval timer structure. */ |
52 | struct k_itimer { | 55 | struct k_itimer { |
53 | struct list_head list; /* free/ allocate list */ | 56 | struct list_head list; /* free/ allocate list */ |
@@ -100,6 +103,7 @@ struct k_clock { | |||
100 | }; | 103 | }; |
101 | 104 | ||
102 | extern struct k_clock clock_posix_cpu; | 105 | extern struct k_clock clock_posix_cpu; |
106 | extern struct k_clock clock_posix_dynamic; | ||
103 | 107 | ||
104 | void posix_timers_register_clock(const clockid_t clock_id, struct k_clock *new_clock); | 108 | void posix_timers_register_clock(const clockid_t clock_id, struct k_clock *new_clock); |
105 | 109 | ||
diff --git a/kernel/posix-timers.c b/kernel/posix-timers.c index af936fd37140..44fcff131b38 100644 --- a/kernel/posix-timers.c +++ b/kernel/posix-timers.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include <linux/init.h> | 41 | #include <linux/init.h> |
42 | #include <linux/compiler.h> | 42 | #include <linux/compiler.h> |
43 | #include <linux/idr.h> | 43 | #include <linux/idr.h> |
44 | #include <linux/posix-clock.h> | ||
44 | #include <linux/posix-timers.h> | 45 | #include <linux/posix-timers.h> |
45 | #include <linux/syscalls.h> | 46 | #include <linux/syscalls.h> |
46 | #include <linux/wait.h> | 47 | #include <linux/wait.h> |
@@ -489,7 +490,8 @@ static void release_posix_timer(struct k_itimer *tmr, int it_id_set) | |||
489 | static struct k_clock *clockid_to_kclock(const clockid_t id) | 490 | static struct k_clock *clockid_to_kclock(const clockid_t id) |
490 | { | 491 | { |
491 | if (id < 0) | 492 | if (id < 0) |
492 | return (id & CLOCKFD_MASK) == CLOCKFD ? NULL : &clock_posix_cpu; | 493 | return (id & CLOCKFD_MASK) == CLOCKFD ? |
494 | &clock_posix_dynamic : &clock_posix_cpu; | ||
493 | 495 | ||
494 | if (id >= MAX_CLOCKS || !posix_clocks[id].clock_getres) | 496 | if (id >= MAX_CLOCKS || !posix_clocks[id].clock_getres) |
495 | return NULL; | 497 | return NULL; |
diff --git a/kernel/time/Makefile b/kernel/time/Makefile index ee266620b06c..b0425991e9ac 100644 --- a/kernel/time/Makefile +++ b/kernel/time/Makefile | |||
@@ -1,4 +1,5 @@ | |||
1 | obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o timecompare.o timeconv.o | 1 | obj-y += timekeeping.o ntp.o clocksource.o jiffies.o timer_list.o timecompare.o |
2 | obj-y += timeconv.o posix-clock.o | ||
2 | 3 | ||
3 | obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD) += clockevents.o | 4 | obj-$(CONFIG_GENERIC_CLOCKEVENTS_BUILD) += clockevents.o |
4 | obj-$(CONFIG_GENERIC_CLOCKEVENTS) += tick-common.o | 5 | obj-$(CONFIG_GENERIC_CLOCKEVENTS) += tick-common.o |
diff --git a/kernel/time/posix-clock.c b/kernel/time/posix-clock.c new file mode 100644 index 000000000000..04498cbf6002 --- /dev/null +++ b/kernel/time/posix-clock.c | |||
@@ -0,0 +1,441 @@ | |||
1 | /* | ||
2 | * posix-clock.c - support for dynamic clock devices | ||
3 | * | ||
4 | * Copyright (C) 2010 OMICRON electronics GmbH | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This program is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
19 | */ | ||
20 | #include <linux/device.h> | ||
21 | #include <linux/file.h> | ||
22 | #include <linux/mutex.h> | ||
23 | #include <linux/posix-clock.h> | ||
24 | #include <linux/slab.h> | ||
25 | #include <linux/syscalls.h> | ||
26 | #include <linux/uaccess.h> | ||
27 | |||
28 | static void delete_clock(struct kref *kref); | ||
29 | |||
30 | /* | ||
31 | * Returns NULL if the posix_clock instance attached to 'fp' is old and stale. | ||
32 | */ | ||
33 | static struct posix_clock *get_posix_clock(struct file *fp) | ||
34 | { | ||
35 | struct posix_clock *clk = fp->private_data; | ||
36 | |||
37 | mutex_lock(&clk->mutex); | ||
38 | |||
39 | if (!clk->zombie) | ||
40 | return clk; | ||
41 | |||
42 | mutex_unlock(&clk->mutex); | ||
43 | |||
44 | return NULL; | ||
45 | } | ||
46 | |||
47 | static void put_posix_clock(struct posix_clock *clk) | ||
48 | { | ||
49 | mutex_unlock(&clk->mutex); | ||
50 | } | ||
51 | |||
52 | static ssize_t posix_clock_read(struct file *fp, char __user *buf, | ||
53 | size_t count, loff_t *ppos) | ||
54 | { | ||
55 | struct posix_clock *clk = get_posix_clock(fp); | ||
56 | int err = -EINVAL; | ||
57 | |||
58 | if (!clk) | ||
59 | return -ENODEV; | ||
60 | |||
61 | if (clk->ops.read) | ||
62 | err = clk->ops.read(clk, fp->f_flags, buf, count); | ||
63 | |||
64 | put_posix_clock(clk); | ||
65 | |||
66 | return err; | ||
67 | } | ||
68 | |||
69 | static unsigned int posix_clock_poll(struct file *fp, poll_table *wait) | ||
70 | { | ||
71 | struct posix_clock *clk = get_posix_clock(fp); | ||
72 | int result = 0; | ||
73 | |||
74 | if (!clk) | ||
75 | return -ENODEV; | ||
76 | |||
77 | if (clk->ops.poll) | ||
78 | result = clk->ops.poll(clk, fp, wait); | ||
79 | |||
80 | put_posix_clock(clk); | ||
81 | |||
82 | return result; | ||
83 | } | ||
84 | |||
85 | static int posix_clock_fasync(int fd, struct file *fp, int on) | ||
86 | { | ||
87 | struct posix_clock *clk = get_posix_clock(fp); | ||
88 | int err = 0; | ||
89 | |||
90 | if (!clk) | ||
91 | return -ENODEV; | ||
92 | |||
93 | if (clk->ops.fasync) | ||
94 | err = clk->ops.fasync(clk, fd, fp, on); | ||
95 | |||
96 | put_posix_clock(clk); | ||
97 | |||
98 | return err; | ||
99 | } | ||
100 | |||
101 | static int posix_clock_mmap(struct file *fp, struct vm_area_struct *vma) | ||
102 | { | ||
103 | struct posix_clock *clk = get_posix_clock(fp); | ||
104 | int err = -ENODEV; | ||
105 | |||
106 | if (!clk) | ||
107 | return -ENODEV; | ||
108 | |||
109 | if (clk->ops.mmap) | ||
110 | err = clk->ops.mmap(clk, vma); | ||
111 | |||
112 | put_posix_clock(clk); | ||
113 | |||
114 | return err; | ||
115 | } | ||
116 | |||
117 | static long posix_clock_ioctl(struct file *fp, | ||
118 | unsigned int cmd, unsigned long arg) | ||
119 | { | ||
120 | struct posix_clock *clk = get_posix_clock(fp); | ||
121 | int err = -ENOTTY; | ||
122 | |||
123 | if (!clk) | ||
124 | return -ENODEV; | ||
125 | |||
126 | if (clk->ops.ioctl) | ||
127 | err = clk->ops.ioctl(clk, cmd, arg); | ||
128 | |||
129 | put_posix_clock(clk); | ||
130 | |||
131 | return err; | ||
132 | } | ||
133 | |||
134 | #ifdef CONFIG_COMPAT | ||
135 | static long posix_clock_compat_ioctl(struct file *fp, | ||
136 | unsigned int cmd, unsigned long arg) | ||
137 | { | ||
138 | struct posix_clock *clk = get_posix_clock(fp); | ||
139 | int err = -ENOTTY; | ||
140 | |||
141 | if (!clk) | ||
142 | return -ENODEV; | ||
143 | |||
144 | if (clk->ops.ioctl) | ||
145 | err = clk->ops.ioctl(clk, cmd, arg); | ||
146 | |||
147 | put_posix_clock(clk); | ||
148 | |||
149 | return err; | ||
150 | } | ||
151 | #endif | ||
152 | |||
153 | static int posix_clock_open(struct inode *inode, struct file *fp) | ||
154 | { | ||
155 | int err; | ||
156 | struct posix_clock *clk = | ||
157 | container_of(inode->i_cdev, struct posix_clock, cdev); | ||
158 | |||
159 | mutex_lock(&clk->mutex); | ||
160 | |||
161 | if (clk->zombie) { | ||
162 | err = -ENODEV; | ||
163 | goto out; | ||
164 | } | ||
165 | if (clk->ops.open) | ||
166 | err = clk->ops.open(clk, fp->f_mode); | ||
167 | else | ||
168 | err = 0; | ||
169 | |||
170 | if (!err) { | ||
171 | kref_get(&clk->kref); | ||
172 | fp->private_data = clk; | ||
173 | } | ||
174 | out: | ||
175 | mutex_unlock(&clk->mutex); | ||
176 | return err; | ||
177 | } | ||
178 | |||
179 | static int posix_clock_release(struct inode *inode, struct file *fp) | ||
180 | { | ||
181 | struct posix_clock *clk = fp->private_data; | ||
182 | int err = 0; | ||
183 | |||
184 | if (clk->ops.release) | ||
185 | err = clk->ops.release(clk); | ||
186 | |||
187 | kref_put(&clk->kref, delete_clock); | ||
188 | |||
189 | fp->private_data = NULL; | ||
190 | |||
191 | return err; | ||
192 | } | ||
193 | |||
194 | static const struct file_operations posix_clock_file_operations = { | ||
195 | .owner = THIS_MODULE, | ||
196 | .llseek = no_llseek, | ||
197 | .read = posix_clock_read, | ||
198 | .poll = posix_clock_poll, | ||
199 | .unlocked_ioctl = posix_clock_ioctl, | ||
200 | .open = posix_clock_open, | ||
201 | .release = posix_clock_release, | ||
202 | .fasync = posix_clock_fasync, | ||
203 | .mmap = posix_clock_mmap, | ||
204 | #ifdef CONFIG_COMPAT | ||
205 | .compat_ioctl = posix_clock_compat_ioctl, | ||
206 | #endif | ||
207 | }; | ||
208 | |||
209 | int posix_clock_register(struct posix_clock *clk, dev_t devid) | ||
210 | { | ||
211 | int err; | ||
212 | |||
213 | kref_init(&clk->kref); | ||
214 | mutex_init(&clk->mutex); | ||
215 | |||
216 | cdev_init(&clk->cdev, &posix_clock_file_operations); | ||
217 | clk->cdev.owner = clk->ops.owner; | ||
218 | err = cdev_add(&clk->cdev, devid, 1); | ||
219 | if (err) | ||
220 | goto no_cdev; | ||
221 | |||
222 | return err; | ||
223 | no_cdev: | ||
224 | mutex_destroy(&clk->mutex); | ||
225 | return err; | ||
226 | } | ||
227 | EXPORT_SYMBOL_GPL(posix_clock_register); | ||
228 | |||
229 | static void delete_clock(struct kref *kref) | ||
230 | { | ||
231 | struct posix_clock *clk = container_of(kref, struct posix_clock, kref); | ||
232 | mutex_destroy(&clk->mutex); | ||
233 | if (clk->release) | ||
234 | clk->release(clk); | ||
235 | } | ||
236 | |||
237 | void posix_clock_unregister(struct posix_clock *clk) | ||
238 | { | ||
239 | cdev_del(&clk->cdev); | ||
240 | |||
241 | mutex_lock(&clk->mutex); | ||
242 | clk->zombie = true; | ||
243 | mutex_unlock(&clk->mutex); | ||
244 | |||
245 | kref_put(&clk->kref, delete_clock); | ||
246 | } | ||
247 | EXPORT_SYMBOL_GPL(posix_clock_unregister); | ||
248 | |||
249 | struct posix_clock_desc { | ||
250 | struct file *fp; | ||
251 | struct posix_clock *clk; | ||
252 | }; | ||
253 | |||
254 | static int get_clock_desc(const clockid_t id, struct posix_clock_desc *cd) | ||
255 | { | ||
256 | struct file *fp = fget(CLOCKID_TO_FD(id)); | ||
257 | int err = -EINVAL; | ||
258 | |||
259 | if (!fp) | ||
260 | return err; | ||
261 | |||
262 | if (fp->f_op->open != posix_clock_open || !fp->private_data) | ||
263 | goto out; | ||
264 | |||
265 | cd->fp = fp; | ||
266 | cd->clk = get_posix_clock(fp); | ||
267 | |||
268 | err = cd->clk ? 0 : -ENODEV; | ||
269 | out: | ||
270 | if (err) | ||
271 | fput(fp); | ||
272 | return err; | ||
273 | } | ||
274 | |||
275 | static void put_clock_desc(struct posix_clock_desc *cd) | ||
276 | { | ||
277 | put_posix_clock(cd->clk); | ||
278 | fput(cd->fp); | ||
279 | } | ||
280 | |||
281 | static int pc_clock_adjtime(clockid_t id, struct timex *tx) | ||
282 | { | ||
283 | struct posix_clock_desc cd; | ||
284 | int err; | ||
285 | |||
286 | err = get_clock_desc(id, &cd); | ||
287 | if (err) | ||
288 | return err; | ||
289 | |||
290 | if (cd.clk->ops.clock_adjtime) | ||
291 | err = cd.clk->ops.clock_adjtime(cd.clk, tx); | ||
292 | else | ||
293 | err = -EOPNOTSUPP; | ||
294 | |||
295 | put_clock_desc(&cd); | ||
296 | |||
297 | return err; | ||
298 | } | ||
299 | |||
300 | static int pc_clock_gettime(clockid_t id, struct timespec *ts) | ||
301 | { | ||
302 | struct posix_clock_desc cd; | ||
303 | int err; | ||
304 | |||
305 | err = get_clock_desc(id, &cd); | ||
306 | if (err) | ||
307 | return err; | ||
308 | |||
309 | if (cd.clk->ops.clock_gettime) | ||
310 | err = cd.clk->ops.clock_gettime(cd.clk, ts); | ||
311 | else | ||
312 | err = -EOPNOTSUPP; | ||
313 | |||
314 | put_clock_desc(&cd); | ||
315 | |||
316 | return err; | ||
317 | } | ||
318 | |||
319 | static int pc_clock_getres(clockid_t id, struct timespec *ts) | ||
320 | { | ||
321 | struct posix_clock_desc cd; | ||
322 | int err; | ||
323 | |||
324 | err = get_clock_desc(id, &cd); | ||
325 | if (err) | ||
326 | return err; | ||
327 | |||
328 | if (cd.clk->ops.clock_getres) | ||
329 | err = cd.clk->ops.clock_getres(cd.clk, ts); | ||
330 | else | ||
331 | err = -EOPNOTSUPP; | ||
332 | |||
333 | put_clock_desc(&cd); | ||
334 | |||
335 | return err; | ||
336 | } | ||
337 | |||
338 | static int pc_clock_settime(clockid_t id, const struct timespec *ts) | ||
339 | { | ||
340 | struct posix_clock_desc cd; | ||
341 | int err; | ||
342 | |||
343 | err = get_clock_desc(id, &cd); | ||
344 | if (err) | ||
345 | return err; | ||
346 | |||
347 | if (cd.clk->ops.clock_settime) | ||
348 | err = cd.clk->ops.clock_settime(cd.clk, ts); | ||
349 | else | ||
350 | err = -EOPNOTSUPP; | ||
351 | |||
352 | put_clock_desc(&cd); | ||
353 | |||
354 | return err; | ||
355 | } | ||
356 | |||
357 | static int pc_timer_create(struct k_itimer *kit) | ||
358 | { | ||
359 | clockid_t id = kit->it_clock; | ||
360 | struct posix_clock_desc cd; | ||
361 | int err; | ||
362 | |||
363 | err = get_clock_desc(id, &cd); | ||
364 | if (err) | ||
365 | return err; | ||
366 | |||
367 | if (cd.clk->ops.timer_create) | ||
368 | err = cd.clk->ops.timer_create(cd.clk, kit); | ||
369 | else | ||
370 | err = -EOPNOTSUPP; | ||
371 | |||
372 | put_clock_desc(&cd); | ||
373 | |||
374 | return err; | ||
375 | } | ||
376 | |||
377 | static int pc_timer_delete(struct k_itimer *kit) | ||
378 | { | ||
379 | clockid_t id = kit->it_clock; | ||
380 | struct posix_clock_desc cd; | ||
381 | int err; | ||
382 | |||
383 | err = get_clock_desc(id, &cd); | ||
384 | if (err) | ||
385 | return err; | ||
386 | |||
387 | if (cd.clk->ops.timer_delete) | ||
388 | err = cd.clk->ops.timer_delete(cd.clk, kit); | ||
389 | else | ||
390 | err = -EOPNOTSUPP; | ||
391 | |||
392 | put_clock_desc(&cd); | ||
393 | |||
394 | return err; | ||
395 | } | ||
396 | |||
397 | static void pc_timer_gettime(struct k_itimer *kit, struct itimerspec *ts) | ||
398 | { | ||
399 | clockid_t id = kit->it_clock; | ||
400 | struct posix_clock_desc cd; | ||
401 | |||
402 | if (get_clock_desc(id, &cd)) | ||
403 | return; | ||
404 | |||
405 | if (cd.clk->ops.timer_gettime) | ||
406 | cd.clk->ops.timer_gettime(cd.clk, kit, ts); | ||
407 | |||
408 | put_clock_desc(&cd); | ||
409 | } | ||
410 | |||
411 | static int pc_timer_settime(struct k_itimer *kit, int flags, | ||
412 | struct itimerspec *ts, struct itimerspec *old) | ||
413 | { | ||
414 | clockid_t id = kit->it_clock; | ||
415 | struct posix_clock_desc cd; | ||
416 | int err; | ||
417 | |||
418 | err = get_clock_desc(id, &cd); | ||
419 | if (err) | ||
420 | return err; | ||
421 | |||
422 | if (cd.clk->ops.timer_settime) | ||
423 | err = cd.clk->ops.timer_settime(cd.clk, kit, flags, ts, old); | ||
424 | else | ||
425 | err = -EOPNOTSUPP; | ||
426 | |||
427 | put_clock_desc(&cd); | ||
428 | |||
429 | return err; | ||
430 | } | ||
431 | |||
432 | struct k_clock clock_posix_dynamic = { | ||
433 | .clock_getres = pc_clock_getres, | ||
434 | .clock_set = pc_clock_settime, | ||
435 | .clock_get = pc_clock_gettime, | ||
436 | .clock_adj = pc_clock_adjtime, | ||
437 | .timer_create = pc_timer_create, | ||
438 | .timer_set = pc_timer_settime, | ||
439 | .timer_del = pc_timer_delete, | ||
440 | .timer_get = pc_timer_gettime, | ||
441 | }; | ||