xpram.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:41k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * Xpram.c -- the S/390 expanded memory RAM-disk
  3.  *           
  4.  * significant parts of this code are based on
  5.  * the sbull device driver presented in
  6.  * A. Rubini: Linux Device Drivers
  7.  *
  8.  * Author of XPRAM specific coding: Reinhard Buendgen
  9.  *                                  buendgen@de.ibm.com
  10.  *
  11.  * External interfaces:
  12.  *   Interfaces to linux kernel
  13.  *        xpram_setup: read kernel parameters   (see init/main.c)
  14.  *        xpram_init:  initialize device driver (see drivers/block/ll_rw_blk.c)
  15.  *   Module interfaces
  16.  *        init_module
  17.  *        cleanup_module
  18.  *   Device specific file operations
  19.  *        xpram_iotcl
  20.  *        xpram_open
  21.  *        xpram_release
  22.  *
  23.  * "ad-hoc" partitioning:         
  24.  *    the expanded memory can be partitioned among several devices 
  25.  *    (with different minors). The partitioning set up can be
  26.  *    set by kernel or module parameters (int devs & int sizes[])
  27.  *
  28.  *    module parameters: devs= and sizes=
  29.  *    kernel parameters: xpram_parts=
  30.  *      note: I did not succeed in parsing numbers 
  31.  *            for module parameters of type string "s" ?!?
  32.  *
  33.  * Other kenel files/modules affected(gerp for "xpram" or "XPRAM":
  34.  *    drivers/s390/Config.in
  35.  *    drivers/s390/block/Makefile
  36.  *    include/linux/blk.h
  37.  *    include/linux/major.h
  38.  *    init/main.c
  39.  *    drivers/block//ll_rw_blk.c
  40.  *
  41.  *
  42.  * Potential future improvements:
  43.  *   request clustering: first coding started not yet tested or integrated
  44.  *                       I doubt that it really pays off 
  45.  *   generic hard disk support to replace ad-hoc partitioning
  46.  *
  47.  * Tested with 2.2.14 (under VM)
  48.  */
  49. #ifdef MODULE
  50. #  ifndef __KERNEL__
  51. #    define __KERNEL__
  52. #  endif
  53. #  define __NO_VERSION__ /* don't define kernel_version in module.h */
  54. #endif /* MODULE */
  55. #include <linux/module.h>
  56. #include <linux/version.h>
  57. #ifdef MODULE
  58. char kernel_version [] = UTS_RELEASE; 
  59. #endif
  60. #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
  61. #  define XPRAM_VERSION 24
  62. #else
  63. #  define XPRAM_VERSION 22
  64. #endif 
  65. #if (XPRAM_VERSION == 24)
  66. #  include <linux/config.h>
  67. #  include <linux/init.h>
  68. #endif /* V24 */
  69. #include <linux/sched.h>
  70. #include <linux/kernel.h> /* printk() */
  71. #include <linux/slab.h> /* kmalloc() */
  72. #if (XPRAM_VERSION == 24)
  73. #  include <linux/devfs_fs_kernel.h>
  74. #endif /* V24 */
  75. #include <linux/fs.h>     /* everything... */
  76. #include <linux/errno.h>  /* error codes */
  77. #include <linux/timer.h>
  78. #include <linux/types.h>  /* size_t */
  79. #include <linux/ctype.h>  /* isdigit, isxdigit */
  80. #include <linux/fcntl.h>  /* O_ACCMODE */
  81. #include <linux/hdreg.h>  /* HDIO_GETGEO */
  82. #include <asm/system.h>   /* cli(), *_flags */
  83. #include <asm/uaccess.h>  /* put_user */
  84. #if (XPRAM_VERSION == 24)
  85. #define MAJOR_NR xpram_major /* force definitions on in blk.h */
  86. int xpram_major;   /* must be declared before including blk.h */
  87. devfs_handle_t xpram_devfs_handle;
  88. #define DEVICE_NR(device) MINOR(device)   /* xpram has no partition bits */
  89. #define DEVICE_NAME "xpram"               /* name for messaging */
  90. #define DEVICE_INTR xpram_intrptr         /* pointer to the bottom half */
  91. #define DEVICE_NO_RANDOM                  /* no entropy to contribute */
  92. #define DEVICE_OFF(d)                     /* do-nothing */
  93. #include <linux/blk.h>
  94. #include "xpram.h"        /* local definitions */
  95. __setup("xpram_parts=", xpram_setup);
  96. #endif /* V24 */
  97. /*
  98.    define the debug levels:
  99.    - 0 No debugging output to console or syslog
  100.    - 1 Log internal errors to syslog, ignore check conditions 
  101.    - 2 Log internal errors and check conditions to syslog
  102.    - 3 Log internal errors to console, log check conditions to syslog
  103.    - 4 Log internal errors and check conditions to console
  104.    - 5 panic on internal errors, log check conditions to console
  105.    - 6 panic on both, internal errors and check conditions
  106.  */
  107. #define XPRAM_DEBUG 4
  108. #define PRINTK_HEADER XPRAM_NAME
  109. #if XPRAM_DEBUG > 0
  110. #define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER "debug:" x )
  111. #define PRINT_INFO(x...) printk ( KERN_INFO PRINTK_HEADER "info:" x )
  112. #define PRINT_WARN(x...) printk ( KERN_WARNING PRINTK_HEADER "warning:" x )
  113. #define PRINT_ERR(x...) printk ( KERN_ERR PRINTK_HEADER "error:" x )
  114. #define PRINT_FATAL(x...) panic ( PRINTK_HEADER "panic:"x )
  115. #else
  116. #define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER "debug:"  x )
  117. #define PRINT_INFO(x...) printk ( KERN_DEBUG PRINTK_HEADER "info:" x )
  118. #define PRINT_WARN(x...) printk ( KERN_DEBUG PRINTK_HEADER "warning:" x )
  119. #define PRINT_ERR(x...) printk ( KERN_DEBUG PRINTK_HEADER "error:" x )
  120. #define PRINT_FATAL(x...) printk ( KERN_DEBUG PRINTK_HEADER "panic:" x )
  121. #endif
  122. #if (XPRAM_VERSION == 22)
  123. #define MAJOR_NR xpram_major /* force definitions on in blk.h */
  124. int xpram_major;   /* must be declared before including blk.h */
  125. #define DEVICE_NR(device) MINOR(device)   /* xpram has no partition bits */
  126. #define DEVICE_NAME "xpram"               /* name for messaging */
  127. #define DEVICE_INTR xpram_intrptr         /* pointer to the bottom half */
  128. #define DEVICE_NO_RANDOM                  /* no entropy to contribute */
  129. #define DEVICE_OFF(d) /* do-nothing */
  130. #define DEVICE_REQUEST *xpram_dummy_device_request  /* dummy function variable 
  131.      * to prevent warnings 
  132.      */#include <linux/blk.h>
  133. #include "xpram.h"        /* local definitions */
  134. #endif /* V22 */
  135. /*
  136.  * Non-prefixed symbols are static. They are meant to be assigned at
  137.  * load time. Prefixed symbols are not static, so they can be used in
  138.  * debugging. They are hidden anyways by register_symtab() unless
  139.  * XPRAM_DEBUG is defined.
  140.  */
  141. static int major    = XPRAM_MAJOR;
  142. static int devs     = XPRAM_DEVS;
  143. static int rahead   = XPRAM_RAHEAD;
  144. static int sizes[XPRAM_MAX_DEVS] = { 0, };
  145. static int blksize  = XPRAM_BLKSIZE;
  146. static int hardsect = XPRAM_HARDSECT;
  147. int xpram_devs, xpram_rahead;
  148. int xpram_blksize, xpram_hardsect;
  149. int xpram_mem_avail = 0;
  150. unsigned long xpram_sizes[XPRAM_MAX_DEVS];
  151. MODULE_PARM(devs,"i");
  152. MODULE_PARM(sizes,"1-" __MODULE_STRING(XPRAM_MAX_DEVS) "i"); 
  153. MODULE_PARM_DESC(devs, "number of devices ("partitions"), " 
  154.  "the default is " __MODULE_STRING(XPRAM_DEVS) "n");
  155. MODULE_PARM_DESC(sizes, "list of device (partition) sizes " 
  156.  "the defaults are 0s n" 
  157.  "All devices with size 0 equally partition the "
  158.  "remaining space on the expanded strorage not "
  159.  "claimed by explicit sizesn");
  160. /* The following items are obtained through kmalloc() in init_module() */
  161. Xpram_Dev *xpram_devices = NULL;
  162. int *xpram_blksizes = NULL;
  163. int *xpram_hardsects = NULL;
  164. int *xpram_offsets = NULL;   /* partition offsets */
  165. #define MIN(x,y) ((x) < (y) ? (x) : (y))
  166. #define MAX(x,y) ((x) > (y) ? (x) : (y))
  167. /* 
  168.  *              compute nearest multiple of 4 , argument must be non-negative
  169.  *              the macros used depends on XPRAM_KB_IN_PG = 4 
  170.  */
  171. #define NEXT4(x) ((x & 0x3) ? (x+4-(x &0x3)) : (x))   /* increment if needed */
  172. #define LAST4(x) ((x & 0x3) ? (x-4+(x & 0x3)) : (x))  /* decrement if needed */
  173. #if 0               /* this is probably not faster than the previous code */
  174. #define NEXT4(x)   ((((x-1)>>2)>>2)+4)             /* increment if needed */
  175. #define LAST4(x)   (((x+3)>>2)<<2)                 /* decrement if needed */
  176. #endif
  177. /* integer formats */
  178. #define XPRAM_INVALF -1    /* invalid     */
  179. #define XPRAM_HEXF    0    /* hexadecimal */
  180. #define XPRAM_DECF    1    /* decimal     */
  181. /* 
  182.  *    parsing operations (needed for kernel parameter parsing)
  183.  */
  184. /* -------------------------------------------------------------------------
  185.  * sets the string pointer after the next comma 
  186.  *
  187.  * argument:    strptr pointer to string
  188.  * side effect: strptr points to endof string or to position of the next 
  189.  *              comma 
  190.  * ------------------------------------------------------------------------*/
  191. static void
  192. xpram_scan_to_next_comma (char **strptr)
  193. {
  194. while ( ((**strptr) != ',') && (**strptr) )
  195. (*strptr)++;
  196. }
  197. /* -------------------------------------------------------------------------
  198.  * interpret character as hex-digit
  199.  *
  200.  * argument: c charcter
  201.  * result: c interpreted as hex-digit
  202.  * note: can be used to read digits for any base <= 16
  203.  * ------------------------------------------------------------------------*/
  204. static int
  205. xpram_get_hexdigit (char c)
  206. {
  207. if ((c >= '0') && (c <= '9'))
  208. return c - '0';
  209. if ((c >= 'a') && (c <= 'f'))
  210. return c + 10 - 'a';
  211. if ((c >= 'A') && (c <= 'F'))
  212. return c + 10 - 'A';
  213. return -1;
  214. }
  215. /*--------------------------------------------------------------------------
  216.  * Check format of unsigned integer
  217.  *
  218.  * Argument: strptr pointer to string 
  219.  * result:   -1 if strptr does not start with a digit 
  220.  *                (does not start an integer)
  221.  *           0  if strptr starts a positive hex-integer with "0x" 
  222.  *           1  if strptr start a positive decimal integer
  223.  *
  224.  * side effect: if strptr start a positive hex-integer then strptr is
  225.  *              set to the character after the "0x"
  226.  *-------------------------------------------------------------------------*/
  227. static int
  228. xpram_int_format(char **strptr)
  229. {
  230. if ( !isdigit(**strptr) )
  231. return XPRAM_INVALF;
  232. if ( (**strptr == '0') 
  233.      && ( (*((*strptr)+1) == 'x') || (*((*strptr) +1) == 'X') ) 
  234.      && isdigit(*((*strptr)+3)) ) {
  235. *strptr=(*strptr)+2;
  236. return XPRAM_HEXF;
  237. } else return XPRAM_DECF;
  238. }
  239. /*--------------------------------------------------------------------------
  240.  * Read non-negative decimal integer
  241.  *
  242.  * Argument: strptr pointer to string starting with a non-negative integer
  243.  *           in decimal format
  244.  * result:   the value of theinitial integer pointed to by strptr
  245.  *
  246.  * side effect: strptr is set to the first character following the integer
  247.  *-------------------------------------------------------------------------*/
  248. static int
  249. xpram_read_decint (char ** strptr)
  250. {
  251. int res=0;
  252. while ( isdigit(**strptr) ) {
  253. res = (res*10) + xpram_get_hexdigit(**strptr);
  254. (*strptr)++;
  255. }
  256. return res;
  257. }
  258. /*--------------------------------------------------------------------------
  259.  * Read non-negative hex-integer
  260.  *
  261.  * Argument: strptr pointer to string starting with a non-negative integer
  262.  *           in hexformat (without "0x" prefix)
  263.  * result:   the value of the initial integer pointed to by strptr
  264.  *
  265.  * side effect: strptr is set to the first character following the integer
  266.  *-------------------------------------------------------------------------*/
  267. static int
  268. xpram_read_hexint (char ** strptr)
  269. {
  270. int res=0;
  271. while ( isxdigit(**strptr) ) {
  272. res = (res<<4) + xpram_get_hexdigit(**strptr);
  273. (*strptr)++;
  274. }
  275. return res;
  276. }
  277. /*--------------------------------------------------------------------------
  278.  * Read non-negative integer
  279.  *
  280.  * Argument: strptr pointer to string starting with a non-negative integer
  281.              (either in decimal- or in hex-format
  282.  * result:   the value of the initial integer pointed to by strptr
  283.  *           in case of a parsing error the result is -EINVAL
  284.  *
  285.  * side effect: strptr is set to the first character following the integer
  286.  *-------------------------------------------------------------------------*/
  287. static int
  288. xpram_read_int (char ** strptr)
  289. {
  290. switch (  xpram_int_format(strptr) ) {
  291. case XPRAM_INVALF: return -EINVAL;
  292. case XPRAM_HEXF:   return xpram_read_hexint(strptr);
  293. case XPRAM_DECF:   return xpram_read_decint(strptr);
  294. default: return -EINVAL;
  295. }
  296. }
  297. /*--------------------------------------------------------------------------
  298.  * Read size
  299.  *
  300.  * Argument: strptr pointer to string starting with a non-negative integer
  301.  *           followed optionally by a size modifier:
  302.  *             k or K for kilo (default),
  303.  *             m or M for mega
  304.  *             g or G for giga
  305.  * result:   the value of the initial integer pointed to by strptr
  306.  *           multiplied by the modifier value devided by 1024
  307.  *           in case of a parsing error the result is -EINVAL
  308.  *
  309.  * side effect: strptr is set to the first character following the size
  310.  *-------------------------------------------------------------------------*/
  311. static int
  312. xpram_read_size (char ** strptr)
  313. {
  314. int res;
  315.   
  316. res=xpram_read_int(strptr);
  317. if ( res < 0 )return res;
  318. switch ( **strptr ) {
  319. case 'g':
  320. case 'G': res=res*1024;
  321. case 'm':
  322. case 'M': res=res*1024;
  323. case 'k' :
  324. case 'K' : (* strptr)++;
  325. }
  326.   
  327. return res;
  328. }
  329. /*--------------------------------------------------------------------------
  330.  * Read tail of comma separated size list  ",i1,i2,...,in"
  331.  *
  332.  * Arguments:strptr pointer to string. It is assumed that the string has
  333.  *                  the format (","<size>)*
  334.  *           maxl integer describing the maximal number of elements in the
  335.                   list pointed to by strptr, max must be > 0.
  336.  *           ilist array of dimension >= maxl of integers to be modified
  337.  *
  338.  * result:   -EINVAL if the list is longer than maxl
  339.  *           0 otherwise
  340.  *
  341.  * side effects: for j=1,...,n ilist[ij] is set to the value of ij if it is
  342.  *               a valid non-negative integer and to -EINVAL otherwise
  343.  *               if no comma is found where it is expected an entry in
  344.  *               ilist is set to -EINVAL
  345.  *-------------------------------------------------------------------------*/
  346. static int
  347. xpram_read_size_list_tail (char ** strptr, int maxl, int * ilist)
  348. int i=0;
  349. char *str = *strptr;
  350. int res=0;
  351. while ( (*str == ',') && (i < maxl) ) {
  352. str++;      
  353. ilist[i] = xpram_read_size(&str);
  354. if ( ilist[i] == -EINVAL ) {
  355. xpram_scan_to_next_comma(&str);
  356. res = -EINVAL;
  357. }
  358. i++;
  359. }
  360. return res;
  361. #if 0  /* be lenient about trailing stuff */
  362. if ( *str != 0 && *str != ' ' ) {
  363. ilist[MAX(i-1,0)] = -EINVAL;
  364. return -EINVAL;
  365. } else return 0;
  366. #endif
  367. }
  368. /*
  369.  *   expanded memory operations
  370.  */
  371. /*--------------------------------------------------------------------*/
  372. /* Copy expanded memory page (4kB) into main memory                   */
  373. /* Arguments                                                          */
  374. /*           page_addr:    address of target page                     */
  375. /*           xpage_index:  index of expandeded memory page            */
  376. /* Return value                                                       */
  377. /*           0:            if operation succeeds                      */
  378. /*           non-0:       otherwise                                   */
  379. /*--------------------------------------------------------------------*/
  380. long xpram_page_in (unsigned long page_addr, unsigned long xpage_index)
  381. {
  382. int cc=0;
  383. unsigned long real_page_addr = __pa(page_addr);
  384. #ifndef CONFIG_ARCH_S390X
  385. __asm__ __volatile__ (
  386. "   lr  1,%1         n"   /* r1 = real_page_addr            */
  387. "   lr  2,%2         n"   /* r2 = xpage_index               */
  388. "   .long 0xb22e0012 n"   /* pgin r1,r2                     */
  389. /* copy page from expanded memory */
  390. "0: ipm  %0          n"   /* save status (cc & program mask */
  391. "   srl  %0,28       n"   /* cc into least significant bits */
  392.                 "1:                  n"   /* we are done                    */
  393.                 ".section .fixup,"ax"n" /* start of fix up section        */
  394.                 "2: lhi    %0,2      n"   /* return unused condition code 2 */
  395.                 "   bras 1,3f        n"   /* safe label 1: in r1 and goto 3 */
  396.                 "   .long 1b         n"   /* literal containing label 1     */
  397.                 "3: l    1,0(1)      n"   /* load label 1 address into r1   */
  398.                 "   br   1           n"   /* goto label 1 (across sections) */
  399.                 ".previous           n"   /* back in text section           */
  400.                 ".section __ex_table,"a"n" /* start __extable             */
  401.                 "   .align 4         n"
  402.                 "   .long 0b,2b      n"   /* failure point 0, fixup code 2  */
  403.                 ".previous           n"
  404. : "=d" (cc) : "d" (real_page_addr), "d" (xpage_index) : "cc", "1", "2"
  405. );
  406. #else /* CONFIG_ARCH_S390X */
  407. __asm__ __volatile__ (
  408. "   lgr  1,%1        n"   /* r1 = real_page_addr            */
  409. "   lgr  2,%2        n"   /* r2 = xpage_index               */
  410. "   .long 0xb22e0012 n"   /* pgin r1,r2                     */
  411. /* copy page from expanded memory */
  412. "0: ipm  %0          n"   /* save status (cc & program mask */
  413. "   srl  %0,28       n"   /* cc into least significant bits */
  414.                 "1:                  n"   /* we are done                    */
  415.                 ".section .fixup,"ax"n" /* start of fix up section        */
  416.                 "2: lghi %0,2        n"   /* return unused condition code 2 */
  417.                 "   jg   1b          n"   /* goto label 1 above             */
  418.                 ".previous           n"   /* back in text section           */
  419.                 ".section __ex_table,"a"n" /* start __extable             */
  420.                 "   .align 8         n"
  421.                 "   .quad 0b,2b      n"   /* failure point 0, fixup code 2  */
  422.                 ".previous           n"
  423. : "=d" (cc) : "d" (real_page_addr), "d" (xpage_index) : "cc", "1", "2"
  424. );
  425. #endif /* CONFIG_ARCH_S390X */
  426. switch (cc) {
  427. case 0: return 0;
  428. case 1: return -EIO;
  429.         case 2: return -ENXIO;
  430. case 3: return -ENXIO;
  431. default: return -EIO;  /* should not happen */
  432. };
  433. }
  434. /*--------------------------------------------------------------------*/
  435. /* Copy a 4kB page of main memory to an expanded memory page          */
  436. /* Arguments                                                          */
  437. /*           page_addr:    address of source page                     */
  438. /*           xpage_index:  index of expandeded memory page            */
  439. /* Return value                                                       */
  440. /*           0:            if operation succeeds                      */
  441. /*           non-0:        otherwise                                  */
  442. /*--------------------------------------------------------------------*/
  443. long xpram_page_out (unsigned long page_addr, unsigned long xpage_index)
  444. {
  445. int cc=0;
  446. unsigned long real_page_addr = __pa(page_addr);
  447. #ifndef CONFIG_ARCH_S390X
  448. __asm__ __volatile__ (
  449. "  lr  1,%1        n"   /* r1 = mem_page                  */
  450. "  lr  2,%2        n"   /* r2 = rpi                       */
  451. " .long 0xb22f0012 n"   /* pgout r1,r2                    */
  452.                                 /* copy page from expanded memory */
  453. "0: ipm  %0        n"   /* save status (cc & program mask */
  454.                 " srl  %0,28       n"   /* cc into least significant bits */
  455.                 "1:                  n"   /* we are done                    */
  456.                 ".section .fixup,"ax"n" /* start of fix up section        */
  457.                 "2: lhi   %0,2       n"   /* return unused condition code 2 */
  458.                 "   bras 1,3f        n"   /* safe label 1: in r1 and goto 3 */
  459.                 "   .long 1b         n"   /* literal containing label 1     */
  460.                 "3: l    1,0(1)      n"   /* load label 1 address into r1   */
  461.                 "   br   1           n"   /* goto label 1 (across sections) */
  462.                 ".previous           n"   /* back in text section           */
  463.                 ".section __ex_table,"a"n" /* start __extable             */
  464.                 "   .align 4         n"
  465.                 "   .long 0b,2b      n"   /* failure point 0, fixup code 2  */
  466.                 ".previous           n"
  467. : "=d" (cc) : "d" (real_page_addr), "d" (xpage_index) : "cc", "1", "2"
  468. );
  469. #else /* CONFIG_ARCH_S390X */
  470. __asm__ __volatile__ (
  471. "  lgr  1,%1       n"   /* r1 = mem_page                  */
  472. "  lgr  2,%2       n"   /* r2 = rpi                       */
  473. " .long 0xb22f0012 n"   /* pgout r1,r2                    */
  474.                                          /* copy page from expanded memory */
  475. "0: ipm  %0        n"   /* save status (cc & program mask */
  476.                 "  srl  %0,28      n"   /* cc into least significant bits */
  477.                 "1:                n"   /* we are done                    */
  478.                 ".section .fixup,"ax"n" /* start of fix up section      */
  479.                 "2: lghi %0,2      n"   /* return unused condition code 2 */
  480.                 "   jg   1b        n"   /* goto label 1 above             */
  481.                 ".previous         n"   /* back in text section           */
  482.                 ".section __ex_table,"a"n" /* start __extable           */
  483.                 "   .align 8       n"
  484.                 "   .quad 0b,2b    n"   /* failure point 0, fixup code 2  */
  485.                 ".previous         n"
  486. : "=d" (cc) : "d" (real_page_addr), "d" (xpage_index) : "cc", "1", "2"
  487. );
  488. #endif  /* CONFIG_ARCH_S390X */
  489. switch (cc) {
  490. case 0: return 0;
  491. case 1: return -EIO;
  492.         case 2: { PRINT_ERR("expanded storage lost!n"); return -ENXIO; }
  493. case 3: return -ENXIO;
  494. default: return -EIO;  /* should not happen */
  495.         }
  496. }
  497. /*--------------------------------------------------------------------*/
  498. /* Measure expanded memory                                            */
  499. /* Return value                                                       */
  500. /*           size of expanded memory in kB (must be a multipe of 4)   */
  501. /*--------------------------------------------------------------------*/
  502. int xpram_size(void)
  503. {
  504. int cc=0;  
  505.         unsigned long base=0;
  506. unsigned long po, pi, rpi;   /* page index order, page index */
  507. unsigned long mem_page = __get_free_page(GFP_KERNEL);
  508. /* for po=0,1,2,... try to move in page number base+(2^po)-1 */
  509. pi=1;   
  510. for (po=0; po <= 32; po++) { /* pi = 2^po */
  511. cc=xpram_page_in(mem_page,base+pi-1);
  512. if ( cc ) break;
  513. pi <<= 1;  
  514. }
  515. if ( cc && (po < 31 ) ) {
  516.                 pi >>=1;
  517. base += pi;
  518. pi >>=1;
  519. for ( ; pi > 0; pi >>= 1) {
  520. rpi = pi - 1;
  521. cc=xpram_page_in(mem_page,base+rpi);
  522. if ( !cc ) base += pi;
  523. }
  524. }
  525. free_page (mem_page);
  526. if ( cc && (po < 31) ) 
  527. return (XPRAM_KB_IN_PG * base);
  528. else          /* return maximal value possible */
  529. return INT_MAX;
  530. }
  531. /*
  532.  * Open and close
  533.  */
  534. int xpram_open (struct inode *inode, struct file *filp)
  535. {
  536. Xpram_Dev *dev; /* device information */
  537. int num = MINOR(inode->i_rdev);
  538. if (num >= xpram_devs) return -ENODEV;
  539. dev = xpram_devices + num;
  540. PRINT_DEBUG("calling xpram_open for device %dn",num);
  541.         PRINT_DEBUG("  size %dkB, name %s, usage: %dn", 
  542.                      dev->size,dev->device_name, atomic_read(&(dev->usage)));
  543. atomic_inc(&(dev->usage));
  544. return 0;          /* success */
  545. }
  546. int xpram_release (struct inode *inode, struct file *filp)
  547. {
  548. Xpram_Dev *dev = xpram_devices + MINOR(inode->i_rdev);
  549. PRINT_DEBUG("calling xpram_release for device %d (size %dkB, usage: %d)n",MINOR(inode->i_rdev) ,dev->size,atomic_read(&(dev->usage)));
  550. /*
  551.  * If the device is closed for the last time, start a timer
  552.  * to release RAM in half a minute. The function and argument
  553.  * for the timer have been setup in init_module()
  554.  */
  555. if (!atomic_dec_return(&(dev->usage))) {
  556. /* but flush it right now */
  557. /* Everything is already flushed by caller -- AV */
  558. }
  559. return(0);
  560. }
  561. /*
  562.  * The ioctl() implementation
  563.  */
  564. int xpram_ioctl (struct inode *inode, struct file *filp,
  565.  unsigned int cmd, unsigned long arg)
  566. {
  567. int err, size;
  568. struct hd_geometry *geo = (struct hd_geometry *)arg;
  569. PRINT_DEBUG("ioctl 0x%x 0x%lxn", cmd, arg);
  570. switch(cmd) {
  571. case BLKGETSIZE:  /* 0x1260 */
  572. /* Return the device size, expressed in sectors */
  573. return put_user( 1024* xpram_sizes[MINOR(inode->i_rdev)]
  574.                            / XPRAM_SOFTSECT,
  575.    (unsigned long *) arg);
  576. case BLKGETSIZE64:
  577. return put_user( (u64)(1024* xpram_sizes[MINOR(inode->i_rdev)]
  578.                            / XPRAM_SOFTSECT) << 9,
  579.    (u64 *) arg);
  580. case BLKFLSBUF: /* flush, 0x1261 */
  581. fsync_dev(inode->i_rdev);
  582. if ( capable(CAP_SYS_ADMIN) )invalidate_buffers(inode->i_rdev);
  583. return 0;
  584. case BLKRAGET: /* return the readahead value, 0x1263 */
  585. if (!arg)  return -EINVAL;
  586. err = 0; /* verify_area_20(VERIFY_WRITE, (long *) arg, sizeof(long));
  587.           * if (err) return err;
  588.                           */
  589. put_user(read_ahead[MAJOR(inode->i_rdev)], (long *)arg);
  590. return 0;
  591. case BLKRASET: /* set the readahead value, 0x1262 */
  592. if (!capable(CAP_SYS_ADMIN)) return -EACCES;
  593. if (arg > 0xff) return -EINVAL; /* limit it */
  594. read_ahead[MAJOR(inode->i_rdev)] = arg;
  595.                 atomic_eieio();
  596. return 0;
  597. case BLKRRPART: /* re-read partition table: can't do it, 0x1259 */
  598. return -EINVAL;
  599. #if (XPRAM_VERSION == 22)
  600. RO_IOCTLS(inode->i_rdev, arg); /* the default RO operations 
  601.                                                 * BLKROSET
  602. * BLKROGET
  603.                                                 */
  604. #endif /* V22 */
  605. case HDIO_GETGEO:
  606. /*
  607.  * get geometry: we have to fake one...  trim the size to a
  608.  * multiple of 64 (32k): tell we have 16 sectors, 4 heads,
  609.  * whatever cylinders. Tell also that data starts at sector. 4.
  610.  */
  611. size = xpram_mem_avail * 1024 / XPRAM_SOFTSECT;
  612. /* size = xpram_mem_avail * 1024 / xpram_hardsect; */
  613. size &= ~0x3f; /* multiple of 64 */
  614. if (geo==NULL) return -EINVAL;
  615.                 /* 
  616.                  * err=verify_area_20(VERIFY_WRITE, geo, sizeof(*geo));
  617.  * if (err) return err;
  618.                  */
  619. put_user(size >> 6, &geo->cylinders);
  620. put_user(        4, &geo->heads);
  621. put_user(       16, &geo->sectors);
  622. put_user(        4, &geo->start);
  623. return 0;
  624. }
  625. return -EINVAL; /* unknown command */
  626. }
  627. /*
  628.  * The file operations
  629.  */
  630. #if (XPRAM_VERSION == 22)
  631. struct file_operations xpram_fops = {
  632. NULL,          /* lseek: default */
  633. block_read,
  634. block_write,
  635. NULL,          /* xpram_readdir */
  636. NULL,          /* xpram_select */
  637. xpram_ioctl,
  638. NULL,          /* xpram_mmap */
  639. xpram_open,
  640. NULL,          /* flush */
  641. xpram_release,
  642. block_fsync,
  643. NULL,          /* xpram_fasync */
  644.         NULL,
  645.         NULL
  646. };
  647. #endif /* V22 */
  648. #if (XPRAM_VERSION == 24)
  649. struct block_device_operations xpram_devops =
  650. {
  651. owner:   THIS_MODULE,
  652. ioctl:   xpram_ioctl,
  653. open:    xpram_open,
  654. release: xpram_release,
  655. };
  656. #endif /* V24 */
  657. /*
  658.  * Block-driver specific functions
  659.  */
  660. void xpram_request(request_queue_t * queue)
  661. {
  662. Xpram_Dev *device;
  663. /*     u8 *ptr;          */
  664. /*    int size;          */
  665. unsigned long page_no;         /* expanded memory page number */
  666. unsigned long sects_to_copy;   /* number of sectors to be copied */
  667.         char * buffer;                 /* local pointer into buffer cache */
  668. int dev_no;                    /* device number of request */
  669. int fault;                     /* faulty access to expanded memory */
  670. #if ( XPRAM_VERSION == 24 )
  671.         struct request * current_req;      /* working request */
  672. #else 
  673. #       define current_req CURRENT
  674. #endif /* V24 */
  675. while(1) {
  676. INIT_REQUEST;
  677. fault=0;
  678. #if ( XPRAM_VERSION == 24 )
  679. current_req = blkdev_entry_next_request (&queue->queue_head);
  680. #endif /* V24 */
  681. dev_no = DEVICE_NR(current_req->rq_dev); 
  682. /* Check if the minor number is in range */
  683. if ( dev_no > xpram_devs ) {
  684. static int count = 0;
  685. if (count++ < 5) /* print the message at most five times */
  686. PRINT_WARN(" request for unknown devicen");
  687. end_request(0);
  688. continue;
  689. }
  690. /* pointer to device structure, from the global array */
  691. device = xpram_devices + dev_no;   
  692. sects_to_copy = current_req->current_nr_sectors;
  693.                 /* does request exceed size of device ? */
  694. if ( XPRAM_SEC2KB(sects_to_copy) > xpram_sizes[dev_no] ) {
  695. PRINT_WARN(" request past end of devicen");
  696. end_request(0);
  697. continue;
  698. }
  699.                 /* Does request start at page boundery? -- paranoia */
  700. #if 0
  701. PRINT_DEBUG(" req %lx, sect %lx, to copy %lx, buf addr %lxn", (unsigned long) current_req, current_req->sector, sects_to_copy, (unsigned long) current_req->buffer);
  702. #endif
  703.                 buffer = current_req->buffer;
  704. #if XPRAM_SEC_IN_PG != 1
  705.                 /* Does request start at an expanded storage page boundery? */
  706.                 if ( current_req->sector &  (XPRAM_SEC_IN_PG - 1) ) {
  707. PRINT_WARN(" request does not start at an expanded storage page bounderyn");
  708. PRINT_WARN(" referenced sector: %ldn",current_req->sector);
  709. end_request(0);
  710. continue;
  711. }
  712. /* Does request refere to partial expanded storage pages? */
  713.                 if ( sects_to_copy & (XPRAM_SEC_IN_PG - 1) ) {
  714. PRINT_WARN(" request referes to a partial expanded storage pagen");
  715. end_request(0);
  716. continue;
  717. }
  718. #endif /*  XPRAM_SEC_IN_PG != 1 */
  719. /* Is request buffer aligned with kernel pages? */
  720. if ( ((unsigned long)buffer) & (XPRAM_PGSIZE-1) ) {
  721. PRINT_WARN(" request buffer is not aligned with kernel pagesn");
  722. end_request(0);
  723. continue;
  724. }
  725.                 /* which page of expanded storage is affected first? */
  726. page_no = (xpram_offsets[dev_no] >> XPRAM_KB_IN_PG_ORDER)
  727. + (current_req->sector >> XPRAM_SEC_IN_PG_ORDER); 
  728. #if 0 
  729. PRINT_DEBUG("request: %d ( dev %d, copy %d sectors, at page %d ) n", current_req->cmd,dev_no,sects_to_copy,page_no);
  730. #endif
  731. switch(current_req->cmd) {
  732. case READ:
  733. do {
  734. if ( (fault=xpram_page_in((unsigned long)buffer,page_no)) ) {
  735. PRINT_WARN("xpram(dev %d): page in failed for page %ld.n",dev_no,page_no);
  736. break;
  737. }
  738. sects_to_copy -= XPRAM_SEC_IN_PG;
  739.                                 buffer += XPRAM_PGSIZE;
  740. page_no++;
  741. } while ( sects_to_copy > 0 );
  742. break;
  743. case WRITE:
  744. do {
  745. if ( (fault=xpram_page_out((unsigned long)buffer,page_no)) 
  746. ) {
  747. PRINT_WARN("xpram(dev %d): page out failed for page %ld.n",dev_no,page_no);
  748. break;
  749. }
  750. sects_to_copy -= XPRAM_SEC_IN_PG;
  751. buffer += XPRAM_PGSIZE;
  752. page_no++;
  753. } while ( sects_to_copy > 0 );
  754. break;
  755. default:
  756. /* can't happen */
  757. end_request(0);
  758. continue;
  759. }
  760. if ( fault ) end_request(0);
  761. else end_request(1); /* success */
  762. }
  763. }
  764. /*
  765.  *    Kernel interfaces
  766.  */
  767. /*
  768.  * Parses the kernel parameters given in the kernel parameter line.
  769.  * The expected format is 
  770.  *           <number_of_partitions>[","<partition_size>]*
  771.  * where 
  772.  *           devices is a positive integer that initializes xpram_devs
  773.  *           each size is a non-negative integer possibly followed by a
  774.  *           magnitude (k,K,m,M,g,G), the list of sizes initialises 
  775.  *           xpram_sizes
  776.  *
  777.  * Arguments
  778.  *           str: substring of kernel parameter line that contains xprams
  779.  *                kernel parameters. 
  780.  *           ints: not used -- not in Version > 2.3 any more
  781.  *
  782.  * Result    0 on success, -EINVAl else -- only for Version > 2.3
  783.  *
  784.  * Side effects
  785.  *           the global variabls devs is set to the value of 
  786.  *           <number_of_partitions> and sizes[i] is set to the i-th
  787.  *           partition size (if provided). A parsing error of a value
  788.  *           results in this value being set to -EINVAL.
  789.  */
  790. #if (XPRAM_VERSION == 22)
  791. void xpram_setup (char *str, int *ints)
  792. #else 
  793. int xpram_setup (char *str)
  794. #endif /* V22 */
  795. {
  796. devs = xpram_read_int(&str);
  797. if ( devs != -EINVAL ) 
  798.   if ( xpram_read_size_list_tail(&str,devs,sizes) < 0 ) {
  799. PRINT_ERR("error while reading xpram parameters.n");
  800. #if (XPRAM_VERSION == 24)
  801. return -EINVAL;
  802. #endif /* V24 */
  803.   }
  804. #if (XPRAM_VERSION == 24)
  805.   else return 0;
  806. else return -EINVAL;
  807. #elif (XPRAM_VERSION == 22)
  808. return; 
  809. #endif /* V24/V22 */
  810. }
  811. /*
  812.  * initialize xpram device driver
  813.  *
  814.  * Result: 0 ok
  815.  *         negative number: negative error code
  816.  */
  817. int xpram_init(void)
  818. {
  819. int result, i;
  820. int mem_usable;       /* net size of expanded memory */
  821. int mem_needed=0;     /* size of expanded memory needed to fullfill
  822.        * requirements of non-zero parameters in sizes
  823.        */
  824. int mem_auto_no=0;    /* number of (implicit) zero parameters in sizes */
  825. int mem_auto;         /* automatically determined device size          */
  826. #if (XPRAM_VERSION == 24)
  827. int minor_length;     /* store the length of a minor (w/o '') */
  828.         int minor_thresh;     /* threshhold for minor lenght            */
  829.         request_queue_t *q;   /* request queue */
  830. #endif /* V24 */
  831. /*
  832.  * Copy the (static) cfg variables to public prefixed ones to allow
  833.  * snoozing with a debugger.
  834.  */
  835. xpram_rahead   = rahead;
  836. xpram_blksize  = blksize;
  837. xpram_hardsect = hardsect;
  838. PRINT_INFO("initializing: %sn","");
  839. /* check arguments */
  840. xpram_major    = major;
  841. if ( (devs <= 0) || (devs > XPRAM_MAX_DEVS) ) {
  842. PRINT_ERR("invalid number %d of devicesn",devs);
  843.                 PRINT_ERR("Giving up xpramn");
  844. return -EINVAL;
  845. }
  846. xpram_devs     = devs;
  847. for (i=0; i < xpram_devs; i++) {
  848. if ( sizes[i] < 0 ) {
  849. PRINT_ERR("Invalid partition size %d kBn",xpram_sizes[i]);
  850.                         PRINT_ERR("Giving up xpramn");
  851. return -EINVAL;
  852. } else {
  853.   xpram_sizes[i] = NEXT4(sizes[i]);  /* page align */
  854. if ( sizes[i] ) mem_needed += xpram_sizes[i];
  855. else mem_auto_no++;
  856. }
  857. }
  858. PRINT_DEBUG("  major %d n", xpram_major);
  859. PRINT_INFO("  number of devices (partitions): %d n", xpram_devs);
  860. for (i=0; i < xpram_devs; i++) {
  861. if ( sizes[i] )
  862. PRINT_INFO("  size of partition %d: %d kBn", i, xpram_sizes[i]);
  863. else
  864. PRINT_INFO("  size of partition %d to be set automaticallyn",i);
  865. }
  866. PRINT_DEBUG("  memory needed (for sized partitions): %d kBn", mem_needed);
  867. PRINT_DEBUG("  partitions to be sized automatically: %dn", mem_auto_no);
  868. #if 0
  869. /* Hardsect can't be changed :( */
  870.                                 /* I try it any way. Yet I must distinguish
  871.                                  * between hardsects (to be changed to 4096)
  872.                                  * and soft sectors, hard-coded for buffer 
  873.                                  * sizes within the requests
  874.                                  */
  875. if (hardsect != 512) {
  876. PRINT_ERR("Can't change hardsect sizen");
  877. hardsect = xpram_hardsect = 512;
  878. }
  879. #endif
  880.         PRINT_INFO("  hardsector size: %dB n",xpram_hardsect);
  881. /*
  882.  * Register your major, and accept a dynamic number
  883.  */
  884. #if (XPRAM_VERSION == 22)
  885. result = register_blkdev(xpram_major, "xpram", &xpram_fops);
  886. #elif (XPRAM_VERSION == 24)
  887. result = devfs_register_blkdev(xpram_major, "xpram", &xpram_devops);
  888. #endif /* V22/V24 */
  889. if (result < 0) {
  890. PRINT_ERR("Can't get major %dn",xpram_major);
  891.                 PRINT_ERR("Giving up xpramn");
  892. return result;
  893. }
  894. #if (XPRAM_VERSION == 24)
  895. xpram_devfs_handle = devfs_mk_dir (NULL, "slram", NULL);
  896. devfs_register_series (xpram_devfs_handle, "%u", XPRAM_MAX_DEVS,
  897.        DEVFS_FL_DEFAULT, XPRAM_MAJOR, 0,
  898.        S_IFBLK | S_IRUSR | S_IWUSR,
  899.        &xpram_devops, NULL);
  900. #endif /* V22/V24 */
  901. if (xpram_major == 0) xpram_major = result; /* dynamic */
  902. major = xpram_major; /* Use `major' later on to save typing */
  903. result = -ENOMEM; /* for the possible errors */
  904. /* 
  905.  * measure expanded memory
  906.  */
  907. xpram_mem_avail = xpram_size();
  908. if (!xpram_mem_avail) {
  909. PRINT_ERR("No or not enough expanded memory availablen");
  910.                 PRINT_ERR("Giving up xpramn");
  911. result = -ENODEV;
  912. goto fail_malloc;
  913. }
  914. PRINT_INFO("  %d kB expanded memory found.n",xpram_mem_avail );
  915. /*
  916.  * Assign the other needed values: request, rahead, size, blksize,
  917.  * hardsect. All the minor devices feature the same value.
  918.  * Note that `xpram' defines all of them to allow testing non-default
  919.  * values. A real device could well avoid setting values in global
  920.  * arrays if it uses the default values.
  921.  */
  922. #if (XPRAM_VERSION == 22)
  923. blk_dev[major].request_fn = xpram_request;
  924. #elif (XPRAM_VERSION == 24)
  925. q = BLK_DEFAULT_QUEUE (major);
  926. blk_init_queue (q, xpram_request);
  927. blk_queue_headactive (BLK_DEFAULT_QUEUE (major), 0);
  928. #endif /* V22/V24 */
  929. read_ahead[major] = xpram_rahead;
  930. /* we want to have XPRAM_UNUSED blocks security buffer between devices */
  931. mem_usable=xpram_mem_avail-(XPRAM_UNUSED*(xpram_devs-1));
  932. if ( mem_needed > mem_usable ) {
  933. PRINT_ERR("Not enough expanded memory availablen");
  934.                 PRINT_ERR("Giving up xpramn");
  935. goto fail_malloc;
  936. }
  937. /*
  938.  * partitioning:
  939.  * xpram_sizes[i] != 0; partition i has size xpram_sizes[i] kB
  940.  * else:             ; all partitions i with xpram_sizesxpram_size[i] 
  941.  *                     partition equally the remaining space
  942.  */
  943. if ( mem_auto_no ) {
  944. mem_auto=LAST4((mem_usable-mem_needed)/mem_auto_no);
  945. PRINT_INFO("  automatically determined partition size: %d kBn", mem_auto);
  946. for (i=0; i < xpram_devs; i++) 
  947. if (xpram_sizes[i] == 0) xpram_sizes[i] = mem_auto;
  948. }
  949. blk_size[major]=xpram_sizes;
  950. xpram_offsets = kmalloc(xpram_devs * sizeof(int), GFP_KERNEL);
  951. if (!xpram_offsets) {
  952. PRINT_ERR("Not enough memory for xpram_offsetsn");
  953.                 PRINT_ERR("Giving up xpramn");
  954. goto fail_malloc;
  955. }
  956. xpram_offsets[0] = 0;
  957. for (i=1; i < xpram_devs; i++) 
  958. xpram_offsets[i] = xpram_offsets[i-1] + xpram_sizes[i-1] + XPRAM_UNUSED;
  959. #if 0
  960. for (i=0; i < xpram_devs; i++)
  961. PRINT_DEBUG(" device(%d) offset = %d kB, size = %d kBn",i, xpram_offsets[i], xpram_sizes[i]);
  962. #endif
  963. xpram_blksizes = kmalloc(xpram_devs * sizeof(int), GFP_KERNEL);
  964. if (!xpram_blksizes) {
  965. PRINT_ERR("Not enough memory for xpram_blksizesn");
  966.                 PRINT_ERR("Giving up xpramn");
  967. goto fail_malloc_blksizes;
  968. }
  969. for (i=0; i < xpram_devs; i++) /* all the same blocksize */
  970. xpram_blksizes[i] = xpram_blksize;
  971. blksize_size[major]=xpram_blksizes;
  972. xpram_hardsects = kmalloc(xpram_devs * sizeof(int), GFP_KERNEL);
  973. if (!xpram_hardsects) {
  974. PRINT_ERR("Not enough memory for xpram_hardsectsn");
  975.                 PRINT_ERR("Giving up xpramn");
  976. goto fail_malloc_hardsects;
  977. }
  978. for (i=0; i < xpram_devs; i++) /* all the same hardsect */
  979. xpram_hardsects[i] = xpram_hardsect;
  980. hardsect_size[major]=xpram_hardsects;
  981.    
  982. /* 
  983.  * allocate the devices -- we can't have them static, as the number
  984.  * can be specified at load time
  985.  */
  986. xpram_devices = kmalloc(xpram_devs * sizeof (Xpram_Dev), GFP_KERNEL);
  987. if (!xpram_devices) {
  988. PRINT_ERR("Not enough memory for xpram_devicesn");
  989.                 PRINT_ERR("Giving up xpramn");
  990. goto fail_malloc_devices;
  991. }
  992. memset(xpram_devices, 0, xpram_devs * sizeof (Xpram_Dev));
  993. #if (XPRAM_VERSION == 24)
  994.         minor_length = 1;
  995.         minor_thresh = 10;
  996. #endif /* V24 */
  997. for (i=0; i < xpram_devs; i++) {
  998. /* data and usage remain zeroed */
  999. xpram_devices[i].size = xpram_sizes[i];  /* size in kB not in bytes */
  1000. atomic_set(&(xpram_devices[i].usage),0);
  1001. #if (XPRAM_VERSION == 24)
  1002.                 if (i == minor_thresh) {
  1003.   minor_length++;
  1004.   minor_thresh *= 10;
  1005. }
  1006.                 xpram_devices[i].device_name = 
  1007.                   kmalloc(1 + strlen(XPRAM_DEVICE_NAME_PREFIX) + minor_length,GFP_KERNEL);
  1008. if ( xpram_devices[i].device_name == NULL ) {
  1009.   PRINT_ERR("Not enough memory for xpram_devices[%d].device_namen",i);
  1010.                   PRINT_ERR("Giving up xpramn");
  1011.   goto fail_devfs_register;
  1012. }
  1013.                 sprintf(xpram_devices[i].device_name,XPRAM_DEVICE_NAME_PREFIX "%d",i);
  1014. PRINT_DEBUG("initializing xpram_open for device %dn",i);
  1015.         PRINT_DEBUG("  size %dkB, name %s, usage: %dn", 
  1016.                      xpram_devices[i].size,xpram_devices[i].device_name, atomic_read(&(xpram_devices[i].usage)));
  1017. #if 0  /* WHY? */
  1018.                 xpram_devices[i].devfs_entry =
  1019.   devfs_register(NULL /* devfs root dir */,
  1020.                                  xpram_devices[i].device_name, 0,
  1021.                                  0 /* flags */,
  1022.  XPRAM_MAJOR,i,
  1023.                                  0755 /* access mode */,
  1024.  0 /* uid */, 0 /* gid */,
  1025.                                  &xpram_devops,
  1026.  (void *) &(xpram_devices[i])
  1027.  );
  1028. if ( xpram_devices[i].devfs_entry == NULL ) {
  1029.   PRINT_ERR("devfs system registry failedn");
  1030.   PRINT_ERR("Giving up xpramn");
  1031.   goto fail_devfs_register;
  1032. }
  1033. #endif  /* WHY? */
  1034. #endif /* V24 */
  1035.  
  1036. }
  1037. return 0; /* succeed */
  1038. /* clean up memory in case of failures */
  1039. #if (XPRAM_VERSION == 24)
  1040.  fail_devfs_register:
  1041.         for (i=0; i < xpram_devs; i++) {
  1042.   if ( xpram_devices[i].device_name )
  1043.     kfree(xpram_devices[i].device_name);
  1044. }
  1045. kfree(xpram_devices);
  1046. #endif /* V24 */
  1047.  fail_malloc_blksizes:
  1048. kfree (xpram_offsets);
  1049.  fail_malloc_hardsects:
  1050. kfree (xpram_blksizes);
  1051. blksize_size[major] = NULL;
  1052.  fail_malloc_devices:
  1053. kfree(xpram_hardsects);
  1054. hardsect_size[major] = NULL;
  1055.  fail_malloc:
  1056. read_ahead[major] = 0;
  1057. #if (XPRAM_VERSION == 22)
  1058. blk_dev[major].request_fn = NULL;
  1059. #endif /* V22 */
  1060. /* ??? unregister_chrdev(major, "xpram"); */
  1061. unregister_blkdev(major, "xpram");
  1062. return result;
  1063. }
  1064. /*
  1065.  * Finally, the module stuff
  1066.  */
  1067. int init_module(void)
  1068. {
  1069. int rc = 0;
  1070. PRINT_INFO ("trying to load modulen");
  1071. rc = xpram_init ();
  1072. if (rc == 0) {
  1073. PRINT_INFO ("Module loaded successfullyn");
  1074. } else {
  1075. PRINT_WARN ("Module load returned rc=%dn", rc);
  1076. }
  1077. return rc;
  1078. }
  1079. void cleanup_module(void)
  1080. {
  1081. int i;
  1082. /* first of all, flush it all and reset all the data structures */
  1083. for (i=0; i<xpram_devs; i++)
  1084. fsync_dev(MKDEV(xpram_major, i)); /* flush the devices */
  1085. #if (XPRAM_VERSION == 22)
  1086. blk_dev[major].request_fn = NULL;
  1087. #endif /* V22 */
  1088. read_ahead[major] = 0;
  1089. blk_size[major] = NULL;
  1090. kfree(blksize_size[major]);
  1091. blksize_size[major] = NULL;
  1092. kfree(hardsect_size[major]);
  1093. hardsect_size[major] = NULL;
  1094. kfree(xpram_offsets);
  1095. /* finally, the usual cleanup */
  1096. #if (XPRAM_VERSION == 22)
  1097. unregister_blkdev(major, "xpram");
  1098. #elif (XPRAM_VERSION == 24)
  1099. devfs_unregister(xpram_devfs_handle);
  1100. if (devfs_unregister_blkdev(MAJOR_NR, "xpram"))
  1101. printk(KERN_WARNING "xpram: cannot unregister blkdevn");
  1102. #endif /* V22/V24 */
  1103. kfree(xpram_devices);
  1104. }