summaryrefslogtreecommitdiffstats
path: root/drivers/mtd/mixmem.c
blob: 18fc4e2d7a701329d1472c29d6a0e30b132ce5c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/* 
 * mixmem - a block device driver for flash rom found on the 
 *          piggyback board of the multi-purpose mixcom card
 *
 * Author: Gergely Madarasz <gorgo@itc.hu> 
 *
 * Copyright (c) 1999 ITConsult-Pro Co. <info@itc.hu>
 *
 * This code is GPL
 *
 */

#include <linux/module.h>
#include <linux/slab.h>
#include <linux/ioport.h>
#include <asm/io.h>
#include <linux/init.h>
#include <linux/mtd/mapped.h>

#define MIXCOM_ID_OFFSET 0xc10
#define MIXCOM_PAGE_OFFSET 0xc11
#define MIXCOM_ID_1 0x11
#define MIXCOM_ID_2 0x13
#define MIXMEM_PAGESIZE 4096
#define FIRST_BLOCK_OFFSET 0x1000

#if LINUX_VERSION_CODE < 0x20300
#define __exit
#endif

static unsigned int mixmem_addrs[] = { 0xc8000, 0xd8000, 0 };
static unsigned int mixcom_ports[] = { 0x180, 0x280, 0x380, 0 };

// We could store these in the mtd structure, but we only support 1 device..
static unsigned long base_io = 0;
static unsigned long base_addr = 0;
static struct mapped_mtd_info *SSD;

static unsigned long mixmem_page(struct mapped_mtd_info *map,
				 unsigned long page)
{
	outb((char)(page & 0xff), base_io+MIXCOM_PAGE_OFFSET);
	outb((char)((page >> 8) & 0x7), base_io+MIXCOM_PAGE_OFFSET+1);
   	return base_addr;
}

static int flash_probe(int base)
{
	int prev,curr;
	unsigned long flags;

	writeb(0xf0, base);
	save_flags(flags); cli();
	
	prev=readw(base);

	writeb(0xaa, base+0x555);
	writeb(0x55, base+0x2AA);
	writeb(0x90, base+0x555);
	
	curr=readw(base);
	
	restore_flags(flags);
	writeb(0xf0, base);
	return(prev==curr?0:curr);
}

static int mixmem_probe(void) 
{
	int i;
	int id;
	int chip;
	
        /* This should really check to see if the io ports are in use before
           writing to them */
	for(i=0;mixcom_ports[i]!=0;i++) {
		id=inb(mixcom_ports[i]+MIXCOM_ID_OFFSET);
		if(id==MIXCOM_ID_1 || id==MIXCOM_ID_2) {
			printk("mixmem: mixcom board found at 0x%3x\n",mixcom_ports[i]);
			break;
		}
	}
	
	if(mixcom_ports[i]==0) {
		printk("mixmem: no mixcom board found\n");
		return -ENODEV;
	}
	
	if (check_region(mixcom_ports[i]+MIXCOM_PAGE_OFFSET, 2)) return -EAGAIN;

	
	
	// What is the deal with first_block_offset?
	for(i=0;mixmem_addrs[i]!=0;i++) {
		chip=flash_probe(mixmem_addrs[i]+FIRST_BLOCK_OFFSET);
		if(chip)break;
	}
	
	if(mixmem_addrs[i]==0) {
		printk("mixmem: no flash available\n");
		return -ENODEV;
	}
        base_io = mixcom_ports[i];
        base_addr = mixmem_addrs[i];
	request_region(mixcom_ports[i]+MIXCOM_PAGE_OFFSET, 2, "mixmem");
        return 0;
}


static void __exit cleanup_mixmem()
{
	mtd_mapped_remove(SSD);
	kfree(SSD);
	SSD = 0;
	release_region(base_io+MIXCOM_PAGE_OFFSET, 2);
}

//static int __init init_mixmem(void)
int __init init_mixmem(void)
{   
   if (mixmem_probe() != 0)
      return -EAGAIN;

   // Print out our little header..
   printk("mixcom MTD IO:0x%lx MEM:0x%lx-0x%lx\n",base_io,base_addr,
	  base_addr+MIXMEM_PAGESIZE);
   
   // Allocate some memory
   SSD = (struct mapped_mtd_info *)kmalloc(sizeof(*SSD),GFP_KERNEL);
   if (SSD == 0)
      return 0;   
   memset(SSD,0,sizeof(*SSD));

   // Setup the MTD structure
   SSD->page = mixmem_page;
   SSD->pagesize = MIXMEM_PAGESIZE;
   SSD->maxsize = 0x7FF;
   SSD->mtd.name = "mixcom piggyback";

   // Setup the MTD, this will sense the flash parameters and so on..
   if (mtd_mapped_setup(SSD) != 0)
   {
      printk("Failed to register new device\n");
      cleanup_module();
      return -EAGAIN;
   }

   return 0;
}
module_init(init_mixmem);
module_exit(cleanup_mixmem);