]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ppbus/pps.c
This commit was generated by cvs2svn to compensate for changes in r49795,
[FreeBSD/FreeBSD.git] / sys / dev / ppbus / pps.c
1 /*
2  * ----------------------------------------------------------------------------
3  * "THE BEER-WARE LICENSE" (Revision 42):
4  * <phk@FreeBSD.org> wrote this file.  As long as you retain this notice you
5  * can do whatever you want with this stuff. If we meet some day, and you think
6  * this stuff is worth it, you can buy me a beer in return.   Poul-Henning Kamp
7  * ----------------------------------------------------------------------------
8  *
9  * $Id: pps.c,v 1.19 1999/05/31 11:25:00 phk Exp $
10  *
11  * This driver implements a draft-mogul-pps-api-02.txt PPS source.
12  *
13  * The input pin is pin#10 
14  * The echo output pin is pin#14
15  *
16  */
17
18 #include <sys/param.h>
19 #include <sys/kernel.h>
20 #include <sys/systm.h>
21 #include <sys/conf.h>
22 #include <sys/timepps.h>
23 #include <sys/malloc.h>
24
25 #include <dev/ppbus/ppbconf.h>
26 #include "pps.h"
27
28 #define PPS_NAME        "pps"           /* our official name */
29
30 struct pps_data {
31         int     pps_open;
32         struct  ppb_device pps_dev;     
33         struct  pps_state pps;
34 };
35
36 static int npps;
37
38 /*
39  * Make ourselves visible as a ppbus driver
40  */
41
42 static struct ppb_device        *ppsprobe(struct ppb_data *ppb);
43 static int                      ppsattach(struct ppb_device *dev);
44 static void                     ppsintr(struct ppb_device *ppd);
45
46 static struct ppb_driver ppsdriver = {
47     ppsprobe, ppsattach, PPS_NAME
48 };
49
50 DATA_SET(ppbdriver_set, ppsdriver);
51
52 static  d_open_t        ppsopen;
53 static  d_close_t       ppsclose;
54 static  d_ioctl_t       ppsioctl;
55
56 #define CDEV_MAJOR 89
57 static struct cdevsw pps_cdevsw = {
58         /* open */      ppsopen,
59         /* close */     ppsclose,
60         /* read */      noread,
61         /* write */     nowrite,
62         /* ioctl */     ppsioctl,
63         /* stop */      nostop,
64         /* reset */     noreset,
65         /* devtotty */  nodevtotty,
66         /* poll */      nopoll,
67         /* mmap */      nommap,
68         /* strategy */  nostrategy,
69         /* name */      PPS_NAME,
70         /* parms */     noparms,
71         /* maj */       CDEV_MAJOR,
72         /* dump */      nodump,
73         /* psize */     nopsize,
74         /* flags */     0,
75         /* maxio */     0,
76         /* bmaj */      -1
77 };
78
79
80 static struct ppb_device *
81 ppsprobe(struct ppb_data *ppb)
82 {
83         struct pps_data *sc;
84         static int once;
85         dev_t dev;
86
87         if (!once++)
88                 cdevsw_add(&pps_cdevsw);
89
90         sc = (struct pps_data *) malloc(sizeof(struct pps_data),
91                                                         M_TEMP, M_NOWAIT);
92         if (!sc) {
93                 printf(PPS_NAME ": cannot malloc!\n");
94                 return (0);
95         }
96         bzero(sc, sizeof(struct pps_data));
97
98         dev = make_dev(&pps_cdevsw, npps,
99             UID_ROOT, GID_WHEEL, 0644, PPS_NAME "%d", npps);
100
101         dev->si_drv1 = sc;
102
103         sc->pps_dev.id_unit = npps++;
104         sc->pps_dev.ppb = ppb;
105         sc->pps_dev.name = ppsdriver.name;
106         sc->pps_dev.bintr = ppsintr;
107         sc->pps_dev.drv1 = sc;
108
109         sc->pps.ppscap = PPS_CAPTUREASSERT | PPS_ECHOASSERT;
110         pps_init(&sc->pps);
111         return (&sc->pps_dev);
112 }
113
114 static int
115 ppsattach(struct ppb_device *dev)
116 {
117
118         /*
119          * Report ourselves
120          */
121         printf(PPS_NAME "%d: <Pulse per second Timing Interface> on ppbus %d\n",
122                dev->id_unit, dev->ppb->ppb_link->adapter_unit);
123
124         return (1);
125 }
126
127 static  int
128 ppsopen(dev_t dev, int flags, int fmt, struct proc *p)
129 {
130         struct pps_data *sc;
131         u_int unit = minor(dev);
132
133         if ((unit >= npps))
134                 return (ENXIO);
135
136         sc = dev->si_drv1;
137
138         if (!sc->pps_open) {
139                 if (ppb_request_bus(&sc->pps_dev, PPB_WAIT|PPB_INTR))
140                         return (EINTR);
141
142                 ppb_wctr(&sc->pps_dev, 0);
143                 ppb_wctr(&sc->pps_dev, IRQENABLE);
144                 sc->pps_open = 1;
145         }
146
147         return(0);
148 }
149
150 static  int
151 ppsclose(dev_t dev, int flags, int fmt, struct proc *p)
152 {
153         struct pps_data *sc = dev->si_drv1;
154
155         sc->pps.ppsparam.mode = 0;      /* PHK ??? */
156
157         ppb_wdtr(&sc->pps_dev, 0);
158         ppb_wctr(&sc->pps_dev, 0);
159
160         ppb_release_bus(&sc->pps_dev);
161         sc->pps_open = 0;
162         return(0);
163 }
164
165 static void
166 ppsintr(struct ppb_device *ppd)
167 {
168         struct pps_data *sc = ppd->drv1;
169         struct timecounter *tc;
170         unsigned count;
171
172         tc = timecounter;
173         count = timecounter->tc_get_timecount(tc);
174         if (!(ppb_rstr(&sc->pps_dev) & nACK))
175                 return;
176         if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) 
177                 ppb_wctr(&sc->pps_dev, IRQENABLE | AUTOFEED);
178         pps_event(&sc->pps, tc, count, PPS_CAPTUREASSERT);
179         if (sc->pps.ppsparam.mode & PPS_ECHOASSERT) 
180                 ppb_wctr(&sc->pps_dev, IRQENABLE);
181 }
182
183 static int
184 ppsioctl(dev_t dev, u_long cmd, caddr_t data, int flags, struct proc *p)
185 {
186         struct pps_data *sc = dev->si_drv1;
187
188         return (pps_ioctl(cmd, data, &sc->pps));
189 }
190