hosts.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:5k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  * IEEE 1394 for Linux
  3.  *
  4.  * Low level (host adapter) management.
  5.  *
  6.  * Copyright (C) 1999 Andreas E. Bombe
  7.  * Copyright (C) 1999 Emanuel Pirker
  8.  *
  9.  * This code is licensed under the GPL.  See the file COPYING in the root
  10.  * directory of the kernel sources for details.
  11.  */
  12. #include <linux/config.h>
  13. #include <linux/types.h>
  14. #include <linux/list.h>
  15. #include <linux/init.h>
  16. #include <linux/slab.h>
  17. #include "ieee1394_types.h"
  18. #include "hosts.h"
  19. #include "ieee1394_core.h"
  20. #include "highlevel.h"
  21. static struct list_head hosts = LIST_HEAD_INIT(hosts);
  22. static struct list_head host_drivers = LIST_HEAD_INIT(host_drivers);
  23. spinlock_t hosts_lock = SPIN_LOCK_UNLOCKED;
  24. spinlock_t host_drivers_lock = SPIN_LOCK_UNLOCKED;
  25. static int dummy_transmit_packet(struct hpsb_host *h, struct hpsb_packet *p)
  26. {
  27.         return 0;
  28. }
  29. static int dummy_devctl(struct hpsb_host *h, enum devctl_cmd c, int arg)
  30. {
  31.         return -1;
  32. }
  33. static struct hpsb_host_driver dummy_driver = {
  34.         .transmit_packet = dummy_transmit_packet,
  35.         .devctl =          dummy_devctl
  36. };
  37. /**
  38.  * hpsb_ref_host - increase reference count for host controller.
  39.  * @host: the host controller
  40.  *
  41.  * Increase the reference count for the specified host controller.
  42.  * When holding a reference to a host, the memory allocated for the
  43.  * host struct will not be freed and the host is guaranteed to be in a
  44.  * consistent state.  The driver may be unloaded or the controller may
  45.  * be removed (PCMCIA), but the host struct will remain valid.
  46.  */
  47. int hpsb_ref_host(struct hpsb_host *host)
  48. {
  49.         struct list_head *lh;
  50. unsigned long flags;
  51.         int retval = 0;
  52.         spin_lock_irqsave(&hosts_lock, flags);
  53.         list_for_each(lh, &hosts) {
  54.                 if (host == list_entry(lh, struct hpsb_host, host_list)) {
  55.                         host->driver->devctl(host, MODIFY_USAGE, 1);
  56. host->refcount++;
  57.                         retval = 1;
  58. break;
  59.          }
  60.         }
  61.         spin_unlock_irqrestore(&hosts_lock, flags);
  62.         return retval;
  63. }
  64. /**
  65.  * hpsb_unref_host - decrease reference count for host controller.
  66.  * @host: the host controller
  67.  *
  68.  * Decrease the reference count for the specified host controller.
  69.  * When the reference count reaches zero, the memory allocated for the
  70.  * &hpsb_host will be freed.
  71.  */
  72. void hpsb_unref_host(struct hpsb_host *host)
  73. {
  74.         unsigned long flags;
  75.         host->driver->devctl(host, MODIFY_USAGE, 0);
  76.         spin_lock_irqsave(&hosts_lock, flags);
  77.         host->refcount--;
  78.         if (!host->refcount && host->is_shutdown)
  79.                 kfree(host);
  80.         spin_unlock_irqrestore(&hosts_lock, flags);
  81. }
  82. /**
  83.  * hpsb_alloc_host - allocate a new host controller.
  84.  * @drv: the driver that will manage the host controller
  85.  * @extra: number of extra bytes to allocate for the driver
  86.  *
  87.  * Allocate a &hpsb_host and initialize the general subsystem specific
  88.  * fields.  If the driver needs to store per host data, as drivers
  89.  * usually do, the amount of memory required can be specified by the
  90.  * @extra parameter.  Once allocated, the driver should initialize the
  91.  * driver specific parts, enable the controller and make it available
  92.  * to the general subsystem using hpsb_add_host().
  93.  *
  94.  * The &hpsb_host is allocated with an single initial reference
  95.  * belonging to the driver.  Once the driver is done with the struct,
  96.  * for example, when the driver is unloaded, it should release this
  97.  * reference using hpsb_unref_host().
  98.  *
  99.  * Return Value: a pointer to the &hpsb_host if succesful, %NULL if
  100.  * no memory was available.
  101.  */
  102. struct hpsb_host *hpsb_alloc_host(struct hpsb_host_driver *drv, size_t extra)
  103. {
  104.         struct hpsb_host *h;
  105.         h = kmalloc(sizeof(struct hpsb_host) + extra, SLAB_KERNEL);
  106.         if (!h) return NULL;
  107.         memset(h, 0, sizeof(struct hpsb_host) + extra);
  108. h->hostdata = h + 1;
  109.         h->driver = drv;
  110. h->refcount = 1;
  111.         INIT_LIST_HEAD(&h->pending_packets);
  112.         spin_lock_init(&h->pending_pkt_lock);
  113.         sema_init(&h->tlabel_count, 64);
  114.         spin_lock_init(&h->tlabel_lock);
  115. atomic_set(&h->generation, 0);
  116. INIT_TQUEUE(&h->timeout_tq, (void (*)(void*))abort_timedouts, h);
  117.         h->topology_map = h->csr.topology_map + 3;
  118.         h->speed_map = (u8 *)(h->csr.speed_map + 2);
  119. return h;
  120. }
  121. void hpsb_add_host(struct hpsb_host *host)
  122. {
  123.         unsigned long flags;
  124.         spin_lock_irqsave(&hosts_lock, flags);
  125.         list_add_tail(&host->host_list, &hosts);
  126.         spin_unlock_irqrestore(&hosts_lock, flags);
  127.         highlevel_add_host(host);
  128.         host->driver->devctl(host, RESET_BUS, 0);
  129. }
  130. void hpsb_remove_host(struct hpsb_host *host)
  131. {
  132.         unsigned long flags;
  133.         host->is_shutdown = 1;
  134.         host->driver = &dummy_driver;
  135.         highlevel_remove_host(host);
  136.         spin_lock_irqsave(&hosts_lock, flags);
  137.         list_del(&host->host_list);
  138.         spin_unlock_irqrestore(&hosts_lock, flags);
  139. }
  140. /*
  141.  * This function calls the given function for every host currently registered.
  142.  */
  143. void hl_all_hosts(void (*function)(struct hpsb_host*))
  144. {
  145.         struct list_head *lh;
  146.         struct hpsb_host *host;
  147.         spin_lock_irq(&hosts_lock);
  148.         list_for_each (lh, &hosts) {
  149.                 host = list_entry(lh, struct hpsb_host, host_list);
  150.                 function(host);
  151. }
  152.         spin_unlock_irq(&hosts_lock);
  153. }