1 /* -*- c-basic-offset: 8 -*-
3 * cmp.c - Connection Management Procedures
4 * Copyright (C) 2001 Kristian Høgsberg
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.
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.
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.
24 * - Implement IEC61883-1 output plugs and connection management.
25 * This should probably be part of the general subsystem, as it could
26 * be shared with dv1394.
28 * - Add IEC61883 unit directory when loading this module. This
29 * requires a run-time changeable config rom.
32 #include <linux/module.h>
33 #include <linux/list.h>
34 #include <linux/sched.h>
35 #include <linux/types.h>
36 #include <linux/wait.h>
37 #include <linux/interrupt.h>
40 #include "highlevel.h"
42 #include "ieee1394_core.h"
50 void (*update
)(struct cmp_pcr
*plug
, void *data
);
55 struct hpsb_host
*host
;
59 quadlet_t ompr_quadlet
;
65 quadlet_t impr_quadlet
;
75 #define CSR_PCR_MAP 0x900
76 #define CSR_PCR_MAP_END 0x9fc
78 static struct hpsb_highlevel cmp_highlevel
;
80 static void cmp_add_host(struct hpsb_host
*host
);
81 static void cmp_host_reset(struct hpsb_host
*host
);
82 static int pcr_read(struct hpsb_host
*host
, int nodeid
, quadlet_t
*buf
,
83 u64 addr
, size_t length
, u16 flags
);
84 static int pcr_lock(struct hpsb_host
*host
, int nodeid
, quadlet_t
*store
,
85 u64 addr
, quadlet_t data
, quadlet_t arg
, int extcode
, u16 flags
);
87 static struct hpsb_highlevel cmp_highlevel
= {
89 .add_host
= cmp_add_host
,
90 .host_reset
= cmp_host_reset
,
93 static struct hpsb_address_ops pcr_ops
= {
100 cmp_register_opcr(struct hpsb_host
*host
, int opcr_number
, int payload
,
101 void (*update
)(struct cmp_pcr
*pcr
, void *data
),
107 ch
= hpsb_get_hostinfo(&cmp_highlevel
, host
);
109 if (opcr_number
>= ch
->u
.ompr
.nplugs
||
110 ch
->opcr
[opcr_number
].update
!= NULL
)
113 plug
= &ch
->opcr
[opcr_number
];
114 plug
->u
.pcr
.online
= 1;
115 plug
->u
.pcr
.bcast_count
= 0;
116 plug
->u
.pcr
.p2p_count
= 0;
117 plug
->u
.pcr
.overhead
= 0;
118 plug
->u
.pcr
.payload
= payload
;
119 plug
->update
= update
;
125 void cmp_unregister_opcr(struct hpsb_host
*host
, struct cmp_pcr
*opcr
)
130 ch
= hpsb_get_hostinfo(&cmp_highlevel
, host
);
131 plug
= (struct plug
*)opcr
;
132 if (plug
- ch
->opcr
>= ch
->u
.ompr
.nplugs
) BUG();
134 plug
->u
.pcr
.online
= 0;
138 static void reset_plugs(struct cmp_host
*ch
)
142 ch
->u
.ompr
.non_persistent_ext
= 0xff;
143 for (i
= 0; i
< ch
->u
.ompr
.nplugs
; i
++) {
144 ch
->opcr
[i
].u
.pcr
.bcast_count
= 0;
145 ch
->opcr
[i
].u
.pcr
.p2p_count
= 0;
146 ch
->opcr
[i
].u
.pcr
.overhead
= 0;
150 static void cmp_add_host(struct hpsb_host
*host
)
152 struct cmp_host
*ch
= hpsb_create_hostinfo(&cmp_highlevel
, host
, sizeof (*ch
));
155 HPSB_ERR("Failed to allocate cmp_host");
159 hpsb_register_addrspace(&cmp_highlevel
, host
, &pcr_ops
,
160 CSR_REGISTER_BASE
+ CSR_PCR_MAP
,
161 CSR_REGISTER_BASE
+ CSR_PCR_MAP_END
);
164 ch
->u
.ompr
.rate
= IEEE1394_SPEED_100
;
165 ch
->u
.ompr
.bcast_channel_base
= 63;
166 ch
->u
.ompr
.nplugs
= 2;
171 static void cmp_host_reset(struct hpsb_host
*host
)
175 ch
= hpsb_get_hostinfo(&cmp_highlevel
, host
);
177 HPSB_ERR("cmp: Tried to reset unknown host");
184 static int pcr_read(struct hpsb_host
*host
, int nodeid
, quadlet_t
*buf
,
185 u64 addr
, size_t length
, u16 flags
)
187 int csraddr
= addr
- CSR_REGISTER_BASE
;
192 return RCODE_TYPE_ERROR
;
194 ch
= hpsb_get_hostinfo(&cmp_highlevel
, host
);
195 if (csraddr
== 0x900) {
196 *buf
= cpu_to_be32(ch
->u
.ompr_quadlet
);
197 return RCODE_COMPLETE
;
199 else if (csraddr
< 0x904 + ch
->u
.ompr
.nplugs
* 4) {
200 plug
= (csraddr
- 0x904) / 4;
201 *buf
= cpu_to_be32(ch
->opcr
[plug
].u
.quadlet
);
202 return RCODE_COMPLETE
;
204 else if (csraddr
< 0x980) {
205 return RCODE_ADDRESS_ERROR
;
207 else if (csraddr
== 0x980) {
208 *buf
= cpu_to_be32(ch
->v
.impr_quadlet
);
209 return RCODE_COMPLETE
;
211 else if (csraddr
< 0x984 + ch
->v
.impr
.nplugs
* 4) {
212 plug
= (csraddr
- 0x984) / 4;
213 *buf
= cpu_to_be32(ch
->ipcr
[plug
].u
.quadlet
);
214 return RCODE_COMPLETE
;
217 return RCODE_ADDRESS_ERROR
;
220 static int pcr_lock(struct hpsb_host
*host
, int nodeid
, quadlet_t
*store
,
221 u64 addr
, quadlet_t data
, quadlet_t arg
, int extcode
, u16 flags
)
223 int csraddr
= addr
- CSR_REGISTER_BASE
;
227 ch
= hpsb_get_hostinfo(&cmp_highlevel
, host
);
229 if (extcode
!= EXTCODE_COMPARE_SWAP
)
230 return RCODE_TYPE_ERROR
;
232 if (csraddr
== 0x900) {
233 /* FIXME: Ignore writes to bits 30-31 and 0-7 */
234 *store
= cpu_to_be32(ch
->u
.ompr_quadlet
);
235 if (arg
== cpu_to_be32(ch
->u
.ompr_quadlet
))
236 ch
->u
.ompr_quadlet
= be32_to_cpu(data
);
238 return RCODE_COMPLETE
;
240 if (csraddr
< 0x904 + ch
->u
.ompr
.nplugs
* 4) {
241 plug
= (csraddr
- 0x904) / 4;
242 *store
= cpu_to_be32(ch
->opcr
[plug
].u
.quadlet
);
245 ch
->opcr
[plug
].u
.quadlet
= be32_to_cpu(data
);
247 if (be32_to_cpu(*store
) != ch
->opcr
[plug
].u
.quadlet
&&
248 ch
->opcr
[plug
].update
!= NULL
)
249 ch
->opcr
[plug
].update(&ch
->opcr
[plug
].u
.pcr
,
250 ch
->opcr
[plug
].data
);
252 return RCODE_COMPLETE
;
254 else if (csraddr
< 0x980) {
255 return RCODE_ADDRESS_ERROR
;
257 else if (csraddr
== 0x980) {
258 /* FIXME: Ignore writes to bits 24-31 and 0-7 */
259 *store
= cpu_to_be32(ch
->u
.ompr_quadlet
);
260 if (arg
== cpu_to_be32(ch
->u
.ompr_quadlet
))
261 ch
->u
.ompr_quadlet
= be32_to_cpu(data
);
263 return RCODE_COMPLETE
;
265 else if (csraddr
< 0x984 + ch
->v
.impr
.nplugs
* 4) {
266 plug
= (csraddr
- 0x984) / 4;
267 *store
= cpu_to_be32(ch
->ipcr
[plug
].u
.quadlet
);
270 ch
->ipcr
[plug
].u
.quadlet
= be32_to_cpu(data
);
272 if (be32_to_cpu(*store
) != ch
->ipcr
[plug
].u
.quadlet
&&
273 ch
->ipcr
[plug
].update
!= NULL
)
274 ch
->ipcr
[plug
].update(&ch
->ipcr
[plug
].u
.pcr
,
275 ch
->ipcr
[plug
].data
);
277 return RCODE_COMPLETE
;
280 return RCODE_ADDRESS_ERROR
;
284 /* Module interface */
286 MODULE_AUTHOR("Kristian Hogsberg <hogsberg@users.sf.net>");
287 MODULE_DESCRIPTION("Connection Management Procedures (CMP)");
288 MODULE_SUPPORTED_DEVICE("cmp");
289 MODULE_LICENSE("GPL");
291 EXPORT_SYMBOL(cmp_register_opcr
);
292 EXPORT_SYMBOL(cmp_unregister_opcr
);
294 static int __init
cmp_init_module (void)
296 hpsb_register_highlevel (&cmp_highlevel
);
298 HPSB_INFO("Loaded CMP driver");
303 static void __exit
cmp_exit_module (void)
305 hpsb_unregister_highlevel(&cmp_highlevel
);
307 HPSB_INFO("Unloaded CMP driver");
310 module_init(cmp_init_module
);
311 module_exit(cmp_exit_module
);