aboutsummaryrefslogtreecommitdiff
path: root/sys/pccard/pccard.c
diff options
context:
space:
mode:
authorWarner Losh <imp@FreeBSD.org>2005-09-25 21:29:32 +0000
committerWarner Losh <imp@FreeBSD.org>2005-09-25 21:29:32 +0000
commit9f8aaf685b48712cfeead72c80a64715c559ad82 (patch)
tree58cc7567434699af9d901ac0a0ab8c262f3b1f22 /sys/pccard/pccard.c
parentf31f999d7d9c64d1269ae74e9be7fe20ffab9274 (diff)
Remove the kernel portion of OLDCARD. I'm working on a replacement
for pccardc dumpcis, but until I'm done with that, I'm leaving pccardc in place. As such, I'm leaving the .h files in place for the moment.
Notes
Notes: svn path=/head/; revision=150556
Diffstat (limited to 'sys/pccard/pccard.c')
-rw-r--r--sys/pccard/pccard.c731
1 files changed, 0 insertions, 731 deletions
diff --git a/sys/pccard/pccard.c b/sys/pccard/pccard.c
deleted file mode 100644
index b8ebea9033c5..000000000000
--- a/sys/pccard/pccard.c
+++ /dev/null
@@ -1,731 +0,0 @@
-/*
- * pccard.c - Interface code for PC-CARD controllers.
- *
- * June 1995, Andrew McRae (andrew@mega.com.au)
- *-------------------------------------------------------------------------
- */
-/*-
- * Copyright (c) 2001 M. Warner Losh. All rights reserved.
- * Copyright (c) 1995 Andrew McRae. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. The name of the author may not be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $FreeBSD$
- */
-
-#define OBSOLETE_IN_6
-
-#include <sys/param.h>
-#include <sys/types.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/malloc.h>
-#include <sys/sysctl.h>
-#include <sys/conf.h>
-#include <sys/uio.h>
-#include <sys/poll.h>
-#include <sys/bus.h>
-#include <sys/proc.h>
-#include <machine/bus.h>
-
-#include <pccard/cardinfo.h>
-#include <pccard/driver.h>
-#include <pccard/slot.h>
-#include <pccard/pccard_nbk.h>
-
-#include <machine/md_var.h>
-
-static int allocate_driver(struct slot *, struct dev_desc *);
-static void inserted(void *);
-static void disable_slot(struct slot *);
-static void disable_slot_to(struct slot *);
-static void power_off_slot(void *);
-
-/*
- * The driver interface for read/write uses a block
- * of memory in the ISA I/O memory space allocated via
- * an ioctl setting.
- *
- * Now that we have different bus attachments, we should really
- * use a better algorythm to allocate memory.
- */
-static unsigned long pccard_mem; /* Physical memory */
-static unsigned char *pccard_kmem; /* Kernel virtual address */
-static struct resource *pccard_mem_res;
-static int pccard_mem_rid;
-
-static d_open_t crdopen;
-static d_close_t crdclose;
-static d_read_t crdread;
-static d_write_t crdwrite;
-static d_ioctl_t crdioctl;
-static d_poll_t crdpoll;
-
-static struct cdevsw crd_cdevsw = {
- .d_version = D_VERSION,
- .d_flags = D_NEEDGIANT,
- .d_open = crdopen,
- .d_close = crdclose,
- .d_read = crdread,
- .d_write = crdwrite,
- .d_ioctl = crdioctl,
- .d_poll = crdpoll,
- .d_name = "crd",
-};
-
-/*
- * Power off the slot.
- * (doing it immediately makes the removal of some cards unstable)
- */
-static void
-power_off_slot(void *arg)
-{
- struct slot *slt = (struct slot *)arg;
- int s;
-
- /*
- * The following will generate an interrupt. So, to hold off
- * the interrupt unitl after disable runs so that we can get rid
- * rid of the interrupt before it becomes unsafe to touch the
- * device.
- *
- * XXX In current, the spl stuff is a nop.
- */
- s = splhigh();
- /* Power off the slot. */
- slt->pwr_off_pending = 0;
- slt->ctrl->disable(slt);
- splx(s);
-}
-
-/*
- * disable_slot - Disables the slot by removing
- * the power and unmapping the I/O
- */
-static void
-disable_slot(struct slot *slt)
-{
- device_t pccarddev;
- device_t *kids;
- int nkids;
- int i;
- int ret;
-
- /*
- * Note that a race condition is possible here; if a
- * driver is accessing the device and it is removed, then
- * all bets are off...
- */
- pccarddev = slt->dev;
- device_get_children(pccarddev, &kids, &nkids);
- for (i = 0; i < nkids; i++) {
- if ((ret = device_delete_child(pccarddev, kids[i])) != 0)
- printf("pccard: delete of %s failed: %d\n",
- device_get_nameunit(kids[i]), ret);
- }
- free(kids, M_TEMP);
-
- /* Power off the slot 1/2 second after removal of the card */
- slt->poff_ch = timeout(power_off_slot, (caddr_t)slt, hz / 2);
- slt->pwr_off_pending = 1;
-}
-
-static void
-disable_slot_to(struct slot *slt)
-{
- disable_slot(slt);
- if (slt->state == empty)
- printf("pccard: card removed, slot %d\n", slt->slotnum);
- else
- printf("pccard: card deactivated, slot %d\n", slt->slotnum);
- pccard_remove_beep();
- selwakeuppri(&slt->selp, PZERO);
-}
-
-/*
- * pccard_init_slot - Initialize the slot controller and attach various
- * things to it. We also make the device for it. We create the device that
- * will be exported to devfs.
- */
-struct slot *
-pccard_init_slot(device_t dev, struct slot_ctrl *ctrl)
-{
- int slotno;
- struct slot *slt;
-
- slt = PCCARD_DEVICE2SOFTC(dev);
- slotno = device_get_unit(dev);
- slt->dev = dev;
- slt->d = make_dev(&crd_cdevsw, slotno, 0, 0, 0600, "card%d", slotno);
- slt->d->si_drv1 = slt;
- slt->ctrl = ctrl;
- slt->slotnum = slotno;
- callout_handle_init(&slt->insert_ch);
- callout_handle_init(&slt->poff_ch);
-
- return (slt);
-}
-
-/*
- * allocate_driver - Create a new device entry for this
- * slot, and attach a driver to it.
- */
-static int
-allocate_driver(struct slot *slt, struct dev_desc *desc)
-{
- struct pccard_devinfo *devi;
- device_t pccarddev;
- int err, irq = 0;
- device_t child;
- device_t *devs;
- int count;
-
- pccarddev = slt->dev;
- err = device_get_children(pccarddev, &devs, &count);
- if (err != 0)
- return (err);
- free(devs, M_TEMP);
- if (count) {
- device_printf(pccarddev,
- "Can not attach more than one child.\n");
- return (EIO);
- }
- irq = ffs(desc->irqmask) - 1;
- MALLOC(devi, struct pccard_devinfo *, sizeof(*devi), M_DEVBUF,
- M_WAITOK | M_ZERO);
- strcpy(devi->name, desc->name);
- /*
- * Create an entry for the device under this slot.
- */
- devi->running = 1;
- devi->slt = slt;
- bcopy(desc->misc, devi->misc, sizeof(desc->misc));
- strcpy(devi->manufstr, desc->manufstr);
- strcpy(devi->versstr, desc->versstr);
- strcpy(devi->cis3str, desc->cis3str);
- strcpy(devi->cis4str, desc->cis4str);
- devi->manufacturer = desc->manufacturer;
- devi->product = desc->product;
- devi->prodext = desc->prodext;
- resource_list_init(&devi->resources);
- child = device_add_child(pccarddev, devi->name, desc->unit);
- if (child == NULL) {
- if (desc->unit != -1)
- device_printf(pccarddev,
- "Unit %d failed for %s, try a different unit\n",
- desc->unit, devi->name);
- else
- device_printf(pccarddev,
- "No units available for %s. Impossible?\n",
- devi->name);
- return (EIO);
- }
- device_set_flags(child, desc->flags);
- device_set_ivars(child, devi);
- if (bootverbose) {
- device_printf(pccarddev, "Assigning %s:",
- device_get_nameunit(child));
- if (desc->iobase)
- printf(" io 0x%x-0x%x",
- desc->iobase, desc->iobase + desc->iosize - 1);
- if (irq)
- printf(" irq %d", irq);
- if (desc->mem)
- printf(" mem 0x%lx-0x%lx", desc->mem,
- desc->mem + desc->memsize - 1);
- printf(" flags 0x%x\n", desc->flags);
- }
- err = bus_set_resource(child, SYS_RES_IOPORT, 0, desc->iobase,
- desc->iosize);
- if (err)
- goto err;
- if (irq)
- err = bus_set_resource(child, SYS_RES_IRQ, 0, irq, 1);
- if (err)
- goto err;
- if (desc->memsize) {
- err = bus_set_resource(child, SYS_RES_MEMORY, 0, desc->mem,
- desc->memsize);
- if (err)
- goto err;
- }
- err = device_probe_and_attach(child);
- /*
- * XXX We unwisely assume that the detach code won't run while the
- * XXX the attach code is attaching. Someone should put some
- * XXX interlock code. This can happen if probe/attach takes a while
- * XXX and the user ejects the card, which causes the detach
- * XXX function to be called.
- */
- strncpy(desc->name, device_get_nameunit(child), sizeof(desc->name));
- desc->name[sizeof(desc->name) - 1] = '\0';
-err:
- if (err)
- device_delete_child(pccarddev, child);
- return (err);
-}
-
-/*
- * card insert routine - Called from a timeout to debounce
- * insertion events.
- */
-static void
-inserted(void *arg)
-{
- struct slot *slt = arg;
-
- slt->state = filled;
- /*
- * Disable any pending timeouts for this slot, and explicitly
- * power it off right now. Then, re-enable the power using
- * the (possibly new) power settings.
- */
- untimeout(power_off_slot, (caddr_t)slt, slt->poff_ch);
- power_off_slot(slt);
-
- /*
- * Enable 5V to the card so that the CIS can be read. Well,
- * enable the most natural voltage so that the CIS can be read.
- */
- slt->pwr.vcc = -1;
- slt->pwr.vpp = -1;
- slt->ctrl->power(slt);
-
- printf("pccard: card inserted, slot %d\n", slt->slotnum);
- pccard_insert_beep();
- slt->ctrl->reset(slt);
-}
-
-/*
- * Card event callback. Called at splhigh to prevent
- * device interrupts from interceding.
- */
-void
-pccard_event(struct slot *slt, enum card_event event)
-{
- if (slt->insert_seq) {
- slt->insert_seq = 0;
- untimeout(inserted, (void *)slt, slt->insert_ch);
- }
-
- switch(event) {
- case card_removed:
- case card_deactivated:
- if (slt->state == filled || slt->state == inactive) {
- if (event == card_removed)
- slt->state = empty;
- else
- slt->state = inactive;
- disable_slot_to(slt);
- }
- break;
- case card_inserted:
- slt->insert_seq = 1;
- slt->insert_ch = timeout(inserted, (void *)slt, hz/4);
- break;
- }
-}
-
-/*
- * Device driver interface.
- */
-static int
-crdopen(struct cdev *dev, int oflags, int devtype, d_thread_t *td)
-{
- struct slot *slt = PCCARD_DEV2SOFTC(dev);
-
- if (slt == NULL)
- return (ENXIO);
- if (slt->rwmem == 0)
- slt->rwmem = MDF_ATTR;
- return (0);
-}
-
-/*
- * Close doesn't de-allocate any resources, since
- * slots may be assigned to drivers already.
- */
-static int
-crdclose(struct cdev *dev, int fflag, int devtype, d_thread_t *td)
-{
- return (0);
-}
-
-/*
- * read interface. Map memory at lseek offset,
- * then transfer to user space.
- */
-static int
-crdread(struct cdev *dev, struct uio *uio, int ioflag)
-{
- struct slot *slt = PCCARD_DEV2SOFTC(dev);
- struct mem_desc *mp, oldmap;
- unsigned char *p;
- unsigned int offs;
- int error = 0, win, count;
-
- if (slt == 0 || slt->state != filled)
- return (ENXIO);
- if (pccard_mem == 0)
- return (ENOMEM);
- for (win = slt->ctrl->maxmem - 1; win >= 0; win--)
- if ((slt->mem[win].flags & MDF_ACTIVE) == 0)
- break;
- if (win < 0)
- return (EBUSY);
- mp = &slt->mem[win];
- oldmap = *mp;
- mp->flags = slt->rwmem | MDF_ACTIVE;
- while (uio->uio_resid && error == 0) {
- mp->card = uio->uio_offset;
- mp->size = PCCARD_MEMSIZE;
- mp->start = (caddr_t)(void *)(uintptr_t)pccard_mem;
- if ((error = slt->ctrl->mapmem(slt, win)) != 0)
- break;
- offs = (unsigned int)uio->uio_offset & (PCCARD_MEMSIZE - 1);
- p = pccard_kmem + offs;
- count = MIN(PCCARD_MEMSIZE - offs, uio->uio_resid);
- error = uiomove(p, count, uio);
- }
- /*
- * Restore original map.
- */
- *mp = oldmap;
- slt->ctrl->mapmem(slt, win);
-
- return (error);
-}
-
-/*
- * crdwrite - Write data to card memory.
- * Handles wrap around so that only one memory
- * window is used.
- */
-static int
-crdwrite(struct cdev *dev, struct uio *uio, int ioflag)
-{
- struct slot *slt = PCCARD_DEV2SOFTC(dev);
- struct mem_desc *mp, oldmap;
- unsigned char *p;
- unsigned int offs;
- int error = 0, win, count;
-
- if (slt == 0 || slt->state != filled)
- return (ENXIO);
- if (pccard_mem == 0)
- return (ENOMEM);
- for (win = slt->ctrl->maxmem - 1; win >= 0; win--)
- if ((slt->mem[win].flags & MDF_ACTIVE) == 0)
- break;
- if (win < 0)
- return (EBUSY);
- mp = &slt->mem[win];
- oldmap = *mp;
- mp->flags = slt->rwmem | MDF_ACTIVE;
- while (uio->uio_resid && error == 0) {
- mp->card = uio->uio_offset;
- mp->size = PCCARD_MEMSIZE;
- mp->start = (caddr_t)(void *)(uintptr_t)pccard_mem;
- if ((error = slt->ctrl->mapmem(slt, win)) != 0)
- break;
- offs = (unsigned int)uio->uio_offset & (PCCARD_MEMSIZE - 1);
- p = pccard_kmem + offs;
- count = MIN(PCCARD_MEMSIZE - offs, uio->uio_resid);
- error = uiomove(p, count, uio);
- }
- /*
- * Restore original map.
- */
- *mp = oldmap;
- slt->ctrl->mapmem(slt, win);
-
- return (error);
-}
-
-/*
- * ioctl calls - allows setting/getting of memory and I/O
- * descriptors, and assignment of drivers.
- */
-static int
-crdioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, d_thread_t *td)
-{
- u_int32_t addr;
- int err;
- struct io_desc *ip;
- struct mem_desc *mp;
- device_t pccarddev;
- int pwval;
- int s;
- struct slot *slt = PCCARD_DEV2SOFTC(dev);
-/*XXX*/#if __FreeBSD_version < 5000000 /* 4.x compatibility only. */
- struct dev_desc d;
- struct dev_desc_old *odp;
-/*XXX*/#endif
-
- if (slt == 0 && cmd != PIOCRWMEM)
- return (ENXIO);
- switch(cmd) {
- default:
- if (slt->ctrl->ioctl)
- return (slt->ctrl->ioctl(slt, cmd, data));
- return (ENOTTY);
- /*
- * Get slot state.
- */
- case PIOCGSTATE:
- s = splhigh();
- ((struct slotstate *)data)->state = slt->state;
- ((struct slotstate *)data)->laststate = slt->laststate;
- slt->laststate = slt->state;
- splx(s);
- ((struct slotstate *)data)->maxmem = slt->ctrl->maxmem;
- ((struct slotstate *)data)->maxio = slt->ctrl->maxio;
- ((struct slotstate *)data)->irqs = 0;
- break;
- /*
- * Get memory context.
- */
- case PIOCGMEM:
- s = ((struct mem_desc *)data)->window;
- if (s < 0 || s >= slt->ctrl->maxmem)
- return (EINVAL);
- mp = &slt->mem[s];
- ((struct mem_desc *)data)->flags = mp->flags;
- ((struct mem_desc *)data)->start = mp->start;
- ((struct mem_desc *)data)->size = mp->size;
- ((struct mem_desc *)data)->card = mp->card;
- break;
- /*
- * Set memory context. If context already active, then unmap it.
- * It is hard to see how the parameters can be checked.
- * At the very least, we only allow root to set the context.
- */
- case PIOCSMEM:
- if (suser(td))
- return (EPERM);
- if (slt->state != filled)
- return (ENXIO);
- s = ((struct mem_desc *)data)->window;
- if (s < 0 || s >= slt->ctrl->maxmem)
- return (EINVAL);
- slt->mem[s] = *((struct mem_desc *)data);
- return (slt->ctrl->mapmem(slt, s));
- /*
- * Get I/O port context.
- */
- case PIOCGIO:
- s = ((struct io_desc *)data)->window;
- if (s < 0 || s >= slt->ctrl->maxio)
- return (EINVAL);
- ip = &slt->io[s];
- ((struct io_desc *)data)->flags = ip->flags;
- ((struct io_desc *)data)->start = ip->start;
- ((struct io_desc *)data)->size = ip->size;
- break;
- /*
- * Set I/O port context.
- */
- case PIOCSIO:
- if (suser(td))
- return (EPERM);
- if (slt->state != filled)
- return (ENXIO);
- s = ((struct io_desc *)data)->window;
- if (s < 0 || s >= slt->ctrl->maxio)
- return (EINVAL);
- slt->io[s] = *((struct io_desc *)data);
- /* XXX Don't actually map */
- return (0);
- break;
- /*
- * Set memory window flags for read/write interface.
- */
- case PIOCRWFLAG:
- slt->rwmem = *(int *)data;
- break;
- /*
- * Set the memory window to be used for the read/write interface.
- */
- case PIOCRWMEM:
- if (*(unsigned long *)data == 0) {
- *(unsigned long *)data = pccard_mem;
- break;
- }
- if (suser(td))
- return (EPERM);
- /*
- * Validate the memory by checking it against the I/O
- * memory range. It must also start on an aligned block size.
- */
- if (*(unsigned long *)data & (PCCARD_MEMSIZE-1))
- return (EINVAL);
- pccarddev = PCCARD_DEV2SOFTC(dev)->dev;
- pccard_mem_rid = 0;
- addr = *(unsigned long *)data;
- if (pccard_mem_res)
- bus_release_resource(pccarddev, SYS_RES_MEMORY,
- pccard_mem_rid, pccard_mem_res);
- pccard_mem_res = bus_alloc_resource(pccarddev, SYS_RES_MEMORY,
- &pccard_mem_rid, addr, addr, PCCARD_MEMSIZE,
- RF_ACTIVE | rman_make_alignment_flags(PCCARD_MEMSIZE));
- if (pccard_mem_res == NULL)
- return (EINVAL);
- pccard_mem = rman_get_start(pccard_mem_res);
- pccard_kmem = rman_get_virtual(pccard_mem_res);
- break;
- /*
- * Set power values.
- */
- case PIOCSPOW:
- slt->pwr = *(struct power *)data;
- return (slt->ctrl->power(slt));
- /*
- * Allocate a driver to this slot.
- */
- case PIOCSDRV:
- if (suser(td))
- return (EPERM);
- err = allocate_driver(slt, (struct dev_desc *)data);
- if (!err)
- pccard_success_beep();
- else
- pccard_failure_beep();
- return (err);
-/***/#if __FreeBSD_version < 5000000 /* 4.x compatibility only. */
- case PIOCSDRVOLD:
- if (suser(td))
- return (EPERM);
- odp = (struct dev_desc_old *) data;
- strlcpy(d.name, odp->name, sizeof(d.name));
- d.unit = odp->unit;
- d.mem = odp->mem;
- d.memsize = odp->memsize;
- d.iobase = odp->iobase;
- d.iosize = odp->iosize;
- d.irqmask = odp->irqmask;
- d.flags = odp->flags;
- memcpy(d.misc, odp->misc, sizeof(odp->misc));
- strlcpy(d.manufstr, odp->manufstr, sizeof(d.manufstr));
- strlcpy(d.versstr, odp->versstr, sizeof(d.versstr));
- *d.cis3str = '\0';
- *d.cis4str = '\0';
- d.manufacturer = odp->manufacturer;
- d.product = odp->product;
- d.prodext = odp->prodext;
- err = allocate_driver(slt, &d);
- if (!err)
- pccard_success_beep();
- else
- pccard_failure_beep();
- return (err);
-/***/#endif
- /*
- * Virtual removal/insertion
- */
- case PIOCSVIR:
- pwval = *(int *)data;
- if (!pwval) {
- if (slt->state != filled)
- return (EINVAL);
- pccard_event(slt, card_deactivated);
- } else {
- if (slt->state != empty && slt->state != inactive)
- return (EINVAL);
- pccard_event(slt, card_inserted);
- }
- break;
- case PIOCSBEEP:
- if (pccard_beep_select(*(int *)data)) {
- return (EINVAL);
- }
- break;
- }
- return (0);
-}
-
-/*
- * poll - Poll on exceptions will return true
- * when a change in card status occurs.
- */
-static int
-crdpoll(struct cdev *dev, int events, d_thread_t *td)
-{
- int revents = 0;
- int s;
- struct slot *slt = PCCARD_DEV2SOFTC(dev);
-
- if (events & (POLLIN | POLLRDNORM))
- revents |= events & (POLLIN | POLLRDNORM);
-
- if (events & (POLLOUT | POLLWRNORM))
- revents |= events & (POLLIN | POLLRDNORM);
-
- s = splhigh();
- /*
- * select for exception - card event.
- */
- if (events & POLLRDBAND)
- if (slt == 0 || slt->laststate != slt->state)
- revents |= POLLRDBAND;
-
- if (revents == 0)
- selrecord(td, &slt->selp);
-
- splx(s);
- return (revents);
-}
-
-/*
- * APM hooks for suspending and resuming.
- */
-int
-pccard_suspend(device_t dev)
-{
- struct slot *slt = PCCARD_DEVICE2SOFTC(dev);
-
- /* This code stolen from pccard_event:card_removed */
- if (slt->state == filled) {
- int s = splhigh(); /* nop on current */
- disable_slot(slt);
- slt->laststate = suspend; /* for pccardd */
- slt->state = empty;
- splx(s);
- printf("pccard: card disabled, slot %d\n", slt->slotnum);
- }
- /*
- * Disable any pending timeouts for this slot since we're
- * powering it down/disabling now.
- */
- untimeout(power_off_slot, (caddr_t)slt, slt->poff_ch);
- slt->ctrl->disable(slt);
- return (0);
-}
-
-int
-pccard_resume(device_t dev)
-{
- struct slot *slt = PCCARD_DEVICE2SOFTC(dev);
-
- slt->ctrl->resume(slt);
- return (0);
-}