comparison vidix/cyberblade_vid.c @ 22850:9a1e26fef45b

Move driver files directly into the vidix directory.
author diego
date Sun, 01 Apr 2007 00:02:43 +0000
parents
children 77def5093daf
comparison
equal deleted inserted replaced
22849:bddb09395c3e 22850:9a1e26fef45b
1 /*
2 Driver for CyberBlade/i1 - Version 0.1.4
3
4 Copyright (C) 2002 by Alastair M. Robinson.
5 Official homepage: http://www.blackfiveservices.co.uk/EPIAVidix.shtml
6
7 Based on Permedia 3 driver by Måns Rullgård
8
9 Thanks to Gilles Frattini for bugfixes
10
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24
25 Changes:
26 18/01/03
27 MMIO is no longer used, sidestepping cache issues on EPIA-800
28 TV-Out modes are now better supported - this should be the end
29 of the magenta stripes :)
30 Brightness/Contrast controls disabled for the time being - they were
31 seriously degrading picture quality, especially with TV-Out.
32
33 To Do:
34 Implement Hue/Saturation controls
35 Support / Test multiple frames
36 Test colour-key code more extensively
37 */
38
39 #include <errno.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <inttypes.h>
44 #include <unistd.h>
45
46 #include "vidix.h"
47 #include "fourcc.h"
48 #include "../libdha/libdha.h"
49 #include "../libdha/pci_ids.h"
50 #include "../libdha/pci_names.h"
51 #include "../config.h"
52
53 #include "cyberblade_regs.h"
54
55 pciinfo_t pci_info;
56
57 char save_colourkey[6];
58 char *cyberblade_mem;
59
60 #ifdef DEBUG_LOGFILE
61 FILE *logfile=0;
62 #define LOGWRITE(x) {if(logfile) fprintf(logfile,x);}
63 #else
64 #define LOGWRITE(x)
65 #endif
66
67 /* Helper functions for reading registers. */
68
69 static int CRINW(int reg)
70 {
71 int result;
72 result=CRINB(reg);
73 result|=CRINB(reg+1)<<8;
74 return(result);
75 }
76
77 static void CROUTW(int reg,int val)
78 {
79 CROUTB(reg,val&255);
80 CROUTB(reg+1,(val>>8)&255);
81 }
82
83 static int SRINW(int reg)
84 {
85 int result;
86 result=SRINB(reg);
87 result|=SRINB(reg+1)<<8;
88 return(result);
89 }
90
91 static void SROUTW(int reg,int val)
92 {
93 SROUTB(reg,val&255);
94 SROUTB(reg+1,(val>>8)&255);
95 }
96
97 void DumpRegisters(void)
98 {
99 int reg,val;
100 #ifdef DEBUG_LOGFILE
101 if(logfile)
102 {
103 LOGWRITE("CRTC Register Dump:\n")
104 for(reg=0;reg<256;++reg)
105 {
106 val=CRINB(reg);
107 fprintf(logfile,"CR0x%2x: 0x%2x\n",reg,val);
108 }
109 LOGWRITE("SR Register Dump:\n")
110 for(reg=0;reg<256;++reg)
111 {
112 val=SRINB(reg);
113 fprintf(logfile,"SR0x%2x: 0x%2x\n",reg,val);
114 }
115 }
116 #endif
117 }
118 /* --- */
119
120 static vidix_capability_t cyberblade_cap =
121 {
122 "Trident CyberBlade i1 driver",
123 "Alastair M. Robinson <blackfive@fakenhamweb.co.uk>",
124 TYPE_OUTPUT,
125 { 0, 0, 0, 0 },
126 1024,
127 1024,
128 4,
129 4,
130 -1,
131 FLAG_UPSCALER|FLAG_DOWNSCALER,
132 VENDOR_TRIDENT,
133 -1,
134 { 0, 0, 0, 0 }
135 };
136
137
138 unsigned int vixGetVersion(void)
139 {
140 return(VIDIX_VERSION);
141 }
142
143
144 static unsigned short cyberblade_card_ids[] =
145 {
146 DEVICE_TRIDENT_CYBERBLADE_I7,
147 DEVICE_TRIDENT_CYBERBLADE_I7D,
148 DEVICE_TRIDENT_CYBERBLADE_I1,
149 DEVICE_TRIDENT_CYBERBLADE_I12,
150 DEVICE_TRIDENT_CYBERBLADE_I13,
151 DEVICE_TRIDENT_CYBERBLADE_XPAI1
152 };
153
154
155 static int find_chip(unsigned chip_id)
156 {
157 unsigned i;
158 for(i = 0;i < sizeof(cyberblade_card_ids)/sizeof(unsigned short);i++)
159 {
160 if(chip_id == cyberblade_card_ids[i]) return i;
161 }
162 return -1;
163 }
164
165 int vixProbe(int verbose, int force)
166 {
167 pciinfo_t lst[MAX_PCI_DEVICES];
168 unsigned i,num_pci;
169 int err;
170 err = pci_scan(lst,&num_pci);
171 if(err)
172 {
173 printf("[cyberblade] Error occurred during pci scan: %s\n",strerror(err));
174 return err;
175 }
176 else
177 {
178 err = ENXIO;
179 for(i=0; i < num_pci; i++)
180 {
181 if(lst[i].vendor == VENDOR_TRIDENT)
182 {
183 int idx;
184 const char *dname;
185 idx = find_chip(lst[i].device);
186 if(idx == -1)
187 continue;
188 dname = pci_device_name(VENDOR_TRIDENT, lst[i].device);
189 dname = dname ? dname : "Unknown chip";
190 printf("[cyberblade] Found chip: %s\n", dname);
191 if ((lst[i].command & PCI_COMMAND_IO) == 0)
192 {
193 printf("[cyberblade] Device is disabled, ignoring\n");
194 continue;
195 }
196 cyberblade_cap.device_id = lst[i].device;
197 err = 0;
198 memcpy(&pci_info, &lst[i], sizeof(pciinfo_t));
199 break;
200 }
201 }
202 }
203
204 if(err && verbose) printf("[cyberblade] Can't find chip\n");
205 return err;
206 }
207
208
209 int vixInit(void)
210 {
211 cyberblade_mem = map_phys_mem(pci_info.base0, 0x800000);
212 enable_app_io();
213 save_colourkey[0]=SRINB(0x50);
214 save_colourkey[1]=SRINB(0x51);
215 save_colourkey[2]=SRINB(0x52);
216 save_colourkey[3]=SRINB(0x54);
217 save_colourkey[4]=SRINB(0x55);
218 save_colourkey[5]=SRINB(0x56);
219 #ifdef DEBUG_LOGFILE
220 logfile=fopen("/tmp/cyberblade_vidix.log","w");
221 #endif
222 return 0;
223 }
224
225 void vixDestroy(void)
226 {
227 int protect;
228 #ifdef DEBUG_LOGFILE
229 if(logfile)
230 fclose(logfile);
231 #endif
232 protect=SRINB(0x11);
233 SROUTB(0x11, 0x92);
234 CROUTB(0x8E, 0xc4); /* Disable overlay */
235 SROUTB(0x50,save_colourkey[0]);
236 SROUTB(0x51,save_colourkey[1]);
237 SROUTB(0x52,save_colourkey[2]);
238 SROUTB(0x54,save_colourkey[3]);
239 SROUTB(0x55,save_colourkey[4]);
240 SROUTB(0x56,save_colourkey[5]);
241 SROUTB(0x11, protect);
242 disable_app_io();
243 unmap_phys_mem(cyberblade_mem, 0x800000);
244 }
245
246
247 int vixGetCapability(vidix_capability_t *to)
248 {
249 memcpy(to, &cyberblade_cap, sizeof(vidix_capability_t));
250 return 0;
251 }
252
253
254 static int is_supported_fourcc(uint32_t fourcc)
255 {
256 switch(fourcc)
257 {
258 case IMGFMT_YUY2:
259 case IMGFMT_YV12:
260 case IMGFMT_I420:
261 case IMGFMT_YVU9:
262 case IMGFMT_BGR16:
263 return 1;
264 default:
265 return 0;
266 }
267 }
268
269 int vixQueryFourcc(vidix_fourcc_t *to)
270 {
271 if(is_supported_fourcc(to->fourcc))
272 {
273 to->depth = VID_DEPTH_1BPP | VID_DEPTH_2BPP |
274 VID_DEPTH_4BPP | VID_DEPTH_8BPP |
275 VID_DEPTH_12BPP| VID_DEPTH_15BPP|
276 VID_DEPTH_16BPP| VID_DEPTH_24BPP|
277 VID_DEPTH_32BPP;
278 to->flags = VID_CAP_EXPAND | VID_CAP_SHRINK | VID_CAP_COLORKEY;
279 return 0;
280 }
281 else
282 to->depth = to->flags = 0;
283 return ENOSYS;
284 }
285
286
287 static int frames[VID_PLAY_MAXFRAMES];
288
289 static vidix_grkey_t cyberblade_grkey;
290
291 int vixGetGrKeys(vidix_grkey_t *grkey)
292 {
293 memcpy(grkey, &cyberblade_grkey, sizeof(vidix_grkey_t));
294 return(0);
295 }
296
297 int vixSetGrKeys(const vidix_grkey_t *grkey)
298 {
299 int pixfmt=CRINB(0x38);
300 int protect;
301 memcpy(&cyberblade_grkey, grkey, sizeof(vidix_grkey_t));
302
303 protect=SRINB(0x11);
304 SROUTB(0x11, 0x92);
305
306 if(pixfmt&0x28) /* 32 or 24 bpp */
307 {
308 SROUTB(0x50, cyberblade_grkey.ckey.blue); /* Colour Key */
309 SROUTB(0x51, cyberblade_grkey.ckey.green); /* Colour Key */
310 SROUTB(0x52, cyberblade_grkey.ckey.red); /* Colour Key */
311 SROUTB(0x54, 0xff); /* Colour Key Mask */
312 SROUTB(0x55, 0xff); /* Colour Key Mask */
313 SROUTB(0x56, 0xff); /* Colour Key Mask */
314 }
315 else
316 {
317 int tmp=((cyberblade_grkey.ckey.blue & 0xF8)>>3)
318 | ((cyberblade_grkey.ckey.green & 0xfc)<<3)
319 | ((cyberblade_grkey.ckey.red & 0xf8)<<8);
320 SROUTB(0x50, tmp&0xff); /* Colour Key */
321 SROUTB(0x51, (tmp>>8)&0xff); /* Colour Key */
322 SROUTB(0x52, 0); /* Colour Key */
323 SROUTB(0x54, 0xff); /* Colour Key Mask */
324 SROUTB(0x55, 0xff); /* Colour Key Mask */
325 SROUTB(0x56, 0x00); /* Colour Key Mask */
326 }
327 SROUTB(0x11,protect);
328 return(0);
329 }
330
331
332 vidix_video_eq_t equal =
333 {
334 VEQ_CAP_BRIGHTNESS | VEQ_CAP_SATURATION | VEQ_CAP_HUE,
335 300, 100, 0, 0, 0, 0, 0, 0
336 };
337
338 int vixPlaybackGetEq( vidix_video_eq_t * eq)
339 {
340 memcpy(eq,&equal,sizeof(vidix_video_eq_t));
341 return 0;
342 }
343
344 int vixPlaybackSetEq( const vidix_video_eq_t * eq)
345 {
346 int br,sat,cr,protect;
347 if(eq->cap & VEQ_CAP_BRIGHTNESS) equal.brightness = eq->brightness;
348 if(eq->cap & VEQ_CAP_CONTRAST) equal.contrast = eq->contrast;
349 if(eq->cap & VEQ_CAP_SATURATION) equal.saturation = eq->saturation;
350 if(eq->cap & VEQ_CAP_HUE) equal.hue = eq->hue;
351 if(eq->cap & VEQ_CAP_RGB_INTENSITY)
352 {
353 equal.red_intensity = eq->red_intensity;
354 equal.green_intensity = eq->green_intensity;
355 equal.blue_intensity = eq->blue_intensity;
356 }
357 equal.flags = eq->flags;
358
359 cr = (equal.contrast) * 31 / 2000; cr+=16;
360 if (cr < 0) cr = 0; if(cr > 7) cr = 7;
361 cr=cr<<4 | cr;
362
363 br = (equal.brightness+1000) * 63 / 2000;
364 if (br < 0) br = 0; if(br > 63) br = 63;
365 if(br>32) br-=32; else br+=32;
366
367 sat = (equal.saturation + 1000) * 16 / 2000;
368 if (sat < 0) sat = 0; if(sat > 31) sat = 31;
369
370 protect=SRINB(0x11);
371 SROUTB(0x11, 0x92);
372
373 SROUTB(0xBC,cr);
374 SROUTW(0xB0,(br<<10)|4);
375
376 SROUTB(0x11, protect);
377
378 return 0;
379 }
380
381
382 static int YOffs,UOffs,VOffs;
383
384 int vixConfigPlayback(vidix_playback_t *info)
385 {
386 int shrink, zoom;
387 int src_w, drw_w;
388 int src_h, drw_h;
389 int hscale,vscale;
390 long base0;
391 int y_pitch, uv_pitch;
392 int protect=0;
393 int layout=0;
394 unsigned int i;
395
396 if(!is_supported_fourcc(info->fourcc))
397 return -1;
398
399 src_w = info->src.w;
400 src_h = info->src.h;
401
402 drw_w = info->dest.w;
403 drw_h = info->dest.h;
404
405 switch(info->fourcc)
406 {
407 case IMGFMT_YUY2:
408 case IMGFMT_BGR16:
409 y_pitch = (src_w*2 + 15) & ~15;
410 uv_pitch = 0;
411 YOffs=VOffs=UOffs=info->offset.y = info->offset.v = info->offset.u = 0;
412 info->frame_size = y_pitch*src_h;
413 layout=0x0; /* packed */
414 break;
415 case IMGFMT_YV12:
416 case IMGFMT_I420:
417 y_pitch = (src_w+15) & ~15;
418 uv_pitch = ((src_w/2)+7) & ~7;
419 YOffs=info->offset.y = 0;
420 VOffs=info->offset.v = y_pitch*src_h;
421 UOffs=info->offset.u = info->offset.v+(uv_pitch)*(src_h/2);
422 info->frame_size = y_pitch*src_h + 2*uv_pitch*(src_h/2);
423 layout=0x1; /* planar, 4:1:1 */
424 break;
425 case IMGFMT_YVU9:
426 y_pitch = (src_w+15) & ~15;
427 uv_pitch = ((src_w/4)+3) & ~3;
428 YOffs=info->offset.y = 0;
429 VOffs=info->offset.v = y_pitch*src_h;
430 UOffs=info->offset.u = info->offset.v+(uv_pitch)*(src_h/4);
431 info->frame_size = y_pitch*src_h + 2*uv_pitch*(src_h/4);
432 layout=0x51; /* planar, 16:1:1 */
433 break;
434 }
435
436 /* Assume we have 2 MB to play with */
437 info->num_frames = 0x200000 / info->frame_size;
438 if(info->num_frames > VID_PLAY_MAXFRAMES)
439 info->num_frames = VID_PLAY_MAXFRAMES;
440
441 /* Start at 6 MB. Let's hope it's not in use. */
442 base0 = 0x600000;
443 info->dga_addr = cyberblade_mem + base0;
444
445 info->dest.pitch.y = 16;
446 info->dest.pitch.u = 16;
447 info->dest.pitch.v = 16;
448
449 for(i = 0; i < info->num_frames; i++)
450 {
451 info->offsets[i] = info->frame_size * i;
452 frames[i] = base0+info->offsets[i];
453 }
454
455 OUTPORT8(0x3d4,0x39);
456 OUTPORT8(0x3d5,INPORT(0x3d5)|1);
457
458 SRINB(0x0b); /* Select new mode */
459
460 /* Unprotect hardware registers... */
461 protect=SRINB(0x11);
462 SROUTB(0x11, 0x92);
463
464 SROUTB(0x57, 0xc0); /* Playback key function */
465 SROUTB(0x21, 0x34); /* Signature control */
466 SROUTB(0x37, 0x30); /* Video key mode */
467
468 vixSetGrKeys(&cyberblade_grkey);
469
470 /* compute_scale_factor(&src_w, &drw_w, &shrink, &zoom); */
471 {
472 int HTotal,VTotal,HSync,VSync,Overflow,HDisp,VDisp;
473 int HWinStart,VWinStart;
474 int tx1,ty1,tx2,ty2;
475
476 HTotal=CRINB(0x00);
477 HSync=CRINB(0x04);
478 VTotal=CRINB(0x06);
479 VSync=CRINB(0x10);
480 Overflow=CRINB(0x07);
481 HTotal <<=3;
482 HSync <<=3;
483 VTotal |= (Overflow & 1) <<8;
484 VTotal |= (Overflow & 0x20) <<4;
485 VTotal +=4;
486 VSync |= (Overflow & 4) <<6;
487 VSync |= (Overflow & 0x80) <<2;
488
489 if(CRINB(0xd1)&0x80)
490 {
491 int TVHTotal,TVVTotal,TVHSyncStart,TVVSyncStart,TVOverflow;
492 LOGWRITE("[cyberblade] Using TV-CRTC\n");
493
494 HDisp=(1+CRINB(0x01))*8;
495 VDisp=1+CRINB(0x12);
496 Overflow=CRINB(0x07);
497 VDisp |= (Overflow & 2) <<7;
498 VDisp |= (Overflow & 0x40) << 3;
499
500 TVHTotal=CRINB(0xe0)*8;
501 TVVTotal=CRINB(0xe6);
502 TVOverflow=CRINB(0xe7);
503 if(TVOverflow&0x20) TVVTotal|=512;
504 if(TVOverflow&0x01) TVVTotal|=256;
505 TVHTotal+=40; TVVTotal+=2;
506
507 TVHSyncStart=CRINB(0xe4)*8;
508 TVVSyncStart=CRINB(0xf0);
509 if(TVOverflow&0x80) TVVSyncStart|=512;
510 if(TVOverflow&0x04) TVVSyncStart|=256;
511
512 HWinStart=(TVHTotal-HDisp)&15;
513 HWinStart|=(HTotal-HDisp)&15;
514 HWinStart+=(TVHTotal-TVHSyncStart)-49;
515 }
516 else
517 {
518 LOGWRITE("[cyberblade] Using Standard CRTC\n");
519 HWinStart=(HTotal-HSync)+15;
520 }
521 VWinStart=(VTotal-VSync)-8;
522
523 printf("[cyberblade] HTotal: 0x%x, HSStart: 0x%x\n",HTotal,HSync);
524 printf(" VTotal: 0x%x, VStart: 0x%x\n",VTotal,VSync);
525 tx1=HWinStart+info->dest.x;
526 ty1=VWinStart+info->dest.y;
527 tx2=tx1+info->dest.w;
528 ty2=ty1+info->dest.h;
529
530 CROUTW(0x86,tx1);
531 CROUTW(0x88,ty1);
532 CROUTW(0x8a,tx2);
533 CROUTW(0x8c,ty2+3);
534 }
535
536 if(src_w==drw_w)
537 hscale=0;
538 else if(src_w<drw_w)
539 {
540 hscale=((src_w<<10)/(drw_w-2)) & 0x1fff;
541 }
542 else
543 {
544 hscale=0x8000 | ((((src_w/drw_w)-1)&7)<<10) | (((drw_w<<10)/src_w) & 0x3ff);
545 }
546
547 vscale=(src_h<<10)/(drw_h);
548 if(drw_h<src_h)
549 vscale=0x8000|((drw_h<<10)/(src_h));
550
551 /* Write scale factors to hardware */
552
553 CROUTW(0x80,hscale); /* Horizontal Scale */
554 CROUTW(0x82,vscale); /* Vertical Scale */
555
556 /* Now set the start address and data layout */
557 {
558 int lb = (y_pitch+2) >> 2;
559 CROUTB(0x95, ((lb & 0x100)>>1) | 0x08 ); /* Linebuffer level bit 8 & threshold */
560 CROUTB(0x96, (lb & 0xFF)); /* Linebuffer level */
561
562 CROUTB(0x97, 0x00); /* VDE Flags */
563 CROUTB(0xBA, 0x00); /* Chroma key */
564 CROUTB(0xBB, 0x00); /* Chroma key */
565 CROUTB(0xBC, 0xFF); /* Chroma key */
566 CROUTB(0xBD, 0xFF); /* Chroma key */
567 CROUTB(0xBE, 0x04); /* Capture control */
568
569 if(src_w > 384)
570 layout|=4; /* 2x line buffers */
571 SROUTB(0x97, layout);
572
573 CROUTW(0x90,y_pitch); /* Y Bytes per row */
574 SROUTW(0x9A,uv_pitch); /* UV Bytes per row */
575
576 switch(info->fourcc)
577 {
578 case IMGFMT_BGR16:
579 CROUTB(0x8F, 0x24); /* VDE Flags - Edge Recovery & CSC Bypass */
580 CROUTB(0xBF, 0x02); /* Video format - RGB16 */
581 SROUTB(0xBE, 0x0); /* HSCB disabled */
582 break;
583 default:
584 CROUTB(0x8F, 0x20); /* VDE Flags - Edge Recovery */
585 CROUTB(0xBF, 0x00); /* Video format - YUV */
586 SROUTB(0xBE, 0x00); /* HSCB disable - was 0x03*/
587 break;
588 }
589
590 CROUTB(0x92, ((base0+info->offset.y) >> 3) &0xff); /* Lower 8 bits of start address */
591 CROUTB(0x93, ((base0+info->offset.y) >> 11) &0xff); /* Mid 8 bits of start address */
592 CROUTB(0x94, ((base0+info->offset.y) >> 19) &0xf); /* Upper 4 bits of start address */
593 SROUTB(0x80, ((base0+info->offset.v) >> 3) &0xff); /* Lower 8 bits of start address */
594 SROUTB(0x81, ((base0+info->offset.v) >> 11) &0xff); /* Mid 8 bits of start address */
595 SROUTB(0x82, ((base0+info->offset.v) >> 19) &0xf); /* Upper 4 bits of start address */
596 SROUTB(0x83, ((base0+info->offset.u) >> 3) &0xff); /* Lower 8 bits of start address */
597 SROUTB(0x84, ((base0+info->offset.u) >> 11) &0xff); /* Mid 8 bits of start address */
598 SROUTB(0x85, ((base0+info->offset.u) >> 19) &0xf); /* Upper 4 bits of start address */
599 }
600
601 vixPlaybackSetEq(&equal);
602
603 /* Protect hardware registers again */
604 SROUTB(0x11, protect);
605 return 0;
606 }
607
608
609 int vixPlaybackOn(void)
610 {
611 LOGWRITE("Enable overlay\n");
612 CROUTB(0x8E, 0xd4); /* VDE Flags*/
613
614 return 0;
615 }
616
617
618 int vixPlaybackOff(void)
619 {
620 LOGWRITE("Disable overlay\n");
621 CROUTB(0x8E, 0xc4); /* VDE Flags*/
622
623 return 0;
624 }
625
626
627 int vixPlaybackFrameSelect(unsigned int frame)
628 {
629 int protect;
630 LOGWRITE("Frame select\n");
631 protect=SRINB(0x11);
632 SROUTB(0x11, 0x92);
633 /* Set overlay address to that of selected frame */
634 CROUTB(0x92, ((frames[frame]+YOffs) >> 3) &0xff); /* Lower 8 bits of start address */
635 CROUTB(0x93, ((frames[frame]+YOffs) >> 11) &0xff); /* Mid 8 bits of start address */
636 CROUTB(0x94, ((frames[frame]+YOffs) >> 19) &0xf); /* Upper 4 bits of start address */
637 SROUTB(0x80, ((frames[frame]+VOffs) >> 3) &0xff); /* Lower 8 bits of start address */
638 SROUTB(0x81, ((frames[frame]+VOffs) >> 11) &0xff); /* Mid 8 bits of start address */
639 SROUTB(0x82, ((frames[frame]+VOffs) >> 19) &0xf); /* Upper 4 bits of start address */
640 SROUTB(0x83, ((frames[frame]+UOffs) >> 3) &0xff); /* Lower 8 bits of start address */
641 SROUTB(0x84, ((frames[frame]+UOffs) >> 11) &0xff); /* Mid 8 bits of start address */
642 SROUTB(0x85, ((frames[frame]+UOffs) >> 19) &0xf); /* Upper 4 bits of start address */
643 SROUTB(0x11, protect);
644 return 0;
645 }
646
647