FreeBSD/Linux Kernel Cross Reference
sys/i386/isa/qcam.c
1 /*
2 * Connectix QuickCam parallel-port camera video capture driver.
3 * Copyright (c) 1996, Paul Traina.
4 *
5 * This driver is based in part on work
6 * Copyright (c) 1996, Thomas Davis.
7 *
8 * QuickCam(TM) is a registered trademark of Connectix Inc.
9 * Use this driver at your own risk, it is not warranted by
10 * Connectix or the authors.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer
17 * in this position and unchanged.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. The name of the author may not be used to endorse or promote products
22 * derived from this software withough specific prior written permission
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #include "qcam.h"
37 #if NQCAM > 0
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/conf.h>
43 #include <sys/ioctl.h>
44 #include <sys/uio.h>
45 #include <sys/malloc.h>
46 #include <sys/errno.h>
47 #ifdef DEVFS
48 #include <sys/devfsext.h>
49 #endif /* DEVFS */
50
51 #include <machine/clock.h>
52 #include <machine/qcam.h>
53
54 #include <i386/isa/qcamreg.h>
55 #include <i386/isa/qcamdefs.h>
56 #include <i386/isa/isa.h>
57 #include <i386/isa/isa_device.h>
58
59 /* working off of nostrategy is very ugly, but we need to determine if we're
60 running in a kernel that has eliminated the cdevsw table (yea!) */
61
62 #if defined(__FreeBSD__) && defined(nostrategy)
63
64 #define CDEV_MAJOR 73
65 #define STATIC_CDEVSW static
66
67 static d_open_t qcam_open;
68 static d_close_t qcam_close;
69 static d_read_t qcam_read;
70 static d_ioctl_t qcam_ioctl;
71
72 static struct cdevsw qcam_cdevsw =
73 { qcam_open, qcam_close, qcam_read, nowrite,
74 qcam_ioctl, nostop, nullreset, nodevtotty,
75 noselect, nommap, nostrategy, "qcam",
76 NULL, -1 };
77
78 static int qcam_probe(struct isa_device *devp);
79 static int qcam_attach(struct isa_device *devp);
80
81 struct isa_driver qcamdriver =
82 {qcam_probe, qcam_attach, "qcam"};
83
84 /*
85 * Initialize the dynamic cdevsw hooks.
86 */
87 static void
88 qcam_drvinit (void *unused)
89 {
90 static int qcam_devsw_installed = 0;
91 dev_t dev;
92
93 if (!qcam_devsw_installed) {
94 dev = makedev(CDEV_MAJOR, 0);
95 cdevsw_add(&dev,&qcam_cdevsw, NULL);
96 qcam_devsw_installed++;
97 }
98 }
99
100 SYSINIT(qcamdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR,qcam_drvinit,NULL)
101
102 #endif /* new FreeBSD configuration system */
103
104 #ifndef STATIC_CDEVSW
105 #define STATIC_CDEVSW
106 #endif
107
108 int qcam_debug = 0;
109
110 static struct qcam_softc qcam_softc[NQCAM];
111
112 #define QC_CONF_NODETECT 0x01 /* always assume camera is present */
113 #define QC_CONF_FORCEUNI 0x02 /* force unidirectional transfers */
114
115 #define UNIT(dev) minor(dev)
116
117 static int
118 qcam_probe (struct isa_device *devp)
119 {
120 switch (devp->id_iobase) { /* don't probe weird ports */
121 case IO_LPT1:
122 case IO_LPT2:
123 case IO_LPT3:
124 break;
125 default:
126 printf("qcam%d: ignoring non-standard port 0x%x\n",
127 devp->id_unit, devp->id_iobase);
128 return 0;
129 }
130
131 /*
132 * XXX The probe code is reported to be flakey.
133 * We need to work on this some more, so temporarily,
134 * allow bit one of the "flags" parameter to bypass this
135 * check.
136 */
137
138 if (!(devp->id_flags & QC_CONF_NODETECT))
139 if (!qcam_detect(devp->id_iobase))
140 return 0; /* failure */
141
142 return 1; /* found */
143 }
144
145 static int
146 qcam_attach (struct isa_device *devp)
147 {
148 struct qcam_softc *qs = &qcam_softc[devp->id_unit];
149
150 qs->iobase = devp->id_iobase;
151 qs->unit = devp->id_unit;
152 qs->flags |= QC_ALIVE;
153
154 /* force unidirectional parallel port mode? */
155 if (devp->id_flags & QC_CONF_FORCEUNI)
156 qs->flags |= QC_FORCEUNI;
157
158 qcam_reset(qs);
159
160 printf("qcam%d: %sdirectional parallel port\n",
161 qs->unit, qs->flags & QC_BIDIR_HW ? "bi" : "uni");
162
163 #ifdef DEVFS
164 qs->devfs_token =
165 devfs_add_devswf(&qcam_cdevsw, qs->unit, DV_CHR, 0, 0, 0600,
166 "qcam%d", qs->unit);
167 #endif
168 return 1;
169 }
170
171 STATIC_CDEVSW int
172 qcam_open (dev_t dev, int flags, int fmt, struct proc *p)
173 {
174 struct qcam_softc *qs = &qcam_softc[UNIT(dev)];
175
176 if (!(qs->flags & QC_ALIVE))
177 return ENXIO;
178
179 if (qs->flags & QC_OPEN)
180 return EBUSY;
181
182 qs->buffer_end = qs->buffer = malloc(QC_MAXFRAMEBUFSIZE, M_DEVBUF,
183 M_WAITOK);
184 if (!qs->buffer)
185 return ENOMEM;
186
187 qcam_reset(qs);
188 qcam_default(qs);
189 qs->init_req = 1; /* request initialization before scan */
190
191 qs->flags |= QC_OPEN;
192
193 return 0;
194 }
195
196 STATIC_CDEVSW int
197 qcam_close (dev_t dev, int flags, int fmt, struct proc *p)
198 {
199 struct qcam_softc *qs = &qcam_softc[UNIT(dev)];
200
201 if (qs->buffer) {
202 free(qs->buffer, M_DEVBUF);
203 qs->buffer = NULL;
204 qs->buffer_end = NULL;
205 }
206
207 qs->flags &= ~QC_OPEN;
208 return 0;
209 }
210
211 STATIC_CDEVSW int
212 qcam_read (dev_t dev, struct uio *uio, int ioflag)
213 {
214 struct qcam_softc *qs = &qcam_softc[UNIT(dev)];
215 int bytes, bufsize;
216 int error;
217
218 /* if we've seeked back to 0, that's our signal to scan */
219 if (uio->uio_offset == 0)
220 if (qcam_scan(qs))
221 return EIO;
222
223 bufsize = qs->buffer_end - qs->buffer;
224 if (uio->uio_offset > bufsize)
225 return EIO;
226
227 bytes = min(uio->uio_resid, (bufsize - uio->uio_offset));
228 error = uiomove(qs->buffer + uio->uio_offset, bytes, uio);
229 if (error)
230 return error;
231
232 return 0; /* success */
233 }
234
235 STATIC_CDEVSW int
236 qcam_ioctl (dev_t dev, int cmd, caddr_t data, int flag, struct proc *p)
237 {
238 struct qcam_softc *qs = &qcam_softc[UNIT(dev)];
239 struct qcam *info = (struct qcam *)data;
240
241 if (!data)
242 return(EINVAL);
243
244 switch (cmd) {
245 case QC_GET:
246 return qcam_ioctl_get(qs, info) ? EINVAL : 0;
247
248 case QC_SET:
249 return qcam_ioctl_set(qs, info) ? EINVAL : 0;
250
251 default:
252 return(ENOTTY);
253 }
254
255 return 0;
256 }
257
258 #ifdef QCAM_MODULE
259
260 #include <sys/exec.h>
261 #include <sys/sysent.h>
262 #include <sys/sysproto.h>
263 #include <sys/lkm.h>
264
265 static struct isa_device qcam_mod_dev =
266 {0, &qcamdriver, IO_LPT1, 0, -1, (caddr_t) 0, 0, 0, 0, 0, 0, 0, 0,
267 0, 1, 0, 0};
268
269 MOD_DEV(qcam, LM_DT_CHAR, CDEV_MAJOR, &qcam_cdevsw);
270
271 static int
272 qcam_load (struct lkm_table *lkmtp, int cmd)
273 {
274 if (qcam_probe(&qcam_mod_dev)) {
275 qcam_attach(&qcam_mod_dev);
276
277 qcam_drvinit(NULL); /* XXX this shouldn't NEED to be here
278 * the LKM code should be doing this
279 * for us! */
280
281 uprintf("qcam: driver loaded\n");
282 return 0;
283 } else {
284 uprintf("qcam: probe failed\n");
285 return 1;
286 }
287 }
288
289 static int
290 qcam_unload (struct lkm_table *lkmtp, int cmd)
291 {
292 struct qcam_softc *qs;
293 int i;
294
295 for (i = 0; i < NQCAM; i++) {
296 qs = &qcam_softc[i];
297 if (qs->flags & QC_OPEN) {
298 uprintf("qcam%d: cannot unload, device busy", qs->unit);
299 return 1;
300 }
301 }
302
303 uprintf("qcam: driver unloaded\n");
304 return 0;
305 }
306
307 static int
308 qcam_stat (struct lkm_table *lkmtp, int cmd)
309 {
310 return 0;
311 }
312
313 int
314 qcam_mod (struct lkm_table *lkmtp, int cmd, int ver)
315 {
316 DISPATCH(lkmtp, cmd, ver,
317 qcam_load, qcam_unload, qcam_stat);
318 }
319
320 #endif /* QCAM_MODULE */
321 #endif /* NQCAM */
Cache object: 1154849dfdc7a1c714b6b778c0b85b67
|