10606f422SRichard Cochran /* 20606f422SRichard Cochran * posix-clock.c - support for dynamic clock devices 30606f422SRichard Cochran * 40606f422SRichard Cochran * Copyright (C) 2010 OMICRON electronics GmbH 50606f422SRichard Cochran * 60606f422SRichard Cochran * This program is free software; you can redistribute it and/or modify 70606f422SRichard Cochran * it under the terms of the GNU General Public License as published by 80606f422SRichard Cochran * the Free Software Foundation; either version 2 of the License, or 90606f422SRichard Cochran * (at your option) any later version. 100606f422SRichard Cochran * 110606f422SRichard Cochran * This program is distributed in the hope that it will be useful, 120606f422SRichard Cochran * but WITHOUT ANY WARRANTY; without even the implied warranty of 130606f422SRichard Cochran * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 140606f422SRichard Cochran * GNU General Public License for more details. 150606f422SRichard Cochran * 160606f422SRichard Cochran * You should have received a copy of the GNU General Public License 170606f422SRichard Cochran * along with this program; if not, write to the Free Software 180606f422SRichard Cochran * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 190606f422SRichard Cochran */ 200606f422SRichard Cochran #include <linux/device.h> 216e5fdeedSPaul Gortmaker #include <linux/export.h> 220606f422SRichard Cochran #include <linux/file.h> 230606f422SRichard Cochran #include <linux/posix-clock.h> 240606f422SRichard Cochran #include <linux/slab.h> 250606f422SRichard Cochran #include <linux/syscalls.h> 260606f422SRichard Cochran #include <linux/uaccess.h> 270606f422SRichard Cochran 280606f422SRichard Cochran static void delete_clock(struct kref *kref); 290606f422SRichard Cochran 300606f422SRichard Cochran /* 310606f422SRichard Cochran * Returns NULL if the posix_clock instance attached to 'fp' is old and stale. 320606f422SRichard Cochran */ 330606f422SRichard Cochran static struct posix_clock *get_posix_clock(struct file *fp) 340606f422SRichard Cochran { 350606f422SRichard Cochran struct posix_clock *clk = fp->private_data; 360606f422SRichard Cochran 371791f881SRichard Cochran down_read(&clk->rwsem); 380606f422SRichard Cochran 390606f422SRichard Cochran if (!clk->zombie) 400606f422SRichard Cochran return clk; 410606f422SRichard Cochran 421791f881SRichard Cochran up_read(&clk->rwsem); 430606f422SRichard Cochran 440606f422SRichard Cochran return NULL; 450606f422SRichard Cochran } 460606f422SRichard Cochran 470606f422SRichard Cochran static void put_posix_clock(struct posix_clock *clk) 480606f422SRichard Cochran { 491791f881SRichard Cochran up_read(&clk->rwsem); 500606f422SRichard Cochran } 510606f422SRichard Cochran 520606f422SRichard Cochran static ssize_t posix_clock_read(struct file *fp, char __user *buf, 530606f422SRichard Cochran size_t count, loff_t *ppos) 540606f422SRichard Cochran { 550606f422SRichard Cochran struct posix_clock *clk = get_posix_clock(fp); 560606f422SRichard Cochran int err = -EINVAL; 570606f422SRichard Cochran 580606f422SRichard Cochran if (!clk) 590606f422SRichard Cochran return -ENODEV; 600606f422SRichard Cochran 610606f422SRichard Cochran if (clk->ops.read) 620606f422SRichard Cochran err = clk->ops.read(clk, fp->f_flags, buf, count); 630606f422SRichard Cochran 640606f422SRichard Cochran put_posix_clock(clk); 650606f422SRichard Cochran 660606f422SRichard Cochran return err; 670606f422SRichard Cochran } 680606f422SRichard Cochran 690606f422SRichard Cochran static unsigned int posix_clock_poll(struct file *fp, poll_table *wait) 700606f422SRichard Cochran { 710606f422SRichard Cochran struct posix_clock *clk = get_posix_clock(fp); 721b9f2372SRichard Cochran unsigned int result = 0; 730606f422SRichard Cochran 740606f422SRichard Cochran if (!clk) 751b9f2372SRichard Cochran return POLLERR; 760606f422SRichard Cochran 770606f422SRichard Cochran if (clk->ops.poll) 780606f422SRichard Cochran result = clk->ops.poll(clk, fp, wait); 790606f422SRichard Cochran 800606f422SRichard Cochran put_posix_clock(clk); 810606f422SRichard Cochran 820606f422SRichard Cochran return result; 830606f422SRichard Cochran } 840606f422SRichard Cochran 850606f422SRichard Cochran static int posix_clock_fasync(int fd, struct file *fp, int on) 860606f422SRichard Cochran { 870606f422SRichard Cochran struct posix_clock *clk = get_posix_clock(fp); 880606f422SRichard Cochran int err = 0; 890606f422SRichard Cochran 900606f422SRichard Cochran if (!clk) 910606f422SRichard Cochran return -ENODEV; 920606f422SRichard Cochran 930606f422SRichard Cochran if (clk->ops.fasync) 940606f422SRichard Cochran err = clk->ops.fasync(clk, fd, fp, on); 950606f422SRichard Cochran 960606f422SRichard Cochran put_posix_clock(clk); 970606f422SRichard Cochran 980606f422SRichard Cochran return err; 990606f422SRichard Cochran } 1000606f422SRichard Cochran 1010606f422SRichard Cochran static int posix_clock_mmap(struct file *fp, struct vm_area_struct *vma) 1020606f422SRichard Cochran { 1030606f422SRichard Cochran struct posix_clock *clk = get_posix_clock(fp); 1040606f422SRichard Cochran int err = -ENODEV; 1050606f422SRichard Cochran 1060606f422SRichard Cochran if (!clk) 1070606f422SRichard Cochran return -ENODEV; 1080606f422SRichard Cochran 1090606f422SRichard Cochran if (clk->ops.mmap) 1100606f422SRichard Cochran err = clk->ops.mmap(clk, vma); 1110606f422SRichard Cochran 1120606f422SRichard Cochran put_posix_clock(clk); 1130606f422SRichard Cochran 1140606f422SRichard Cochran return err; 1150606f422SRichard Cochran } 1160606f422SRichard Cochran 1170606f422SRichard Cochran static long posix_clock_ioctl(struct file *fp, 1180606f422SRichard Cochran unsigned int cmd, unsigned long arg) 1190606f422SRichard Cochran { 1200606f422SRichard Cochran struct posix_clock *clk = get_posix_clock(fp); 1210606f422SRichard Cochran int err = -ENOTTY; 1220606f422SRichard Cochran 1230606f422SRichard Cochran if (!clk) 1240606f422SRichard Cochran return -ENODEV; 1250606f422SRichard Cochran 1260606f422SRichard Cochran if (clk->ops.ioctl) 1270606f422SRichard Cochran err = clk->ops.ioctl(clk, cmd, arg); 1280606f422SRichard Cochran 1290606f422SRichard Cochran put_posix_clock(clk); 1300606f422SRichard Cochran 1310606f422SRichard Cochran return err; 1320606f422SRichard Cochran } 1330606f422SRichard Cochran 1340606f422SRichard Cochran #ifdef CONFIG_COMPAT 1350606f422SRichard Cochran static long posix_clock_compat_ioctl(struct file *fp, 1360606f422SRichard Cochran unsigned int cmd, unsigned long arg) 1370606f422SRichard Cochran { 1380606f422SRichard Cochran struct posix_clock *clk = get_posix_clock(fp); 1390606f422SRichard Cochran int err = -ENOTTY; 1400606f422SRichard Cochran 1410606f422SRichard Cochran if (!clk) 1420606f422SRichard Cochran return -ENODEV; 1430606f422SRichard Cochran 1440606f422SRichard Cochran if (clk->ops.ioctl) 1450606f422SRichard Cochran err = clk->ops.ioctl(clk, cmd, arg); 1460606f422SRichard Cochran 1470606f422SRichard Cochran put_posix_clock(clk); 1480606f422SRichard Cochran 1490606f422SRichard Cochran return err; 1500606f422SRichard Cochran } 1510606f422SRichard Cochran #endif 1520606f422SRichard Cochran 1530606f422SRichard Cochran static int posix_clock_open(struct inode *inode, struct file *fp) 1540606f422SRichard Cochran { 1550606f422SRichard Cochran int err; 1560606f422SRichard Cochran struct posix_clock *clk = 1570606f422SRichard Cochran container_of(inode->i_cdev, struct posix_clock, cdev); 1580606f422SRichard Cochran 1591791f881SRichard Cochran down_read(&clk->rwsem); 1600606f422SRichard Cochran 1610606f422SRichard Cochran if (clk->zombie) { 1620606f422SRichard Cochran err = -ENODEV; 1630606f422SRichard Cochran goto out; 1640606f422SRichard Cochran } 1650606f422SRichard Cochran if (clk->ops.open) 1660606f422SRichard Cochran err = clk->ops.open(clk, fp->f_mode); 1670606f422SRichard Cochran else 1680606f422SRichard Cochran err = 0; 1690606f422SRichard Cochran 1700606f422SRichard Cochran if (!err) { 1710606f422SRichard Cochran kref_get(&clk->kref); 1720606f422SRichard Cochran fp->private_data = clk; 1730606f422SRichard Cochran } 1740606f422SRichard Cochran out: 1751791f881SRichard Cochran up_read(&clk->rwsem); 1760606f422SRichard Cochran return err; 1770606f422SRichard Cochran } 1780606f422SRichard Cochran 1790606f422SRichard Cochran static int posix_clock_release(struct inode *inode, struct file *fp) 1800606f422SRichard Cochran { 1810606f422SRichard Cochran struct posix_clock *clk = fp->private_data; 1820606f422SRichard Cochran int err = 0; 1830606f422SRichard Cochran 1840606f422SRichard Cochran if (clk->ops.release) 1850606f422SRichard Cochran err = clk->ops.release(clk); 1860606f422SRichard Cochran 1870606f422SRichard Cochran kref_put(&clk->kref, delete_clock); 1880606f422SRichard Cochran 1890606f422SRichard Cochran fp->private_data = NULL; 1900606f422SRichard Cochran 1910606f422SRichard Cochran return err; 1920606f422SRichard Cochran } 1930606f422SRichard Cochran 1940606f422SRichard Cochran static const struct file_operations posix_clock_file_operations = { 1950606f422SRichard Cochran .owner = THIS_MODULE, 1960606f422SRichard Cochran .llseek = no_llseek, 1970606f422SRichard Cochran .read = posix_clock_read, 1980606f422SRichard Cochran .poll = posix_clock_poll, 1990606f422SRichard Cochran .unlocked_ioctl = posix_clock_ioctl, 2000606f422SRichard Cochran .open = posix_clock_open, 2010606f422SRichard Cochran .release = posix_clock_release, 2020606f422SRichard Cochran .fasync = posix_clock_fasync, 2030606f422SRichard Cochran .mmap = posix_clock_mmap, 2040606f422SRichard Cochran #ifdef CONFIG_COMPAT 2050606f422SRichard Cochran .compat_ioctl = posix_clock_compat_ioctl, 2060606f422SRichard Cochran #endif 2070606f422SRichard Cochran }; 2080606f422SRichard Cochran 2090606f422SRichard Cochran int posix_clock_register(struct posix_clock *clk, dev_t devid) 2100606f422SRichard Cochran { 2110606f422SRichard Cochran int err; 2120606f422SRichard Cochran 2130606f422SRichard Cochran kref_init(&clk->kref); 2141791f881SRichard Cochran init_rwsem(&clk->rwsem); 2150606f422SRichard Cochran 2160606f422SRichard Cochran cdev_init(&clk->cdev, &posix_clock_file_operations); 2170606f422SRichard Cochran clk->cdev.owner = clk->ops.owner; 2180606f422SRichard Cochran err = cdev_add(&clk->cdev, devid, 1); 2190606f422SRichard Cochran 2200606f422SRichard Cochran return err; 2210606f422SRichard Cochran } 2220606f422SRichard Cochran EXPORT_SYMBOL_GPL(posix_clock_register); 2230606f422SRichard Cochran 2240606f422SRichard Cochran static void delete_clock(struct kref *kref) 2250606f422SRichard Cochran { 2260606f422SRichard Cochran struct posix_clock *clk = container_of(kref, struct posix_clock, kref); 2271791f881SRichard Cochran 2280606f422SRichard Cochran if (clk->release) 2290606f422SRichard Cochran clk->release(clk); 2300606f422SRichard Cochran } 2310606f422SRichard Cochran 2320606f422SRichard Cochran void posix_clock_unregister(struct posix_clock *clk) 2330606f422SRichard Cochran { 2340606f422SRichard Cochran cdev_del(&clk->cdev); 2350606f422SRichard Cochran 2361791f881SRichard Cochran down_write(&clk->rwsem); 2370606f422SRichard Cochran clk->zombie = true; 2381791f881SRichard Cochran up_write(&clk->rwsem); 2390606f422SRichard Cochran 2400606f422SRichard Cochran kref_put(&clk->kref, delete_clock); 2410606f422SRichard Cochran } 2420606f422SRichard Cochran EXPORT_SYMBOL_GPL(posix_clock_unregister); 2430606f422SRichard Cochran 2440606f422SRichard Cochran struct posix_clock_desc { 2450606f422SRichard Cochran struct file *fp; 2460606f422SRichard Cochran struct posix_clock *clk; 2470606f422SRichard Cochran }; 2480606f422SRichard Cochran 2490606f422SRichard Cochran static int get_clock_desc(const clockid_t id, struct posix_clock_desc *cd) 2500606f422SRichard Cochran { 2510606f422SRichard Cochran struct file *fp = fget(CLOCKID_TO_FD(id)); 2520606f422SRichard Cochran int err = -EINVAL; 2530606f422SRichard Cochran 2540606f422SRichard Cochran if (!fp) 2550606f422SRichard Cochran return err; 2560606f422SRichard Cochran 2570606f422SRichard Cochran if (fp->f_op->open != posix_clock_open || !fp->private_data) 2580606f422SRichard Cochran goto out; 2590606f422SRichard Cochran 2600606f422SRichard Cochran cd->fp = fp; 2610606f422SRichard Cochran cd->clk = get_posix_clock(fp); 2620606f422SRichard Cochran 2630606f422SRichard Cochran err = cd->clk ? 0 : -ENODEV; 2640606f422SRichard Cochran out: 2650606f422SRichard Cochran if (err) 2660606f422SRichard Cochran fput(fp); 2670606f422SRichard Cochran return err; 2680606f422SRichard Cochran } 2690606f422SRichard Cochran 2700606f422SRichard Cochran static void put_clock_desc(struct posix_clock_desc *cd) 2710606f422SRichard Cochran { 2720606f422SRichard Cochran put_posix_clock(cd->clk); 2730606f422SRichard Cochran fput(cd->fp); 2740606f422SRichard Cochran } 2750606f422SRichard Cochran 2760606f422SRichard Cochran static int pc_clock_adjtime(clockid_t id, struct timex *tx) 2770606f422SRichard Cochran { 2780606f422SRichard Cochran struct posix_clock_desc cd; 2790606f422SRichard Cochran int err; 2800606f422SRichard Cochran 2810606f422SRichard Cochran err = get_clock_desc(id, &cd); 2820606f422SRichard Cochran if (err) 2830606f422SRichard Cochran return err; 2840606f422SRichard Cochran 2856e6823d1STorben Hohn if ((cd.fp->f_mode & FMODE_WRITE) == 0) { 2866e6823d1STorben Hohn err = -EACCES; 2876e6823d1STorben Hohn goto out; 2886e6823d1STorben Hohn } 2896e6823d1STorben Hohn 2900606f422SRichard Cochran if (cd.clk->ops.clock_adjtime) 2910606f422SRichard Cochran err = cd.clk->ops.clock_adjtime(cd.clk, tx); 2920606f422SRichard Cochran else 2930606f422SRichard Cochran err = -EOPNOTSUPP; 2946e6823d1STorben Hohn out: 2950606f422SRichard Cochran put_clock_desc(&cd); 2960606f422SRichard Cochran 2970606f422SRichard Cochran return err; 2980606f422SRichard Cochran } 2990606f422SRichard Cochran 3003c9c12f4SDeepa Dinamani static int pc_clock_gettime(clockid_t id, struct timespec64 *ts) 3010606f422SRichard Cochran { 3020606f422SRichard Cochran struct posix_clock_desc cd; 3030606f422SRichard Cochran int err; 3040606f422SRichard Cochran 3050606f422SRichard Cochran err = get_clock_desc(id, &cd); 3060606f422SRichard Cochran if (err) 3070606f422SRichard Cochran return err; 3080606f422SRichard Cochran 3093c9c12f4SDeepa Dinamani if (cd.clk->ops.clock_gettime) 3103c9c12f4SDeepa Dinamani err = cd.clk->ops.clock_gettime(cd.clk, ts); 3110606f422SRichard Cochran else 3120606f422SRichard Cochran err = -EOPNOTSUPP; 3130606f422SRichard Cochran 3140606f422SRichard Cochran put_clock_desc(&cd); 3150606f422SRichard Cochran 3160606f422SRichard Cochran return err; 3170606f422SRichard Cochran } 3180606f422SRichard Cochran 319d2e3e0caSDeepa Dinamani static int pc_clock_getres(clockid_t id, struct timespec64 *ts) 3200606f422SRichard Cochran { 3210606f422SRichard Cochran struct posix_clock_desc cd; 3220606f422SRichard Cochran int err; 3230606f422SRichard Cochran 3240606f422SRichard Cochran err = get_clock_desc(id, &cd); 3250606f422SRichard Cochran if (err) 3260606f422SRichard Cochran return err; 3270606f422SRichard Cochran 328d2e3e0caSDeepa Dinamani if (cd.clk->ops.clock_getres) 329d2e3e0caSDeepa Dinamani err = cd.clk->ops.clock_getres(cd.clk, ts); 3300606f422SRichard Cochran else 3310606f422SRichard Cochran err = -EOPNOTSUPP; 3320606f422SRichard Cochran 3330606f422SRichard Cochran put_clock_desc(&cd); 3340606f422SRichard Cochran 3350606f422SRichard Cochran return err; 3360606f422SRichard Cochran } 3370606f422SRichard Cochran 3380606f422SRichard Cochran static int pc_clock_settime(clockid_t id, const struct timespec *ts) 3390606f422SRichard Cochran { 340d340266eSDeepa Dinamani struct timespec64 ts64 = timespec_to_timespec64(*ts); 3410606f422SRichard Cochran struct posix_clock_desc cd; 3420606f422SRichard Cochran int err; 3430606f422SRichard Cochran 3440606f422SRichard Cochran err = get_clock_desc(id, &cd); 3450606f422SRichard Cochran if (err) 3460606f422SRichard Cochran return err; 3470606f422SRichard Cochran 3486e6823d1STorben Hohn if ((cd.fp->f_mode & FMODE_WRITE) == 0) { 3496e6823d1STorben Hohn err = -EACCES; 3506e6823d1STorben Hohn goto out; 3516e6823d1STorben Hohn } 3526e6823d1STorben Hohn 3530606f422SRichard Cochran if (cd.clk->ops.clock_settime) 354d340266eSDeepa Dinamani err = cd.clk->ops.clock_settime(cd.clk, &ts64); 3550606f422SRichard Cochran else 3560606f422SRichard Cochran err = -EOPNOTSUPP; 3576e6823d1STorben Hohn out: 3580606f422SRichard Cochran put_clock_desc(&cd); 3590606f422SRichard Cochran 3600606f422SRichard Cochran return err; 3610606f422SRichard Cochran } 3620606f422SRichard Cochran 3630606f422SRichard Cochran static int pc_timer_create(struct k_itimer *kit) 3640606f422SRichard Cochran { 3650606f422SRichard Cochran clockid_t id = kit->it_clock; 3660606f422SRichard Cochran struct posix_clock_desc cd; 3670606f422SRichard Cochran int err; 3680606f422SRichard Cochran 3690606f422SRichard Cochran err = get_clock_desc(id, &cd); 3700606f422SRichard Cochran if (err) 3710606f422SRichard Cochran return err; 3720606f422SRichard Cochran 3730606f422SRichard Cochran if (cd.clk->ops.timer_create) 3740606f422SRichard Cochran err = cd.clk->ops.timer_create(cd.clk, kit); 3750606f422SRichard Cochran else 3760606f422SRichard Cochran err = -EOPNOTSUPP; 3770606f422SRichard Cochran 3780606f422SRichard Cochran put_clock_desc(&cd); 3790606f422SRichard Cochran 3800606f422SRichard Cochran return err; 3810606f422SRichard Cochran } 3820606f422SRichard Cochran 3830606f422SRichard Cochran static int pc_timer_delete(struct k_itimer *kit) 3840606f422SRichard Cochran { 3850606f422SRichard Cochran clockid_t id = kit->it_clock; 3860606f422SRichard Cochran struct posix_clock_desc cd; 3870606f422SRichard Cochran int err; 3880606f422SRichard Cochran 3890606f422SRichard Cochran err = get_clock_desc(id, &cd); 3900606f422SRichard Cochran if (err) 3910606f422SRichard Cochran return err; 3920606f422SRichard Cochran 3930606f422SRichard Cochran if (cd.clk->ops.timer_delete) 3940606f422SRichard Cochran err = cd.clk->ops.timer_delete(cd.clk, kit); 3950606f422SRichard Cochran else 3960606f422SRichard Cochran err = -EOPNOTSUPP; 3970606f422SRichard Cochran 3980606f422SRichard Cochran put_clock_desc(&cd); 3990606f422SRichard Cochran 4000606f422SRichard Cochran return err; 4010606f422SRichard Cochran } 4020606f422SRichard Cochran 4030606f422SRichard Cochran static void pc_timer_gettime(struct k_itimer *kit, struct itimerspec *ts) 4040606f422SRichard Cochran { 4050606f422SRichard Cochran clockid_t id = kit->it_clock; 4060606f422SRichard Cochran struct posix_clock_desc cd; 407d340266eSDeepa Dinamani struct itimerspec64 ts64; 4080606f422SRichard Cochran 4090606f422SRichard Cochran if (get_clock_desc(id, &cd)) 4100606f422SRichard Cochran return; 4110606f422SRichard Cochran 412d340266eSDeepa Dinamani if (cd.clk->ops.timer_gettime) { 413d340266eSDeepa Dinamani cd.clk->ops.timer_gettime(cd.clk, kit, &ts64); 414d340266eSDeepa Dinamani *ts = itimerspec64_to_itimerspec(&ts64); 415d340266eSDeepa Dinamani } 4160606f422SRichard Cochran put_clock_desc(&cd); 4170606f422SRichard Cochran } 4180606f422SRichard Cochran 4190606f422SRichard Cochran static int pc_timer_settime(struct k_itimer *kit, int flags, 4200606f422SRichard Cochran struct itimerspec *ts, struct itimerspec *old) 4210606f422SRichard Cochran { 422d340266eSDeepa Dinamani struct itimerspec64 ts64 = itimerspec_to_itimerspec64(ts); 4230606f422SRichard Cochran clockid_t id = kit->it_clock; 4240606f422SRichard Cochran struct posix_clock_desc cd; 425d340266eSDeepa Dinamani struct itimerspec64 old64; 4260606f422SRichard Cochran int err; 4270606f422SRichard Cochran 4280606f422SRichard Cochran err = get_clock_desc(id, &cd); 4290606f422SRichard Cochran if (err) 4300606f422SRichard Cochran return err; 4310606f422SRichard Cochran 432d340266eSDeepa Dinamani if (cd.clk->ops.timer_settime) { 433d340266eSDeepa Dinamani err = cd.clk->ops.timer_settime(cd.clk, kit, flags, &ts64, &old64); 434d340266eSDeepa Dinamani if (old) 435d340266eSDeepa Dinamani *old = itimerspec64_to_itimerspec(&old64); 436d340266eSDeepa Dinamani } 4370606f422SRichard Cochran else 4380606f422SRichard Cochran err = -EOPNOTSUPP; 4390606f422SRichard Cochran 4400606f422SRichard Cochran put_clock_desc(&cd); 4410606f422SRichard Cochran 4420606f422SRichard Cochran return err; 4430606f422SRichard Cochran } 4440606f422SRichard Cochran 4450606f422SRichard Cochran struct k_clock clock_posix_dynamic = { 4460606f422SRichard Cochran .clock_getres = pc_clock_getres, 4470606f422SRichard Cochran .clock_set = pc_clock_settime, 4480606f422SRichard Cochran .clock_get = pc_clock_gettime, 4490606f422SRichard Cochran .clock_adj = pc_clock_adjtime, 4500606f422SRichard Cochran .timer_create = pc_timer_create, 4510606f422SRichard Cochran .timer_set = pc_timer_settime, 4520606f422SRichard Cochran .timer_del = pc_timer_delete, 4530606f422SRichard Cochran .timer_get = pc_timer_gettime, 4540606f422SRichard Cochran }; 455