sda_nexus.c revision f2b90c3c415ff04d4adb3a54242822b41d74bfd9
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* SD card nexus support.
*
* NB that this file contains a fair bit of non-DDI compliant code.
* But writing a nexus driver would be impossible to do with only DDI
* compliant interfaces.
*/
#include <sys/sysmacros.h>
/*
* Local prototypes.
*/
static int sda_nexus_ap_disconnect(sda_slot_t *);
static int sda_nexus_ap_configure(sda_slot_t *);
static int sda_nexus_ap_unconfigure(sda_slot_t *);
static void sda_nexus_reinsert(sda_slot_t *);
static void sda_nexus_create(sda_slot_t *);
/*
* Static Variables.
*/
static kmutex_t sda_nexus_lock;
static list_t sda_nexus_list;
/*
* Minor number allocation.
*
* We have up to NBITSMINOR32 (18) bits available.
*
* For each instance, we need one minor number for each slot, and one
* minor number for the devctl node.
*
* For simplicity's sake, we use the lower 8 bits for AP and DEVCTL nodes,
* and the remaining 10 bits for the instance number.
*/
#define MINOR_DC 0xff
/*
* Implementation.
*/
void
sda_nexus_init(void)
{
}
void
sda_nexus_fini(void)
{
}
int
{
switch (ctlop) {
case DDI_CTLOPS_REPORTDEV:
{
return (DDI_SUCCESS);
}
case DDI_CTLOPS_INITCHILD:
{
char addr[16];
return (DDI_NOT_WELL_FORMED);
}
/*
* TODO: SDIO: We will need to use x,y addresses for
* SDIO function numbers. Memory cards will always
* resid at address 0. Probably this can be passed in
* to this function using properties.
*/
/*
* Prevent duplicate nodes.
*/
}
/*
* Stash the address in the devinfo node.
*/
return (DDI_SUCCESS);
}
case DDI_CTLOPS_UNINITCHILD:
{
return (DDI_SUCCESS);
}
case DDI_CTLOPS_SIDDEV:
/*
* All SDA target devices are self-identifying.
*/
return (DDI_SUCCESS);
case DDI_CTLOPS_SLAVEONLY:
/*
* We don't support DMA master for SDA targets.
*/
return (DDI_SUCCESS);
case DDI_CTLOPS_AFFINITY:
/*
* NB: We may want to revisit this later, so that functions
* on one card can see other functions on the same card.
* Right now there is no need.
*/
return (DDI_FAILURE);
case DDI_CTLOPS_DMAPMAPC:
case DDI_CTLOPS_REPORTINT:
case DDI_CTLOPS_POKE:
case DDI_CTLOPS_PEEK:
case DDI_CTLOPS_NREGS:
case DDI_CTLOPS_REGSIZE:
/*
* We don't support any of these (yet?).
*/
return (DDI_FAILURE);
default:
/*
* Everything else goes to the parent nexus.
*/
}
}
void
{
int i;
int inst;
char name[16];
/*
* Now create minor nodes. Note that failures to create these nodes
* are mostly harmless, so we don't do much besides warn about it.
* (It means cfgadm will be useless, but most folks aren't likely
* to use cfgadm anyway.)
*/
/*
* Create the devctl minor node.
*/
}
for (i = 0; i < h->h_nslot; i++) {
/*
* Create the attachment point minor nodes.
*/
0) != DDI_SUCCESS) {
"Unable to create attachment point node");
}
}
}
void
{
/*
* Remove all minor nodes.
*/
list_remove(&sda_nexus_list, h);
}
{
int inst;
sda_host_t *h;
h = list_head(&sda_nexus_list);
while (h != NULL) {
break;
}
h = list_next(&sda_nexus_list, h);
}
return (h);
}
void
{
int rv;
/*
* SDIO: This whole function will need to be recrafted to
* support non-memory children. For SDIO, there could be
* multiple functions, which get inserted or removed together.
*/
NDI_SUCCESS) {
return;
}
/*
*/
if (rv != 0) {
(void) ndi_devi_free(cdip);
return;
}
(void) ndi_devi_free(cdip);
} else {
}
}
void
{
int circ;
}
}
void
{
char uuid[40];
} else {
/*
* SDIO: For SDIO, we can write the card's MANFID
* tuple in CIS to the UUID. Until we support SDIO,
* we just suppress creating devinfo nodes.
*/
uuid[0] = 0;
}
if (!match) {
} else {
}
} else {
/*
* Remember the UUID.
*/
/*
* Create the children.
*/
if (uuid[0] != 0)
}
}
void
{
int circ;
}
if (reap) {
}
}
void
sda_nexus_reap(void *arg)
{
int circ;
char *devnm;
int rv;
} else {
}
if (rv != NDI_SUCCESS) {
return;
}
}
}
/* woohoo, done reaping nodes */
}
/*ARGSUSED3*/
int
{
int rv = 0;
sda_host_t *h;
return (EINVAL);
return (ENXIO);
}
} else {
h->h_flags |= HOST_XOPEN;
}
} else {
if ((h->h_flags & HOST_XOPEN) != 0) {
} else {
h->h_flags |= HOST_SOPEN;
}
}
return (rv);
}
/*ARGSUSED1*/
int
{
sda_host_t *h;
return (EINVAL);
return (ENXIO);
}
return (0);
}
void
{
int circ;
/*
* Default state.
*/
if (slot->s_inserted) {
}
if (DEVI_IS_DEVICE_REMOVED(cdip)) {
}
if (DEVI_IS_DEVICE_OFFLINE(cdip) ||
} else {
}
}
}
}
int
{
int rv = 0;
int circ;
/* if a child node exists, try to delete it */
/* couldn't disconnect, why not? */
goto done;
}
}
done:
return (rv);
}
int
{
int rv = 0;
int circ;
/* attempt to unconfigure the node */
/* failed to unconfigure the node (EBUSY?) */
goto done;
}
}
done:
return (rv);
}
int
{
/* device not present */
return (ENXIO);
}
/* attempt to configure the node */
/* node not there! */
return (ENXIO);
}
/* failed to configure the node */
slot->s_intransit = 0;
return (EIO);
}
slot->s_intransit = 0;
return (0);
}
int
{
int rv = 0;
/*
* In theory we could try to support this operation on the
* DEVCTL minor, but then we would need a slot member in the
* user nvlist. For now its easiest to assume a 1:1 relation
* between the AP minor node, and the slot number.
*/
return (ENXIO);
}
return (EFAULT);
switch (cmd) {
case DEVCTL_AP_DISCONNECT:
break;
case DEVCTL_AP_UNCONFIGURE:
break;
case DEVCTL_AP_CONFIGURE:
break;
case DEVCTL_AP_GETSTATE:
}
break;
}
return (rv);
}
int
{
struct sda_ap_control apc;
struct sda_ap_control32 apc32;
int rv = 0;
return (ENXIO);
}
case DDI_MODEL_ILP32:
0) {
return (EFAULT);
}
break;
case DDI_MODEL_NONE:
return (EFAULT);
}
break;
}
case SDA_CFGA_GET_CARD_INFO: {
break;
}
if (!slot->s_inserted) {
} else {
}
} else {
}
} else {
}
}
return (EFAULT);
}
break;
}
case SDA_CFGA_GET_DEVICE_PATH:
{
char path[MAXPATHLEN];
int slen;
return (ENOENT);
}
break;
}
return (EFAULT);
}
break;
}
case SDA_CFGA_RESET_SLOT:
{
break;
}
default:
return (EINVAL);
}
case DDI_MODEL_ILP32:
0) {
return (EFAULT);
}
break;
case DDI_MODEL_NONE:
return (EFAULT);
}
break;
}
return (rv);
}
/*ARGSUSED4*/
int
int *rvp)
{
sda_host_t *h;
h = sda_nexus_lookup_dev(dev);
if (h == NULL)
return (ENXIO);
switch (cmd) {
case DEVCTL_DEVICE_GETSTATE:
case DEVCTL_DEVICE_ONLINE:
case DEVCTL_DEVICE_OFFLINE:
case DEVCTL_DEVICE_REMOVE:
case DEVCTL_BUS_GETSTATE:
case DEVCTL_AP_DISCONNECT:
case DEVCTL_AP_CONFIGURE:
case DEVCTL_AP_UNCONFIGURE:
case DEVCTL_AP_GETSTATE:
case DEVCTL_AP_CONTROL:
default:
return (ENOTSUP);
}
}
/*ARGSUSED*/
int
{
sda_host_t *h;
int rv;
rv = DDI_FAILURE;
switch (cmd) {
case DDI_INFO_DEVT2DEVINFO:
if (h != NULL) {
rv = DDI_SUCCESS;
}
break;
case DDI_INFO_DEVT2INSTANCE:
rv = DDI_SUCCESS;
break;
}
return (rv);
}