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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* -*- c-basic-offset: 8 -*-
  2.  *
  3.  * cmp.c - Connection Management Procedures
  4.  * Copyright (C) 2001 Kristian H鴊sberg
  5.  *
  6.  * This program is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; either version 2 of the License, or
  9.  * (at your option) any later version.
  10.  *
  11.  * This program is distributed in the hope that it will be useful,
  12.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  * GNU General Public License for more details.
  15.  *
  16.  * You should have received a copy of the GNU General Public License
  17.  * along with this program; if not, write to the Free Software Foundation,
  18.  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  19.  */
  20. /* TODO
  21.  * ----
  22.  *
  23.  * - Implement IEC61883-1 output plugs and connection management.
  24.  *   This should probably be part of the general subsystem, as it could
  25.  *   be shared with dv1394.
  26.  *
  27.  * - Add IEC61883 unit directory when loading this module.  This
  28.  *   requires a run-time changeable config rom.
  29.  */
  30. #include <linux/module.h>
  31. #include <linux/list.h>
  32. #include <linux/sched.h>
  33. #include <linux/types.h>
  34. #include <linux/wait.h>
  35. #include "hosts.h"
  36. #include "highlevel.h"
  37. #include "ieee1394.h"
  38. #include "ieee1394_core.h"
  39. #include "cmp.h"
  40. struct plug {
  41. union {
  42. struct cmp_pcr pcr;
  43. quadlet_t quadlet;
  44. } u;
  45. void (*update)(struct cmp_pcr *plug, void *data);
  46. void *data;
  47. };
  48. struct cmp_host {
  49. struct hpsb_host *host;
  50. union {
  51. struct cmp_mpr ompr;
  52. quadlet_t ompr_quadlet;
  53. } u;
  54. struct plug opcr[2];
  55. union {
  56. struct cmp_mpr impr;
  57. quadlet_t impr_quadlet;
  58. } v;
  59. struct plug ipcr[2];
  60. struct list_head link;
  61. };
  62. enum {
  63. CMP_P2P_CONNECTION,
  64. CMP_BC_CONNECTION
  65. };
  66. #define CSR_PCR_MAP      0x900
  67. #define CSR_PCR_MAP_END  0x9fc
  68. static struct hpsb_highlevel *cmp_highlevel;
  69. static LIST_HEAD(host_list);
  70. static spinlock_t host_list_lock = SPIN_LOCK_UNLOCKED;
  71. static struct cmp_host *
  72. lookup_cmp_host(struct hpsb_host *host)
  73. {
  74. struct cmp_host *ch;
  75. struct list_head *lh;
  76. unsigned long flags;
  77. ch = NULL;
  78. spin_lock_irqsave(&host_list_lock, flags);
  79. list_for_each(lh, &host_list) {
  80. ch = list_entry(lh, struct cmp_host, link);
  81. if (ch->host == host)
  82. break;
  83. }
  84. spin_unlock_irqrestore(&host_list_lock, flags);
  85. if (lh == &host_list)
  86. return NULL;
  87. else
  88. return ch;
  89. }
  90. struct cmp_pcr *
  91. cmp_register_opcr(struct hpsb_host *host, int opcr_number, int payload,
  92.   void (*update)(struct cmp_pcr *pcr, void *data),
  93.   void *data)
  94. {
  95. struct cmp_host *ch;
  96. struct plug *plug;
  97. ch = lookup_cmp_host(host);
  98. if (opcr_number >= ch->u.ompr.nplugs ||
  99.     ch->opcr[opcr_number].update != NULL)
  100. return NULL;
  101. plug = &ch->opcr[opcr_number];
  102. plug->u.pcr.online = 1;
  103. plug->u.pcr.bcast_count = 0;
  104. plug->u.pcr.p2p_count = 0;
  105. plug->u.pcr.overhead = 0;
  106. plug->u.pcr.payload = payload;
  107. plug->update = update;
  108. plug->data = data;
  109. return &plug->u.pcr;
  110. }
  111. void cmp_unregister_opcr(struct hpsb_host *host, struct cmp_pcr *opcr)
  112. {
  113. struct cmp_host *ch;
  114. struct plug *plug;
  115. ch = lookup_cmp_host(host);
  116. plug = (struct plug *)opcr;
  117. if (plug - ch->opcr >= ch->u.ompr.nplugs) BUG();
  118. plug->u.pcr.online = 0;
  119. plug->update = NULL;
  120. }
  121. static void reset_plugs(struct cmp_host *ch)
  122. {
  123. int i;
  124. ch->u.ompr.non_persistent_ext = 0xff;
  125. for (i = 0; i < ch->u.ompr.nplugs; i++) {
  126. ch->opcr[i].u.pcr.bcast_count = 0;
  127. ch->opcr[i].u.pcr.p2p_count = 0;
  128. ch->opcr[i].u.pcr.overhead = 0;
  129. }
  130. }
  131. static void cmp_add_host(struct hpsb_host *host)
  132. {
  133. struct cmp_host *ch;
  134. ch = kmalloc(sizeof *ch, SLAB_KERNEL);
  135. if (ch == NULL) {
  136. HPSB_ERR("Failed to allocate cmp_host");
  137. return;
  138. }
  139. memset(ch, 0, sizeof *ch);
  140. ch->host = host;
  141. ch->u.ompr.rate = SPEED_100;
  142. ch->u.ompr.bcast_channel_base = 63;
  143. ch->u.ompr.nplugs = 2;
  144. reset_plugs(ch);
  145. spin_lock_irq(&host_list_lock);
  146. list_add_tail(&ch->link, &host_list);
  147. spin_unlock_irq(&host_list_lock);
  148. }
  149. static void cmp_host_reset(struct hpsb_host *host)
  150. {
  151. struct cmp_host *ch;
  152. ch = lookup_cmp_host(host);
  153. if (ch == NULL) BUG();
  154. reset_plugs(ch);
  155. }
  156. static void cmp_remove_host(struct hpsb_host *host)
  157. {
  158. struct cmp_host *ch;
  159. ch = lookup_cmp_host(host);
  160. if (ch == NULL) BUG();
  161. spin_lock_irq(&host_list_lock);
  162. list_del(&ch->link);
  163. spin_unlock_irq(&host_list_lock);
  164. kfree(ch);
  165. }
  166. static int pcr_read(struct hpsb_host *host, int nodeid, quadlet_t *buf,
  167.     u64 addr, unsigned int length)
  168. {
  169. int csraddr = addr - CSR_REGISTER_BASE;
  170. int plug;
  171. struct cmp_host *ch;
  172. if (length != 4)
  173. return RCODE_TYPE_ERROR;
  174. ch = lookup_cmp_host(host);
  175. if (csraddr == 0x900) {
  176. *buf = cpu_to_be32(ch->u.ompr_quadlet);
  177. return RCODE_COMPLETE;   
  178. }
  179. else if (csraddr < 0x904 + ch->u.ompr.nplugs * 4) {
  180. plug = (csraddr - 0x904) / 4;
  181. *buf = cpu_to_be32(ch->opcr[plug].u.quadlet);
  182. return RCODE_COMPLETE;
  183. }
  184. else if (csraddr < 0x980) {
  185. return RCODE_ADDRESS_ERROR;
  186. }
  187. else if (csraddr == 0x980) {
  188. *buf = cpu_to_be32(ch->v.impr_quadlet);
  189. return RCODE_COMPLETE;   
  190. }
  191. else if (csraddr < 0x984 + ch->v.impr.nplugs * 4) {
  192. plug = (csraddr - 0x984) / 4;
  193. *buf = cpu_to_be32(ch->ipcr[plug].u.quadlet);
  194. return RCODE_COMPLETE;
  195. }
  196. else
  197. return RCODE_ADDRESS_ERROR;
  198. }
  199. static int pcr_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
  200.     u64 addr, quadlet_t data, quadlet_t arg, int extcode)
  201. {
  202. int csraddr = addr - CSR_REGISTER_BASE;
  203. int plug;
  204. struct cmp_host *ch;
  205. ch = lookup_cmp_host(host);
  206. if (extcode != EXTCODE_COMPARE_SWAP) 
  207. return RCODE_TYPE_ERROR;
  208. if (csraddr == 0x900) {
  209. /* FIXME: Ignore writes to bits 30-31 and 0-7 */
  210. *store = cpu_to_be32(ch->u.ompr_quadlet);
  211. if (arg == cpu_to_be32(ch->u.ompr_quadlet))
  212. ch->u.ompr_quadlet = be32_to_cpu(data);
  213. return RCODE_COMPLETE;
  214. }
  215. if (csraddr < 0x904 + ch->u.ompr.nplugs * 4) {
  216. plug = (csraddr - 0x904) / 4;
  217. *store = cpu_to_be32(ch->opcr[plug].u.quadlet);
  218. if (arg == *store)
  219. ch->opcr[plug].u.quadlet = be32_to_cpu(data);
  220. if (be32_to_cpu(*store) != ch->opcr[plug].u.quadlet &&
  221.     ch->opcr[plug].update != NULL)
  222. ch->opcr[plug].update(&ch->opcr[plug].u.pcr,
  223.       ch->opcr[plug].data);
  224. return RCODE_COMPLETE;
  225. }
  226. else if (csraddr < 0x980) {
  227. return RCODE_ADDRESS_ERROR;
  228. }
  229. else if (csraddr == 0x980) {
  230. /* FIXME: Ignore writes to bits 24-31 and 0-7 */
  231. *store = cpu_to_be32(ch->u.ompr_quadlet);
  232. if (arg == cpu_to_be32(ch->u.ompr_quadlet))
  233. ch->u.ompr_quadlet = be32_to_cpu(data);
  234. return RCODE_COMPLETE;
  235. }
  236. else if (csraddr < 0x984 + ch->v.impr.nplugs * 4) {
  237. plug = (csraddr - 0x984) / 4;
  238. *store = cpu_to_be32(ch->ipcr[plug].u.quadlet);
  239. if (arg == *store)
  240. ch->ipcr[plug].u.quadlet = be32_to_cpu(data);
  241. if (be32_to_cpu(*store) != ch->ipcr[plug].u.quadlet &&
  242.     ch->ipcr[plug].update != NULL)
  243. ch->ipcr[plug].update(&ch->ipcr[plug].u.pcr,
  244.       ch->ipcr[plug].data);
  245. return RCODE_COMPLETE;
  246. }
  247. else
  248. return RCODE_ADDRESS_ERROR;
  249. }
  250. static struct hpsb_highlevel_ops cmp_highlevel_ops = {
  251. .add_host = cmp_add_host,
  252. .remove_host = cmp_remove_host,
  253.         .host_reset = cmp_host_reset,
  254. };
  255. static struct hpsb_address_ops pcr_ops = {
  256. .read = pcr_read,
  257.         .lock = pcr_lock,
  258. };
  259. /* Module interface */
  260. MODULE_AUTHOR("Kristian Hogsberg <hogsberg@users.sf.net>");
  261. MODULE_DESCRIPTION("Connection Management Procedures (CMP)");
  262. MODULE_SUPPORTED_DEVICE("cmp");
  263. MODULE_LICENSE("GPL");
  264. EXPORT_SYMBOL(cmp_register_opcr);
  265. EXPORT_SYMBOL(cmp_unregister_opcr);
  266. static int __init cmp_init_module (void)
  267. {
  268. cmp_highlevel = hpsb_register_highlevel ("cmp",
  269.  &cmp_highlevel_ops);
  270. if (cmp_highlevel == NULL) {
  271. HPSB_ERR("cmp: unable to register highlevel ops");
  272. return -EIO;
  273. }
  274. hpsb_register_addrspace(cmp_highlevel, &pcr_ops,
  275. CSR_REGISTER_BASE + CSR_PCR_MAP,
  276. CSR_REGISTER_BASE + CSR_PCR_MAP_END);
  277. HPSB_INFO("Loaded CMP driver");
  278. return 0;
  279. }
  280. static void __exit cmp_exit_module (void)
  281. {
  282.         hpsb_unregister_highlevel(cmp_highlevel);
  283. HPSB_INFO("Unloaded CMP driver");
  284. }
  285. module_init(cmp_init_module);
  286. module_exit(cmp_exit_module);