diff options
author | Richard Cochran <richardcochran@gmail.com> | 2014-03-20 17:21:52 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-03-21 14:21:13 -0400 |
commit | 6092315dfdec5185881605d15a0e200d6e90eb66 (patch) | |
tree | 8b018970396a2e2380fe51ed14d2f860ce6010e1 | |
parent | a85ae0e97879f51bccd8511668b07d346d98b3eb (diff) |
ptp: introduce programmable pins.
This patch adds a pair of new ioctls to the PTP Hardware Clock device
interface. Using the ioctls, user space programs can query each pin to
find out its current function and also reprogram a different function
if desired.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | drivers/ptp/ptp_chardev.c | 128 | ||||
-rw-r--r-- | drivers/ptp/ptp_clock.c | 23 | ||||
-rw-r--r-- | drivers/ptp/ptp_private.h | 5 | ||||
-rw-r--r-- | include/linux/ptp_clock_kernel.h | 33 | ||||
-rw-r--r-- | include/uapi/linux/ptp_clock.h | 39 |
5 files changed, 226 insertions, 2 deletions
diff --git a/drivers/ptp/ptp_chardev.c b/drivers/ptp/ptp_chardev.c index 34a0c607318e..419056d7887e 100644 --- a/drivers/ptp/ptp_chardev.c +++ b/drivers/ptp/ptp_chardev.c | |||
@@ -25,6 +25,96 @@ | |||
25 | 25 | ||
26 | #include "ptp_private.h" | 26 | #include "ptp_private.h" |
27 | 27 | ||
28 | static int ptp_disable_pinfunc(struct ptp_clock_info *ops, | ||
29 | enum ptp_pin_function func, unsigned int chan) | ||
30 | { | ||
31 | struct ptp_clock_request rq; | ||
32 | int err = 0; | ||
33 | |||
34 | memset(&rq, 0, sizeof(rq)); | ||
35 | |||
36 | switch (func) { | ||
37 | case PTP_PF_NONE: | ||
38 | break; | ||
39 | case PTP_PF_EXTTS: | ||
40 | rq.type = PTP_CLK_REQ_EXTTS; | ||
41 | rq.extts.index = chan; | ||
42 | err = ops->enable(ops, &rq, 0); | ||
43 | break; | ||
44 | case PTP_PF_PEROUT: | ||
45 | rq.type = PTP_CLK_REQ_PEROUT; | ||
46 | rq.perout.index = chan; | ||
47 | err = ops->enable(ops, &rq, 0); | ||
48 | break; | ||
49 | case PTP_PF_PHYSYNC: | ||
50 | break; | ||
51 | default: | ||
52 | return -EINVAL; | ||
53 | } | ||
54 | |||
55 | return err; | ||
56 | } | ||
57 | |||
58 | int ptp_set_pinfunc(struct ptp_clock *ptp, unsigned int pin, | ||
59 | enum ptp_pin_function func, unsigned int chan) | ||
60 | { | ||
61 | struct ptp_clock_info *info = ptp->info; | ||
62 | struct ptp_pin_desc *pin1 = NULL, *pin2 = &info->pin_config[pin]; | ||
63 | unsigned int i; | ||
64 | |||
65 | /* Check to see if any other pin previously had this function. */ | ||
66 | for (i = 0; i < info->n_pins; i++) { | ||
67 | if (info->pin_config[i].func == func && | ||
68 | info->pin_config[i].chan == chan) { | ||
69 | pin1 = &info->pin_config[i]; | ||
70 | break; | ||
71 | } | ||
72 | } | ||
73 | if (pin1 && i == pin) | ||
74 | return 0; | ||
75 | |||
76 | /* Check the desired function and channel. */ | ||
77 | switch (func) { | ||
78 | case PTP_PF_NONE: | ||
79 | break; | ||
80 | case PTP_PF_EXTTS: | ||
81 | if (chan >= info->n_ext_ts) | ||
82 | return -EINVAL; | ||
83 | break; | ||
84 | case PTP_PF_PEROUT: | ||
85 | if (chan >= info->n_per_out) | ||
86 | return -EINVAL; | ||
87 | break; | ||
88 | case PTP_PF_PHYSYNC: | ||
89 | pr_err("sorry, cannot reassign the calibration pin\n"); | ||
90 | return -EINVAL; | ||
91 | default: | ||
92 | return -EINVAL; | ||
93 | } | ||
94 | |||
95 | if (pin2->func == PTP_PF_PHYSYNC) { | ||
96 | pr_err("sorry, cannot reprogram the calibration pin\n"); | ||
97 | return -EINVAL; | ||
98 | } | ||
99 | |||
100 | if (info->verify(info, pin, func, chan)) { | ||
101 | pr_err("driver cannot use function %u on pin %u\n", func, chan); | ||
102 | return -EOPNOTSUPP; | ||
103 | } | ||
104 | |||
105 | /* Disable whatever function was previously assigned. */ | ||
106 | if (pin1) { | ||
107 | ptp_disable_pinfunc(info, func, chan); | ||
108 | pin1->func = PTP_PF_NONE; | ||
109 | pin1->chan = 0; | ||
110 | } | ||
111 | ptp_disable_pinfunc(info, pin2->func, pin2->chan); | ||
112 | pin2->func = func; | ||
113 | pin2->chan = chan; | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
28 | int ptp_open(struct posix_clock *pc, fmode_t fmode) | 118 | int ptp_open(struct posix_clock *pc, fmode_t fmode) |
29 | { | 119 | { |
30 | return 0; | 120 | return 0; |
@@ -35,12 +125,13 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg) | |||
35 | struct ptp_clock_caps caps; | 125 | struct ptp_clock_caps caps; |
36 | struct ptp_clock_request req; | 126 | struct ptp_clock_request req; |
37 | struct ptp_sys_offset *sysoff = NULL; | 127 | struct ptp_sys_offset *sysoff = NULL; |
128 | struct ptp_pin_desc pd; | ||
38 | struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); | 129 | struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); |
39 | struct ptp_clock_info *ops = ptp->info; | 130 | struct ptp_clock_info *ops = ptp->info; |
40 | struct ptp_clock_time *pct; | 131 | struct ptp_clock_time *pct; |
41 | struct timespec ts; | 132 | struct timespec ts; |
42 | int enable, err = 0; | 133 | int enable, err = 0; |
43 | unsigned int i; | 134 | unsigned int i, pin_index; |
44 | 135 | ||
45 | switch (cmd) { | 136 | switch (cmd) { |
46 | 137 | ||
@@ -51,6 +142,7 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg) | |||
51 | caps.n_ext_ts = ptp->info->n_ext_ts; | 142 | caps.n_ext_ts = ptp->info->n_ext_ts; |
52 | caps.n_per_out = ptp->info->n_per_out; | 143 | caps.n_per_out = ptp->info->n_per_out; |
53 | caps.pps = ptp->info->pps; | 144 | caps.pps = ptp->info->pps; |
145 | caps.n_pins = ptp->info->n_pins; | ||
54 | if (copy_to_user((void __user *)arg, &caps, sizeof(caps))) | 146 | if (copy_to_user((void __user *)arg, &caps, sizeof(caps))) |
55 | err = -EFAULT; | 147 | err = -EFAULT; |
56 | break; | 148 | break; |
@@ -126,6 +218,40 @@ long ptp_ioctl(struct posix_clock *pc, unsigned int cmd, unsigned long arg) | |||
126 | err = -EFAULT; | 218 | err = -EFAULT; |
127 | break; | 219 | break; |
128 | 220 | ||
221 | case PTP_PIN_GETFUNC: | ||
222 | if (copy_from_user(&pd, (void __user *)arg, sizeof(pd))) { | ||
223 | err = -EFAULT; | ||
224 | break; | ||
225 | } | ||
226 | pin_index = pd.index; | ||
227 | if (pin_index >= ops->n_pins) { | ||
228 | err = -EINVAL; | ||
229 | break; | ||
230 | } | ||
231 | if (mutex_lock_interruptible(&ptp->pincfg_mux)) | ||
232 | return -ERESTARTSYS; | ||
233 | pd = ops->pin_config[pin_index]; | ||
234 | mutex_unlock(&ptp->pincfg_mux); | ||
235 | if (!err && copy_to_user((void __user *)arg, &pd, sizeof(pd))) | ||
236 | err = -EFAULT; | ||
237 | break; | ||
238 | |||
239 | case PTP_PIN_SETFUNC: | ||
240 | if (copy_from_user(&pd, (void __user *)arg, sizeof(pd))) { | ||
241 | err = -EFAULT; | ||
242 | break; | ||
243 | } | ||
244 | pin_index = pd.index; | ||
245 | if (pin_index >= ops->n_pins) { | ||
246 | err = -EINVAL; | ||
247 | break; | ||
248 | } | ||
249 | if (mutex_lock_interruptible(&ptp->pincfg_mux)) | ||
250 | return -ERESTARTSYS; | ||
251 | err = ptp_set_pinfunc(ptp, pin_index, pd.func, pd.chan); | ||
252 | mutex_unlock(&ptp->pincfg_mux); | ||
253 | break; | ||
254 | |||
129 | default: | 255 | default: |
130 | err = -ENOTTY; | 256 | err = -ENOTTY; |
131 | break; | 257 | break; |
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c index a8319b266643..e25d2bc898e5 100644 --- a/drivers/ptp/ptp_clock.c +++ b/drivers/ptp/ptp_clock.c | |||
@@ -169,6 +169,7 @@ static void delete_ptp_clock(struct posix_clock *pc) | |||
169 | struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); | 169 | struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); |
170 | 170 | ||
171 | mutex_destroy(&ptp->tsevq_mux); | 171 | mutex_destroy(&ptp->tsevq_mux); |
172 | mutex_destroy(&ptp->pincfg_mux); | ||
172 | ida_simple_remove(&ptp_clocks_map, ptp->index); | 173 | ida_simple_remove(&ptp_clocks_map, ptp->index); |
173 | kfree(ptp); | 174 | kfree(ptp); |
174 | } | 175 | } |
@@ -203,6 +204,7 @@ struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info, | |||
203 | ptp->index = index; | 204 | ptp->index = index; |
204 | spin_lock_init(&ptp->tsevq.lock); | 205 | spin_lock_init(&ptp->tsevq.lock); |
205 | mutex_init(&ptp->tsevq_mux); | 206 | mutex_init(&ptp->tsevq_mux); |
207 | mutex_init(&ptp->pincfg_mux); | ||
206 | init_waitqueue_head(&ptp->tsev_wq); | 208 | init_waitqueue_head(&ptp->tsev_wq); |
207 | 209 | ||
208 | /* Create a new device in our class. */ | 210 | /* Create a new device in our class. */ |
@@ -249,6 +251,7 @@ no_sysfs: | |||
249 | device_destroy(ptp_class, ptp->devid); | 251 | device_destroy(ptp_class, ptp->devid); |
250 | no_device: | 252 | no_device: |
251 | mutex_destroy(&ptp->tsevq_mux); | 253 | mutex_destroy(&ptp->tsevq_mux); |
254 | mutex_destroy(&ptp->pincfg_mux); | ||
252 | no_slot: | 255 | no_slot: |
253 | kfree(ptp); | 256 | kfree(ptp); |
254 | no_memory: | 257 | no_memory: |
@@ -305,6 +308,26 @@ int ptp_clock_index(struct ptp_clock *ptp) | |||
305 | } | 308 | } |
306 | EXPORT_SYMBOL(ptp_clock_index); | 309 | EXPORT_SYMBOL(ptp_clock_index); |
307 | 310 | ||
311 | int ptp_find_pin(struct ptp_clock *ptp, | ||
312 | enum ptp_pin_function func, unsigned int chan) | ||
313 | { | ||
314 | struct ptp_pin_desc *pin = NULL; | ||
315 | int i; | ||
316 | |||
317 | mutex_lock(&ptp->pincfg_mux); | ||
318 | for (i = 0; i < ptp->info->n_pins; i++) { | ||
319 | if (ptp->info->pin_config[i].func == func && | ||
320 | ptp->info->pin_config[i].chan == chan) { | ||
321 | pin = &ptp->info->pin_config[i]; | ||
322 | break; | ||
323 | } | ||
324 | } | ||
325 | mutex_unlock(&ptp->pincfg_mux); | ||
326 | |||
327 | return pin ? i : -1; | ||
328 | } | ||
329 | EXPORT_SYMBOL(ptp_find_pin); | ||
330 | |||
308 | /* module operations */ | 331 | /* module operations */ |
309 | 332 | ||
310 | static void __exit ptp_exit(void) | 333 | static void __exit ptp_exit(void) |
diff --git a/drivers/ptp/ptp_private.h b/drivers/ptp/ptp_private.h index df03f2e30ad9..b114a84c63c7 100644 --- a/drivers/ptp/ptp_private.h +++ b/drivers/ptp/ptp_private.h | |||
@@ -48,6 +48,7 @@ struct ptp_clock { | |||
48 | long dialed_frequency; /* remembers the frequency adjustment */ | 48 | long dialed_frequency; /* remembers the frequency adjustment */ |
49 | struct timestamp_event_queue tsevq; /* simple fifo for time stamps */ | 49 | struct timestamp_event_queue tsevq; /* simple fifo for time stamps */ |
50 | struct mutex tsevq_mux; /* one process at a time reading the fifo */ | 50 | struct mutex tsevq_mux; /* one process at a time reading the fifo */ |
51 | struct mutex pincfg_mux; /* protect concurrent info->pin_config access */ | ||
51 | wait_queue_head_t tsev_wq; | 52 | wait_queue_head_t tsev_wq; |
52 | int defunct; /* tells readers to go away when clock is being removed */ | 53 | int defunct; /* tells readers to go away when clock is being removed */ |
53 | }; | 54 | }; |
@@ -69,6 +70,10 @@ static inline int queue_cnt(struct timestamp_event_queue *q) | |||
69 | * see ptp_chardev.c | 70 | * see ptp_chardev.c |
70 | */ | 71 | */ |
71 | 72 | ||
73 | /* caller must hold pincfg_mux */ | ||
74 | int ptp_set_pinfunc(struct ptp_clock *ptp, unsigned int pin, | ||
75 | enum ptp_pin_function func, unsigned int chan); | ||
76 | |||
72 | long ptp_ioctl(struct posix_clock *pc, | 77 | long ptp_ioctl(struct posix_clock *pc, |
73 | unsigned int cmd, unsigned long arg); | 78 | unsigned int cmd, unsigned long arg); |
74 | 79 | ||
diff --git a/include/linux/ptp_clock_kernel.h b/include/linux/ptp_clock_kernel.h index 38a993508327..0d8ff3fb84ba 100644 --- a/include/linux/ptp_clock_kernel.h +++ b/include/linux/ptp_clock_kernel.h | |||
@@ -49,7 +49,11 @@ struct ptp_clock_request { | |||
49 | * @n_alarm: The number of programmable alarms. | 49 | * @n_alarm: The number of programmable alarms. |
50 | * @n_ext_ts: The number of external time stamp channels. | 50 | * @n_ext_ts: The number of external time stamp channels. |
51 | * @n_per_out: The number of programmable periodic signals. | 51 | * @n_per_out: The number of programmable periodic signals. |
52 | * @n_pins: The number of programmable pins. | ||
52 | * @pps: Indicates whether the clock supports a PPS callback. | 53 | * @pps: Indicates whether the clock supports a PPS callback. |
54 | * @pin_config: Array of length 'n_pins'. If the number of | ||
55 | * programmable pins is nonzero, then drivers must | ||
56 | * allocate and initialize this array. | ||
53 | * | 57 | * |
54 | * clock operations | 58 | * clock operations |
55 | * | 59 | * |
@@ -70,6 +74,18 @@ struct ptp_clock_request { | |||
70 | * parameter request: Desired resource to enable or disable. | 74 | * parameter request: Desired resource to enable or disable. |
71 | * parameter on: Caller passes one to enable or zero to disable. | 75 | * parameter on: Caller passes one to enable or zero to disable. |
72 | * | 76 | * |
77 | * @verify: Confirm that a pin can perform a given function. The PTP | ||
78 | * Hardware Clock subsystem maintains the 'pin_config' | ||
79 | * array on behalf of the drivers, but the PHC subsystem | ||
80 | * assumes that every pin can perform every function. This | ||
81 | * hook gives drivers a way of telling the core about | ||
82 | * limitations on specific pins. This function must return | ||
83 | * zero if the function can be assigned to this pin, and | ||
84 | * nonzero otherwise. | ||
85 | * parameter pin: index of the pin in question. | ||
86 | * parameter func: the desired function to use. | ||
87 | * parameter chan: the function channel index to use. | ||
88 | * | ||
73 | * Drivers should embed their ptp_clock_info within a private | 89 | * Drivers should embed their ptp_clock_info within a private |
74 | * structure, obtaining a reference to it using container_of(). | 90 | * structure, obtaining a reference to it using container_of(). |
75 | * | 91 | * |
@@ -83,13 +99,17 @@ struct ptp_clock_info { | |||
83 | int n_alarm; | 99 | int n_alarm; |
84 | int n_ext_ts; | 100 | int n_ext_ts; |
85 | int n_per_out; | 101 | int n_per_out; |
102 | int n_pins; | ||
86 | int pps; | 103 | int pps; |
104 | struct ptp_pin_desc *pin_config; | ||
87 | int (*adjfreq)(struct ptp_clock_info *ptp, s32 delta); | 105 | int (*adjfreq)(struct ptp_clock_info *ptp, s32 delta); |
88 | int (*adjtime)(struct ptp_clock_info *ptp, s64 delta); | 106 | int (*adjtime)(struct ptp_clock_info *ptp, s64 delta); |
89 | int (*gettime)(struct ptp_clock_info *ptp, struct timespec *ts); | 107 | int (*gettime)(struct ptp_clock_info *ptp, struct timespec *ts); |
90 | int (*settime)(struct ptp_clock_info *ptp, const struct timespec *ts); | 108 | int (*settime)(struct ptp_clock_info *ptp, const struct timespec *ts); |
91 | int (*enable)(struct ptp_clock_info *ptp, | 109 | int (*enable)(struct ptp_clock_info *ptp, |
92 | struct ptp_clock_request *request, int on); | 110 | struct ptp_clock_request *request, int on); |
111 | int (*verify)(struct ptp_clock_info *ptp, unsigned int pin, | ||
112 | enum ptp_pin_function func, unsigned int chan); | ||
93 | }; | 113 | }; |
94 | 114 | ||
95 | struct ptp_clock; | 115 | struct ptp_clock; |
@@ -156,4 +176,17 @@ extern void ptp_clock_event(struct ptp_clock *ptp, | |||
156 | 176 | ||
157 | extern int ptp_clock_index(struct ptp_clock *ptp); | 177 | extern int ptp_clock_index(struct ptp_clock *ptp); |
158 | 178 | ||
179 | /** | ||
180 | * ptp_find_pin() - obtain the pin index of a given auxiliary function | ||
181 | * | ||
182 | * @ptp: The clock obtained from ptp_clock_register(). | ||
183 | * @func: One of the ptp_pin_function enumerated values. | ||
184 | * @chan: The particular functional channel to find. | ||
185 | * Return: Pin index in the range of zero to ptp_clock_caps.n_pins - 1, | ||
186 | * or -1 if the auxiliary function cannot be found. | ||
187 | */ | ||
188 | |||
189 | int ptp_find_pin(struct ptp_clock *ptp, | ||
190 | enum ptp_pin_function func, unsigned int chan); | ||
191 | |||
159 | #endif | 192 | #endif |
diff --git a/include/uapi/linux/ptp_clock.h b/include/uapi/linux/ptp_clock.h index b65c834f83e9..f0b7bfe5da92 100644 --- a/include/uapi/linux/ptp_clock.h +++ b/include/uapi/linux/ptp_clock.h | |||
@@ -50,7 +50,8 @@ struct ptp_clock_caps { | |||
50 | int n_ext_ts; /* Number of external time stamp channels. */ | 50 | int n_ext_ts; /* Number of external time stamp channels. */ |
51 | int n_per_out; /* Number of programmable periodic signals. */ | 51 | int n_per_out; /* Number of programmable periodic signals. */ |
52 | int pps; /* Whether the clock supports a PPS callback. */ | 52 | int pps; /* Whether the clock supports a PPS callback. */ |
53 | int rsv[15]; /* Reserved for future use. */ | 53 | int n_pins; /* Number of input/output pins. */ |
54 | int rsv[14]; /* Reserved for future use. */ | ||
54 | }; | 55 | }; |
55 | 56 | ||
56 | struct ptp_extts_request { | 57 | struct ptp_extts_request { |
@@ -80,6 +81,40 @@ struct ptp_sys_offset { | |||
80 | struct ptp_clock_time ts[2 * PTP_MAX_SAMPLES + 1]; | 81 | struct ptp_clock_time ts[2 * PTP_MAX_SAMPLES + 1]; |
81 | }; | 82 | }; |
82 | 83 | ||
84 | enum ptp_pin_function { | ||
85 | PTP_PF_NONE, | ||
86 | PTP_PF_EXTTS, | ||
87 | PTP_PF_PEROUT, | ||
88 | PTP_PF_PHYSYNC, | ||
89 | }; | ||
90 | |||
91 | struct ptp_pin_desc { | ||
92 | /* | ||
93 | * Hardware specific human readable pin name. This field is | ||
94 | * set by the kernel during the PTP_PIN_GETFUNC ioctl and is | ||
95 | * ignored for the PTP_PIN_SETFUNC ioctl. | ||
96 | */ | ||
97 | char name[64]; | ||
98 | /* | ||
99 | * Pin index in the range of zero to ptp_clock_caps.n_pins - 1. | ||
100 | */ | ||
101 | unsigned int index; | ||
102 | /* | ||
103 | * Which of the PTP_PF_xxx functions to use on this pin. | ||
104 | */ | ||
105 | unsigned int func; | ||
106 | /* | ||
107 | * The specific channel to use for this function. | ||
108 | * This corresponds to the 'index' field of the | ||
109 | * PTP_EXTTS_REQUEST and PTP_PEROUT_REQUEST ioctls. | ||
110 | */ | ||
111 | unsigned int chan; | ||
112 | /* | ||
113 | * Reserved for future use. | ||
114 | */ | ||
115 | unsigned int rsv[5]; | ||
116 | }; | ||
117 | |||
83 | #define PTP_CLK_MAGIC '=' | 118 | #define PTP_CLK_MAGIC '=' |
84 | 119 | ||
85 | #define PTP_CLOCK_GETCAPS _IOR(PTP_CLK_MAGIC, 1, struct ptp_clock_caps) | 120 | #define PTP_CLOCK_GETCAPS _IOR(PTP_CLK_MAGIC, 1, struct ptp_clock_caps) |
@@ -87,6 +122,8 @@ struct ptp_sys_offset { | |||
87 | #define PTP_PEROUT_REQUEST _IOW(PTP_CLK_MAGIC, 3, struct ptp_perout_request) | 122 | #define PTP_PEROUT_REQUEST _IOW(PTP_CLK_MAGIC, 3, struct ptp_perout_request) |
88 | #define PTP_ENABLE_PPS _IOW(PTP_CLK_MAGIC, 4, int) | 123 | #define PTP_ENABLE_PPS _IOW(PTP_CLK_MAGIC, 4, int) |
89 | #define PTP_SYS_OFFSET _IOW(PTP_CLK_MAGIC, 5, struct ptp_sys_offset) | 124 | #define PTP_SYS_OFFSET _IOW(PTP_CLK_MAGIC, 5, struct ptp_sys_offset) |
125 | #define PTP_PIN_GETFUNC _IOWR(PTP_CLK_MAGIC, 6, struct ptp_pin_desc) | ||
126 | #define PTP_PIN_SETFUNC _IOW(PTP_CLK_MAGIC, 7, struct ptp_pin_desc) | ||
90 | 127 | ||
91 | struct ptp_extts_event { | 128 | struct ptp_extts_event { |
92 | struct ptp_clock_time t; /* Time event occured. */ | 129 | struct ptp_clock_time t; /* Time event occured. */ |