Logo Search packages:      
Sourcecode: alsa-driver version File versions

misc.c

#define __NO_VERSION__
#include "../alsa-kernel/core/misc.c"
#include <linux/smp_lock.h>
#include <linux/vmalloc.h>
#include <linux/slab.h>


#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)

#include <linux/slab.h>
#include <asm/io.h>

int try_inc_mod_count(struct module *module)
{
      __MOD_INC_USE_COUNT(module);
      return 1;
}

struct resource *snd_compat_request_region(unsigned long start, unsigned long size, const char *name, int is_memory)
{
      struct resource *resource;

#ifdef CONFIG_SND_DEBUG_MEMORY
      /* DON'T use kmalloc here; the allocated resource is released
       * by kfree without wrapper in each driver
       */
      resource = snd_wrapper_kmalloc(sizeof(struct resource), GFP_KERNEL);
#else
      resource = kmalloc(sizeof(struct resource), GFP_KERNEL);
#endif
      if (resource == NULL)
            return NULL;
      if (! is_memory) {
            if (check_region(start, size)) {
                  kfree_nocheck(resource);
                  return NULL;
            }
            snd_wrapper_request_region(start, size, name);
      }
      memset(resource, 0, sizeof(struct resource));
      resource->name = name;
      resource->start = start;
      resource->end = start + size - 1;
      resource->flags = is_memory ? IORESOURCE_MEM : IORESOURCE_IO;
      return resource;
}

int snd_compat_release_resource(struct resource *resource)
{
      snd_runtime_check(resource != NULL, return -EINVAL);
      if (resource->flags & IORESOURCE_MEM)
            return 0;
      release_region(resource->start, (resource->end - resource->start) + 1);
      return 0;
}

#endif


#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0) && defined(CONFIG_APM)

#include <linux/apm_bios.h>

static spinlock_t pm_devs_lock = SPIN_LOCK_UNLOCKED;
static LIST_HEAD(pm_devs);

#ifdef CONFIG_PCI
static struct pm_dev *pci_compat_pm_dev;
static int pci_compat_pm_callback(struct pm_dev *pdev, pm_request_t rqst, void *data)
{
      struct pci_dev *dev;
      switch (rqst) {
      case PM_SUSPEND:
            pci_for_each_dev(dev) {
                  struct pci_driver *drv = snd_pci_compat_get_pci_driver(dev);
                  if (drv && drv->suspend)
                        drv->suspend(dev, 0);
            }
            break;
      case PM_RESUME:
            pci_for_each_dev(dev) {
                  struct pci_driver *drv = snd_pci_compat_get_pci_driver(dev);
                  if (drv && drv->resume)
                        drv->resume(dev);
            }
            break;
      }     
      return 0;
}
#endif

static int snd_apm_callback(apm_event_t ev)
{
      struct list_head *entry;
      pm_request_t rqst;
      void *data;
      int status;
      
      switch (ev) {
      case APM_SYS_SUSPEND:
      case APM_USER_SUSPEND:
      case APM_CRITICAL_SUSPEND:
            rqst = PM_SUSPEND;
            data = (void *)3;
            break;
      case APM_NORMAL_RESUME:
      case APM_CRITICAL_RESUME:
      case APM_STANDBY_RESUME:            /* ??? */
            rqst = PM_RESUME;
            data = (void *)0;
            break;
      default:
            return 0;
      }
      for (entry = pm_devs.next; entry != &pm_devs; entry = entry->next) {
            struct pm_dev *dev = list_entry(entry, struct pm_dev, entry);
            if ((status = pm_send(dev, rqst, data)))
                  return status;
      }
      return 0;
}

int __init pm_init(void)
{
      if (apm_register_callback(snd_apm_callback))
            snd_printk("apm_register_callback failure!\n");
#ifdef CONFIG_PCI
      pci_compat_pm_dev = pm_register(PM_PCI_DEV, 0, pci_compat_pm_callback);
#endif
      return 0;
}

void __exit pm_done(void)
{
#ifdef CONFIG_PCI
      if (pci_compat_pm_dev)
            pm_unregister(pci_compat_pm_dev);
#endif
      apm_unregister_callback(snd_apm_callback);
}

struct pm_dev *pm_register(pm_dev_t type,
                     unsigned long id,
                     pm_callback callback)
{
      struct pm_dev *dev = kmalloc(sizeof(struct pm_dev), GFP_KERNEL);

      if (dev) {
            unsigned long flags;
            
            memset(dev, 0, sizeof(*dev));
            dev->type = type;
            dev->id = id;
            dev->callback = callback;
            
            spin_lock_irqsave(&pm_devs_lock, flags);
            list_add(&dev->entry, &pm_devs);
            spin_unlock_irqrestore(&pm_devs_lock, flags);
      }
      return dev;
}

void pm_unregister(struct pm_dev *dev)
{
      if (dev) {
            unsigned long flags;
            
            spin_lock_irqsave(&pm_devs_lock, flags);
            list_del(&dev->entry);
            spin_unlock_irqrestore(&pm_devs_lock, flags);

            kfree(dev);
      }
}

int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data)
{
      int status = 0;
      int prev_state, next_state;
      
      switch (rqst) {
      case PM_SUSPEND:
      case PM_RESUME:
            prev_state = dev->state;
            next_state = (int) data;
            if (prev_state != next_state) {
                  if (dev->callback)
                        status = (*dev->callback)(dev, rqst, data);
                  if (!status) {
                        dev->state = next_state;
                        dev->prev_state = prev_state;
                  }
            } else {
                  dev->prev_state = prev_state;
            }
            break;
      default:
            if (dev->callback)
                  status = (*dev->callback)(dev, rqst, data);
            break;
      }
      return status;
}

#endif /* kernel version < 2.3.0 && CONFIG_APM */

/* workqueue-alike; 2.5.45 */
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 45)

static int work_caller(void *data)
{
      struct work_struct *works = data;

#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
      lock_kernel();
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 2, 18)
      daemonize();
#endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0) && LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 8)
      reparent_to_init();
#endif
      strcpy(current->comm, "snd"); /* FIXME: different names? */

      works->func(works->data);

#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
      unlock_kernel();
#endif

      return 0;
}

int snd_compat_schedule_work(struct work_struct *works)
{
      return kernel_thread(work_caller, works, 0) >= 0;
}

#endif

#ifndef CONFIG_HAVE_KCALLOC
#ifndef CONFIG_SND_DEBUG_MEMORY
/* Don't put this to wrappers.c.  We need to call the kmalloc wrapper here. */
void *snd_compat_kcalloc(size_t n, size_t size, int flags)
{
      void *ret = NULL;

      if (n != 0 && size > INT_MAX / n)
            return ret;

      ret = kmalloc(n * size, flags);
      if (ret)
            memset(ret, 0, n * size);
      return ret;
}
#endif
#endif

Generated by  Doxygen 1.6.0   Back to index