1 /*======================================================================
3 PCMCIA Bulk Memory Services
5 bulkmem.c 1.38 2000/09/25 19:29:51
7 The contents of this file are subject to the Mozilla Public
8 License Version 1.1 (the "License"); you may not use this file
9 except in compliance with the License. You may obtain a copy of
10 the License at http://www.mozilla.org/MPL/
12 Software distributed under the License is distributed on an "AS
13 IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 implied. See the License for the specific language governing
15 rights and limitations under the License.
17 The initial developer of the original code is David A. Hinds
18 <dahinds@users.sourceforge.net>. Portions created by David A. Hinds
19 are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
21 Alternatively, the contents of this file may be used under the
22 terms of the GNU General Public License version 2 (the "GPL"), in which
23 case the provisions of the GPL are applicable instead of the
24 above. If you wish to allow the use of your version of this file
25 only under the terms of the GPL and not to allow others to use
26 your version of this file under the MPL, indicate your decision
27 by deleting the provisions above and replace them with the notice
28 and other provisions required by the GPL. If you do not delete
29 the provisions above, a recipient may use your version of this
30 file under either the MPL or the GPL.
32 ======================================================================*/
34 #include <linux/module.h>
35 #include <linux/kernel.h>
36 #include <linux/string.h>
37 #include <linux/errno.h>
38 #include <linux/slab.h>
40 #include <linux/sched.h>
41 #include <linux/timer.h>
43 #define IN_CARD_SERVICES
44 #include <pcmcia/cs_types.h>
45 #include <pcmcia/ss.h>
46 #include <pcmcia/cs.h>
47 #include <pcmcia/bulkmem.h>
48 #include <pcmcia/cistpl.h>
49 #include "cs_internal.h"
52 extern int ds_pc_debug;
53 #define cs_socket_name(skt) ((skt)->dev.class_id)
55 #define ds_dbg(skt, lvl, fmt, arg...) do { \
56 if (ds_pc_debug >= lvl) \
57 printk(KERN_DEBUG "ds: %s: " fmt, \
58 cs_socket_name(skt) , ## arg); \
61 #define ds_dbg(lvl, fmt, arg...) do { } while (0)
64 /*======================================================================
66 This stuff is used by Card Services to initialize the table of
67 region info used for subsequent calls to GetFirstRegion and
70 ======================================================================*/
72 static void setup_regions(struct pcmcia_socket *s, unsigned int function,
73 int attr, memory_handle_t *list)
75 int i, code, has_jedec, has_geo;
77 cistpl_device_t device;
79 cistpl_device_geo_t geo;
82 ds_dbg(s, 1, "setup_regions(0x%d, %d, 0x%p)\n",
83 function, attr, list);
85 code = (attr) ? CISTPL_DEVICE_A : CISTPL_DEVICE;
86 if (pccard_read_tuple(s, function, code, &device) != CS_SUCCESS)
88 code = (attr) ? CISTPL_JEDEC_A : CISTPL_JEDEC_C;
89 has_jedec = (pccard_read_tuple(s, function, code, &jedec) == CS_SUCCESS);
90 if (has_jedec && (device.ndev != jedec.nid)) {
91 ds_dbg(s, 0, "Device info does not match JEDEC info.\n");
94 code = (attr) ? CISTPL_DEVICE_GEO_A : CISTPL_DEVICE_GEO;
95 has_geo = (pccard_read_tuple(s, function, code, &geo) == CS_SUCCESS);
96 if (has_geo && (device.ndev != geo.ngeo)) {
97 ds_dbg(s, 0, "Device info does not match geometry tuple.\n");
102 for (i = 0; i < device.ndev; i++) {
103 if ((device.dev[i].type != CISTPL_DTYPE_NULL) &&
104 (device.dev[i].size != 0)) {
105 r = kmalloc(sizeof(*r), GFP_KERNEL);
107 printk(KERN_NOTICE "cs: setup_regions: kmalloc failed!\n");
110 r->region_magic = REGION_MAGIC;
112 r->dev_info[0] = '\0';
114 r->info.Attributes = (attr) ? REGION_TYPE_AM : 0;
115 r->info.CardOffset = offset;
116 r->info.RegionSize = device.dev[i].size;
117 r->info.AccessSpeed = device.dev[i].speed;
119 r->info.JedecMfr = jedec.id[i].mfr;
120 r->info.JedecInfo = jedec.id[i].info;
122 r->info.JedecMfr = r->info.JedecInfo = 0;
124 r->info.BlockSize = geo.geo[i].buswidth *
125 geo.geo[i].erase_block * geo.geo[i].interleave;
126 r->info.PartMultiple =
127 r->info.BlockSize * geo.geo[i].partition;
129 r->info.BlockSize = r->info.PartMultiple = 1;
130 r->info.next = *list; *list = r;
132 offset += device.dev[i].size;
134 } /* setup_regions */
136 /*======================================================================
138 This is tricky. When get_first_region() is called by Driver
139 Services, we initialize the region info table in the socket
140 structure. When it is called by an MTD, we can just scan the
141 table for matching entries.
143 ======================================================================*/
145 static int pccard_match_region(memory_handle_t list, region_info_t *match)
151 return CS_NO_MORE_ITEMS;
154 int pccard_get_first_region(struct pcmcia_socket *s, region_info_t *rgn)
156 if (!(s->state & SOCKET_REGION_INFO)) {
157 setup_regions(s, BIND_FN_ALL, 0, &s->c_region);
158 setup_regions(s, BIND_FN_ALL, 1, &s->a_region);
159 s->state |= SOCKET_REGION_INFO;
162 if (rgn->Attributes & REGION_TYPE_AM)
163 return pccard_match_region(s->a_region, rgn);
165 return pccard_match_region(s->c_region, rgn);
166 } /* get_first_region */
168 int pccard_get_next_region(struct pcmcia_socket *s, region_info_t *rgn)
170 return pccard_match_region(rgn->next, rgn);
171 } /* get_next_region */
174 #ifdef CONFIG_PCMCIA_OBSOLETE
176 static int match_region(client_handle_t handle, memory_handle_t list,
177 region_info_t *match)
179 while (list != NULL) {
180 if (!(handle->Attributes & INFO_MTD_CLIENT) ||
181 (strcmp(handle->dev_info, list->dev_info) == 0)) {
185 list = list->info.next;
187 return CS_NO_MORE_ITEMS;
190 int pcmcia_get_first_region(client_handle_t handle, region_info_t *rgn)
192 struct pcmcia_socket *s = SOCKET(handle);
193 if (CHECK_HANDLE(handle))
194 return CS_BAD_HANDLE;
196 if ((handle->Attributes & INFO_MASTER_CLIENT) &&
197 (!(s->state & SOCKET_REGION_INFO))) {
198 setup_regions(s, handle->Function, 0, &s->c_region);
199 setup_regions(s, handle->Function, 1, &s->a_region);
200 s->state |= SOCKET_REGION_INFO;
203 if (rgn->Attributes & REGION_TYPE_AM)
204 return match_region(handle, s->a_region, rgn);
206 return match_region(handle, s->c_region, rgn);
207 } /* get_first_region */
208 EXPORT_SYMBOL(pcmcia_get_first_region);
210 int pcmcia_get_next_region(client_handle_t handle, region_info_t *rgn)
212 if (CHECK_HANDLE(handle))
213 return CS_BAD_HANDLE;
214 return match_region(handle, rgn->next, rgn);
215 } /* get_next_region */
216 EXPORT_SYMBOL(pcmcia_get_next_region);