/* * power management */ static int rtsx_suspend(struct pci_dev *pci, pm_message_t state) { struct rtsx_dev *dev = pci_get_drvdata(pci); struct rtsx_chip *chip; if (!dev) return 0; /* lock the device pointers */ mutex_lock(&(dev->dev_mutex)); chip = dev->chip; rtsx_do_before_power_down(chip, PM_S3); if (dev->irq >= 0) { free_irq(dev->irq, (void *)dev); dev->irq = -1; } if (chip->msi_en) pci_disable_msi(pci); pci_save_state(pci); pci_enable_wake(pci, pci_choose_state(pci, state), 1); pci_disable_device(pci); pci_set_power_state(pci, pci_choose_state(pci, state)); /* unlock the device pointers */ mutex_unlock(&dev->dev_mutex); return 0; }
static int rt2860_suspend( struct pci_dev *pci_dev, pm_message_t state) { struct net_device *net_dev = pci_get_drvdata(pci_dev); PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)NULL; INT32 retval = 0; DBGPRINT(RT_DEBUG_TRACE, ("===> rt2860_suspend()\n")); if (net_dev == NULL) { DBGPRINT(RT_DEBUG_ERROR, ("net_dev == NULL!\n")); } else { pAd = (PRTMP_ADAPTER)RTMP_OS_NETDEV_GET_PRIV(net_dev); if (VIRTUAL_IF_NUM(pAd) > 0) { netif_carrier_off(net_dev); netif_stop_queue(net_dev); netif_device_detach(net_dev); RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); rt28xx_close((PNET_DEV)net_dev); RT_MOD_DEC_USE_COUNT(); } } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10) retval = pci_enable_wake(pci_dev, pci_choose_state(pci_dev, state), 1); pci_save_state(pci_dev); pci_disable_device(pci_dev); retval = pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); #endif DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2860_suspend()\n")); return retval; }
static int rt2860_suspend( struct pci_dev *pci_dev, pm_message_t state) { struct net_device *net_dev = pci_get_drvdata(pci_dev); PRTMP_ADAPTER pAd = (PRTMP_ADAPTER)NULL; INT32 retval = 0; DBGPRINT(RT_DEBUG_TRACE, ("===> rt2860_suspend()\n")); if (net_dev == NULL) { DBGPRINT(RT_DEBUG_ERROR, ("net_dev == NULL!\n")); } else { GET_PAD_FROM_NET_DEV(pAd, net_dev); /* we can not use IFF_UP because ra0 down but ra1 up */ /* and 1 suspend/resume function for 1 module, not for each interface */ /* so Linux will call suspend/resume function once */ if (VIRTUAL_IF_NUM(pAd) > 0) { // avoid users do suspend after interface is down // stop interface netif_carrier_off(net_dev); netif_stop_queue(net_dev); // mark device as removed from system and therefore no longer available netif_device_detach(net_dev); // mark halt flag RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_HALT_IN_PROGRESS); RTMP_SET_FLAG(pAd, fRTMP_ADAPTER_RADIO_OFF); // take down the device rt28xx_close((PNET_DEV)net_dev); RT_MOD_DEC_USE_COUNT(); } } #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,10) // reference to http://vovo2000.com/type-lab/linux/kernel-api/linux-kernel-api.html // enable device to generate PME# when suspended // pci_choose_state(): Choose the power state of a PCI device to be suspended retval = pci_enable_wake(pci_dev, pci_choose_state(pci_dev, state), 1); // save the PCI configuration space of a device before suspending pci_save_state(pci_dev); // disable PCI device after use pci_disable_device(pci_dev); retval = pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); #endif DBGPRINT(RT_DEBUG_TRACE, ("<=== rt2860_suspend()\n")); return retval; }
int chd_dec_pci_suspend(struct pci_dev *pdev, pm_message_t state) { struct crystalhd_adp *adp; struct crystalhd_ioctl_data *temp; enum BC_STATUS sts = BC_STS_SUCCESS; adp = (struct crystalhd_adp *)pci_get_drvdata(pdev); if (!adp) { BCMLOG_ERR("could not get adp\n"); return -ENODEV; } temp = chd_dec_alloc_iodata(adp, false); if (!temp) { BCMLOG_ERR("could not get ioctl data\n"); return -ENODEV; } sts = crystalhd_suspend(&adp->cmds, temp); if (sts != BC_STS_SUCCESS) { BCMLOG_ERR("BCM70012 Suspend %d\n", sts); return -ENODEV; } chd_dec_free_iodata(adp, temp, false); chd_dec_disable_int(adp); pci_save_state(pdev); /* Disable IO/bus master/irq router */ pci_disable_device(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; }
int snd_cs5535audio_suspend(struct pci_dev *pci, pm_message_t state) { struct snd_card *card = pci_get_drvdata(pci); struct cs5535audio *cs5535au = card->private_data; int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(cs5535au->pcm); snd_ac97_suspend(cs5535au->ac97); for (i = 0; i < NUM_CS5535AUDIO_DMAS; i++) { struct cs5535audio_dma *dma = &cs5535au->dmas[i]; if (dma && dma->substream) dma->saved_prd = dma->ops->read_prd(cs5535au); } /* save important regs, then disable aclink in hw */ snd_cs5535audio_stop_hardware(cs5535au); if (pci_save_state(pci)) { printk(KERN_ERR "cs5535audio: pci_save_state failed!\n"); return -EIO; } pci_disable_device(pci); pci_set_power_state(pci, pci_choose_state(pci, state)); return 0; }
static int agp_amdk7_suspend(struct pci_dev *pdev, pm_message_t state) { pci_save_state(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; }
int oxygen_pci_suspend(struct pci_dev *pci, pm_message_t state) { struct snd_card *card = pci_get_drvdata(pci); struct oxygen *chip = card->private_data; unsigned int i, saved_interrupt_mask; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); for (i = 0; i < PCM_COUNT; ++i) if (chip->streams[i]) snd_pcm_suspend(chip->streams[i]); if (chip->model.suspend) chip->model.suspend(chip); spin_lock_irq(&chip->reg_lock); saved_interrupt_mask = chip->interrupt_mask; chip->interrupt_mask = 0; oxygen_write16(chip, OXYGEN_DMA_STATUS, 0); oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, 0); spin_unlock_irq(&chip->reg_lock); synchronize_irq(chip->irq); flush_scheduled_work(); chip->interrupt_mask = saved_interrupt_mask; pci_disable_device(pci); pci_save_state(pci); pci_set_power_state(pci, pci_choose_state(pci, state)); return 0; }
static int snd_emu10k1_suspend(struct pci_dev *pci, pm_message_t state) { struct snd_card *card = pci_get_drvdata(pci); struct snd_emu10k1 *emu = card->private_data; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(emu->pcm); snd_pcm_suspend_all(emu->pcm_mic); snd_pcm_suspend_all(emu->pcm_efx); snd_pcm_suspend_all(emu->pcm_multi); snd_pcm_suspend_all(emu->pcm_p16v); snd_ac97_suspend(emu->ac97); snd_emu10k1_efx_suspend(emu); snd_emu10k1_suspend_regs(emu); if (emu->card_capabilities->ca0151_chip) snd_p16v_suspend(emu); snd_emu10k1_done(emu); pci_disable_device(pci); pci_save_state(pci); pci_set_power_state(pci, pci_choose_state(pci, state)); return 0; }
static int delkin_cb_suspend(struct pci_dev *dev, pm_message_t state) { pci_save_state(dev); pci_disable_device(dev); pci_set_power_state(dev, pci_choose_state(dev, state)); return 0; }
int rtl8192E_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); struct r8192_priv *priv = rtllib_priv(dev); u32 ulRegRead; netdev_info(dev, "============> r8192E suspend call.\n"); del_timer_sync(&priv->gpio_polling_timer); cancel_delayed_work(&priv->gpio_change_rf_wq); priv->polling_timer_on = 0; if (!netif_running(dev)) { netdev_info(dev, "RTL819XE:UI is open out of suspend function\n"); goto out_pci_suspend; } if (dev->netdev_ops->ndo_stop) dev->netdev_ops->ndo_stop(dev); netif_device_detach(dev); if (!priv->rtllib->bSupportRemoteWakeUp) { MgntActSet_RF_State(dev, eRfOff, RF_CHANGE_BY_INIT, true); ulRegRead = read_nic_dword(dev, CPU_GEN); ulRegRead |= CPU_GEN_SYSTEM_RESET; write_nic_dword(dev, CPU_GEN, ulRegRead); } else { write_nic_dword(dev, WFCRC0, 0xffffffff); write_nic_dword(dev, WFCRC1, 0xffffffff); write_nic_dword(dev, WFCRC2, 0xffffffff); write_nic_byte(dev, PMR, 0x5); write_nic_byte(dev, MacBlkCtrl, 0xa); } out_pci_suspend: netdev_info(dev, "WOL is %s\n", priv->rtllib->bSupportRemoteWakeUp ? "Supported" : "Not supported"); pci_save_state(pdev); pci_disable_device(pdev); pci_enable_wake(pdev, pci_choose_state(pdev, state), priv->rtllib->bSupportRemoteWakeUp ? 1 : 0); pci_set_power_state(pdev, pci_choose_state(pdev, state)); mdelay(20); return 0; }
/*************************************************************************/ /*! @Function OSPCIResumeDev @Description Prepare a PCI device to be resumed by power management @Input hPVRPCI PCI device handle @Return PVRSRV_ERROR Services error code */ /**************************************************************************/ PVRSRV_ERROR OSPCIResumeDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI) { PVR_PCI_DEV *psPVRPCI = (PVR_PCI_DEV *)hPVRPCI; int err; int i; err = pci_set_power_state(psPVRPCI->psPCIDev, pci_choose_state(psPVRPCI->psPCIDev, PMSG_ON)); switch(err) { case 0: break; case -EIO: printk(KERN_ERR "OSPCIResumeDev: device doesn't support PCI PM"); break; case -EINVAL: printk(KERN_ERR "OSPCIResumeDev: can't enter requested power state"); return PVRSRV_ERROR_UNKNOWN_POWER_STATE; default: printk(KERN_ERR "OSPCIResumeDev: pci_set_power_state failed (%d)", err); return PVRSRV_ERROR_UNKNOWN_POWER_STATE; } #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,38)) pci_restore_state(psPVRPCI->psPCIDev); #else err = pci_restore_state(psPVRPCI->psPCIDev); if (err != 0) { printk(KERN_ERR "OSPCIResumeDev: pci_restore_state failed (%d)", err); return PVRSRV_ERROR_PCI_CALL_FAILED; } #endif err = pci_enable_device(psPVRPCI->psPCIDev); if (err != 0) { printk(KERN_ERR "OSPCIResumeDev: Couldn't enable device (%d)", err); return PVRSRV_ERROR_PCI_CALL_FAILED; } if (psPVRPCI->ePCIFlags & HOST_PCI_INIT_FLAG_BUS_MASTER) /* PRQA S 3358 */ /* misuse of enums */ pci_set_master(psPVRPCI->psPCIDev); /* Restore the PCI resource tracking array */ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { if (psPVRPCI->abPCIResourceInUse[i]) { err = pci_request_region(psPVRPCI->psPCIDev, i, PVRSRV_MODNAME); if (err != 0) { printk(KERN_ERR "OSPCIResumeDev: pci_request_region_failed (region %d, error %d)", i, err); } } } return PVRSRV_OK; }
static int stmmac_pci_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *ndev = pci_get_drvdata(pdev); int ret; ret = stmmac_suspend(ndev); pci_save_state(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); return ret; }
static int agnx_pci_suspend(struct pci_dev *pdev, pm_message_t state) { struct ieee80211_hw *dev = pci_get_drvdata(pdev); AGNX_TRACE; ieee80211_stop_queues(dev); agnx_stop(dev); pci_save_state(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; }
static int snd_vx222_suspend(struct pci_dev *pci, pm_message_t state) { struct snd_card *card = pci_get_drvdata(pci); struct snd_vx222 *vx = card->private_data; int err; err = snd_vx_suspend(&vx->core, state); pci_disable_device(pci); pci_save_state(pci); pci_set_power_state(pci, pci_choose_state(pci, state)); return err; }
static int spi_suspend(struct pci_dev *pdev, pm_message_t state) { struct dw_spi_pci *dwpci = pci_get_drvdata(pdev); int ret; ret = dw_spi_suspend_host(&dwpci->dws); if (ret) return ret; pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); return ret; }
/* * power management */ static int rtsx_suspend(struct pci_dev *pci, pm_message_t state) { struct rtsx_dev *dev = (struct rtsx_dev *)pci_get_drvdata(pci); struct rtsx_chip *chip; printk(KERN_INFO "Ready to suspend\n"); if (!dev) { printk(KERN_ERR "Invalid memory\n"); return 0; } mutex_lock(&(dev->dev_mutex)); chip = dev->chip; rtsx_do_before_power_down(chip, PM_S3); if (dev->irq >= 0) { synchronize_irq(dev->irq); free_irq(dev->irq, (void *)dev); dev->irq = -1; } if (chip->msi_en) { pci_disable_msi(pci); } pci_save_state(pci); pci_enable_wake(pci, pci_choose_state(pci, state), 1); pci_disable_device(pci); pci_set_power_state(pci, pci_choose_state(pci, state)); mutex_unlock(&dev->dev_mutex); return 0; }
static s32 pch_suspend(struct pci_dev *pdev, pm_message_t state) { pci_disable_device(pdev); pci_enable_wake(pdev, PCI_D3hot, 0); if (pci_save_state(pdev) != 0) { dev_err(&pdev->dev, "could not save PCI config state\n"); return -ENOMEM; } pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; }
static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state) { struct ssb_bus *ssb = pci_get_drvdata(dev); int err; err = ssb_bus_suspend(ssb); if (err) return err; pci_save_state(dev); pci_disable_device(dev); pci_set_power_state(dev, pci_choose_state(dev, state)); return 0; }
/* * APM event handler, so the card is properly reinitialized after a power * event. */ static int nm256_suspend(struct pci_dev *pci, pm_message_t state) { struct snd_card *card = pci_get_drvdata(pci); struct nm256 *chip = card->private_data; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); snd_pcm_suspend_all(chip->pcm); snd_ac97_suspend(chip->ac97); chip->coeffs_current = 0; pci_disable_device(pci); pci_save_state(pci); pci_set_power_state(pci, pci_choose_state(pci, state)); return 0; }
int rt2x00pci_suspend(struct pci_dev *pci_dev, pm_message_t state) { struct ieee80211_hw *hw = pci_get_drvdata(pci_dev); struct rt2x00_dev *rt2x00dev = hw->priv; int retval; retval = rt2x00lib_suspend(rt2x00dev, state); if (retval) return retval; pci_save_state(pci_dev); pci_disable_device(pci_dev); return pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); }
static int p54p_suspend(struct pci_dev *pdev, pm_message_t state) { struct ieee80211_hw *dev = pci_get_drvdata(pdev); struct p54p_priv *priv = dev->priv; if (priv->common.mode != NL80211_IFTYPE_UNSPECIFIED) { ieee80211_stop_queues(dev); p54p_stop(dev); } pci_save_state(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; }
static int serial_hsu_suspend(struct pci_dev *pdev, pm_message_t state) { void *priv = pci_get_drvdata(pdev); struct uart_hsu_port *up; /* Make sure this is not the internal dma controller */ if (priv && (pdev->device != 0x081E)) { up = priv; uart_suspend_port(&serial_hsu_reg, &up->port); } pci_save_state(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; }
static int intelce_wdt_suspend(struct pci_dev *pdev, pm_message_t state) { /* Save watchdog state */ wtctrl_save = readl(INTELCE_WDT_CTRL); wtreload_save = readl(INTELCE_WDT_RELOAD); /* Stop watchdog */ intelce_wdt_stop(); /*PCI device save*/ pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; }
static int pch_phub_suspend(struct pci_dev *pdev, pm_message_t state) { int ret; pch_phub_save_reg_conf(pdev); ret = pci_save_state(pdev); if (ret) { dev_err(&pdev->dev, " %s -pci_save_state returns %d\n", __func__, ret); return ret; } pci_enable_wake(pdev, PCI_D3hot, 0); pci_disable_device(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; }
static int tw68_suspend(struct pci_dev *pci_dev , pm_message_t state) { struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev); struct tw68_dev *dev = container_of(v4l2_dev, struct tw68_dev, v4l2_dev); tw_clearl(TW68_DMAC, TW68_DMAP_EN | TW68_FIFO_EN); dev->pci_irqmask &= ~TW68_VID_INTS; tw_writel(TW68_INTMASK, 0); synchronize_irq(pci_dev->irq); pci_save_state(pci_dev); pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state)); vb2_discard_done(&dev->vidq); return 0; }
int rtl8180_suspend (struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); // struct r8180_priv *priv = ieee80211_priv(dev); if (!netif_running(dev)) goto out_pci_suspend; dev->stop(dev); netif_device_detach(dev); out_pci_suspend: pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev,pci_choose_state(pdev,state)); return 0; }
/* * power management */ static int snd_via82xx_suspend(struct pci_dev *pci, pm_message_t state) { struct snd_card *card = pci_get_drvdata(pci); struct via82xx_modem *chip = card->private_data; int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); for (i = 0; i < 2; i++) snd_pcm_suspend_all(chip->pcms[i]); for (i = 0; i < chip->num_devs; i++) snd_via82xx_channel_reset(chip, &chip->devs[i]); synchronize_irq(chip->irq); snd_ac97_suspend(chip->ac97); pci_disable_device(pci); pci_save_state(pci); pci_set_power_state(pci, pci_choose_state(pci, state)); return 0; }
/*************************************************************************/ /*! @Function OSPCISuspendDev @Description Prepare PCI device to be turned off by power management @Input hPVRPCI PCI device handle @Return PVRSRV_ERROR Services error code */ /**************************************************************************/ PVRSRV_ERROR OSPCISuspendDev(PVRSRV_PCI_DEV_HANDLE hPVRPCI) { PVR_PCI_DEV *psPVRPCI = (PVR_PCI_DEV *)hPVRPCI; int i; int err; /* Release all PCI regions that are currently in use */ for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { if (psPVRPCI->abPCIResourceInUse[i]) { pci_release_region(psPVRPCI->psPCIDev, i); } } err = pci_save_state(psPVRPCI->psPCIDev); if (err != 0) { printk(KERN_ERR "OSPCISuspendDev: pci_save_state_failed (%d)", err); return PVRSRV_ERROR_PCI_CALL_FAILED; } pci_disable_device(psPVRPCI->psPCIDev); err = pci_set_power_state(psPVRPCI->psPCIDev, pci_choose_state(psPVRPCI->psPCIDev, PMSG_SUSPEND)); switch(err) { case 0: break; case -EIO: printk(KERN_ERR "OSPCISuspendDev: device doesn't support PCI PM"); break; case -EINVAL: printk(KERN_ERR "OSPCISuspendDev: can't enter requested power state"); break; default: printk(KERN_ERR "OSPCISuspendDev: pci_set_power_state failed (%d)", err); break; } return PVRSRV_OK; }
static int be_suspend(struct pci_dev *pdev, pm_message_t state) { struct be_adapter *adapter = pci_get_drvdata(pdev); struct net_device *netdev = adapter->netdevp; struct be_net_object *pnob = netdev_priv(netdev); adapter->dev_pm_state = adapter->dev_state; adapter->dev_state = BE_DEV_STATE_SUSPEND; netif_device_detach(netdev); if (netif_running(netdev)) be_pm_cleanup(adapter, pnob, netdev); pci_enable_wake(pdev, 3, 1); pci_enable_wake(pdev, 4, 1); /* D3 Cold = 4 */ pci_save_state(pdev); pci_disable_device(pdev); pci_set_power_state(pdev, pci_choose_state(pdev, state)); return 0; }
static int snd_atiixp_pcm_open(struct snd_pcm_substream *substream, struct atiixp_dma *dma, int pcm_type) { struct atiixp_modem *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int err; static unsigned int rates[] = { 8000, 9600, 12000, 16000 }; static struct snd_pcm_hw_constraint_list hw_constraints_rates = { .count = ARRAY_SIZE(rates), .list = rates, .mask = 0, }; if (snd_BUG_ON(!dma->ops || !dma->ops->enable_dma)) return -EINVAL; if (dma->opened) return -EBUSY; dma->substream = substream; runtime->hw = snd_atiixp_pcm_hw; dma->ac97_pcm_type = pcm_type; if ((err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates)) < 0) return err; if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err; runtime->private_data = dma; /* */ spin_lock_irq(&chip->reg_lock); dma->ops->enable_dma(chip, 1); spin_unlock_irq(&chip->reg_lock); dma->opened = 1; return 0; } static int snd_atiixp_pcm_close(struct snd_pcm_substream *substream, struct atiixp_dma *dma) { struct atiixp_modem *chip = snd_pcm_substream_chip(substream); /* */ if (snd_BUG_ON(!dma->ops || !dma->ops->enable_dma)) return -EINVAL; spin_lock_irq(&chip->reg_lock); dma->ops->enable_dma(chip, 0); spin_unlock_irq(&chip->reg_lock); dma->substream = NULL; dma->opened = 0; return 0; } /* */ static int snd_atiixp_playback_open(struct snd_pcm_substream *substream) { struct atiixp_modem *chip = snd_pcm_substream_chip(substream); int err; mutex_lock(&chip->open_mutex); err = snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_PLAYBACK], 0); mutex_unlock(&chip->open_mutex); if (err < 0) return err; return 0; } static int snd_atiixp_playback_close(struct snd_pcm_substream *substream) { struct atiixp_modem *chip = snd_pcm_substream_chip(substream); int err; mutex_lock(&chip->open_mutex); err = snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_PLAYBACK]); mutex_unlock(&chip->open_mutex); return err; } static int snd_atiixp_capture_open(struct snd_pcm_substream *substream) { struct atiixp_modem *chip = snd_pcm_substream_chip(substream); return snd_atiixp_pcm_open(substream, &chip->dmas[ATI_DMA_CAPTURE], 1); } static int snd_atiixp_capture_close(struct snd_pcm_substream *substream) { struct atiixp_modem *chip = snd_pcm_substream_chip(substream); return snd_atiixp_pcm_close(substream, &chip->dmas[ATI_DMA_CAPTURE]); } /* */ static struct snd_pcm_ops snd_atiixp_playback_ops = { .open = snd_atiixp_playback_open, .close = snd_atiixp_playback_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_atiixp_pcm_hw_params, .hw_free = snd_atiixp_pcm_hw_free, .prepare = snd_atiixp_playback_prepare, .trigger = snd_atiixp_pcm_trigger, .pointer = snd_atiixp_pcm_pointer, }; /* */ static struct snd_pcm_ops snd_atiixp_capture_ops = { .open = snd_atiixp_capture_open, .close = snd_atiixp_capture_close, .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_atiixp_pcm_hw_params, .hw_free = snd_atiixp_pcm_hw_free, .prepare = snd_atiixp_capture_prepare, .trigger = snd_atiixp_pcm_trigger, .pointer = snd_atiixp_pcm_pointer, }; static struct atiixp_dma_ops snd_atiixp_playback_dma_ops = { .type = ATI_DMA_PLAYBACK, .llp_offset = ATI_REG_MODEM_OUT_DMA1_LINKPTR, .dt_cur = ATI_REG_MODEM_OUT_DMA1_DT_CUR, .enable_dma = atiixp_out_enable_dma, .enable_transfer = atiixp_out_enable_transfer, .flush_dma = atiixp_out_flush_dma, }; static struct atiixp_dma_ops snd_atiixp_capture_dma_ops = { .type = ATI_DMA_CAPTURE, .llp_offset = ATI_REG_MODEM_IN_DMA_LINKPTR, .dt_cur = ATI_REG_MODEM_IN_DMA_DT_CUR, .enable_dma = atiixp_in_enable_dma, .enable_transfer = atiixp_in_enable_transfer, .flush_dma = atiixp_in_flush_dma, }; static int __devinit snd_atiixp_pcm_new(struct atiixp_modem *chip) { struct snd_pcm *pcm; int err; /* */ chip->dmas[ATI_DMA_PLAYBACK].ops = &snd_atiixp_playback_dma_ops; chip->dmas[ATI_DMA_CAPTURE].ops = &snd_atiixp_capture_dma_ops; /* */ err = snd_pcm_new(chip->card, "ATI IXP MC97", ATI_PCMDEV_ANALOG, 1, 1, &pcm); if (err < 0) return err; snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_atiixp_playback_ops); snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_atiixp_capture_ops); pcm->dev_class = SNDRV_PCM_CLASS_MODEM; pcm->private_data = chip; strcpy(pcm->name, "ATI IXP MC97"); chip->pcmdevs[ATI_PCMDEV_ANALOG] = pcm; snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), 64*1024, 128*1024); return 0; } /* */ static irqreturn_t snd_atiixp_interrupt(int irq, void *dev_id) { struct atiixp_modem *chip = dev_id; unsigned int status; status = atiixp_read(chip, ISR); if (! status) return IRQ_NONE; /* */ if (status & ATI_REG_ISR_MODEM_OUT1_XRUN) snd_atiixp_xrun_dma(chip, &chip->dmas[ATI_DMA_PLAYBACK]); else if (status & ATI_REG_ISR_MODEM_OUT1_STATUS) snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_PLAYBACK]); if (status & ATI_REG_ISR_MODEM_IN_XRUN) snd_atiixp_xrun_dma(chip, &chip->dmas[ATI_DMA_CAPTURE]); else if (status & ATI_REG_ISR_MODEM_IN_STATUS) snd_atiixp_update_dma(chip, &chip->dmas[ATI_DMA_CAPTURE]); /* */ if (status & CODEC_CHECK_BITS) { unsigned int detected; detected = status & CODEC_CHECK_BITS; spin_lock(&chip->reg_lock); chip->codec_not_ready_bits |= detected; atiixp_update(chip, IER, detected, 0); /* */ spin_unlock(&chip->reg_lock); } /* */ atiixp_write(chip, ISR, status); return IRQ_HANDLED; } /* */ static int __devinit snd_atiixp_mixer_new(struct atiixp_modem *chip, int clock) { struct snd_ac97_bus *pbus; struct snd_ac97_template ac97; int i, err; int codec_count; static struct snd_ac97_bus_ops ops = { .write = snd_atiixp_ac97_write, .read = snd_atiixp_ac97_read, }; static unsigned int codec_skip[NUM_ATI_CODECS] = { ATI_REG_ISR_CODEC0_NOT_READY, ATI_REG_ISR_CODEC1_NOT_READY, ATI_REG_ISR_CODEC2_NOT_READY, }; if (snd_atiixp_codec_detect(chip) < 0) return -ENXIO; if ((err = snd_ac97_bus(chip->card, 0, &ops, chip, &pbus)) < 0) return err; pbus->clock = clock; chip->ac97_bus = pbus; codec_count = 0; for (i = 0; i < NUM_ATI_CODECS; i++) { if (chip->codec_not_ready_bits & codec_skip[i]) continue; memset(&ac97, 0, sizeof(ac97)); ac97.private_data = chip; ac97.pci = chip->pci; ac97.num = i; ac97.scaps = AC97_SCAP_SKIP_AUDIO | AC97_SCAP_POWER_SAVE; if ((err = snd_ac97_mixer(pbus, &ac97, &chip->ac97[i])) < 0) { chip->ac97[i] = NULL; /* */ snd_printdd("atiixp-modem: codec %d not available for modem\n", i); continue; } codec_count++; } if (! codec_count) { snd_printk(KERN_ERR "atiixp-modem: no codec available\n"); return -ENODEV; } /* */ return 0; } #ifdef CONFIG_PM /* */ static int snd_atiixp_suspend(struct pci_dev *pci, pm_message_t state) { struct snd_card *card = pci_get_drvdata(pci); struct atiixp_modem *chip = card->private_data; int i; snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); for (i = 0; i < NUM_ATI_PCMDEVS; i++) snd_pcm_suspend_all(chip->pcmdevs[i]); for (i = 0; i < NUM_ATI_CODECS; i++) snd_ac97_suspend(chip->ac97[i]); snd_atiixp_aclink_down(chip); snd_atiixp_chip_stop(chip); pci_disable_device(pci); pci_save_state(pci); pci_set_power_state(pci, pci_choose_state(pci, state)); return 0; } static int snd_atiixp_resume(struct pci_dev *pci) { struct snd_card *card = pci_get_drvdata(pci); struct atiixp_modem *chip = card->private_data; int i; pci_set_power_state(pci, PCI_D0); pci_restore_state(pci); if (pci_enable_device(pci) < 0) { printk(KERN_ERR "atiixp-modem: pci_enable_device failed, " "disabling device\n"); snd_card_disconnect(card); return -EIO; } pci_set_master(pci); snd_atiixp_aclink_reset(chip); snd_atiixp_chip_start(chip); for (i = 0; i < NUM_ATI_CODECS; i++) snd_ac97_resume(chip->ac97[i]); snd_power_change_state(card, SNDRV_CTL_POWER_D0); return 0; } #endif /* */ #ifdef CONFIG_PROC_FS /* */ static void snd_atiixp_proc_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer) { struct atiixp_modem *chip = entry->private_data; int i; for (i = 0; i < 256; i += 4) snd_iprintf(buffer, "%02x: %08x\n", i, readl(chip->remap_addr + i)); } static void __devinit snd_atiixp_proc_init(struct atiixp_modem *chip) { struct snd_info_entry *entry; if (! snd_card_proc_new(chip->card, "atiixp-modem", &entry)) snd_info_set_text_ops(entry, chip, snd_atiixp_proc_read); } #else #define snd_atiixp_proc_init(chip) #endif /* */ static int snd_atiixp_free(struct atiixp_modem *chip) { if (chip->irq < 0) goto __hw_end; snd_atiixp_chip_stop(chip); __hw_end: if (chip->irq >= 0) free_irq(chip->irq, chip); if (chip->remap_addr) iounmap(chip->remap_addr); pci_release_regions(chip->pci); pci_disable_device(chip->pci); kfree(chip); return 0; } static int snd_atiixp_dev_free(struct snd_device *device) { struct atiixp_modem *chip = device->device_data; return snd_atiixp_free(chip); } /* */ static int __devinit snd_atiixp_create(struct snd_card *card, struct pci_dev *pci, struct atiixp_modem **r_chip) { static struct snd_device_ops ops = { .dev_free = snd_atiixp_dev_free, }; struct atiixp_modem *chip; int err; if ((err = pci_enable_device(pci)) < 0) return err; chip = kzalloc(sizeof(*chip), GFP_KERNEL); if (chip == NULL) { pci_disable_device(pci); return -ENOMEM; } spin_lock_init(&chip->reg_lock); mutex_init(&chip->open_mutex); chip->card = card; chip->pci = pci; chip->irq = -1; if ((err = pci_request_regions(pci, "ATI IXP MC97")) < 0) { kfree(chip); pci_disable_device(pci); return err; } chip->addr = pci_resource_start(pci, 0); chip->remap_addr = pci_ioremap_bar(pci, 0); if (chip->remap_addr == NULL) { snd_printk(KERN_ERR "AC'97 space ioremap problem\n"); snd_atiixp_free(chip); return -EIO; } if (request_irq(pci->irq, snd_atiixp_interrupt, IRQF_SHARED, KBUILD_MODNAME, chip)) { snd_printk(KERN_ERR "unable to grab IRQ %d\n", pci->irq); snd_atiixp_free(chip); return -EBUSY; } chip->irq = pci->irq; pci_set_master(pci); synchronize_irq(chip->irq); if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { snd_atiixp_free(chip); return err; } snd_card_set_dev(card, &pci->dev); *r_chip = chip; return 0; } static int __devinit snd_atiixp_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) { struct snd_card *card; struct atiixp_modem *chip; int err; err = snd_card_create(index, id, THIS_MODULE, 0, &card); if (err < 0) return err; strcpy(card->driver, "ATIIXP-MODEM"); strcpy(card->shortname, "ATI IXP Modem"); if ((err = snd_atiixp_create(card, pci, &chip)) < 0) goto __error; card->private_data = chip; if ((err = snd_atiixp_aclink_reset(chip)) < 0) goto __error; if ((err = snd_atiixp_mixer_new(chip, ac97_clock)) < 0) goto __error; if ((err = snd_atiixp_pcm_new(chip)) < 0) goto __error; snd_atiixp_proc_init(chip); snd_atiixp_chip_start(chip); sprintf(card->longname, "%s rev %x at 0x%lx, irq %i", card->shortname, pci->revision, chip->addr, chip->irq); if ((err = snd_card_register(card)) < 0) goto __error; pci_set_drvdata(pci, card); return 0; __error: snd_card_free(card); return err; } static void __devexit snd_atiixp_remove(struct pci_dev *pci) { snd_card_free(pci_get_drvdata(pci)); pci_set_drvdata(pci, NULL); }