Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * Lml 22 driver
3
 */
4
#include	"u.h"
5
#include	"../port/lib.h"
6
#include	"mem.h"
7
#include	"dat.h"
8
#include	"fns.h"
9
#include	"../port/error.h"
10
#include	"io.h"
11
 
12
#include	"devlml.h"
13
 
14
#define DBGREAD	0x01
15
#define DBGWRIT	0x02
16
#define DBGINTR	0x04
17
#define DBGINTS	0x08
18
#define DBGFS	0x10
19
 
20
int debug = DBGREAD|DBGWRIT|DBGFS;
21
 
22
enum{
23
	Qdir,
24
	Qctl0,
25
	Qjpg0,
26
	Qraw0,
27
	Qctl1,
28
	Qjpg1,
29
	Qraw1,
30
};
31
 
32
static Dirtab lmldir[] = {
33
	".",		{Qdir, 0, QTDIR},	0,	0555,
34
	"lml0ctl",	{Qctl0},		0,	0666,
35
	"lml0jpg",	{Qjpg0},		0,	0444,
36
	"lml0raw",	{Qraw0},		0,	0444,
37
	"lml1ctl",	{Qctl1},		0,	0666,
38
	"lml1jpg",	{Qjpg1},		0,	0444,
39
	"lml1raw",	{Qraw1},		0,	0444,
40
};
41
 
42
typedef struct LML LML;
43
 
44
struct LML {
45
	/* Hardware */
46
	Pcidev	*pcidev;
47
	ulong	pciBaseAddr;
48
 
49
	/* Allocated memory */
50
	CodeData *codedata;
51
 
52
	/* Software state */
53
	ulong	jpgframeno;
54
	int	frameNo;
55
	Rendez	sleepjpg;
56
	int	jpgopens;
57
} lmls[NLML];
58
 
59
int nlml;
60
 
61
static FrameHeader jpgheader = {
62
	MRK_SOI, MRK_APP3, (sizeof(FrameHeader)-4) << 8,
63
	{ 'L', 'M', 'L', '\0'},
64
	-1, 0, 0,  0
65
};
66
 
67
#define writel(v, a) *(ulong *)(a) = (v)
68
#define readl(a) *(ulong*)(a)
69
 
70
static int
71
getbuffer(void *x)
72
{
73
	static last = NBUF-1;
74
	int l = last;
75
	LML *lml;
76
 
77
	lml = x;
78
	for(;;){
79
		last = (last+1) % NBUF;
80
		if(lml->codedata->statCom[last] & STAT_BIT)
81
			return last + 1;
82
		if(last == l)
83
			return 0;
84
	}
85
}
86
 
87
static long
88
jpgread(LML *lml, void *va, long nbytes, vlong, int dosleep)
89
{
90
	int bufno;
91
	FrameHeader *jpgheader;
92
 
93
	/*
94
	 * reads should be of size 1 or sizeof(FrameHeader).
95
	 * Frameno is the number of the buffer containing the data.
96
	 */
97
	while((bufno = getbuffer(lml)) == 0 && dosleep)
98
		sleep(&lml->sleepjpg, getbuffer, lml);
99
	if(--bufno < 0)
100
		return 0;
101
 
102
	jpgheader = (FrameHeader*)(lml->codedata->frag[bufno].hdr+2);
103
	if(nbytes == sizeof(FrameHeader)){
104
		memmove(va, jpgheader, sizeof(FrameHeader));
105
		return sizeof(FrameHeader);
106
	}
107
	if(nbytes == 1){
108
		*(char *)va = bufno;
109
		return 1;
110
	}
111
	return 0;
112
}
113
 
114
static void lmlintr(Ureg *, void *);
115
 
116
static void
117
prepbuf(LML *lml)
118
{
119
	int i;
120
	CodeData *cd;
121
 
122
	cd = lml->codedata;
123
	for(i = 0; i < NBUF; i++){
124
		cd->statCom[i] = PADDR(&(cd->fragdesc[i]));
125
		cd->fragdesc[i].addr = PADDR(cd->frag[i].fb);
126
		/* Length is in double words, in position 1..20 */
127
		cd->fragdesc[i].leng = FRAGSIZE >> 1 | FRAGM_FINAL_B;
128
		memmove(cd->frag[i].hdr+2, &jpgheader, sizeof(FrameHeader)-2);
129
	}
130
}
131
 
132
static void
133
lmlreset(void)
134
{
135
	ulong regpa;
136
	char name[32];
137
	void *regva;
138
	LML *lml;
139
	Pcidev *pcidev;
140
	Physseg segbuf;
141
 
142
	pcidev = nil;
143
 
144
	for(nlml = 0; nlml < NLML && (pcidev = pcimatch(pcidev, VENDOR_ZORAN,
145
	    ZORAN_36067)); nlml++){
146
		lml = &lmls[nlml];
147
		lml->pcidev = pcidev;
148
		lml->codedata = (CodeData*)(((ulong)xalloc(Codedatasize+ BY2PG)
149
			+ BY2PG-1) & ~(BY2PG-1));
150
		if(lml->codedata == nil){
151
			print("devlml: xalloc(%ux, %ux, 0)\n", Codedatasize, BY2PG);
152
			return;
153
		}
154
 
155
		print("Installing Motion JPEG driver %s, irq %d\n",
156
			MJPG_VERSION, pcidev->intl);
157
		print("MJPG buffer at 0x%.8p, size 0x%.8ux\n", lml->codedata,
158
			Codedatasize);
159
 
160
		/* Get access to DMA memory buffer */
161
		lml->codedata->pamjpg = PADDR(lml->codedata->statCom);
162
 
163
		prepbuf(lml);
164
 
165
		print("zr36067 found at 0x%.8lux", pcidev->mem[0].bar & ~0x0F);
166
 
167
		regpa = pcidev->mem[0].bar & ~0x0F;
168
		regva = vmap(regpa, pcidev->mem[0].size);
169
		if(regva == 0){
170
			print("lml: failed to map registers\n");
171
			return;
172
		}
173
		lml->pciBaseAddr = (ulong)regva;
174
		print(", mapped at 0x%.8lux\n", lml->pciBaseAddr);
175
 
176
		memset(&segbuf, 0, sizeof(segbuf));
177
		segbuf.attr = SG_PHYSICAL;
178
		sprint(name, "lml%d.mjpg", nlml);
179
		kstrdup(&segbuf.name, name);
180
		segbuf.pa = PADDR(lml->codedata);
181
		segbuf.size = Codedatasize;
182
		if(addphysseg(&segbuf) == -1){
183
			print("lml: physsegment: %s\n", name);
184
			return;
185
		}
186
 
187
		memset(&segbuf, 0, sizeof(segbuf));
188
		segbuf.attr = SG_PHYSICAL;
189
		sprint(name, "lml%d.regs", nlml);
190
		kstrdup(&segbuf.name, name);
191
		segbuf.pa = (ulong)regpa;
192
		segbuf.size = pcidev->mem[0].size;
193
		if(addphysseg(&segbuf) == -1){
194
			print("lml: physsegment: %s\n", name);
195
			return;
196
		}
197
 
198
		/* set up interrupt handler */
199
		intrenable(pcidev->intl, lmlintr, lml, pcidev->tbdf, "lml");
200
	}
201
}
202
 
203
static Chan*
204
lmlattach(char *spec)
205
{
206
	if(debug&DBGFS)
207
		print("lmlattach\n");
208
	return devattach(L'Λ', spec);
209
}
210
 
211
static Walkqid*
212
lmlwalk(Chan *c, Chan *nc, char **name, int nname)
213
{
214
	if(debug&DBGFS)
215
		print("lmlwalk\n");
216
	return devwalk(c, nc, name, nname, lmldir, 3*nlml+1, devgen);
217
}
218
 
219
static int
220
lmlstat(Chan *c, uchar *db, int n)
221
{
222
	if(debug&DBGFS)
223
		print("lmlstat\n");
224
	return devstat(c, db, n, lmldir, 3*nlml+1, devgen);
225
}
226
 
227
static Chan*
228
lmlopen(Chan *c, int omode)
229
{
230
	int i;
231
	LML *lml;
232
 
233
	if(debug&DBGFS)
234
		print("lmlopen\n");
235
	if(omode != OREAD)
236
		error(Eperm);
237
	c->aux = 0;
238
	i = 0;
239
	switch((ulong)c->qid.path){
240
	case Qctl1:
241
		i++;
242
		/* fall through */
243
	case Qctl0:
244
		if(i >= nlml)
245
			error(Eio);
246
		break;
247
	case Qjpg1:
248
	case Qraw1:
249
		i++;
250
		/* fall through */
251
	case Qjpg0:
252
	case Qraw0:
253
		/* allow one open */
254
		if(i >= nlml)
255
			error(Eio);
256
		lml = lmls+i;
257
		if(lml->jpgopens)
258
			error(Einuse);
259
		lml->jpgopens = 1;
260
		lml->jpgframeno = 0;
261
		prepbuf(lml);
262
		break;
263
	}
264
	return devopen(c, omode, lmldir, 3*nlml+1, devgen);
265
}
266
 
267
static void
268
lmlclose(Chan *c)
269
{
270
	int i;
271
 
272
	if(debug&DBGFS)
273
		print("lmlclose\n");
274
	i = 0;
275
	switch((ulong)c->qid.path){
276
	case Qjpg1:
277
	case Qraw1:
278
		i++;
279
		/* fall through */
280
	case Qjpg0:
281
	case Qraw0:
282
		lmls[i].jpgopens = 0;
283
		break;
284
	}
285
}
286
 
287
static long
288
lmlread(Chan *c, void *va, long n, vlong voff)
289
{
290
	int i, len;
291
	long off = voff;
292
	uchar *buf = va;
293
	LML *lml;
294
	static char lmlinfo[1024];
295
 
296
	i = 0;
297
	switch((ulong)c->qid.path){
298
	case Qdir:
299
		n = devdirread(c, (char *)buf, n, lmldir, 3*nlml+1, devgen);
300
		if(debug&(DBGFS|DBGREAD))
301
			print("lmlread %ld\n", n);
302
		return n;
303
	case Qctl1:
304
		i++;
305
		/* fall through */
306
	case Qctl0:
307
		if(i >= nlml)
308
			error(Eio);
309
		lml = lmls+i;
310
		len = snprint(lmlinfo, sizeof lmlinfo, "lml%djpg	lml%draw\nlml%d.regs	0x%lux	0x%ux\nlml%d.mjpg	0x%lux	0x%ux\n",
311
			i, i,
312
			i, lml->pcidev->mem[0].bar & ~0x0F, lml->pcidev->mem[0].size,
313
			i, PADDR(lml->codedata), Codedatasize);
314
		if(voff > len)
315
			return 0;
316
		if(n > len - voff)
317
			n = len - voff;
318
		memmove(va, lmlinfo+voff, n);
319
		return n;
320
	case Qjpg1:
321
		i++;
322
		/* fall through */
323
	case Qjpg0:
324
		if(i >= nlml)
325
			error(Eio);
326
		return jpgread(lmls+i, buf, n, off, 1);
327
	case Qraw1:
328
		i++;
329
		/* fall through */
330
	case Qraw0:
331
		if(i >= nlml)
332
			error(Eio);
333
		return jpgread(lmls+i, buf, n, off, 0);
334
	}
335
	return -1;
336
}
337
 
338
static long
339
lmlwrite(Chan *, void *, long, vlong)
340
{
341
	error(Eperm);
342
	return 0;
343
}
344
 
345
Dev lmldevtab = {
346
	L'Λ',
347
	"video",
348
 
349
	lmlreset,
350
	devinit,
351
	devshutdown,
352
	lmlattach,
353
	lmlwalk,
354
	lmlstat,
355
	lmlopen,
356
	devcreate,
357
	lmlclose,
358
	lmlread,
359
	devbread,
360
	lmlwrite,
361
	devbwrite,
362
	devremove,
363
	devwstat,
364
};
365
 
366
static void
367
lmlintr(Ureg *, void *x)
368
{
369
	ulong fstart, fno, flags, statcom;
370
	FrameHeader *jpgheader;
371
	LML *lml;
372
 
373
	lml = x;
374
	flags = readl(lml->pciBaseAddr+INTR_STAT);
375
	/* Reset all interrupts from 067 */
376
	writel(0xff000000, lml->pciBaseAddr + INTR_STAT);
377
 
378
	if(flags & INTR_JPEGREP){
379
 
380
		if(debug&DBGINTR)
381
			print("MjpgDrv_intrHandler stat=0x%.8lux\n", flags);
382
 
383
		fstart = lml->jpgframeno & 3;
384
		for(;;){
385
			lml->jpgframeno++;
386
			fno = lml->jpgframeno & 3;
387
			if(lml->codedata->statCom[fno] & STAT_BIT)
388
				break;
389
			if(fno == fstart){
390
				if(debug & DBGINTR)
391
					print("Spurious lml jpg intr?\n");
392
				return;
393
			}
394
		}
395
		statcom = lml->codedata->statCom[fno];
396
		jpgheader = (FrameHeader *)(lml->codedata->frag[fno].hdr + 2);
397
		jpgheader->frameNo = lml->jpgframeno;
398
		jpgheader->ftime  = todget(nil);
399
		jpgheader->frameSize = (statcom & 0x00ffffff) >> 1;
400
		jpgheader->frameSeqNo = statcom >> 24;
401
		wakeup(&lml->sleepjpg);
402
	}
403
}