1/*
2 * Copyright 2004-2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3 * Copyright 2002-2004, Thomas Kurschel. All rights reserved.
4 *
5 * Distributed under the terms of the MIT License.
6 */
7
8
9#include "io_resources.h"
10
11#include <stdlib.h>
12#include <string.h>
13
14
15//#define TRACE_IO_RESOURCES
16#ifdef TRACE_IO_RESOURCES
17#	define TRACE(x) dprintf x
18#else
19#	define TRACE(x) ;
20#endif
21
22
23typedef DoublyLinkedList<io_resource_private,
24	DoublyLinkedListMemberGetLink<io_resource_private,
25		&io_resource_private::fTypeLink> > ResourceTypeList;
26
27
28static ResourceTypeList sMemoryList;
29static ResourceTypeList sPortList;
30static ResourceTypeList sDMAChannelList;
31
32
33io_resource_private::io_resource_private()
34{
35	_Init();
36}
37
38
39io_resource_private::~io_resource_private()
40{
41	Release();
42}
43
44
45void
46io_resource_private::_Init()
47{
48	type = 0;
49	base = 0;
50	length = 0;
51}
52
53
54status_t
55io_resource_private::Acquire(const io_resource& resource)
56{
57	if (!_IsValid(resource))
58		return B_BAD_VALUE;
59
60	type = resource.type;
61	base = resource.base;
62
63	if (type != B_ISA_DMA_CHANNEL)
64		length = resource.length;
65	else
66		length = 1;
67
68	ResourceTypeList* list = NULL;
69
70	switch (type) {
71		case B_IO_MEMORY:
72			list = &sMemoryList;
73			break;
74		case B_IO_PORT:
75			list = &sPortList;
76			break;
77		case B_ISA_DMA_CHANNEL:
78			list = &sDMAChannelList;
79			break;
80	}
81
82	ResourceTypeList::Iterator iterator = list->GetIterator();
83	while (iterator.HasNext()) {
84		io_resource* resource = iterator.Next();
85
86		// we need the "base + length - 1" trick to avoid wrap around at 4 GB
87		if (resource->base >= base
88			&& resource->base + length - 1 <= base + length - 1) {
89			// This range is already covered by someone else
90			// TODO: we might want to ignore resources that belong to
91			// a node that isn't used.
92			_Init();
93			return B_RESOURCE_UNAVAILABLE;
94		}
95	}
96
97	list->Add(this);
98	return B_OK;
99}
100
101
102void
103io_resource_private::Release()
104{
105	if (type == 0)
106		return;
107
108	switch (type) {
109		case B_IO_MEMORY:
110			sMemoryList.Remove(this);
111			break;
112		case B_IO_PORT:
113			sPortList.Remove(this);
114			break;
115		case B_ISA_DMA_CHANNEL:
116			sDMAChannelList.Remove(this);
117			break;
118	}
119
120	_Init();
121}
122
123
124/*static*/ bool
125io_resource_private::_IsValid(const io_resource& resource)
126{
127	switch (resource.type) {
128		case B_IO_MEMORY:
129			return resource.base + resource.length > resource.base;
130		case B_IO_PORT:
131			return (uint16)resource.base == resource.base
132				&& (uint16)resource.length == resource.length
133				&& resource.base + resource.length > resource.base;
134		case B_ISA_DMA_CHANNEL:
135			return resource.base <= 8;
136
137		default:
138			return false;
139	}
140}
141
142
143//	#pragma mark -
144
145
146void
147dm_init_io_resources(void)
148{
149	new(&sMemoryList) ResourceTypeList;
150	new(&sPortList) ResourceTypeList;
151	new(&sDMAChannelList) ResourceTypeList;
152}
153