static ssize_t eisa_eeprom_read(struct file * file,
			      char *buf, size_t count, loff_t *ppos )
{
	unsigned char *tmp;
	ssize_t ret;
	int i;
	
	if (*ppos >= HPEE_MAX_LENGTH)
		return 0;
	
	count = *ppos + count < HPEE_MAX_LENGTH ? count : HPEE_MAX_LENGTH - *ppos;
	tmp = kmalloc(count, GFP_KERNEL);
	if (tmp) {
		for (i = 0; i < count; i++)
			tmp[i] = gsc_readb(eeprom_addr+(*ppos)++);

		if (copy_to_user (buf, tmp, count))
			ret = -EFAULT;
		else
			ret = count;
		kfree (tmp);
	} else
		ret = -ENOMEM;
	
	return ret;
}
Esempio n. 2
0
int __init
asp_init_chip(struct parisc_device *dev)
{
	struct busdevice *asp;
	struct gsc_irq gsc_irq;
	int irq, ret;

	asp = kmalloc(sizeof(struct busdevice), GFP_KERNEL);
	if(!asp)
		return -ENOMEM;

	asp->version = gsc_readb(dev->hpa + ASP_VER_OFFSET) & 0xf;
	asp->name = (asp->version == 1) ? "Asp" : "Cutoff";
	asp->hpa = ASP_INTERRUPT_ADDR;

	printk(KERN_INFO "%s version %d at 0x%lx found.\n", 
		asp->name, asp->version, dev->hpa);

	/* the IRQ ASP should use */
	ret = -EBUSY;
	irq = gsc_claim_irq(&gsc_irq, ASP_GSC_IRQ);
	if (irq < 0) {
		printk(KERN_ERR "%s(): cannot get GSC irq\n", __FUNCTION__);
		goto out;
	}

	ret = request_irq(gsc_irq.irq, busdev_barked, 0, "asp", asp);
	if (ret < 0)
		goto out;

	/* Save this for debugging later */
	asp->parent_irq = gsc_irq.irq;
	asp->eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;

	/* Program VIPER to interrupt on the ASP irq */
	gsc_writel((1 << (31 - ASP_GSC_IRQ)),VIPER_INT_WORD);

	/* Done init'ing, register this driver */
	ret = gsc_common_irqsetup(dev, asp);
	if (ret)
		goto out;

	fixup_child_irqs(dev, asp->busdev_region->data.irqbase, asp_choose_irq);
	/* Mongoose is a sibling of Asp, not a child... */
	fixup_child_irqs(dev->parent, asp->busdev_region->data.irqbase,
			asp_choose_irq);

	/* initialize the chassis LEDs */ 
#ifdef CONFIG_CHASSIS_LCD_LED	
	register_led_driver(DISPLAY_MODEL_OLD_ASP, LED_CMD_REG_NONE, 
		    (char *)ASP_LED_ADDR);
#endif

	return 0;

out:
	kfree(asp);
	return ret;
}
Esempio n. 3
0
/*************** primitives for use in any context *********************/
static inline uint8_t hp_sdc_status_in8 (void) {
	uint8_t status;
	unsigned long flags;

	write_lock_irqsave(&hp_sdc.ibf_lock, flags);
	status = gsc_readb(hp_sdc.status_io);
	if (!(status & HP_SDC_STATUS_IBF)) hp_sdc.ibf = 0;
	write_unlock_irqrestore(&hp_sdc.ibf_lock, flags);

	return status;
}
Esempio n. 4
0
static int __init asp_init_chip(struct parisc_device *dev)
{
	struct gsc_irq gsc_irq;
	int ret;

	asp.version = gsc_readb(dev->hpa.start + ASP_VER_OFFSET) & 0xf;
	asp.name = (asp.version == 1) ? "Asp" : "Cutoff";
	asp.hpa = ASP_INTERRUPT_ADDR;

#ifdef CONFIG_DEBUG_PRINTK
	printk(KERN_INFO "%s version %d at 0x%lx found.\n", 
		asp.name, asp.version, (unsigned long)dev->hpa.start);
#else
	;
#endif

	/* the IRQ ASP should use */
	ret = -EBUSY;
	dev->irq = gsc_claim_irq(&gsc_irq, ASP_GSC_IRQ);
	if (dev->irq < 0) {
		printk(KERN_ERR "%s(): cannot get GSC irq\n", __func__);
		goto out;
	}

	asp.eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;

	ret = request_irq(gsc_irq.irq, gsc_asic_intr, 0, "asp", &asp);
	if (ret < 0)
		goto out;

	/* Program VIPER to interrupt on the ASP irq */
	gsc_writel((1 << (31 - ASP_GSC_IRQ)),VIPER_INT_WORD);

	/* Done init'ing, register this driver */
	ret = gsc_common_setup(dev, &asp);
	if (ret)
		goto out;

	gsc_fixup_irqs(dev, &asp, asp_choose_irq);
	/* Mongoose is a sibling of Asp, not a child... */
	gsc_fixup_irqs(parisc_parent(dev), &asp, asp_choose_irq);

	/* initialize the chassis LEDs */ 
#ifdef CONFIG_CHASSIS_LCD_LED	
	register_led_driver(DISPLAY_MODEL_OLD_ASP, LED_CMD_REG_NONE, 
		    ASP_LED_ADDR);
#endif

 out:
	return ret;
}
Esempio n. 5
0
static u8 handle_lasikbd_event(unsigned long hpa)
{
        u8 status_keyb,status_mouse,scancode,id;
        extern void handle_at_scancode(int); /* in drivers/char/keyb_at.c */
        
        /* Mask to get the base address of the PS/2 controller */
        id = gsc_readb(hpa+LASI_ID) & 0x0f;
        
        if (id==1) 
		hpa -= LASI_PSAUX_OFFSET; 
	
        status_keyb = read_status(hpa);
        status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);

        while ((status_keyb|status_mouse) & LASI_STAT_RBNE){
           
		while (status_keyb & LASI_STAT_RBNE) {
	      
		scancode = read_input(hpa);

	        /* XXX don't know if this is a valid fix, but filtering
	         * 0xfa avoids 'unknown scancode' errors on, eg, capslock
	         * on some keyboards.
	         */
	      	      
		if (scancode == AUX_REPLY_ACK) 
			cmd_status=0;
			
		else if (scancode == AUX_RESEND)
			cmd_status=1;
		else 
			handle_at_scancode(scancode); 
	      
		status_keyb =read_status(hpa);
		}
	   
#ifdef CONFIG_PSMOUSE
		while (status_mouse & LASI_STAT_RBNE) {
			scancode = read_input(hpa+LASI_PSAUX_OFFSET);
			handle_mouse_scancode(scancode);
			status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);
		}
		status_mouse = read_status(hpa+LASI_PSAUX_OFFSET);
#endif /* CONFIG_PSMOUSE */
		status_keyb = read_status(hpa);
        }

        tasklet_schedule(&keyboard_tasklet);
        return (status_keyb|status_mouse);
}
Esempio n. 6
0
static int __init asp_init_chip(struct parisc_device *dev)
{
	struct gsc_irq gsc_irq;
	int ret;

	asp.version = gsc_readb(dev->hpa.start + ASP_VER_OFFSET) & 0xf;
	asp.name = (asp.version == 1) ? "Asp" : "Cutoff";
	asp.hpa = ASP_INTERRUPT_ADDR;

	printk(KERN_INFO "%s version %d at 0x%lx found.\n", 
		asp.name, asp.version, (unsigned long)dev->hpa.start);

	
	ret = -EBUSY;
	dev->irq = gsc_claim_irq(&gsc_irq, ASP_GSC_IRQ);
	if (dev->irq < 0) {
		printk(KERN_ERR "%s(): cannot get GSC irq\n", __func__);
		goto out;
	}

	asp.eim = ((u32) gsc_irq.txn_addr) | gsc_irq.txn_data;

	ret = request_irq(gsc_irq.irq, gsc_asic_intr, 0, "asp", &asp);
	if (ret < 0)
		goto out;

	
	gsc_writel((1 << (31 - ASP_GSC_IRQ)),VIPER_INT_WORD);

	
	ret = gsc_common_setup(dev, &asp);
	if (ret)
		goto out;

	gsc_fixup_irqs(dev, &asp, asp_choose_irq);
	
	gsc_fixup_irqs(parisc_parent(dev), &asp, asp_choose_irq);

	 
#ifdef CONFIG_CHASSIS_LCD_LED	
	register_led_driver(DISPLAY_MODEL_OLD_ASP, LED_CMD_REG_NONE, 
		    ASP_LED_ADDR);
#endif

 out:
	return ret;
}
Esempio n. 7
0
/*	Care must be taken to only invoke hp_sdc_spin_ibf when 
 *	absolutely needed, or in rarely invoked subroutines.  
 *	Not only does it waste CPU cycles, it also wastes bus cycles. 
 */
static inline void hp_sdc_spin_ibf(void) {
	unsigned long flags;
	rwlock_t *lock;

	lock = &hp_sdc.ibf_lock;

	read_lock_irqsave(lock, flags);
	if (!hp_sdc.ibf) {
		read_unlock_irqrestore(lock, flags);
		return;
	}
	read_unlock(lock);
	write_lock(lock);
	while (gsc_readb(hp_sdc.status_io) & HP_SDC_STATUS_IBF) {};
	hp_sdc.ibf = 0;
	write_unlock_irqrestore(lock, flags);
}
int eisa_enumerator(unsigned long eeprom_addr,
		    struct resource *io_parent, struct resource *mem_parent) 
{
	int i;
	struct eeprom_header *eh;
	static char eeprom_buf[HPEE_MAX_LENGTH];
	
	for (i=0; i < HPEE_MAX_LENGTH; i++) {
		eeprom_buf[i] = gsc_readb(eeprom_addr+i);
	}
	
	printk(KERN_INFO "Enumerating EISA bus\n");
		    	
	eh = (struct eeprom_header*)(eeprom_buf);
	for (i=0;i<eh->num_slots;i++) {
		struct eeprom_eisa_slot_info *es;
		
		es = (struct eeprom_eisa_slot_info*)
			(&eeprom_buf[HPEE_SLOT_INFO(i)]);
	        
		if (-1==init_slot(i+1, es)) {
			return -1;
			
		}
		
		if (es->config_data_offset < HPEE_MAX_LENGTH) {
			if (parse_slot_config(i+1, &eeprom_buf[es->config_data_offset],
					      es, io_parent, mem_parent)) {
				return -1;
			}
		} else {
			printk (KERN_WARNING "EISA EEPROM offset 0x%x out of range\n",es->config_data_offset);
			return -1;
		}
	}
	return 0;
}
Esempio n. 9
0
void
sti_putc(struct sti_struct *sti, int c, int y, int x)
{
	struct sti_font_inptr inptr = {
		.font_start_addr= STI_PTR(sti->font->raw),
		.index		= c_index(sti, c),
		.fg_color	= c_fg(sti, c),
		.bg_color	= c_bg(sti, c),
		.dest_x		= x * sti->font_width,
		.dest_y		= y * sti->font_height,
	};
	struct sti_font_outptr outptr = { 0, };
	s32 ret;
	unsigned long flags;

	do {
		spin_lock_irqsave(&sti->lock, flags);
		ret = STI_CALL(sti->font_unpmv, &default_font_flags,
			&inptr, &outptr, sti->glob_cfg);
		spin_unlock_irqrestore(&sti->lock, flags);
	} while (ret == 1);
}

static const struct sti_blkmv_flags clear_blkmv_flags = {
	.wait	= STI_WAIT, 
	.color	= 1, 
	.clear	= 1, 
};

void
sti_set(struct sti_struct *sti, int src_y, int src_x,
	int height, int width, u8 color)
{
	struct sti_blkmv_inptr inptr = {
		.fg_color	= color,
		.bg_color	= color,
		.src_x		= src_x,
		.src_y		= src_y,
		.dest_x		= src_x,
		.dest_y		= src_y,
		.width		= width,
		.height		= height,
	};
	struct sti_blkmv_outptr outptr = { 0, };
	s32 ret;
	unsigned long flags;
	
	do {
		spin_lock_irqsave(&sti->lock, flags);
		ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
			&inptr, &outptr, sti->glob_cfg);
		spin_unlock_irqrestore(&sti->lock, flags);
	} while (ret == 1);
}

void
sti_clear(struct sti_struct *sti, int src_y, int src_x,
	  int height, int width, int c)
{
	struct sti_blkmv_inptr inptr = {
		.fg_color	= c_fg(sti, c),
		.bg_color	= c_bg(sti, c),
		.src_x		= src_x * sti->font_width,
		.src_y		= src_y * sti->font_height,
		.dest_x		= src_x * sti->font_width,
		.dest_y		= src_y * sti->font_height,
		.width		= width * sti->font_width,
		.height		= height* sti->font_height,
	};
	struct sti_blkmv_outptr outptr = { 0, };
	s32 ret;
	unsigned long flags;

	do {
		spin_lock_irqsave(&sti->lock, flags);
		ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
			&inptr, &outptr, sti->glob_cfg);
		spin_unlock_irqrestore(&sti->lock, flags);
	} while (ret == 1);
}

static const struct sti_blkmv_flags default_blkmv_flags = {
	.wait = STI_WAIT, 
};

void
sti_bmove(struct sti_struct *sti, int src_y, int src_x,
	  int dst_y, int dst_x, int height, int width)
{
	struct sti_blkmv_inptr inptr = {
		.src_x		= src_x * sti->font_width,
		.src_y		= src_y * sti->font_height,
		.dest_x		= dst_x * sti->font_width,
		.dest_y		= dst_y * sti->font_height,
		.width		= width * sti->font_width,
		.height		= height* sti->font_height,
	};
	struct sti_blkmv_outptr outptr = { 0, };
	s32 ret;
	unsigned long flags;

	do {
		spin_lock_irqsave(&sti->lock, flags);
		ret = STI_CALL(sti->block_move, &default_blkmv_flags,
			&inptr, &outptr, sti->glob_cfg);
		spin_unlock_irqrestore(&sti->lock, flags);
	} while (ret == 1);
}


/* FIXME: Do we have another solution for this ? */
static void sti_flush(unsigned long from, unsigned long len)
{
	flush_data_cache();
	flush_kernel_dcache_range(from, len);
	flush_icache_range(from, from+len);
}

void __init
sti_rom_copy(unsigned long base, unsigned long count, void *dest)
{
	unsigned long dest_len = count;
	unsigned long dest_start = (unsigned long) dest;

	/* this still needs to be revisited (see arch/parisc/mm/init.c:246) ! */
	while (count >= 4) {
		count -= 4;
		*(u32 *)dest = gsc_readl(base);
		base += 4;
		dest += 4;
	}
	while (count) {
		count--;
		*(u8 *)dest = gsc_readb(base);
		base++;
		dest++;
	}

	sti_flush(dest_start, dest_len);
}




static char default_sti_path[21] __read_mostly;

#ifndef MODULE
static int __init sti_setup(char *str)
{
	if (str)
		strlcpy (default_sti_path, str, sizeof (default_sti_path));
	
	return 1;
}

/*	Assuming the machine has multiple STI consoles (=graphic cards) which
 *	all get detected by sticon, the user may define with the linux kernel
 *	parameter sti=<x> which of them will be the initial boot-console.
 *	<x> is a number between 0 and MAX_STI_ROMS, with 0 as the default 
 *	STI screen.
 */
__setup("sti=", sti_setup);
#endif



static char __initdata	*font_name[MAX_STI_ROMS] = { "VGA8x16", };
static int __initdata	font_index[MAX_STI_ROMS], 
			font_height[MAX_STI_ROMS],
			font_width[MAX_STI_ROMS];
#ifndef MODULE
static int __init sti_font_setup(char *str)
{
	char *x;
	int i = 0;

	/* we accept sti_font=VGA8x16, sti_font=10x20, sti_font=10*20 
	 * or sti_font=7 style command lines. */

	while (i<MAX_STI_ROMS && str && *str) {
		if (*str>='0' && *str<='9') {
			if ((x = strchr(str, 'x')) || (x = strchr(str, '*'))) {
				font_height[i] = simple_strtoul(str, NULL, 0);
				font_width[i] = simple_strtoul(x+1, NULL, 0);
			} else {
				font_index[i] = simple_strtoul(str, NULL, 0);
			}
		} else {
			font_name[i] = str;	/* fb font name */
		}

		if ((x = strchr(str, ',')))
			*x++ = 0;
		str = x;

		i++;
	}

	return 1;
}

/*	The optional linux kernel parameter "sti_font" defines which font
 *	should be used by the sticon driver to draw characters to the screen.
 *	Possible values are:
 *	- sti_font=<fb_fontname>:
 *		<fb_fontname> is the name of one of the linux-kernel built-in 
 *		framebuffer font names (e.g. VGA8x16, SUN22x18). 
 *		This is only available if the fonts have been statically compiled 
 *		in with e.g. the CONFIG_FONT_8x16 or CONFIG_FONT_SUN12x22 options.
 *	- sti_font=<number>
 *		most STI ROMs have built-in HP specific fonts, which can be selected
 *		by giving the desired number to the sticon driver. 
 *		NOTE: This number is machine and STI ROM dependend.
 *	- sti_font=<height>x<width>  (e.g. sti_font=16x8)
 *		<height> and <width> gives hints to the height and width of the
 *		font which the user wants. The sticon driver will try to use
 *		a font with this height and width, but if no suitable font is
 *		found, sticon will use the default 8x8 font.
 */
__setup("sti_font=", sti_font_setup);
#endif


	
static void __init
sti_dump_globcfg(struct sti_glob_cfg *glob_cfg, unsigned int sti_mem_request)
{
	struct sti_glob_cfg_ext *cfg;
	
	DPRINTK((KERN_INFO
		"%d text planes\n"
		"%4d x %4d screen resolution\n"
		"%4d x %4d offscreen\n"
		"%4d x %4d layout\n"
		"regions at %08x %08x %08x %08x\n"
		"regions at %08x %08x %08x %08x\n"
		"reent_lvl %d\n"
		"save_addr %08x\n",
		glob_cfg->text_planes,
		glob_cfg->onscreen_x, glob_cfg->onscreen_y,
		glob_cfg->offscreen_x, glob_cfg->offscreen_y,
		glob_cfg->total_x, glob_cfg->total_y,
		glob_cfg->region_ptrs[0], glob_cfg->region_ptrs[1],
		glob_cfg->region_ptrs[2], glob_cfg->region_ptrs[3],
		glob_cfg->region_ptrs[4], glob_cfg->region_ptrs[5],
		glob_cfg->region_ptrs[6], glob_cfg->region_ptrs[7],
		glob_cfg->reent_lvl,
		glob_cfg->save_addr));

	/* dump extended cfg */ 
	cfg = PTR_STI((unsigned long)glob_cfg->ext_ptr);
	DPRINTK(( KERN_INFO
		"monitor %d\n"
		"in friendly mode: %d\n"
		"power consumption %d watts\n"
		"freq ref %d\n"
		"sti_mem_addr %08x (size=%d bytes)\n",
		cfg->curr_mon,
		cfg->friendly_boot,
		cfg->power,
		cfg->freq_ref,
		cfg->sti_mem_addr, sti_mem_request));
}

static void __init
sti_dump_outptr(struct sti_struct *sti)
{
	DPRINTK((KERN_INFO
		"%d bits per pixel\n"
		"%d used bits\n"
		"%d planes\n"
		"attributes %08x\n",
		 sti->outptr.bits_per_pixel,
		 sti->outptr.bits_used,
		 sti->outptr.planes,
		 sti->outptr.attributes));
}
Esempio n. 10
0
static inline u8 read_status(unsigned long hpa)
{
        return gsc_readb(hpa+LASI_STATUS);
}
Esempio n. 11
0
static inline u8 read_control(unsigned long hpa)
{
        return gsc_readb(hpa+LASI_CONTROL);
}
Esempio n. 12
0
static inline u8 read_input(unsigned long hpa)
{
	return gsc_readb(hpa+LASI_RCVDATA);
}
Esempio n. 13
0
static int __init
lasi_ps2_register(struct parisc_device *dev)
{
	unsigned long hpa = dev->hpa;
	char *name;
	int device_found = 0;
	u8 id;

	id = gsc_readb(hpa+LASI_ID) & 0x0f;

	switch (id) {
	case 0:
		name = "keyboard";
		lasikbd_hpa = hpa;	/* save "hpa" for lasikbd_leds() */
		break;
	case 1:
		name = "psaux";
		break;
	default:
		printk(KERN_WARNING "%s: Unknown PS/2 port (id=%d) - ignored.\n",
			__FUNCTION__, id );
		return 0;
	}
	
	/* reset the PS/2 port */
	lasi_ps2_reset(hpa);

	switch (id) {
	case 0:	
	        device_found = init_keyb(hpa);
		if (device_found) register_kbd_ops(&gsc_ps2_kbd_ops);
		break;
	case 1:
#ifdef CONFIG_PSMOUSE
		queue = (struct aux_queue *) kmalloc(sizeof(*queue), GFP_KERNEL);
		if (!queue)
			return -ENOMEM;

		memset(queue, 0, sizeof(*queue));
		queue->head = queue->tail = 0;
		init_waitqueue_head(&queue->proc_list);
		
		misc_register(&psaux_mouse);

		aux_write_ack(AUX_ENABLE_DEV);
		/* try it a second time, this will give status if the device is
		 * available */
		device_found = aux_write_ack(AUX_ENABLE_DEV);
		break;
#else
		/* return without printing any unnecessary and misleading info */
		return 0;	
#endif
	} /* of case */
	
	if (device_found) {
	/* Here we claim only if we have a device attached */   
		/* allocate the irq and memory region for that device */
		if (!dev->irq)
	 	return -ENODEV;
	   
	  	if (request_irq(dev->irq, lasikbd_interrupt, 0, name, (void *)hpa))
	  	return -ENODEV;
	   
	  	if (!request_mem_region(hpa, LASI_STATUS + 4, name))
	  	return -ENODEV;
	}
	
	printk(KERN_INFO "PS/2 %s port at 0x%08lx (irq %d) found, "
			 "%sdevice attached.\n",
			name, hpa, dev->irq, device_found ? "":"no ");

	return 0;
}
Esempio n. 14
0
static inline uint8_t hp_sdc_data_in8 (void) {
	return gsc_readb(hp_sdc.data_io); 
}
Esempio n. 15
0
void
sti_putc(struct sti_struct *sti, int c, int y, int x)
{
	struct sti_font_inptr inptr = {
		.font_start_addr= STI_PTR(sti->font->raw),
		.index		= c_index(sti, c),
		.fg_color	= c_fg(sti, c),
		.bg_color	= c_bg(sti, c),
		.dest_x		= x * sti->font_width,
		.dest_y		= y * sti->font_height,
	};
	struct sti_font_outptr outptr = { 0, };
	s32 ret;
	unsigned long flags;

	do {
		spin_lock_irqsave(&sti->lock, flags);
		ret = STI_CALL(sti->font_unpmv, &default_font_flags,
			&inptr, &outptr, sti->glob_cfg);
		spin_unlock_irqrestore(&sti->lock, flags);
	} while (ret == 1);
}

static const struct sti_blkmv_flags clear_blkmv_flags = {
	.wait	= STI_WAIT, 
	.color	= 1, 
	.clear	= 1, 
};

void
sti_set(struct sti_struct *sti, int src_y, int src_x,
	int height, int width, u8 color)
{
	struct sti_blkmv_inptr inptr = {
		.fg_color	= color,
		.bg_color	= color,
		.src_x		= src_x,
		.src_y		= src_y,
		.dest_x		= src_x,
		.dest_y		= src_y,
		.width		= width,
		.height		= height,
	};
	struct sti_blkmv_outptr outptr = { 0, };
	s32 ret;
	unsigned long flags;
	
	do {
		spin_lock_irqsave(&sti->lock, flags);
		ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
			&inptr, &outptr, sti->glob_cfg);
		spin_unlock_irqrestore(&sti->lock, flags);
	} while (ret == 1);
}

void
sti_clear(struct sti_struct *sti, int src_y, int src_x,
	  int height, int width, int c)
{
	struct sti_blkmv_inptr inptr = {
		.fg_color	= c_fg(sti, c),
		.bg_color	= c_bg(sti, c),
		.src_x		= src_x * sti->font_width,
		.src_y		= src_y * sti->font_height,
		.dest_x		= src_x * sti->font_width,
		.dest_y		= src_y * sti->font_height,
		.width		= width * sti->font_width,
		.height		= height* sti->font_height,
	};
	struct sti_blkmv_outptr outptr = { 0, };
	s32 ret;
	unsigned long flags;

	do {
		spin_lock_irqsave(&sti->lock, flags);
		ret = STI_CALL(sti->block_move, &clear_blkmv_flags,
			&inptr, &outptr, sti->glob_cfg);
		spin_unlock_irqrestore(&sti->lock, flags);
	} while (ret == 1);
}

static const struct sti_blkmv_flags default_blkmv_flags = {
	.wait = STI_WAIT, 
};

void
sti_bmove(struct sti_struct *sti, int src_y, int src_x,
	  int dst_y, int dst_x, int height, int width)
{
	struct sti_blkmv_inptr inptr = {
		.src_x		= src_x * sti->font_width,
		.src_y		= src_y * sti->font_height,
		.dest_x		= dst_x * sti->font_width,
		.dest_y		= dst_y * sti->font_height,
		.width		= width * sti->font_width,
		.height		= height* sti->font_height,
	};
	struct sti_blkmv_outptr outptr = { 0, };
	s32 ret;
	unsigned long flags;

	do {
		spin_lock_irqsave(&sti->lock, flags);
		ret = STI_CALL(sti->block_move, &default_blkmv_flags,
			&inptr, &outptr, sti->glob_cfg);
		spin_unlock_irqrestore(&sti->lock, flags);
	} while (ret == 1);
}


static void sti_flush(unsigned long start, unsigned long end)
{
	flush_icache_range(start, end);
}

static void __devinit sti_rom_copy(unsigned long base, unsigned long count,
				   void *dest)
{
	unsigned long dest_start = (unsigned long) dest;

	/* this still needs to be revisited (see arch/parisc/mm/init.c:246) ! */
	while (count >= 4) {
		count -= 4;
		*(u32 *)dest = gsc_readl(base);
		base += 4;
		dest += 4;
	}
	while (count) {
		count--;
		*(u8 *)dest = gsc_readb(base);
		base++;
		dest++;
	}

	sti_flush(dest_start, (unsigned long)dest);
}




static char default_sti_path[21] __read_mostly;

#ifndef MODULE
static int __devinit sti_setup(char *str)
{
	if (str)
		strlcpy (default_sti_path, str, sizeof (default_sti_path));
	
	return 1;
}

__setup("sti=", sti_setup);
#endif



static char __devinitdata	*font_name[MAX_STI_ROMS] = { "VGA8x16", };
static int __devinitdata	font_index[MAX_STI_ROMS],
				font_height[MAX_STI_ROMS],
				font_width[MAX_STI_ROMS];
#ifndef MODULE
static int __devinit sti_font_setup(char *str)
{
	char *x;
	int i = 0;

	/* we accept sti_font=VGA8x16, sti_font=10x20, sti_font=10*20 
	 * or sti_font=7 style command lines. */

	while (i<MAX_STI_ROMS && str && *str) {
		if (*str>='0' && *str<='9') {
			if ((x = strchr(str, 'x')) || (x = strchr(str, '*'))) {
				font_height[i] = simple_strtoul(str, NULL, 0);
				font_width[i] = simple_strtoul(x+1, NULL, 0);
			} else {
				font_index[i] = simple_strtoul(str, NULL, 0);
			}
		} else {
			font_name[i] = str;	/* fb font name */
		}

		if ((x = strchr(str, ',')))
			*x++ = 0;
		str = x;

		i++;
	}

	return 1;
}

__setup("sti_font=", sti_font_setup);
#endif


	
static void __devinit
sti_dump_globcfg(struct sti_glob_cfg *glob_cfg, unsigned int sti_mem_request)
{
	struct sti_glob_cfg_ext *cfg;
	
	DPRINTK((KERN_INFO
		"%d text planes\n"
		"%4d x %4d screen resolution\n"
		"%4d x %4d offscreen\n"
		"%4d x %4d layout\n"
		"regions at %08x %08x %08x %08x\n"
		"regions at %08x %08x %08x %08x\n"
		"reent_lvl %d\n"
		"save_addr %08x\n",
		glob_cfg->text_planes,
		glob_cfg->onscreen_x, glob_cfg->onscreen_y,
		glob_cfg->offscreen_x, glob_cfg->offscreen_y,
		glob_cfg->total_x, glob_cfg->total_y,
		glob_cfg->region_ptrs[0], glob_cfg->region_ptrs[1],
		glob_cfg->region_ptrs[2], glob_cfg->region_ptrs[3],
		glob_cfg->region_ptrs[4], glob_cfg->region_ptrs[5],
		glob_cfg->region_ptrs[6], glob_cfg->region_ptrs[7],
		glob_cfg->reent_lvl,
		glob_cfg->save_addr));

	/* dump extended cfg */ 
	cfg = PTR_STI((unsigned long)glob_cfg->ext_ptr);
	DPRINTK(( KERN_INFO
		"monitor %d\n"
		"in friendly mode: %d\n"
		"power consumption %d watts\n"
		"freq ref %d\n"
		"sti_mem_addr %08x (size=%d bytes)\n",
		cfg->curr_mon,
		cfg->friendly_boot,
		cfg->power,
		cfg->freq_ref,
		cfg->sti_mem_addr, sti_mem_request));
}

static void __devinit
sti_dump_outptr(struct sti_struct *sti)
{
	DPRINTK((KERN_INFO
		"%d bits per pixel\n"
		"%d used bits\n"
		"%d planes\n"
		"attributes %08x\n",
		 sti->outptr.bits_per_pixel,
		 sti->outptr.bits_used,
		 sti->outptr.planes,
		 sti->outptr.attributes));
}