ssize_t ptp_read(struct posix_clock *pc, uint rdflags, char __user *buf, size_t cnt) { struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); struct timestamp_event_queue *queue = &ptp->tsevq; struct ptp_extts_event event[PTP_BUF_TIMESTAMPS]; unsigned long flags; size_t qcnt, i; if (cnt % sizeof(struct ptp_extts_event) != 0) return -EINVAL; if (cnt > sizeof(event)) cnt = sizeof(event); cnt = cnt / sizeof(struct ptp_extts_event); if (mutex_lock_interruptible(&ptp->tsevq_mux)) return -ERESTARTSYS; if (wait_event_interruptible(ptp->tsev_wq, queue_cnt(queue))) { mutex_unlock(&ptp->tsevq_mux); return -ERESTARTSYS; } spin_lock_irqsave(&queue->lock, flags); qcnt = queue_cnt(queue); if (cnt > qcnt) cnt = qcnt; for (i = 0; i < cnt; i++) { event[i] = queue->buf[queue->head]; queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS; } spin_unlock_irqrestore(&queue->lock, flags); cnt = cnt * sizeof(struct ptp_extts_event); mutex_unlock(&ptp->tsevq_mux); if (copy_to_user(buf, event, cnt)) { mutex_unlock(&ptp->tsevq_mux); return -EFAULT; } return cnt; }
static ssize_t extts_fifo_show(struct device *dev, struct device_attribute *attr, char *page) { struct ptp_clock *ptp = dev_get_drvdata(dev); struct timestamp_event_queue *queue = &ptp->tsevq; struct ptp_extts_event event; unsigned long flags; size_t qcnt; int cnt = 0; memset(&event, 0, sizeof(event)); if (mutex_lock_interruptible(&ptp->tsevq_mux)) return -ERESTARTSYS; spin_lock_irqsave(&queue->lock, flags); qcnt = queue_cnt(queue); if (qcnt) { event = queue->buf[queue->head]; queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS; } spin_unlock_irqrestore(&queue->lock, flags); if (!qcnt) goto out; cnt = snprintf(page, PAGE_SIZE, "%u %lld %u\n", event.index, event.t.sec, event.t.nsec); out: mutex_unlock(&ptp->tsevq_mux); return cnt; }
__poll_t ptp_poll(struct posix_clock *pc, struct file *fp, poll_table *wait) { struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); poll_wait(fp, &ptp->tsev_wq, wait); return queue_cnt(&ptp->tsevq) ? EPOLLIN : 0; }
ssize_t ptp_read(struct posix_clock *pc, uint rdflags, char __user *buf, size_t cnt) { struct ptp_clock *ptp = container_of(pc, struct ptp_clock, clock); struct timestamp_event_queue *queue = &ptp->tsevq; struct ptp_extts_event *event; unsigned long flags; size_t qcnt, i; int result; if (cnt % sizeof(struct ptp_extts_event) != 0) return -EINVAL; if (cnt > EXTTS_BUFSIZE) cnt = EXTTS_BUFSIZE; cnt = cnt / sizeof(struct ptp_extts_event); if (mutex_lock_interruptible(&ptp->tsevq_mux)) return -ERESTARTSYS; if (wait_event_interruptible(ptp->tsev_wq, ptp->defunct || queue_cnt(queue))) { mutex_unlock(&ptp->tsevq_mux); return -ERESTARTSYS; } if (ptp->defunct) { mutex_unlock(&ptp->tsevq_mux); return -ENODEV; } event = kmalloc(EXTTS_BUFSIZE, GFP_KERNEL); if (!event) { mutex_unlock(&ptp->tsevq_mux); return -ENOMEM; } spin_lock_irqsave(&queue->lock, flags); qcnt = queue_cnt(queue); if (cnt > qcnt) cnt = qcnt; for (i = 0; i < cnt; i++) { event[i] = queue->buf[queue->head]; queue->head = (queue->head + 1) % PTP_MAX_TIMESTAMPS; } spin_unlock_irqrestore(&queue->lock, flags); cnt = cnt * sizeof(struct ptp_extts_event); mutex_unlock(&ptp->tsevq_mux); result = cnt; if (copy_to_user(buf, event, cnt)) result = -EFAULT; kfree(event); return result; }
static inline int queue_free(struct timestamp_event_queue *q) { return PTP_MAX_TIMESTAMPS - queue_cnt(q) - 1; }