From 23e707dd9b0b26215d801c59e87feed1c218a0f9 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 11 Dec 2009 15:38:46 -0800 Subject: [PATCH 01/19] Staging: batman: fix debug Kconfig option The debug batman option needs to depend on the correct config option. Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/batman-adv/Kconfig b/drivers/staging/batman-adv/Kconfig index b9742e7c7d9e..7632f5760060 100644 --- a/drivers/staging/batman-adv/Kconfig +++ b/drivers/staging/batman-adv/Kconfig @@ -15,7 +15,7 @@ config BATMAN_ADV config BATMAN_DEBUG bool "B.A.T.M.A.N. debugging" - depends on BATMAN != n + depends on BATMAN_ADV != n help This is an option for use by developers; most people should From d7edf47947f9d921be6ca5fc8e83049124466f98 Mon Sep 17 00:00:00 2001 From: Wu Zhangjin Date: Mon, 23 Nov 2009 10:28:24 +0800 Subject: [PATCH 02/19] Staging: sm7xx: add a new framebuffer driver Yeeloong netbook has a sm712 video card, need this driver, but it is not ready to upstream yet, so, go to drivers/staing at first. This source code is originally from Silicon Motion Technology Corp, and maintained at http://dev.lemote.com/code/linux_loongson for YeeLoong netbook. I have done a lot of cleanups for it and merged it into my git repository at http://dev.lemote.com/code/rt4ls. Thanks to Simon for testing it on a little-endian x86 platform. Thanks to Olivier Croset for reporting the problem about __BIG_ENDIAN compiling problem and send a relative patch. The suspend/resume and blank support are contributed by Jason from Silicon Motion Technology. Tested-by: Simon Braunschmidt Signed-off-by: Wu Zhangjin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/Kconfig | 2 + drivers/staging/Makefile | 1 + drivers/staging/sm7xx/Kconfig | 15 + drivers/staging/sm7xx/Makefile | 3 + drivers/staging/sm7xx/TODO | 10 + drivers/staging/sm7xx/smtc2d.c | 979 +++++++++++++++++++++++++ drivers/staging/sm7xx/smtc2d.h | 530 ++++++++++++++ drivers/staging/sm7xx/smtcfb.c | 1253 ++++++++++++++++++++++++++++++++ drivers/staging/sm7xx/smtcfb.h | 793 ++++++++++++++++++++ 9 files changed, 3586 insertions(+) create mode 100644 drivers/staging/sm7xx/Kconfig create mode 100644 drivers/staging/sm7xx/Makefile create mode 100644 drivers/staging/sm7xx/TODO create mode 100644 drivers/staging/sm7xx/smtc2d.c create mode 100644 drivers/staging/sm7xx/smtc2d.h create mode 100644 drivers/staging/sm7xx/smtcfb.c create mode 100644 drivers/staging/sm7xx/smtcfb.h diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index 093f57af32d3..db0de940949e 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -145,5 +145,7 @@ source "drivers/staging/wavelan/Kconfig" source "drivers/staging/netwave/Kconfig" +source "drivers/staging/sm7xx/Kconfig" + endif # !STAGING_EXCLUDE_BUILD endif # STAGING diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 069864f4391e..73c6a71155e0 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -53,3 +53,4 @@ obj-$(CONFIG_ARLAN) += arlan/ obj-$(CONFIG_WAVELAN) += wavelan/ obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan/ obj-$(CONFIG_PCMCIA_NETWAVE) += netwave/ +obj-$(CONFIG_FB_SM7XX) += sm7xx/ diff --git a/drivers/staging/sm7xx/Kconfig b/drivers/staging/sm7xx/Kconfig new file mode 100644 index 000000000000..204dbfc3c38b --- /dev/null +++ b/drivers/staging/sm7xx/Kconfig @@ -0,0 +1,15 @@ +config FB_SM7XX + tristate "Silicon Motion SM7XX Frame Buffer Support" + depends on FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + help + Frame Buffer driver for the Silicon Motion SM7XX serial graphic card. + +config FB_SM7XX_ACCEL + bool "Siliconmotion Acceleration functions (EXPERIMENTAL)" + depends on FB_SM7XX && EXPERIMENTAL + help + This will compile the Trident frame buffer device with + acceleration functions. diff --git a/drivers/staging/sm7xx/Makefile b/drivers/staging/sm7xx/Makefile new file mode 100644 index 000000000000..f43cb9106305 --- /dev/null +++ b/drivers/staging/sm7xx/Makefile @@ -0,0 +1,3 @@ +obj-$(CONFIG_FB_SM7XX) += sm7xx.o + +sm7xx-y := smtcfb.o diff --git a/drivers/staging/sm7xx/TODO b/drivers/staging/sm7xx/TODO new file mode 100644 index 000000000000..1f61f5e11cf5 --- /dev/null +++ b/drivers/staging/sm7xx/TODO @@ -0,0 +1,10 @@ +TODO: +- Dual head support +- use kernel coding style +- checkpatch.pl clean +- refine the code and remove unused code +- use kernel framebuffer mode setting instead of hard code +- move it to drivers/video/sm7xx/ or make it be drivers/video/sm7xxfb.c + +Please send any patches to Greg Kroah-Hartman and +Teddy Wang . diff --git a/drivers/staging/sm7xx/smtc2d.c b/drivers/staging/sm7xx/smtc2d.c new file mode 100644 index 000000000000..133b86c6a678 --- /dev/null +++ b/drivers/staging/sm7xx/smtc2d.c @@ -0,0 +1,979 @@ +/* + * Silicon Motion SM7XX 2D drawing engine functions. + * + * Copyright (C) 2006 Silicon Motion Technology Corp. + * Author: Boyod boyod.yang@siliconmotion.com.cn + * + * Copyright (C) 2009 Lemote, Inc. + * Author: Wu Zhangjin, wuzj@lemote.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * Version 0.10.26192.21.01 + * - Add PowerPC support + * - Add 2D support for Lynx - + * Verified on 2.6.19.2 + * Boyod.yang + */ + +unsigned char smtc_de_busy; + +void SMTC_write2Dreg(unsigned long nOffset, unsigned long nData) +{ + writel(nData, smtc_2DBaseAddress + nOffset); +} + +unsigned long SMTC_read2Dreg(unsigned long nOffset) +{ + return readl(smtc_2DBaseAddress + nOffset); +} + +void SMTC_write2Ddataport(unsigned long nOffset, unsigned long nData) +{ + writel(nData, smtc_2Ddataport + nOffset); +} + +/********************************************************************** + * + * deInit + * + * Purpose + * Drawing engine initialization. + * + **********************************************************************/ + +void deInit(unsigned int nModeWidth, unsigned int nModeHeight, + unsigned int bpp) +{ + /* Get current power configuration. */ + unsigned char clock; + clock = smtc_seqr(0x21); + + /* initialize global 'mutex lock' variable */ + smtc_de_busy = 0; + + /* Enable 2D Drawing Engine */ + smtc_seqw(0x21, clock & 0xF8); + + SMTC_write2Dreg(DE_CLIP_TL, + FIELD_VALUE(0, DE_CLIP_TL, TOP, 0) | + FIELD_SET(0, DE_CLIP_TL, STATUS, DISABLE) | + FIELD_SET(0, DE_CLIP_TL, INHIBIT, OUTSIDE) | + FIELD_VALUE(0, DE_CLIP_TL, LEFT, 0)); + + if (bpp >= 24) { + SMTC_write2Dreg(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, + nModeWidth * 3) | FIELD_VALUE(0, + DE_PITCH, + SOURCE, + nModeWidth + * 3)); + } else { + SMTC_write2Dreg(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, + nModeWidth) | FIELD_VALUE(0, + DE_PITCH, + SOURCE, + nModeWidth)); + } + + SMTC_write2Dreg(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, + nModeWidth) | FIELD_VALUE(0, + DE_WINDOW_WIDTH, + SOURCE, + nModeWidth)); + + switch (bpp) { + case 8: + SMTC_write2Dreg(DE_STRETCH_FORMAT, + FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY, + NORMAL) | FIELD_VALUE(0, + DE_STRETCH_FORMAT, + PATTERN_Y, + 0) | + FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X, + 0) | FIELD_SET(0, DE_STRETCH_FORMAT, + PIXEL_FORMAT, + 8) | FIELD_SET(0, + DE_STRETCH_FORMAT, + ADDRESSING, + XY) | + FIELD_VALUE(0, DE_STRETCH_FORMAT, + SOURCE_HEIGHT, 3)); + break; + case 24: + SMTC_write2Dreg(DE_STRETCH_FORMAT, + FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY, + NORMAL) | FIELD_VALUE(0, + DE_STRETCH_FORMAT, + PATTERN_Y, + 0) | + FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X, + 0) | FIELD_SET(0, DE_STRETCH_FORMAT, + PIXEL_FORMAT, + 24) | FIELD_SET(0, + DE_STRETCH_FORMAT, + ADDRESSING, + XY) | + FIELD_VALUE(0, DE_STRETCH_FORMAT, + SOURCE_HEIGHT, 3)); + break; + case 16: + default: + SMTC_write2Dreg(DE_STRETCH_FORMAT, + FIELD_SET(0, DE_STRETCH_FORMAT, PATTERN_XY, + NORMAL) | FIELD_VALUE(0, + DE_STRETCH_FORMAT, + PATTERN_Y, + 0) | + FIELD_VALUE(0, DE_STRETCH_FORMAT, PATTERN_X, + 0) | FIELD_SET(0, DE_STRETCH_FORMAT, + PIXEL_FORMAT, + 16) | FIELD_SET(0, + DE_STRETCH_FORMAT, + ADDRESSING, + XY) | + FIELD_VALUE(0, DE_STRETCH_FORMAT, + SOURCE_HEIGHT, 3)); + break; + } + + SMTC_write2Dreg(DE_MASKS, + FIELD_VALUE(0, DE_MASKS, BYTE_MASK, 0xFFFF) | + FIELD_VALUE(0, DE_MASKS, BIT_MASK, 0xFFFF)); + SMTC_write2Dreg(DE_COLOR_COMPARE_MASK, + FIELD_VALUE(0, DE_COLOR_COMPARE_MASK, MASKS, \ + 0xFFFFFF)); + SMTC_write2Dreg(DE_COLOR_COMPARE, + FIELD_VALUE(0, DE_COLOR_COMPARE, COLOR, 0xFFFFFF)); +} + +void deVerticalLine(unsigned long dst_base, + unsigned long dst_pitch, + unsigned long nX, + unsigned long nY, + unsigned long dst_height, unsigned long nColor) +{ + deWaitForNotBusy(); + + SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, + FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS, + dst_base)); + + SMTC_write2Dreg(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, dst_pitch) | + FIELD_VALUE(0, DE_PITCH, SOURCE, dst_pitch)); + + SMTC_write2Dreg(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, + dst_pitch) | FIELD_VALUE(0, DE_WINDOW_WIDTH, + SOURCE, + dst_pitch)); + + SMTC_write2Dreg(DE_FOREGROUND, + FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor)); + + SMTC_write2Dreg(DE_DESTINATION, + FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, nX) | + FIELD_VALUE(0, DE_DESTINATION, Y, nY)); + + SMTC_write2Dreg(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, 1) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height)); + + SMTC_write2Dreg(DE_CONTROL, + FIELD_SET(0, DE_CONTROL, STATUS, START) | + FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | + FIELD_SET(0, DE_CONTROL, MAJOR, Y) | + FIELD_SET(0, DE_CONTROL, STEP_X, NEGATIVE) | + FIELD_SET(0, DE_CONTROL, STEP_Y, POSITIVE) | + FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) | + FIELD_SET(0, DE_CONTROL, COMMAND, SHORT_STROKE) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C)); + + smtc_de_busy = 1; +} + +void deHorizontalLine(unsigned long dst_base, + unsigned long dst_pitch, + unsigned long nX, + unsigned long nY, + unsigned long dst_width, unsigned long nColor) +{ + deWaitForNotBusy(); + + SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, + FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS, + dst_base)); + + SMTC_write2Dreg(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, dst_pitch) | + FIELD_VALUE(0, DE_PITCH, SOURCE, dst_pitch)); + + SMTC_write2Dreg(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, + dst_pitch) | FIELD_VALUE(0, DE_WINDOW_WIDTH, + SOURCE, + dst_pitch)); + SMTC_write2Dreg(DE_FOREGROUND, + FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor)); + SMTC_write2Dreg(DE_DESTINATION, + FIELD_SET(0, DE_DESTINATION, WRAP, + DISABLE) | FIELD_VALUE(0, DE_DESTINATION, X, + nX) | FIELD_VALUE(0, + DE_DESTINATION, + Y, + nY)); + SMTC_write2Dreg(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, + dst_width) | FIELD_VALUE(0, DE_DIMENSION, + Y_ET, 1)); + SMTC_write2Dreg(DE_CONTROL, + FIELD_SET(0, DE_CONTROL, STATUS, START) | FIELD_SET(0, + DE_CONTROL, + DIRECTION, + RIGHT_TO_LEFT) + | FIELD_SET(0, DE_CONTROL, MAJOR, X) | FIELD_SET(0, + DE_CONTROL, + STEP_X, + POSITIVE) + | FIELD_SET(0, DE_CONTROL, STEP_Y, + NEGATIVE) | FIELD_SET(0, DE_CONTROL, + LAST_PIXEL, + OFF) | FIELD_SET(0, + DE_CONTROL, + COMMAND, + SHORT_STROKE) + | FIELD_SET(0, DE_CONTROL, ROP_SELECT, + ROP2) | FIELD_VALUE(0, DE_CONTROL, ROP, + 0x0C)); + + smtc_de_busy = 1; +} + +void deLine(unsigned long dst_base, + unsigned long dst_pitch, + unsigned long nX1, + unsigned long nY1, + unsigned long nX2, unsigned long nY2, unsigned long nColor) +{ + unsigned long nCommand = + FIELD_SET(0, DE_CONTROL, STATUS, START) | + FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | + FIELD_SET(0, DE_CONTROL, MAJOR, X) | + FIELD_SET(0, DE_CONTROL, STEP_X, POSITIVE) | + FIELD_SET(0, DE_CONTROL, STEP_Y, POSITIVE) | + FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C); + unsigned long DeltaX; + unsigned long DeltaY; + + /* Calculate delta X */ + if (nX1 <= nX2) + DeltaX = nX2 - nX1; + else { + DeltaX = nX1 - nX2; + nCommand = FIELD_SET(nCommand, DE_CONTROL, STEP_X, NEGATIVE); + } + + /* Calculate delta Y */ + if (nY1 <= nY2) + DeltaY = nY2 - nY1; + else { + DeltaY = nY1 - nY2; + nCommand = FIELD_SET(nCommand, DE_CONTROL, STEP_Y, NEGATIVE); + } + + /* Determine the major axis */ + if (DeltaX < DeltaY) + nCommand = FIELD_SET(nCommand, DE_CONTROL, MAJOR, Y); + + /* Vertical line? */ + if (nX1 == nX2) + deVerticalLine(dst_base, dst_pitch, nX1, nY1, DeltaY, nColor); + + /* Horizontal line? */ + else if (nY1 == nY2) + deHorizontalLine(dst_base, dst_pitch, nX1, nY1, \ + DeltaX, nColor); + + /* Diagonal line? */ + else if (DeltaX == DeltaY) { + deWaitForNotBusy(); + + SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, + FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, + ADDRESS, dst_base)); + + SMTC_write2Dreg(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, + dst_pitch) | FIELD_VALUE(0, + DE_PITCH, + SOURCE, + dst_pitch)); + + SMTC_write2Dreg(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, + dst_pitch) | FIELD_VALUE(0, + DE_WINDOW_WIDTH, + SOURCE, + dst_pitch)); + + SMTC_write2Dreg(DE_FOREGROUND, + FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor)); + + SMTC_write2Dreg(DE_DESTINATION, + FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, 1) | + FIELD_VALUE(0, DE_DESTINATION, Y, nY1)); + + SMTC_write2Dreg(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, 1) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, DeltaX)); + + SMTC_write2Dreg(DE_CONTROL, + FIELD_SET(nCommand, DE_CONTROL, COMMAND, + SHORT_STROKE)); + } + + /* Generic line */ + else { + unsigned int k1, k2, et, w; + if (DeltaX < DeltaY) { + k1 = 2 * DeltaX; + et = k1 - DeltaY; + k2 = et - DeltaY; + w = DeltaY + 1; + } else { + k1 = 2 * DeltaY; + et = k1 - DeltaX; + k2 = et - DeltaX; + w = DeltaX + 1; + } + + deWaitForNotBusy(); + + SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, + FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, + ADDRESS, dst_base)); + + SMTC_write2Dreg(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, + dst_pitch) | FIELD_VALUE(0, + DE_PITCH, + SOURCE, + dst_pitch)); + + SMTC_write2Dreg(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, + dst_pitch) | FIELD_VALUE(0, + DE_WINDOW_WIDTH, + SOURCE, + dst_pitch)); + + SMTC_write2Dreg(DE_FOREGROUND, + FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor)); + + SMTC_write2Dreg(DE_SOURCE, + FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1, k1) | + FIELD_VALUE(0, DE_SOURCE, Y_K2, k2)); + + SMTC_write2Dreg(DE_DESTINATION, + FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, nX1) | + FIELD_VALUE(0, DE_DESTINATION, Y, nY1)); + + SMTC_write2Dreg(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, w) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, et)); + + SMTC_write2Dreg(DE_CONTROL, + FIELD_SET(nCommand, DE_CONTROL, COMMAND, + LINE_DRAW)); + } + + smtc_de_busy = 1; +} + +void deFillRect(unsigned long dst_base, + unsigned long dst_pitch, + unsigned long dst_X, + unsigned long dst_Y, + unsigned long dst_width, + unsigned long dst_height, unsigned long nColor) +{ + deWaitForNotBusy(); + + SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, + FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS, + dst_base)); + + if (dst_pitch) { + SMTC_write2Dreg(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, + dst_pitch) | FIELD_VALUE(0, + DE_PITCH, + SOURCE, + dst_pitch)); + + SMTC_write2Dreg(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, + dst_pitch) | FIELD_VALUE(0, + DE_WINDOW_WIDTH, + SOURCE, + dst_pitch)); + } + + SMTC_write2Dreg(DE_FOREGROUND, + FIELD_VALUE(0, DE_FOREGROUND, COLOR, nColor)); + + SMTC_write2Dreg(DE_DESTINATION, + FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dst_X) | + FIELD_VALUE(0, DE_DESTINATION, Y, dst_Y)); + + SMTC_write2Dreg(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, dst_width) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height)); + + SMTC_write2Dreg(DE_CONTROL, + FIELD_SET(0, DE_CONTROL, STATUS, START) | + FIELD_SET(0, DE_CONTROL, DIRECTION, LEFT_TO_RIGHT) | + FIELD_SET(0, DE_CONTROL, LAST_PIXEL, OFF) | + FIELD_SET(0, DE_CONTROL, COMMAND, RECTANGLE_FILL) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_VALUE(0, DE_CONTROL, ROP, 0x0C)); + + smtc_de_busy = 1; +} + +/********************************************************************** + * + * deRotatePattern + * + * Purpose + * Rotate the given pattern if necessary + * + * Parameters + * [in] + * pPattern - Pointer to DE_SURFACE structure containing + * pattern attributes + * patternX - X position (0-7) of pattern origin + * patternY - Y position (0-7) of pattern origin + * + * [out] + * pattern_dstaddr - Pointer to pre-allocated buffer containing + * rotated pattern + * + **********************************************************************/ +void deRotatePattern(unsigned char *pattern_dstaddr, + unsigned long pattern_src_addr, + unsigned long pattern_BPP, + unsigned long pattern_stride, int patternX, int patternY) +{ + unsigned int i; + unsigned long pattern[PATTERN_WIDTH * PATTERN_HEIGHT]; + unsigned int x, y; + unsigned char *pjPatByte; + + if (pattern_dstaddr != NULL) { + deWaitForNotBusy(); + + if (patternX || patternY) { + /* Rotate pattern */ + pjPatByte = (unsigned char *)pattern; + + switch (pattern_BPP) { + case 8: + { + for (y = 0; y < 8; y++) { + unsigned char *pjBuffer = + pattern_dstaddr + + ((patternY + y) & 7) * 8; + for (x = 0; x < 8; x++) { + pjBuffer[(patternX + + x) & 7] = + pjPatByte[x]; + } + pjPatByte += pattern_stride; + } + break; + } + + case 16: + { + for (y = 0; y < 8; y++) { + unsigned short *pjBuffer = + (unsigned short *) + pattern_dstaddr + + ((patternY + y) & 7) * 8; + for (x = 0; x < 8; x++) { + pjBuffer[(patternX + + x) & 7] = + ((unsigned short *) + pjPatByte)[x]; + } + pjPatByte += pattern_stride; + } + break; + } + + case 32: + { + for (y = 0; y < 8; y++) { + unsigned long *pjBuffer = + (unsigned long *) + pattern_dstaddr + + ((patternY + y) & 7) * 8; + for (x = 0; x < 8; x++) { + pjBuffer[(patternX + + x) & 7] = + ((unsigned long *) + pjPatByte)[x]; + } + pjPatByte += pattern_stride; + } + break; + } + } + } else { + /*Don't rotate,just copy pattern into pattern_dstaddr*/ + for (i = 0; i < (pattern_BPP * 2); i++) { + ((unsigned long *)pattern_dstaddr)[i] = + pattern[i]; + } + } + + } +} + +/********************************************************************** + * + * deCopy + * + * Purpose + * Copy a rectangular area of the source surface to a destination surface + * + * Remarks + * Source bitmap must have the same color depth (BPP) as the destination + * bitmap. + * +**********************************************************************/ +void deCopy(unsigned long dst_base, + unsigned long dst_pitch, + unsigned long dst_BPP, + unsigned long dst_X, + unsigned long dst_Y, + unsigned long dst_width, + unsigned long dst_height, + unsigned long src_base, + unsigned long src_pitch, + unsigned long src_X, + unsigned long src_Y, pTransparent pTransp, unsigned char nROP2) +{ + unsigned long nDirection = 0; + unsigned long nTransparent = 0; + /* Direction of ROP2 operation: + * 1 = Left to Right, + * (-1) = Right to Left + */ + unsigned long opSign = 1; + /* xWidth is in pixels */ + unsigned long xWidth = 192 / (dst_BPP / 8); + unsigned long de_ctrl = 0; + + deWaitForNotBusy(); + + SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, + FIELD_VALUE(0, DE_WINDOW_DESTINATION_BASE, ADDRESS, + dst_base)); + + SMTC_write2Dreg(DE_WINDOW_SOURCE_BASE, + FIELD_VALUE(0, DE_WINDOW_SOURCE_BASE, ADDRESS, + src_base)); + + if (dst_pitch && src_pitch) { + SMTC_write2Dreg(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, + dst_pitch) | FIELD_VALUE(0, + DE_PITCH, + SOURCE, + src_pitch)); + + SMTC_write2Dreg(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, + dst_pitch) | FIELD_VALUE(0, + DE_WINDOW_WIDTH, + SOURCE, + src_pitch)); + } + + /* Set transparent bits if necessary */ + if (pTransp != NULL) { + nTransparent = + pTransp->match | pTransp->select | pTransp->control; + + /* Set color compare register */ + SMTC_write2Dreg(DE_COLOR_COMPARE, + FIELD_VALUE(0, DE_COLOR_COMPARE, COLOR, + pTransp->color)); + } + + /* Determine direction of operation */ + if (src_Y < dst_Y) { + /* +----------+ + |S | + | +----------+ + | | | | + | | | | + +---|------+ | + | D | + +----------+ */ + + nDirection = BOTTOM_TO_TOP; + } else if (src_Y > dst_Y) { + /* +----------+ + |D | + | +----------+ + | | | | + | | | | + +---|------+ | + | S | + +----------+ */ + + nDirection = TOP_TO_BOTTOM; + } else { + /* src_Y == dst_Y */ + + if (src_X <= dst_X) { + /* +------+---+------+ + |S | | D| + | | | | + | | | | + | | | | + +------+---+------+ */ + + nDirection = RIGHT_TO_LEFT; + } else { + /* src_X > dst_X */ + + /* +------+---+------+ + |D | | S| + | | | | + | | | | + | | | | + +------+---+------+ */ + + nDirection = LEFT_TO_RIGHT; + } + } + + if ((nDirection == BOTTOM_TO_TOP) || (nDirection == RIGHT_TO_LEFT)) { + src_X += dst_width - 1; + src_Y += dst_height - 1; + dst_X += dst_width - 1; + dst_Y += dst_height - 1; + opSign = (-1); + } + + if (dst_BPP >= 24) { + src_X *= 3; + src_Y *= 3; + dst_X *= 3; + dst_Y *= 3; + dst_width *= 3; + if ((nDirection == BOTTOM_TO_TOP) + || (nDirection == RIGHT_TO_LEFT)) { + src_X += 2; + dst_X += 2; + } + } + + /* Workaround for 192 byte hw bug */ + if ((nROP2 != 0x0C) && ((dst_width * (dst_BPP / 8)) >= 192)) { + /* + * Perform the ROP2 operation in chunks of (xWidth * + * dst_height) + */ + while (1) { + deWaitForNotBusy(); + + SMTC_write2Dreg(DE_SOURCE, + FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1, src_X) | + FIELD_VALUE(0, DE_SOURCE, Y_K2, src_Y)); + + SMTC_write2Dreg(DE_DESTINATION, + FIELD_SET(0, DE_DESTINATION, WRAP, + DISABLE) | FIELD_VALUE(0, + DE_DESTINATION, + X, + dst_X) + | FIELD_VALUE(0, DE_DESTINATION, Y, + dst_Y)); + + SMTC_write2Dreg(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, + xWidth) | FIELD_VALUE(0, + DE_DIMENSION, + Y_ET, + dst_height)); + + de_ctrl = + FIELD_VALUE(0, DE_CONTROL, ROP, + nROP2) | nTransparent | FIELD_SET(0, + DE_CONTROL, + ROP_SELECT, + ROP2) + | FIELD_SET(0, DE_CONTROL, COMMAND, + BITBLT) | ((nDirection == + 1) ? FIELD_SET(0, + DE_CONTROL, + DIRECTION, + RIGHT_TO_LEFT) + : FIELD_SET(0, DE_CONTROL, + DIRECTION, + LEFT_TO_RIGHT)) | + FIELD_SET(0, DE_CONTROL, STATUS, START); + + SMTC_write2Dreg(DE_CONTROL, de_ctrl); + + src_X += (opSign * xWidth); + dst_X += (opSign * xWidth); + dst_width -= xWidth; + + if (dst_width <= 0) { + /* ROP2 operation is complete */ + break; + } + + if (xWidth > dst_width) + xWidth = dst_width; + } + } else { + deWaitForNotBusy(); + SMTC_write2Dreg(DE_SOURCE, + FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1, src_X) | + FIELD_VALUE(0, DE_SOURCE, Y_K2, src_Y)); + + SMTC_write2Dreg(DE_DESTINATION, + FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dst_X) | + FIELD_VALUE(0, DE_DESTINATION, Y, dst_Y)); + + SMTC_write2Dreg(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, dst_width) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, dst_height)); + + de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, nROP2) | + nTransparent | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_SET(0, DE_CONTROL, COMMAND, BITBLT) | + ((nDirection == 1) ? FIELD_SET(0, DE_CONTROL, DIRECTION, + RIGHT_TO_LEFT) + : FIELD_SET(0, DE_CONTROL, DIRECTION, + LEFT_TO_RIGHT)) | FIELD_SET(0, DE_CONTROL, + STATUS, START); + SMTC_write2Dreg(DE_CONTROL, de_ctrl); + } + + smtc_de_busy = 1; +} + +/* + * This function sets the pixel format that will apply to the 2D Engine. + */ +void deSetPixelFormat(unsigned long bpp) +{ + unsigned long de_format; + + de_format = SMTC_read2Dreg(DE_STRETCH_FORMAT); + + switch (bpp) { + case 8: + de_format = + FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 8); + break; + default: + case 16: + de_format = + FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 16); + break; + case 32: + de_format = + FIELD_SET(de_format, DE_STRETCH_FORMAT, PIXEL_FORMAT, 32); + break; + } + + SMTC_write2Dreg(DE_STRETCH_FORMAT, de_format); +} + +/* + * System memory to Video memory monochrome expansion. + * + * Source is monochrome image in system memory. This function expands the + * monochrome data to color image in video memory. + */ + +long deSystemMem2VideoMemMonoBlt(const char *pSrcbuf, + long srcDelta, + unsigned long startBit, + unsigned long dBase, + unsigned long dPitch, + unsigned long bpp, + unsigned long dx, unsigned long dy, + unsigned long width, unsigned long height, + unsigned long fColor, + unsigned long bColor, + unsigned long rop2) { + unsigned long bytePerPixel; + unsigned long ulBytesPerScan; + unsigned long ul4BytesPerScan; + unsigned long ulBytesRemain; + unsigned long de_ctrl = 0; + unsigned char ajRemain[4]; + long i, j; + + bytePerPixel = bpp / 8; + + /* Just make sure the start bit is within legal range */ + startBit &= 7; + + ulBytesPerScan = (width + startBit + 7) / 8; + ul4BytesPerScan = ulBytesPerScan & ~3; + ulBytesRemain = ulBytesPerScan & 3; + + if (smtc_de_busy) + deWaitForNotBusy(); + + /* + * 2D Source Base. Use 0 for HOST Blt. + */ + + SMTC_write2Dreg(DE_WINDOW_SOURCE_BASE, 0); + + /* + * 2D Destination Base. + * + * It is an address offset (128 bit aligned) from the beginning of + * frame buffer. + */ + + SMTC_write2Dreg(DE_WINDOW_DESTINATION_BASE, dBase); + + if (dPitch) { + + /* + * Program pitch (distance between the 1st points of two + * adjacent lines). + * + * Note that input pitch is BYTE value, but the 2D Pitch + * register uses pixel values. Need Byte to pixel convertion. + */ + + SMTC_write2Dreg(DE_PITCH, + FIELD_VALUE(0, DE_PITCH, DESTINATION, + dPitch / + bytePerPixel) | FIELD_VALUE(0, + DE_PITCH, + SOURCE, + dPitch / + bytePerPixel)); + + /* Screen Window width in Pixels. + * + * 2D engine uses this value to calculate the linear address in + * frame buffer for a given point. + */ + + SMTC_write2Dreg(DE_WINDOW_WIDTH, + FIELD_VALUE(0, DE_WINDOW_WIDTH, DESTINATION, + (dPitch / + bytePerPixel)) | FIELD_VALUE(0, + DE_WINDOW_WIDTH, + SOURCE, + (dPitch + / + bytePerPixel))); + } + /* Note: For 2D Source in Host Write, only X_K1 field is needed, and + * Y_K2 field is not used. For mono bitmap, use startBit for X_K1. + */ + + SMTC_write2Dreg(DE_SOURCE, + FIELD_SET(0, DE_SOURCE, WRAP, DISABLE) | + FIELD_VALUE(0, DE_SOURCE, X_K1, startBit) | + FIELD_VALUE(0, DE_SOURCE, Y_K2, 0)); + + SMTC_write2Dreg(DE_DESTINATION, + FIELD_SET(0, DE_DESTINATION, WRAP, DISABLE) | + FIELD_VALUE(0, DE_DESTINATION, X, dx) | + FIELD_VALUE(0, DE_DESTINATION, Y, dy)); + + SMTC_write2Dreg(DE_DIMENSION, + FIELD_VALUE(0, DE_DIMENSION, X, width) | + FIELD_VALUE(0, DE_DIMENSION, Y_ET, height)); + + SMTC_write2Dreg(DE_FOREGROUND, fColor); + SMTC_write2Dreg(DE_BACKGROUND, bColor); + + if (bpp) + deSetPixelFormat(bpp); + /* Set the pixel format of the destination */ + + de_ctrl = FIELD_VALUE(0, DE_CONTROL, ROP, rop2) | + FIELD_SET(0, DE_CONTROL, ROP_SELECT, ROP2) | + FIELD_SET(0, DE_CONTROL, COMMAND, HOST_WRITE) | + FIELD_SET(0, DE_CONTROL, HOST, MONO) | + FIELD_SET(0, DE_CONTROL, STATUS, START); + + SMTC_write2Dreg(DE_CONTROL, de_ctrl | deGetTransparency()); + + /* Write MONO data (line by line) to 2D Engine data port */ + for (i = 0; i < height; i++) { + /* For each line, send the data in chunks of 4 bytes */ + for (j = 0; j < (ul4BytesPerScan / 4); j++) + SMTC_write2Ddataport(0, + *(unsigned long *)(pSrcbuf + + (j * 4))); + + if (ulBytesRemain) { + memcpy(ajRemain, pSrcbuf + ul4BytesPerScan, + ulBytesRemain); + SMTC_write2Ddataport(0, *(unsigned long *)ajRemain); + } + + pSrcbuf += srcDelta; + } + smtc_de_busy = 1; + + return 0; +} + +/* + * This function gets the transparency status from DE_CONTROL register. + * It returns a double word with the transparent fields properly set, + * while other fields are 0. + */ +unsigned long deGetTransparency(void) +{ + unsigned long de_ctrl; + + de_ctrl = SMTC_read2Dreg(DE_CONTROL); + + de_ctrl &= + FIELD_MASK(DE_CONTROL_TRANSPARENCY_MATCH) | + FIELD_MASK(DE_CONTROL_TRANSPARENCY_SELECT) | + FIELD_MASK(DE_CONTROL_TRANSPARENCY); + + return de_ctrl; +} diff --git a/drivers/staging/sm7xx/smtc2d.h b/drivers/staging/sm7xx/smtc2d.h new file mode 100644 index 000000000000..38d0c335322b --- /dev/null +++ b/drivers/staging/sm7xx/smtc2d.h @@ -0,0 +1,530 @@ +/* + * Silicon Motion SM712 2D drawing engine functions. + * + * Copyright (C) 2006 Silicon Motion Technology Corp. + * Author: Ge Wang, gewang@siliconmotion.com + * + * Copyright (C) 2009 Lemote, Inc. + * Author: Wu Zhangjin, wuzj@lemote.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#ifndef NULL +#define NULL 0 +#endif + +/* Internal macros */ + +#define _F_START(f) (0 ? f) +#define _F_END(f) (1 ? f) +#define _F_SIZE(f) (1 + _F_END(f) - _F_START(f)) +#define _F_MASK(f) (((1ULL << _F_SIZE(f)) - 1) << _F_START(f)) +#define _F_NORMALIZE(v, f) (((v) & _F_MASK(f)) >> _F_START(f)) +#define _F_DENORMALIZE(v, f) (((v) << _F_START(f)) & _F_MASK(f)) + +/* Global macros */ + +#define FIELD_GET(x, reg, field) \ +( \ + _F_NORMALIZE((x), reg ## _ ## field) \ +) + +#define FIELD_SET(x, reg, field, value) \ +( \ + (x & ~_F_MASK(reg ## _ ## field)) \ + | _F_DENORMALIZE(reg ## _ ## field ## _ ## value, reg ## _ ## field) \ +) + +#define FIELD_VALUE(x, reg, field, value) \ +( \ + (x & ~_F_MASK(reg ## _ ## field)) \ + | _F_DENORMALIZE(value, reg ## _ ## field) \ +) + +#define FIELD_CLEAR(reg, field) \ +( \ + ~_F_MASK(reg ## _ ## field) \ +) + +/* Field Macros */ + +#define FIELD_START(field) (0 ? field) +#define FIELD_END(field) (1 ? field) +#define FIELD_SIZE(field) \ + (1 + FIELD_END(field) - FIELD_START(field)) + +#define FIELD_MASK(field) \ + (((1 << (FIELD_SIZE(field)-1)) \ + | ((1 << (FIELD_SIZE(field)-1)) - 1)) \ + << FIELD_START(field)) + +#define FIELD_NORMALIZE(reg, field) \ + (((reg) & FIELD_MASK(field)) >> FIELD_START(field)) + +#define FIELD_DENORMALIZE(field, value) \ + (((value) << FIELD_START(field)) & FIELD_MASK(field)) + +#define FIELD_INIT(reg, field, value) \ + FIELD_DENORMALIZE(reg ## _ ## field, \ + reg ## _ ## field ## _ ## value) + +#define FIELD_INIT_VAL(reg, field, value) \ + (FIELD_DENORMALIZE(reg ## _ ## field, value)) + +#define FIELD_VAL_SET(x, r, f, v) ({ \ + x = (x & ~FIELD_MASK(r ## _ ## f)) \ + | FIELD_DENORMALIZE(r ## _ ## f, r ## _ ## f ## _ ## v) \ +}) + +#define RGB(r, g, b) ((unsigned long)(((r) << 16) | ((g) << 8) | (b))) + +/* Transparent info definition */ +typedef struct { + unsigned long match; /* Matching pixel is OPAQUE/TRANSPARENT */ + unsigned long select; /* Transparency controlled by SRC/DST */ + unsigned long control; /* ENABLE/DISABLE transparency */ + unsigned long color; /* Transparent color */ +} Transparent, *pTransparent; + +#define PIXEL_DEPTH_1_BP 0 /* 1 bit per pixel */ +#define PIXEL_DEPTH_8_BPP 1 /* 8 bits per pixel */ +#define PIXEL_DEPTH_16_BPP 2 /* 16 bits per pixel */ +#define PIXEL_DEPTH_32_BPP 3 /* 32 bits per pixel */ +#define PIXEL_DEPTH_YUV422 8 /* 16 bits per pixel YUV422 */ +#define PIXEL_DEPTH_YUV420 9 /* 16 bits per pixel YUV420 */ + +#define PATTERN_WIDTH 8 +#define PATTERN_HEIGHT 8 + +#define TOP_TO_BOTTOM 0 +#define BOTTOM_TO_TOP 1 +#define RIGHT_TO_LEFT BOTTOM_TO_TOP +#define LEFT_TO_RIGHT TOP_TO_BOTTOM + +/* Constants used in Transparent structure */ +#define MATCH_OPAQUE 0x00000000 +#define MATCH_TRANSPARENT 0x00000400 +#define SOURCE 0x00000000 +#define DESTINATION 0x00000200 + +/* 2D registers. */ + +#define DE_SOURCE 0x000000 +#define DE_SOURCE_WRAP 31 : 31 +#define DE_SOURCE_WRAP_DISABLE 0 +#define DE_SOURCE_WRAP_ENABLE 1 +#define DE_SOURCE_X_K1 29 : 16 +#define DE_SOURCE_Y_K2 15 : 0 + +#define DE_DESTINATION 0x000004 +#define DE_DESTINATION_WRAP 31 : 31 +#define DE_DESTINATION_WRAP_DISABLE 0 +#define DE_DESTINATION_WRAP_ENABLE 1 +#define DE_DESTINATION_X 28 : 16 +#define DE_DESTINATION_Y 15 : 0 + +#define DE_DIMENSION 0x000008 +#define DE_DIMENSION_X 28 : 16 +#define DE_DIMENSION_Y_ET 15 : 0 + +#define DE_CONTROL 0x00000C +#define DE_CONTROL_STATUS 31 : 31 +#define DE_CONTROL_STATUS_STOP 0 +#define DE_CONTROL_STATUS_START 1 +#define DE_CONTROL_PATTERN 30 : 30 +#define DE_CONTROL_PATTERN_MONO 0 +#define DE_CONTROL_PATTERN_COLOR 1 +#define DE_CONTROL_UPDATE_DESTINATION_X 29 : 29 +#define DE_CONTROL_UPDATE_DESTINATION_X_DISABLE 0 +#define DE_CONTROL_UPDATE_DESTINATION_X_ENABLE 1 +#define DE_CONTROL_QUICK_START 28 : 28 +#define DE_CONTROL_QUICK_START_DISABLE 0 +#define DE_CONTROL_QUICK_START_ENABLE 1 +#define DE_CONTROL_DIRECTION 27 : 27 +#define DE_CONTROL_DIRECTION_LEFT_TO_RIGHT 0 +#define DE_CONTROL_DIRECTION_RIGHT_TO_LEFT 1 +#define DE_CONTROL_MAJOR 26 : 26 +#define DE_CONTROL_MAJOR_X 0 +#define DE_CONTROL_MAJOR_Y 1 +#define DE_CONTROL_STEP_X 25 : 25 +#define DE_CONTROL_STEP_X_POSITIVE 1 +#define DE_CONTROL_STEP_X_NEGATIVE 0 +#define DE_CONTROL_STEP_Y 24 : 24 +#define DE_CONTROL_STEP_Y_POSITIVE 1 +#define DE_CONTROL_STEP_Y_NEGATIVE 0 +#define DE_CONTROL_STRETCH 23 : 23 +#define DE_CONTROL_STRETCH_DISABLE 0 +#define DE_CONTROL_STRETCH_ENABLE 1 +#define DE_CONTROL_HOST 22 : 22 +#define DE_CONTROL_HOST_COLOR 0 +#define DE_CONTROL_HOST_MONO 1 +#define DE_CONTROL_LAST_PIXEL 21 : 21 +#define DE_CONTROL_LAST_PIXEL_OFF 0 +#define DE_CONTROL_LAST_PIXEL_ON 1 +#define DE_CONTROL_COMMAND 20 : 16 +#define DE_CONTROL_COMMAND_BITBLT 0 +#define DE_CONTROL_COMMAND_RECTANGLE_FILL 1 +#define DE_CONTROL_COMMAND_DE_TILE 2 +#define DE_CONTROL_COMMAND_TRAPEZOID_FILL 3 +#define DE_CONTROL_COMMAND_ALPHA_BLEND 4 +#define DE_CONTROL_COMMAND_RLE_STRIP 5 +#define DE_CONTROL_COMMAND_SHORT_STROKE 6 +#define DE_CONTROL_COMMAND_LINE_DRAW 7 +#define DE_CONTROL_COMMAND_HOST_WRITE 8 +#define DE_CONTROL_COMMAND_HOST_READ 9 +#define DE_CONTROL_COMMAND_HOST_WRITE_BOTTOM_UP 10 +#define DE_CONTROL_COMMAND_ROTATE 11 +#define DE_CONTROL_COMMAND_FONT 12 +#define DE_CONTROL_COMMAND_TEXTURE_LOAD 15 +#define DE_CONTROL_ROP_SELECT 15 : 15 +#define DE_CONTROL_ROP_SELECT_ROP3 0 +#define DE_CONTROL_ROP_SELECT_ROP2 1 +#define DE_CONTROL_ROP2_SOURCE 14 : 14 +#define DE_CONTROL_ROP2_SOURCE_BITMAP 0 +#define DE_CONTROL_ROP2_SOURCE_PATTERN 1 +#define DE_CONTROL_MONO_DATA 13 : 12 +#define DE_CONTROL_MONO_DATA_NOT_PACKED 0 +#define DE_CONTROL_MONO_DATA_8_PACKED 1 +#define DE_CONTROL_MONO_DATA_16_PACKED 2 +#define DE_CONTROL_MONO_DATA_32_PACKED 3 +#define DE_CONTROL_REPEAT_ROTATE 11 : 11 +#define DE_CONTROL_REPEAT_ROTATE_DISABLE 0 +#define DE_CONTROL_REPEAT_ROTATE_ENABLE 1 +#define DE_CONTROL_TRANSPARENCY_MATCH 10 : 10 +#define DE_CONTROL_TRANSPARENCY_MATCH_OPAQUE 0 +#define DE_CONTROL_TRANSPARENCY_MATCH_TRANSPARENT 1 +#define DE_CONTROL_TRANSPARENCY_SELECT 9 : 9 +#define DE_CONTROL_TRANSPARENCY_SELECT_SOURCE 0 +#define DE_CONTROL_TRANSPARENCY_SELECT_DESTINATION 1 +#define DE_CONTROL_TRANSPARENCY 8 : 8 +#define DE_CONTROL_TRANSPARENCY_DISABLE 0 +#define DE_CONTROL_TRANSPARENCY_ENABLE 1 +#define DE_CONTROL_ROP 7 : 0 + +/* Pseudo fields. */ + +#define DE_CONTROL_SHORT_STROKE_DIR 27 : 24 +#define DE_CONTROL_SHORT_STROKE_DIR_225 0 +#define DE_CONTROL_SHORT_STROKE_DIR_135 1 +#define DE_CONTROL_SHORT_STROKE_DIR_315 2 +#define DE_CONTROL_SHORT_STROKE_DIR_45 3 +#define DE_CONTROL_SHORT_STROKE_DIR_270 4 +#define DE_CONTROL_SHORT_STROKE_DIR_90 5 +#define DE_CONTROL_SHORT_STROKE_DIR_180 8 +#define DE_CONTROL_SHORT_STROKE_DIR_0 10 +#define DE_CONTROL_ROTATION 25 : 24 +#define DE_CONTROL_ROTATION_0 0 +#define DE_CONTROL_ROTATION_270 1 +#define DE_CONTROL_ROTATION_90 2 +#define DE_CONTROL_ROTATION_180 3 + +#define DE_PITCH 0x000010 +#define DE_PITCH_DESTINATION 28 : 16 +#define DE_PITCH_SOURCE 12 : 0 + +#define DE_FOREGROUND 0x000014 +#define DE_FOREGROUND_COLOR 31 : 0 + +#define DE_BACKGROUND 0x000018 +#define DE_BACKGROUND_COLOR 31 : 0 + +#define DE_STRETCH_FORMAT 0x00001C +#define DE_STRETCH_FORMAT_PATTERN_XY 30 : 30 +#define DE_STRETCH_FORMAT_PATTERN_XY_NORMAL 0 +#define DE_STRETCH_FORMAT_PATTERN_XY_OVERWRITE 1 +#define DE_STRETCH_FORMAT_PATTERN_Y 29 : 27 +#define DE_STRETCH_FORMAT_PATTERN_X 25 : 23 +#define DE_STRETCH_FORMAT_PIXEL_FORMAT 21 : 20 +#define DE_STRETCH_FORMAT_PIXEL_FORMAT_8 0 +#define DE_STRETCH_FORMAT_PIXEL_FORMAT_16 1 +#define DE_STRETCH_FORMAT_PIXEL_FORMAT_24 3 +#define DE_STRETCH_FORMAT_PIXEL_FORMAT_32 2 +#define DE_STRETCH_FORMAT_ADDRESSING 19 : 16 +#define DE_STRETCH_FORMAT_ADDRESSING_XY 0 +#define DE_STRETCH_FORMAT_ADDRESSING_LINEAR 15 +#define DE_STRETCH_FORMAT_SOURCE_HEIGHT 11 : 0 + +#define DE_COLOR_COMPARE 0x000020 +#define DE_COLOR_COMPARE_COLOR 23 : 0 + +#define DE_COLOR_COMPARE_MASK 0x000024 +#define DE_COLOR_COMPARE_MASK_MASKS 23 : 0 + +#define DE_MASKS 0x000028 +#define DE_MASKS_BYTE_MASK 31 : 16 +#define DE_MASKS_BIT_MASK 15 : 0 + +#define DE_CLIP_TL 0x00002C +#define DE_CLIP_TL_TOP 31 : 16 +#define DE_CLIP_TL_STATUS 13 : 13 +#define DE_CLIP_TL_STATUS_DISABLE 0 +#define DE_CLIP_TL_STATUS_ENABLE 1 +#define DE_CLIP_TL_INHIBIT 12 : 12 +#define DE_CLIP_TL_INHIBIT_OUTSIDE 0 +#define DE_CLIP_TL_INHIBIT_INSIDE 1 +#define DE_CLIP_TL_LEFT 11 : 0 + +#define DE_CLIP_BR 0x000030 +#define DE_CLIP_BR_BOTTOM 31 : 16 +#define DE_CLIP_BR_RIGHT 12 : 0 + +#define DE_MONO_PATTERN_LOW 0x000034 +#define DE_MONO_PATTERN_LOW_PATTERN 31 : 0 + +#define DE_MONO_PATTERN_HIGH 0x000038 +#define DE_MONO_PATTERN_HIGH_PATTERN 31 : 0 + +#define DE_WINDOW_WIDTH 0x00003C +#define DE_WINDOW_WIDTH_DESTINATION 28 : 16 +#define DE_WINDOW_WIDTH_SOURCE 12 : 0 + +#define DE_WINDOW_SOURCE_BASE 0x000040 +#define DE_WINDOW_SOURCE_BASE_EXT 27 : 27 +#define DE_WINDOW_SOURCE_BASE_EXT_LOCAL 0 +#define DE_WINDOW_SOURCE_BASE_EXT_EXTERNAL 1 +#define DE_WINDOW_SOURCE_BASE_CS 26 : 26 +#define DE_WINDOW_SOURCE_BASE_CS_0 0 +#define DE_WINDOW_SOURCE_BASE_CS_1 1 +#define DE_WINDOW_SOURCE_BASE_ADDRESS 25 : 0 + +#define DE_WINDOW_DESTINATION_BASE 0x000044 +#define DE_WINDOW_DESTINATION_BASE_EXT 27 : 27 +#define DE_WINDOW_DESTINATION_BASE_EXT_LOCAL 0 +#define DE_WINDOW_DESTINATION_BASE_EXT_EXTERNAL 1 +#define DE_WINDOW_DESTINATION_BASE_CS 26 : 26 +#define DE_WINDOW_DESTINATION_BASE_CS_0 0 +#define DE_WINDOW_DESTINATION_BASE_CS_1 1 +#define DE_WINDOW_DESTINATION_BASE_ADDRESS 25 : 0 + +#define DE_ALPHA 0x000048 +#define DE_ALPHA_VALUE 7 : 0 + +#define DE_WRAP 0x00004C +#define DE_WRAP_X 31 : 16 +#define DE_WRAP_Y 15 : 0 + +#define DE_STATUS 0x000050 +#define DE_STATUS_CSC 1 : 1 +#define DE_STATUS_CSC_CLEAR 0 +#define DE_STATUS_CSC_NOT_ACTIVE 0 +#define DE_STATUS_CSC_ACTIVE 1 +#define DE_STATUS_2D 0 : 0 +#define DE_STATUS_2D_CLEAR 0 +#define DE_STATUS_2D_NOT_ACTIVE 0 +#define DE_STATUS_2D_ACTIVE 1 + +/* Color Space Conversion registers. */ + +#define CSC_Y_SOURCE_BASE 0x0000C8 +#define CSC_Y_SOURCE_BASE_EXT 27 : 27 +#define CSC_Y_SOURCE_BASE_EXT_LOCAL 0 +#define CSC_Y_SOURCE_BASE_EXT_EXTERNAL 1 +#define CSC_Y_SOURCE_BASE_CS 26 : 26 +#define CSC_Y_SOURCE_BASE_CS_0 0 +#define CSC_Y_SOURCE_BASE_CS_1 1 +#define CSC_Y_SOURCE_BASE_ADDRESS 25 : 0 + +#define CSC_CONSTANTS 0x0000CC +#define CSC_CONSTANTS_Y 31 : 24 +#define CSC_CONSTANTS_R 23 : 16 +#define CSC_CONSTANTS_G 15 : 8 +#define CSC_CONSTANTS_B 7 : 0 + +#define CSC_Y_SOURCE_X 0x0000D0 +#define CSC_Y_SOURCE_X_INTEGER 26 : 16 +#define CSC_Y_SOURCE_X_FRACTION 15 : 3 + +#define CSC_Y_SOURCE_Y 0x0000D4 +#define CSC_Y_SOURCE_Y_INTEGER 27 : 16 +#define CSC_Y_SOURCE_Y_FRACTION 15 : 3 + +#define CSC_U_SOURCE_BASE 0x0000D8 +#define CSC_U_SOURCE_BASE_EXT 27 : 27 +#define CSC_U_SOURCE_BASE_EXT_LOCAL 0 +#define CSC_U_SOURCE_BASE_EXT_EXTERNAL 1 +#define CSC_U_SOURCE_BASE_CS 26 : 26 +#define CSC_U_SOURCE_BASE_CS_0 0 +#define CSC_U_SOURCE_BASE_CS_1 1 +#define CSC_U_SOURCE_BASE_ADDRESS 25 : 0 + +#define CSC_V_SOURCE_BASE 0x0000DC +#define CSC_V_SOURCE_BASE_EXT 27 : 27 +#define CSC_V_SOURCE_BASE_EXT_LOCAL 0 +#define CSC_V_SOURCE_BASE_EXT_EXTERNAL 1 +#define CSC_V_SOURCE_BASE_CS 26 : 26 +#define CSC_V_SOURCE_BASE_CS_0 0 +#define CSC_V_SOURCE_BASE_CS_1 1 +#define CSC_V_SOURCE_BASE_ADDRESS 25 : 0 + +#define CSC_SOURCE_DIMENSION 0x0000E0 +#define CSC_SOURCE_DIMENSION_X 31 : 16 +#define CSC_SOURCE_DIMENSION_Y 15 : 0 + +#define CSC_SOURCE_PITCH 0x0000E4 +#define CSC_SOURCE_PITCH_Y 31 : 16 +#define CSC_SOURCE_PITCH_UV 15 : 0 + +#define CSC_DESTINATION 0x0000E8 +#define CSC_DESTINATION_WRAP 31 : 31 +#define CSC_DESTINATION_WRAP_DISABLE 0 +#define CSC_DESTINATION_WRAP_ENABLE 1 +#define CSC_DESTINATION_X 27 : 16 +#define CSC_DESTINATION_Y 11 : 0 + +#define CSC_DESTINATION_DIMENSION 0x0000EC +#define CSC_DESTINATION_DIMENSION_X 31 : 16 +#define CSC_DESTINATION_DIMENSION_Y 15 : 0 + +#define CSC_DESTINATION_PITCH 0x0000F0 +#define CSC_DESTINATION_PITCH_X 31 : 16 +#define CSC_DESTINATION_PITCH_Y 15 : 0 + +#define CSC_SCALE_FACTOR 0x0000F4 +#define CSC_SCALE_FACTOR_HORIZONTAL 31 : 16 +#define CSC_SCALE_FACTOR_VERTICAL 15 : 0 + +#define CSC_DESTINATION_BASE 0x0000F8 +#define CSC_DESTINATION_BASE_EXT 27 : 27 +#define CSC_DESTINATION_BASE_EXT_LOCAL 0 +#define CSC_DESTINATION_BASE_EXT_EXTERNAL 1 +#define CSC_DESTINATION_BASE_CS 26 : 26 +#define CSC_DESTINATION_BASE_CS_0 0 +#define CSC_DESTINATION_BASE_CS_1 1 +#define CSC_DESTINATION_BASE_ADDRESS 25 : 0 + +#define CSC_CONTROL 0x0000FC +#define CSC_CONTROL_STATUS 31 : 31 +#define CSC_CONTROL_STATUS_STOP 0 +#define CSC_CONTROL_STATUS_START 1 +#define CSC_CONTROL_SOURCE_FORMAT 30 : 28 +#define CSC_CONTROL_SOURCE_FORMAT_YUV422 0 +#define CSC_CONTROL_SOURCE_FORMAT_YUV420I 1 +#define CSC_CONTROL_SOURCE_FORMAT_YUV420 2 +#define CSC_CONTROL_SOURCE_FORMAT_YVU9 3 +#define CSC_CONTROL_SOURCE_FORMAT_IYU1 4 +#define CSC_CONTROL_SOURCE_FORMAT_IYU2 5 +#define CSC_CONTROL_SOURCE_FORMAT_RGB565 6 +#define CSC_CONTROL_SOURCE_FORMAT_RGB8888 7 +#define CSC_CONTROL_DESTINATION_FORMAT 27 : 26 +#define CSC_CONTROL_DESTINATION_FORMAT_RGB565 0 +#define CSC_CONTROL_DESTINATION_FORMAT_RGB8888 1 +#define CSC_CONTROL_HORIZONTAL_FILTER 25 : 25 +#define CSC_CONTROL_HORIZONTAL_FILTER_DISABLE 0 +#define CSC_CONTROL_HORIZONTAL_FILTER_ENABLE 1 +#define CSC_CONTROL_VERTICAL_FILTER 24 : 24 +#define CSC_CONTROL_VERTICAL_FILTER_DISABLE 0 +#define CSC_CONTROL_VERTICAL_FILTER_ENABLE 1 +#define CSC_CONTROL_BYTE_ORDER 23 : 23 +#define CSC_CONTROL_BYTE_ORDER_YUYV 0 +#define CSC_CONTROL_BYTE_ORDER_UYVY 1 + +#define DE_DATA_PORT_501 0x110000 +#define DE_DATA_PORT_712 0x400000 +#define DE_DATA_PORT_722 0x6000 + +/* point to virtual Memory Map IO starting address */ +extern char *smtc_RegBaseAddress; +/* point to virtual video memory starting address */ +extern char *smtc_VRAMBaseAddress; +extern unsigned char smtc_de_busy; + +extern unsigned long memRead32(unsigned long nOffset); +extern void memWrite32(unsigned long nOffset, unsigned long nData); +extern unsigned long SMTC_read2Dreg(unsigned long nOffset); + +/* 2D functions */ +extern void deInit(unsigned int nModeWidth, unsigned int nModeHeight, + unsigned int bpp); + +extern void deWaitForNotBusy(void); + +extern void deVerticalLine(unsigned long dst_base, + unsigned long dst_pitch, + unsigned long nX, + unsigned long nY, + unsigned long dst_height, + unsigned long nColor); + +extern void deHorizontalLine(unsigned long dst_base, + unsigned long dst_pitch, + unsigned long nX, + unsigned long nY, + unsigned long dst_width, + unsigned long nColor); + +extern void deLine(unsigned long dst_base, + unsigned long dst_pitch, + unsigned long nX1, + unsigned long nY1, + unsigned long nX2, + unsigned long nY2, + unsigned long nColor); + +extern void deFillRect(unsigned long dst_base, + unsigned long dst_pitch, + unsigned long dst_X, + unsigned long dst_Y, + unsigned long dst_width, + unsigned long dst_height, + unsigned long nColor); + +extern void deRotatePattern(unsigned char *pattern_dstaddr, + unsigned long pattern_src_addr, + unsigned long pattern_BPP, + unsigned long pattern_stride, + int patternX, + int patternY); + +extern void deCopy(unsigned long dst_base, + unsigned long dst_pitch, + unsigned long dst_BPP, + unsigned long dst_X, + unsigned long dst_Y, + unsigned long dst_width, + unsigned long dst_height, + unsigned long src_base, + unsigned long src_pitch, + unsigned long src_X, + unsigned long src_Y, + pTransparent pTransp, + unsigned char nROP2); + +/* + * System memory to Video memory monochrome expansion. + * + * Source is monochrome image in system memory. This function expands the + * monochrome data to color image in video memory. + * + * @pSrcbuf: pointer to start of source buffer in system memory + * @srcDelta: Pitch value (in bytes) of the source buffer, +ive means top + * down and -ive mean button up + * @startBit: Mono data can start at any bit in a byte, this value should + * be 0 to 7 + * @dBase: Address of destination : offset in frame buffer + * @dPitch: Pitch value of destination surface in BYTE + * @bpp: Color depth of destination surface + * @dx, dy: Starting coordinate of destination surface + * @width, height: width and height of rectange in pixel value + * @fColor,bColor: Foreground, Background color (corresponding to a 1, 0 in + * the monochrome data) + * @rop2: ROP value + */ + +extern long deSystemMem2VideoMemMonoBlt( + const char *pSrcbuf, + long srcDelta, + unsigned long startBit, + unsigned long dBase, + unsigned long dPitch, + unsigned long bpp, + unsigned long dx, unsigned long dy, + unsigned long width, unsigned long height, + unsigned long fColor, + unsigned long bColor, + unsigned long rop2); + +extern unsigned long deGetTransparency(void); +extern void deSetPixelFormat(unsigned long bpp); diff --git a/drivers/staging/sm7xx/smtcfb.c b/drivers/staging/sm7xx/smtcfb.c new file mode 100644 index 000000000000..161dbc9c1397 --- /dev/null +++ b/drivers/staging/sm7xx/smtcfb.c @@ -0,0 +1,1253 @@ +/* + * Silicon Motion SM7XX frame buffer device + * + * Copyright (C) 2006 Silicon Motion Technology Corp. + * Authors: Ge Wang, gewang@siliconmotion.com + * Boyod boyod.yang@siliconmotion.com.cn + * + * Copyright (C) 2009 Lemote, Inc. + * Author: Wu Zhangjin, wuzj@lemote.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + * + * Version 0.10.26192.21.01 + * - Add PowerPC/Big endian support + * - Add 2D support for Lynx + * - Verified on2.6.19.2 Boyod.yang + * + * Version 0.09.2621.00.01 + * - Only support Linux Kernel's version 2.6.21. + * Boyod.yang + * + * Version 0.09 + * - Only support Linux Kernel's version 2.6.12. + * Boyod.yang + */ + +#ifndef __KERNEL__ +#define __KERNEL__ +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PM +#include +#endif + +struct screen_info smtc_screen_info; + +#include "smtcfb.h" +#include "smtc2d.h" + +#ifdef DEBUG +#define smdbg(format, arg...) printk(KERN_DEBUG format , ## arg) +#else +#define smdbg(format, arg...) +#endif + +/* +* Private structure +*/ +struct smtcfb_info { + /* + * The following is a pointer to be passed into the + * functions below. The modules outside the main + * voyager.c driver have no knowledge as to what + * is within this structure. + */ + struct fb_info fb; + struct display_switch *dispsw; + struct pci_dev *dev; + signed int currcon; + + struct { + u8 red, green, blue; + } palette[NR_RGB]; + + u_int palette_size; +}; + +struct par_info { + /* + * Hardware + */ + u16 chipID; + unsigned char __iomem *m_pMMIO; + char __iomem *m_pLFB; + char *m_pDPR; + char *m_pVPR; + char *m_pCPR; + + u_int width; + u_int height; + u_int hz; + u_long BaseAddressInVRAM; + u8 chipRevID; +}; + +struct vesa_mode_table { + char mode_index[6]; + u16 lfb_width; + u16 lfb_height; + u16 lfb_depth; +}; + +static struct vesa_mode_table vesa_mode[] = { + {"0x301", 640, 480, 8}, + {"0x303", 800, 600, 8}, + {"0x305", 1024, 768, 8}, + {"0x307", 1280, 1024, 8}, + + {"0x311", 640, 480, 16}, + {"0x314", 800, 600, 16}, + {"0x317", 1024, 768, 16}, + {"0x31A", 1280, 1024, 16}, + + {"0x312", 640, 480, 24}, + {"0x315", 800, 600, 24}, + {"0x318", 1024, 768, 24}, + {"0x31B", 1280, 1024, 24}, +}; + +char __iomem *smtc_RegBaseAddress; /* Memory Map IO starting address */ +char __iomem *smtc_VRAMBaseAddress; /* video memory starting address */ + +char *smtc_2DBaseAddress; /* 2D engine starting address */ +char *smtc_2Ddataport; /* 2D data port offset */ +short smtc_2Dacceleration; + +static u32 colreg[17]; +static struct par_info hw; /* hardware information */ + +u16 smtc_ChipIDs[] = { + 0x710, + 0x712, + 0x720 +}; + +#define numSMTCchipIDs (sizeof(smtc_ChipIDs) / sizeof(u16)) + +void deWaitForNotBusy(void) +{ + unsigned long i = 0x1000000; + while (i--) { + if ((smtc_seqr(0x16) & 0x18) == 0x10) + break; + } + smtc_de_busy = 0; +} + +static void sm712_set_timing(struct smtcfb_info *sfb, + struct par_info *ppar_info) +{ + int i = 0, j = 0; + u32 m_nScreenStride; + + smdbg("\nppar_info->width = %d ppar_info->height = %d" + "sfb->fb.var.bits_per_pixel = %d ppar_info->hz = %d\n", + ppar_info->width, ppar_info->height, + sfb->fb.var.bits_per_pixel, ppar_info->hz); + + for (j = 0; j < numVGAModes; j++) { + if (VGAMode[j].mmSizeX == ppar_info->width && + VGAMode[j].mmSizeY == ppar_info->height && + VGAMode[j].bpp == sfb->fb.var.bits_per_pixel && + VGAMode[j].hz == ppar_info->hz) { + + smdbg("\nVGAMode[j].mmSizeX = %d VGAMode[j].mmSizeY =" + "%d VGAMode[j].bpp = %d" + "VGAMode[j].hz=%d\n", + VGAMode[j].mmSizeX, VGAMode[j].mmSizeY, + VGAMode[j].bpp, VGAMode[j].hz); + + smdbg("VGAMode index=%d\n", j); + + smtc_mmiowb(0x0, 0x3c6); + + smtc_seqw(0, 0x1); + + smtc_mmiowb(VGAMode[j].Init_MISC, 0x3c2); + + /* init SEQ register SR00 - SR04 */ + for (i = 0; i < SIZE_SR00_SR04; i++) + smtc_seqw(i, VGAMode[j].Init_SR00_SR04[i]); + + /* init SEQ register SR10 - SR24 */ + for (i = 0; i < SIZE_SR10_SR24; i++) + smtc_seqw(i + 0x10, + VGAMode[j].Init_SR10_SR24[i]); + + /* init SEQ register SR30 - SR75 */ + for (i = 0; i < SIZE_SR30_SR75; i++) + if (((i + 0x30) != 0x62) \ + && ((i + 0x30) != 0x6a) \ + && ((i + 0x30) != 0x6b)) + smtc_seqw(i + 0x30, + VGAMode[j].Init_SR30_SR75[i]); + + /* init SEQ register SR80 - SR93 */ + for (i = 0; i < SIZE_SR80_SR93; i++) + smtc_seqw(i + 0x80, + VGAMode[j].Init_SR80_SR93[i]); + + /* init SEQ register SRA0 - SRAF */ + for (i = 0; i < SIZE_SRA0_SRAF; i++) + smtc_seqw(i + 0xa0, + VGAMode[j].Init_SRA0_SRAF[i]); + + /* init Graphic register GR00 - GR08 */ + for (i = 0; i < SIZE_GR00_GR08; i++) + smtc_grphw(i, VGAMode[j].Init_GR00_GR08[i]); + + /* init Attribute register AR00 - AR14 */ + for (i = 0; i < SIZE_AR00_AR14; i++) + smtc_attrw(i, VGAMode[j].Init_AR00_AR14[i]); + + /* init CRTC register CR00 - CR18 */ + for (i = 0; i < SIZE_CR00_CR18; i++) + smtc_crtcw(i, VGAMode[j].Init_CR00_CR18[i]); + + /* init CRTC register CR30 - CR4D */ + for (i = 0; i < SIZE_CR30_CR4D; i++) + smtc_crtcw(i + 0x30, + VGAMode[j].Init_CR30_CR4D[i]); + + /* init CRTC register CR90 - CRA7 */ + for (i = 0; i < SIZE_CR90_CRA7; i++) + smtc_crtcw(i + 0x90, + VGAMode[j].Init_CR90_CRA7[i]); + } + } + smtc_mmiowb(0x67, 0x3c2); + + /* set VPR registers */ + writel(0x0, ppar_info->m_pVPR + 0x0C); + writel(0x0, ppar_info->m_pVPR + 0x40); + + /* set data width */ + m_nScreenStride = + (ppar_info->width * sfb->fb.var.bits_per_pixel) / 64; + switch (sfb->fb.var.bits_per_pixel) { + case 8: + writel(0x0, ppar_info->m_pVPR + 0x0); + break; + case 16: + writel(0x00020000, ppar_info->m_pVPR + 0x0); + break; + case 24: + writel(0x00040000, ppar_info->m_pVPR + 0x0); + break; + case 32: + writel(0x00030000, ppar_info->m_pVPR + 0x0); + break; + } + writel((u32) (((m_nScreenStride + 2) << 16) | m_nScreenStride), + ppar_info->m_pVPR + 0x10); + +} + +static void sm712_setpalette(int regno, unsigned red, unsigned green, + unsigned blue, struct fb_info *info) +{ + struct par_info *cur_par = (struct par_info *)info->par; + + if (cur_par->BaseAddressInVRAM) + /* + * second display palette for dual head. Enable CRT RAM, 6-bit + * RAM + */ + smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x20); + else + /* primary display palette. Enable LCD RAM only, 6-bit RAM */ + smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10); + smtc_mmiowb(regno, dac_reg); + smtc_mmiowb(red >> 10, dac_val); + smtc_mmiowb(green >> 10, dac_val); + smtc_mmiowb(blue >> 10, dac_val); +} + +static void smtc_set_timing(struct smtcfb_info *sfb, struct par_info + *ppar_info) +{ + switch (ppar_info->chipID) { + case 0x710: + case 0x712: + case 0x720: + sm712_set_timing(sfb, ppar_info); + break; + } +} + +static struct fb_var_screeninfo smtcfb_var = { + .xres = 1024, + .yres = 600, + .xres_virtual = 1024, + .yres_virtual = 600, + .bits_per_pixel = 16, + .red = {16, 8, 0}, + .green = {8, 8, 0}, + .blue = {0, 8, 0}, + .activate = FB_ACTIVATE_NOW, + .height = -1, + .width = -1, + .vmode = FB_VMODE_NONINTERLACED, +}; + +static struct fb_fix_screeninfo smtcfb_fix = { + .id = "sm712fb", + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, + .line_length = 800 * 3, + .accel = FB_ACCEL_SMI_LYNX, +}; + +/* chan_to_field + * + * convert a colour value into a field position + * + * from pxafb.c + */ + +static inline unsigned int chan_to_field(unsigned int chan, + struct fb_bitfield *bf) +{ + chan &= 0xffff; + chan >>= 16 - bf->length; + return chan << bf->offset; +} + +static int smtcfb_blank(int blank_mode, struct fb_info *info) +{ + /* clear DPMS setting */ + switch (blank_mode) { + case FB_BLANK_UNBLANK: + /* Screen On: HSync: On, VSync : On */ + smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20))); + smtc_seqw(0x6a, 0x16); + smtc_seqw(0x6b, 0x02); + smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77)); + smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30))); + smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0))); + smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01)); + smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03)); + break; + case FB_BLANK_NORMAL: + /* Screen Off: HSync: On, VSync : On Soft blank */ + smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20))); + smtc_seqw(0x6a, 0x16); + smtc_seqw(0x6b, 0x02); + smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30))); + smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0))); + smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01)); + smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); + break; + case FB_BLANK_VSYNC_SUSPEND: + /* Screen On: HSync: On, VSync : Off */ + smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20)); + smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); + smtc_seqw(0x6a, 0x0c); + smtc_seqw(0x6b, 0x02); + smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88)); + smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20)); + smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20)); + smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); + smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); + smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80)); + break; + case FB_BLANK_HSYNC_SUSPEND: + /* Screen On: HSync: Off, VSync : On */ + smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20)); + smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); + smtc_seqw(0x6a, 0x0c); + smtc_seqw(0x6b, 0x02); + smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88)); + smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10)); + smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8)); + smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); + smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); + smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80)); + break; + case FB_BLANK_POWERDOWN: + /* Screen On: HSync: Off, VSync : Off */ + smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20)); + smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0))); + smtc_seqw(0x6a, 0x0c); + smtc_seqw(0x6b, 0x02); + smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88)); + smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30)); + smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8)); + smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01))); + smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00)); + smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80)); + break; + default: + return -EINVAL; + } + + return 0; +} + +static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned trans, struct fb_info *info) +{ + struct smtcfb_info *sfb = (struct smtcfb_info *)info; + u32 val; + + if (regno > 255) + return 1; + + switch (sfb->fb.fix.visual) { + case FB_VISUAL_DIRECTCOLOR: + case FB_VISUAL_TRUECOLOR: + /* + * 16/32 bit true-colour, use pseuo-palette for 16 base color + */ + if (regno < 16) { + if (sfb->fb.var.bits_per_pixel == 16) { + u32 *pal = sfb->fb.pseudo_palette; + val = chan_to_field(red, &sfb->fb.var.red); + val |= chan_to_field(green, \ + &sfb->fb.var.green); + val |= chan_to_field(blue, &sfb->fb.var.blue); +#ifdef __BIG_ENDIAN + pal[regno] = + ((red & 0xf800) >> 8) | + ((green & 0xe000) >> 13) | + ((green & 0x1c00) << 3) | + ((blue & 0xf800) >> 3); +#else + pal[regno] = val; +#endif + } else { + u32 *pal = sfb->fb.pseudo_palette; + val = chan_to_field(red, &sfb->fb.var.red); + val |= chan_to_field(green, \ + &sfb->fb.var.green); + val |= chan_to_field(blue, &sfb->fb.var.blue); +#ifdef __BIG_ENDIAN + val = + (val & 0xff00ff00 >> 8) | + (val & 0x00ff00ff << 8); +#endif + pal[regno] = val; + } + } + break; + + case FB_VISUAL_PSEUDOCOLOR: + /* color depth 8 bit */ + sm712_setpalette(regno, red, green, blue, info); + break; + + default: + return 1; /* unknown type */ + } + + return 0; + +} + +#ifdef __BIG_ENDIAN +static ssize_t smtcfb_read(struct fb_info *info, char __user * buf, size_t + count, loff_t *ppos) +{ + unsigned long p = *ppos; + + u32 *buffer, *dst; + u32 __iomem *src; + int c, i, cnt = 0, err = 0; + unsigned long total_size; + + if (!info || !info->screen_base) + return -ENODEV; + + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + + total_size = info->screen_size; + + if (total_size == 0) + total_size = info->fix.smem_len; + + if (p >= total_size) + return 0; + + if (count >= total_size) + count = total_size; + + if (count + p > total_size) + count = total_size - p; + + buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + src = (u32 __iomem *) (info->screen_base + p); + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + + while (count) { + c = (count > PAGE_SIZE) ? PAGE_SIZE : count; + dst = buffer; + for (i = c >> 2; i--;) { + *dst = fb_readl(src++); + *dst = + (*dst & 0xff00ff00 >> 8) | + (*dst & 0x00ff00ff << 8); + dst++; + } + if (c & 3) { + u8 *dst8 = (u8 *) dst; + u8 __iomem *src8 = (u8 __iomem *) src; + + for (i = c & 3; i--;) { + if (i & 1) { + *dst8++ = fb_readb(++src8); + } else { + *dst8++ = fb_readb(--src8); + src8 += 2; + } + } + src = (u32 __iomem *) src8; + } + + if (copy_to_user(buf, buffer, c)) { + err = -EFAULT; + break; + } + *ppos += c; + buf += c; + cnt += c; + count -= c; + } + + kfree(buffer); + + return (err) ? err : cnt; +} + +static ssize_t +smtcfb_write(struct fb_info *info, const char __user *buf, size_t count, + loff_t *ppos) +{ + unsigned long p = *ppos; + + u32 *buffer, *src; + u32 __iomem *dst; + int c, i, cnt = 0, err = 0; + unsigned long total_size; + + if (!info || !info->screen_base) + return -ENODEV; + + if (info->state != FBINFO_STATE_RUNNING) + return -EPERM; + + total_size = info->screen_size; + + if (total_size == 0) + total_size = info->fix.smem_len; + + if (p > total_size) + return -EFBIG; + + if (count > total_size) { + err = -EFBIG; + count = total_size; + } + + if (count + p > total_size) { + if (!err) + err = -ENOSPC; + + count = total_size - p; + } + + buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + dst = (u32 __iomem *) (info->screen_base + p); + + if (info->fbops->fb_sync) + info->fbops->fb_sync(info); + + while (count) { + c = (count > PAGE_SIZE) ? PAGE_SIZE : count; + src = buffer; + + if (copy_from_user(src, buf, c)) { + err = -EFAULT; + break; + } + + for (i = c >> 2; i--;) { + fb_writel((*src & 0xff00ff00 >> 8) | + (*src & 0x00ff00ff << 8), dst++); + src++; + } + if (c & 3) { + u8 *src8 = (u8 *) src; + u8 __iomem *dst8 = (u8 __iomem *) dst; + + for (i = c & 3; i--;) { + if (i & 1) { + fb_writeb(*src8++, ++dst8); + } else { + fb_writeb(*src8++, --dst8); + dst8 += 2; + } + } + dst = (u32 __iomem *) dst8; + } + + *ppos += c; + buf += c; + cnt += c; + count -= c; + } + + kfree(buffer); + + return (cnt) ? cnt : err; +} +#endif /* ! __BIG_ENDIAN */ + +#include "smtc2d.c" + +void smtcfb_copyarea(struct fb_info *info, const struct fb_copyarea *area) +{ + struct par_info *p = (struct par_info *)info->par; + + if (smtc_2Dacceleration) { + if (!area->width || !area->height) + return; + + deCopy(p->BaseAddressInVRAM, 0, info->var.bits_per_pixel, + area->dx, area->dy, area->width, area->height, + p->BaseAddressInVRAM, 0, area->sx, area->sy, 0, 0xC); + + } else + cfb_copyarea(info, area); +} + +void smtcfb_fillrect(struct fb_info *info, const struct fb_fillrect *rect) +{ + struct par_info *p = (struct par_info *)info->par; + + if (smtc_2Dacceleration) { + if (!rect->width || !rect->height) + return; + if (info->var.bits_per_pixel >= 24) + deFillRect(p->BaseAddressInVRAM, 0, rect->dx * 3, + rect->dy * 3, rect->width * 3, rect->height, + rect->color); + else + deFillRect(p->BaseAddressInVRAM, 0, rect->dx, rect->dy, + rect->width, rect->height, rect->color); + } else + cfb_fillrect(info, rect); +} + +void smtcfb_imageblit(struct fb_info *info, const struct fb_image *image) +{ + struct par_info *p = (struct par_info *)info->par; + u32 bg_col = 0, fg_col = 0; + + if ((smtc_2Dacceleration) && (image->depth == 1)) { + if (smtc_de_busy) + deWaitForNotBusy(); + + switch (info->var.bits_per_pixel) { + case 8: + bg_col = image->bg_color; + fg_col = image->fg_color; + break; + case 16: + bg_col = + ((u32 *) (info->pseudo_palette))[image->bg_color]; + fg_col = + ((u32 *) (info->pseudo_palette))[image->fg_color]; + break; + case 32: + bg_col = + ((u32 *) (info->pseudo_palette))[image->bg_color]; + fg_col = + ((u32 *) (info->pseudo_palette))[image->fg_color]; + break; + } + + deSystemMem2VideoMemMonoBlt( + image->data, + image->width / 8, + 0, + p->BaseAddressInVRAM, + 0, + 0, + image->dx, image->dy, + image->width, image->height, + fg_col, bg_col, + 0x0C); + + } else + cfb_imageblit(info, image); +} + +static struct fb_ops smtcfb_ops = { + .owner = THIS_MODULE, + .fb_setcolreg = smtc_setcolreg, + .fb_blank = smtcfb_blank, + .fb_fillrect = smtcfb_fillrect, + .fb_imageblit = smtcfb_imageblit, + .fb_copyarea = smtcfb_copyarea, +#ifdef __BIG_ENDIAN + .fb_read = smtcfb_read, + .fb_write = smtcfb_write, +#endif + +}; + +void smtcfb_setmode(struct smtcfb_info *sfb) +{ + switch (sfb->fb.var.bits_per_pixel) { + case 32: + sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; + sfb->fb.fix.line_length = sfb->fb.var.xres * 4; + sfb->fb.var.red.length = 8; + sfb->fb.var.green.length = 8; + sfb->fb.var.blue.length = 8; + sfb->fb.var.red.offset = 16; + sfb->fb.var.green.offset = 8; + sfb->fb.var.blue.offset = 0; + + break; + case 8: + sfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR; + sfb->fb.fix.line_length = sfb->fb.var.xres; + sfb->fb.var.red.offset = 5; + sfb->fb.var.red.length = 3; + sfb->fb.var.green.offset = 2; + sfb->fb.var.green.length = 3; + sfb->fb.var.blue.offset = 0; + sfb->fb.var.blue.length = 2; + break; + case 24: + sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; + sfb->fb.fix.line_length = sfb->fb.var.xres * 3; + sfb->fb.var.red.length = 8; + sfb->fb.var.green.length = 8; + sfb->fb.var.blue.length = 8; + + sfb->fb.var.red.offset = 16; + sfb->fb.var.green.offset = 8; + sfb->fb.var.blue.offset = 0; + + break; + case 16: + default: + sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR; + sfb->fb.fix.line_length = sfb->fb.var.xres * 2; + + sfb->fb.var.red.length = 5; + sfb->fb.var.green.length = 6; + sfb->fb.var.blue.length = 5; + + sfb->fb.var.red.offset = 11; + sfb->fb.var.green.offset = 5; + sfb->fb.var.blue.offset = 0; + + break; + } + + hw.width = sfb->fb.var.xres; + hw.height = sfb->fb.var.yres; + hw.hz = 60; + smtc_set_timing(sfb, &hw); + if (smtc_2Dacceleration) { + printk("2D acceleration enabled!\n"); + /* Init smtc drawing engine */ + deInit(sfb->fb.var.xres, sfb->fb.var.yres, + sfb->fb.var.bits_per_pixel); + } +} + +/* + * Alloc struct smtcfb_info and assign the default value + */ +static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *dev, + char *name) +{ + struct smtcfb_info *sfb; + + sfb = kmalloc(sizeof(struct smtcfb_info), GFP_KERNEL); + + if (!sfb) + return NULL; + + memset(sfb, 0, sizeof(struct smtcfb_info)); + + sfb->currcon = -1; + sfb->dev = dev; + + /*** Init sfb->fb with default value ***/ + sfb->fb.flags = FBINFO_FLAG_DEFAULT; + sfb->fb.fbops = &smtcfb_ops; + sfb->fb.var = smtcfb_var; + sfb->fb.fix = smtcfb_fix; + + strcpy(sfb->fb.fix.id, name); + + sfb->fb.fix.type = FB_TYPE_PACKED_PIXELS; + sfb->fb.fix.type_aux = 0; + sfb->fb.fix.xpanstep = 0; + sfb->fb.fix.ypanstep = 0; + sfb->fb.fix.ywrapstep = 0; + sfb->fb.fix.accel = FB_ACCEL_SMI_LYNX; + + sfb->fb.var.nonstd = 0; + sfb->fb.var.activate = FB_ACTIVATE_NOW; + sfb->fb.var.height = -1; + sfb->fb.var.width = -1; + /* text mode acceleration */ + sfb->fb.var.accel_flags = FB_ACCELF_TEXT; + sfb->fb.var.vmode = FB_VMODE_NONINTERLACED; + sfb->fb.par = &hw; + sfb->fb.pseudo_palette = colreg; + + return sfb; +} + +/* + * Unmap in the memory mapped IO registers + */ + +static void smtc_unmap_mmio(struct smtcfb_info *sfb) +{ + if (sfb && smtc_RegBaseAddress) + smtc_RegBaseAddress = NULL; +} + +/* + * Map in the screen memory + */ + +static int smtc_map_smem(struct smtcfb_info *sfb, + struct pci_dev *dev, u_long smem_len) +{ + if (sfb->fb.var.bits_per_pixel == 32) { +#ifdef __BIG_ENDIAN + sfb->fb.fix.smem_start = pci_resource_start(dev, 0) + + 0x800000; +#else + sfb->fb.fix.smem_start = pci_resource_start(dev, 0); +#endif + } else { + sfb->fb.fix.smem_start = pci_resource_start(dev, 0); + } + + sfb->fb.fix.smem_len = smem_len; + + sfb->fb.screen_base = smtc_VRAMBaseAddress; + + if (!sfb->fb.screen_base) { + printk(KERN_INFO "%s: unable to map screen memory\n", + sfb->fb.fix.id); + return -ENOMEM; + } + + return 0; +} + +/* + * Unmap in the screen memory + * + */ +static void smtc_unmap_smem(struct smtcfb_info *sfb) +{ + if (sfb && sfb->fb.screen_base) { + iounmap(sfb->fb.screen_base); + sfb->fb.screen_base = NULL; + } +} + +/* + * We need to wake up the LynxEM+, and make sure its in linear memory mode. + */ +static inline void sm7xx_init_hw(void) +{ + outb_p(0x18, 0x3c4); + outb_p(0x11, 0x3c5); +} + +static void smtc_free_fb_info(struct smtcfb_info *sfb) +{ + if (sfb) { + fb_alloc_cmap(&sfb->fb.cmap, 0, 0); + kfree(sfb); + } +} + +/* + * sm712vga_setup - process command line options, get vga parameter + * @options: string of options + * Returns zero. + * + */ +static int __init __maybe_unused sm712vga_setup(char *options) +{ + int index; + + if (!options || !*options) { + smdbg("\n No vga parameter\n"); + return -EINVAL; + } + + smtc_screen_info.lfb_width = 0; + smtc_screen_info.lfb_height = 0; + smtc_screen_info.lfb_depth = 0; + + smdbg("\nsm712vga_setup = %s\n", options); + + for (index = 0; + index < (sizeof(vesa_mode) / sizeof(struct vesa_mode_table)); + index++) { + if (strstr(options, vesa_mode[index].mode_index)) { + smtc_screen_info.lfb_width = vesa_mode[index].lfb_width; + smtc_screen_info.lfb_height = + vesa_mode[index].lfb_height; + smtc_screen_info.lfb_depth = vesa_mode[index].lfb_depth; + return 0; + } + } + + return -1; +} +__setup("vga=", sm712vga_setup); + +/* Jason (08/13/2009) + * Original init function changed to probe method to be used by pci_drv + * process used to detect chips replaced with kernel process in pci_drv + */ +static int __init smtcfb_pci_probe(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct smtcfb_info *sfb; + u_long smem_size = 0x00800000; /* default 8MB */ + char name[16]; + int err; + unsigned long pFramebufferPhysical; + + printk(KERN_INFO + "Silicon Motion display driver " SMTC_LINUX_FB_VERSION "\n"); + + err = pci_enable_device(pdev); /* enable SMTC chip */ + + if (err) + return err; + err = -ENOMEM; + + hw.chipID = ent->device; + sprintf(name, "sm%Xfb", hw.chipID); + + sfb = smtc_alloc_fb_info(pdev, name); + + if (!sfb) + goto failed; + /* Jason (08/13/2009) + * Store fb_info to be further used when suspending and resuming + */ + pci_set_drvdata(pdev, sfb); + + sm7xx_init_hw(); + + /*get mode parameter from smtc_screen_info */ + if (smtc_screen_info.lfb_width != 0) { + sfb->fb.var.xres = smtc_screen_info.lfb_width; + sfb->fb.var.yres = smtc_screen_info.lfb_height; + sfb->fb.var.bits_per_pixel = smtc_screen_info.lfb_depth; + } else { + /* default resolution 1024x600 16bit mode */ + sfb->fb.var.xres = SCREEN_X_RES; + sfb->fb.var.yres = SCREEN_Y_RES; + sfb->fb.var.bits_per_pixel = SCREEN_BPP; + } + +#ifdef __BIG_ENDIAN + if (sfb->fb.var.bits_per_pixel == 24) + sfb->fb.var.bits_per_pixel = (smtc_screen_info.lfb_depth = 32); +#endif + /* Map address and memory detection */ + pFramebufferPhysical = pci_resource_start(pdev, 0); + pci_read_config_byte(pdev, PCI_REVISION_ID, &hw.chipRevID); + + switch (hw.chipID) { + case 0x710: + case 0x712: + sfb->fb.fix.mmio_start = pFramebufferPhysical + 0x00400000; + sfb->fb.fix.mmio_len = 0x00400000; + smem_size = SM712_VIDEOMEMORYSIZE; +#ifdef __BIG_ENDIAN + hw.m_pLFB = (smtc_VRAMBaseAddress = + ioremap(pFramebufferPhysical, 0x00c00000)); +#else + hw.m_pLFB = (smtc_VRAMBaseAddress = + ioremap(pFramebufferPhysical, 0x00800000)); +#endif + hw.m_pMMIO = (smtc_RegBaseAddress = + smtc_VRAMBaseAddress + 0x00700000); + smtc_2DBaseAddress = (hw.m_pDPR = + smtc_VRAMBaseAddress + 0x00408000); + smtc_2Ddataport = smtc_VRAMBaseAddress + DE_DATA_PORT_712; + hw.m_pVPR = hw.m_pLFB + 0x0040c000; +#ifdef __BIG_ENDIAN + if (sfb->fb.var.bits_per_pixel == 32) { + smtc_VRAMBaseAddress += 0x800000; + hw.m_pLFB += 0x800000; + printk(KERN_INFO + "\nsmtc_VRAMBaseAddress=%p hw.m_pLFB=%p\n", + smtc_VRAMBaseAddress, hw.m_pLFB); + } +#endif + if (!smtc_RegBaseAddress) { + printk(KERN_INFO + "%s: unable to map memory mapped IO\n", + sfb->fb.fix.id); + return -ENOMEM; + } + + /* set MCLK = 14.31818 * (0x16 / 0x2) */ + smtc_seqw(0x6a, 0x16); + smtc_seqw(0x6b, 0x02); + smtc_seqw(0x62, 0x3e); + /* enable PCI burst */ + smtc_seqw(0x17, 0x20); + /* enable word swap */ +#ifdef __BIG_ENDIAN + if (sfb->fb.var.bits_per_pixel == 32) + smtc_seqw(0x17, 0x30); +#endif +#ifdef CONFIG_FB_SM7XX_ACCEL + smtc_2Dacceleration = 1; +#endif + break; + case 0x720: + sfb->fb.fix.mmio_start = pFramebufferPhysical; + sfb->fb.fix.mmio_len = 0x00200000; + smem_size = SM722_VIDEOMEMORYSIZE; + smtc_2DBaseAddress = (hw.m_pDPR = + ioremap(pFramebufferPhysical, 0x00a00000)); + hw.m_pLFB = (smtc_VRAMBaseAddress = + smtc_2DBaseAddress + 0x00200000); + hw.m_pMMIO = (smtc_RegBaseAddress = + smtc_2DBaseAddress + 0x000c0000); + smtc_2Ddataport = smtc_2DBaseAddress + DE_DATA_PORT_722; + hw.m_pVPR = smtc_2DBaseAddress + 0x800; + + smtc_seqw(0x62, 0xff); + smtc_seqw(0x6a, 0x0d); + smtc_seqw(0x6b, 0x02); + smtc_2Dacceleration = 0; + break; + default: + printk(KERN_INFO + "No valid Silicon Motion display chip was detected!\n"); + + smtc_free_fb_info(sfb); + return err; + } + + /* can support 32 bpp */ + if (15 == sfb->fb.var.bits_per_pixel) + sfb->fb.var.bits_per_pixel = 16; + + sfb->fb.var.xres_virtual = sfb->fb.var.xres; + sfb->fb.var.yres_virtual = sfb->fb.var.yres; + err = smtc_map_smem(sfb, pdev, smem_size); + if (err) + goto failed; + + smtcfb_setmode(sfb); + /* Primary display starting from 0 postion */ + hw.BaseAddressInVRAM = 0; + sfb->fb.par = &hw; + + err = register_framebuffer(&sfb->fb); + if (err < 0) + goto failed; + + printk(KERN_INFO "Silicon Motion SM%X Rev%X primary display mode" + "%dx%d-%d Init Complete.\n", hw.chipID, hw.chipRevID, + sfb->fb.var.xres, sfb->fb.var.yres, + sfb->fb.var.bits_per_pixel); + + return 0; + + failed: + printk(KERN_INFO "Silicon Motion, Inc. primary display init fail\n"); + + smtc_unmap_smem(sfb); + smtc_unmap_mmio(sfb); + smtc_free_fb_info(sfb); + + return err; +} + + +/* Jason (08/11/2009) PCI_DRV wrapper essential structs */ +static struct pci_device_id smtcfb_pci_table[] = { + {0x126f, 0x710, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x126f, 0x712, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0x126f, 0x720, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + {0,} +}; + + +/* Jason (08/14/2009) + * do some clean up when the driver module is removed + */ +static void __devexit smtcfb_pci_remove(struct pci_dev *pdev) +{ + struct smtcfb_info *sfb; + + sfb = pci_get_drvdata(pdev); + pci_set_drvdata(pdev, NULL); + smtc_unmap_smem(sfb); + smtc_unmap_mmio(sfb); + unregister_framebuffer(&sfb->fb); + smtc_free_fb_info(sfb); +} + +/* Jason (08/14/2009) + * suspend function, called when the suspend event is triggered + */ +static int __maybe_unused smtcfb_suspend(struct pci_dev *pdev, pm_message_t msg) +{ + struct smtcfb_info *sfb; + int retv; + + sfb = pci_get_drvdata(pdev); + + /* set the hw in sleep mode use externel clock and self memory refresh + * so that we can turn off internal PLLs later on + */ + smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0)); + smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7)); + + switch (msg.event) { + case PM_EVENT_FREEZE: + case PM_EVENT_PRETHAW: + pdev->dev.power.power_state = msg; + return 0; + } + + /* when doing suspend, call fb apis and pci apis */ + if (msg.event == PM_EVENT_SUSPEND) { + acquire_console_sem(); + fb_set_suspend(&sfb->fb, 1); + release_console_sem(); + retv = pci_save_state(pdev); + pci_disable_device(pdev); + retv = pci_choose_state(pdev, msg); + retv = pci_set_power_state(pdev, retv); + } + + pdev->dev.power.power_state = msg; + + /* additionaly turn off all function blocks including internal PLLs */ + smtc_seqw(0x21, 0xff); + + return 0; +} + +static int __maybe_unused smtcfb_resume(struct pci_dev *pdev) +{ + struct smtcfb_info *sfb; + int retv; + + sfb = pci_get_drvdata(pdev); + + /* when resuming, restore pci data and fb cursor */ + if (pdev->dev.power.power_state.event != PM_EVENT_FREEZE) { + retv = pci_set_power_state(pdev, PCI_D0); + retv = pci_restore_state(pdev); + if (pci_enable_device(pdev)) + return -1; + pci_set_master(pdev); + } + + /* reinit hardware */ + sm7xx_init_hw(); + switch (hw.chipID) { + case 0x710: + case 0x712: + /* set MCLK = 14.31818 * (0x16 / 0x2) */ + smtc_seqw(0x6a, 0x16); + smtc_seqw(0x6b, 0x02); + smtc_seqw(0x62, 0x3e); + /* enable PCI burst */ + smtc_seqw(0x17, 0x20); +#ifdef __BIG_ENDIAN + if (sfb->fb.var.bits_per_pixel == 32) + smtc_seqw(0x17, 0x30); +#endif + break; + case 0x720: + smtc_seqw(0x62, 0xff); + smtc_seqw(0x6a, 0x0d); + smtc_seqw(0x6b, 0x02); + break; + } + + smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0)); + smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb)); + + smtcfb_setmode(sfb); + + acquire_console_sem(); + fb_set_suspend(&sfb->fb, 0); + release_console_sem(); + + return 0; +} + +/* Jason (08/13/2009) + * pci_driver struct used to wrap the original driver + * so that it can be registered into the kernel and + * the proper method would be called when suspending and resuming + */ +static struct pci_driver smtcfb_driver = { + .name = "smtcfb", + .id_table = smtcfb_pci_table, + .probe = smtcfb_pci_probe, + .remove = __devexit_p(smtcfb_pci_remove), +#ifdef CONFIG_PM + .suspend = smtcfb_suspend, + .resume = smtcfb_resume, +#endif +}; + +static int __init smtcfb_init(void) +{ + return pci_register_driver(&smtcfb_driver); +} + +static void __exit smtcfb_exit(void) +{ + pci_unregister_driver(&smtcfb_driver); +} + +module_init(smtcfb_init); +module_exit(smtcfb_exit); + +MODULE_AUTHOR("Siliconmotion "); +MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards"); +MODULE_LICENSE("GPL"); diff --git a/drivers/staging/sm7xx/smtcfb.h b/drivers/staging/sm7xx/smtcfb.h new file mode 100644 index 000000000000..7f2c34138215 --- /dev/null +++ b/drivers/staging/sm7xx/smtcfb.h @@ -0,0 +1,793 @@ +/* + * Silicon Motion SM712 frame buffer device + * + * Copyright (C) 2006 Silicon Motion Technology Corp. + * Authors: Ge Wang, gewang@siliconmotion.com + * Boyod boyod.yang@siliconmotion.com.cn + * + * Copyright (C) 2009 Lemote, Inc. + * Author: Wu Zhangjin, wuzj@lemote.com + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#define SMTC_LINUX_FB_VERSION "version 0.11.2619.21.01 July 27, 2008" + +#define NR_PALETTE 256 +#define NR_RGB 2 + +#define FB_ACCEL_SMI_LYNX 88 + +#ifdef __BIG_ENDIAN +#define PC_VGA 0 +#else +#define PC_VGA 1 +#endif + +#define SCREEN_X_RES 1024 +#define SCREEN_Y_RES 600 +#define SCREEN_BPP 16 + +#ifndef FIELD_OFFSET +#define FIELD_OFSFET(type, field) \ + ((unsigned long) (PUCHAR) & (((type *)0)->field)) +#endif + +/*Assume SM712 graphics chip has 4MB VRAM */ +#define SM712_VIDEOMEMORYSIZE 0x00400000 +/*Assume SM722 graphics chip has 8MB VRAM */ +#define SM722_VIDEOMEMORYSIZE 0x00800000 + +#define dac_reg (0x3c8) +#define dac_val (0x3c9) + +extern char *smtc_RegBaseAddress; +#define smtc_mmiowb(dat, reg) writeb(dat, smtc_RegBaseAddress + reg) +#define smtc_mmioww(dat, reg) writew(dat, smtc_RegBaseAddress + reg) +#define smtc_mmiowl(dat, reg) writel(dat, smtc_RegBaseAddress + reg) + +#define smtc_mmiorb(reg) readb(smtc_RegBaseAddress + reg) +#define smtc_mmiorw(reg) readw(smtc_RegBaseAddress + reg) +#define smtc_mmiorl(reg) readl(smtc_RegBaseAddress + reg) + +#define SIZE_SR00_SR04 (0x04 - 0x00 + 1) +#define SIZE_SR10_SR24 (0x24 - 0x10 + 1) +#define SIZE_SR30_SR75 (0x75 - 0x30 + 1) +#define SIZE_SR80_SR93 (0x93 - 0x80 + 1) +#define SIZE_SRA0_SRAF (0xAF - 0xA0 + 1) +#define SIZE_GR00_GR08 (0x08 - 0x00 + 1) +#define SIZE_AR00_AR14 (0x14 - 0x00 + 1) +#define SIZE_CR00_CR18 (0x18 - 0x00 + 1) +#define SIZE_CR30_CR4D (0x4D - 0x30 + 1) +#define SIZE_CR90_CRA7 (0xA7 - 0x90 + 1) +#define SIZE_VPR (0x6C + 1) +#define SIZE_DPR (0x44 + 1) + +static inline void smtc_crtcw(int reg, int val) +{ + smtc_mmiowb(reg, 0x3d4); + smtc_mmiowb(val, 0x3d5); +} + +static inline unsigned int smtc_crtcr(int reg) +{ + smtc_mmiowb(reg, 0x3d4); + return smtc_mmiorb(0x3d5); +} + +static inline void smtc_grphw(int reg, int val) +{ + smtc_mmiowb(reg, 0x3ce); + smtc_mmiowb(val, 0x3cf); +} + +static inline unsigned int smtc_grphr(int reg) +{ + smtc_mmiowb(reg, 0x3ce); + return smtc_mmiorb(0x3cf); +} + +static inline void smtc_attrw(int reg, int val) +{ + smtc_mmiorb(0x3da); + smtc_mmiowb(reg, 0x3c0); + smtc_mmiorb(0x3c1); + smtc_mmiowb(val, 0x3c0); +} + +static inline void smtc_seqw(int reg, int val) +{ + smtc_mmiowb(reg, 0x3c4); + smtc_mmiowb(val, 0x3c5); +} + +static inline unsigned int smtc_seqr(int reg) +{ + smtc_mmiowb(reg, 0x3c4); + return smtc_mmiorb(0x3c5); +} + +/* The next structure holds all information relevant for a specific video mode. + */ + +struct ModeInit { + int mmSizeX; + int mmSizeY; + int bpp; + int hz; + unsigned char Init_MISC; + unsigned char Init_SR00_SR04[SIZE_SR00_SR04]; + unsigned char Init_SR10_SR24[SIZE_SR10_SR24]; + unsigned char Init_SR30_SR75[SIZE_SR30_SR75]; + unsigned char Init_SR80_SR93[SIZE_SR80_SR93]; + unsigned char Init_SRA0_SRAF[SIZE_SRA0_SRAF]; + unsigned char Init_GR00_GR08[SIZE_GR00_GR08]; + unsigned char Init_AR00_AR14[SIZE_AR00_AR14]; + unsigned char Init_CR00_CR18[SIZE_CR00_CR18]; + unsigned char Init_CR30_CR4D[SIZE_CR30_CR4D]; + unsigned char Init_CR90_CRA7[SIZE_CR90_CRA7]; +}; + +/********************************************************************** + SM712 Mode table. + **********************************************************************/ +struct ModeInit VGAMode[] = { + { + /* mode#0: 640 x 480 16Bpp 60Hz */ + 640, 480, 16, 60, + /* Init_MISC */ + 0xE3, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x00, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, + 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, + 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, + 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, + 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, + 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, + 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, + 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, + }, + { /* Init_CR90_CRA7 */ + 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, + 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, + 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, + }, + }, + { + /* mode#1: 640 x 480 24Bpp 60Hz */ + 640, 480, 24, 60, + /* Init_MISC */ + 0xE3, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x00, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, + 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, + 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, + 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, + 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, + 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, + 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, + 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, + }, + { /* Init_CR90_CRA7 */ + 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, + 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, + 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, + }, + }, + { + /* mode#0: 640 x 480 32Bpp 60Hz */ + 640, 480, 32, 60, + /* Init_MISC */ + 0xE3, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x00, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32, + 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32, + 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA, + 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04, + 0x00, 0x45, 0x30, 0x30, 0x40, 0x30, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32, + 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, + 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E, + 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD, + 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00, + 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF, + }, + { /* Init_CR90_CRA7 */ + 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55, + 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00, + 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00, + }, + }, + + { /* mode#2: 800 x 600 16Bpp 60Hz */ + 800, 600, 16, 60, + /* Init_MISC */ + 0x2B, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x03, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, + 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, + 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, + 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, + 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, + 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, + 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, + 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, + }, + { /* Init_CR90_CRA7 */ + 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, + 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, + 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, + }, + }, + { /* mode#3: 800 x 600 24Bpp 60Hz */ + 800, 600, 24, 60, + 0x2B, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x03, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36, + 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36, + 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, + 0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, + 0x02, 0x45, 0x30, 0x30, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36, + 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, + 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, + 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, + 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, + }, + { /* Init_CR90_CRA7 */ + 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, + 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, + 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, + }, + }, + { /* mode#7: 800 x 600 32Bpp 60Hz */ + 800, 600, 32, 60, + /* Init_MISC */ + 0x2B, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x03, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24, + 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24, + 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58, + 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24, + 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13, + 0x02, 0x45, 0x30, 0x35, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED, + 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD, + 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00, + 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57, + }, + { /* Init_CR90_CRA7 */ + 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA, + 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00, + 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00, + }, + }, + /* We use 1024x768 table to light 1024x600 panel for lemote */ + { /* mode#4: 1024 x 600 16Bpp 60Hz */ + 1024, 600, 16, 60, + /* Init_MISC */ + 0xEB, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x00, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20, + 0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x00, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22, + 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22, + 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, + 0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22, + 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02, + 0x04, 0x45, 0x3F, 0x30, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, + 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, + 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, + 0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00, + 0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57, + }, + { /* Init_CR90_CRA7 */ + 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, + 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, + }, + }, + { /* mode#5: 1024 x 768 24Bpp 60Hz */ + 1024, 768, 24, 60, + /* Init_MISC */ + 0xEB, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x03, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x30, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, + 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, + 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, + 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, + 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, + 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, + 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, + 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, + 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, + }, + { /* Init_CR90_CRA7 */ + 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, + 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, + }, + }, + { /* mode#4: 1024 x 768 32Bpp 60Hz */ + 1024, 768, 32, 60, + /* Init_MISC */ + 0xEB, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x03, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x32, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, + 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, + 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, + 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02, + 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, + 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, + 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, + 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF, + 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00, + 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF, + }, + { /* Init_CR90_CRA7 */ + 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, + 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, + }, + }, + { /* mode#6: 320 x 240 16Bpp 60Hz */ + 320, 240, 16, 60, + /* Init_MISC */ + 0xEB, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x03, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x32, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, + 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, + 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, + 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, + 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, + 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, + 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, + 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, + 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, + 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, + }, + { /* Init_CR90_CRA7 */ + 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, + 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, + }, + }, + + { /* mode#8: 320 x 240 32Bpp 60Hz */ + 320, 240, 32, 60, + /* Init_MISC */ + 0xEB, + { /* Init_SR0_SR4 */ + 0x03, 0x01, 0x0F, 0x03, 0x0E, + }, + { /* Init_SR10_SR24 */ + 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C, + 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xC4, 0x32, 0x02, 0x01, 0x01, + }, + { /* Init_SR30_SR75 */ + 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A, + 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF, + 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC, + 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A, + 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03, + 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A, + 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00, + 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43, + 0x04, 0x45, 0x30, 0x30, 0x40, 0x20, + }, + { /* Init_SR80_SR93 */ + 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A, + 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A, + 0x00, 0x00, 0x00, 0x00, + }, + { /* Init_SRA0_SRAF */ + 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED, + 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF, + }, + { /* Init_GR00_GR08 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, + 0xFF, + }, + { /* Init_AR00_AR14 */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x41, 0x00, 0x0F, 0x00, 0x00, + }, + { /* Init_CR00_CR18 */ + 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5, + 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3, + 0xFF, + }, + { /* Init_CR30_CR4D */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20, + 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF, + 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00, + 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF, + }, + { /* Init_CR90_CRA7 */ + 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26, + 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03, + }, + }, +}; + +#define numVGAModes (sizeof(VGAMode) / sizeof(struct ModeInit)) From 29d249ed80c80b479df78e456e6809223c648505 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 18 Dec 2009 09:59:48 -0800 Subject: [PATCH 03/19] Staging: dst: remove from the tree DST is dead, no one is using it and upstream has abandoned it, so remove it from the tree because it is not going anywhere. Acked-by: Evgeniy Polyakov Signed-off-by: Greg Kroah-Hartman --- drivers/staging/Kconfig | 2 - drivers/staging/Makefile | 1 - drivers/staging/dst/Kconfig | 67 --- drivers/staging/dst/Makefile | 3 - drivers/staging/dst/crypto.c | 733 ---------------------- drivers/staging/dst/dcore.c | 968 ------------------------------ drivers/staging/dst/export.c | 660 -------------------- drivers/staging/dst/state.c | 844 -------------------------- drivers/staging/dst/thread_pool.c | 348 ----------- drivers/staging/dst/trans.c | 337 ----------- include/linux/dst.h | 587 ------------------ 11 files changed, 4550 deletions(-) delete mode 100644 drivers/staging/dst/Kconfig delete mode 100644 drivers/staging/dst/Makefile delete mode 100644 drivers/staging/dst/crypto.c delete mode 100644 drivers/staging/dst/dcore.c delete mode 100644 drivers/staging/dst/export.c delete mode 100644 drivers/staging/dst/state.c delete mode 100644 drivers/staging/dst/thread_pool.c delete mode 100644 drivers/staging/dst/trans.c delete mode 100644 include/linux/dst.h diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig index db0de940949e..94eb86319ff3 100644 --- a/drivers/staging/Kconfig +++ b/drivers/staging/Kconfig @@ -87,8 +87,6 @@ source "drivers/staging/frontier/Kconfig" source "drivers/staging/dream/Kconfig" -source "drivers/staging/dst/Kconfig" - source "drivers/staging/pohmelfs/Kconfig" source "drivers/staging/b3dfg/Kconfig" diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile index 73c6a71155e0..b5e67b889f60 100644 --- a/drivers/staging/Makefile +++ b/drivers/staging/Makefile @@ -26,7 +26,6 @@ obj-$(CONFIG_RTL8192E) += rtl8192e/ obj-$(CONFIG_INPUT_MIMIO) += mimio/ obj-$(CONFIG_TRANZPORT) += frontier/ obj-$(CONFIG_DREAM) += dream/ -obj-$(CONFIG_DST) += dst/ obj-$(CONFIG_POHMELFS) += pohmelfs/ obj-$(CONFIG_B3DFG) += b3dfg/ obj-$(CONFIG_IDE_PHISON) += phison/ diff --git a/drivers/staging/dst/Kconfig b/drivers/staging/dst/Kconfig deleted file mode 100644 index 448d342ac2a2..000000000000 --- a/drivers/staging/dst/Kconfig +++ /dev/null @@ -1,67 +0,0 @@ -config DST - tristate "Distributed storage" - depends on NET && CRYPTO && SYSFS && BLK_DEV - select CONNECTOR - ---help--- - DST is a network block device storage, which can be used to organize - exported storage on the remote nodes into the local block device. - - DST works on top of any network media and protocol; it is just a matter - of configuration utility to understand the correct addresses. The most - common example is TCP over IP, which allows to pass through firewalls and - create remote backup storage in a different datacenter. DST requires - single port to be enabled on the exporting node and outgoing connections - on the local node. - - DST works with in-kernel client and server, which improves performance by - eliminating unneded data copies and by not depending on the version - of the external IO components. It requires userspace configuration utility - though. - - DST uses transaction model, when each store has to be explicitly acked - from the remote node to be considered as successfully written. There - may be lots of in-flight transactions. When remote host does not ack - the transaction it will be resent predefined number of times with specified - timeouts between them. All those parameters are configurable. Transactions - are marked as failed after all resends complete unsuccessfully; having - long enough resend timeout and/or large number of resends allows not to - return error to the higher (FS usually) layer in case of short network - problems or remote node outages. In case of network RAID setup this means - that storage will not degrade until transactions are marked as failed, and - thus will not force checksum recalculation and data rebuild. In case of - connection failure DST will try to reconnect to the remote node automatically. - DST sends ping commands at idle time to detect if remote node is alive. - - Because of transactional model it is possible to use zero-copy sending - without worry of data corruption (which in turn could be detected by the - strong checksums though). - - DST may fully encrypt the data channel in case of untrusted channel and implement - strong checksum of the transferred data. It is possible to configure algorithms - and crypto keys; they should match on both sides of the network channel. - Crypto processing does not introduce noticeble performance overhead, since DST - uses configurable pool of threads to perform crypto processing. - - DST utilizes memory pool model of all its transaction allocations (it is the - only additional allocation on the client) and server allocations (bio pools, - while pages are allocated from the slab). - - At startup DST performs a simple negotiation with the export node to determine - access permissions and size of the exported storage. It can be extended if - new parameters should be autonegotiated. - - DST carries block IO flags in the protocol, which allows to transparently implement - barriers and sync/flush operations. Those flags are used in the export node where - IO against the local storage is performed, which means that sync write will be sync - on the remote node too, which in turn improves data integrity and improved resistance - to errors and data corruption during power outages or storage damages. - - Homepage: http://www.ioremap.net/projects/dst - Userspace configuration utility and the latest releases: http://www.ioremap.net/archive/dst/ - -config DST_DEBUG - bool "DST debug" - depends on DST - ---help--- - This option will enable HEAVY debugging of the DST. - Turn it on ONLY if you have to debug some really obscure problem. diff --git a/drivers/staging/dst/Makefile b/drivers/staging/dst/Makefile deleted file mode 100644 index 3a8b0cf9643e..000000000000 --- a/drivers/staging/dst/Makefile +++ /dev/null @@ -1,3 +0,0 @@ -obj-$(CONFIG_DST) += nst.o - -nst-y := dcore.o state.o export.o thread_pool.o crypto.o trans.o diff --git a/drivers/staging/dst/crypto.c b/drivers/staging/dst/crypto.c deleted file mode 100644 index 351295c97a4b..000000000000 --- a/drivers/staging/dst/crypto.c +++ /dev/null @@ -1,733 +0,0 @@ -/* - * 2007+ Copyright (c) Evgeniy Polyakov - * All rights reserved. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include - -/* - * Tricky bastard, but IV can be more complex with time... - */ -static inline u64 dst_gen_iv(struct dst_trans *t) -{ - return t->gen; -} - -/* - * Crypto machinery: hash/cipher support for the given crypto controls. - */ -static struct crypto_hash *dst_init_hash(struct dst_crypto_ctl *ctl, u8 *key) -{ - int err; - struct crypto_hash *hash; - - hash = crypto_alloc_hash(ctl->hash_algo, 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(hash)) { - err = PTR_ERR(hash); - dprintk("%s: failed to allocate hash '%s', err: %d.\n", - __func__, ctl->hash_algo, err); - goto err_out_exit; - } - - ctl->crypto_attached_size = crypto_hash_digestsize(hash); - - if (!ctl->hash_keysize) - return hash; - - err = crypto_hash_setkey(hash, key, ctl->hash_keysize); - if (err) { - dprintk("%s: failed to set key for hash '%s', err: %d.\n", - __func__, ctl->hash_algo, err); - goto err_out_free; - } - - return hash; - -err_out_free: - crypto_free_hash(hash); -err_out_exit: - return ERR_PTR(err); -} - -static struct crypto_ablkcipher *dst_init_cipher(struct dst_crypto_ctl *ctl, - u8 *key) -{ - int err = -EINVAL; - struct crypto_ablkcipher *cipher; - - if (!ctl->cipher_keysize) - goto err_out_exit; - - cipher = crypto_alloc_ablkcipher(ctl->cipher_algo, 0, 0); - if (IS_ERR(cipher)) { - err = PTR_ERR(cipher); - dprintk("%s: failed to allocate cipher '%s', err: %d.\n", - __func__, ctl->cipher_algo, err); - goto err_out_exit; - } - - crypto_ablkcipher_clear_flags(cipher, ~0); - - err = crypto_ablkcipher_setkey(cipher, key, ctl->cipher_keysize); - if (err) { - dprintk("%s: failed to set key for cipher '%s', err: %d.\n", - __func__, ctl->cipher_algo, err); - goto err_out_free; - } - - return cipher; - -err_out_free: - crypto_free_ablkcipher(cipher); -err_out_exit: - return ERR_PTR(err); -} - -/* - * Crypto engine has a pool of pages to encrypt data into before sending - * it over the network. This pool is freed/allocated here. - */ -static void dst_crypto_pages_free(struct dst_crypto_engine *e) -{ - unsigned int i; - - for (i = 0; i < e->page_num; ++i) - __free_page(e->pages[i]); - kfree(e->pages); -} - -static int dst_crypto_pages_alloc(struct dst_crypto_engine *e, int num) -{ - int i; - - e->pages = kmalloc(num * sizeof(struct page **), GFP_KERNEL); - if (!e->pages) - return -ENOMEM; - - for (i = 0; i < num; ++i) { - e->pages[i] = alloc_page(GFP_KERNEL); - if (!e->pages[i]) - goto err_out_free_pages; - } - - e->page_num = num; - return 0; - -err_out_free_pages: - while (--i >= 0) - __free_page(e->pages[i]); - - kfree(e->pages); - return -ENOMEM; -} - -/* - * Initialize crypto engine for given node. - * Setup cipher/hash, keys, pool of threads and private data. - */ -static int dst_crypto_engine_init(struct dst_crypto_engine *e, - struct dst_node *n) -{ - int err; - struct dst_crypto_ctl *ctl = &n->crypto; - - err = dst_crypto_pages_alloc(e, n->max_pages); - if (err) - goto err_out_exit; - - e->size = PAGE_SIZE; - e->data = kmalloc(e->size, GFP_KERNEL); - if (!e->data) { - err = -ENOMEM; - goto err_out_free_pages; - } - - if (ctl->hash_algo[0]) { - e->hash = dst_init_hash(ctl, n->hash_key); - if (IS_ERR(e->hash)) { - err = PTR_ERR(e->hash); - e->hash = NULL; - goto err_out_free; - } - } - - if (ctl->cipher_algo[0]) { - e->cipher = dst_init_cipher(ctl, n->cipher_key); - if (IS_ERR(e->cipher)) { - err = PTR_ERR(e->cipher); - e->cipher = NULL; - goto err_out_free_hash; - } - } - - return 0; - -err_out_free_hash: - crypto_free_hash(e->hash); -err_out_free: - kfree(e->data); -err_out_free_pages: - dst_crypto_pages_free(e); -err_out_exit: - return err; -} - -static void dst_crypto_engine_exit(struct dst_crypto_engine *e) -{ - if (e->hash) - crypto_free_hash(e->hash); - if (e->cipher) - crypto_free_ablkcipher(e->cipher); - dst_crypto_pages_free(e); - kfree(e->data); -} - -/* - * Waiting for cipher processing to be completed. - */ -struct dst_crypto_completion { - struct completion complete; - int error; -}; - -static void dst_crypto_complete(struct crypto_async_request *req, int err) -{ - struct dst_crypto_completion *c = req->data; - - if (err == -EINPROGRESS) - return; - - dprintk("%s: req: %p, err: %d.\n", __func__, req, err); - c->error = err; - complete(&c->complete); -} - -static int dst_crypto_process(struct ablkcipher_request *req, - struct scatterlist *sg_dst, struct scatterlist *sg_src, - void *iv, int enc, unsigned long timeout) -{ - struct dst_crypto_completion c; - int err; - - init_completion(&c.complete); - c.error = -EINPROGRESS; - - ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, - dst_crypto_complete, &c); - - ablkcipher_request_set_crypt(req, sg_src, sg_dst, sg_src->length, iv); - - if (enc) - err = crypto_ablkcipher_encrypt(req); - else - err = crypto_ablkcipher_decrypt(req); - - switch (err) { - case -EINPROGRESS: - case -EBUSY: - err = wait_for_completion_interruptible_timeout(&c.complete, - timeout); - if (!err) - err = -ETIMEDOUT; - else - err = c.error; - break; - default: - break; - } - - return err; -} - -/* - * DST uses generic iteration approach for data crypto processing. - * Single block IO request is switched into array of scatterlists, - * which are submitted to the crypto processing iterator. - * - * Input and output iterator initialization are different, since - * in output case we can not encrypt data in-place and need a - * temporary storage, which is then being sent to the remote peer. - */ -static int dst_trans_iter_out(struct bio *bio, struct dst_crypto_engine *e, - int (*iterator) (struct dst_crypto_engine *e, - struct scatterlist *dst, - struct scatterlist *src)) -{ - struct bio_vec *bv; - int err, i; - - sg_init_table(e->src, bio->bi_vcnt); - sg_init_table(e->dst, bio->bi_vcnt); - - bio_for_each_segment(bv, bio, i) { - sg_set_page(&e->src[i], bv->bv_page, bv->bv_len, bv->bv_offset); - sg_set_page(&e->dst[i], e->pages[i], bv->bv_len, bv->bv_offset); - - err = iterator(e, &e->dst[i], &e->src[i]); - if (err) - return err; - } - - return 0; -} - -static int dst_trans_iter_in(struct bio *bio, struct dst_crypto_engine *e, - int (*iterator) (struct dst_crypto_engine *e, - struct scatterlist *dst, - struct scatterlist *src)) -{ - struct bio_vec *bv; - int err, i; - - sg_init_table(e->src, bio->bi_vcnt); - sg_init_table(e->dst, bio->bi_vcnt); - - bio_for_each_segment(bv, bio, i) { - sg_set_page(&e->src[i], bv->bv_page, bv->bv_len, bv->bv_offset); - sg_set_page(&e->dst[i], bv->bv_page, bv->bv_len, bv->bv_offset); - - err = iterator(e, &e->dst[i], &e->src[i]); - if (err) - return err; - } - - return 0; -} - -static int dst_crypt_iterator(struct dst_crypto_engine *e, - struct scatterlist *sg_dst, struct scatterlist *sg_src) -{ - struct ablkcipher_request *req = e->data; - u8 iv[32]; - - memset(iv, 0, sizeof(iv)); - - memcpy(iv, &e->iv, sizeof(e->iv)); - - return dst_crypto_process(req, sg_dst, sg_src, iv, e->enc, e->timeout); -} - -static int dst_crypt(struct dst_crypto_engine *e, struct bio *bio) -{ - struct ablkcipher_request *req = e->data; - - memset(req, 0, sizeof(struct ablkcipher_request)); - ablkcipher_request_set_tfm(req, e->cipher); - - if (e->enc) - return dst_trans_iter_out(bio, e, dst_crypt_iterator); - else - return dst_trans_iter_in(bio, e, dst_crypt_iterator); -} - -static int dst_hash_iterator(struct dst_crypto_engine *e, - struct scatterlist *sg_dst, struct scatterlist *sg_src) -{ - return crypto_hash_update(e->data, sg_src, sg_src->length); -} - -static int dst_hash(struct dst_crypto_engine *e, struct bio *bio, void *dst) -{ - struct hash_desc *desc = e->data; - int err; - - desc->tfm = e->hash; - desc->flags = 0; - - err = crypto_hash_init(desc); - if (err) - return err; - - err = dst_trans_iter_in(bio, e, dst_hash_iterator); - if (err) - return err; - - err = crypto_hash_final(desc, dst); - if (err) - return err; - - return 0; -} - -/* - * Initialize/cleanup a crypto thread. The only thing it should - * do is to allocate a pool of pages as temporary storage. - * And to setup cipher and/or hash. - */ -static void *dst_crypto_thread_init(void *data) -{ - struct dst_node *n = data; - struct dst_crypto_engine *e; - int err = -ENOMEM; - - e = kzalloc(sizeof(struct dst_crypto_engine), GFP_KERNEL); - if (!e) - goto err_out_exit; - e->src = kcalloc(2 * n->max_pages, sizeof(struct scatterlist), - GFP_KERNEL); - if (!e->src) - goto err_out_free; - - e->dst = e->src + n->max_pages; - - err = dst_crypto_engine_init(e, n); - if (err) - goto err_out_free_all; - - return e; - -err_out_free_all: - kfree(e->src); -err_out_free: - kfree(e); -err_out_exit: - return ERR_PTR(err); -} - -static void dst_crypto_thread_cleanup(void *private) -{ - struct dst_crypto_engine *e = private; - - dst_crypto_engine_exit(e); - kfree(e->src); - kfree(e); -} - -/* - * Initialize crypto engine for given node: store keys, create pool - * of threads, initialize each one. - * - * Each thread has unique ID, but 0 and 1 are reserved for receiving and - * accepting threads (if export node), so IDs could start from 2, but starting - * them from 10 allows easily understand what this thread is for. - */ -int dst_node_crypto_init(struct dst_node *n, struct dst_crypto_ctl *ctl) -{ - void *key = (ctl + 1); - int err = -ENOMEM, i; - char name[32]; - - if (ctl->hash_keysize) { - n->hash_key = kmalloc(ctl->hash_keysize, GFP_KERNEL); - if (!n->hash_key) - goto err_out_exit; - memcpy(n->hash_key, key, ctl->hash_keysize); - } - - if (ctl->cipher_keysize) { - n->cipher_key = kmalloc(ctl->cipher_keysize, GFP_KERNEL); - if (!n->cipher_key) - goto err_out_free_hash; - memcpy(n->cipher_key, key, ctl->cipher_keysize); - } - memcpy(&n->crypto, ctl, sizeof(struct dst_crypto_ctl)); - - for (i = 0; i < ctl->thread_num; ++i) { - snprintf(name, sizeof(name), "%s-crypto-%d", n->name, i); - /* Unique ids... */ - err = thread_pool_add_worker(n->pool, name, i + 10, - dst_crypto_thread_init, dst_crypto_thread_cleanup, n); - if (err) - goto err_out_free_threads; - } - - return 0; - -err_out_free_threads: - while (--i >= 0) - thread_pool_del_worker_id(n->pool, i+10); - - if (ctl->cipher_keysize) - kfree(n->cipher_key); - ctl->cipher_keysize = 0; -err_out_free_hash: - if (ctl->hash_keysize) - kfree(n->hash_key); - ctl->hash_keysize = 0; -err_out_exit: - return err; -} - -void dst_node_crypto_exit(struct dst_node *n) -{ - struct dst_crypto_ctl *ctl = &n->crypto; - - if (ctl->cipher_algo[0] || ctl->hash_algo[0]) { - kfree(n->hash_key); - kfree(n->cipher_key); - } -} - -/* - * Thrad pool setup callback. Just stores a transaction in private data. - */ -static int dst_trans_crypto_setup(void *crypto_engine, void *trans) -{ - struct dst_crypto_engine *e = crypto_engine; - - e->private = trans; - return 0; -} - -#if 0 -static void dst_dump_bio(struct bio *bio) -{ - u8 *p; - struct bio_vec *bv; - int i; - - bio_for_each_segment(bv, bio, i) { - dprintk("%s: %llu/%u: size: %u, offset: %u, data: ", - __func__, bio->bi_sector, bio->bi_size, - bv->bv_len, bv->bv_offset); - - p = kmap(bv->bv_page) + bv->bv_offset; - for (i = 0; i < bv->bv_len; ++i) - printk(KERN_DEBUG "%02x ", p[i]); - kunmap(bv->bv_page); - printk("\n"); - } -} -#endif - -/* - * Encrypt/hash data and send it to the network. - */ -static int dst_crypto_process_sending(struct dst_crypto_engine *e, - struct bio *bio, u8 *hash) -{ - int err; - - if (e->cipher) { - err = dst_crypt(e, bio); - if (err) - goto err_out_exit; - } - - if (e->hash) { - err = dst_hash(e, bio, hash); - if (err) - goto err_out_exit; - -#ifdef CONFIG_DST_DEBUG - { - unsigned int i; - - /* dst_dump_bio(bio); */ - - printk(KERN_DEBUG "%s: bio: %llu/%u, rw: %lu, hash: ", - __func__, (u64)bio->bi_sector, - bio->bi_size, bio_data_dir(bio)); - for (i = 0; i < crypto_hash_digestsize(e->hash); ++i) - printk("%02x ", hash[i]); - printk("\n"); - } -#endif - } - - return 0; - -err_out_exit: - return err; -} - -/* - * Check if received data is valid. Decipher if it is. - */ -static int dst_crypto_process_receiving(struct dst_crypto_engine *e, - struct bio *bio, u8 *hash, u8 *recv_hash) -{ - int err; - - if (e->hash) { - int mismatch; - - err = dst_hash(e, bio, hash); - if (err) - goto err_out_exit; - - mismatch = !!memcmp(recv_hash, hash, - crypto_hash_digestsize(e->hash)); -#ifdef CONFIG_DST_DEBUG - /* dst_dump_bio(bio); */ - - printk(KERN_DEBUG "%s: bio: %llu/%u, rw: %lu, hash mismatch: %d", - __func__, (u64)bio->bi_sector, bio->bi_size, - bio_data_dir(bio), mismatch); - if (mismatch) { - unsigned int i; - - printk(", recv/calc: "); - for (i = 0; i < crypto_hash_digestsize(e->hash); ++i) - printk("%02x/%02x ", recv_hash[i], hash[i]); - - } - printk("\n"); -#endif - err = -1; - if (mismatch) - goto err_out_exit; - } - - if (e->cipher) { - err = dst_crypt(e, bio); - if (err) - goto err_out_exit; - } - - return 0; - -err_out_exit: - return err; -} - -/* - * Thread pool callback to encrypt data and send it to the netowork. - */ -static int dst_trans_crypto_action(void *crypto_engine, void *schedule_data) -{ - struct dst_crypto_engine *e = crypto_engine; - struct dst_trans *t = schedule_data; - struct bio *bio = t->bio; - int err; - - dprintk("%s: t: %p, gen: %llu, cipher: %p, hash: %p.\n", - __func__, t, t->gen, e->cipher, e->hash); - - e->enc = t->enc; - e->iv = dst_gen_iv(t); - - if (bio_data_dir(bio) == WRITE) { - err = dst_crypto_process_sending(e, bio, t->cmd.hash); - if (err) - goto err_out_exit; - - if (e->hash) { - t->cmd.csize = crypto_hash_digestsize(e->hash); - t->cmd.size += t->cmd.csize; - } - - return dst_trans_send(t); - } else { - u8 *hash = e->data + e->size/2; - - err = dst_crypto_process_receiving(e, bio, hash, t->cmd.hash); - if (err) - goto err_out_exit; - - dst_trans_remove(t); - dst_trans_put(t); - } - - return 0; - -err_out_exit: - t->error = err; - dst_trans_put(t); - return err; -} - -/* - * Schedule crypto processing for given transaction. - */ -int dst_trans_crypto(struct dst_trans *t) -{ - struct dst_node *n = t->n; - int err; - - err = thread_pool_schedule(n->pool, - dst_trans_crypto_setup, dst_trans_crypto_action, - t, MAX_SCHEDULE_TIMEOUT); - if (err) - goto err_out_exit; - - return 0; - -err_out_exit: - dst_trans_put(t); - return err; -} - -/* - * Crypto machinery for the export node. - */ -static int dst_export_crypto_setup(void *crypto_engine, void *bio) -{ - struct dst_crypto_engine *e = crypto_engine; - - e->private = bio; - return 0; -} - -static int dst_export_crypto_action(void *crypto_engine, void *schedule_data) -{ - struct dst_crypto_engine *e = crypto_engine; - struct bio *bio = schedule_data; - struct dst_export_priv *p = bio->bi_private; - int err; - - dprintk("%s: e: %p, data: %p, bio: %llu/%u, dir: %lu.\n", - __func__, e, e->data, (u64)bio->bi_sector, - bio->bi_size, bio_data_dir(bio)); - - e->enc = (bio_data_dir(bio) == READ); - e->iv = p->cmd.id; - - if (bio_data_dir(bio) == WRITE) { - u8 *hash = e->data + e->size/2; - - err = dst_crypto_process_receiving(e, bio, hash, p->cmd.hash); - if (err) - goto err_out_exit; - - generic_make_request(bio); - } else { - err = dst_crypto_process_sending(e, bio, p->cmd.hash); - if (err) - goto err_out_exit; - - if (e->hash) { - p->cmd.csize = crypto_hash_digestsize(e->hash); - p->cmd.size += p->cmd.csize; - } - - err = dst_export_send_bio(bio); - } - return 0; - -err_out_exit: - bio_put(bio); - return err; -} - -int dst_export_crypto(struct dst_node *n, struct bio *bio) -{ - int err; - - err = thread_pool_schedule(n->pool, - dst_export_crypto_setup, dst_export_crypto_action, - bio, MAX_SCHEDULE_TIMEOUT); - if (err) - goto err_out_exit; - - return 0; - -err_out_exit: - bio_put(bio); - return err; -} diff --git a/drivers/staging/dst/dcore.c b/drivers/staging/dst/dcore.c deleted file mode 100644 index c83ca7e3d048..000000000000 --- a/drivers/staging/dst/dcore.c +++ /dev/null @@ -1,968 +0,0 @@ -/* - * 2007+ Copyright (c) Evgeniy Polyakov - * All rights reserved. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include - -static int dst_major; - -static DEFINE_MUTEX(dst_hash_lock); -static struct list_head *dst_hashtable; -static unsigned int dst_hashtable_size = 128; -module_param(dst_hashtable_size, uint, 0644); - -static char dst_name[] = "Dementianting goldfish"; - -static DEFINE_IDR(dst_index_idr); -static struct cb_id cn_dst_id = { CN_DST_IDX, CN_DST_VAL }; - -/* - * DST sysfs tree for device called 'storage': - * - * /sys/bus/dst/devices/storage/ - * /sys/bus/dst/devices/storage/type : 192.168.4.80:1025 - * /sys/bus/dst/devices/storage/size : 800 - * /sys/bus/dst/devices/storage/name : storage - */ - -static int dst_dev_match(struct device *dev, struct device_driver *drv) -{ - return 1; -} - -static struct bus_type dst_dev_bus_type = { - .name = "dst", - .match = &dst_dev_match, -}; - -static void dst_node_release(struct device *dev) -{ - struct dst_info *info = container_of(dev, struct dst_info, device); - - kfree(info); -} - -static struct device dst_node_dev = { - .bus = &dst_dev_bus_type, - .release = &dst_node_release -}; - -/* - * Setting size of the node after it was changed. - */ -static void dst_node_set_size(struct dst_node *n) -{ - struct block_device *bdev; - - set_capacity(n->disk, n->size >> 9); - - bdev = bdget_disk(n->disk, 0); - if (bdev) { - mutex_lock(&bdev->bd_inode->i_mutex); - i_size_write(bdev->bd_inode, n->size); - mutex_unlock(&bdev->bd_inode->i_mutex); - bdput(bdev); - } -} - -/* - * Distributed storage request processing function. - */ -static int dst_request(struct request_queue *q, struct bio *bio) -{ - struct dst_node *n = q->queuedata; - int err = -EIO; - - if (bio_empty_barrier(bio) && !blk_queue_discard(q)) { - /* - * This is a dirty^Wnice hack, but if we complete this - * operation with -EOPNOTSUPP like intended, XFS - * will stuck and freeze the machine. This may be - * not particulary XFS problem though, but it is the - * only FS which sends empty barrier at umount time - * I worked with. - * - * Empty barriers are not allowed anyway, see 51fd77bd9f512 - * for example, although later it was changed to - * bio_rw_flagged(bio, BIO_RW_DISCARD) only, which does not - * work in this case. - */ - /* err = -EOPNOTSUPP; */ - err = 0; - goto end_io; - } - - bio_get(bio); - - return dst_process_bio(n, bio); - -end_io: - bio_endio(bio, err); - return err; -} - -/* - * Open/close callbacks for appropriate block device. - */ -static int dst_bdev_open(struct block_device *bdev, fmode_t mode) -{ - struct dst_node *n = bdev->bd_disk->private_data; - - dst_node_get(n); - return 0; -} - -static int dst_bdev_release(struct gendisk *disk, fmode_t mode) -{ - struct dst_node *n = disk->private_data; - - dst_node_put(n); - return 0; -} - -static struct block_device_operations dst_blk_ops = { - .open = dst_bdev_open, - .release = dst_bdev_release, - .owner = THIS_MODULE, -}; - -/* - * Block layer binding - disk is created when array is fully configured - * by userspace request. - */ -static int dst_node_create_disk(struct dst_node *n) -{ - int err = -ENOMEM; - u32 index = 0; - - n->queue = blk_init_queue(NULL, NULL); - if (!n->queue) - goto err_out_exit; - - n->queue->queuedata = n; - blk_queue_make_request(n->queue, dst_request); - blk_queue_max_phys_segments(n->queue, n->max_pages); - blk_queue_max_hw_segments(n->queue, n->max_pages); - - err = -ENOMEM; - n->disk = alloc_disk(1); - if (!n->disk) - goto err_out_free_queue; - - if (!(n->state->permissions & DST_PERM_WRITE)) { - printk(KERN_INFO "DST node %s attached read-only.\n", n->name); - set_disk_ro(n->disk, 1); - } - - if (!idr_pre_get(&dst_index_idr, GFP_KERNEL)) - goto err_out_put; - - mutex_lock(&dst_hash_lock); - err = idr_get_new(&dst_index_idr, NULL, &index); - mutex_unlock(&dst_hash_lock); - if (err) - goto err_out_put; - - n->disk->major = dst_major; - n->disk->first_minor = index; - n->disk->fops = &dst_blk_ops; - n->disk->queue = n->queue; - n->disk->private_data = n; - snprintf(n->disk->disk_name, sizeof(n->disk->disk_name), - "dst-%s", n->name); - - return 0; - -err_out_put: - put_disk(n->disk); -err_out_free_queue: - blk_cleanup_queue(n->queue); -err_out_exit: - return err; -} - -/* - * Sysfs machinery: show device's size. - */ -static ssize_t dst_show_size(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct dst_info *info = container_of(dev, struct dst_info, device); - - return sprintf(buf, "%llu\n", info->size); -} - -/* - * Show local exported device. - */ -static ssize_t dst_show_local(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct dst_info *info = container_of(dev, struct dst_info, device); - - return sprintf(buf, "%s\n", info->local); -} - -/* - * Shows type of the remote node - device major/minor number - * for local nodes and address (af_inet ipv4/ipv6 only) for remote nodes. - */ -static ssize_t dst_show_type(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct dst_info *info = container_of(dev, struct dst_info, device); - int family = info->net.addr.sa_family; - - if (family == AF_INET) { - struct sockaddr_in *sin = (struct sockaddr_in *)&info->net.addr; - return sprintf(buf, "%u.%u.%u.%u:%d\n", - NIPQUAD(sin->sin_addr.s_addr), ntohs(sin->sin_port)); - } else if (family == AF_INET6) { - struct sockaddr_in6 *sin = (struct sockaddr_in6 *) - &info->net.addr; - return sprintf(buf, - "%pi6:%d\n", - &sin->sin6_addr, ntohs(sin->sin6_port)); - } else { - int i, sz = PAGE_SIZE - 2; /* 0 symbol and '\n' below */ - int size, addrlen = info->net.addr.sa_data_len; - unsigned char *a = (unsigned char *)&info->net.addr.sa_data; - char *buf_orig = buf; - - size = snprintf(buf, sz, "family: %d, addrlen: %u, addr: ", - family, addrlen); - sz -= size; - buf += size; - - for (i = 0; i < addrlen; ++i) { - if (sz < 3) - break; - - size = snprintf(buf, sz, "%02x ", a[i]); - sz -= size; - buf += size; - } - buf += sprintf(buf, "\n"); - - return buf - buf_orig; - } - return 0; -} - -static struct device_attribute dst_node_attrs[] = { - __ATTR(size, 0444, dst_show_size, NULL), - __ATTR(type, 0444, dst_show_type, NULL), - __ATTR(local, 0444, dst_show_local, NULL), -}; - -static int dst_create_node_attributes(struct dst_node *n) -{ - int err, i; - - for (i = 0; i < ARRAY_SIZE(dst_node_attrs); ++i) { - err = device_create_file(&n->info->device, - &dst_node_attrs[i]); - if (err) - goto err_out_remove_all; - } - return 0; - -err_out_remove_all: - while (--i >= 0) - device_remove_file(&n->info->device, - &dst_node_attrs[i]); - - return err; -} - -static void dst_remove_node_attributes(struct dst_node *n) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(dst_node_attrs); ++i) - device_remove_file(&n->info->device, - &dst_node_attrs[i]); -} - -/* - * Sysfs cleanup and initialization. - * Shows number of useful parameters. - */ -static void dst_node_sysfs_exit(struct dst_node *n) -{ - if (n->info) { - dst_remove_node_attributes(n); - device_unregister(&n->info->device); - n->info = NULL; - } -} - -static int dst_node_sysfs_init(struct dst_node *n) -{ - int err; - - n->info = kzalloc(sizeof(struct dst_info), GFP_KERNEL); - if (!n->info) - return -ENOMEM; - - memcpy(&n->info->device, &dst_node_dev, sizeof(struct device)); - n->info->size = n->size; - - dev_set_name(&n->info->device, "dst-%s", n->name); - err = device_register(&n->info->device); - if (err) { - dprintk(KERN_ERR "Failed to register node '%s', err: %d.\n", - n->name, err); - goto err_out_exit; - } - - dst_create_node_attributes(n); - - return 0; - -err_out_exit: - kfree(n->info); - n->info = NULL; - return err; -} - -/* - * DST node hash tables machinery. - */ -static inline unsigned int dst_hash(char *str, unsigned int size) -{ - return jhash(str, size, 0) % dst_hashtable_size; -} - -static void dst_node_remove(struct dst_node *n) -{ - mutex_lock(&dst_hash_lock); - list_del_init(&n->node_entry); - mutex_unlock(&dst_hash_lock); -} - -static void dst_node_add(struct dst_node *n) -{ - unsigned hash = dst_hash(n->name, sizeof(n->name)); - - mutex_lock(&dst_hash_lock); - list_add_tail(&n->node_entry, &dst_hashtable[hash]); - mutex_unlock(&dst_hash_lock); -} - -/* - * Cleaning node when it is about to be freed. - * There are still users of the socket though, - * so connection cleanup should be protected. - */ -static void dst_node_cleanup(struct dst_node *n) -{ - struct dst_state *st = n->state; - - if (!st) - return; - - if (n->queue) { - blk_cleanup_queue(n->queue); - - mutex_lock(&dst_hash_lock); - idr_remove(&dst_index_idr, n->disk->first_minor); - mutex_unlock(&dst_hash_lock); - - put_disk(n->disk); - } - - if (n->bdev) { - sync_blockdev(n->bdev); - close_bdev_exclusive(n->bdev, FMODE_READ|FMODE_WRITE); - } - - dst_state_lock(st); - st->need_exit = 1; - dst_state_exit_connected(st); - dst_state_unlock(st); - - wake_up(&st->thread_wait); - - dst_state_put(st); - n->state = NULL; -} - -/* - * Free security attributes attached to given node. - */ -static void dst_security_exit(struct dst_node *n) -{ - struct dst_secure *s, *tmp; - - list_for_each_entry_safe(s, tmp, &n->security_list, sec_entry) { - list_del(&s->sec_entry); - kfree(s); - } -} - -/* - * Free node when there are no more users. - * Actually node has to be freed on behalf od userspace process, - * since there are number of threads, which are embedded in the - * node, so they can not exit and free node from there, that is - * why there is a wakeup if reference counter is not equal to zero. - */ -void dst_node_put(struct dst_node *n) -{ - if (unlikely(!n)) - return; - - dprintk("%s: n: %p, refcnt: %d.\n", - __func__, n, atomic_read(&n->refcnt)); - - if (atomic_dec_and_test(&n->refcnt)) { - dst_node_remove(n); - n->trans_scan_timeout = 0; - dst_node_cleanup(n); - thread_pool_destroy(n->pool); - dst_node_sysfs_exit(n); - dst_node_crypto_exit(n); - dst_security_exit(n); - dst_node_trans_exit(n); - - kfree(n); - - dprintk("%s: freed n: %p.\n", __func__, n); - } else { - wake_up(&n->wait); - } -} - -/* - * Setting up export device: lookup by the name, get its size - * and setup listening socket, which will accept clients, which - * will submit IO for given storage. - */ -static int dst_setup_export(struct dst_node *n, struct dst_ctl *ctl, - struct dst_export_ctl *le) -{ - int err; - - snprintf(n->info->local, sizeof(n->info->local), "%s", le->device); - - n->bdev = open_bdev_exclusive(le->device, FMODE_READ|FMODE_WRITE, NULL); - if (IS_ERR(n->bdev)) - return PTR_ERR(n->bdev); - - if (n->size != 0) - n->size = min_t(loff_t, n->bdev->bd_inode->i_size, n->size); - else - n->size = n->bdev->bd_inode->i_size; - - n->info->size = n->size; - err = dst_node_init_listened(n, le); - if (err) - goto err_out_cleanup; - - return 0; - -err_out_cleanup: - close_bdev_exclusive(n->bdev, FMODE_READ|FMODE_WRITE); - n->bdev = NULL; - - return err; -} - -/* Empty thread pool callbacks for the network processing threads. */ -static inline void *dst_thread_network_init(void *data) -{ - dprintk("%s: data: %p.\n", __func__, data); - return data; -} - -static inline void dst_thread_network_cleanup(void *data) -{ - dprintk("%s: data: %p.\n", __func__, data); -} - -/* - * Allocate DST node and initialize some of its parameters. - */ -static struct dst_node *dst_alloc_node(struct dst_ctl *ctl, - int (*start)(struct dst_node *), - int num) -{ - struct dst_node *n; - int err; - - n = kzalloc(sizeof(struct dst_node), GFP_KERNEL); - if (!n) - return NULL; - - INIT_LIST_HEAD(&n->node_entry); - - INIT_LIST_HEAD(&n->security_list); - mutex_init(&n->security_lock); - - init_waitqueue_head(&n->wait); - - n->trans_scan_timeout = msecs_to_jiffies(ctl->trans_scan_timeout); - if (!n->trans_scan_timeout) - n->trans_scan_timeout = HZ; - - n->trans_max_retries = ctl->trans_max_retries; - if (!n->trans_max_retries) - n->trans_max_retries = 10; - - /* - * Pretty much arbitrary default numbers. - * 32 matches maximum number of pages in bio originated from ext3 (31). - */ - n->max_pages = ctl->max_pages; - if (!n->max_pages) - n->max_pages = 32; - - if (n->max_pages > 1024) - n->max_pages = 1024; - - n->start = start; - n->size = ctl->size; - - atomic_set(&n->refcnt, 1); - atomic_long_set(&n->gen, 0); - snprintf(n->name, sizeof(n->name), "%s", ctl->name); - - err = dst_node_sysfs_init(n); - if (err) - goto err_out_free; - - n->pool = thread_pool_create(num, n->name, dst_thread_network_init, - dst_thread_network_cleanup, n); - if (IS_ERR(n->pool)) { - err = PTR_ERR(n->pool); - goto err_out_sysfs_exit; - } - - dprintk("%s: n: %p, name: %s.\n", __func__, n, n->name); - - return n; - -err_out_sysfs_exit: - dst_node_sysfs_exit(n); -err_out_free: - kfree(n); - return NULL; -} - -/* - * Starting a node, connected to the remote server: - * register block device and initialize transaction mechanism. - * In revers order though. - * - * It will autonegotiate some parameters with the remote node - * and update local if needed. - * - * Transaction initialization should be the last thing before - * starting the node, since transaction should include not only - * block IO, but also crypto related data (if any), which are - * initialized separately. - */ -static int dst_start_remote(struct dst_node *n) -{ - int err; - - err = dst_node_trans_init(n, sizeof(struct dst_trans)); - if (err) - return err; - - err = dst_node_create_disk(n); - if (err) - return err; - - dst_node_set_size(n); - add_disk(n->disk); - - dprintk("DST: started remote node '%s', minor: %d.\n", - n->name, n->disk->first_minor); - - return 0; -} - -/* - * Adding remote node and initialize connection. - */ -static int dst_add_remote(struct dst_node *n, struct dst_ctl *ctl, - void *data, unsigned int size) -{ - int err; - struct dst_network_ctl *rctl = data; - - if (n) - return -EEXIST; - - if (size != sizeof(struct dst_network_ctl)) - return -EINVAL; - - n = dst_alloc_node(ctl, dst_start_remote, 1); - if (!n) - return -ENOMEM; - - memcpy(&n->info->net, rctl, sizeof(struct dst_network_ctl)); - err = dst_node_init_connected(n, rctl); - if (err) - goto err_out_free; - - dst_node_add(n); - - return 0; - -err_out_free: - dst_node_put(n); - return err; -} - -/* - * Adding export node: initializing block device and listening socket. - */ -static int dst_add_export(struct dst_node *n, struct dst_ctl *ctl, - void *data, unsigned int size) -{ - int err; - struct dst_export_ctl *le = data; - - if (n) - return -EEXIST; - - if (size != sizeof(struct dst_export_ctl)) - return -EINVAL; - - n = dst_alloc_node(ctl, dst_start_export, 2); - if (!n) - return -EINVAL; - - err = dst_setup_export(n, ctl, le); - if (err) - goto err_out_free; - - dst_node_add(n); - - return 0; - -err_out_free: - dst_node_put(n); - return err; -} - -static int dst_node_remove_unload(struct dst_node *n) -{ - printk(KERN_INFO "STOPPED name: '%s', size: %llu.\n", - n->name, n->size); - - if (n->disk) - del_gendisk(n->disk); - - dst_node_remove(n); - dst_node_sysfs_exit(n); - - /* - * This is not a hack. Really. - * Node's reference counter allows to implement fine grained - * node freeing, but since all transactions (which hold node's - * reference counter) are processed in the dedicated thread, - * it is possible that reference will hit zero in that thread, - * so we will not be able to exit thread and cleanup the node. - * - * So, we remove disk, so no new activity is possible, and - * wait until all pending transaction are completed (either - * in receiving thread or by timeout in workqueue), in this - * case reference counter will be less or equal to 2 (once set in - * dst_alloc_node() and then in connector message parser; - * or when we force module unloading, and connector message - * parser does not hold a reference, in this case reference - * counter will be equal to 1), - * and subsequent dst_node_put() calls will free the node. - */ - dprintk("%s: going to sleep with %d refcnt.\n", - __func__, atomic_read(&n->refcnt)); - wait_event(n->wait, atomic_read(&n->refcnt) <= 2); - - dst_node_put(n); - return 0; -} - -/* - * Remove node from the hash table. - */ -static int dst_del_node(struct dst_node *n, struct dst_ctl *ctl, - void *data, unsigned int size) -{ - if (!n) - return -ENODEV; - - return dst_node_remove_unload(n); -} - -/* - * Initialize crypto processing for given node. - */ -static int dst_crypto_init(struct dst_node *n, struct dst_ctl *ctl, - void *data, unsigned int size) -{ - struct dst_crypto_ctl *crypto = data; - - if (!n) - return -ENODEV; - - if (size != sizeof(struct dst_crypto_ctl) + crypto->hash_keysize + - crypto->cipher_keysize) - return -EINVAL; - - if (n->trans_cache) - return -EEXIST; - - return dst_node_crypto_init(n, crypto); -} - -/* - * Security attributes for given node. - */ -static int dst_security_init(struct dst_node *n, struct dst_ctl *ctl, - void *data, unsigned int size) -{ - struct dst_secure *s; - - if (!n) - return -ENODEV; - - if (size != sizeof(struct dst_secure_user)) - return -EINVAL; - - s = kmalloc(sizeof(struct dst_secure), GFP_KERNEL); - if (!s) - return -ENOMEM; - - memcpy(&s->sec, data, size); - - mutex_lock(&n->security_lock); - list_add_tail(&s->sec_entry, &n->security_list); - mutex_unlock(&n->security_lock); - - return 0; -} - -/* - * Kill'em all! - */ -static int dst_start_node(struct dst_node *n, struct dst_ctl *ctl, - void *data, unsigned int size) -{ - int err; - - if (!n) - return -ENODEV; - - if (n->trans_cache) - return 0; - - err = n->start(n); - if (err) - return err; - - printk(KERN_INFO "STARTED name: '%s', size: %llu.\n", n->name, n->size); - return 0; -} - -typedef int (*dst_command_func)(struct dst_node *n, struct dst_ctl *ctl, - void *data, unsigned int size); - -/* - * List of userspace commands. - */ -static dst_command_func dst_commands[] = { - [DST_ADD_REMOTE] = &dst_add_remote, - [DST_ADD_EXPORT] = &dst_add_export, - [DST_DEL_NODE] = &dst_del_node, - [DST_CRYPTO] = &dst_crypto_init, - [DST_SECURITY] = &dst_security_init, - [DST_START] = &dst_start_node, -}; - -/* - * Configuration parser. - */ -static void cn_dst_callback(struct cn_msg *msg, struct netlink_skb_parms *nsp) -{ - struct dst_ctl *ctl; - int err; - struct dst_ctl_ack ack; - struct dst_node *n = NULL, *tmp; - unsigned int hash; - - if (!cap_raised(nsp->eff_cap, CAP_SYS_ADMIN)) { - err = -EPERM; - goto out; - } - - if (msg->len < sizeof(struct dst_ctl)) { - err = -EBADMSG; - goto out; - } - - ctl = (struct dst_ctl *)msg->data; - - if (ctl->cmd >= DST_CMD_MAX) { - err = -EINVAL; - goto out; - } - hash = dst_hash(ctl->name, sizeof(ctl->name)); - - mutex_lock(&dst_hash_lock); - list_for_each_entry(tmp, &dst_hashtable[hash], node_entry) { - if (!memcmp(tmp->name, ctl->name, sizeof(tmp->name))) { - n = tmp; - dst_node_get(n); - break; - } - } - mutex_unlock(&dst_hash_lock); - - err = dst_commands[ctl->cmd](n, ctl, msg->data + sizeof(struct dst_ctl), - msg->len - sizeof(struct dst_ctl)); - - dst_node_put(n); -out: - memcpy(&ack.msg, msg, sizeof(struct cn_msg)); - - ack.msg.ack = msg->ack + 1; - ack.msg.len = sizeof(struct dst_ctl_ack) - sizeof(struct cn_msg); - - ack.error = err; - - cn_netlink_send(&ack.msg, 0, GFP_KERNEL); -} - -/* - * Global initialization: sysfs, hash table, block device registration, - * connector and various caches. - */ -static int __init dst_sysfs_init(void) -{ - return bus_register(&dst_dev_bus_type); -} - -static void dst_sysfs_exit(void) -{ - bus_unregister(&dst_dev_bus_type); -} - -static int __init dst_hashtable_init(void) -{ - unsigned int i; - - dst_hashtable = kcalloc(dst_hashtable_size, sizeof(struct list_head), - GFP_KERNEL); - if (!dst_hashtable) - return -ENOMEM; - - for (i = 0; i < dst_hashtable_size; ++i) - INIT_LIST_HEAD(&dst_hashtable[i]); - - return 0; -} - -static void dst_hashtable_exit(void) -{ - unsigned int i; - struct dst_node *n, *tmp; - - for (i = 0; i < dst_hashtable_size; ++i) { - list_for_each_entry_safe(n, tmp, &dst_hashtable[i], node_entry) { - dst_node_remove_unload(n); - } - } - - kfree(dst_hashtable); -} - -static int __init dst_sys_init(void) -{ - int err = -ENOMEM; - - err = dst_hashtable_init(); - if (err) - goto err_out_exit; - - err = dst_export_init(); - if (err) - goto err_out_hashtable_exit; - - err = register_blkdev(dst_major, DST_NAME); - if (err < 0) - goto err_out_export_exit; - if (err) - dst_major = err; - - err = dst_sysfs_init(); - if (err) - goto err_out_unregister; - - err = cn_add_callback(&cn_dst_id, "DST", cn_dst_callback); - if (err) - goto err_out_sysfs_exit; - - printk(KERN_INFO "Distributed storage, '%s' release.\n", dst_name); - - return 0; - -err_out_sysfs_exit: - dst_sysfs_exit(); -err_out_unregister: - unregister_blkdev(dst_major, DST_NAME); -err_out_export_exit: - dst_export_exit(); -err_out_hashtable_exit: - dst_hashtable_exit(); -err_out_exit: - return err; -} - -static void __exit dst_sys_exit(void) -{ - cn_del_callback(&cn_dst_id); - unregister_blkdev(dst_major, DST_NAME); - dst_hashtable_exit(); - dst_sysfs_exit(); - dst_export_exit(); -} - -module_init(dst_sys_init); -module_exit(dst_sys_exit); - -MODULE_DESCRIPTION("Distributed storage"); -MODULE_AUTHOR("Evgeniy Polyakov "); -MODULE_LICENSE("GPL"); diff --git a/drivers/staging/dst/export.c b/drivers/staging/dst/export.c deleted file mode 100644 index c324230e8b60..000000000000 --- a/drivers/staging/dst/export.c +++ /dev/null @@ -1,660 +0,0 @@ -/* - * 2007+ Copyright (c) Evgeniy Polyakov - * All rights reserved. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* - * Export bioset is used for server block IO requests. - */ -static struct bio_set *dst_bio_set; - -int __init dst_export_init(void) -{ - int err = -ENOMEM; - - dst_bio_set = bioset_create(32, sizeof(struct dst_export_priv)); - if (!dst_bio_set) - goto err_out_exit; - - return 0; - -err_out_exit: - return err; -} - -void dst_export_exit(void) -{ - bioset_free(dst_bio_set); -} - -/* - * When client connects and autonegotiates with the server node, - * its permissions are checked in a security attributes and sent - * back. - */ -static unsigned int dst_check_permissions(struct dst_state *main, - struct dst_state *st) -{ - struct dst_node *n = main->node; - struct dst_secure *sentry; - struct dst_secure_user *s; - struct saddr *sa = &st->ctl.addr; - unsigned int perm = 0; - - mutex_lock(&n->security_lock); - list_for_each_entry(sentry, &n->security_list, sec_entry) { - s = &sentry->sec; - - if (s->addr.sa_family != sa->sa_family) - continue; - - if (s->addr.sa_data_len != sa->sa_data_len) - continue; - - /* - * This '2' below is a port field. This may be very wrong to do - * in atalk for example though. If there will be any need - * to extent protocol to something else, I can create - * per-family helpers and use them instead of this memcmp. - */ - if (memcmp(s->addr.sa_data + 2, sa->sa_data + 2, - sa->sa_data_len - 2)) - continue; - - perm = s->permissions; - } - mutex_unlock(&n->security_lock); - - return perm; -} - -/* - * Accept new client: allocate appropriate network state and check permissions. - */ -static struct dst_state *dst_accept_client(struct dst_state *st) -{ - unsigned int revents = 0; - unsigned int err_mask = POLLERR | POLLHUP | POLLRDHUP; - unsigned int mask = err_mask | POLLIN; - struct dst_node *n = st->node; - int err = 0; - struct socket *sock = NULL; - struct dst_state *new; - - while (!err && !sock) { - revents = dst_state_poll(st); - - if (!(revents & mask)) { - DEFINE_WAIT(wait); - - for (;;) { - prepare_to_wait(&st->thread_wait, - &wait, TASK_INTERRUPTIBLE); - if (!n->trans_scan_timeout || st->need_exit) - break; - - revents = dst_state_poll(st); - - if (revents & mask) - break; - - if (signal_pending(current)) - break; - - /* - * Magic HZ? Polling check above is not safe in - * all cases (like socket reset in BH context), - * so it is simpler just to postpone it to the - * process context instead of implementing - * special locking there. - */ - schedule_timeout(HZ); - } - finish_wait(&st->thread_wait, &wait); - } - - err = -ECONNRESET; - dst_state_lock(st); - - dprintk("%s: st: %p, revents: %x [err: %d, in: %d].\n", - __func__, st, revents, revents & err_mask, - revents & POLLIN); - - if (revents & err_mask) { - dprintk("%s: revents: %x, socket: %p, err: %d.\n", - __func__, revents, st->socket, err); - err = -ECONNRESET; - } - - if (!n->trans_scan_timeout || st->need_exit) - err = -ENODEV; - - if (st->socket && (revents & POLLIN)) - err = kernel_accept(st->socket, &sock, 0); - - dst_state_unlock(st); - } - - if (err) - goto err_out_exit; - - new = dst_state_alloc(st->node); - if (IS_ERR(new)) { - err = -ENOMEM; - goto err_out_release; - } - new->socket = sock; - - new->ctl.addr.sa_data_len = sizeof(struct sockaddr); - err = kernel_getpeername(sock, (struct sockaddr *)&new->ctl.addr, - (int *)&new->ctl.addr.sa_data_len); - if (err) - goto err_out_put; - - new->permissions = dst_check_permissions(st, new); - if (new->permissions == 0) { - err = -EPERM; - dst_dump_addr(sock, (struct sockaddr *)&new->ctl.addr, - "Client is not allowed to connect"); - goto err_out_put; - } - - err = dst_poll_init(new); - if (err) - goto err_out_put; - - dst_dump_addr(sock, (struct sockaddr *)&new->ctl.addr, - "Connected client"); - - return new; - -err_out_put: - dst_state_put(new); -err_out_release: - sock_release(sock); -err_out_exit: - return ERR_PTR(err); -} - -/* - * Each server's block request sometime finishes. - * Usually it happens in hard irq context of the appropriate controller, - * so to play good with all cases we just queue BIO into the queue - * and wake up processing thread, which gets completed request and - * send (encrypting if needed) it back to the client (if it was a read - * request), or sends back reply that writing successfully completed. - */ -static int dst_export_process_request_queue(struct dst_state *st) -{ - unsigned long flags; - struct dst_export_priv *p = NULL; - struct bio *bio; - int err = 0; - - while (!list_empty(&st->request_list)) { - spin_lock_irqsave(&st->request_lock, flags); - if (!list_empty(&st->request_list)) { - p = list_first_entry(&st->request_list, - struct dst_export_priv, request_entry); - list_del(&p->request_entry); - } - spin_unlock_irqrestore(&st->request_lock, flags); - - if (!p) - break; - - bio = p->bio; - - if (dst_need_crypto(st->node) && (bio_data_dir(bio) == READ)) - err = dst_export_crypto(st->node, bio); - else - err = dst_export_send_bio(bio); - - if (err) - break; - } - - return err; -} - -/* - * Cleanup export state. - * It has to wait until all requests are finished, - * and then free them all. - */ -static void dst_state_cleanup_export(struct dst_state *st) -{ - struct dst_export_priv *p; - unsigned long flags; - - /* - * This loop waits for all pending bios to be completed and freed. - */ - while (atomic_read(&st->refcnt) > 1) { - dprintk("%s: st: %p, refcnt: %d, list_empty: %d.\n", - __func__, st, atomic_read(&st->refcnt), - list_empty(&st->request_list)); - wait_event_timeout(st->thread_wait, - (atomic_read(&st->refcnt) == 1) || - !list_empty(&st->request_list), - HZ/2); - - while (!list_empty(&st->request_list)) { - p = NULL; - spin_lock_irqsave(&st->request_lock, flags); - if (!list_empty(&st->request_list)) { - p = list_first_entry(&st->request_list, - struct dst_export_priv, request_entry); - list_del(&p->request_entry); - } - spin_unlock_irqrestore(&st->request_lock, flags); - - if (p) - bio_put(p->bio); - - dprintk("%s: st: %p, refcnt: %d, list_empty: %d, p: " - "%p.\n", __func__, st, atomic_read(&st->refcnt), - list_empty(&st->request_list), p); - } - } - - dst_state_put(st); -} - -/* - * Client accepting thread. - * Not only accepts new connection, but also schedules receiving thread - * and performs request completion described above. - */ -static int dst_accept(void *init_data, void *schedule_data) -{ - struct dst_state *main_st = schedule_data; - struct dst_node *n = init_data; - struct dst_state *st; - int err; - - while (n->trans_scan_timeout && !main_st->need_exit) { - dprintk("%s: main_st: %p, n: %p.\n", __func__, main_st, n); - st = dst_accept_client(main_st); - if (IS_ERR(st)) - continue; - - err = dst_state_schedule_receiver(st); - if (!err) { - while (n->trans_scan_timeout) { - err = wait_event_interruptible_timeout(st->thread_wait, - !list_empty(&st->request_list) || - !n->trans_scan_timeout || - st->need_exit, - HZ); - - if (!n->trans_scan_timeout || st->need_exit) - break; - - if (list_empty(&st->request_list)) - continue; - - err = dst_export_process_request_queue(st); - if (err) - break; - } - - st->need_exit = 1; - wake_up(&st->thread_wait); - } - - dst_state_cleanup_export(st); - } - - dprintk("%s: freeing listening socket st: %p.\n", __func__, main_st); - - dst_state_lock(main_st); - dst_poll_exit(main_st); - dst_state_socket_release(main_st); - dst_state_unlock(main_st); - dst_state_put(main_st); - dprintk("%s: freed listening socket st: %p.\n", __func__, main_st); - - return 0; -} - -int dst_start_export(struct dst_node *n) -{ - if (list_empty(&n->security_list)) { - printk(KERN_ERR "You are trying to export node '%s' " - "without security attributes.\nNo clients will " - "be allowed to connect. Exiting.\n", n->name); - return -EINVAL; - } - return dst_node_trans_init(n, sizeof(struct dst_export_priv)); -} - -/* - * Initialize listening state and schedule accepting thread. - */ -int dst_node_init_listened(struct dst_node *n, struct dst_export_ctl *le) -{ - struct dst_state *st; - int err = -ENOMEM; - struct dst_network_ctl *ctl = &le->ctl; - - memcpy(&n->info->net, ctl, sizeof(struct dst_network_ctl)); - - st = dst_state_alloc(n); - if (IS_ERR(st)) { - err = PTR_ERR(st); - goto err_out_exit; - } - memcpy(&st->ctl, ctl, sizeof(struct dst_network_ctl)); - - err = dst_state_socket_create(st); - if (err) - goto err_out_put; - - st->socket->sk->sk_reuse = 1; - - err = kernel_bind(st->socket, (struct sockaddr *)&ctl->addr, - ctl->addr.sa_data_len); - if (err) - goto err_out_socket_release; - - err = kernel_listen(st->socket, 1024); - if (err) - goto err_out_socket_release; - n->state = st; - - err = dst_poll_init(st); - if (err) - goto err_out_socket_release; - - dst_state_get(st); - - err = thread_pool_schedule(n->pool, dst_thread_setup, - dst_accept, st, MAX_SCHEDULE_TIMEOUT); - if (err) - goto err_out_poll_exit; - - return 0; - -err_out_poll_exit: - dst_poll_exit(st); -err_out_socket_release: - dst_state_socket_release(st); -err_out_put: - dst_state_put(st); -err_out_exit: - n->state = NULL; - return err; -} - -/* - * Free bio and related private data. - * Also drop a reference counter for appropriate state, - * which waits when there are no more block IOs in-flight. - */ -static void dst_bio_destructor(struct bio *bio) -{ - struct bio_vec *bv; - struct dst_export_priv *priv = bio->bi_private; - int i; - - bio_for_each_segment(bv, bio, i) { - if (!bv->bv_page) - break; - - __free_page(bv->bv_page); - } - - if (priv) - dst_state_put(priv->state); - bio_free(bio, dst_bio_set); -} - -/* - * Block IO completion. Queue request to be sent back to - * the client (or just confirmation). - */ -static void dst_bio_end_io(struct bio *bio, int err) -{ - struct dst_export_priv *p = bio->bi_private; - struct dst_state *st = p->state; - unsigned long flags; - - spin_lock_irqsave(&st->request_lock, flags); - list_add_tail(&p->request_entry, &st->request_list); - spin_unlock_irqrestore(&st->request_lock, flags); - - wake_up(&st->thread_wait); -} - -/* - * Allocate read request for the server. - */ -static int dst_export_read_request(struct bio *bio, unsigned int total_size) -{ - unsigned int size; - struct page *page; - int err; - - while (total_size) { - err = -ENOMEM; - page = alloc_page(GFP_KERNEL); - if (!page) - goto err_out_exit; - - size = min_t(unsigned int, PAGE_SIZE, total_size); - - err = bio_add_page(bio, page, size, 0); - dprintk("%s: bio: %llu/%u, size: %u, err: %d.\n", - __func__, (u64)bio->bi_sector, bio->bi_size, - size, err); - if (err <= 0) - goto err_out_free_page; - - total_size -= size; - } - - return 0; - -err_out_free_page: - __free_page(page); -err_out_exit: - return err; -} - -/* - * Allocate write request for the server. - * Should not only get pages, but also read data from the network. - */ -static int dst_export_write_request(struct dst_state *st, - struct bio *bio, unsigned int total_size) -{ - unsigned int size; - struct page *page; - void *data; - int err; - - while (total_size) { - err = -ENOMEM; - page = alloc_page(GFP_KERNEL); - if (!page) - goto err_out_exit; - - data = kmap(page); - if (!data) - goto err_out_free_page; - - size = min_t(unsigned int, PAGE_SIZE, total_size); - - err = dst_data_recv(st, data, size); - if (err) - goto err_out_unmap_page; - - err = bio_add_page(bio, page, size, 0); - if (err <= 0) - goto err_out_unmap_page; - - kunmap(page); - - total_size -= size; - } - - return 0; - -err_out_unmap_page: - kunmap(page); -err_out_free_page: - __free_page(page); -err_out_exit: - return err; -} - -/* - * Groovy, we've gotten an IO request from the client. - * Allocate BIO from the bioset, private data from the mempool - * and lots of pages for IO. - */ -int dst_process_io(struct dst_state *st) -{ - struct dst_node *n = st->node; - struct dst_cmd *cmd = st->data; - struct bio *bio; - struct dst_export_priv *priv; - int err = -ENOMEM; - - if (unlikely(!n->bdev)) { - err = -EINVAL; - goto err_out_exit; - } - - bio = bio_alloc_bioset(GFP_KERNEL, - PAGE_ALIGN(cmd->size) >> PAGE_SHIFT, - dst_bio_set); - if (!bio) - goto err_out_exit; - - priv = (struct dst_export_priv *)(((void *)bio) - - sizeof (struct dst_export_priv)); - - priv->state = dst_state_get(st); - priv->bio = bio; - - bio->bi_private = priv; - bio->bi_end_io = dst_bio_end_io; - bio->bi_destructor = dst_bio_destructor; - bio->bi_bdev = n->bdev; - - /* - * Server side is only interested in two low bits: - * uptodate (set by itself actually) and rw block - */ - bio->bi_flags |= cmd->flags & 3; - - bio->bi_rw = cmd->rw; - bio->bi_size = 0; - bio->bi_sector = cmd->sector; - - dst_bio_to_cmd(bio, &priv->cmd, DST_IO_RESPONSE, cmd->id); - - priv->cmd.flags = 0; - priv->cmd.size = cmd->size; - - if (bio_data_dir(bio) == WRITE) { - err = dst_recv_cdata(st, priv->cmd.hash); - if (err) - goto err_out_free; - - err = dst_export_write_request(st, bio, cmd->size); - if (err) - goto err_out_free; - - if (dst_need_crypto(n)) - return dst_export_crypto(n, bio); - } else { - err = dst_export_read_request(bio, cmd->size); - if (err) - goto err_out_free; - } - - dprintk("%s: bio: %llu/%u, rw: %lu, dir: %lu, flags: %lx, phys: %d.\n", - __func__, (u64)bio->bi_sector, bio->bi_size, - bio->bi_rw, bio_data_dir(bio), - bio->bi_flags, bio->bi_phys_segments); - - generic_make_request(bio); - - return 0; - -err_out_free: - bio_put(bio); -err_out_exit: - return err; -} - -/* - * Ok, block IO is ready, let's send it back to the client... - */ -int dst_export_send_bio(struct bio *bio) -{ - struct dst_export_priv *p = bio->bi_private; - struct dst_state *st = p->state; - struct dst_cmd *cmd = &p->cmd; - int err; - - dprintk("%s: id: %llu, bio: %llu/%u, csize: %u, flags: %lu, rw: %lu.\n", - __func__, cmd->id, (u64)bio->bi_sector, bio->bi_size, - cmd->csize, bio->bi_flags, bio->bi_rw); - - dst_convert_cmd(cmd); - - dst_state_lock(st); - if (!st->socket) { - err = -ECONNRESET; - goto err_out_unlock; - } - - if (bio_data_dir(bio) == WRITE) { - /* ... or just confirmation that writing has completed. */ - cmd->size = cmd->csize = 0; - err = dst_data_send_header(st->socket, cmd, - sizeof(struct dst_cmd), 0); - if (err) - goto err_out_unlock; - } else { - err = dst_send_bio(st, cmd, bio); - if (err) - goto err_out_unlock; - } - - dst_state_unlock(st); - - bio_put(bio); - return 0; - -err_out_unlock: - dst_state_unlock(st); - - bio_put(bio); - return err; -} diff --git a/drivers/staging/dst/state.c b/drivers/staging/dst/state.c deleted file mode 100644 index 02a05e6c48c3..000000000000 --- a/drivers/staging/dst/state.c +++ /dev/null @@ -1,844 +0,0 @@ -/* - * 2007+ Copyright (c) Evgeniy Polyakov - * All rights reserved. - * - * 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. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* - * Polling machinery. - */ - -struct dst_poll_helper { - poll_table pt; - struct dst_state *st; -}; - -static int dst_queue_wake(wait_queue_t *wait, unsigned mode, - int sync, void *key) -{ - struct dst_state *st = container_of(wait, struct dst_state, wait); - - wake_up(&st->thread_wait); - return 1; -} - -static void dst_queue_func(struct file *file, wait_queue_head_t *whead, - poll_table *pt) -{ - struct dst_state *st = container_of(pt, struct dst_poll_helper, pt)->st; - - st->whead = whead; - init_waitqueue_func_entry(&st->wait, dst_queue_wake); - add_wait_queue(whead, &st->wait); -} - -void dst_poll_exit(struct dst_state *st) -{ - if (st->whead) { - remove_wait_queue(st->whead, &st->wait); - st->whead = NULL; - } -} - -int dst_poll_init(struct dst_state *st) -{ - struct dst_poll_helper ph; - - ph.st = st; - init_poll_funcptr(&ph.pt, &dst_queue_func); - - st->socket->ops->poll(NULL, st->socket, &ph.pt); - return 0; -} - -/* - * Header receiving function - may block. - */ -static int dst_data_recv_header(struct socket *sock, - void *data, unsigned int size, int block) -{ - struct msghdr msg; - struct kvec iov; - int err; - - iov.iov_base = data; - iov.iov_len = size; - - msg.msg_iov = (struct iovec *)&iov; - msg.msg_iovlen = 1; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_flags = (block) ? MSG_WAITALL : MSG_DONTWAIT; - - err = kernel_recvmsg(sock, &msg, &iov, 1, iov.iov_len, - msg.msg_flags); - if (err != size) - return -1; - - return 0; -} - -/* - * Header sending function - may block. - */ -int dst_data_send_header(struct socket *sock, - void *data, unsigned int size, int more) -{ - struct msghdr msg; - struct kvec iov; - int err; - - iov.iov_base = data; - iov.iov_len = size; - - msg.msg_iov = (struct iovec *)&iov; - msg.msg_iovlen = 1; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_flags = MSG_WAITALL | (more ? MSG_MORE : 0); - - err = kernel_sendmsg(sock, &msg, &iov, 1, iov.iov_len); - if (err != size) { - dprintk("%s: size: %u, more: %d, err: %d.\n", - __func__, size, more, err); - return -1; - } - - return 0; -} - -/* - * Block autoconfiguration: request size of the storage and permissions. - */ -static int dst_request_remote_config(struct dst_state *st) -{ - struct dst_node *n = st->node; - int err = -EINVAL; - struct dst_cmd *cmd = st->data; - - memset(cmd, 0, sizeof(struct dst_cmd)); - cmd->cmd = DST_CFG; - - dst_convert_cmd(cmd); - - err = dst_data_send_header(st->socket, cmd, sizeof(struct dst_cmd), 0); - if (err) - goto out; - - err = dst_data_recv_header(st->socket, cmd, sizeof(struct dst_cmd), 1); - if (err) - goto out; - - dst_convert_cmd(cmd); - - if (cmd->cmd != DST_CFG) { - err = -EINVAL; - dprintk("%s: checking result: cmd: %d, size reported: %llu.\n", - __func__, cmd->cmd, cmd->sector); - goto out; - } - - if (n->size != 0) - n->size = min_t(loff_t, n->size, cmd->sector); - else - n->size = cmd->sector; - - n->info->size = n->size; - st->permissions = cmd->rw; - -out: - dprintk("%s: n: %p, err: %d, size: %llu, permission: %x.\n", - __func__, n, err, n->size, st->permissions); - return err; -} - -/* - * Socket machinery. - */ - -#define DST_DEFAULT_TIMEO 20000 - -int dst_state_socket_create(struct dst_state *st) -{ - int err; - struct socket *sock; - struct dst_network_ctl *ctl = &st->ctl; - - err = sock_create(ctl->addr.sa_family, ctl->type, ctl->proto, &sock); - if (err < 0) - return err; - - sock->sk->sk_sndtimeo = sock->sk->sk_rcvtimeo = - msecs_to_jiffies(DST_DEFAULT_TIMEO); - sock->sk->sk_allocation = GFP_NOIO; - - st->socket = st->read_socket = sock; - return 0; -} - -void dst_state_socket_release(struct dst_state *st) -{ - dprintk("%s: st: %p, socket: %p, n: %p.\n", - __func__, st, st->socket, st->node); - if (st->socket) { - sock_release(st->socket); - st->socket = NULL; - st->read_socket = NULL; - } -} - -void dst_dump_addr(struct socket *sk, struct sockaddr *sa, char *str) -{ - if (sk->ops->family == AF_INET) { - struct sockaddr_in *sin = (struct sockaddr_in *)sa; - printk(KERN_INFO "%s %u.%u.%u.%u:%d.\n", str, - NIPQUAD(sin->sin_addr.s_addr), ntohs(sin->sin_port)); - } else if (sk->ops->family == AF_INET6) { - struct sockaddr_in6 *sin = (struct sockaddr_in6 *)sa; - printk(KERN_INFO "%s %pi6:%d", - str, &sin->sin6_addr, ntohs(sin->sin6_port)); - } -} - -void dst_state_exit_connected(struct dst_state *st) -{ - if (st->socket) { - dst_poll_exit(st); - st->socket->ops->shutdown(st->socket, 2); - - dst_dump_addr(st->socket, (struct sockaddr *)&st->ctl.addr, - "Disconnected peer"); - dst_state_socket_release(st); - } -} - -static int dst_state_init_connected(struct dst_state *st) -{ - int err; - struct dst_network_ctl *ctl = &st->ctl; - - err = dst_state_socket_create(st); - if (err) - goto err_out_exit; - - err = kernel_connect(st->socket, (struct sockaddr *)&st->ctl.addr, - st->ctl.addr.sa_data_len, 0); - if (err) - goto err_out_release; - - err = dst_poll_init(st); - if (err) - goto err_out_release; - - dst_dump_addr(st->socket, (struct sockaddr *)&ctl->addr, - "Connected to peer"); - - return 0; - -err_out_release: - dst_state_socket_release(st); -err_out_exit: - return err; -} - -/* - * State reset is used to reconnect to the remote peer. - * May fail, but who cares, we will try again later. - */ -static inline void dst_state_reset_nolock(struct dst_state *st) -{ - dst_state_exit_connected(st); - dst_state_init_connected(st); -} - -static inline void dst_state_reset(struct dst_state *st) -{ - dst_state_lock(st); - dst_state_reset_nolock(st); - dst_state_unlock(st); -} - -/* - * Basic network sending/receiving functions. - * Blocked mode is used. - */ -static int dst_data_recv_raw(struct dst_state *st, void *buf, u64 size) -{ - struct msghdr msg; - struct kvec iov; - int err; - - BUG_ON(!size); - - iov.iov_base = buf; - iov.iov_len = size; - - msg.msg_iov = (struct iovec *)&iov; - msg.msg_iovlen = 1; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_flags = MSG_DONTWAIT; - - err = kernel_recvmsg(st->socket, &msg, &iov, 1, iov.iov_len, - msg.msg_flags); - if (err <= 0) { - dprintk("%s: failed to recv data: size: %llu, err: %d.\n", - __func__, size, err); - if (err == 0) - err = -ECONNRESET; - - dst_state_exit_connected(st); - } - - return err; -} - -/* - * Ping command to early detect failed nodes. - */ -static int dst_send_ping(struct dst_state *st) -{ - struct dst_cmd *cmd = st->data; - int err = -ECONNRESET; - - dst_state_lock(st); - if (st->socket) { - memset(cmd, 0, sizeof(struct dst_cmd)); - - cmd->cmd = __cpu_to_be32(DST_PING); - - err = dst_data_send_header(st->socket, cmd, - sizeof(struct dst_cmd), 0); - } - dprintk("%s: st: %p, socket: %p, err: %d.\n", __func__, - st, st->socket, err); - dst_state_unlock(st); - - return err; -} - -/* - * Receiving function, which should either return error or read - * whole block request. If there was no traffic for a one second, - * send a ping, since remote node may die. - */ -int dst_data_recv(struct dst_state *st, void *data, unsigned int size) -{ - unsigned int revents = 0; - unsigned int err_mask = POLLERR | POLLHUP | POLLRDHUP; - unsigned int mask = err_mask | POLLIN; - struct dst_node *n = st->node; - int err = 0; - - while (size && !err) { - revents = dst_state_poll(st); - - if (!(revents & mask)) { - DEFINE_WAIT(wait); - - for (;;) { - prepare_to_wait(&st->thread_wait, &wait, - TASK_INTERRUPTIBLE); - if (!n->trans_scan_timeout || st->need_exit) - break; - - revents = dst_state_poll(st); - - if (revents & mask) - break; - - if (signal_pending(current)) - break; - - if (!schedule_timeout(HZ)) { - err = dst_send_ping(st); - if (err) - return err; - } - - continue; - } - finish_wait(&st->thread_wait, &wait); - } - - err = -ECONNRESET; - dst_state_lock(st); - - if (st->socket && (st->read_socket == st->socket) && - (revents & POLLIN)) { - err = dst_data_recv_raw(st, data, size); - if (err > 0) { - data += err; - size -= err; - err = 0; - } - } - - if (revents & err_mask || !st->socket) { - dprintk("%s: revents: %x, socket: %p, size: %u, " - "err: %d.\n", __func__, revents, - st->socket, size, err); - err = -ECONNRESET; - } - - dst_state_unlock(st); - - if (!n->trans_scan_timeout) - err = -ENODEV; - } - - return err; -} - -/* - * Send block autoconf reply. - */ -static int dst_process_cfg(struct dst_state *st) -{ - struct dst_node *n = st->node; - struct dst_cmd *cmd = st->data; - int err; - - cmd->sector = n->size; - cmd->rw = st->permissions; - - dst_convert_cmd(cmd); - - dst_state_lock(st); - err = dst_data_send_header(st->socket, cmd, sizeof(struct dst_cmd), 0); - dst_state_unlock(st); - - return err; -} - -/* - * Receive block IO from the network. - */ -static int dst_recv_bio(struct dst_state *st, struct bio *bio, - unsigned int total_size) -{ - struct bio_vec *bv; - int i, err; - void *data; - unsigned int sz; - - bio_for_each_segment(bv, bio, i) { - sz = min(total_size, bv->bv_len); - - dprintk("%s: bio: %llu/%u, total: %u, len: %u, sz: %u, " - "off: %u.\n", __func__, (u64)bio->bi_sector, - bio->bi_size, total_size, bv->bv_len, sz, - bv->bv_offset); - - data = kmap(bv->bv_page) + bv->bv_offset; - err = dst_data_recv(st, data, sz); - kunmap(bv->bv_page); - - bv->bv_len = sz; - - if (err) - return err; - - total_size -= sz; - if (total_size == 0) - break; - } - - return 0; -} - -/* - * Our block IO has just completed and arrived: get it. - */ -static int dst_process_io_response(struct dst_state *st) -{ - struct dst_node *n = st->node; - struct dst_cmd *cmd = st->data; - struct dst_trans *t; - int err = 0; - struct bio *bio; - - mutex_lock(&n->trans_lock); - t = dst_trans_search(n, cmd->id); - mutex_unlock(&n->trans_lock); - - if (!t) - goto err_out_exit; - - bio = t->bio; - - dprintk("%s: bio: %llu/%u, cmd_size: %u, csize: %u, dir: %lu.\n", - __func__, (u64)bio->bi_sector, bio->bi_size, cmd->size, - cmd->csize, bio_data_dir(bio)); - - if (bio_data_dir(bio) == READ) { - if (bio->bi_size != cmd->size - cmd->csize) - goto err_out_exit; - - if (dst_need_crypto(n)) { - err = dst_recv_cdata(st, t->cmd.hash); - if (err) - goto err_out_exit; - } - - err = dst_recv_bio(st, t->bio, bio->bi_size); - if (err) - goto err_out_exit; - - if (dst_need_crypto(n)) - return dst_trans_crypto(t); - } else { - err = -EBADMSG; - if (cmd->size || cmd->csize) - goto err_out_exit; - } - - dst_trans_remove(t); - dst_trans_put(t); - - return 0; - -err_out_exit: - return err; -} - -/* - * Receive crypto data. - */ -int dst_recv_cdata(struct dst_state *st, void *cdata) -{ - struct dst_cmd *cmd = st->data; - struct dst_node *n = st->node; - struct dst_crypto_ctl *c = &n->crypto; - int err; - - if (cmd->csize != c->crypto_attached_size) { - dprintk("%s: cmd: cmd: %u, sector: %llu, size: %u, " - "csize: %u != digest size %u.\n", - __func__, cmd->cmd, cmd->sector, cmd->size, - cmd->csize, c->crypto_attached_size); - err = -EINVAL; - goto err_out_exit; - } - - err = dst_data_recv(st, cdata, cmd->csize); - if (err) - goto err_out_exit; - - cmd->size -= cmd->csize; - return 0; - -err_out_exit: - return err; -} - -/* - * Receive the command and start its processing. - */ -static int dst_recv_processing(struct dst_state *st) -{ - int err = -EINTR; - struct dst_cmd *cmd = st->data; - - /* - * If socket will be reset after this statement, then - * dst_data_recv() will just fail and loop will - * start again, so it can be done without any locks. - * - * st->read_socket is needed to prevents state machine - * breaking between this data reading and subsequent one - * in protocol specific functions during connection reset. - * In case of reset we have to read next command and do - * not expect data for old command to magically appear in - * new connection. - */ - st->read_socket = st->socket; - err = dst_data_recv(st, cmd, sizeof(struct dst_cmd)); - if (err) - goto out_exit; - - dst_convert_cmd(cmd); - - dprintk("%s: cmd: %u, size: %u, csize: %u, id: %llu, " - "sector: %llu, flags: %llx, rw: %llx.\n", - __func__, cmd->cmd, cmd->size, - cmd->csize, cmd->id, cmd->sector, - cmd->flags, cmd->rw); - - /* - * This should catch protocol breakage and random garbage - * instead of commands. - */ - if (unlikely(cmd->csize > st->size - sizeof(struct dst_cmd))) { - err = -EBADMSG; - goto out_exit; - } - - err = -EPROTO; - switch (cmd->cmd) { - case DST_IO_RESPONSE: - err = dst_process_io_response(st); - break; - case DST_IO: - err = dst_process_io(st); - break; - case DST_CFG: - err = dst_process_cfg(st); - break; - case DST_PING: - err = 0; - break; - default: - break; - } - -out_exit: - return err; -} - -/* - * Receiving thread. For the client node we should try to reconnect, - * for accepted client we just drop the state and expect it to reconnect. - */ -static int dst_recv(void *init_data, void *schedule_data) -{ - struct dst_state *st = schedule_data; - struct dst_node *n = init_data; - int err = 0; - - dprintk("%s: start st: %p, n: %p, scan: %lu, need_exit: %d.\n", - __func__, st, n, n->trans_scan_timeout, st->need_exit); - - while (n->trans_scan_timeout && !st->need_exit) { - err = dst_recv_processing(st); - if (err < 0) { - if (!st->ctl.type) - break; - - if (!n->trans_scan_timeout || st->need_exit) - break; - - dst_state_reset(st); - msleep(1000); - } - } - - st->need_exit = 1; - wake_up(&st->thread_wait); - - dprintk("%s: freeing receiving socket st: %p.\n", __func__, st); - dst_state_lock(st); - dst_state_exit_connected(st); - dst_state_unlock(st); - dst_state_put(st); - - dprintk("%s: freed receiving socket st: %p.\n", __func__, st); - - return err; -} - -/* - * Network state dies here and borns couple of lines below. - * This object is the main network state processing engine: - * sending, receiving, reconnections, all network related - * tasks are handled on behalf of the state. - */ -static void dst_state_free(struct dst_state *st) -{ - dprintk("%s: st: %p.\n", __func__, st); - if (st->cleanup) - st->cleanup(st); - kfree(st->data); - kfree(st); -} - -struct dst_state *dst_state_alloc(struct dst_node *n) -{ - struct dst_state *st; - int err = -ENOMEM; - - st = kzalloc(sizeof(struct dst_state), GFP_KERNEL); - if (!st) - goto err_out_exit; - - st->node = n; - st->need_exit = 0; - - st->size = PAGE_SIZE; - st->data = kmalloc(st->size, GFP_KERNEL); - if (!st->data) - goto err_out_free; - - spin_lock_init(&st->request_lock); - INIT_LIST_HEAD(&st->request_list); - - mutex_init(&st->state_lock); - init_waitqueue_head(&st->thread_wait); - - /* - * One for processing thread, another one for node itself. - */ - atomic_set(&st->refcnt, 2); - - dprintk("%s: st: %p, n: %p.\n", __func__, st, st->node); - - return st; - -err_out_free: - kfree(st); -err_out_exit: - return ERR_PTR(err); -} - -int dst_state_schedule_receiver(struct dst_state *st) -{ - return thread_pool_schedule_private(st->node->pool, dst_thread_setup, - dst_recv, st, MAX_SCHEDULE_TIMEOUT, st->node); -} - -/* - * Initialize client's connection to the remote peer: allocate state, - * connect and perform block IO autoconfiguration. - */ -int dst_node_init_connected(struct dst_node *n, struct dst_network_ctl *r) -{ - struct dst_state *st; - int err = -ENOMEM; - - st = dst_state_alloc(n); - if (IS_ERR(st)) { - err = PTR_ERR(st); - goto err_out_exit; - } - memcpy(&st->ctl, r, sizeof(struct dst_network_ctl)); - - err = dst_state_init_connected(st); - if (err) - goto err_out_free_data; - - err = dst_request_remote_config(st); - if (err) - goto err_out_exit_connected; - n->state = st; - - err = dst_state_schedule_receiver(st); - if (err) - goto err_out_exit_connected; - - return 0; - -err_out_exit_connected: - dst_state_exit_connected(st); -err_out_free_data: - dst_state_free(st); -err_out_exit: - n->state = NULL; - return err; -} - -void dst_state_put(struct dst_state *st) -{ - dprintk("%s: st: %p, refcnt: %d.\n", - __func__, st, atomic_read(&st->refcnt)); - if (atomic_dec_and_test(&st->refcnt)) - dst_state_free(st); -} - -/* - * Send block IO to the network one by one using zero-copy ->sendpage(). - */ -int dst_send_bio(struct dst_state *st, struct dst_cmd *cmd, struct bio *bio) -{ - struct bio_vec *bv; - struct dst_crypto_ctl *c = &st->node->crypto; - int err, i = 0; - int flags = MSG_WAITALL; - - err = dst_data_send_header(st->socket, cmd, - sizeof(struct dst_cmd) + c->crypto_attached_size, bio->bi_vcnt); - if (err) - goto err_out_exit; - - bio_for_each_segment(bv, bio, i) { - if (i < bio->bi_vcnt - 1) - flags |= MSG_MORE; - - err = kernel_sendpage(st->socket, bv->bv_page, bv->bv_offset, - bv->bv_len, flags); - if (err <= 0) - goto err_out_exit; - } - - return 0; - -err_out_exit: - dprintk("%s: %d/%d, flags: %x, err: %d.\n", - __func__, i, bio->bi_vcnt, flags, err); - return err; -} - -/* - * Send transaction to the remote peer. - */ -int dst_trans_send(struct dst_trans *t) -{ - int err; - struct dst_state *st = t->n->state; - struct bio *bio = t->bio; - - dst_convert_cmd(&t->cmd); - - dst_state_lock(st); - if (!st->socket) { - err = dst_state_init_connected(st); - if (err) - goto err_out_unlock; - } - - if (bio_data_dir(bio) == WRITE) { - err = dst_send_bio(st, &t->cmd, t->bio); - } else { - err = dst_data_send_header(st->socket, &t->cmd, - sizeof(struct dst_cmd), 0); - } - if (err) - goto err_out_reset; - - dst_state_unlock(st); - return 0; - -err_out_reset: - dst_state_reset_nolock(st); -err_out_unlock: - dst_state_unlock(st); - - return err; -} diff --git a/drivers/staging/dst/thread_pool.c b/drivers/staging/dst/thread_pool.c deleted file mode 100644 index 29a82b2602f3..000000000000 --- a/drivers/staging/dst/thread_pool.c +++ /dev/null @@ -1,348 +0,0 @@ -/* - * 2007+ Copyright (c) Evgeniy Polyakov - * All rights reserved. - * - * 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. - */ - -#include -#include -#include -#include - -/* - * Thread pool abstraction allows to schedule a work to be performed - * on behalf of kernel thread. One does not operate with threads itself, - * instead user provides setup and cleanup callbacks for thread pool itself, - * and action and cleanup callbacks for each submitted work. - * - * Each worker has private data initialized at creation time and data, - * provided by user at scheduling time. - * - * When action is being performed, thread can not be used by other users, - * instead they will sleep until there is free thread to pick their work. - */ -struct thread_pool_worker { - struct list_head worker_entry; - - struct task_struct *thread; - - struct thread_pool *pool; - - int error; - int has_data; - int need_exit; - unsigned int id; - - wait_queue_head_t wait; - - void *private; - void *schedule_data; - - int (*action)(void *private, void *schedule_data); - void (*cleanup)(void *private); -}; - -static void thread_pool_exit_worker(struct thread_pool_worker *w) -{ - kthread_stop(w->thread); - - w->cleanup(w->private); - kfree(w); -} - -/* - * Called to mark thread as ready and allow users to schedule new work. - */ -static void thread_pool_worker_make_ready(struct thread_pool_worker *w) -{ - struct thread_pool *p = w->pool; - - mutex_lock(&p->thread_lock); - - if (!w->need_exit) { - list_move_tail(&w->worker_entry, &p->ready_list); - w->has_data = 0; - mutex_unlock(&p->thread_lock); - - wake_up(&p->wait); - } else { - p->thread_num--; - list_del(&w->worker_entry); - mutex_unlock(&p->thread_lock); - - thread_pool_exit_worker(w); - } -} - -/* - * Thread action loop: waits until there is new work. - */ -static int thread_pool_worker_func(void *data) -{ - struct thread_pool_worker *w = data; - - while (!kthread_should_stop()) { - wait_event_interruptible(w->wait, - kthread_should_stop() || w->has_data); - - if (kthread_should_stop()) - break; - - if (!w->has_data) - continue; - - w->action(w->private, w->schedule_data); - thread_pool_worker_make_ready(w); - } - - return 0; -} - -/* - * Remove single worker without specifying which one. - */ -void thread_pool_del_worker(struct thread_pool *p) -{ - struct thread_pool_worker *w = NULL; - - while (!w && p->thread_num) { - wait_event(p->wait, !list_empty(&p->ready_list) || - !p->thread_num); - - dprintk("%s: locking list_empty: %d, thread_num: %d.\n", - __func__, list_empty(&p->ready_list), - p->thread_num); - - mutex_lock(&p->thread_lock); - if (!list_empty(&p->ready_list)) { - w = list_first_entry(&p->ready_list, - struct thread_pool_worker, - worker_entry); - - dprintk("%s: deleting w: %p, thread_num: %d, " - "list: %p [%p.%p].\n", __func__, - w, p->thread_num, &p->ready_list, - p->ready_list.prev, p->ready_list.next); - - p->thread_num--; - list_del(&w->worker_entry); - } - mutex_unlock(&p->thread_lock); - } - - if (w) - thread_pool_exit_worker(w); - dprintk("%s: deleted w: %p, thread_num: %d.\n", - __func__, w, p->thread_num); -} - -/* - * Remove a worker with given ID. - */ -void thread_pool_del_worker_id(struct thread_pool *p, unsigned int id) -{ - struct thread_pool_worker *w; - int found = 0; - - mutex_lock(&p->thread_lock); - list_for_each_entry(w, &p->ready_list, worker_entry) { - if (w->id == id) { - found = 1; - p->thread_num--; - list_del(&w->worker_entry); - break; - } - } - - if (!found) { - list_for_each_entry(w, &p->active_list, worker_entry) { - if (w->id == id) { - w->need_exit = 1; - break; - } - } - } - mutex_unlock(&p->thread_lock); - - if (found) - thread_pool_exit_worker(w); -} - -/* - * Add new worker thread with given parameters. - * If initialization callback fails, return error. - */ -int thread_pool_add_worker(struct thread_pool *p, - char *name, - unsigned int id, - void *(*init)(void *private), - void (*cleanup)(void *private), - void *private) -{ - struct thread_pool_worker *w; - int err = -ENOMEM; - - w = kzalloc(sizeof(struct thread_pool_worker), GFP_KERNEL); - if (!w) - goto err_out_exit; - - w->pool = p; - init_waitqueue_head(&w->wait); - w->cleanup = cleanup; - w->id = id; - - w->thread = kthread_run(thread_pool_worker_func, w, "%s", name); - if (IS_ERR(w->thread)) { - err = PTR_ERR(w->thread); - goto err_out_free; - } - - w->private = init(private); - if (IS_ERR(w->private)) { - err = PTR_ERR(w->private); - goto err_out_stop_thread; - } - - mutex_lock(&p->thread_lock); - list_add_tail(&w->worker_entry, &p->ready_list); - p->thread_num++; - mutex_unlock(&p->thread_lock); - - return 0; - -err_out_stop_thread: - kthread_stop(w->thread); -err_out_free: - kfree(w); -err_out_exit: - return err; -} - -/* - * Destroy the whole pool. - */ -void thread_pool_destroy(struct thread_pool *p) -{ - while (p->thread_num) { - dprintk("%s: num: %d.\n", __func__, p->thread_num); - thread_pool_del_worker(p); - } - - kfree(p); -} - -/* - * Create a pool with given number of threads. - * They will have sequential IDs started from zero. - */ -struct thread_pool *thread_pool_create(int num, char *name, - void *(*init)(void *private), - void (*cleanup)(void *private), - void *private) -{ - struct thread_pool_worker *w, *tmp; - struct thread_pool *p; - int err = -ENOMEM; - int i; - - p = kzalloc(sizeof(struct thread_pool), GFP_KERNEL); - if (!p) - goto err_out_exit; - - init_waitqueue_head(&p->wait); - mutex_init(&p->thread_lock); - INIT_LIST_HEAD(&p->ready_list); - INIT_LIST_HEAD(&p->active_list); - p->thread_num = 0; - - for (i = 0; i < num; ++i) { - err = thread_pool_add_worker(p, name, i, init, - cleanup, private); - if (err) - goto err_out_free_all; - } - - return p; - -err_out_free_all: - list_for_each_entry_safe(w, tmp, &p->ready_list, worker_entry) { - list_del(&w->worker_entry); - thread_pool_exit_worker(w); - } - kfree(p); -err_out_exit: - return ERR_PTR(err); -} - -/* - * Schedule execution of the action on a given thread, - * provided ID pointer has to match previously stored - * private data. - */ -int thread_pool_schedule_private(struct thread_pool *p, - int (*setup)(void *private, void *data), - int (*action)(void *private, void *data), - void *data, long timeout, void *id) -{ - struct thread_pool_worker *w, *tmp, *worker = NULL; - int err = 0; - - while (!worker && !err) { - timeout = wait_event_interruptible_timeout(p->wait, - !list_empty(&p->ready_list), - timeout); - - if (!timeout) { - err = -ETIMEDOUT; - break; - } - - worker = NULL; - mutex_lock(&p->thread_lock); - list_for_each_entry_safe(w, tmp, &p->ready_list, worker_entry) { - if (id && id != w->private) - continue; - - worker = w; - - list_move_tail(&w->worker_entry, &p->active_list); - - err = setup(w->private, data); - if (!err) { - w->schedule_data = data; - w->action = action; - w->has_data = 1; - wake_up(&w->wait); - } else { - list_move_tail(&w->worker_entry, - &p->ready_list); - } - - break; - } - mutex_unlock(&p->thread_lock); - } - - return err; -} - -/* - * Schedule execution on arbitrary thread from the pool. - */ -int thread_pool_schedule(struct thread_pool *p, - int (*setup)(void *private, void *data), - int (*action)(void *private, void *data), - void *data, long timeout) -{ - return thread_pool_schedule_private(p, setup, - action, data, timeout, NULL); -} diff --git a/drivers/staging/dst/trans.c b/drivers/staging/dst/trans.c deleted file mode 100644 index 1c36a6bc31d5..000000000000 --- a/drivers/staging/dst/trans.c +++ /dev/null @@ -1,337 +0,0 @@ -/* - * 2007+ Copyright (c) Evgeniy Polyakov - * All rights reserved. - * - * 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. - */ - -#include -#include -#include -#include - -/* - * Transaction memory pool size. - */ -static int dst_mempool_num = 32; -module_param(dst_mempool_num, int, 0644); - -/* - * Transaction tree management. - */ -static inline int dst_trans_cmp(dst_gen_t gen, dst_gen_t new) -{ - if (gen < new) - return 1; - if (gen > new) - return -1; - return 0; -} - -struct dst_trans *dst_trans_search(struct dst_node *node, dst_gen_t gen) -{ - struct rb_root *root = &node->trans_root; - struct rb_node *n = root->rb_node; - struct dst_trans *t, *ret = NULL; - int cmp; - - while (n) { - t = rb_entry(n, struct dst_trans, trans_entry); - - cmp = dst_trans_cmp(t->gen, gen); - if (cmp < 0) - n = n->rb_left; - else if (cmp > 0) - n = n->rb_right; - else { - ret = t; - break; - } - } - - dprintk("%s: %s transaction: id: %llu.\n", __func__, - (ret) ? "found" : "not found", gen); - - return ret; -} - -static int dst_trans_insert(struct dst_trans *new) -{ - struct rb_root *root = &new->n->trans_root; - struct rb_node **n = &root->rb_node, *parent = NULL; - struct dst_trans *ret = NULL, *t; - int cmp; - - while (*n) { - parent = *n; - - t = rb_entry(parent, struct dst_trans, trans_entry); - - cmp = dst_trans_cmp(t->gen, new->gen); - if (cmp < 0) - n = &parent->rb_left; - else if (cmp > 0) - n = &parent->rb_right; - else { - ret = t; - break; - } - } - - new->send_time = jiffies; - if (ret) { - printk(KERN_DEBUG "%s: exist: old: gen: %llu, bio: %llu/%u, " - "send_time: %lu, new: gen: %llu, bio: %llu/%u, " - "send_time: %lu.\n", __func__, - ret->gen, (u64)ret->bio->bi_sector, - ret->bio->bi_size, ret->send_time, - new->gen, (u64)new->bio->bi_sector, - new->bio->bi_size, new->send_time); - return -EEXIST; - } - - rb_link_node(&new->trans_entry, parent, n); - rb_insert_color(&new->trans_entry, root); - - dprintk("%s: inserted: gen: %llu, bio: %llu/%u, send_time: %lu.\n", - __func__, new->gen, (u64)new->bio->bi_sector, - new->bio->bi_size, new->send_time); - - return 0; -} - -int dst_trans_remove_nolock(struct dst_trans *t) -{ - struct dst_node *n = t->n; - - if (t->trans_entry.rb_parent_color) { - rb_erase(&t->trans_entry, &n->trans_root); - t->trans_entry.rb_parent_color = 0; - } - return 0; -} - -int dst_trans_remove(struct dst_trans *t) -{ - int ret; - struct dst_node *n = t->n; - - mutex_lock(&n->trans_lock); - ret = dst_trans_remove_nolock(t); - mutex_unlock(&n->trans_lock); - - return ret; -} - -/* - * When transaction is completed and there are no more users, - * we complete appriate block IO request with given error status. - */ -void dst_trans_put(struct dst_trans *t) -{ - if (atomic_dec_and_test(&t->refcnt)) { - struct bio *bio = t->bio; - - dprintk("%s: completed t: %p, gen: %llu, bio: %p.\n", - __func__, t, t->gen, bio); - - bio_endio(bio, t->error); - bio_put(bio); - - dst_node_put(t->n); - mempool_free(t, t->n->trans_pool); - } -} - -/* - * Process given block IO request: allocate transaction, insert it into the tree - * and send/schedule crypto processing. - */ -int dst_process_bio(struct dst_node *n, struct bio *bio) -{ - struct dst_trans *t; - int err = -ENOMEM; - - t = mempool_alloc(n->trans_pool, GFP_NOFS); - if (!t) - goto err_out_exit; - - t->n = dst_node_get(n); - t->bio = bio; - t->error = 0; - t->retries = 0; - atomic_set(&t->refcnt, 1); - t->gen = atomic_long_inc_return(&n->gen); - - t->enc = bio_data_dir(bio); - dst_bio_to_cmd(bio, &t->cmd, DST_IO, t->gen); - - mutex_lock(&n->trans_lock); - err = dst_trans_insert(t); - mutex_unlock(&n->trans_lock); - if (err) - goto err_out_free; - - dprintk("%s: gen: %llu, bio: %llu/%u, dir/enc: %d, need_crypto: %d.\n", - __func__, t->gen, (u64)bio->bi_sector, - bio->bi_size, t->enc, dst_need_crypto(n)); - - if (dst_need_crypto(n) && t->enc) - dst_trans_crypto(t); - else - dst_trans_send(t); - - return 0; - -err_out_free: - dst_node_put(n); - mempool_free(t, n->trans_pool); -err_out_exit: - bio_endio(bio, err); - bio_put(bio); - return err; -} - -/* - * Scan for timeout/stale transactions. - * Each transaction is being resent multiple times before error completion. - */ -static void dst_trans_scan(struct work_struct *work) -{ - struct dst_node *n = container_of(work, struct dst_node, - trans_work.work); - struct rb_node *rb_node; - struct dst_trans *t; - unsigned long timeout = n->trans_scan_timeout; - int num = 10 * n->trans_max_retries; - - mutex_lock(&n->trans_lock); - - for (rb_node = rb_first(&n->trans_root); rb_node; ) { - t = rb_entry(rb_node, struct dst_trans, trans_entry); - - if (timeout && time_after(t->send_time + timeout, jiffies) - && t->retries == 0) - break; -#if 0 - dprintk("%s: t: %p, gen: %llu, n: %s, retries: %u, max: %u.\n", - __func__, t, t->gen, n->name, - t->retries, n->trans_max_retries); -#endif - if (--num == 0) - break; - - dst_trans_get(t); - - rb_node = rb_next(rb_node); - - if (timeout && (++t->retries < n->trans_max_retries)) { - dst_trans_send(t); - } else { - t->error = -ETIMEDOUT; - dst_trans_remove_nolock(t); - dst_trans_put(t); - } - - dst_trans_put(t); - } - - mutex_unlock(&n->trans_lock); - - /* - * If no timeout specified then system is in the middle of exiting - * process, so no need to reschedule scanning process again. - */ - if (timeout) { - if (!num) - timeout = HZ; - schedule_delayed_work(&n->trans_work, timeout); - } -} - -/* - * Flush all transactions and mark them as timed out. - * Destroy transaction pools. - */ -void dst_node_trans_exit(struct dst_node *n) -{ - struct dst_trans *t; - struct rb_node *rb_node; - - if (!n->trans_cache) - return; - - dprintk("%s: n: %p, cancelling the work.\n", __func__, n); - cancel_delayed_work_sync(&n->trans_work); - flush_scheduled_work(); - dprintk("%s: n: %p, work has been cancelled.\n", __func__, n); - - for (rb_node = rb_first(&n->trans_root); rb_node; ) { - t = rb_entry(rb_node, struct dst_trans, trans_entry); - - dprintk("%s: t: %p, gen: %llu, n: %s.\n", - __func__, t, t->gen, n->name); - - rb_node = rb_next(rb_node); - - t->error = -ETIMEDOUT; - dst_trans_remove_nolock(t); - dst_trans_put(t); - } - - mempool_destroy(n->trans_pool); - kmem_cache_destroy(n->trans_cache); -} - -/* - * Initialize transaction storage for given node. - * Transaction stores not only control information, - * but also network command and crypto data (if needed) - * to reduce number of allocations. Thus transaction size - * differs from node to node. - */ -int dst_node_trans_init(struct dst_node *n, unsigned int size) -{ - /* - * We need this, since node with given name can be dropped from the - * hash table, but be still alive, so subsequent creation of the node - * with the same name may collide with existing cache name. - */ - - snprintf(n->cache_name, sizeof(n->cache_name), "%s-%p", n->name, n); - - n->trans_cache = kmem_cache_create(n->cache_name, - size + n->crypto.crypto_attached_size, - 0, 0, NULL); - if (!n->trans_cache) - goto err_out_exit; - - n->trans_pool = mempool_create_slab_pool(dst_mempool_num, - n->trans_cache); - if (!n->trans_pool) - goto err_out_cache_destroy; - - mutex_init(&n->trans_lock); - n->trans_root = RB_ROOT; - - INIT_DELAYED_WORK(&n->trans_work, dst_trans_scan); - schedule_delayed_work(&n->trans_work, n->trans_scan_timeout); - - dprintk("%s: n: %p, size: %u, crypto: %u.\n", - __func__, n, size, n->crypto.crypto_attached_size); - - return 0; - -err_out_cache_destroy: - kmem_cache_destroy(n->trans_cache); -err_out_exit: - return -ENOMEM; -} diff --git a/include/linux/dst.h b/include/linux/dst.h deleted file mode 100644 index e26fed84b1aa..000000000000 --- a/include/linux/dst.h +++ /dev/null @@ -1,587 +0,0 @@ -/* - * 2007+ Copyright (c) Evgeniy Polyakov - * All rights reserved. - * - * 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. - */ - -#ifndef __DST_H -#define __DST_H - -#include -#include - -#define DST_NAMELEN 32 -#define DST_NAME "dst" - -enum { - /* Remove node with given id from storage */ - DST_DEL_NODE = 0, - /* Add remote node with given id to the storage */ - DST_ADD_REMOTE, - /* Add local node with given id to the storage to be exported and used by remote peers */ - DST_ADD_EXPORT, - /* Crypto initialization command (hash/cipher used to protect the connection) */ - DST_CRYPTO, - /* Security attributes for given connection (permissions for example) */ - DST_SECURITY, - /* Register given node in the block layer subsystem */ - DST_START, - DST_CMD_MAX -}; - -struct dst_ctl -{ - /* Storage name */ - char name[DST_NAMELEN]; - /* Command flags */ - __u32 flags; - /* Command itself (see above) */ - __u32 cmd; - /* Maximum number of pages per single request in this device */ - __u32 max_pages; - /* Stale/error transaction scanning timeout in milliseconds */ - __u32 trans_scan_timeout; - /* Maximum number of retry sends before completing transaction as broken */ - __u32 trans_max_retries; - /* Storage size */ - __u64 size; -}; - -/* Reply command carries completion status */ -struct dst_ctl_ack -{ - struct cn_msg msg; - int error; - int unused[3]; -}; - -/* - * Unfortunaltely socket address structure is not exported to userspace - * and is redefined there. - */ -#define SADDR_MAX_DATA 128 - -struct saddr { - /* address family, AF_xxx */ - unsigned short sa_family; - /* 14 bytes of protocol address */ - char sa_data[SADDR_MAX_DATA]; - /* Number of bytes used in sa_data */ - unsigned short sa_data_len; -}; - -/* Address structure */ -struct dst_network_ctl -{ - /* Socket type: datagram, stream...*/ - unsigned int type; - /* Let me guess, is it a Jupiter diameter? */ - unsigned int proto; - /* Peer's address */ - struct saddr addr; -}; - -struct dst_crypto_ctl -{ - /* Cipher and hash names */ - char cipher_algo[DST_NAMELEN]; - char hash_algo[DST_NAMELEN]; - - /* Key sizes. Can be zero for digest for example */ - unsigned int cipher_keysize, hash_keysize; - /* Alignment. Calculated by the DST itself. */ - unsigned int crypto_attached_size; - /* Number of threads to perform crypto operations */ - int thread_num; -}; - -/* Export security attributes have this bits checked in when client connects */ -#define DST_PERM_READ (1<<0) -#define DST_PERM_WRITE (1<<1) - -/* - * Right now it is simple model, where each remote address - * is assigned to set of permissions it is allowed to perform. - * In real world block device does not know anything but - * reading and writing, so it should be more than enough. - */ -struct dst_secure_user -{ - unsigned int permissions; - struct saddr addr; -}; - -/* - * Export control command: device to export and network address to accept - * clients to work with given device - */ -struct dst_export_ctl -{ - char device[DST_NAMELEN]; - struct dst_network_ctl ctl; -}; - -enum { - DST_CFG = 1, /* Request remote configuration */ - DST_IO, /* IO command */ - DST_IO_RESPONSE, /* IO response */ - DST_PING, /* Keepalive message */ - DST_NCMD_MAX, -}; - -struct dst_cmd -{ - /* Network command itself, see above */ - __u32 cmd; - /* - * Size of the attached data - * (in most cases, for READ command it means how many bytes were requested) - */ - __u32 size; - /* Crypto size: number of attached bytes with digest/hmac */ - __u32 csize; - /* Here we can carry secret data */ - __u32 reserved; - /* Read/write bits, see how they are encoded in bio structure */ - __u64 rw; - /* BIO flags */ - __u64 flags; - /* Unique command id (like transaction ID) */ - __u64 id; - /* Sector to start IO from */ - __u64 sector; - /* Hash data is placed after this header */ - __u8 hash[0]; -}; - -/* - * Convert command to/from network byte order. - * We do not use hton*() functions, since there is - * no 64-bit implementation. - */ -static inline void dst_convert_cmd(struct dst_cmd *c) -{ - c->cmd = __cpu_to_be32(c->cmd); - c->csize = __cpu_to_be32(c->csize); - c->size = __cpu_to_be32(c->size); - c->sector = __cpu_to_be64(c->sector); - c->id = __cpu_to_be64(c->id); - c->flags = __cpu_to_be64(c->flags); - c->rw = __cpu_to_be64(c->rw); -} - -/* Transaction id */ -typedef __u64 dst_gen_t; - -#ifdef __KERNEL__ - -#include -#include -#include -#include -#include -#include -#include - -#ifdef CONFIG_DST_DEBUG -#define dprintk(f, a...) printk(KERN_NOTICE f, ##a) -#else -static inline void __attribute__ ((format (printf, 1, 2))) - dprintk(const char *fmt, ...) {} -#endif - -struct dst_node; - -struct dst_trans -{ - /* DST node we are working with */ - struct dst_node *n; - - /* Entry inside transaction tree */ - struct rb_node trans_entry; - - /* Merlin kills this transaction when this memory cell equals zero */ - atomic_t refcnt; - - /* How this transaction should be processed by crypto engine */ - short enc; - /* How many times this transaction was resent */ - short retries; - /* Completion status */ - int error; - - /* When did we send it to the remote peer */ - long send_time; - - /* My name is... - * Well, computers does not speak, they have unique id instead */ - dst_gen_t gen; - - /* Block IO we are working with */ - struct bio *bio; - - /* Network command for above block IO request */ - struct dst_cmd cmd; -}; - -struct dst_crypto_engine -{ - /* What should we do with all block requests */ - struct crypto_hash *hash; - struct crypto_ablkcipher *cipher; - - /* Pool of pages used to encrypt data into before sending */ - int page_num; - struct page **pages; - - /* What to do with current request */ - int enc; - /* Who we are and where do we go */ - struct scatterlist *src, *dst; - - /* Maximum timeout waiting for encryption to be completed */ - long timeout; - /* IV is a 64-bit sequential counter */ - u64 iv; - - /* Secret data */ - void *private; - - /* Cached temporary data lives here */ - int size; - void *data; -}; - -struct dst_state -{ - /* The main state protection */ - struct mutex state_lock; - - /* Polling machinery for sockets */ - wait_queue_t wait; - wait_queue_head_t *whead; - /* Most of events are being waited here */ - wait_queue_head_t thread_wait; - - /* Who owns this? */ - struct dst_node *node; - - /* Network address for this state */ - struct dst_network_ctl ctl; - - /* Permissions to work with: read-only or rw connection */ - u32 permissions; - - /* Called when we need to clean private data */ - void (* cleanup)(struct dst_state *st); - - /* Used by the server: BIO completion queues BIOs here */ - struct list_head request_list; - spinlock_t request_lock; - - /* Guess what? No, it is not number of planets */ - atomic_t refcnt; - - /* This flags is set when connection should be dropped */ - int need_exit; - - /* - * Socket to work with. Second pointer is used for - * lockless check if socket was changed before performing - * next action (like working with cached polling result) - */ - struct socket *socket, *read_socket; - - /* Cached preallocated data */ - void *data; - unsigned int size; - - /* Currently processed command */ - struct dst_cmd cmd; -}; - -struct dst_info -{ - /* Device size */ - u64 size; - - /* Local device name for export devices */ - char local[DST_NAMELEN]; - - /* Network setup */ - struct dst_network_ctl net; - - /* Sysfs bits use this */ - struct device device; -}; - -struct dst_node -{ - struct list_head node_entry; - - /* Hi, my name is stored here */ - char name[DST_NAMELEN]; - /* My cache name is stored here */ - char cache_name[DST_NAMELEN]; - - /* Block device attached to given node. - * Only valid for exporting nodes */ - struct block_device *bdev; - /* Network state machine for given peer */ - struct dst_state *state; - - /* Block IO machinery */ - struct request_queue *queue; - struct gendisk *disk; - - /* Number of threads in processing pool */ - int thread_num; - /* Maximum number of pages in single IO */ - int max_pages; - - /* I'm that big in bytes */ - loff_t size; - - /* Exported to userspace node information */ - struct dst_info *info; - - /* - * Security attribute list. - * Used only by exporting node currently. - */ - struct list_head security_list; - struct mutex security_lock; - - /* - * When this unerflows below zero, university collapses. - * But this will not happen, since node will be freed, - * when reference counter reaches zero. - */ - atomic_t refcnt; - - /* How precisely should I be started? */ - int (*start)(struct dst_node *); - - /* Crypto capabilities */ - struct dst_crypto_ctl crypto; - u8 *hash_key; - u8 *cipher_key; - - /* Pool of processing thread */ - struct thread_pool *pool; - - /* Transaction IDs live here */ - atomic_long_t gen; - - /* - * How frequently and how many times transaction - * tree should be scanned to drop stale objects. - */ - long trans_scan_timeout; - int trans_max_retries; - - /* Small gnomes live here */ - struct rb_root trans_root; - struct mutex trans_lock; - - /* - * Transaction cache/memory pool. - * It is big enough to contain not only transaction - * itself, but additional crypto data (digest/hmac). - */ - struct kmem_cache *trans_cache; - mempool_t *trans_pool; - - /* This entity scans transaction tree */ - struct delayed_work trans_work; - - wait_queue_head_t wait; -}; - -/* Kernel representation of the security attribute */ -struct dst_secure -{ - struct list_head sec_entry; - struct dst_secure_user sec; -}; - -int dst_process_bio(struct dst_node *n, struct bio *bio); - -int dst_node_init_connected(struct dst_node *n, struct dst_network_ctl *r); -int dst_node_init_listened(struct dst_node *n, struct dst_export_ctl *le); - -static inline struct dst_state *dst_state_get(struct dst_state *st) -{ - BUG_ON(atomic_read(&st->refcnt) == 0); - atomic_inc(&st->refcnt); - return st; -} - -void dst_state_put(struct dst_state *st); - -struct dst_state *dst_state_alloc(struct dst_node *n); -int dst_state_socket_create(struct dst_state *st); -void dst_state_socket_release(struct dst_state *st); - -void dst_state_exit_connected(struct dst_state *st); - -int dst_state_schedule_receiver(struct dst_state *st); - -void dst_dump_addr(struct socket *sk, struct sockaddr *sa, char *str); - -static inline void dst_state_lock(struct dst_state *st) -{ - mutex_lock(&st->state_lock); -} - -static inline void dst_state_unlock(struct dst_state *st) -{ - mutex_unlock(&st->state_lock); -} - -void dst_poll_exit(struct dst_state *st); -int dst_poll_init(struct dst_state *st); - -static inline unsigned int dst_state_poll(struct dst_state *st) -{ - unsigned int revents = POLLHUP | POLLERR; - - dst_state_lock(st); - if (st->socket) - revents = st->socket->ops->poll(NULL, st->socket, NULL); - dst_state_unlock(st); - - return revents; -} - -static inline int dst_thread_setup(void *private, void *data) -{ - return 0; -} - -void dst_node_put(struct dst_node *n); - -static inline struct dst_node *dst_node_get(struct dst_node *n) -{ - atomic_inc(&n->refcnt); - return n; -} - -int dst_data_recv(struct dst_state *st, void *data, unsigned int size); -int dst_recv_cdata(struct dst_state *st, void *cdata); -int dst_data_send_header(struct socket *sock, - void *data, unsigned int size, int more); - -int dst_send_bio(struct dst_state *st, struct dst_cmd *cmd, struct bio *bio); - -int dst_process_io(struct dst_state *st); -int dst_export_crypto(struct dst_node *n, struct bio *bio); -int dst_export_send_bio(struct bio *bio); -int dst_start_export(struct dst_node *n); - -int __init dst_export_init(void); -void dst_export_exit(void); - -/* Private structure for export block IO requests */ -struct dst_export_priv -{ - struct list_head request_entry; - struct dst_state *state; - struct bio *bio; - struct dst_cmd cmd; -}; - -static inline void dst_trans_get(struct dst_trans *t) -{ - atomic_inc(&t->refcnt); -} - -struct dst_trans *dst_trans_search(struct dst_node *node, dst_gen_t gen); -int dst_trans_remove(struct dst_trans *t); -int dst_trans_remove_nolock(struct dst_trans *t); -void dst_trans_put(struct dst_trans *t); - -/* - * Convert bio into network command. - */ -static inline void dst_bio_to_cmd(struct bio *bio, struct dst_cmd *cmd, - u32 command, u64 id) -{ - cmd->cmd = command; - cmd->flags = (bio->bi_flags << BIO_POOL_BITS) >> BIO_POOL_BITS; - cmd->rw = bio->bi_rw; - cmd->size = bio->bi_size; - cmd->csize = 0; - cmd->id = id; - cmd->sector = bio->bi_sector; -}; - -int dst_trans_send(struct dst_trans *t); -int dst_trans_crypto(struct dst_trans *t); - -int dst_node_crypto_init(struct dst_node *n, struct dst_crypto_ctl *ctl); -void dst_node_crypto_exit(struct dst_node *n); - -static inline int dst_need_crypto(struct dst_node *n) -{ - struct dst_crypto_ctl *c = &n->crypto; - /* - * Logical OR is appropriate here, but boolean one produces - * more optimal code, so it is used instead. - */ - return (c->hash_algo[0] | c->cipher_algo[0]); -} - -int dst_node_trans_init(struct dst_node *n, unsigned int size); -void dst_node_trans_exit(struct dst_node *n); - -/* - * Pool of threads. - * Ready list contains threads currently free to be used, - * active one contains threads with some work scheduled for them. - * Caller can wait in given queue when thread is ready. - */ -struct thread_pool -{ - int thread_num; - struct mutex thread_lock; - struct list_head ready_list, active_list; - - wait_queue_head_t wait; -}; - -void thread_pool_del_worker(struct thread_pool *p); -void thread_pool_del_worker_id(struct thread_pool *p, unsigned int id); -int thread_pool_add_worker(struct thread_pool *p, - char *name, - unsigned int id, - void *(* init)(void *data), - void (* cleanup)(void *data), - void *data); - -void thread_pool_destroy(struct thread_pool *p); -struct thread_pool *thread_pool_create(int num, char *name, - void *(* init)(void *data), - void (* cleanup)(void *data), - void *data); - -int thread_pool_schedule(struct thread_pool *p, - int (* setup)(void *stored_private, void *setup_data), - int (* action)(void *stored_private, void *setup_data), - void *setup_data, long timeout); -int thread_pool_schedule_private(struct thread_pool *p, - int (* setup)(void *private, void *data), - int (* action)(void *private, void *data), - void *data, long timeout, void *id); - -#endif /* __KERNEL__ */ -#endif /* __DST_H */ From d4c3a56587af3edbe5f618b20e800e9f9fde13cb Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Fri, 27 Nov 2009 12:00:53 +0000 Subject: [PATCH 04/19] Staging: comedi: usbdux.c: fix locking up of the driver when the comedi ringbuffer runs empty Jan-Matthias Braun spotted a bug which locks up the driver when the comedi ring buffer runs empty and provided a patch. The driver would still send the data to comedi but the reader won't wake up any more. What's required is setting the flag COMEDI_CB_BLOCK after new data has arrived which wakes up the reader and therefore the read() command. Signed-off-by: Bernd Porr Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/usbdux.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c index 06c020466298..9a1b559c4b0d 100644 --- a/drivers/staging/comedi/drivers/usbdux.c +++ b/drivers/staging/comedi/drivers/usbdux.c @@ -1,4 +1,4 @@ -#define DRIVER_VERSION "v2.3" +#define DRIVER_VERSION "v2.4" #define DRIVER_AUTHOR "Bernd Porr, BerndPorr@f2s.com" #define DRIVER_DESC "Stirling/ITL USB-DUX -- Bernd.Porr@f2s.com" /* @@ -81,6 +81,8 @@ sampling rate. If you sample two channels you get 4kHz and so on. * 2.1: changed PWM API * 2.2: added firmware kernel request to fix an udev problem * 2.3: corrected a bug in bulk timeouts which were far too short + * 2.4: fixed a bug which causes the driver to hang when it ran out of data. + * Thanks to Jan-Matthias Braun and Ian to spot the bug and fix it. * */ @@ -532,6 +534,7 @@ static void usbduxsub_ai_IsocIrq(struct urb *urb) } } /* tell comedi that data is there */ + s->async->events |= COMEDI_CB_BLOCK | COMEDI_CB_EOS; comedi_event(this_usbduxsub->comedidev, s); } From d103bef45180892515345e761f42db5601de9846 Mon Sep 17 00:00:00 2001 From: Bernd Porr Date: Fri, 27 Nov 2009 12:07:48 +0000 Subject: [PATCH 05/19] Staging: comedi: removed "depricated" from COMEDI_CB_BLOCK The flag COMEDI_CB_BLOCK was marked as "depricated in the header file". However, this flag is important to wake up the data-reader (and writer) after new data has arrived from(for) the DAQ card. Signed-off-by: Bernd Porr Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/comedi.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/comedi/comedi.h b/drivers/staging/comedi/comedi.h index ccc5cdc008c6..b559a9c2f857 100644 --- a/drivers/staging/comedi/comedi.h +++ b/drivers/staging/comedi/comedi.h @@ -451,7 +451,7 @@ #define COMEDI_CB_EOS 1 /* end of scan */ #define COMEDI_CB_EOA 2 /* end of acquisition */ -#define COMEDI_CB_BLOCK 4 /* DEPRECATED: convenient block size */ +#define COMEDI_CB_BLOCK 4 /* data has arrived: wakes up read() / write() */ #define COMEDI_CB_EOBUF 8 /* DEPRECATED: end of buffer */ #define COMEDI_CB_ERROR 16 /* card error during acquisition */ #define COMEDI_CB_OVERFLOW 32 /* buffer overflow/underflow */ From fa5c5f4ce0c9ba03a670c640cad17e14cb35678b Mon Sep 17 00:00:00 2001 From: Ian Abbott Date: Mon, 30 Nov 2009 10:59:27 +0000 Subject: [PATCH 06/19] Staging: comedi: jr3_pci: Don't ioremap too much space. Check result. For the JR3/PCI cards, the size of the PCIBAR0 region depends on the number of channels. Don't try and ioremap space for 4 channels if the card has fewer channels. Also check for ioremap failure. Thanks to Anders Blomdell for input and Sami Hussein for testing. Signed-off-by: Ian Abbott Signed-off-by: Greg Kroah-Hartman --- drivers/staging/comedi/drivers/jr3_pci.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/staging/comedi/drivers/jr3_pci.c b/drivers/staging/comedi/drivers/jr3_pci.c index 0d2c2eb23b23..bd397840dcba 100644 --- a/drivers/staging/comedi/drivers/jr3_pci.c +++ b/drivers/staging/comedi/drivers/jr3_pci.c @@ -849,8 +849,11 @@ static int jr3_pci_attach(struct comedi_device *dev, } devpriv->pci_enabled = 1; - devpriv->iobase = - ioremap(pci_resource_start(card, 0), sizeof(struct jr3_t)); + devpriv->iobase = ioremap(pci_resource_start(card, 0), + offsetof(struct jr3_t, channel[devpriv->n_channels])); + if (!devpriv->iobase) + return -ENOMEM; + result = alloc_subdevices(dev, devpriv->n_channels); if (result < 0) goto out; From aad445f8ccd554cd3013af7bd0a6cfae599a2505 Mon Sep 17 00:00:00 2001 From: Roel Kluin Date: Fri, 20 Nov 2009 20:12:33 +0100 Subject: [PATCH 07/19] Staging: rtl8192su: fix test for negative error in rtl8192_rx_isr() The error tested for is negative Signed-off-by: Roel Kluin Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192su/r8192U_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/rtl8192su/r8192U_core.c b/drivers/staging/rtl8192su/r8192U_core.c index 66274d7666ff..b492ff588b8c 100644 --- a/drivers/staging/rtl8192su/r8192U_core.c +++ b/drivers/staging/rtl8192su/r8192U_core.c @@ -1501,7 +1501,7 @@ static void rtl8192_rx_isr(struct urb *urb) urb->context = skb; skb_queue_tail(&priv->rx_queue, skb); err = usb_submit_urb(urb, GFP_ATOMIC); - if(err && err != EPERM) + if(err && err != -EPERM) printk("can not submit rxurb, err is %x,URB status is %x\n",err,urb->status); } From df574b8ecfb3a84af96229f336a6be88ca4a7055 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Thu, 17 Dec 2009 01:16:00 +0200 Subject: [PATCH 08/19] Staging: fix rtl8187se compilation errors with mac80211 This patch fixes compilation problems that were caused by function naming conflicts between the rtl8187se driver and the mac80211 stack. Signed-off-by: George Kadianakis Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8187se/ieee80211/ieee80211.h | 10 +++++----- drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c | 2 +- .../rtl8187se/ieee80211/ieee80211_softmac.c | 14 +++++++------- drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c | 2 +- drivers/staging/rtl8187se/r8180_core.c | 10 +++++----- drivers/staging/rtl8187se/r8180_wx.c | 2 +- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211.h b/drivers/staging/rtl8187se/ieee80211/ieee80211.h index 3222c22152fb..0d490c164db6 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211.h +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211.h @@ -1318,13 +1318,13 @@ extern int ieee80211_encrypt_fragment( struct sk_buff *frag, int hdr_len); -extern int ieee80211_xmit(struct sk_buff *skb, +extern int ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev); extern void ieee80211_txb_free(struct ieee80211_txb *); /* ieee80211_rx.c */ -extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, +extern int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats); extern void ieee80211_rx_mgt(struct ieee80211_device *ieee, struct ieee80211_hdr_4addr *header, @@ -1376,8 +1376,8 @@ extern void ieee80211_stop_protocol(struct ieee80211_device *ieee); extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee); extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee); extern void ieee80211_reset_queue(struct ieee80211_device *ieee); -extern void ieee80211_wake_queue(struct ieee80211_device *ieee); -extern void ieee80211_stop_queue(struct ieee80211_device *ieee); +extern void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee); +extern void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee); extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee); extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee); extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee); @@ -1385,7 +1385,7 @@ extern int ieee80211_wpa_supplicant_ioctl(struct ieee80211_device *ieee, struct extern void notify_wx_assoc_event(struct ieee80211_device *ieee); extern void ieee80211_ps_tx_ack(struct ieee80211_device *ieee, short success); extern void SendDisassociation(struct ieee80211_device *ieee,u8* asSta,u8 asRsn); -extern void ieee80211_start_scan(struct ieee80211_device *ieee); +extern void ieee80211_rtl_start_scan(struct ieee80211_device *ieee); //Add for RF power on power off by lizhaoming 080512 extern void SendDisassociation(struct ieee80211_device *ieee, diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c index f882dd8cf9b5..9128c181bc7d 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_rx.c @@ -469,7 +469,7 @@ drop: /* All received frames are sent to this function. @skb contains the frame in * IEEE 802.11 format, i.e., in the format it was sent over air. * This function is called only as a tasklet (software IRQ). */ -int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, +int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats) { struct net_device *dev = ieee->dev; diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c index 1fe19c39d702..c7c645af0ebb 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_softmac.c @@ -689,7 +689,7 @@ void ieee80211_stop_scan(struct ieee80211_device *ieee) } /* called with ieee->lock held */ -void ieee80211_start_scan(struct ieee80211_device *ieee) +void ieee80211_rtl_start_scan(struct ieee80211_device *ieee) { if(IS_DOT11D_ENABLE(ieee) ) { @@ -1196,7 +1196,7 @@ void ieee80211_associate_step1(struct ieee80211_device *ieee) } } -void ieee80211_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen) +void ieee80211_rtl_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen) { u8 *c; struct sk_buff *skb; @@ -1898,7 +1898,7 @@ associate_complete: ieee80211_associate_step2(ieee); }else{ - ieee80211_auth_challenge(ieee, challenge, chlen); + ieee80211_rtl_auth_challenge(ieee, challenge, chlen); } }else{ ieee->softmac_stats.rx_auth_rs_err++; @@ -2047,7 +2047,7 @@ void ieee80211_reset_queue(struct ieee80211_device *ieee) } -void ieee80211_wake_queue(struct ieee80211_device *ieee) +void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee) { unsigned long flags; @@ -2089,7 +2089,7 @@ exit : } -void ieee80211_stop_queue(struct ieee80211_device *ieee) +void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee) { //unsigned long flags; //spin_lock_irqsave(&ieee->lock,flags); @@ -2301,7 +2301,7 @@ void ieee80211_start_bss(struct ieee80211_device *ieee) //#else if (ieee->state == IEEE80211_NOLINK){ ieee->actscanning = true; - ieee80211_start_scan(ieee); + ieee80211_rtl_start_scan(ieee); } //#endif spin_unlock_irqrestore(&ieee->lock, flags); @@ -2357,7 +2357,7 @@ void ieee80211_associate_retry_wq(struct work_struct *work) if(ieee->state == IEEE80211_NOLINK){ ieee->beinretry = false; ieee->actscanning = true; - ieee80211_start_scan(ieee); + ieee80211_rtl_start_scan(ieee); } //YJ,add,080828, notify os here if(ieee->state == IEEE80211_NOLINK) diff --git a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c index dde1f2e0cf32..69bd02164b0c 100644 --- a/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c +++ b/drivers/staging/rtl8187se/ieee80211/ieee80211_tx.c @@ -304,7 +304,7 @@ ieee80211_classify(struct sk_buff *skb, struct ieee80211_network *network) } /* SKBs are added to the ieee->tx_queue. */ -int ieee80211_xmit(struct sk_buff *skb, +int ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev) { struct ieee80211_device *ieee = netdev_priv(dev); diff --git a/drivers/staging/rtl8187se/r8180_core.c b/drivers/staging/rtl8187se/r8180_core.c index 57c62b0a402f..e0f13efdb15a 100644 --- a/drivers/staging/rtl8187se/r8180_core.c +++ b/drivers/staging/rtl8187se/r8180_core.c @@ -1811,7 +1811,7 @@ void rtl8180_rx(struct net_device *dev) if(priv->rx_skb->len > 4) skb_trim(priv->rx_skb,priv->rx_skb->len-4); #ifndef RX_DONT_PASS_UL - if(!ieee80211_rx(priv->ieee80211, + if(!ieee80211_rtl_rx(priv->ieee80211, priv->rx_skb, &stats)){ #endif // RX_DONT_PASS_UL @@ -1917,11 +1917,11 @@ rate) if (!check_nic_enought_desc(dev, priority)){ DMESGW("Error: no descriptor left by previous TX (avail %d) ", get_curr_tx_free_desc(dev, priority)); - ieee80211_stop_queue(priv->ieee80211); + ieee80211_rtl_stop_queue(priv->ieee80211); } rtl8180_tx(dev, skb->data, skb->len, priority, morefrag,0,rate); if (!check_nic_enought_desc(dev, priority)) - ieee80211_stop_queue(priv->ieee80211); + ieee80211_rtl_stop_queue(priv->ieee80211); spin_unlock_irqrestore(&priv->tx_lock,flags); } @@ -3680,7 +3680,7 @@ static const struct net_device_ops rtl8180_netdev_ops = { .ndo_set_mac_address = r8180_set_mac_adr, .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = eth_change_mtu, - .ndo_start_xmit = ieee80211_xmit, + .ndo_start_xmit = ieee80211_rtl_xmit, }; static int __devinit rtl8180_pci_probe(struct pci_dev *pdev, @@ -3900,7 +3900,7 @@ void rtl8180_try_wake_queue(struct net_device *dev, int pri) spin_unlock_irqrestore(&priv->tx_lock,flags); if(enough_desc) - ieee80211_wake_queue(priv->ieee80211); + ieee80211_rtl_wake_queue(priv->ieee80211); } void rtl8180_tx_isr(struct net_device *dev, int pri,short error) diff --git a/drivers/staging/rtl8187se/r8180_wx.c b/drivers/staging/rtl8187se/r8180_wx.c index 536cb6e8e796..124cde356cbc 100644 --- a/drivers/staging/rtl8187se/r8180_wx.c +++ b/drivers/staging/rtl8187se/r8180_wx.c @@ -377,7 +377,7 @@ static int r8180_wx_set_scan(struct net_device *dev, struct iw_request_info *a, // queue_work(priv->ieee80211->wq, &priv->ieee80211->wx_sync_scan_wq); //printk("start scan============================>\n"); ieee80211_softmac_ips_scan_syncro(priv->ieee80211); -//ieee80211_start_scan(priv->ieee80211); +//ieee80211_rtl_start_scan(priv->ieee80211); /* intentionally forget to up sem */ // up(&priv->ieee80211->wx_sem); ret = 0; From fb5fe2776d1e2a0645d8aa3286a1d5ddd95b0723 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Thu, 17 Dec 2009 01:18:08 +0200 Subject: [PATCH 09/19] staging: fix rtl8192e compilation errors with mac80211 This patch series fixes compilation problems that were caused by function naming conflicts between the rtl8192e driver and the mac80211 stack. Signed-off-by: George Kadianakis Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/ieee80211.h | 12 +++++----- .../staging/rtl8192e/ieee80211/ieee80211.h | 12 +++++----- .../rtl8192e/ieee80211/ieee80211_module.c | 10 ++++---- .../staging/rtl8192e/ieee80211/ieee80211_rx.c | 2 +- .../rtl8192e/ieee80211/ieee80211_softmac.c | 24 +++++++++---------- .../staging/rtl8192e/ieee80211/ieee80211_tx.c | 2 +- drivers/staging/rtl8192e/r8192E_core.c | 14 +++++------ 7 files changed, 38 insertions(+), 38 deletions(-) diff --git a/drivers/staging/rtl8192e/ieee80211.h b/drivers/staging/rtl8192e/ieee80211.h index 97137ddefff4..3ba9e9e90bda 100644 --- a/drivers/staging/rtl8192e/ieee80211.h +++ b/drivers/staging/rtl8192e/ieee80211.h @@ -303,8 +303,8 @@ enum _ReasonCode{ #define ieee80211_rx_mgt ieee80211_rx_mgt_rsl #define ieee80211_get_beacon ieee80211_get_beacon_rsl -#define ieee80211_wake_queue ieee80211_wake_queue_rsl -#define ieee80211_stop_queue ieee80211_stop_queue_rsl +#define ieee80211_rtl_wake_queue ieee80211_rtl_wake_queue_rsl +#define ieee80211_rtl_stop_queue ieee80211_rtl_stop_queue_rsl #define ieee80211_reset_queue ieee80211_reset_queue_rsl #define ieee80211_softmac_stop_protocol ieee80211_softmac_stop_protocol_rsl #define ieee80211_softmac_start_protocol ieee80211_softmac_start_protocol_rsl @@ -2435,13 +2435,13 @@ extern int ieee80211_encrypt_fragment( struct sk_buff *frag, int hdr_len); -extern int ieee80211_xmit(struct sk_buff *skb, +extern int ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev); extern void ieee80211_txb_free(struct ieee80211_txb *); /* ieee80211_rx.c */ -extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, +extern int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats); extern void ieee80211_rx_mgt(struct ieee80211_device *ieee, struct ieee80211_hdr_4addr *header, @@ -2502,8 +2502,8 @@ extern void ieee80211_stop_protocol(struct ieee80211_device *ieee); extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee); extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee); extern void ieee80211_reset_queue(struct ieee80211_device *ieee); -extern void ieee80211_wake_queue(struct ieee80211_device *ieee); -extern void ieee80211_stop_queue(struct ieee80211_device *ieee); +extern void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee); +extern void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee); extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee); extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee); extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee); diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211.h b/drivers/staging/rtl8192e/ieee80211/ieee80211.h index 83c8452de378..aa76390487bb 100644 --- a/drivers/staging/rtl8192e/ieee80211/ieee80211.h +++ b/drivers/staging/rtl8192e/ieee80211/ieee80211.h @@ -333,8 +333,8 @@ enum _ReasonCode{ #define ieee80211_rx_mgt ieee80211_rx_mgt_rsl #define ieee80211_get_beacon ieee80211_get_beacon_rsl -#define ieee80211_wake_queue ieee80211_wake_queue_rsl -#define ieee80211_stop_queue ieee80211_stop_queue_rsl +#define ieee80211_rtl_wake_queue ieee80211_rtl_wake_queue_rsl +#define ieee80211_rtl_stop_queue ieee80211_rtl_stop_queue_rsl #define ieee80211_reset_queue ieee80211_reset_queue_rsl #define ieee80211_softmac_stop_protocol ieee80211_softmac_stop_protocol_rsl #define ieee80211_softmac_start_protocol ieee80211_softmac_start_protocol_rsl @@ -2546,13 +2546,13 @@ extern int ieee80211_encrypt_fragment( struct sk_buff *frag, int hdr_len); -extern int ieee80211_xmit(struct sk_buff *skb, +extern int ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev); extern void ieee80211_txb_free(struct ieee80211_txb *); /* ieee80211_rx.c */ -extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, +extern int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats); extern void ieee80211_rx_mgt(struct ieee80211_device *ieee, struct ieee80211_hdr_4addr *header, @@ -2613,8 +2613,8 @@ extern void ieee80211_stop_protocol(struct ieee80211_device *ieee); extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee); extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee); extern void ieee80211_reset_queue(struct ieee80211_device *ieee); -extern void ieee80211_wake_queue(struct ieee80211_device *ieee); -extern void ieee80211_stop_queue(struct ieee80211_device *ieee); +extern void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee); +extern void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee); extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee); extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee); extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee); diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_module.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_module.c index 2644155737a8..f43a7db5c78b 100644 --- a/drivers/staging/rtl8192e/ieee80211/ieee80211_module.c +++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_module.c @@ -119,7 +119,7 @@ struct net_device *alloc_ieee80211(int sizeof_priv) ieee = (struct ieee80211_device *)dev->priv; #endif #if 0 - dev->hard_start_xmit = ieee80211_xmit; + dev->hard_start_xmit = ieee80211_rtl_xmit; #endif memset(ieee, 0, sizeof(struct ieee80211_device)+sizeof_priv); @@ -333,7 +333,7 @@ extern void ieee80211_crypto_ccmp_exit(void); extern int ieee80211_crypto_wep_init(void); extern void ieee80211_crypto_wep_exit(void); -int __init ieee80211_init(void) +int __init ieee80211_rtl_init(void) { struct proc_dir_entry *e; int retval; @@ -389,7 +389,7 @@ int __init ieee80211_init(void) return 0; } -void __exit ieee80211_exit(void) +void __exit ieee80211_rtl_exit(void) { if (ieee80211_proc) { remove_proc_entry("debug_level", ieee80211_proc); @@ -412,8 +412,8 @@ module_param(debug, int, 0444); MODULE_PARM_DESC(debug, "debug output mask"); -//module_exit(ieee80211_exit); -//module_init(ieee80211_init); +//module_exit(ieee80211_rtl_exit); +//module_init(ieee80211_rtl_init); #endif #endif diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c index 5dc478b86375..06d91715143c 100644 --- a/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c +++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_rx.c @@ -923,7 +923,7 @@ u8 parse_subframe(struct sk_buff *skb, /* All received frames are sent to this function. @skb contains the frame in * IEEE 802.11 format, i.e., in the format it was sent over air. * This function is called only as a tasklet (software IRQ). */ -int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, +int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats) { struct net_device *dev = ieee->dev; diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c index 593d22825184..6d1ddec39f0e 100644 --- a/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c +++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_softmac.c @@ -684,7 +684,7 @@ void ieee80211_stop_scan(struct ieee80211_device *ieee) } /* called with ieee->lock held */ -void ieee80211_start_scan(struct ieee80211_device *ieee) +void ieee80211_rtl_start_scan(struct ieee80211_device *ieee) { #ifdef ENABLE_DOT11D if(IS_DOT11D_ENABLE(ieee) ) @@ -1430,7 +1430,7 @@ void ieee80211_associate_step1(struct ieee80211_device *ieee) } } -void ieee80211_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen) +void ieee80211_rtl_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen) { u8 *c; struct sk_buff *skb; @@ -2262,7 +2262,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, ieee80211_associate_step2(ieee); }else{ - ieee80211_auth_challenge(ieee, challenge, chlen); + ieee80211_rtl_auth_challenge(ieee, challenge, chlen); } }else{ ieee->softmac_stats.rx_auth_rs_err++; @@ -2376,7 +2376,7 @@ void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device * * to check it any more. * */ //printk("error:no descriptor left@queue_index %d\n", queue_index); - //ieee80211_stop_queue(ieee); + //ieee80211_rtl_stop_queue(ieee); #ifdef USB_TX_DRIVER_AGGREGATION_ENABLE skb_queue_tail(&ieee->skb_drv_aggQ[queue_index], txb->fragments[i]); #else @@ -2440,7 +2440,7 @@ void ieee80211_reset_queue(struct ieee80211_device *ieee) } -void ieee80211_wake_queue(struct ieee80211_device *ieee) +void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee) { unsigned long flags; @@ -2481,7 +2481,7 @@ exit : } -void ieee80211_stop_queue(struct ieee80211_device *ieee) +void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee) { //unsigned long flags; //spin_lock_irqsave(&ieee->lock,flags); @@ -2706,7 +2706,7 @@ void ieee80211_start_bss(struct ieee80211_device *ieee) if (ieee->state == IEEE80211_NOLINK){ ieee->actscanning = true; - ieee80211_start_scan(ieee); + ieee80211_rtl_start_scan(ieee); } spin_unlock_irqrestore(&ieee->lock, flags); } @@ -2775,7 +2775,7 @@ void ieee80211_associate_retry_wq(struct ieee80211_device *ieee) { ieee->is_roaming= false; ieee->actscanning = true; - ieee80211_start_scan(ieee); + ieee80211_rtl_start_scan(ieee); } spin_unlock_irqrestore(&ieee->lock, flags); @@ -3497,8 +3497,8 @@ void notify_wx_assoc_event(struct ieee80211_device *ieee) #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) //EXPORT_SYMBOL(ieee80211_get_beacon); -//EXPORT_SYMBOL(ieee80211_wake_queue); -//EXPORT_SYMBOL(ieee80211_stop_queue); +//EXPORT_SYMBOL(ieee80211_rtl_wake_queue); +//EXPORT_SYMBOL(ieee80211_rtl_stop_queue); //EXPORT_SYMBOL(ieee80211_reset_queue); //EXPORT_SYMBOL(ieee80211_softmac_stop_protocol); //EXPORT_SYMBOL(ieee80211_softmac_start_protocol); @@ -3518,8 +3518,8 @@ void notify_wx_assoc_event(struct ieee80211_device *ieee) //EXPORT_SYMBOL(ieee80211_start_scan_syncro); #else EXPORT_SYMBOL_NOVERS(ieee80211_get_beacon); -EXPORT_SYMBOL_NOVERS(ieee80211_wake_queue); -EXPORT_SYMBOL_NOVERS(ieee80211_stop_queue); +EXPORT_SYMBOL_NOVERS(ieee80211_rtl_wake_queue); +EXPORT_SYMBOL_NOVERS(ieee80211_rtl_stop_queue); EXPORT_SYMBOL_NOVERS(ieee80211_reset_queue); EXPORT_SYMBOL_NOVERS(ieee80211_softmac_stop_protocol); EXPORT_SYMBOL_NOVERS(ieee80211_softmac_start_protocol); diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c index 103b33c093f5..798fb4154c25 100644 --- a/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c +++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_tx.c @@ -604,7 +604,7 @@ void ieee80211_query_seqnum(struct ieee80211_device*ieee, struct sk_buff* skb, u } } -int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) +int ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev) { #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) struct ieee80211_device *ieee = netdev_priv(dev); diff --git a/drivers/staging/rtl8192e/r8192E_core.c b/drivers/staging/rtl8192e/r8192E_core.c index ff8fe7e32a92..0ca5d8b4f746 100644 --- a/drivers/staging/rtl8192e/r8192E_core.c +++ b/drivers/staging/rtl8192e/r8192E_core.c @@ -5795,7 +5795,7 @@ static void rtl8192_rx(struct net_device *dev) stats.fragoffset = 0; stats.ntotalfrag = 1; - if(!ieee80211_rx(priv->ieee80211, skb, &stats)){ + if(!ieee80211_rtl_rx(priv->ieee80211, skb, &stats)){ dev_kfree_skb_any(skb); } else { priv->stats.rxok++; @@ -5837,7 +5837,7 @@ static const struct net_device_ops rtl8192_netdev_ops = { .ndo_do_ioctl = rtl8192_ioctl, .ndo_set_multicast_list = r8192_set_multicast, .ndo_set_mac_address = r8192_set_mac_adr, - .ndo_start_xmit = ieee80211_xmit, + .ndo_start_xmit = ieee80211_rtl_xmit, }; /**************************************************************************** @@ -6121,14 +6121,14 @@ static void __devexit rtl8192_pci_disconnect(struct pci_dev *pdev) RT_TRACE(COMP_DOWN, "wlan driver removed\n"); } -extern int ieee80211_init(void); -extern void ieee80211_exit(void); +extern int ieee80211_rtl_init(void); +extern void ieee80211_rtl_exit(void); static int __init rtl8192_pci_module_init(void) { int retval; - retval = ieee80211_init(); + retval = ieee80211_rtl_init(); if (retval) return retval; @@ -6153,7 +6153,7 @@ static void __exit rtl8192_pci_module_exit(void) RT_TRACE(COMP_DOWN, "Exiting"); rtl8192_proc_module_remove(); - ieee80211_exit(); + ieee80211_rtl_exit(); } //warning message WB @@ -6313,7 +6313,7 @@ void rtl8192_try_wake_queue(struct net_device *dev, int pri) spin_unlock_irqrestore(&priv->tx_lock,flags); if(enough_desc) - ieee80211_wake_queue(priv->ieee80211); + ieee80211_rtl_wake_queue(priv->ieee80211); #endif } From 55c7d5fc185e592c317e7cb175f91ee6b9d6c637 Mon Sep 17 00:00:00 2001 From: George Kadianakis Date: Thu, 17 Dec 2009 01:19:13 +0200 Subject: [PATCH 10/19] staging: fix rtl8192su compilation errors with mac80211 This patch series fixes compilation problems that were caused by function naming conflicts between the rtl8192su driver and the mac80211 stack. Signed-off-by: George Kadianakis Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192su/ieee80211/ieee80211.h | 8 ++++---- .../staging/rtl8192su/ieee80211/ieee80211_rx.c | 6 +++--- .../rtl8192su/ieee80211/ieee80211_softmac.c | 16 ++++++++-------- .../staging/rtl8192su/ieee80211/ieee80211_tx.c | 2 +- drivers/staging/rtl8192su/r8192U_core.c | 6 +++--- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211.h b/drivers/staging/rtl8192su/ieee80211/ieee80211.h index f22d024b1c39..9a4c858b0666 100644 --- a/drivers/staging/rtl8192su/ieee80211/ieee80211.h +++ b/drivers/staging/rtl8192su/ieee80211/ieee80211.h @@ -1721,13 +1721,13 @@ extern int ieee80211_encrypt_fragment( struct sk_buff *frag, int hdr_len); -extern int rtl8192_ieee80211_xmit(struct sk_buff *skb, +extern int rtl8192_ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev); extern void ieee80211_txb_free(struct ieee80211_txb *); /* ieee80211_rx.c */ -extern int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, +extern int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats); extern void ieee80211_rx_mgt(struct ieee80211_device *ieee, struct ieee80211_hdr_4addr *header, @@ -1783,8 +1783,8 @@ extern void ieee80211_stop_protocol(struct ieee80211_device *ieee); extern void ieee80211_softmac_start_protocol(struct ieee80211_device *ieee); extern void ieee80211_softmac_stop_protocol(struct ieee80211_device *ieee); extern void ieee80211_reset_queue(struct ieee80211_device *ieee); -extern void ieee80211_wake_queue(struct ieee80211_device *ieee); -extern void ieee80211_stop_queue(struct ieee80211_device *ieee); +extern void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee); +extern void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee); extern struct sk_buff *ieee80211_get_beacon(struct ieee80211_device *ieee); extern void ieee80211_start_send_beacons(struct ieee80211_device *ieee); extern void ieee80211_stop_send_beacons(struct ieee80211_device *ieee); diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c index ac223cef1d33..fecfa120ff48 100644 --- a/drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c +++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_rx.c @@ -208,7 +208,7 @@ static int ieee80211_frag_cache_invalidate(struct ieee80211_device *ieee, * * Responsible for handling management control frames * - * Called by ieee80211_rx */ + * Called by ieee80211_rtl_rx */ static inline int ieee80211_rx_frame_mgmt(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats, u16 type, @@ -289,7 +289,7 @@ static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee, return 0; } -/* Called only as a tasklet (software IRQ), by ieee80211_rx */ +/* Called only as a tasklet (software IRQ), by ieee80211_rtl_rx */ static inline int ieee80211_rx_frame_decrypt(struct ieee80211_device* ieee, struct sk_buff *skb, struct ieee80211_crypt_data *crypt) @@ -858,7 +858,7 @@ u8 parse_subframe(struct sk_buff *skb, /* All received frames are sent to this function. @skb contains the frame in * IEEE 802.11 format, i.e., in the format it was sent over air. * This function is called only as a tasklet (software IRQ). */ -int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, +int ieee80211_rtl_rx(struct ieee80211_device *ieee, struct sk_buff *skb, struct ieee80211_rx_stats *rx_stats) { struct net_device *dev = ieee->dev; diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c index 203c0a5cc8c1..95d4f84dcf3f 100644 --- a/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c +++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_softmac.c @@ -610,7 +610,7 @@ void ieee80211_stop_scan(struct ieee80211_device *ieee) } /* called with ieee->lock held */ -void ieee80211_start_scan(struct ieee80211_device *ieee) +void ieee80211_rtl_start_scan(struct ieee80211_device *ieee) { if(IS_DOT11D_ENABLE(ieee) ) { @@ -1281,7 +1281,7 @@ void ieee80211_associate_step1(struct ieee80211_device *ieee) } } -void ieee80211_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen) +void ieee80211_rtl_auth_challenge(struct ieee80211_device *ieee, u8 *challenge, int chlen) { u8 *c; struct sk_buff *skb; @@ -2054,7 +2054,7 @@ ieee80211_rx_frame_softmac(struct ieee80211_device *ieee, struct sk_buff *skb, ieee80211_associate_step2(ieee); }else{ - ieee80211_auth_challenge(ieee, challenge, chlen); + ieee80211_rtl_auth_challenge(ieee, challenge, chlen); } }else{ ieee->softmac_stats.rx_auth_rs_err++; @@ -2162,7 +2162,7 @@ void ieee80211_softmac_xmit(struct ieee80211_txb *txb, struct ieee80211_device * * to check it any more. * */ //printk("error:no descriptor left@queue_index %d, %d, %d\n", queue_index, skb_queue_len(&ieee->skb_waitQ[queue_index]), ieee->check_nic_enough_desc(ieee->dev,queue_index)); - //ieee80211_stop_queue(ieee); + //ieee80211_rtl_stop_queue(ieee); skb_queue_tail(&ieee->skb_waitQ[queue_index], txb->fragments[i]); }else{ ieee->softmac_data_hard_start_xmit( @@ -2222,7 +2222,7 @@ void ieee80211_reset_queue(struct ieee80211_device *ieee) } -void ieee80211_wake_queue(struct ieee80211_device *ieee) +void ieee80211_rtl_wake_queue(struct ieee80211_device *ieee) { unsigned long flags; @@ -2263,7 +2263,7 @@ exit : } -void ieee80211_stop_queue(struct ieee80211_device *ieee) +void ieee80211_rtl_stop_queue(struct ieee80211_device *ieee) { //unsigned long flags; //spin_lock_irqsave(&ieee->lock,flags); @@ -2479,7 +2479,7 @@ void ieee80211_start_bss(struct ieee80211_device *ieee) if (ieee->state == IEEE80211_NOLINK){ ieee->actscanning = true; - ieee80211_start_scan(ieee); + ieee80211_rtl_start_scan(ieee); } spin_unlock_irqrestore(&ieee->lock, flags); } @@ -2552,7 +2552,7 @@ void ieee80211_associate_retry_wq(struct work_struct *work) if(ieee->state == IEEE80211_NOLINK) { ieee->actscanning = true; - ieee80211_start_scan(ieee); + ieee80211_rtl_start_scan(ieee); } spin_unlock_irqrestore(&ieee->lock, flags); diff --git a/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c b/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c index 60621d6b2a6b..4d54e1e62d22 100644 --- a/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c +++ b/drivers/staging/rtl8192su/ieee80211/ieee80211_tx.c @@ -604,7 +604,7 @@ void ieee80211_query_seqnum(struct ieee80211_device*ieee, struct sk_buff* skb, u } } -int rtl8192_ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) +int rtl8192_ieee80211_rtl_xmit(struct sk_buff *skb, struct net_device *dev) { struct ieee80211_device *ieee = netdev_priv(dev); struct ieee80211_txb *txb = NULL; diff --git a/drivers/staging/rtl8192su/r8192U_core.c b/drivers/staging/rtl8192su/r8192U_core.c index b492ff588b8c..b06fca05c501 100644 --- a/drivers/staging/rtl8192su/r8192U_core.c +++ b/drivers/staging/rtl8192su/r8192U_core.c @@ -7155,7 +7155,7 @@ void rtl8192SU_rx_nomal(struct sk_buff* skb) unicast_packet = true; } - if(!ieee80211_rx(priv->ieee80211,skb, &stats)) { + if(!ieee80211_rtl_rx(priv->ieee80211,skb, &stats)) { dev_kfree_skb_any(skb); } else { // priv->stats.rxoktotal++; //YJ,test,090108 @@ -7426,7 +7426,7 @@ static const struct net_device_ops rtl8192_netdev_ops = { .ndo_set_mac_address = r8192_set_mac_adr, .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = eth_change_mtu, - .ndo_start_xmit = rtl8192_ieee80211_xmit, + .ndo_start_xmit = rtl8192_ieee80211_rtl_xmit, }; static int __devinit rtl8192_usb_probe(struct usb_interface *intf, @@ -7619,7 +7619,7 @@ void rtl8192_try_wake_queue(struct net_device *dev, int pri) spin_unlock_irqrestore(&priv->tx_lock,flags); if(enough_desc) - ieee80211_wake_queue(priv->ieee80211); + ieee80211_rtl_wake_queue(priv->ieee80211); } void EnableHWSecurityConfig8192(struct net_device *dev) From 488d3749620779ab2668c0dba2962836e51e3cd6 Mon Sep 17 00:00:00 2001 From: Stephane Glondu Date: Thu, 17 Dec 2009 15:41:23 +0100 Subject: [PATCH 11/19] staging: rtl8192su: add USB VID/PID for HWNUm-300 The Hercules Wireless N USB mini (HWNUm-300) uses the RTL8191S chipset and seems to work with this driver. Signed-off-by: Stephane Glondu Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192su/r8192U_core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/staging/rtl8192su/r8192U_core.c b/drivers/staging/rtl8192su/r8192U_core.c index b06fca05c501..ccb9d5b8cd44 100644 --- a/drivers/staging/rtl8192su/r8192U_core.c +++ b/drivers/staging/rtl8192su/r8192U_core.c @@ -126,6 +126,8 @@ static struct usb_device_id rtl8192_usb_id_tbl[] = { {USB_DEVICE(0x2001, 0x3301)}, /* Zinwell */ {USB_DEVICE(0x5a57, 0x0290)}, + /* Guillemot */ + {USB_DEVICE(0x06f8, 0xe031)}, //92SU {USB_DEVICE(0x0bda, 0x8172)}, {} From 4068fe8b2aa3e12643db0ad5dd4bcf6755a7320f Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Wed, 9 Dec 2009 20:25:04 +0100 Subject: [PATCH 12/19] Staging: wlan-ng: fix Correct size given to memset Memset should be given the size of the structure, not the size of the pointer. The semantic patch that makes this change is as follows: (http://coccinelle.lip6.fr/) // @@ type T; T *x; expression E; @@ memset(x, E, sizeof( + * x)) // Signed-off-by: Julia Lawall Signed-off-by: Greg Kroah-Hartman --- drivers/staging/wlan-ng/prism2fw.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/wlan-ng/prism2fw.c b/drivers/staging/wlan-ng/prism2fw.c index 7d76a7f92a33..aaa70ed57710 100644 --- a/drivers/staging/wlan-ng/prism2fw.c +++ b/drivers/staging/wlan-ng/prism2fw.c @@ -439,7 +439,7 @@ void free_chunks(imgchunk_t *fchunk, unsigned int *nfchunks) } } *nfchunks = 0; - memset(fchunk, 0, sizeof(fchunk)); + memset(fchunk, 0, sizeof(*fchunk)); } From 3d8affc001a37664b2f5cb29aa12cf8f6c582d52 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Tue, 24 Nov 2009 12:13:55 -0800 Subject: [PATCH 13/19] Staging: rtl8192x: fix printk formats Fix printk format warnings in rtl8192[eu]: drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c:979: warning: format '%d' expects type 'int', but argument 2 has type 'size_t' drivers/staging/rtl8192e/ieee80211/rtl819x_BAProc.c:385: warning: format '%d' expects type 'int', but argument 3 has type 'long unsigned int' drivers/staging/rtl8192e/ieee80211/rtl819x_BAProc.c:484: warning: format '%d' expects type 'int', but argument 3 has type 'long unsigned int' drivers/staging/rtl8192e/ieee80211/rtl819x_BAProc.c:614: warning: format '%d' expects type 'int', but argument 3 has type 'long unsigned int' drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c:848: warning: format '%d' expects type 'int', but argument 2 has type 'size_t' drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c:343: warning: format '%d' expects type 'int', but argument 3 has type 'long unsigned int' drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c:442: warning: format '%d' expects type 'int', but argument 3 has type 'long unsigned int' drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c:572: warning: format '%d' expects type 'int', but argument 3 has type 'long unsigned int' Signed-off-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c | 2 +- drivers/staging/rtl8192e/ieee80211/rtl819x_BAProc.c | 6 +++--- drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c | 2 +- drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c | 6 +++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c index 4e34a1f4c66b..3441b72dd8fa 100644 --- a/drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c +++ b/drivers/staging/rtl8192e/ieee80211/ieee80211_wx.c @@ -976,7 +976,7 @@ int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len) { if (len != ie[1]+2) { - printk("len:%d, ie:%d\n", len, ie[1]); + printk("len:%zu, ie:%d\n", len, ie[1]); return -EINVAL; } buf = kmalloc(len, GFP_KERNEL); diff --git a/drivers/staging/rtl8192e/ieee80211/rtl819x_BAProc.c b/drivers/staging/rtl8192e/ieee80211/rtl819x_BAProc.c index 98b3bb6b6d69..e41e8a0c739c 100644 --- a/drivers/staging/rtl8192e/ieee80211/rtl819x_BAProc.c +++ b/drivers/staging/rtl8192e/ieee80211/rtl819x_BAProc.c @@ -382,7 +382,7 @@ int ieee80211_rx_ADDBAReq( struct ieee80211_device* ieee, struct sk_buff *skb) if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 9) { - IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BAREQ(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9)); + IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BAREQ(%d / %zu)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9)); return -1; } @@ -481,7 +481,7 @@ int ieee80211_rx_ADDBARsp( struct ieee80211_device* ieee, struct sk_buff *skb) if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 9) { - IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BARSP(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9)); + IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BARSP(%d / %zu)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9)); return -1; } rsp = ( struct ieee80211_hdr_3addr*)skb->data; @@ -611,7 +611,7 @@ int ieee80211_rx_DELBA(struct ieee80211_device* ieee,struct sk_buff *skb) if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 6) { - IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in DELBA(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 6)); + IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in DELBA(%d / %zu)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 6)); return -1; } diff --git a/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c b/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c index d397f1d68eb7..5f12d62658c9 100644 --- a/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c +++ b/drivers/staging/rtl8192u/ieee80211/ieee80211_wx.c @@ -845,7 +845,7 @@ int ieee80211_wx_set_gen_ie(struct ieee80211_device *ieee, u8 *ie, size_t len) { if (len != ie[1]+2) { - printk("len:%d, ie:%d\n", len, ie[1]); + printk("len:%zu, ie:%d\n", len, ie[1]); return -EINVAL; } buf = kmalloc(len, GFP_KERNEL); diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c index 26af43bb8390..512a57aebde3 100644 --- a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c +++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c @@ -340,7 +340,7 @@ int ieee80211_rx_ADDBAReq( struct ieee80211_device* ieee, struct sk_buff *skb) if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 9) { - IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BAREQ(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9)); + IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BAREQ(%d / %zu)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9)); return -1; } @@ -439,7 +439,7 @@ int ieee80211_rx_ADDBARsp( struct ieee80211_device* ieee, struct sk_buff *skb) if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 9) { - IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BARSP(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9)); + IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in BARSP(%d / %zu)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 9)); return -1; } rsp = ( struct ieee80211_hdr_3addr*)skb->data; @@ -569,7 +569,7 @@ int ieee80211_rx_DELBA(struct ieee80211_device* ieee,struct sk_buff *skb) if (skb->len < sizeof( struct ieee80211_hdr_3addr) + 6) { - IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in DELBA(%d / %d)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 6)); + IEEE80211_DEBUG(IEEE80211_DL_ERR, " Invalid skb len in DELBA(%d / %zu)\n", skb->len, (sizeof( struct ieee80211_hdr_3addr) + 6)); return -1; } From 30fb8a7141e906116bb536dd54be99480b8fd238 Mon Sep 17 00:00:00 2001 From: Nitin Gupta Date: Sat, 12 Dec 2009 11:44:46 +0530 Subject: [PATCH 14/19] Staging: ramzswap: remove ARM specific d-cache hack Remove d-cache hack in ramzswap driver that was needed to workaround a bug in ARM version of update_mmu_cache() which caused stale data in d-cache to be transferred to userspace. This bug was fixed by git commit: 787b2faadc4356b6c2c71feb42fb944fece9a12f This also brings down one entry in TODO file. Signed-off-by: Nitin Gupta Acked-by: Pekka Enberg Signed-off-by: Greg Kroah-Hartman --- drivers/staging/ramzswap/TODO | 1 - drivers/staging/ramzswap/ramzswap_drv.c | 28 +++---------------------- 2 files changed, 3 insertions(+), 26 deletions(-) diff --git a/drivers/staging/ramzswap/TODO b/drivers/staging/ramzswap/TODO index bac40d6cb9f1..8d64e28fac0e 100644 --- a/drivers/staging/ramzswap/TODO +++ b/drivers/staging/ramzswap/TODO @@ -1,6 +1,5 @@ TODO: - Add support for swap notifiers - - Remove CONFIG_ARM hack Please send patches to Greg Kroah-Hartman and Nitin Gupta diff --git a/drivers/staging/ramzswap/ramzswap_drv.c b/drivers/staging/ramzswap/ramzswap_drv.c index b839f05efbce..989fac5b01b3 100644 --- a/drivers/staging/ramzswap/ramzswap_drv.c +++ b/drivers/staging/ramzswap/ramzswap_drv.c @@ -222,28 +222,6 @@ out: return ret; } -static void ramzswap_flush_dcache_page(struct page *page) -{ -#ifdef CONFIG_ARM - int flag = 0; - /* - * Ugly hack to get flush_dcache_page() work on ARM. - * page_mapping(page) == NULL after clearing this swap cache flag. - * Without clearing this flag, flush_dcache_page() will simply set - * "PG_dcache_dirty" bit and return. - */ - if (PageSwapCache(page)) { - flag = 1; - ClearPageSwapCache(page); - } -#endif - flush_dcache_page(page); -#ifdef CONFIG_ARM - if (flag) - SetPageSwapCache(page); -#endif -} - void ramzswap_ioctl_get_stats(struct ramzswap *rzs, struct ramzswap_ioctl_stats *s) { @@ -655,7 +633,7 @@ static int handle_zero_page(struct bio *bio) memset(user_mem, 0, PAGE_SIZE); kunmap_atomic(user_mem, KM_USER0); - ramzswap_flush_dcache_page(page); + flush_dcache_page(page); set_bit(BIO_UPTODATE, &bio->bi_flags); bio_endio(bio, 0); @@ -679,7 +657,7 @@ static int handle_uncompressed_page(struct ramzswap *rzs, struct bio *bio) kunmap_atomic(user_mem, KM_USER0); kunmap_atomic(cmem, KM_USER1); - ramzswap_flush_dcache_page(page); + flush_dcache_page(page); set_bit(BIO_UPTODATE, &bio->bi_flags); bio_endio(bio, 0); @@ -779,7 +757,7 @@ static int ramzswap_read(struct ramzswap *rzs, struct bio *bio) goto out; } - ramzswap_flush_dcache_page(page); + flush_dcache_page(page); set_bit(BIO_UPTODATE, &bio->bi_flags); bio_endio(bio, 0); From a6a6c90804f657a91fb080c7a525a8f90bc38867 Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Tue, 15 Dec 2009 06:21:45 +0100 Subject: [PATCH 15/19] Staging: panel: Fix compilation error with custom lcd charset When compiling panel.c with a DEFAULT_LCD_CHARSET it fails to compile with the following error message: drivers/staging/panel/panel.c: In function >>lcd_init<<: drivers/staging/panel/panel.c:1396: error: expected expression before >>;<< token drivers/staging/panel/panel.c:1475: error: expected expression before >>;<< token make[3]: *** [drivers/staging/panel/panel.o] error 1 make[2]: *** [drivers/staging/panel] error 2 make[1]: *** [drivers/staging] error 2 The config used was: CONFIG_PANEL=m CONFIG_PANEL_PARPORT=0 CONFIG_PANEL_PROFILE=0 CONFIG_PANEL_KEYPAD=0 CONFIG_PANEL_LCD=1 CONFIG_PANEL_LCD_HEIGHT=2 CONFIG_PANEL_LCD_WIDTH=20 CONFIG_PANEL_LCD_BWIDTH=40 CONFIG_PANEL_LCD_HWIDTH=64 CONFIG_PANEL_LCD_CHARSET=0 CONFIG_PANEL_LCD_PROTO=0 CONFIG_PANEL_LCD_PIN_E=14 CONFIG_PANEL_LCD_PIN_RS=17 CONFIG_PANEL_LCD_PIN_RW=16 CONFIG_PANEL_LCD_PIN_BL=0 This patch fixes both errors, as it fixes the define Patch against current linux-next tree at Tue Dec 15 06:07:01 2009 +0100 Signed-off-by: Peter Huewe Acked-by: Willy Tarreau Signed-off-by: Greg Kroah-Hartman --- drivers/staging/panel/panel.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c index f98a52448eae..95c93e82ccec 100644 --- a/drivers/staging/panel/panel.c +++ b/drivers/staging/panel/panel.c @@ -378,7 +378,7 @@ static unsigned char lcd_bits[LCD_PORTS][LCD_BITS][BIT_STATES]; #ifdef CONFIG_PANEL_LCD_CHARSET #undef DEFAULT_LCD_CHARSET -#define DEFAULT_LCD_CHARSET +#define DEFAULT_LCD_CHARSET CONFIG_PANEL_LCD_CHARSET #endif #endif /* DEFAULT_PROFILE == 0 */ From ae08961a99853c5b930845b00e3e609ad13dd61a Mon Sep 17 00:00:00 2001 From: Peter Huewe Date: Tue, 15 Dec 2009 06:37:36 +0100 Subject: [PATCH 16/19] Staging: panel: Adjust range for PANEL_KEYPAD in Kconfig In panel.c there are only the values 0-3 defined. So 4 is invalid: Signed-off-by: Peter Huewe Cc: Willy Tarreau Signed-off-by: Greg Kroah-Hartman --- drivers/staging/panel/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/panel/Kconfig b/drivers/staging/panel/Kconfig index 3abe7c9d558d..3defa0133f2e 100644 --- a/drivers/staging/panel/Kconfig +++ b/drivers/staging/panel/Kconfig @@ -47,7 +47,7 @@ config PANEL_PROFILE config PANEL_KEYPAD depends on PANEL && PANEL_PROFILE="0" int "Keypad type (0=none, 1=old 6 keys, 2=new 6 keys, 3=Nexcom 4 keys)" - range 0 4 + range 0 3 default 0 ---help--- This enables and configures a keypad connected to the parallel port. From ae67491ea085529759ab7475f73e7f3f1e825704 Mon Sep 17 00:00:00 2001 From: Andrew Lunn Date: Sat, 12 Dec 2009 23:39:47 +0100 Subject: [PATCH 17/19] Staging: batman-adv: Add Kconfig dependancies on PROC_FS and PACKET. Signed-off-by: Andrew Lunn Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/staging/batman-adv/Kconfig b/drivers/staging/batman-adv/Kconfig index 7632f5760060..1d74dabf9511 100644 --- a/drivers/staging/batman-adv/Kconfig +++ b/drivers/staging/batman-adv/Kconfig @@ -4,6 +4,7 @@ config BATMAN_ADV tristate "B.A.T.M.A.N. Advanced Meshing Protocol" + depends on PROC_FS && PACKET default n ---help--- From e281cf8966fa723d067343364ba576fb736bfa13 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Sun, 13 Dec 2009 14:11:39 +0100 Subject: [PATCH 18/19] Staging: batman-adv: introduce missing kfree Error handling code following a kzalloc should free the allocated data. Similarly for usb-alloc urb. The semantic match that finds the first problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r exists@ local idexpression x; statement S; expression E; identifier f,f1,l; position p1,p2; expression *ptr != NULL; @@ x@p1 = \(kmalloc\|kzalloc\|kcalloc\)(...); ... if (x == NULL) S <... when != x when != if (...) { <+...x...+> } ( x->f1 = E | (x->f1 == NULL || ...) | f(...,x->f1,...) ) ...> ( return \(0\|<+...x...+>\|ptr\); | return@p2 ...; ) @script:python@ p1 << r.p1; p2 << r.p2; @@ print "* file: %s kmalloc %s return %s" % (p1[0].file,p1[0].line,p2[0].line) // Signed-off-by: Julia Lawall Cc: Andrew Lunn Signed-off-by: Greg Kroah-Hartman --- drivers/staging/batman-adv/send.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/staging/batman-adv/send.c b/drivers/staging/batman-adv/send.c index d724798278d6..eb617508cca4 100644 --- a/drivers/staging/batman-adv/send.c +++ b/drivers/staging/batman-adv/send.c @@ -363,8 +363,10 @@ void add_bcast_packet_to_list(unsigned char *packet_buff, int packet_len) return; forw_packet->packet_buff = kmalloc(packet_len, GFP_ATOMIC); - if (!forw_packet->packet_buff) + if (!forw_packet->packet_buff) { + kfree(forw_packet); return; + } forw_packet->packet_len = packet_len; memcpy(forw_packet->packet_buff, packet_buff, forw_packet->packet_len); From b2cd41496c70a1653f28c6d07b61cbdd25167679 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Mon, 14 Dec 2009 08:44:46 -0800 Subject: [PATCH 19/19] Staging/vt66*: kconfig, depends on WLAN The vt665[56] drivers can be built when CONFIG_NET=n & CONFIG_NETDEVICES=n or just when CONFIG_WLAN=n. This leads to build failures. Prevent this by making them depend on WLAN. [This patch was lost in a dualing trees merge; still needs to be re-applied.] Signed-off-by: Randy Dunlap Signed-off-by: Greg Kroah-Hartman --- drivers/staging/vt6655/Kconfig | 2 +- drivers/staging/vt6656/Kconfig | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/staging/vt6655/Kconfig b/drivers/staging/vt6655/Kconfig index 825bbc4fc3fa..061e730df2d0 100644 --- a/drivers/staging/vt6655/Kconfig +++ b/drivers/staging/vt6655/Kconfig @@ -1,6 +1,6 @@ config VT6655 tristate "VIA Technologies VT6655 support" - depends on PCI + depends on PCI && WLAN select WIRELESS_EXT select WEXT_PRIV ---help--- diff --git a/drivers/staging/vt6656/Kconfig b/drivers/staging/vt6656/Kconfig index 87bcd269310c..1055b526c532 100644 --- a/drivers/staging/vt6656/Kconfig +++ b/drivers/staging/vt6656/Kconfig @@ -1,6 +1,6 @@ config VT6656 tristate "VIA Technologies VT6656 support" - depends on USB + depends on USB && WLAN select WIRELESS_EXT select WEXT_PRIV ---help---