4 * Copyright (C) 1999 Andreas E. Bombe
6 * This code is licensed under the GPL. See the file COPYING in the root
7 * directory of the kernel sources for details.
12 * Christian Toegel <christian.toegel@gmx.at>
13 * unregister address space
15 * Manfred Weihs <weihs@ict.tuwien.ac.at>
16 * unregister address space
20 #include <linux/config.h>
21 #include <linux/slab.h>
24 #include "ieee1394_types.h"
26 #include "ieee1394_core.h"
27 #include "highlevel.h"
30 LIST_HEAD(hl_drivers);
31 rwlock_t hl_drivers_lock = RW_LOCK_UNLOCKED;
33 LIST_HEAD(addr_space);
34 rwlock_t addr_space_lock = RW_LOCK_UNLOCKED;
36 /* addr_space list will have zero and max already included as bounds */
37 static struct hpsb_address_ops dummy_ops = { NULL, NULL, NULL, NULL };
38 static struct hpsb_address_serve dummy_zero_addr, dummy_max_addr;
40 struct hpsb_highlevel *hpsb_register_highlevel(const char *name,
41 struct hpsb_highlevel_ops *ops)
43 struct hpsb_highlevel *hl;
45 hl = (struct hpsb_highlevel *)kmalloc(sizeof(struct hpsb_highlevel),
51 INIT_LIST_HEAD(&hl->hl_list);
52 INIT_LIST_HEAD(&hl->addr_list);
56 write_lock_irq(&hl_drivers_lock);
57 list_add_tail(&hl->hl_list, &hl_drivers);
58 write_unlock_irq(&hl_drivers_lock);
60 hl_all_hosts(hl->op->add_host);
65 void hpsb_unregister_highlevel(struct hpsb_highlevel *hl)
67 struct list_head *entry;
68 struct hpsb_address_serve *as;
74 write_lock_irq(&addr_space_lock);
75 entry = hl->addr_list.next;
77 while (entry != &hl->addr_list) {
78 as = list_entry(entry, struct hpsb_address_serve, addr_list);
79 list_del(&as->as_list);
83 write_unlock_irq(&addr_space_lock);
85 write_lock_irq(&hl_drivers_lock);
86 list_del(&hl->hl_list);
87 write_unlock_irq(&hl_drivers_lock);
89 if (hl->op->remove_host)
90 hl_all_hosts(hl->op->remove_host);
95 int hpsb_register_addrspace(struct hpsb_highlevel *hl,
96 struct hpsb_address_ops *ops, u64 start, u64 end)
98 struct hpsb_address_serve *as;
99 struct list_head *entry;
102 if (((start|end) & 3) || (start >= end) || (end > 0x1000000000000ULL)) {
103 HPSB_ERR("%s called with invalid addresses", __FUNCTION__);
107 as = (struct hpsb_address_serve *)
108 kmalloc(sizeof(struct hpsb_address_serve), GFP_KERNEL);
113 INIT_LIST_HEAD(&as->as_list);
114 INIT_LIST_HEAD(&as->addr_list);
119 write_lock_irq(&addr_space_lock);
120 entry = addr_space.next;
122 while (list_entry(entry, struct hpsb_address_serve, as_list)->end
124 if (list_entry(entry->next, struct hpsb_address_serve, as_list)
126 list_add(&as->as_list, entry);
127 list_add_tail(&as->addr_list, &hl->addr_list);
133 write_unlock_irq(&addr_space_lock);
142 int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, u64 start)
145 struct hpsb_address_serve *as;
146 struct list_head *entry;
148 write_lock_irq(&addr_space_lock);
150 entry = hl->addr_list.next;
152 while (entry != &hl->addr_list) {
153 as = list_entry(entry, struct hpsb_address_serve, addr_list);
155 if (as->start == start) {
156 list_del(&as->as_list);
157 list_del(&as->addr_list);
164 write_unlock_irq(&addr_space_lock);
169 void hpsb_listen_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
170 unsigned int channel)
173 HPSB_ERR("%s called with invalid channel", __FUNCTION__);
177 if (host->iso_listen_count[channel]++ == 0) {
178 host->driver->devctl(host, ISO_LISTEN_CHANNEL, channel);
182 void hpsb_unlisten_channel(struct hpsb_highlevel *hl, struct hpsb_host *host,
183 unsigned int channel)
186 HPSB_ERR("%s called with invalid channel", __FUNCTION__);
190 if (--host->iso_listen_count[channel] == 0) {
191 host->driver->devctl(host, ISO_UNLISTEN_CHANNEL, channel);
196 void highlevel_add_host(struct hpsb_host *host)
198 struct list_head *entry;
199 struct hpsb_highlevel *hl;
201 read_lock(&hl_drivers_lock);
202 list_for_each(entry, &hl_drivers) {
203 hl = list_entry(entry, struct hpsb_highlevel, hl_list);
205 hl->op->add_host(host);
207 read_unlock(&hl_drivers_lock);
210 void highlevel_remove_host(struct hpsb_host *host)
212 struct list_head *entry;
213 struct hpsb_highlevel *hl;
215 write_lock_irq(&hl_drivers_lock);
216 list_for_each(entry, &hl_drivers) {
217 hl = list_entry(entry, struct hpsb_highlevel, hl_list);
219 if (hl->op->remove_host)
220 hl->op->remove_host(host);
222 write_unlock_irq(&hl_drivers_lock);
225 void highlevel_host_reset(struct hpsb_host *host)
227 struct list_head *entry;
228 struct hpsb_highlevel *hl;
230 read_lock(&hl_drivers_lock);
231 list_for_each(entry, &hl_drivers) {
232 hl = list_entry(entry, struct hpsb_highlevel, hl_list);
234 if (hl->op->host_reset)
235 hl->op->host_reset(host);
237 read_unlock(&hl_drivers_lock);
240 void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data,
243 struct list_head *entry;
244 struct hpsb_highlevel *hl;
245 int channel = (data[0] >> 8) & 0x3f;
247 read_lock(&hl_drivers_lock);
248 entry = hl_drivers.next;
250 while (entry != &hl_drivers) {
251 hl = list_entry(entry, struct hpsb_highlevel, hl_list);
252 if (hl->op->iso_receive) {
253 hl->op->iso_receive(host, channel, data, length);
257 read_unlock(&hl_drivers_lock);
260 void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
261 u8 *data, unsigned int length)
263 struct list_head *entry;
264 struct hpsb_highlevel *hl;
265 int cts = data[0] >> 4;
267 read_lock(&hl_drivers_lock);
268 entry = hl_drivers.next;
270 while (entry != &hl_drivers) {
271 hl = list_entry(entry, struct hpsb_highlevel, hl_list);
272 if (hl->op->fcp_request) {
273 hl->op->fcp_request(host, nodeid, direction, cts, data,
278 read_unlock(&hl_drivers_lock);
281 int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
282 u64 addr, unsigned int length, u16 flags)
284 struct hpsb_address_serve *as;
285 struct list_head *entry;
286 unsigned int partlength;
287 int rcode = RCODE_ADDRESS_ERROR;
289 read_lock(&addr_space_lock);
291 entry = addr_space.next;
292 as = list_entry(entry, struct hpsb_address_serve, as_list);
294 while (as->start <= addr) {
295 if (as->end > addr) {
296 partlength = min(as->end - addr, (u64) length);
298 if (as->op->read != NULL) {
299 rcode = as->op->read(host, nodeid, buffer,
300 addr, partlength, flags);
302 rcode = RCODE_TYPE_ERROR;
305 length -= partlength;
308 if ((rcode != RCODE_COMPLETE) || !length) {
314 as = list_entry(entry, struct hpsb_address_serve, as_list);
317 read_unlock(&addr_space_lock);
319 if (length && (rcode == RCODE_COMPLETE)) {
320 rcode = RCODE_ADDRESS_ERROR;
326 int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
327 quadlet_t *data, u64 addr, unsigned int length, u16 flags)
329 struct hpsb_address_serve *as;
330 struct list_head *entry;
331 unsigned int partlength;
332 int rcode = RCODE_ADDRESS_ERROR;
334 read_lock(&addr_space_lock);
336 entry = addr_space.next;
337 as = list_entry(entry, struct hpsb_address_serve, as_list);
339 while (as->start <= addr) {
340 if (as->end > addr) {
341 partlength = min(as->end - addr, (u64) length);
343 if (as->op->write != NULL) {
344 rcode = as->op->write(host, nodeid, destid,
345 data, addr, partlength, flags);
347 rcode = RCODE_TYPE_ERROR;
350 length -= partlength;
353 if ((rcode != RCODE_COMPLETE) || !length) {
359 as = list_entry(entry, struct hpsb_address_serve, as_list);
362 read_unlock(&addr_space_lock);
364 if (length && (rcode == RCODE_COMPLETE)) {
365 rcode = RCODE_ADDRESS_ERROR;
372 int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
373 u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags)
375 struct hpsb_address_serve *as;
376 struct list_head *entry;
377 int rcode = RCODE_ADDRESS_ERROR;
379 read_lock(&addr_space_lock);
381 entry = addr_space.next;
382 as = list_entry(entry, struct hpsb_address_serve, as_list);
384 while (as->start <= addr) {
385 if (as->end > addr) {
386 if (as->op->lock != NULL) {
387 rcode = as->op->lock(host, nodeid, store, addr,
388 data, arg, ext_tcode, flags);
390 rcode = RCODE_TYPE_ERROR;
397 as = list_entry(entry, struct hpsb_address_serve, as_list);
400 read_unlock(&addr_space_lock);
405 int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
406 u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags)
408 struct hpsb_address_serve *as;
409 struct list_head *entry;
410 int rcode = RCODE_ADDRESS_ERROR;
412 read_lock(&addr_space_lock);
414 entry = addr_space.next;
415 as = list_entry(entry, struct hpsb_address_serve, as_list);
417 while (as->start <= addr) {
418 if (as->end > addr) {
419 if (as->op->lock64 != NULL) {
420 rcode = as->op->lock64(host, nodeid, store,
424 rcode = RCODE_TYPE_ERROR;
431 as = list_entry(entry, struct hpsb_address_serve, as_list);
434 read_unlock(&addr_space_lock);
439 void init_hpsb_highlevel(void)
441 INIT_LIST_HEAD(&dummy_zero_addr.as_list);
442 INIT_LIST_HEAD(&dummy_zero_addr.addr_list);
443 INIT_LIST_HEAD(&dummy_max_addr.as_list);
444 INIT_LIST_HEAD(&dummy_max_addr.addr_list);
446 dummy_zero_addr.op = dummy_max_addr.op = &dummy_ops;
448 dummy_zero_addr.start = dummy_zero_addr.end = 0;
449 dummy_max_addr.start = dummy_max_addr.end = ((u64) 1) << 48;
451 list_add_tail(&dummy_zero_addr.as_list, &addr_space);
452 list_add_tail(&dummy_max_addr.as_list, &addr_space);