⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cobalt_lcdfb.c

📁 Linux环境下视频显示卡设备的驱动程序源代码
💻 C
字号:
/* *  Cobalt server LCD frame buffer driver. * *  Copyright (C) 2008  Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp> * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */#include <linux/delay.h>#include <linux/fb.h>#include <linux/init.h>#include <linux/io.h>#include <linux/ioport.h>#include <linux/uaccess.h>#include <linux/platform_device.h>/* * Cursor position address * \X  0    1    2  ...  14   15 * Y+----+----+----+---+----+----+ * 0|0x00|0x01|0x02|...|0x0e|0x0f| *  +----+----+----+---+----+----+ * 1|0x40|0x41|0x42|...|0x4e|0x4f| *  +----+----+----+---+----+----+ */#define LCD_DATA_REG_OFFSET	0x10#define LCD_XRES_MAX		16#define LCD_YRES_MAX		2#define LCD_CHARS_MAX		32#define LCD_CLEAR		0x01#define LCD_CURSOR_MOVE_HOME	0x02#define LCD_RESET		0x06#define LCD_OFF			0x08#define LCD_CURSOR_OFF		0x0c#define LCD_CURSOR_BLINK_OFF	0x0e#define LCD_CURSOR_ON		0x0f#define LCD_ON			LCD_CURSOR_ON#define LCD_CURSOR_MOVE_LEFT	0x10#define LCD_CURSOR_MOVE_RIGHT	0x14#define LCD_DISPLAY_LEFT	0x18#define LCD_DISPLAY_RIGHT	0x1c#define LCD_PRERESET		0x3f	/* execute 4 times continuously */#define LCD_BUSY		0x80#define LCD_GRAPHIC_MODE	0x40#define LCD_TEXT_MODE		0x80#define LCD_CUR_POS_MASK	0x7f#define LCD_CUR_POS(x)		((x) & LCD_CUR_POS_MASK)#define LCD_TEXT_POS(x)		((x) | LCD_TEXT_MODE)static inline void lcd_write_control(struct fb_info *info, u8 control){	writel((u32)control << 24, info->screen_base);}static inline u8 lcd_read_control(struct fb_info *info){	return readl(info->screen_base) >> 24;}static inline void lcd_write_data(struct fb_info *info, u8 data){	writel((u32)data << 24, info->screen_base + LCD_DATA_REG_OFFSET);}static inline u8 lcd_read_data(struct fb_info *info){	return readl(info->screen_base + LCD_DATA_REG_OFFSET) >> 24;}static int lcd_busy_wait(struct fb_info *info){	u8 val = 0;	int timeout = 10, retval = 0;	do {		val = lcd_read_control(info);		val &= LCD_BUSY;		if (val != LCD_BUSY)			break;		if (msleep_interruptible(1))			return -EINTR;		timeout--;	} while (timeout);	if (val == LCD_BUSY)		retval = -EBUSY;	return retval;}static void lcd_clear(struct fb_info *info){	int i;	for (i = 0; i < 4; i++) {		udelay(150);		lcd_write_control(info, LCD_PRERESET);	}	udelay(150);	lcd_write_control(info, LCD_CLEAR);	udelay(150);	lcd_write_control(info, LCD_RESET);}static struct fb_fix_screeninfo cobalt_lcdfb_fix __initdata = {	.id		= "cobalt-lcd",	.type		= FB_TYPE_TEXT,	.type_aux	= FB_AUX_TEXT_MDA,	.visual		= FB_VISUAL_MONO01,	.line_length	= LCD_XRES_MAX,	.accel		= FB_ACCEL_NONE,};static ssize_t cobalt_lcdfb_read(struct fb_info *info, char __user *buf,				 size_t count, loff_t *ppos){	char src[LCD_CHARS_MAX];	unsigned long pos;	int len, retval = 0;	pos = *ppos;	if (pos >= LCD_CHARS_MAX || count == 0)		return 0;	if (count > LCD_CHARS_MAX)		count = LCD_CHARS_MAX;	if (pos + count > LCD_CHARS_MAX)		count = LCD_CHARS_MAX - pos;	for (len = 0; len < count; len++) {		retval = lcd_busy_wait(info);		if (retval < 0)			break;		lcd_write_control(info, LCD_TEXT_POS(pos));		retval = lcd_busy_wait(info);		if (retval < 0)			break;		src[len] = lcd_read_data(info);		if (pos == 0x0f)			pos = 0x40;		else			pos++;	}	if (retval < 0 && signal_pending(current))		return -ERESTARTSYS;	if (copy_to_user(buf, src, len))		return -EFAULT;	*ppos += len;	return len;}static ssize_t cobalt_lcdfb_write(struct fb_info *info, const char __user *buf,				  size_t count, loff_t *ppos){	char dst[LCD_CHARS_MAX];	unsigned long pos;	int len, retval = 0;	pos = *ppos;	if (pos >= LCD_CHARS_MAX || count == 0)		return 0;	if (count > LCD_CHARS_MAX)		count = LCD_CHARS_MAX;	if (pos + count > LCD_CHARS_MAX)		count = LCD_CHARS_MAX - pos;	if (copy_from_user(dst, buf, count))		return -EFAULT;	for (len = 0; len < count; len++) {		retval = lcd_busy_wait(info);		if (retval < 0)			break;		lcd_write_control(info, LCD_TEXT_POS(pos));		retval = lcd_busy_wait(info);		if (retval < 0)			break;		lcd_write_data(info, dst[len]);		if (pos == 0x0f)			pos = 0x40;		else			pos++;	}	if (retval < 0 && signal_pending(current))		return -ERESTARTSYS;	*ppos += len;	return len;}static int cobalt_lcdfb_blank(int blank_mode, struct fb_info *info){	int retval;	retval = lcd_busy_wait(info);	if (retval < 0)		return retval;	switch (blank_mode) {	case FB_BLANK_UNBLANK:		lcd_write_control(info, LCD_ON);		break;	default:		lcd_write_control(info, LCD_OFF);		break;	}	return 0;}static int cobalt_lcdfb_cursor(struct fb_info *info, struct fb_cursor *cursor){	u32 x, y;	int retval;	switch (cursor->set) {	case FB_CUR_SETPOS:		x = cursor->image.dx;		y = cursor->image.dy;		if (x >= LCD_XRES_MAX || y >= LCD_YRES_MAX)			return -EINVAL;		retval = lcd_busy_wait(info);		if (retval < 0)			return retval;		lcd_write_control(info,				  LCD_TEXT_POS(info->fix.line_length * y + x));		break;	default:		return -EINVAL;	}	retval = lcd_busy_wait(info);	if (retval < 0)		return retval;	if (cursor->enable)		lcd_write_control(info, LCD_CURSOR_ON);	else		lcd_write_control(info, LCD_CURSOR_OFF);	return 0;}static struct fb_ops cobalt_lcd_fbops = {	.owner		= THIS_MODULE,	.fb_read	= cobalt_lcdfb_read,	.fb_write	= cobalt_lcdfb_write,	.fb_blank	= cobalt_lcdfb_blank,	.fb_cursor	= cobalt_lcdfb_cursor,};static int __init cobalt_lcdfb_probe(struct platform_device *dev){	struct fb_info *info;	struct resource *res;	int retval;	info = framebuffer_alloc(0, &dev->dev);	if (!info)		return -ENOMEM;	res = platform_get_resource(dev, IORESOURCE_MEM, 0);	if (!res) {		framebuffer_release(info);		return -EBUSY;	}	info->screen_size = res->end - res->start + 1;	info->screen_base = ioremap(res->start, info->screen_size);	info->fbops = &cobalt_lcd_fbops;	info->fix = cobalt_lcdfb_fix;	info->fix.smem_start = res->start;	info->fix.smem_len = info->screen_size;	info->pseudo_palette = NULL;	info->par = NULL;	info->flags = FBINFO_DEFAULT;	retval = register_framebuffer(info);	if (retval < 0) {		iounmap(info->screen_base);		framebuffer_release(info);		return retval;	}	platform_set_drvdata(dev, info);	lcd_clear(info);	printk(KERN_INFO "fb%d: Cobalt server LCD frame buffer device\n",		info->node);	return 0;}static int __devexit cobalt_lcdfb_remove(struct platform_device *dev){	struct fb_info *info;	info = platform_get_drvdata(dev);	if (info) {		iounmap(info->screen_base);		unregister_framebuffer(info);		framebuffer_release(info);	}	return 0;}static struct platform_driver cobalt_lcdfb_driver = {	.probe	= cobalt_lcdfb_probe,	.remove	= __devexit_p(cobalt_lcdfb_remove),	.driver	= {		.name	= "cobalt-lcd",		.owner	= THIS_MODULE,	},};static int __init cobalt_lcdfb_init(void){	return platform_driver_register(&cobalt_lcdfb_driver);}static void __exit cobalt_lcdfb_exit(void){	platform_driver_unregister(&cobalt_lcdfb_driver);}module_init(cobalt_lcdfb_init);module_exit(cobalt_lcdfb_exit);MODULE_LICENSE("GPL v2");MODULE_AUTHOR("Yoichi Yuasa");MODULE_DESCRIPTION("Cobalt server LCD frame buffer driver");

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -