1 // SPDX-License-Identifier: GPL-2.0-only
3 * newport_con.c: Abscon for newport hardware
5 * (C) 1998 Thomas Bogendoerfer (tsbogend@alpha.franken.de)
6 * (C) 1999 Ulf Carlsson (ulfc@thepuffingruop.com)
8 * This driver is based on sgicons.c and cons_newport.
10 * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
11 * Copyright (C) 1997 Miguel de Icaza (miguel@nuclecu.unam.mx)
13 #include <linux/init.h>
14 #include <linux/kernel.h>
15 #include <linux/errno.h>
17 #include <linux/selection.h>
18 #include <linux/console.h>
19 #include <linux/vt_kern.h>
21 #include <linux/module.h>
22 #include <linux/slab.h>
25 #include <linux/uaccess.h>
27 #include <asm/gio_device.h>
29 #include <video/newport.h>
31 #include <linux/linux_logo.h>
32 #include <linux/font.h>
34 #define NEWPORT_LEN 0x10000
36 #define FONT_DATA ((unsigned char *)font_vga_8x16.data)
38 static unsigned char *font_data
[MAX_NR_CONSOLES
];
40 static struct newport_regs
*npregs
;
41 static unsigned long newport_addr
;
43 static int logo_active
;
45 static int xcurs_correction
= 29;
46 static int newport_xsize
;
47 static int newport_ysize
;
48 static int newport_has_init
;
50 static int newport_set_def_font(int unit
, struct console_font
*op
);
52 #define BMASK(c) (c << 24)
54 #define RENDER(regs, cp) do { \
55 (regs)->go.zpattern = BMASK((cp)[0x0]); (regs)->go.zpattern = BMASK((cp)[0x1]); \
56 (regs)->go.zpattern = BMASK((cp)[0x2]); (regs)->go.zpattern = BMASK((cp)[0x3]); \
57 (regs)->go.zpattern = BMASK((cp)[0x4]); (regs)->go.zpattern = BMASK((cp)[0x5]); \
58 (regs)->go.zpattern = BMASK((cp)[0x6]); (regs)->go.zpattern = BMASK((cp)[0x7]); \
59 (regs)->go.zpattern = BMASK((cp)[0x8]); (regs)->go.zpattern = BMASK((cp)[0x9]); \
60 (regs)->go.zpattern = BMASK((cp)[0xa]); (regs)->go.zpattern = BMASK((cp)[0xb]); \
61 (regs)->go.zpattern = BMASK((cp)[0xc]); (regs)->go.zpattern = BMASK((cp)[0xd]); \
62 (regs)->go.zpattern = BMASK((cp)[0xe]); (regs)->go.zpattern = BMASK((cp)[0xf]); \
65 #define TESTVAL 0xdeadbeef
66 #define XSTI_TO_FXSTART(val) (((val) & 0xffff) << 11)
68 static inline void newport_render_background(int xstart
, int ystart
,
69 int xend
, int yend
, int ci
)
72 npregs
->set
.wrmask
= 0xffffffff;
73 npregs
->set
.drawmode0
= (NPORT_DMODE0_DRAW
| NPORT_DMODE0_BLOCK
|
74 NPORT_DMODE0_DOSETUP
| NPORT_DMODE0_STOPX
75 | NPORT_DMODE0_STOPY
);
76 npregs
->set
.colori
= ci
;
77 npregs
->set
.xystarti
=
78 (xstart
<< 16) | ((ystart
+ topscan
) & 0x3ff);
80 ((xend
+ 7) << 16) | ((yend
+ topscan
+ 15) & 0x3ff);
83 static inline void newport_init_cmap(void)
87 for (i
= 0; i
< 16; i
++) {
88 newport_bfwait(npregs
);
89 newport_cmap_setaddr(npregs
, color_table
[i
]);
90 newport_cmap_setrgb(npregs
,
92 default_grn
[i
], default_blu
[i
]);
96 static const struct linux_logo
*newport_show_logo(void)
98 #ifdef CONFIG_LOGO_SGI_CLUT224
99 const struct linux_logo
*logo
= fb_find_logo(8);
100 const unsigned char *clut
;
101 const unsigned char *data
;
109 for (i
= 0; i
< logo
->clutsize
; i
++) {
110 newport_bfwait(npregs
);
111 newport_cmap_setaddr(npregs
, i
+ 0x20);
112 newport_cmap_setrgb(npregs
, clut
[0], clut
[1], clut
[2]);
116 newport_wait(npregs
);
117 npregs
->set
.drawmode0
= (NPORT_DMODE0_DRAW
| NPORT_DMODE0_BLOCK
|
120 npregs
->set
.xystarti
= ((newport_xsize
- logo
->width
) << 16) | (0);
121 npregs
->set
.xyendi
= ((newport_xsize
- 1) << 16);
122 newport_wait(npregs
);
124 for (i
= 0; i
< logo
->width
*logo
->height
; i
++)
125 npregs
->go
.hostrw0
= *data
++ << 24;
130 #endif /* CONFIG_LOGO_SGI_CLUT224 */
133 static inline void newport_clear_screen(int xstart
, int ystart
, int xend
,
139 newport_wait(npregs
);
140 npregs
->set
.wrmask
= 0xffffffff;
141 npregs
->set
.drawmode0
= (NPORT_DMODE0_DRAW
| NPORT_DMODE0_BLOCK
|
142 NPORT_DMODE0_DOSETUP
| NPORT_DMODE0_STOPX
143 | NPORT_DMODE0_STOPY
);
144 npregs
->set
.colori
= ci
;
145 npregs
->set
.xystarti
= (xstart
<< 16) | ystart
;
146 npregs
->go
.xyendi
= (xend
<< 16) | yend
;
149 static inline void newport_clear_lines(int ystart
, int yend
, int ci
)
151 ystart
= ((ystart
<< 4) + topscan
) & 0x3ff;
152 yend
= ((yend
<< 4) + topscan
+ 15) & 0x3ff;
153 newport_clear_screen(0, ystart
, 1280 + 63, yend
, ci
);
156 static void newport_reset(void)
161 newport_wait(npregs
);
162 treg
= newport_vc2_get(npregs
, VC2_IREG_CONTROL
);
163 newport_vc2_set(npregs
, VC2_IREG_CONTROL
,
164 (treg
| VC2_CTRL_EVIDEO
));
166 treg
= newport_vc2_get(npregs
, VC2_IREG_CENTRY
);
167 newport_vc2_set(npregs
, VC2_IREG_RADDR
, treg
);
168 npregs
->set
.dcbmode
= (NPORT_DMODE_AVC2
| VC2_REGADDR_RAM
|
169 NPORT_DMODE_W2
| VC2_PROTOCOL
);
170 for (i
= 0; i
< 128; i
++) {
171 newport_bfwait(npregs
);
172 if (i
== 92 || i
== 94)
173 npregs
->set
.dcbdata0
.byshort
.s1
= 0xff00;
175 npregs
->set
.dcbdata0
.byshort
.s1
= 0x0000;
180 /* turn off popup plane */
181 npregs
->set
.dcbmode
= (DCB_XMAP0
| R_DCB_XMAP9_PROTOCOL
|
182 XM9_CRS_CONFIG
| NPORT_DMODE_W1
);
183 npregs
->set
.dcbdata0
.bybytes
.b3
&= ~XM9_PUPMODE
;
184 npregs
->set
.dcbmode
= (DCB_XMAP1
| R_DCB_XMAP9_PROTOCOL
|
185 XM9_CRS_CONFIG
| NPORT_DMODE_W1
);
186 npregs
->set
.dcbdata0
.bybytes
.b3
&= ~XM9_PUPMODE
;
189 npregs
->cset
.topscan
= 0x3ff;
190 npregs
->cset
.xywin
= (4096 << 16) | 4096;
192 /* Clear the screen. */
193 newport_clear_screen(0, 0, 1280 + 63, 1024, 0);
197 * calculate the actual screen size by reading
198 * the video timing out of the VC2
200 static void newport_get_screensize(void)
203 unsigned short ventry
, treg
;
204 unsigned short linetable
[128]; /* should be enough */
206 ventry
= newport_vc2_get(npregs
, VC2_IREG_VENTRY
);
207 newport_vc2_set(npregs
, VC2_IREG_RADDR
, ventry
);
208 npregs
->set
.dcbmode
= (NPORT_DMODE_AVC2
| VC2_REGADDR_RAM
|
209 NPORT_DMODE_W2
| VC2_PROTOCOL
);
210 for (i
= 0; i
< 128; i
++) {
211 newport_bfwait(npregs
);
212 linetable
[i
] = npregs
->set
.dcbdata0
.byshort
.s1
;
215 newport_xsize
= newport_ysize
= 0;
216 for (i
= 0; i
< ARRAY_SIZE(linetable
) - 1 && linetable
[i
+ 1]; i
+= 2) {
218 newport_vc2_set(npregs
, VC2_IREG_RADDR
, linetable
[i
]);
219 npregs
->set
.dcbmode
= (NPORT_DMODE_AVC2
| VC2_REGADDR_RAM
|
220 NPORT_DMODE_W2
| VC2_PROTOCOL
);
222 newport_bfwait(npregs
);
223 treg
= npregs
->set
.dcbdata0
.byshort
.s1
;
225 cols
+= (treg
>> 7) & 0xfe;
226 if ((treg
& 0x80) == 0) {
227 newport_bfwait(npregs
);
228 treg
= npregs
->set
.dcbdata0
.byshort
.s1
;
230 } while ((treg
& 0x8000) == 0);
232 if (cols
> newport_xsize
)
233 newport_xsize
= cols
;
234 newport_ysize
+= linetable
[i
+ 1];
237 printk("NG1: Screensize %dx%d\n", newport_xsize
, newport_ysize
);
240 static void newport_get_revisions(void)
243 unsigned int board_rev
;
244 unsigned int rex3_rev
;
245 unsigned int vc2_rev
;
246 unsigned int cmap_rev
;
247 unsigned int xmap9_rev
;
248 unsigned int bt445_rev
;
249 unsigned int bitplanes
;
251 rex3_rev
= npregs
->cset
.status
& NPORT_STAT_VERS
;
253 npregs
->set
.dcbmode
= (DCB_CMAP0
| NCMAP_PROTOCOL
|
254 NCMAP_REGADDR_RREG
| NPORT_DMODE_W1
);
255 tmp
= npregs
->set
.dcbdata0
.bybytes
.b3
;
257 board_rev
= (tmp
>> 4) & 7;
258 bitplanes
= ((board_rev
> 1) && (tmp
& 0x80)) ? 8 : 24;
260 npregs
->set
.dcbmode
= (DCB_CMAP1
| NCMAP_PROTOCOL
|
261 NCMAP_REGADDR_RREG
| NPORT_DMODE_W1
);
262 tmp
= npregs
->set
.dcbdata0
.bybytes
.b3
;
263 if ((tmp
& 7) < cmap_rev
)
264 cmap_rev
= (tmp
& 7);
266 vc2_rev
= (newport_vc2_get(npregs
, VC2_IREG_CONFIG
) >> 5) & 7;
268 npregs
->set
.dcbmode
= (DCB_XMAP0
| R_DCB_XMAP9_PROTOCOL
|
269 XM9_CRS_REVISION
| NPORT_DMODE_W1
);
270 xmap9_rev
= npregs
->set
.dcbdata0
.bybytes
.b3
& 7;
272 npregs
->set
.dcbmode
= (DCB_BT445
| BT445_PROTOCOL
|
273 BT445_CSR_ADDR_REG
| NPORT_DMODE_W1
);
274 npregs
->set
.dcbdata0
.bybytes
.b3
= BT445_REVISION_REG
;
275 npregs
->set
.dcbmode
= (DCB_BT445
| BT445_PROTOCOL
|
276 BT445_CSR_REVISION
| NPORT_DMODE_W1
);
277 bt445_rev
= (npregs
->set
.dcbdata0
.bybytes
.b3
>> 4) - 0x0a;
279 #define L(a) (char)('A'+(a))
281 ("NG1: Revision %d, %d bitplanes, REX3 revision %c, VC2 revision %c, xmap9 revision %c, cmap revision %c, bt445 revision %c\n",
282 board_rev
, bitplanes
, L(rex3_rev
), L(vc2_rev
), L(xmap9_rev
),
283 L(cmap_rev
? (cmap_rev
+ 1) : 0), L(bt445_rev
));
286 if (board_rev
== 3) /* I don't know all affected revisions */
287 xcurs_correction
= 21;
290 static void newport_exit(void)
294 /* free memory used by user font */
295 for (i
= 0; i
< MAX_NR_CONSOLES
; i
++)
296 newport_set_def_font(i
, NULL
);
299 /* Can't be __init, do_take_over_console may call it later */
300 static const char *newport_startup(void)
304 npregs
->cset
.config
= NPORT_CFG_GD0
;
306 if (newport_wait(npregs
))
309 npregs
->set
.xstarti
= TESTVAL
;
310 if (npregs
->set
._xstart
.word
!= XSTI_TO_FXSTART(TESTVAL
))
313 for (i
= 0; i
< MAX_NR_CONSOLES
; i
++)
314 font_data
[i
] = FONT_DATA
;
317 newport_get_revisions();
318 newport_get_screensize();
319 newport_has_init
= 1;
321 return "SGI Newport";
327 static void newport_init(struct vc_data
*vc
, int init
)
331 cols
= newport_xsize
/ 8;
332 rows
= newport_ysize
/ 16;
333 vc
->vc_can_do_color
= 1;
338 vc_resize(vc
, cols
, rows
);
341 static void newport_deinit(struct vc_data
*c
)
343 if (!con_is_bound(&newport_con
) && newport_has_init
) {
345 newport_has_init
= 0;
349 static void newport_clear(struct vc_data
*vc
, int sy
, int sx
, int height
,
352 int xend
= ((sx
+ width
) << 3) - 1;
353 int ystart
= ((sy
<< 4) + topscan
) & 0x3ff;
354 int yend
= (((sy
+ height
) << 4) + topscan
- 1) & 0x3ff;
360 newport_clear_screen(sx
<< 3, ystart
, xend
, yend
,
361 (vc
->state
.color
& 0xf0) >> 4);
363 newport_clear_screen(sx
<< 3, ystart
, xend
, 1023,
364 (vc
->state
.color
& 0xf0) >> 4);
365 newport_clear_screen(sx
<< 3, 0, xend
, yend
,
366 (vc
->state
.color
& 0xf0) >> 4);
370 static void newport_putc(struct vc_data
*vc
, int charattr
, int ypos
,
375 p
= &font_data
[vc
->vc_num
][(charattr
& 0xff) << 4];
376 charattr
= (charattr
>> 8) & 0xff;
380 newport_render_background(xpos
, ypos
, xpos
, ypos
,
381 (charattr
& 0xf0) >> 4);
383 /* Set the color and drawing mode. */
384 newport_wait(npregs
);
385 npregs
->set
.colori
= charattr
& 0xf;
386 npregs
->set
.drawmode0
= (NPORT_DMODE0_DRAW
| NPORT_DMODE0_BLOCK
|
387 NPORT_DMODE0_STOPX
| NPORT_DMODE0_ZPENAB
|
390 /* Set coordinates for bitmap operation. */
391 npregs
->set
.xystarti
= (xpos
<< 16) | ((ypos
+ topscan
) & 0x3ff);
392 npregs
->set
.xyendi
= ((xpos
+ 7) << 16);
393 newport_wait(npregs
);
395 /* Go, baby, go... */
399 static void newport_putcs(struct vc_data
*vc
, const unsigned short *s
,
400 int count
, int ypos
, int xpos
)
406 charattr
= (scr_readw(s
) >> 8) & 0xff;
412 /* Clear the area behing the string */
413 newport_render_background(xpos
, ypos
,
414 xpos
+ ((count
- 1) << 3), ypos
,
415 (charattr
& 0xf0) >> 4);
417 newport_wait(npregs
);
419 /* Set the color and drawing mode. */
420 npregs
->set
.colori
= charattr
& 0xf;
421 npregs
->set
.drawmode0
= (NPORT_DMODE0_DRAW
| NPORT_DMODE0_BLOCK
|
422 NPORT_DMODE0_STOPX
| NPORT_DMODE0_ZPENAB
|
425 for (i
= 0; i
< count
; i
++, xpos
+= 8) {
426 p
= &font_data
[vc
->vc_num
][(scr_readw(s
++) & 0xff) << 4];
428 newport_wait(npregs
);
430 /* Set coordinates for bitmap operation. */
431 npregs
->set
.xystarti
=
432 (xpos
<< 16) | ((ypos
+ topscan
) & 0x3ff);
433 npregs
->set
.xyendi
= ((xpos
+ 7) << 16);
435 /* Go, baby, go... */
440 static void newport_cursor(struct vc_data
*vc
, int mode
)
447 treg
= newport_vc2_get(npregs
, VC2_IREG_CONTROL
);
448 newport_vc2_set(npregs
, VC2_IREG_CONTROL
,
449 (treg
& ~(VC2_CTRL_ECDISP
)));
454 treg
= newport_vc2_get(npregs
, VC2_IREG_CONTROL
);
455 newport_vc2_set(npregs
, VC2_IREG_CONTROL
,
456 (treg
| VC2_CTRL_ECDISP
));
457 xcurs
= (vc
->vc_pos
- vc
->vc_visible_origin
) / 2;
458 ycurs
= ((xcurs
/ vc
->vc_cols
) << 4) + 31;
459 xcurs
= ((xcurs
% vc
->vc_cols
) << 3) + xcurs_correction
;
460 newport_vc2_set(npregs
, VC2_IREG_CURSX
, xcurs
);
461 newport_vc2_set(npregs
, VC2_IREG_CURSY
, ycurs
);
465 static int newport_switch(struct vc_data
*vc
)
467 static int logo_drawn
= 0;
470 npregs
->cset
.topscan
= 0x3ff;
473 if (newport_show_logo()) {
482 static int newport_blank(struct vc_data
*c
, int blank
, int mode_switch
)
487 /* unblank console */
488 treg
= newport_vc2_get(npregs
, VC2_IREG_CONTROL
);
489 newport_vc2_set(npregs
, VC2_IREG_CONTROL
,
490 (treg
| VC2_CTRL_EDISP
));
493 treg
= newport_vc2_get(npregs
, VC2_IREG_CONTROL
);
494 newport_vc2_set(npregs
, VC2_IREG_CONTROL
,
495 (treg
& ~(VC2_CTRL_EDISP
)));
500 static int newport_set_font(int unit
, struct console_font
*op
)
504 int size
= h
* op
->charcount
;
506 unsigned char *new_data
, *data
= op
->data
, *p
;
508 /* ladis: when I grow up, there will be a day... and more sizes will
509 * be supported ;-) */
510 if ((w
!= 8) || (h
!= 16)
511 || (op
->charcount
!= 256 && op
->charcount
!= 512))
514 if (!(new_data
= kmalloc(FONT_EXTRA_WORDS
* sizeof(int) + size
,
515 GFP_USER
))) return -ENOMEM
;
517 new_data
+= FONT_EXTRA_WORDS
* sizeof(int);
518 FNTSIZE(new_data
) = size
;
519 FNTCHARCNT(new_data
) = op
->charcount
;
520 REFCOUNT(new_data
) = 0; /* usage counter */
521 FNTSUM(new_data
) = 0;
524 for (i
= 0; i
< op
->charcount
; i
++) {
530 /* check if font is already used by other console */
531 for (i
= 0; i
< MAX_NR_CONSOLES
; i
++) {
532 if (font_data
[i
] != FONT_DATA
533 && FNTSIZE(font_data
[i
]) == size
534 && !memcmp(font_data
[i
], new_data
, size
)) {
535 kfree(new_data
- FONT_EXTRA_WORDS
* sizeof(int));
536 /* current font is the same as the new one */
539 new_data
= font_data
[i
];
543 /* old font is user font */
544 if (font_data
[unit
] != FONT_DATA
) {
545 if (--REFCOUNT(font_data
[unit
]) == 0)
546 kfree(font_data
[unit
] -
547 FONT_EXTRA_WORDS
* sizeof(int));
549 REFCOUNT(new_data
)++;
550 font_data
[unit
] = new_data
;
555 static int newport_set_def_font(int unit
, struct console_font
*op
)
557 if (font_data
[unit
] != FONT_DATA
) {
558 if (--REFCOUNT(font_data
[unit
]) == 0)
559 kfree(font_data
[unit
] -
560 FONT_EXTRA_WORDS
* sizeof(int));
561 font_data
[unit
] = FONT_DATA
;
567 static int newport_font_default(struct vc_data
*vc
, struct console_font
*op
, char *name
)
569 return newport_set_def_font(vc
->vc_num
, op
);
572 static int newport_font_set(struct vc_data
*vc
, struct console_font
*font
, unsigned flags
)
574 return newport_set_font(vc
->vc_num
, font
);
577 static bool newport_scroll(struct vc_data
*vc
, unsigned int t
, unsigned int b
,
578 enum con_scroll dir
, unsigned int lines
)
581 unsigned short *s
, *d
;
582 unsigned short chattr
;
584 logo_active
= 0; /* it's time to disable the logo now.. */
586 if (t
== 0 && b
== vc
->vc_rows
) {
588 topscan
= (topscan
+ (lines
<< 4)) & 0x3ff;
589 newport_clear_lines(vc
->vc_rows
- lines
,
591 (vc
->state
.color
& 0xf0) >> 4);
593 topscan
= (topscan
+ (-lines
<< 4)) & 0x3ff;
594 newport_clear_lines(0, lines
- 1,
595 (vc
->state
.color
& 0xf0) >> 4);
597 npregs
->cset
.topscan
= (topscan
- 1) & 0x3ff;
601 count
= (b
- t
- lines
) * vc
->vc_cols
;
605 s
= (unsigned short *) (vc
->vc_origin
+
606 vc
->vc_size_row
* (t
+ lines
));
607 d
= (unsigned short *) (vc
->vc_origin
+
608 vc
->vc_size_row
* t
);
610 chattr
= scr_readw(s
++);
611 if (chattr
!= scr_readw(d
)) {
612 newport_putc(vc
, chattr
, y
, x
);
613 scr_writew(chattr
, d
);
616 if (++x
== vc
->vc_cols
) {
621 d
= (unsigned short *) (vc
->vc_origin
+
622 vc
->vc_size_row
* (b
- lines
));
625 for (count
= 0; count
< (lines
* vc
->vc_cols
); count
++) {
626 if (scr_readw(d
) != vc
->vc_video_erase_char
) {
627 newport_putc(vc
, vc
->vc_video_erase_char
,
629 scr_writew(vc
->vc_video_erase_char
, d
);
632 if (++x
== vc
->vc_cols
) {
640 s
= (unsigned short *) (vc
->vc_origin
+
641 vc
->vc_size_row
* (b
- lines
) - 2);
642 d
= (unsigned short *) (vc
->vc_origin
+
643 vc
->vc_size_row
* b
- 2);
645 chattr
= scr_readw(s
--);
646 if (chattr
!= scr_readw(d
)) {
647 newport_putc(vc
, chattr
, y
, x
);
648 scr_writew(chattr
, d
);
656 d
= (unsigned short *) (vc
->vc_origin
+
657 vc
->vc_size_row
* t
);
660 for (count
= 0; count
< (lines
* vc
->vc_cols
); count
++) {
661 if (scr_readw(d
) != vc
->vc_video_erase_char
) {
662 newport_putc(vc
, vc
->vc_video_erase_char
,
664 scr_writew(vc
->vc_video_erase_char
, d
);
667 if (++x
== vc
->vc_cols
) {
676 static void newport_save_screen(struct vc_data
*vc
) { }
678 const struct consw newport_con
= {
679 .owner
= THIS_MODULE
,
680 .con_startup
= newport_startup
,
681 .con_init
= newport_init
,
682 .con_deinit
= newport_deinit
,
683 .con_clear
= newport_clear
,
684 .con_putc
= newport_putc
,
685 .con_putcs
= newport_putcs
,
686 .con_cursor
= newport_cursor
,
687 .con_scroll
= newport_scroll
,
688 .con_switch
= newport_switch
,
689 .con_blank
= newport_blank
,
690 .con_font_set
= newport_font_set
,
691 .con_font_default
= newport_font_default
,
692 .con_save_screen
= newport_save_screen
695 static int newport_probe(struct gio_device
*dev
,
696 const struct gio_device_id
*id
)
700 if (!dev
->resource
.start
)
704 return -EBUSY
; /* we only support one Newport as console */
706 newport_addr
= dev
->resource
.start
+ 0xF0000;
707 if (!request_mem_region(newport_addr
, NEWPORT_LEN
, "Newport"))
710 npregs
= (struct newport_regs
*)/* ioremap cannot fail */
711 ioremap(newport_addr
, sizeof(struct newport_regs
));
713 err
= do_take_over_console(&newport_con
, 0, MAX_NR_CONSOLES
- 1, 1);
717 iounmap((void *)npregs
);
718 release_mem_region(newport_addr
, NEWPORT_LEN
);
723 static void newport_remove(struct gio_device
*dev
)
725 give_up_console(&newport_con
);
726 iounmap((void *)npregs
);
727 release_mem_region(newport_addr
, NEWPORT_LEN
);
730 static struct gio_device_id newport_ids
[] = {
735 MODULE_ALIAS("gio:7e");
737 static struct gio_driver newport_driver
= {
739 .id_table
= newport_ids
,
740 .probe
= newport_probe
,
741 .remove
= newport_remove
,
743 module_driver(newport_driver
, gio_register_driver
, gio_unregister_driver
);
745 MODULE_LICENSE("GPL");