4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 #include <sys/types.h>
29 #include <sys/cmn_err.h>
33 #include <sys/modctl.h>
34 #include <sys/errno.h>
36 #include <sys/sunddi.h>
38 /* #define SBUSMEM_DEBUG */
41 #include <sys/ddi_impldefs.h>
43 int sbusmem_debug_flag
;
44 #define sbusmem_debug if (sbusmem_debug_flag) printf
45 #endif /* SBUSMEM_DEBUG */
47 static void *sbusmem_state_head
;
55 static int sbmem_open(dev_t
*, int, int, cred_t
*);
56 static int sbmem_close(dev_t
, int, int, struct cred
*);
57 static int sbmem_read(dev_t
, struct uio
*, cred_t
*);
58 static int sbmem_write(dev_t
, struct uio
*, cred_t
*);
59 static int sbmem_devmap(dev_t
, devmap_cookie_t
, offset_t
, size_t,
62 static struct cb_ops sbmem_cb_ops
= {
63 sbmem_open
, /* open */
64 sbmem_close
, /* close */
68 sbmem_read
, /* read */
69 sbmem_write
, /* write */
71 sbmem_devmap
, /* devmap */
73 ddi_devmap_segmap
, /* segmap */
75 ddi_prop_op
, /* cb_prop_op */
77 D_NEW
|D_MP
|D_DEVMAP
|D_HOTPLUG
, /* Driver compatibility flag */
79 nodev
, /* int (*cb_aread)() */
80 nodev
/* int (*cb_awrite)() */
83 static int sbmem_attach(dev_info_t
*, ddi_attach_cmd_t
);
84 static int sbmem_detach(dev_info_t
*, ddi_detach_cmd_t
);
85 static int sbmem_info(dev_info_t
*, ddi_info_cmd_t
, void *, void **);
87 static struct dev_ops sbmem_ops
= {
88 DEVO_REV
, /* devo_rev, */
90 sbmem_info
, /* get_dev_info */
91 nulldev
, /* identify */
93 sbmem_attach
, /* attach */
94 sbmem_detach
, /* detach */
96 &sbmem_cb_ops
, /* driver operations */
97 (struct bus_ops
*)0, /* bus operations */
99 ddi_quiesce_not_needed
, /* quiesce */
102 static struct modldrv modldrv
= {
103 &mod_driverops
, /* Type of module. This one is a driver */
104 "SBus memory driver", /* Name of module. */
105 &sbmem_ops
, /* driver ops */
108 static struct modlinkage modlinkage
= {
109 MODREV_1
, (void *)&modldrv
, NULL
112 static int sbmem_rw(dev_t
, struct uio
*, enum uio_rw
, cred_t
*);
115 static char sbusmem_initmsg
[] = "sbusmem _init: sbusmem.c\t1.28\t08/19/2008\n";
123 if ((error
= ddi_soft_state_init(&sbusmem_state_head
,
124 sizeof (struct sbusmem_unit
), 1)) != 0) {
127 if ((error
= mod_install(&modlinkage
)) != 0) {
128 ddi_soft_state_fini(&sbusmem_state_head
);
138 if ((error
= mod_remove(&modlinkage
)) == 0) {
139 ddi_soft_state_fini(&sbusmem_state_head
);
145 _info(struct modinfo
*modinfop
)
147 return (mod_info(&modlinkage
, modinfop
));
151 sbmem_attach(dev_info_t
*devi
, ddi_attach_cmd_t cmd
)
153 struct sbusmem_unit
*un
;
154 int error
= DDI_FAILURE
;
161 instance
= ddi_get_instance(devi
);
163 size
= ddi_getprop(DDI_DEV_T_NONE
, devi
,
164 DDI_PROP_DONTPASS
| DDI_PROP_CANSLEEP
, "size", -1);
165 if (size
== (uint_t
)-1) {
168 "sbmem_attach%d: No size property\n", instance
);
169 #endif /* SBUSMEM_DEBUG */
175 struct regspec
*rp
= ddi_rnumber_to_regspec(devi
, 0);
179 "sbmem_attach%d: No reg property\n", instance
);
182 "sbmem_attach%d: slot 0x%x size 0x%x\n", instance
,
183 rp
->regspec_bustype
, rp
->regspec_size
);
186 #endif /* SBUSMEM_DEBUG */
188 if (ddi_getlongprop(DDI_DEV_T_ANY
, devi
,
189 DDI_PROP_DONTPASS
| DDI_PROP_CANSLEEP
, "ident",
190 (caddr_t
)&ident
, &ilen
) != DDI_PROP_SUCCESS
) {
193 "sbmem_attach%d: No ident property\n", instance
);
194 #endif /* SBUSMEM_DEBUG */
198 if (ddi_soft_state_zalloc(sbusmem_state_head
,
199 instance
) != DDI_SUCCESS
)
202 if ((un
= ddi_get_soft_state(sbusmem_state_head
,
203 instance
)) == NULL
) {
204 ddi_soft_state_free(sbusmem_state_head
, instance
);
208 if (ddi_create_minor_node(devi
, ident
, S_IFCHR
, instance
,
209 DDI_PSEUDO
, NULL
) == DDI_FAILURE
) {
210 kmem_free(ident
, ilen
);
211 ddi_remove_minor_node(devi
, NULL
);
212 ddi_soft_state_free(sbusmem_state_head
, instance
);
215 kmem_free(ident
, ilen
);
218 un
->pagesize
= ddi_ptob(devi
, 1);
221 sbusmem_debug("sbmem_attach%d: dip 0x%p size 0x%x\n",
222 instance
, devi
, size
);
223 #endif /* SBUSMEM_DEBUG */
225 ddi_report_dev(devi
);
238 sbmem_detach(dev_info_t
*devi
, ddi_detach_cmd_t cmd
)
244 instance
= ddi_get_instance(devi
);
245 ddi_remove_minor_node(devi
, NULL
);
246 ddi_soft_state_free(sbusmem_state_head
, instance
);
247 return (DDI_SUCCESS
);
250 return (DDI_SUCCESS
);
252 return (DDI_FAILURE
);
257 sbmem_open(dev_t
*devp
, int flag
, int typ
, cred_t
*cred
)
264 instance
= getminor(*devp
);
265 if (ddi_get_soft_state(sbusmem_state_head
, instance
) == NULL
) {
273 sbmem_close(dev_t dev
, int flag
, int otyp
, struct cred
*cred
)
275 if (otyp
!= OTYP_CHR
)
282 sbmem_info(dev_info_t
*dip
, ddi_info_cmd_t infocmd
, void *arg
, void **result
)
284 int instance
, error
= DDI_FAILURE
;
285 struct sbusmem_unit
*un
;
287 #if defined(lint) || defined(__lint)
289 #endif /* lint || __lint */
292 case DDI_INFO_DEVT2DEVINFO
:
293 instance
= getminor((dev_t
)arg
);
294 if ((un
= ddi_get_soft_state(sbusmem_state_head
,
295 instance
)) != NULL
) {
296 *result
= (void *)un
->dip
;
300 "sbmem_info%d: returning dip 0x%p\n", instance
, un
->dip
);
301 #endif /* SBUSMEM_DEBUG */
306 case DDI_INFO_DEVT2INSTANCE
:
307 instance
= getminor((dev_t
)arg
);
308 *result
= (void *)(uintptr_t)instance
;
319 sbmem_read(dev_t dev
, struct uio
*uio
, cred_t
*cred
)
321 return (sbmem_rw(dev
, uio
, UIO_READ
, cred
));
325 sbmem_write(dev_t dev
, struct uio
*uio
, cred_t
*cred
)
327 return (sbmem_rw(dev
, uio
, UIO_WRITE
, cred
));
331 sbmem_rw(dev_t dev
, struct uio
*uio
, enum uio_rw rw
, cred_t
*cred
)
335 struct sbusmem_unit
*un
;
336 uint_t pagesize
, msize
;
337 int instance
, error
= 0;
341 #if defined(lint) || defined(__lint)
343 #endif /* lint || __lint */
345 instance
= getminor(dev
);
346 if ((un
= ddi_get_soft_state(sbusmem_state_head
, instance
)) == NULL
) {
350 pagesize
= un
->pagesize
;
352 while (uio
->uio_resid
> 0 && error
== 0) {
354 if (iov
->iov_len
== 0) {
357 if (uio
->uio_iovcnt
< 0)
358 cmn_err(CE_PANIC
, "sbmem_rw");
362 if (uio
->uio_offset
> un
->size
) {
366 if (uio
->uio_offset
== un
->size
) {
367 return (0); /* EOF */
369 msize
= pagesize
- (uio
->uio_offset
& (pagesize
- 1));
370 if (ddi_map_regs(dip
, 0, ®
, uio
->uio_offset
,
371 (off_t
)msize
) != DDI_SUCCESS
) {
374 c
= min(msize
, (uint_t
)iov
->iov_len
);
375 if (ddi_peekpokeio(dip
, uio
, rw
, reg
, (int)c
,
376 sizeof (int)) != DDI_SUCCESS
)
379 ddi_unmap_regs(dip
, 0, ®
, uio
->uio_offset
, (off_t
)msize
);
385 sbmem_devmap(dev_t dev
, devmap_cookie_t dhp
, offset_t off
, size_t len
,
386 size_t *maplen
, uint_t model
)
388 struct sbusmem_unit
*un
;
391 #if defined(lint) || defined(__lint)
393 #endif /* lint || __lint */
395 instance
= getminor(dev
);
396 if ((un
= ddi_get_soft_state(sbusmem_state_head
, instance
)) == NULL
) {
399 if (off
+ len
> un
->size
) {
402 if ((error
= devmap_devmem_setup(dhp
, un
->dip
, NULL
, 0,
403 off
, len
, PROT_ALL
, DEVMAP_DEFAULTS
, NULL
)) < 0) {
406 *maplen
= ptob(btopr(len
));