highlevel.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:12k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * IEEE 1394 for Linux
  3.  *
  4.  * Copyright (C) 1999 Andreas E. Bombe
  5.  *
  6.  * This code is licensed under the GPL.  See the file COPYING in the root
  7.  * directory of the kernel sources for details.
  8.  */
  9. #include <linux/config.h>
  10. #include <linux/slab.h>
  11. #include "ieee1394.h"
  12. #include "ieee1394_types.h"
  13. #include "hosts.h"
  14. #include "ieee1394_core.h"
  15. #include "highlevel.h"
  16. LIST_HEAD(hl_drivers);
  17. rwlock_t hl_drivers_lock = RW_LOCK_UNLOCKED;
  18. LIST_HEAD(addr_space);
  19. rwlock_t addr_space_lock = RW_LOCK_UNLOCKED;
  20. /* addr_space list will have zero and max already included as bounds */
  21. static struct hpsb_address_ops dummy_ops = { NULL, NULL, NULL, NULL };
  22. static struct hpsb_address_serve dummy_zero_addr, dummy_max_addr;
  23. struct hpsb_highlevel *hpsb_register_highlevel(const char *name,
  24.                                                struct hpsb_highlevel_ops *ops)
  25. {
  26.         struct hpsb_highlevel *hl;
  27.         hl = (struct hpsb_highlevel *)kmalloc(sizeof(struct hpsb_highlevel),
  28.                                               GFP_KERNEL);
  29.         if (hl == NULL) {
  30.                 return NULL;
  31.         }
  32.         INIT_LIST_HEAD(&hl->hl_list);
  33.         INIT_LIST_HEAD(&hl->addr_list);
  34.         hl->name = name;
  35.         hl->op = ops;
  36.         write_lock_irq(&hl_drivers_lock);
  37.         hl_all_hosts(hl, 1);
  38.         list_add_tail(&hl->hl_list, &hl_drivers);
  39.         write_unlock_irq(&hl_drivers_lock);
  40.         return hl;
  41. }
  42. void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
  43. {
  44.         struct list_head *entry;
  45.         struct hpsb_address_serve *as;
  46.         if (hl == NULL) {
  47.                 return;
  48.         }
  49.         write_lock_irq(&addr_space_lock);
  50.         entry = hl->addr_list.next;
  51.         while (entry != &hl->addr_list) {
  52.                 as = list_entry(entry, struct hpsb_address_serve, addr_list);
  53.                 list_del(&as->as_list);
  54.                 entry = entry->next;
  55.                 kfree(as);
  56.         }
  57.         write_unlock_irq(&addr_space_lock);
  58.         write_lock_irq(&hl_drivers_lock);
  59.         list_del(&hl->hl_list);
  60.         hl_all_hosts(hl, 0);
  61.         write_unlock_irq(&hl_drivers_lock);
  62.         kfree(hl);
  63. }
  64. int hpsb_register_addrspace(struct hpsb_highlevel *hl,
  65.                             struct hpsb_address_ops *ops, u64 start, u64 end)
  66. {
  67.         struct hpsb_address_serve *as;
  68.         struct list_head *entry;
  69.         int retval = 0;
  70.         if (((start|end) & 3) || (start >= end) || (end > 0x1000000000000ULL)) {
  71.                 HPSB_ERR(__FUNCTION__ " called with invalid addresses");
  72.                 return 0;
  73.         }
  74.         as = (struct hpsb_address_serve *)
  75.                 kmalloc(sizeof(struct hpsb_address_serve), GFP_KERNEL);
  76.         if (as == NULL) {
  77.                 return 0;
  78.         }
  79.         INIT_LIST_HEAD(&as->as_list);
  80.         INIT_LIST_HEAD(&as->addr_list);
  81.         as->op = ops;
  82.         as->start = start;
  83.         as->end = end;
  84.         write_lock_irq(&addr_space_lock);
  85.         entry = addr_space.next;
  86.         while (list_entry(entry, struct hpsb_address_serve, as_list)->end
  87.                <= start) {
  88.                 if (list_entry(entry->next, struct hpsb_address_serve, as_list)
  89.                     ->start >= end) {
  90.                         list_add(&as->as_list, entry);
  91.                         list_add_tail(&as->addr_list, &hl->addr_list);
  92.                         retval = 1;
  93.                         break;
  94.                 }
  95.                 entry = entry->next;
  96.         }
  97.         write_unlock_irq(&addr_space_lock);
  98.         if (retval == 0) {
  99.                 kfree(as);
  100.         }
  101.         return retval;
  102. }
  103. void hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
  104.                          unsigned int channel)
  105. {
  106.         if (channel > 63) {
  107.                 HPSB_ERR(__FUNCTION__ " called with invalid channel");
  108.                 return;
  109.         }
  110.         if (host->iso_listen_count[channel]++ == 0) {
  111.                 host->template->devctl(host, ISO_LISTEN_CHANNEL, channel);
  112.         }
  113. }
  114. void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host, 
  115.                            unsigned int channel)
  116. {
  117.         if (channel > 63) {
  118.                 HPSB_ERR(__FUNCTION__ " called with invalid channel");
  119.                 return;
  120.         }
  121.         if (--host->iso_listen_count[channel] == 0) {
  122.                 host->template->devctl(host, ISO_UNLISTEN_CHANNEL, channel);
  123.         }
  124. }
  125. #define DEFINE_MULTIPLEXER(Function)
  126. void highlevel_##Function(struct hpsb_host *host)
  127. {
  128. struct list_head *lh;
  129. void (*funcptr)(struct hpsb_host*);
  130. read_lock(&hl_drivers_lock);
  131. list_for_each(lh, &hl_drivers) {
  132. funcptr = list_entry(lh, struct hpsb_highlevel, hl_list) 
  133. ->op->Function;
  134. if (funcptr) funcptr(host);
  135. }
  136. read_unlock(&hl_drivers_lock);
  137. }
  138. DEFINE_MULTIPLEXER(add_host)
  139. DEFINE_MULTIPLEXER(remove_host)
  140. DEFINE_MULTIPLEXER(host_reset)
  141. #undef DEFINE_MULTIPLEXER
  142. /* Add one host to our list */
  143. void highlevel_add_one_host (struct hpsb_host *host)
  144. {
  145. if (host->template->initialize_host)
  146. if (!host->template->initialize_host(host))
  147. goto fail;
  148. host->initialized = 1;
  149. highlevel_add_host (host);
  150. hpsb_reset_bus (host, LONG_RESET);
  151. fail:
  152. host->template->number_of_hosts++;
  153. }
  154. void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data,
  155.                            unsigned int length)
  156. {
  157.         struct list_head *entry;
  158.         struct hpsb_highlevel *hl;
  159.         int channel = (data[0] >> 8) & 0x3f;
  160.         read_lock(&hl_drivers_lock);
  161.         entry = hl_drivers.next;
  162.         while (entry != &hl_drivers) {
  163.                 hl = list_entry(entry, struct hpsb_highlevel, hl_list);
  164.                 if (hl->op->iso_receive) {
  165.                         hl->op->iso_receive(host, channel, data, length);
  166.                 }
  167.                 entry = entry->next;
  168.         }
  169.         read_unlock(&hl_drivers_lock);
  170. }
  171. void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
  172.                            u8 *data, unsigned int length)
  173. {
  174.         struct list_head *entry;
  175.         struct hpsb_highlevel *hl;
  176.         int cts = data[0] >> 4;
  177.         read_lock(&hl_drivers_lock);
  178.         entry = hl_drivers.next;
  179.         while (entry != &hl_drivers) {
  180.                 hl = list_entry(entry, struct hpsb_highlevel, hl_list);
  181.                 if (hl->op->fcp_request) {
  182.                         hl->op->fcp_request(host, nodeid, direction, cts, data,
  183.                                             length);
  184.                 }
  185.                 entry = entry->next;
  186.         }
  187.         read_unlock(&hl_drivers_lock);
  188. }
  189. int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
  190.                    u64 addr, unsigned int length)
  191. {
  192.         struct hpsb_address_serve *as;
  193.         struct list_head *entry;
  194.         unsigned int partlength;
  195.         int rcode = RCODE_ADDRESS_ERROR;
  196.         read_lock(&addr_space_lock);
  197.         entry = addr_space.next;
  198.         as = list_entry(entry, struct hpsb_address_serve, as_list);
  199.         while (as->start <= addr) {
  200.                 if (as->end > addr) {
  201.                         partlength = MIN((unsigned int)(as->end - addr),
  202.                                          length);
  203.                         if (as->op->read != NULL) {
  204.                                 rcode = as->op->read(host, nodeid, buffer, addr,
  205.                                                      partlength);
  206.                         } else {
  207.                                 rcode = RCODE_TYPE_ERROR;
  208.                         }
  209.                         length -= partlength;
  210.                         addr += partlength;
  211.                         if ((rcode != RCODE_COMPLETE) || !length) {
  212.                                 break;
  213.                         }
  214.                 }
  215.                 entry = entry->next;
  216.                 as = list_entry(entry, struct hpsb_address_serve, as_list);
  217.         }
  218.         read_unlock(&addr_space_lock);
  219.         if (length && (rcode == RCODE_COMPLETE)) {
  220.                 rcode = RCODE_ADDRESS_ERROR;
  221.         }
  222.         return rcode;
  223. }
  224. int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
  225.     quadlet_t *data, u64 addr, unsigned int length)
  226. {
  227.         struct hpsb_address_serve *as;
  228.         struct list_head *entry;
  229.         unsigned int partlength;
  230.         int rcode = RCODE_ADDRESS_ERROR;
  231.         read_lock(&addr_space_lock);
  232.         entry = addr_space.next;
  233.         as = list_entry(entry, struct hpsb_address_serve, as_list);
  234.         while (as->start <= addr) {
  235.                 if (as->end > addr) {
  236.                         partlength = MIN((unsigned int)(as->end - addr),
  237.                                          length);
  238.                         if (as->op->write != NULL) {
  239.                                 rcode = as->op->write(host, nodeid, destid, data,
  240.       addr, partlength);
  241.                         } else {
  242.                                 rcode = RCODE_TYPE_ERROR;
  243.                         }
  244.                         length -= partlength;
  245.                         addr += partlength;
  246.                         if ((rcode != RCODE_COMPLETE) || !length) {
  247.                                 break;
  248.                         }
  249.                 }
  250.                 entry = entry->next;
  251.                 as = list_entry(entry, struct hpsb_address_serve, as_list);
  252.         }
  253.         read_unlock(&addr_space_lock);
  254.         if (length && (rcode == RCODE_COMPLETE)) {
  255.                 rcode = RCODE_ADDRESS_ERROR;
  256.         }
  257.         return rcode;
  258. }
  259. int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
  260.                    u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode)
  261. {
  262.         struct hpsb_address_serve *as;
  263.         struct list_head *entry;
  264.         int rcode = RCODE_ADDRESS_ERROR;
  265.         read_lock(&addr_space_lock);
  266.         entry = addr_space.next;
  267.         as = list_entry(entry, struct hpsb_address_serve, as_list);
  268.         while (as->start <= addr) {
  269.                 if (as->end > addr) {
  270.                         if (as->op->lock != NULL) {
  271.                                 rcode = as->op->lock(host, nodeid, store, addr,
  272.                                                      data, arg, ext_tcode);
  273.                         } else {
  274.                                 rcode = RCODE_TYPE_ERROR;
  275.                         }
  276.                         break;
  277.                 }
  278.                 entry = entry->next;
  279.                 as = list_entry(entry, struct hpsb_address_serve, as_list);
  280.         }
  281.         read_unlock(&addr_space_lock);
  282.         return rcode;
  283. }
  284. int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
  285.                      u64 addr, octlet_t data, octlet_t arg, int ext_tcode)
  286. {
  287.         struct hpsb_address_serve *as;
  288.         struct list_head *entry;
  289.         int rcode = RCODE_ADDRESS_ERROR;
  290.         read_lock(&addr_space_lock);
  291.         entry = addr_space.next;
  292.         as = list_entry(entry, struct hpsb_address_serve, as_list);
  293.         while (as->start <= addr) {
  294.                 if (as->end > addr) {
  295.                         if (as->op->lock64 != NULL) {
  296.                                 rcode = as->op->lock64(host, nodeid, store,
  297.                                                        addr, data, arg,
  298.                                                        ext_tcode);
  299.                         } else {
  300.                                 rcode = RCODE_TYPE_ERROR;
  301.                         }
  302.                         break;
  303.                 }
  304.                 entry = entry->next;
  305.                 as = list_entry(entry, struct hpsb_address_serve, as_list);
  306.         }
  307.         read_unlock(&addr_space_lock);
  308.         return rcode;
  309. }
  310. void init_hpsb_highlevel(void)
  311. {
  312.         INIT_LIST_HEAD(&dummy_zero_addr.as_list);
  313.         INIT_LIST_HEAD(&dummy_zero_addr.addr_list);
  314.         INIT_LIST_HEAD(&dummy_max_addr.as_list);
  315.         INIT_LIST_HEAD(&dummy_max_addr.addr_list);
  316.         dummy_zero_addr.op = dummy_max_addr.op = &dummy_ops;
  317.         dummy_zero_addr.start = dummy_zero_addr.end = 0;
  318.         dummy_max_addr.start = dummy_max_addr.end = ((u64) 1) << 48;
  319.         list_add_tail(&dummy_zero_addr.as_list, &addr_space);
  320.         list_add_tail(&dummy_max_addr.as_list, &addr_space);
  321. }