xref: /freebsd/sys/dev/fb/fbd.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
127cf7d04SAleksandr Rybalko /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
427cf7d04SAleksandr Rybalko  * Copyright (c) 2013 The FreeBSD Foundation
527cf7d04SAleksandr Rybalko  *
627cf7d04SAleksandr Rybalko  * This software was developed by Aleksandr Rybalko under sponsorship from the
727cf7d04SAleksandr Rybalko  * FreeBSD Foundation.
827cf7d04SAleksandr Rybalko  *
927cf7d04SAleksandr Rybalko  * Redistribution and use in source and binary forms, with or without
1027cf7d04SAleksandr Rybalko  * modification, are permitted provided that the following conditions
1127cf7d04SAleksandr Rybalko  * are met:
1227cf7d04SAleksandr Rybalko  * 1. Redistributions of source code must retain the above copyright
1327cf7d04SAleksandr Rybalko  *    notice, this list of conditions and the following disclaimer.
1427cf7d04SAleksandr Rybalko  * 2. Redistributions in binary form must reproduce the above copyright
1527cf7d04SAleksandr Rybalko  *    notice, this list of conditions and the following disclaimer in the
1627cf7d04SAleksandr Rybalko  *    documentation and/or other materials provided with the distribution.
1727cf7d04SAleksandr Rybalko  *
1827cf7d04SAleksandr Rybalko  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1927cf7d04SAleksandr Rybalko  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2027cf7d04SAleksandr Rybalko  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2127cf7d04SAleksandr Rybalko  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2227cf7d04SAleksandr Rybalko  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2327cf7d04SAleksandr Rybalko  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2427cf7d04SAleksandr Rybalko  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2527cf7d04SAleksandr Rybalko  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2627cf7d04SAleksandr Rybalko  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2727cf7d04SAleksandr Rybalko  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2827cf7d04SAleksandr Rybalko  * SUCH DAMAGE.
2927cf7d04SAleksandr Rybalko  */
3027cf7d04SAleksandr Rybalko 
3127cf7d04SAleksandr Rybalko /* Generic framebuffer */
3227cf7d04SAleksandr Rybalko /* TODO unlink from VT(9) */
3327cf7d04SAleksandr Rybalko /* TODO done normal /dev/fb methods */
3427cf7d04SAleksandr Rybalko 
3527cf7d04SAleksandr Rybalko #include <sys/param.h>
3627cf7d04SAleksandr Rybalko #include <sys/systm.h>
3727cf7d04SAleksandr Rybalko #include <sys/bus.h>
3827cf7d04SAleksandr Rybalko #include <sys/conf.h>
39e12be321SConrad Meyer #include <sys/eventhandler.h>
4027cf7d04SAleksandr Rybalko #include <sys/kernel.h>
4127cf7d04SAleksandr Rybalko #include <sys/malloc.h>
4227cf7d04SAleksandr Rybalko #include <sys/module.h>
4327cf7d04SAleksandr Rybalko #include <sys/queue.h>
4427cf7d04SAleksandr Rybalko #include <sys/fbio.h>
4527cf7d04SAleksandr Rybalko 
4627cf7d04SAleksandr Rybalko #include <machine/bus.h>
4727cf7d04SAleksandr Rybalko 
4827cf7d04SAleksandr Rybalko #include <dev/vt/vt.h>
4927cf7d04SAleksandr Rybalko #include <dev/vt/hw/fb/vt_fb.h>
5027cf7d04SAleksandr Rybalko 
51a985ae9bSHans Petter Selasky #include <vm/vm.h>
52a985ae9bSHans Petter Selasky #include <vm/pmap.h>
53a985ae9bSHans Petter Selasky 
5427cf7d04SAleksandr Rybalko #include "fb_if.h"
5527cf7d04SAleksandr Rybalko 
5627cf7d04SAleksandr Rybalko LIST_HEAD(fb_list_head_t, fb_list_entry) fb_list_head =
5727cf7d04SAleksandr Rybalko     LIST_HEAD_INITIALIZER(fb_list_head);
5827cf7d04SAleksandr Rybalko struct fb_list_entry {
5927cf7d04SAleksandr Rybalko 	struct fb_info	*fb_info;
6027cf7d04SAleksandr Rybalko 	struct cdev	*fb_si;
6127cf7d04SAleksandr Rybalko 	LIST_ENTRY(fb_list_entry) fb_list;
6227cf7d04SAleksandr Rybalko };
6327cf7d04SAleksandr Rybalko 
6427cf7d04SAleksandr Rybalko struct fbd_softc {
6527cf7d04SAleksandr Rybalko 	device_t	sc_dev;
6627cf7d04SAleksandr Rybalko 	struct fb_info	*sc_info;
6727cf7d04SAleksandr Rybalko };
6827cf7d04SAleksandr Rybalko 
6927cf7d04SAleksandr Rybalko static void fbd_evh_init(void *);
7027cf7d04SAleksandr Rybalko /* SI_ORDER_SECOND, just after EVENTHANDLERs initialized. */
7127cf7d04SAleksandr Rybalko SYSINIT(fbd_evh_init, SI_SUB_CONFIGURE, SI_ORDER_SECOND, fbd_evh_init, NULL);
7227cf7d04SAleksandr Rybalko 
7327cf7d04SAleksandr Rybalko static d_open_t		fb_open;
7427cf7d04SAleksandr Rybalko static d_close_t	fb_close;
7527cf7d04SAleksandr Rybalko static d_read_t		fb_read;
7627cf7d04SAleksandr Rybalko static d_write_t	fb_write;
7727cf7d04SAleksandr Rybalko static d_ioctl_t	fb_ioctl;
7827cf7d04SAleksandr Rybalko static d_mmap_t		fb_mmap;
7927cf7d04SAleksandr Rybalko 
8027cf7d04SAleksandr Rybalko static struct cdevsw fb_cdevsw = {
8127cf7d04SAleksandr Rybalko 	.d_version =	D_VERSION,
8227cf7d04SAleksandr Rybalko 	.d_flags =	D_NEEDGIANT,
8327cf7d04SAleksandr Rybalko 	.d_open =	fb_open,
8427cf7d04SAleksandr Rybalko 	.d_close =	fb_close,
8527cf7d04SAleksandr Rybalko 	.d_read =	fb_read,
8627cf7d04SAleksandr Rybalko 	.d_write =	fb_write,
8727cf7d04SAleksandr Rybalko 	.d_ioctl =	fb_ioctl,
8827cf7d04SAleksandr Rybalko 	.d_mmap =	fb_mmap,
8927cf7d04SAleksandr Rybalko 	.d_name =	"fb",
9027cf7d04SAleksandr Rybalko };
9127cf7d04SAleksandr Rybalko 
9227cf7d04SAleksandr Rybalko static int framebuffer_dev_unit = 0;
9327cf7d04SAleksandr Rybalko 
9427cf7d04SAleksandr Rybalko static int
fb_open(struct cdev * dev,int oflags,int devtype,struct thread * td)9527cf7d04SAleksandr Rybalko fb_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
9627cf7d04SAleksandr Rybalko {
9727cf7d04SAleksandr Rybalko 
9827cf7d04SAleksandr Rybalko 	return (0);
9927cf7d04SAleksandr Rybalko }
10027cf7d04SAleksandr Rybalko 
10127cf7d04SAleksandr Rybalko static int
fb_close(struct cdev * dev,int fflag,int devtype,struct thread * td)10227cf7d04SAleksandr Rybalko fb_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
10327cf7d04SAleksandr Rybalko {
10427cf7d04SAleksandr Rybalko 
10527cf7d04SAleksandr Rybalko 	return (0);
10627cf7d04SAleksandr Rybalko }
10727cf7d04SAleksandr Rybalko 
10827cf7d04SAleksandr Rybalko static int
fb_ioctl(struct cdev * dev,u_long cmd,caddr_t data,int fflag,struct thread * td)10927cf7d04SAleksandr Rybalko fb_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
11027cf7d04SAleksandr Rybalko     struct thread *td)
11127cf7d04SAleksandr Rybalko {
11227cf7d04SAleksandr Rybalko 	struct fb_info *info;
11327cf7d04SAleksandr Rybalko 	int error;
11427cf7d04SAleksandr Rybalko 
11527cf7d04SAleksandr Rybalko 	error = 0;
11627cf7d04SAleksandr Rybalko 	info = dev->si_drv1;
11727cf7d04SAleksandr Rybalko 
11827cf7d04SAleksandr Rybalko 	switch (cmd) {
11927cf7d04SAleksandr Rybalko 	case FBIOGTYPE:
12027cf7d04SAleksandr Rybalko 		bcopy(info, (struct fbtype *)data, sizeof(struct fbtype));
12127cf7d04SAleksandr Rybalko 		break;
12227cf7d04SAleksandr Rybalko 
12327cf7d04SAleksandr Rybalko 	case FBIO_GETWINORG:	/* get frame buffer window origin */
12427cf7d04SAleksandr Rybalko 		*(u_int *)data = 0;
12527cf7d04SAleksandr Rybalko 		break;
12627cf7d04SAleksandr Rybalko 
12727cf7d04SAleksandr Rybalko 	case FBIO_GETDISPSTART:	/* get display start address */
12827cf7d04SAleksandr Rybalko 		((video_display_start_t *)data)->x = 0;
12927cf7d04SAleksandr Rybalko 		((video_display_start_t *)data)->y = 0;
13027cf7d04SAleksandr Rybalko 		break;
13127cf7d04SAleksandr Rybalko 
13227cf7d04SAleksandr Rybalko 	case FBIO_GETLINEWIDTH:	/* get scan line width in bytes */
13327cf7d04SAleksandr Rybalko 		*(u_int *)data = info->fb_stride;
13427cf7d04SAleksandr Rybalko 		break;
13527cf7d04SAleksandr Rybalko 
13627cf7d04SAleksandr Rybalko 	case FBIO_BLANK:	/* blank display */
137b914a529SHans Petter Selasky 		if (info->setblankmode != NULL)
138b914a529SHans Petter Selasky 			error = info->setblankmode(info->fb_priv, *(int *)data);
13927cf7d04SAleksandr Rybalko 		break;
14027cf7d04SAleksandr Rybalko 
14127cf7d04SAleksandr Rybalko 	default:
14227cf7d04SAleksandr Rybalko 		error = ENOIOCTL;
14327cf7d04SAleksandr Rybalko 		break;
14427cf7d04SAleksandr Rybalko 	}
14527cf7d04SAleksandr Rybalko 	return (error);
14627cf7d04SAleksandr Rybalko }
14727cf7d04SAleksandr Rybalko 
14827cf7d04SAleksandr Rybalko static int
fb_read(struct cdev * dev,struct uio * uio,int ioflag)14927cf7d04SAleksandr Rybalko fb_read(struct cdev *dev, struct uio *uio, int ioflag)
15027cf7d04SAleksandr Rybalko {
15127cf7d04SAleksandr Rybalko 
15227cf7d04SAleksandr Rybalko 	return (0); /* XXX nothing to read, yet */
15327cf7d04SAleksandr Rybalko }
15427cf7d04SAleksandr Rybalko 
15527cf7d04SAleksandr Rybalko static int
fb_write(struct cdev * dev,struct uio * uio,int ioflag)15627cf7d04SAleksandr Rybalko fb_write(struct cdev *dev, struct uio *uio, int ioflag)
15727cf7d04SAleksandr Rybalko {
15827cf7d04SAleksandr Rybalko 
15927cf7d04SAleksandr Rybalko 	return (0); /* XXX nothing written */
16027cf7d04SAleksandr Rybalko }
16127cf7d04SAleksandr Rybalko 
16227cf7d04SAleksandr Rybalko static int
fb_mmap(struct cdev * dev,vm_ooffset_t offset,vm_paddr_t * paddr,int nprot,vm_memattr_t * memattr)16327cf7d04SAleksandr Rybalko fb_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, int nprot,
16427cf7d04SAleksandr Rybalko     vm_memattr_t *memattr)
16527cf7d04SAleksandr Rybalko {
16627cf7d04SAleksandr Rybalko 	struct fb_info *info;
16727cf7d04SAleksandr Rybalko 
16827cf7d04SAleksandr Rybalko 	info = dev->si_drv1;
1699ed297c8SNathan Whitehorn 
170a985ae9bSHans Petter Selasky 	if (info->fb_flags & FB_FLAG_NOMMAP)
1719ed297c8SNathan Whitehorn 		return (ENODEV);
1729ed297c8SNathan Whitehorn 
173f9cc8410SEric van Gyzen 	if (offset < info->fb_size) {
174a985ae9bSHans Petter Selasky 		if (info->fb_pbase == 0)
175a985ae9bSHans Petter Selasky 			*paddr = vtophys((uint8_t *)info->fb_vbase + offset);
176a985ae9bSHans Petter Selasky 		else
17727cf7d04SAleksandr Rybalko 			*paddr = info->fb_pbase + offset;
1782685a39aSOleksandr Tymoshenko 		if (info->fb_flags & FB_FLAG_MEMATTR)
1792685a39aSOleksandr Tymoshenko 			*memattr = info->fb_memattr;
18027cf7d04SAleksandr Rybalko 		return (0);
18127cf7d04SAleksandr Rybalko 	}
18227cf7d04SAleksandr Rybalko 	return (EINVAL);
18327cf7d04SAleksandr Rybalko }
18427cf7d04SAleksandr Rybalko 
18527cf7d04SAleksandr Rybalko static int
fb_init(struct fb_list_entry * entry,int unit)18627cf7d04SAleksandr Rybalko fb_init(struct fb_list_entry *entry, int unit)
18727cf7d04SAleksandr Rybalko {
18827cf7d04SAleksandr Rybalko 	struct fb_info *info;
18927cf7d04SAleksandr Rybalko 
19027cf7d04SAleksandr Rybalko 	info = entry->fb_info;
19127cf7d04SAleksandr Rybalko 	entry->fb_si = make_dev(&fb_cdevsw, unit, UID_ROOT, GID_WHEEL,
19227cf7d04SAleksandr Rybalko 	    0600, "fb%d", unit);
19327cf7d04SAleksandr Rybalko 	entry->fb_si->si_drv1 = info;
1947a1a32c4SAleksandr Rybalko 	info->fb_cdev = entry->fb_si;
19527cf7d04SAleksandr Rybalko 
19627cf7d04SAleksandr Rybalko 	return (0);
19727cf7d04SAleksandr Rybalko }
19827cf7d04SAleksandr Rybalko 
19927cf7d04SAleksandr Rybalko int
fbd_list(void)2009863e501SDimitry Andric fbd_list(void)
20127cf7d04SAleksandr Rybalko {
20227cf7d04SAleksandr Rybalko 	struct fb_list_entry *entry;
20327cf7d04SAleksandr Rybalko 
20427cf7d04SAleksandr Rybalko 	if (LIST_EMPTY(&fb_list_head))
20527cf7d04SAleksandr Rybalko 		return (ENOENT);
20627cf7d04SAleksandr Rybalko 
20727cf7d04SAleksandr Rybalko 	LIST_FOREACH(entry, &fb_list_head, fb_list) {
208a9fca3b9SJohn Baldwin 		printf("FB %s @%#jx\n", entry->fb_info->fb_name,
209a9fca3b9SJohn Baldwin 		    (uintmax_t)entry->fb_info->fb_pbase);
21027cf7d04SAleksandr Rybalko 	}
21127cf7d04SAleksandr Rybalko 
21227cf7d04SAleksandr Rybalko 	return (0);
21327cf7d04SAleksandr Rybalko }
21427cf7d04SAleksandr Rybalko 
21527cf7d04SAleksandr Rybalko static struct fb_list_entry *
fbd_find(struct fb_info * info)21627cf7d04SAleksandr Rybalko fbd_find(struct fb_info* info)
21727cf7d04SAleksandr Rybalko {
21827cf7d04SAleksandr Rybalko 	struct fb_list_entry *entry, *tmp;
21927cf7d04SAleksandr Rybalko 
22027cf7d04SAleksandr Rybalko 	LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) {
22127cf7d04SAleksandr Rybalko 		if (entry->fb_info == info) {
22227cf7d04SAleksandr Rybalko 			return (entry);
22327cf7d04SAleksandr Rybalko 		}
22427cf7d04SAleksandr Rybalko 	}
22527cf7d04SAleksandr Rybalko 
22627cf7d04SAleksandr Rybalko 	return (NULL);
22727cf7d04SAleksandr Rybalko }
22827cf7d04SAleksandr Rybalko 
22927cf7d04SAleksandr Rybalko int
fbd_register(struct fb_info * info)23027cf7d04SAleksandr Rybalko fbd_register(struct fb_info* info)
23127cf7d04SAleksandr Rybalko {
23227cf7d04SAleksandr Rybalko 	struct fb_list_entry *entry;
23327cf7d04SAleksandr Rybalko 	int err, first;
23427cf7d04SAleksandr Rybalko 
23527cf7d04SAleksandr Rybalko 	first = 0;
23627cf7d04SAleksandr Rybalko 	if (LIST_EMPTY(&fb_list_head))
23727cf7d04SAleksandr Rybalko 		first++;
23827cf7d04SAleksandr Rybalko 
23927cf7d04SAleksandr Rybalko 	entry = fbd_find(info);
24027cf7d04SAleksandr Rybalko 	if (entry != NULL) {
24127cf7d04SAleksandr Rybalko 		/* XXX Update framebuffer params */
24227cf7d04SAleksandr Rybalko 		return (0);
24327cf7d04SAleksandr Rybalko 	}
24427cf7d04SAleksandr Rybalko 
24527cf7d04SAleksandr Rybalko 	entry = malloc(sizeof(struct fb_list_entry), M_DEVBUF, M_WAITOK|M_ZERO);
24627cf7d04SAleksandr Rybalko 	entry->fb_info = info;
24727cf7d04SAleksandr Rybalko 
24827cf7d04SAleksandr Rybalko 	LIST_INSERT_HEAD(&fb_list_head, entry, fb_list);
24927cf7d04SAleksandr Rybalko 
25027cf7d04SAleksandr Rybalko 	err = fb_init(entry, framebuffer_dev_unit++);
25127cf7d04SAleksandr Rybalko 	if (err)
25227cf7d04SAleksandr Rybalko 		return (err);
25327cf7d04SAleksandr Rybalko 
2549ed297c8SNathan Whitehorn 	if (first) {
2552cf9e30bSJean-Sébastien Pédron 		err = vt_fb_attach(info);
2562cf9e30bSJean-Sébastien Pédron 		if (err)
2572cf9e30bSJean-Sébastien Pédron 			return (err);
2589ed297c8SNathan Whitehorn 	}
25927cf7d04SAleksandr Rybalko 
26027cf7d04SAleksandr Rybalko 	return (0);
26127cf7d04SAleksandr Rybalko }
26227cf7d04SAleksandr Rybalko 
26327cf7d04SAleksandr Rybalko int
fbd_unregister(struct fb_info * info)26427cf7d04SAleksandr Rybalko fbd_unregister(struct fb_info* info)
26527cf7d04SAleksandr Rybalko {
26627cf7d04SAleksandr Rybalko 	struct fb_list_entry *entry, *tmp;
26727cf7d04SAleksandr Rybalko 
26827cf7d04SAleksandr Rybalko 	LIST_FOREACH_SAFE(entry, &fb_list_head, fb_list, tmp) {
26927cf7d04SAleksandr Rybalko 		if (entry->fb_info == info) {
27027cf7d04SAleksandr Rybalko 			LIST_REMOVE(entry, fb_list);
27176e2f976SJean-Sébastien Pédron 			if (LIST_EMPTY(&fb_list_head))
27276e2f976SJean-Sébastien Pédron 				vt_fb_detach(info);
27327cf7d04SAleksandr Rybalko 			free(entry, M_DEVBUF);
27427cf7d04SAleksandr Rybalko 			return (0);
27527cf7d04SAleksandr Rybalko 		}
27627cf7d04SAleksandr Rybalko 	}
27727cf7d04SAleksandr Rybalko 
27827cf7d04SAleksandr Rybalko 	return (ENOENT);
27927cf7d04SAleksandr Rybalko }
28027cf7d04SAleksandr Rybalko 
28127cf7d04SAleksandr Rybalko static void
register_fb_wrap(void * arg,void * ptr)28227cf7d04SAleksandr Rybalko register_fb_wrap(void *arg, void *ptr)
28327cf7d04SAleksandr Rybalko {
28427cf7d04SAleksandr Rybalko 
28527cf7d04SAleksandr Rybalko 	fbd_register((struct fb_info *)ptr);
28627cf7d04SAleksandr Rybalko }
28727cf7d04SAleksandr Rybalko 
28827cf7d04SAleksandr Rybalko static void
unregister_fb_wrap(void * arg,void * ptr)28927cf7d04SAleksandr Rybalko unregister_fb_wrap(void *arg, void *ptr)
29027cf7d04SAleksandr Rybalko {
29127cf7d04SAleksandr Rybalko 
29227cf7d04SAleksandr Rybalko 	fbd_unregister((struct fb_info *)ptr);
29327cf7d04SAleksandr Rybalko }
29427cf7d04SAleksandr Rybalko 
29527cf7d04SAleksandr Rybalko static void
fbd_evh_init(void * ctx)29627cf7d04SAleksandr Rybalko fbd_evh_init(void *ctx)
29727cf7d04SAleksandr Rybalko {
29827cf7d04SAleksandr Rybalko 
29927cf7d04SAleksandr Rybalko 	EVENTHANDLER_REGISTER(register_framebuffer, register_fb_wrap, NULL,
30027cf7d04SAleksandr Rybalko 	    EVENTHANDLER_PRI_ANY);
30127cf7d04SAleksandr Rybalko 	EVENTHANDLER_REGISTER(unregister_framebuffer, unregister_fb_wrap, NULL,
30227cf7d04SAleksandr Rybalko 	    EVENTHANDLER_PRI_ANY);
30327cf7d04SAleksandr Rybalko }
30427cf7d04SAleksandr Rybalko 
30527cf7d04SAleksandr Rybalko /* Newbus methods. */
30627cf7d04SAleksandr Rybalko static int
fbd_probe(device_t dev)30727cf7d04SAleksandr Rybalko fbd_probe(device_t dev)
30827cf7d04SAleksandr Rybalko {
30927cf7d04SAleksandr Rybalko 
31027cf7d04SAleksandr Rybalko 	return (BUS_PROBE_NOWILDCARD);
31127cf7d04SAleksandr Rybalko }
31227cf7d04SAleksandr Rybalko 
31327cf7d04SAleksandr Rybalko static int
fbd_attach(device_t dev)31427cf7d04SAleksandr Rybalko fbd_attach(device_t dev)
31527cf7d04SAleksandr Rybalko {
31627cf7d04SAleksandr Rybalko 	struct fbd_softc *sc;
31727cf7d04SAleksandr Rybalko 	int err;
31827cf7d04SAleksandr Rybalko 
31927cf7d04SAleksandr Rybalko 	sc = device_get_softc(dev);
32027cf7d04SAleksandr Rybalko 
32127cf7d04SAleksandr Rybalko 	sc->sc_dev = dev;
32227cf7d04SAleksandr Rybalko 	sc->sc_info = FB_GETINFO(device_get_parent(dev));
32327cf7d04SAleksandr Rybalko 	if (sc->sc_info == NULL)
32427cf7d04SAleksandr Rybalko 		return (ENXIO);
32527cf7d04SAleksandr Rybalko 	err = fbd_register(sc->sc_info);
32627cf7d04SAleksandr Rybalko 
32727cf7d04SAleksandr Rybalko 	return (err);
32827cf7d04SAleksandr Rybalko }
32927cf7d04SAleksandr Rybalko 
33027cf7d04SAleksandr Rybalko static int
fbd_detach(device_t dev)33127cf7d04SAleksandr Rybalko fbd_detach(device_t dev)
33227cf7d04SAleksandr Rybalko {
33327cf7d04SAleksandr Rybalko 	struct fbd_softc *sc;
33427cf7d04SAleksandr Rybalko 	int err;
33527cf7d04SAleksandr Rybalko 
33627cf7d04SAleksandr Rybalko 	sc = device_get_softc(dev);
33727cf7d04SAleksandr Rybalko 
33827cf7d04SAleksandr Rybalko 	err = fbd_unregister(sc->sc_info);
33927cf7d04SAleksandr Rybalko 
34027cf7d04SAleksandr Rybalko 	return (err);
34127cf7d04SAleksandr Rybalko }
34227cf7d04SAleksandr Rybalko 
34327cf7d04SAleksandr Rybalko static device_method_t fbd_methods[] = {
34427cf7d04SAleksandr Rybalko 	/* Device interface */
34527cf7d04SAleksandr Rybalko 	DEVMETHOD(device_probe,		fbd_probe),
34627cf7d04SAleksandr Rybalko 	DEVMETHOD(device_attach,	fbd_attach),
34727cf7d04SAleksandr Rybalko 	DEVMETHOD(device_detach,	fbd_detach),
34827cf7d04SAleksandr Rybalko 
34927cf7d04SAleksandr Rybalko 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
35027cf7d04SAleksandr Rybalko 
35127cf7d04SAleksandr Rybalko 	{ 0, 0 }
35227cf7d04SAleksandr Rybalko };
35327cf7d04SAleksandr Rybalko 
35427cf7d04SAleksandr Rybalko driver_t fbd_driver = {
35527cf7d04SAleksandr Rybalko 	"fbd",
35627cf7d04SAleksandr Rybalko 	fbd_methods,
35727cf7d04SAleksandr Rybalko 	sizeof(struct fbd_softc)
35827cf7d04SAleksandr Rybalko };
35927cf7d04SAleksandr Rybalko 
3609360510bSJohn Baldwin DRIVER_MODULE(fbd, fb, fbd_driver, 0, 0);
3619360510bSJohn Baldwin DRIVER_MODULE(fbd, drmn, fbd_driver, 0, 0);
3629360510bSJohn Baldwin DRIVER_MODULE(fbd, udl, fbd_driver, 0, 0);
36327cf7d04SAleksandr Rybalko MODULE_VERSION(fbd, 1);
36427cf7d04SAleksandr Rybalko 
365