|
|
1.1 root 1: /*======================================================================
2:
3: PCMCIA Bulk Memory Services
4:
5: bulkmem.c 1.44 2002/06/29 06:23:09
6:
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/
11:
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.
16:
17: The initial developer of the original code is David A. Hinds
18: <[email protected]>. Portions created by David A. Hinds
19: are Copyright (C) 1999 David A. Hinds. All Rights Reserved.
20:
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
23: which 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.
31:
32: ======================================================================*/
33:
34: #define __NO_VERSION__
35:
36: #include <linux/module.h>
37: #include <linux/kernel.h>
38: #include <linux/string.h>
39: #include <linux/errno.h>
40: #include <linux/slab.h>
41: #include <linux/mm.h>
42: #include <linux/sched.h>
43: #include <linux/timer.h>
44:
45: #define IN_CARD_SERVICES
46: #include <pcmcia/cs_types.h>
47: #include <pcmcia/ss.h>
48: #include <pcmcia/cs.h>
49: #include <pcmcia/bulkmem.h>
50: #include <pcmcia/cistpl.h>
51: #include "cs_internal.h"
52:
53: /*======================================================================
54:
55: This function handles submitting an MTD request, and retrying
56: requests when an MTD is busy.
57:
58: An MTD request should never block.
59:
60: ======================================================================*/
61:
62: static int do_mtd_request(memory_handle_t handle, mtd_request_t *req,
63: caddr_t buf)
64: {
65: int ret, tries;
66: client_t *mtd;
67: socket_info_t *s;
68:
69: mtd = handle->mtd;
70: if (mtd == NULL)
71: return CS_GENERAL_FAILURE;
72: s = SOCKET(mtd);
73: for (ret = tries = 0; tries < 100; tries++) {
74: mtd->event_callback_args.mtdrequest = req;
75: mtd->event_callback_args.buffer = buf;
76: ret = EVENT(mtd, CS_EVENT_MTD_REQUEST, CS_EVENT_PRI_LOW);
77: if (ret != CS_BUSY)
78: break;
79: switch (req->Status) {
80: case MTD_WAITREQ:
81: /* Not that we should ever need this... */
82: interruptible_sleep_on_timeout(&mtd->mtd_req, HZ);
83: break;
84: case MTD_WAITTIMER:
85: case MTD_WAITRDY:
86: interruptible_sleep_on_timeout(&mtd->mtd_req,
87: req->Timeout*HZ/1000);
88: req->Function |= MTD_REQ_TIMEOUT;
89: break;
90: case MTD_WAITPOWER:
91: interruptible_sleep_on(&mtd->mtd_req);
92: break;
93: }
94: if (signal_pending(current))
95: printk(KERN_NOTICE "cs: do_mtd_request interrupted!\n");
96: }
97: if (tries == 20) {
98: printk(KERN_NOTICE "cs: MTD request timed out!\n");
99: ret = CS_GENERAL_FAILURE;
100: }
101: wake_up_interruptible(&mtd->mtd_req);
102: retry_erase_list(&mtd->erase_busy, 0);
103: return ret;
104: } /* do_mtd_request */
105:
106: /*======================================================================
107:
108: This stuff is all for handling asynchronous erase requests. It
109: is complicated because all the retry stuff has to be dealt with
110: in timer interrupts or in the card status event handler.
111:
112: ======================================================================*/
113:
114: static void insert_queue(erase_busy_t *head, erase_busy_t *entry)
115: {
116: DEBUG(2, "cs: adding 0x%p to queue 0x%p\n", entry, head);
117: entry->next = head;
118: entry->prev = head->prev;
119: head->prev->next = entry;
120: head->prev = entry;
121: }
122:
123: static void remove_queue(erase_busy_t *entry)
124: {
125: DEBUG(2, "cs: unqueueing 0x%p\n", entry);
126: entry->next->prev = entry->prev;
127: entry->prev->next = entry->next;
128: }
129:
130: static void retry_erase(erase_busy_t *busy, u_int cause)
131: {
132: eraseq_entry_t *erase = busy->erase;
133: mtd_request_t req;
134: client_t *mtd;
135: socket_info_t *s;
136: int ret;
137:
138: DEBUG(2, "cs: trying erase request 0x%p...\n", busy);
139: if (busy->next)
140: remove_queue(busy);
141: req.Function = MTD_REQ_ERASE | cause;
142: req.TransferLength = erase->Size;
143: req.DestCardOffset = erase->Offset + erase->Handle->info.CardOffset;
144: req.MediaID = erase->Handle->MediaID;
145: mtd = erase->Handle->mtd;
146: s = SOCKET(mtd);
147: mtd->event_callback_args.mtdrequest = &req;
148: ret = EVENT(mtd, CS_EVENT_MTD_REQUEST, CS_EVENT_PRI_LOW);
149: if (ret == CS_BUSY) {
150: DEBUG(2, " Status = %d, requeueing.\n", req.Status);
151: switch (req.Status) {
152: case MTD_WAITREQ:
153: case MTD_WAITPOWER:
154: insert_queue(&mtd->erase_busy, busy);
155: break;
156: case MTD_WAITTIMER:
157: case MTD_WAITRDY:
158: if (req.Status == MTD_WAITRDY)
159: insert_queue(&s->erase_busy, busy);
160: mod_timer(&busy->timeout, jiffies + req.Timeout*HZ/1000);
161: break;
162: }
163: } else {
164: /* update erase queue status */
165: DEBUG(2, " Ret = %d\n", ret);
166: switch (ret) {
167: case CS_SUCCESS:
168: erase->State = ERASE_PASSED; break;
169: case CS_WRITE_PROTECTED:
170: erase->State = ERASE_MEDIA_WRPROT; break;
171: case CS_BAD_OFFSET:
172: erase->State = ERASE_BAD_OFFSET; break;
173: case CS_BAD_SIZE:
174: erase->State = ERASE_BAD_SIZE; break;
175: case CS_NO_CARD:
176: erase->State = ERASE_BAD_SOCKET; break;
177: default:
178: erase->State = ERASE_FAILED; break;
179: }
180: busy->client->event_callback_args.info = erase;
181: EVENT(busy->client, CS_EVENT_ERASE_COMPLETE, CS_EVENT_PRI_LOW);
182: kfree(busy);
183: /* Resubmit anything waiting for a request to finish */
184: wake_up_interruptible(&mtd->mtd_req);
185: retry_erase_list(&mtd->erase_busy, 0);
186: }
187: } /* retry_erase */
188:
189: void retry_erase_list(erase_busy_t *list, u_int cause)
190: {
191: erase_busy_t tmp = *list;
192:
193: DEBUG(2, "cs: rescanning erase queue list 0x%p\n", list);
194: if (list->next == list)
195: return;
196: /* First, truncate the original list */
197: list->prev->next = &tmp;
198: list->next->prev = &tmp;
199: list->prev = list->next = list;
200: tmp.prev->next = &tmp;
201: tmp.next->prev = &tmp;
202:
203: /* Now, retry each request, in order. */
204: while (tmp.next != &tmp)
205: retry_erase(tmp.next, cause);
206: } /* retry_erase_list */
207:
208: static void handle_erase_timeout(u_long arg)
209: {
210: DEBUG(0, "cs: erase timeout for entry 0x%lx\n", arg);
211: retry_erase((erase_busy_t *)arg, MTD_REQ_TIMEOUT);
212: }
213:
214: static void setup_erase_request(client_handle_t handle, eraseq_entry_t *erase)
215: {
216: erase_busy_t *busy;
217: region_info_t *info;
218:
219: if (CHECK_REGION(erase->Handle))
220: erase->State = ERASE_BAD_SOCKET;
221: else {
222: info = &erase->Handle->info;
223: if ((erase->Offset >= info->RegionSize) ||
224: (erase->Offset & (info->BlockSize-1)))
225: erase->State = ERASE_BAD_OFFSET;
226: else if ((erase->Offset+erase->Size > info->RegionSize) ||
227: (erase->Size & (info->BlockSize-1)))
228: erase->State = ERASE_BAD_SIZE;
229: else {
230: erase->State = 1;
231: busy = kmalloc(sizeof(erase_busy_t), GFP_KERNEL);
232: busy->erase = erase;
233: busy->client = handle;
234: init_timer(&busy->timeout);
235: busy->timeout.data = (u_long)busy;
236: busy->timeout.function = &handle_erase_timeout;
237: busy->prev = busy->next = NULL;
238: retry_erase(busy, 0);
239: }
240: }
241: } /* setup_erase_request */
242:
243: /*======================================================================
244:
245: MTD helper functions
246:
247: ======================================================================*/
248:
249: static int mtd_modify_window(window_handle_t win, mtd_mod_win_t *req)
250: {
251: if ((win == NULL) || (win->magic != WINDOW_MAGIC))
252: return CS_BAD_HANDLE;
253: win->ctl.flags = MAP_16BIT | MAP_ACTIVE;
254: if (req->Attributes & WIN_USE_WAIT)
255: win->ctl.flags |= MAP_USE_WAIT;
256: if (req->Attributes & WIN_MEMORY_TYPE)
257: win->ctl.flags |= MAP_ATTRIB;
258: win->ctl.speed = req->AccessSpeed;
259: win->ctl.card_start = req->CardOffset;
260: win->sock->ss_entry(win->sock->sock, SS_SetMemMap, &win->ctl);
261: return CS_SUCCESS;
262: }
263:
264: static int mtd_set_vpp(client_handle_t handle, mtd_vpp_req_t *req)
265: {
266: socket_info_t *s;
267: if (CHECK_HANDLE(handle))
268: return CS_BAD_HANDLE;
269: if (req->Vpp1 != req->Vpp2)
270: return CS_BAD_VPP;
271: s = SOCKET(handle);
272: s->socket.Vpp = req->Vpp1;
273: if (s->ss_entry(s->sock, SS_SetSocket, &s->socket))
274: return CS_BAD_VPP;
275: return CS_SUCCESS;
276: }
277:
278: static int mtd_rdy_mask(client_handle_t handle, mtd_rdy_req_t *req)
279: {
280: socket_info_t *s;
281: if (CHECK_HANDLE(handle))
282: return CS_BAD_HANDLE;
283: s = SOCKET(handle);
284: if (req->Mask & CS_EVENT_READY_CHANGE)
285: s->socket.csc_mask |= SS_READY;
286: else
287: s->socket.csc_mask &= ~SS_READY;
288: if (s->ss_entry(s->sock, SS_SetSocket, &s->socket))
289: return CS_GENERAL_FAILURE;
290: return CS_SUCCESS;
291: }
292:
293: int MTDHelperEntry(int func, void *a1, void *a2)
294: {
295: switch (func) {
296: case MTDRequestWindow:
297: return CardServices(RequestWindow, a1, a2, NULL);
298: case MTDReleaseWindow:
299: return CardServices(ReleaseWindow, a1, NULL, NULL);
300: case MTDModifyWindow:
301: return mtd_modify_window(a1, a2); break;
302: case MTDSetVpp:
303: return mtd_set_vpp(a1, a2); break;
304: case MTDRDYMask:
305: return mtd_rdy_mask(a1, a2); break;
306: default:
307: return CS_UNSUPPORTED_FUNCTION; break;
308: }
309: } /* MTDHelperEntry */
310:
311: /*======================================================================
312:
313: This stuff is used by Card Services to initialize the table of
314: region info used for subsequent calls to GetFirstRegion and
315: GetNextRegion.
316:
317: ======================================================================*/
318:
319: static void setup_regions(client_handle_t handle, int attr,
320: memory_handle_t *list)
321: {
322: int i, code, has_jedec, has_geo;
323: u_int offset;
324: cistpl_device_t device;
325: cistpl_jedec_t jedec;
326: cistpl_device_geo_t geo;
327: memory_handle_t r;
328:
329: DEBUG(1, "cs: setup_regions(0x%p, %d, 0x%p)\n",
330: handle, attr, list);
331:
332: code = (attr) ? CISTPL_DEVICE_A : CISTPL_DEVICE;
333: if (read_tuple(handle, code, &device) != CS_SUCCESS)
334: return;
335: code = (attr) ? CISTPL_JEDEC_A : CISTPL_JEDEC_C;
336: has_jedec = (read_tuple(handle, code, &jedec) == CS_SUCCESS);
337: if (has_jedec && (device.ndev != jedec.nid)) {
338: #ifdef PCMCIA_DEBUG
339: printk(KERN_DEBUG "cs: Device info does not match JEDEC info.\n");
340: #endif
341: has_jedec = 0;
342: }
343: code = (attr) ? CISTPL_DEVICE_GEO_A : CISTPL_DEVICE_GEO;
344: has_geo = (read_tuple(handle, code, &geo) == CS_SUCCESS);
345: if (has_geo && (device.ndev != geo.ngeo)) {
346: #ifdef PCMCIA_DEBUG
347: printk(KERN_DEBUG "cs: Device info does not match geometry tuple.\n");
348: #endif
349: has_geo = 0;
350: }
351:
352: offset = 0;
353: for (i = 0; i < device.ndev; i++) {
354: if ((device.dev[i].type != CISTPL_DTYPE_NULL) &&
355: (device.dev[i].size != 0)) {
356: r = kmalloc(sizeof(*r), GFP_KERNEL);
357: r->region_magic = REGION_MAGIC;
358: r->state = 0;
359: r->dev_info[0] = '\0';
360: r->mtd = NULL;
361: r->info.Attributes = (attr) ? REGION_TYPE_AM : 0;
362: r->info.CardOffset = offset;
363: r->info.RegionSize = device.dev[i].size;
364: r->info.AccessSpeed = device.dev[i].speed;
365: if (has_jedec) {
366: r->info.JedecMfr = jedec.id[i].mfr;
367: r->info.JedecInfo = jedec.id[i].info;
368: } else
369: r->info.JedecMfr = r->info.JedecInfo = 0;
370: if (has_geo) {
371: r->info.BlockSize = geo.geo[i].buswidth *
372: geo.geo[i].erase_block * geo.geo[i].interleave;
373: r->info.PartMultiple =
374: r->info.BlockSize * geo.geo[i].partition;
375: } else
376: r->info.BlockSize = r->info.PartMultiple = 1;
377: r->info.next = *list; *list = r;
378: }
379: offset += device.dev[i].size;
380: }
381: } /* setup_regions */
382:
383: /*======================================================================
384:
385: This is tricky. When get_first_region() is called by Driver
386: Services, we initialize the region info table in the socket
387: structure. When it is called by an MTD, we can just scan the
388: table for matching entries.
389:
390: ======================================================================*/
391:
392: static int match_region(client_handle_t handle, memory_handle_t list,
393: region_info_t *match)
394: {
395: while (list != NULL) {
396: if (!(handle->Attributes & INFO_MTD_CLIENT) ||
397: (strcmp(handle->dev_info, list->dev_info) == 0)) {
398: *match = list->info;
399: return CS_SUCCESS;
400: }
401: list = list->info.next;
402: }
403: return CS_NO_MORE_ITEMS;
404: } /* match_region */
405:
406: int get_first_region(client_handle_t handle, region_info_t *rgn)
407: {
408: socket_info_t *s = SOCKET(handle);
409: if (CHECK_HANDLE(handle))
410: return CS_BAD_HANDLE;
411:
412: if ((handle->Attributes & INFO_MASTER_CLIENT) &&
413: (!(s->state & SOCKET_REGION_INFO))) {
414: setup_regions(handle, 0, &s->c_region);
415: setup_regions(handle, 1, &s->a_region);
416: s->state |= SOCKET_REGION_INFO;
417: }
418:
419: if (rgn->Attributes & REGION_TYPE_AM)
420: return match_region(handle, s->a_region, rgn);
421: else
422: return match_region(handle, s->c_region, rgn);
423: } /* get_first_region */
424:
425: int get_next_region(client_handle_t handle, region_info_t *rgn)
426: {
427: if (CHECK_HANDLE(handle))
428: return CS_BAD_HANDLE;
429: return match_region(handle, rgn->next, rgn);
430: } /* get_next_region */
431:
432: /*======================================================================
433:
434: Connect an MTD with a memory region.
435:
436: ======================================================================*/
437:
438: int register_mtd(client_handle_t handle, mtd_reg_t *reg)
439: {
440: memory_handle_t list;
441: socket_info_t *s;
442:
443: if (CHECK_HANDLE(handle))
444: return CS_BAD_HANDLE;
445: s = SOCKET(handle);
446: if (reg->Attributes & REGION_TYPE_AM)
447: list = s->a_region;
448: else
449: list = s->c_region;
450: DEBUG(1, "cs: register_mtd(0x%p, '%s', 0x%x)\n",
451: handle, handle->dev_info, reg->Offset);
452: while (list) {
453: if (list->info.CardOffset == reg->Offset) break;
454: list = list->info.next;
455: }
456: if (list && (list->mtd == NULL) &&
457: (strcmp(handle->dev_info, list->dev_info) == 0)) {
458: list->info.Attributes = reg->Attributes;
459: list->MediaID = reg->MediaID;
460: list->mtd = handle;
461: handle->mtd_count++;
462: return CS_SUCCESS;
463: } else
464: return CS_BAD_OFFSET;
465: } /* register_mtd */
466:
467: /*======================================================================
468:
469: Erase queue management functions
470:
471: ======================================================================*/
472:
473: int register_erase_queue(client_handle_t *handle, eraseq_hdr_t *header)
474: {
475: eraseq_t *queue;
476:
477: if ((handle == NULL) || CHECK_HANDLE(*handle))
478: return CS_BAD_HANDLE;
479: queue = kmalloc(sizeof(*queue), GFP_KERNEL);
480: if (!queue) return CS_OUT_OF_RESOURCE;
481: queue->eraseq_magic = ERASEQ_MAGIC;
482: queue->handle = *handle;
483: queue->count = header->QueueEntryCnt;
484: queue->entry = header->QueueEntryArray;
485: *handle = (client_handle_t)queue;
486: return CS_SUCCESS;
487: } /* register_erase_queue */
488:
489: int deregister_erase_queue(eraseq_handle_t eraseq)
490: {
491: int i;
492: if (CHECK_ERASEQ(eraseq))
493: return CS_BAD_HANDLE;
494: for (i = 0; i < eraseq->count; i++)
495: if (ERASE_IN_PROGRESS(eraseq->entry[i].State)) break;
496: if (i < eraseq->count)
497: return CS_BUSY;
498: eraseq->eraseq_magic = 0;
499: kfree(eraseq);
500: return CS_SUCCESS;
501: } /* deregister_erase_queue */
502:
503: int check_erase_queue(eraseq_handle_t eraseq)
504: {
505: int i;
506: if (CHECK_ERASEQ(eraseq))
507: return CS_BAD_HANDLE;
508: for (i = 0; i < eraseq->count; i++)
509: if (eraseq->entry[i].State == ERASE_QUEUED)
510: setup_erase_request(eraseq->handle, &eraseq->entry[i]);
511: return CS_SUCCESS;
512: } /* check_erase_queue */
513:
514: /*======================================================================
515:
516: Look up the memory region matching the request, and return a
517: memory handle.
518:
519: ======================================================================*/
520:
521: int open_memory(client_handle_t *handle, open_mem_t *open)
522: {
523: socket_info_t *s;
524: memory_handle_t region;
525:
526: if ((handle == NULL) || CHECK_HANDLE(*handle))
527: return CS_BAD_HANDLE;
528: s = SOCKET(*handle);
529: if (open->Attributes & MEMORY_TYPE_AM)
530: region = s->a_region;
531: else
532: region = s->c_region;
533: while (region) {
534: if (region->info.CardOffset == open->Offset) break;
535: region = region->info.next;
536: }
537: if (region && region->mtd) {
538: *handle = (client_handle_t)region;
539: DEBUG(1, "cs: open_memory(0x%p, 0x%x) = 0x%p\n",
540: handle, open->Offset, region);
541: return CS_SUCCESS;
542: } else
543: return CS_BAD_OFFSET;
544: } /* open_memory */
545:
546: /*======================================================================
547:
548: Close a memory handle from an earlier call to OpenMemory.
549:
550: For the moment, I don't think this needs to do anything.
551:
552: ======================================================================*/
553:
554: int close_memory(memory_handle_t handle)
555: {
556: DEBUG(1, "cs: close_memory(0x%p)\n", handle);
557: if (CHECK_REGION(handle))
558: return CS_BAD_HANDLE;
559: return CS_SUCCESS;
560: } /* close_memory */
561:
562: /*======================================================================
563:
564: Read from a memory device, using a handle previously returned
565: by a call to OpenMemory.
566:
567: ======================================================================*/
568:
569: int read_memory(memory_handle_t handle, mem_op_t *req, caddr_t buf)
570: {
571: mtd_request_t mtd;
572: if (CHECK_REGION(handle))
573: return CS_BAD_HANDLE;
574: if (req->Offset >= handle->info.RegionSize)
575: return CS_BAD_OFFSET;
576: if (req->Offset+req->Count > handle->info.RegionSize)
577: return CS_BAD_SIZE;
578:
579: mtd.SrcCardOffset = req->Offset + handle->info.CardOffset;
580: mtd.TransferLength = req->Count;
581: mtd.MediaID = handle->MediaID;
582: mtd.Function = MTD_REQ_READ;
583: if (req->Attributes & MEM_OP_BUFFER_KERNEL)
584: mtd.Function |= MTD_REQ_KERNEL;
585: return do_mtd_request(handle, &mtd, buf);
586: } /* read_memory */
587:
588: /*======================================================================
589:
590: Write to a memory device, using a handle previously returned by
591: a call to OpenMemory.
592:
593: ======================================================================*/
594:
595: int write_memory(memory_handle_t handle, mem_op_t *req, caddr_t buf)
596: {
597: mtd_request_t mtd;
598: if (CHECK_REGION(handle))
599: return CS_BAD_HANDLE;
600: if (req->Offset >= handle->info.RegionSize)
601: return CS_BAD_OFFSET;
602: if (req->Offset+req->Count > handle->info.RegionSize)
603: return CS_BAD_SIZE;
604:
605: mtd.DestCardOffset = req->Offset + handle->info.CardOffset;
606: mtd.TransferLength = req->Count;
607: mtd.MediaID = handle->MediaID;
608: mtd.Function = MTD_REQ_WRITE;
609: if (req->Attributes & MEM_OP_BUFFER_KERNEL)
610: mtd.Function |= MTD_REQ_KERNEL;
611: return do_mtd_request(handle, &mtd, buf);
612: } /* write_memory */
613:
614: /*======================================================================
615:
616: This isn't needed for anything I could think of.
617:
618: ======================================================================*/
619:
620: int copy_memory(memory_handle_t handle, copy_op_t *req)
621: {
622: if (CHECK_REGION(handle))
623: return CS_BAD_HANDLE;
624: return CS_UNSUPPORTED_FUNCTION;
625: }
626:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.