xref: /haiku/src/system/kernel/device_manager/io_resources.cpp (revision 19b07e67d2c729c9878c33dac650db407baee7ab)
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 
23 typedef DoublyLinkedList<io_resource_private,
24 	DoublyLinkedListMemberGetLink<io_resource_private,
25 		&io_resource_private::fTypeLink> > ResourceTypeList;
26 
27 
28 static ResourceTypeList sMemoryList;
29 static ResourceTypeList sPortList;
30 static ResourceTypeList sDMAChannelList;
31 
32 
io_resource_private()33 io_resource_private::io_resource_private()
34 {
35 	_Init();
36 }
37 
38 
~io_resource_private()39 io_resource_private::~io_resource_private()
40 {
41 	Release();
42 }
43 
44 
45 void
_Init()46 io_resource_private::_Init()
47 {
48 	type = 0;
49 	base = 0;
50 	length = 0;
51 }
52 
53 
54 status_t
Acquire(const io_resource & resource)55 io_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 
102 void
Release()103 io_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
_IsValid(const io_resource & resource)125 io_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 
146 void
dm_init_io_resources(void)147 dm_init_io_resources(void)
148 {
149 	new(&sMemoryList) ResourceTypeList;
150 	new(&sPortList) ResourceTypeList;
151 	new(&sDMAChannelList) ResourceTypeList;
152 }
153