Annotation of wikisrc/users/mlelstv/disk-driver-template.mdwn, revision 1.12
1.1 mlelstv 1: **Contents**
2:
3: [[!toc levels=2]]
4:
5: # Disk driver template when using dksubr library
6:
7: ## Declaration
8:
9: <pre><code>
1.4 mlelstv 10: static dev_type_open(xxxopen);
11: static dev_type_close(xxxclose);
12: static dev_type_read(xxxread);
13: static dev_type_write(xxxwrite);
14: static dev_type_ioctl(xxxioctl);
15: static dev_type_strategy(xxxstrategy);
16: static dev_type_dump(xxxdump);
17: static dev_type_size(xxxsize);
18: static dev_type_discard(xxxdiscard);
19:
1.1 mlelstv 20: const struct bdevsw xxx_bdevsww= {
21: .d_open = xxxopen,
22: .d_close = xxxclose,
23: .d_strategy = xxxstrategy,
24: .d_ioctl = xxxioctl,
25: .d_dump = xxxdump,
26: .d_psize = xxxsize,
27: .d_discard = xxxdiscard,
1.10 mlelstv 28: .d_flag = D_DISK | D_MPSAFE
1.1 mlelstv 29: };
30:
31: const struct cdevsw xxx_cdevsw = {
32: .d_open = xxxopen,
33: .d_close = xxxclose,
34: .d_read = xxxread,
35: .d_write = xxxwrite,
36: .d_ioctl = xxxioctl,
37: .d_stop = nostop,
38: .d_tty = notty,
39: .d_poll = nopoll,
40: .d_mmap = nommap,
41: .d_kqfilter = nokqfilter,
42: .d_discard = xxxdiscard,
1.10 mlelstv 43: .d_flag = D_DISK | D_MPSAFE
1.1 mlelstv 44: };
45:
1.4 mlelstv 46: static void xxxminphys(struct buf *bp);
47: static int xxxdiskstart(device_t, struct buf *bp);
48: static void xxx_iosize(device_t, int *);
49: static int xxx_dumpblocks(device_t, void *, daddr_t, int);
50: static int xxx_lastclose(device_t);
51: static int xxx_discard(device_t, off_t, off_t);
52:
1.1 mlelstv 53: static const struct dkdriver xxxdkdriver = {
54: .d_open = xxxopen,
55: .d_close = xxxclose,
56: .d_strategy = xxxstrategy,
57: .d_minphys = xxxminphys,
58: .d_diskstart = xxx_diskstart,
1.9 mlelstv 59: .d_discard = xxx_discard,
1.12 ! mlelstv 60: .d_dumpblocks = xxx_dumpblocks, /* optional */
! 61: .d_iosize = xxx_iosize, /* optional */
! 62: .d_lastclose = xxx_lastclose, /* optional */
! 63: .d_firstopen = xxx_firstopen, /* optional */
! 64: .d_label = xxx_label, /* optional */
1.1 mlelstv 65: };
66:
1.4 mlelstv 67: static int xxx_match(device_t, cfdata_t, void *);
68: static void xxx_attach(device_t, device_t, void *);
69: static int xxx_detach(device_t, int);
1.11 mlelstv 70: static int xxx_activate(device_t, enum devact);
1.4 mlelstv 71:
1.7 mlelstv 72: struct xxx_softc {
73: struct dk_softc sc_dksc; /* generic disk interface */
74: // private data
75: };
76:
1.4 mlelstv 77: CFATTACH_DECL3_NEW(xxx, sizeof(struct xxx_softc),
78: xxx_match, xxx_attach, xxx_detach, NULL, NULL, NULL, DVF_DETACH_SHUTDOWN);
79: extern struct cfdriver xxx_cd;
1.1 mlelstv 80: extern struct cfdriver xxx_cd;
81:
1.5 mlelstv 82: #ifdef PSEUDODEVICE
1.7 mlelstv 83: static void xxxattach(int);
84: static device_t xxx_create(int);
85: static int xxx_destroy(device_t);
1.5 mlelstv 86: #endif
87:
88: static int xxx_init(device_t);
89: static int xxx_finish(device_t);
90:
1.4 mlelstv 91: static int xxxdone(struct buf *);
1.1 mlelstv 92:
93:
94: #define DEVPROLOG \
95: struct xxx_softc *sc; \
96: struct dk_softc *dksc; \
97: int unit; \
98: \
99: unit = DISKUNIT(dev); \
100: if ((sc = device_lookup_private(&xxx_cd, unit)) == NULL) \
101: return ENXIO; \
102: dksc = &sc->sc_dksc
103: </code></pre>
104:
105: ----
106:
1.5 mlelstv 107: ## Pseudo-Device Attachment and Standard driver interface
1.1 mlelstv 108:
109: <pre><code>
1.5 mlelstv 110: #ifdef PSEUDODEVICE
1.1 mlelstv 111: void
1.5 mlelstv 112: xxxattach(int num)
1.1 mlelstv 113: {
1.7 mlelstv 114: #ifndef _MODULE
1.5 mlelstv 115: int error;
1.1 mlelstv 116:
1.5 mlelstv 117: error = config_cfattach_attach(xxx_cd.cd_name, &xxx_ca);
118: if (error) {
119: aprint_error("%s: unable to register cfattach %d\n",
120: xxx_cd.cd_name, error);
121: return;
122: }
1.1 mlelstv 123:
1.5 mlelstv 124: // some global initialization
1.7 mlelstv 125: #endif
126: }
127:
128: static device_t
129: xxx_create(int unit)
130: {
131: cfdata_t cf;
132: device_t dv;
133:
134: cf = malloc(sizeof(*cf), M_DEVBUF, M_WAITOK);
135: cf->cf_name = xxx_cd.cd_name;
136: cf->cf_atname = xxx_cd.cd_name;
137: cf->cf_unit = unit;
138: cf->cf_fstate = FSTATE_STAR;
139:
140: dv = config_attach_pseudo(cf);
141: if (dv == NULL) {
142: aprint_error("%s: failed to attach pseudo device\n",
143: xxx_cd.cd_name);
144: free(cf, M_DEVBUF);
145: }
146:
147: return dv;
148: }
149:
150: static int
151: xxx_destroy(device_t dv)
152: {
153: int error;
154: cfdata_t cf;
155:
156: cf = device_cfdata(dv);
157: error = config_detach(dev, DETACH_QUIET);
158: if (error)
159: return error;
160: free(cf, M_DEVBUF);
161: return 0;
1.1 mlelstv 162: }
1.5 mlelstv 163: #endif
1.1 mlelstv 164:
165: static int
166: xxxopen(dev_t dev, int flags, int fmt, struct lwp *l)
167: {
168: DEVPROLOG;
169:
170: return dk_open(dksc, dev, flags, fmt, l);
171: }
172:
173: static int
174: xxxclose(dev_t dev, int flags, int fmt, struct lwp *l)
175: {
176: DEVPROLOG;
177:
178: return dk_close(dksc, dev, flags, fmt, l);
179: }
180:
181: static int
182: xxxread(dev_t dev, struct uio *uio, int ioflag)
183: {
184:
185: return physio(xxxstrategy, NULL, dev, B_READ, xxxminphys, uio);
186: }
187:
188: static int
189: xxxwrite(dev_t dev, struct uio *uio, int ioflag)
190: {
191:
192: return physio(xxxstrategy, NULL, dev, B_WRITE, xxxminphys, uio);
193: }
194:
195: static int
196: xxxioctl(dev_t dev, u_long cmd, void *addr, int32_t flag, struct lwp *l)
197: {
198: int error;
199: DEVPROLOG;
200:
201: error = dk_ioctl(dksc, dev, cmd, addr, flag, l);
202: if (error != EPASSTHROUGH)
203: return error;
204:
205: error = 0;
206:
207: switch (cmd) {
208: // private IOCTLs
209: default:
210: error = ENOTTY;
211: }
212:
213: return error;
214: }
215:
216: static void
217: xxxstrategy(struct buf *bp)
218: {
219: DEVPROLOG;
220:
221: dk_strategy(dksc, bp);
222: }
223:
224: static int
225: xxxdiscard(dev_t dev, off_t pos, off_t len)
226: {
227: DEVPROLOG;
228:
229: return dk_discard(dksc, dev, pos, len);
230: }
231:
232: static int
233: xxxsize(dev_t dev)
234: {
235: DEVPROLOG;
236:
237: return dk_size(dksc, dev);
238: }
239:
240: static int
241: xxxdump(dev_t dev, daddr_t blkno, void *va, size_t size)
242: {
243: DEVPROLOG;
244:
245: return dk_dump(dksc, dev, blkno, va, size);
246: }
247:
248: static void
249: xxxminphys(struct buf *bp)
250: {
251: struct xxx_softc *sc;
252: int unit;
253:
254: unit = DISKUNIT(bp->b_dev);
255: if ((sc = device_lookup_private(&xxx_cd, unit)) == NULL)
256: return;
257:
258: xxx_iosize(sc->sc_dv, &bp->b_count);
259: minphys(bp);
260: }
261: </code></pre>
262:
263: ----
264:
265: ## I/O callback
266:
267: <pre><code>
268: static void
269: xxxdone(struct xxx_softc *sc, struct buf *bp)
270: {
271: struct dk_softc *dksc = &sc->sc_dksc;
272:
273: dk_done(dksc, bp);
274: dk_start(dksc, NULL);
275: }
1.2 mlelstv 276: </code></pre>
1.1 mlelstv 277:
278: ----
279:
1.5 mlelstv 280: ## Startup and Shutdown
281:
282: <pre><code>
283: static int
284: xxx_init(device_t self)
285: {
286: struct xxx_softc *sc = device_private(self);
287: struct dk_softc *dksc = &sc->sc_dk;
288:
289: dk_init(dksc, self, DKTYPE_xxx);
290: disk_init(&dksc->sc_dkdev, dksc->sc_xname, &xxdkdriver);
291:
292: dk_attach(dksc);
293: disk_attach(&dksc->sc_dkdev);
294: // initialize dksc->sc_dkdev.dk_geom
295:
296: bufq_alloc(&dksc->sc_bufq, BUFQ_DISK_DEFAULT_STRAT, BUFQ_SORT_RAWBLOCK);
297:
298: // possibly deferred with config_interrupts()
299: dkwedge_discover(&dksc->sc_dkdev);
300:
301: return 0;
302: }
303:
304: static int
305: xxx_finish(device_t self)
306: {
307: struct xxx_softc *sc = device_private(self);
308: struct dk_softc *dksc = &sc->sc_dksc;
309:
310: dkwedge_delall(&dksc->sc_dkdev);
311:
312: dk_drain(dksc);
313: bufq_free(dksc->sc_bufq);
314:
315: dk_detach(dksc);
316: disk_detach(&dksc->sc_dkdev);
317: disk_destroy(&dksc->sc_dkdev);
318:
319: return 0;
320: }
321: </code></pre>
322:
323: ----
324:
1.4 mlelstv 325: ## Autoconf interface
326:
327: <pre><code>
328: static int
329: xxx_match(device_t self, cfdata_t cfdata, void *aux)
330: {
331: return 1;
332: }
333:
334: static void
335: xxx_attach(device_t parent, device_t self, void *aux)
336: {
1.5 mlelstv 337: #ifndef _MODULE
338: xxx_init(self);
339: #endif
1.4 mlelstv 340: }
341:
342: static void
343: xxx_detach(device_t self, int flags)
344: {
1.5 mlelstv 345: #ifndef _MODULE
346: xxx_finish(self);
347: #endif
348: }
1.11 mlelstv 349:
350: static int
351: xxx_activate(device_t self, enum devact act)
352: {
353: // switch (act) {
354: // case DVACT_ACTIVATE:
355: // return 0;
356: // case DVACT_DEACTIVATE:
357: // return 0;
358: // }
359:
360: return EOPNOTSUPP;
361: }
1.5 mlelstv 362: </code></pre>
363:
364: ----
365:
366: ## Kernel module interface
367:
368: <pre><code>
369: MODULE(MODULE_CLASS_DRIVER, xxx, "dk_subr");
1.4 mlelstv 370:
1.5 mlelstv 371: static int
372: xxx_modcmd(modcmd_t cmd, void *data)
373: {
374: int error;
375: #ifdef _MODULE
376: int bmajor, cmajor;
377: #endif
1.4 mlelstv 378:
1.5 mlelstv 379: error = 0;
380: switch (cmd) {
381: case MODULE_CMD_INIT:
382: #ifdef _MODULE
383: bmajor = cmajor = -1;
384: error = devsw_attach("xxx", &xxx_bdevsw, &bmajor,
385: &xxx_cdevsw, &cmajor);
386: if (error) {
387: aprint_error("%s: devsw_attach failed %d\n",
388: xxx_cd.cd_name, error);
389: break;
390: }
391: error = config_cfdriver_attach(&xxx_cd);
392: if (error) {
393: aprint_error("%s: config_cfdriver_attach failed %d\n",
394: xxx_cd.cd_name, error);
395: devsw_detach(&xxx_bdevsw, &xxx_cdevsw);
396: break;
397: }
398: error = config_cfattach_attach(&xxx_cd);
399: if (error) {
400: aprint_error("%s: config_cfattach_attach failed %d\n",
401: xxx_cd.cd_name, error);
402: config_cfdriver_detach(&xxx_cd);
403: devsw_detach(&xxx_bdevsw, &xxx_cdevsw);
404: break;
405: }
406: // some global initialization
407:
1.6 mlelstv 408: #ifdef PSEUDODEVICE
409: xxxattach(0);
1.5 mlelstv 410: #endif
411: break;
412: case MODULE_CMD_FINI:
1.6 mlelstv 413: // outside of #ifdef _MODULE to allow removal of builtins
1.5 mlelstv 414: // some global finalization
415: #ifdef _MODULE
416: error = config_cfattach_detach(&xxx_cd.cd_name, &xxx_ca);
417: if (error)
418: break;
419: config_cfdriver_detach(&xxx_cd);
420: devsw_detach(&xxx_bdevsw, &xxx_cdevsw);
421: #endif
422: break;
423: case MODULE_CMD_STAT:
424: error = ENOTTY;
425: break;
426: default:
427: error = ENOTTY;
428: break;
429: }
1.4 mlelstv 430:
1.5 mlelstv 431: return error;
1.4 mlelstv 432: }
433: </code></pre>
434:
435: ----
436:
437: ## DK driver interface
1.1 mlelstv 438:
1.2 mlelstv 439: <pre><code>
1.1 mlelstv 440: static int
1.8 mlelstv 441: xxx_firstopen(device_t dv)
442: {
443: // private startup
444:
445: return 0;
446: }
447:
448: static int
1.1 mlelstv 449: xxx_lastclose(device_t dv)
450: {
451: // private cleanup
452:
453: return 0;
454: }
455:
456: static int
457: xxx_diskstart(device_t dv, struct buf *bp)
458: {
459: // issue I/O for bp
460: // return EAGAIN if controller busy
461: }
462:
463: static int
464: xxx_dumpblocks(device_t dv, void *va, daddr_t blkno, int nblk)
465: {
466: // issue polling I/O to dump a page
1.12 ! mlelstv 467: // return error
1.1 mlelstv 468: }
469:
470: static void
471: xxx_iosize(device_t dv, int *countp)
472: {
473: // limit *countp as necessary
474: }
475:
476: static int
477: xxx_discard(device_t dv, off_t pos, off_t len)
478: {
479: // issue request to discard bytes
1.12 ! mlelstv 480: // return error
1.1 mlelstv 481: }
1.12 ! mlelstv 482:
! 483: static void
! 484: xxx_label(device_t dv, struct disklabel *lp)
! 485: {
! 486: // lp is initialized for generic disk
! 487: // augment with driver specific information
! 488: }
! 489:
1.2 mlelstv 490: </code></pre>
1.1 mlelstv 491:
492: ----
493:
494: ## Alternative when using a separate I/O thread
495:
1.2 mlelstv 496: <pre><code>
1.1 mlelstv 497: static void
498: xxxstrategy(struct buf *bp)
499: {
500: DEVPROLOG;
501:
502: if (dk_strategy_defer(dksc, bp))
503: return;
504:
505: // wake up I/O thread
506: }
507:
508: static void
509: xxxdone(struct xxx_softc *sc, struct buf *bp)
510: {
511: struct dk_softc *dksc = &sc->sc_dksc;
512:
513: dk_done(dksc, bp);
514: // wake up I/O thread
515: }
516:
517: static void
1.10 mlelstv 518: xxx_iothread(struct dk_softc *dksc)
1.1 mlelstv 519: {
520: while (!shutting_down) {
1.3 mlelstv 521: if (dk_strategy_pending(dksc))
1.1 mlelstv 522: dk_start(dksc, NULL);
523: // sleep
524: }
525: }
526: </code></pre>
527:
528: ----
CVSweb for NetBSD wikisrc <wikimaster@NetBSD.org> software: FreeBSD-CVSweb