1/*
2 *	SiS 190/191 NIC Driver.
3 *	Copyright (c) 2009 S.Zharski <imker@gmx.li>
4 *	Distributed under the terms of the MIT license.
5 *
6 */
7#ifndef _SiS19X_DATARING_H_
8#define _SiS19X_DATARING_H_
9
10
11#include <KernelExport.h>
12
13#include "Driver.h"
14#include "Registers.h"
15#include "Settings.h"
16
17
18class Device;
19
20template<typename __type, uint32 __count>
21class DataRing {
22public:
23						DataRing(Device* device, bool isTx);
24						~DataRing();
25
26			status_t	Open();
27			void		CleanUp();
28			status_t	Close();
29
30			status_t	Read(uint8* buffer, size_t* numBytes);
31			status_t	Write(const uint8* buffer, size_t* numBytes);
32
33			int32		InterruptHandler();
34
35			void		Trace();
36			void		Dump();
37
38private:
39			status_t	_InitArea();
40			void		_SetBaseAddress(phys_addr_t address);
41
42			Device*		fDevice;
43			bool		fIsTx;
44			status_t	fStatus;
45			area_id		fArea;
46			int32		fSpinlock;
47			sem_id		fSemaphore;
48			uint32		fHead;
49			uint32		fTail;
50
51	volatile __type*	fDescriptors;
52	volatile uint8*		fBuffers[__count];
53};
54
55
56
57template<typename __type, uint32 __count>
58DataRing<__type, __count>::DataRing(Device* device, bool isTx)
59							:
60							fDevice(device),
61							fIsTx(isTx),
62							fStatus(B_NO_INIT),
63							fArea(-1),
64							fSpinlock(0),
65							fSemaphore(0),
66							fHead(0),
67							fTail(0),
68							fDescriptors(NULL)
69{
70	memset(fBuffers, 0, sizeof(fBuffers));
71}
72
73
74template<typename __type, uint32 __count>
75DataRing<__type, __count>::~DataRing()
76{
77	delete_sem(fSemaphore);
78	delete_area(fArea);
79}
80
81
82template<typename __type, uint32 __count>
83status_t
84DataRing<__type, __count>::_InitArea()
85{
86	// create area for xfer data descriptors and buffers...
87	//
88	// layout is following:
89	// | descriptors array | buffers array |
90	//
91	uint32 buffSize = BufferSize + sizeof(__type);
92	buffSize *=	__count;
93	buffSize = (buffSize + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
94	fArea = create_area(DRIVER_NAME "_data_ring", (void**)&fDescriptors,
95			B_ANY_KERNEL_ADDRESS, buffSize,
96			B_CONTIGUOUS, B_READ_AREA | B_WRITE_AREA);
97	if (fArea < 0) {
98		TRACE_ALWAYS("Cannot create area with size %d bytes:%#010x\n",
99				buffSize, fArea);
100		return fStatus = fArea;
101	}
102
103	// setup descriptors and buffers layout
104	uint8* buffersData = (uint8*)fDescriptors;
105	uint32 descriptorsSize = sizeof(__type) * __count;
106	buffersData += descriptorsSize;
107
108	physical_entry table = {0};
109
110	for (size_t i = 0; i < __count; i++) {
111		fBuffers[i] = buffersData + BufferSize * i;
112
113		get_memory_map((void*)fBuffers[i], BufferSize, &table, 1);
114		fDescriptors[i].Init(table.address, i == (__count - 1));
115	}
116
117	get_memory_map((void*)fDescriptors, descriptorsSize, &table, 1);
118
119	_SetBaseAddress(table.address);
120
121	return fStatus = B_OK;
122}
123
124
125template<typename __type, uint32 __count>
126status_t
127DataRing<__type, __count>::Open()
128{
129	if (fStatus != B_OK && _InitArea() != B_OK) {
130		return fStatus;
131	}
132
133	if (fIsTx) {
134		fSemaphore = create_sem(__count, "SiS19X Transmit");
135	} else {
136		fSemaphore = create_sem(0, "SiS19X Receive");
137	}
138
139	if (fSemaphore < 0) {
140		TRACE_ALWAYS("Cannot create %s semaphore:%#010x\n",
141				fIsTx ? "transmit" : "receive", fSemaphore);
142		return fStatus = fSemaphore;
143	}
144
145	set_sem_owner(fSemaphore, B_SYSTEM_TEAM);
146
147	return fStatus = B_OK;
148}
149
150
151template<typename __type, uint32 __count>
152status_t
153DataRing<__type, __count>::Close()
154{
155	delete_sem(fSemaphore);
156	fSemaphore = 0;
157
158	return B_OK;
159}
160
161
162template<typename __type, uint32 __count>
163void
164DataRing<__type, __count>::Trace()
165{
166	int32 count = 0;
167	get_sem_count(fSemaphore, &count);
168	TRACE_ALWAYS("%s:[count:%d] n:%lu l:%lu d:%lu\n", fIsTx ? "Tx" : "Rx",
169			count, fHead, fTail, fHead - fTail);
170}
171
172
173#endif //_SiS19X_DATARING_H_
174
175