throbber
iflash2+_mtd.c
`
`1 /*======================================================================
`2
`3 A simple MTD for Intel Series 2+ Flash devices
`4
`5 iflash2+_mtd.c 1.66 2000/07/24 20:41:31
`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 <dahinds@users.sourceforge.net>. 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 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.
`31
`32 For efficiency and simplicity, this driver is very block oriented.
`33 Reads and writes must not span erase block boundaries. Erases
`34 are limited to one erase block per request. This makes it much
`35 easier to manage multiple asynchronous erases efficiently.
`36
`37 ======================================================================*/
`38
`39 #include <pcmcia/config.h>
`40 #include <pcmcia/k_compat.h>
`41
`42 #ifdef __LINUX__
`43 #include <linux/kernel.h>
`44 #include <linux/module.h>
`45 #include <linux/init.h>
`46 #include <linux/sched.h>
`47 #include <linux/ptrace.h>
`48 #include <linux/malloc.h>
`49 #include <linux/string.h>
`50 #include <linux/timer.h>
`51 #include <linux/timex.h>
`52 #include <linux/major.h>
`53 #include <linux/fs.h>
`
`-1-
`
`APPLE INC.
`EXHIBIT 1036 - PAGE 0001
`
`

`
`iflash2+_mtd.c
`
`54 #include <linux/delay.h>
`55 #include <asm/io.h>
`56 #include <asm/system.h>
`57 #include <asm/segment.h>
`58 #endif
`59
`60 #include <stdarg.h>
`61
`62 #include <pcmcia/version.h>
`63 #include <pcmcia/cs_types.h>
`64 #include <pcmcia/cs.h>
`65 #include <pcmcia/bulkmem.h>
`66 #include <pcmcia/cistpl.h>
`67 #include <pcmcia/ds.h>
`68 #include <pcmcia/mem_op.h>
`69 #include "iflash.h"
`70
`71 #ifdef PCMCIA_DEBUG
`72 static int pc_debug = PCMCIA_DEBUG;
`73 MODULE_PARM(pc_debug, "i");
`74 #define DEBUG(n, args...) do { if (pc_debug>(n)) printk(KERN_INFO args); } while (0)
`75 static char *version =
`76 "iflash2+_mtd.c 1.66 2000/07/24 20:41:31 (David Hinds)";
`77 #else
`78 #define DEBUG(n, args...) do { } while (0)
`79 #endif
`80
`81 /*====================================================================*/
`82
`83 /* Parameters that can be set with 'insmod' */
`84
`85 #define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
`86
`87 INT_MODULE_PARM(word_width, 1);
`/* 1 = 16-bit */
`88 INT_MODULE_PARM(mem_speed, 0);
`/* in ns */
`89 INT_MODULE_PARM(vpp_timeout_period, 1000);
`/* in ms */
`90 INT_MODULE_PARM(vpp_settle, 100);
`/* in ms */
`91 INT_MODULE_PARM(write_timeout, 100);
`/* in ms */
`92 INT_MODULE_PARM(erase_timeout, 100);
`/* in ms */
`93 INT_MODULE_PARM(erase_limit, 10000);
`/* in ms */
`94 INT_MODULE_PARM(retry_limit, 8);
`/* write retries */
`95 INT_MODULE_PARM(max_tries, 4096);
`/* status polling */
`96 INT_MODULE_PARM(do_sleep, 1);
`/* spin vs sleep? */
`97
`98 /*====================================================================*/
`99
`100 static void flash_config(dev_link_t *link);
`101 static void flash_release(u_long arg);
`102 static int flash_event(event_t event, int priority,
`event_callback_args_t *args);
`103
`104
`105 static dev_link_t *flash_attach(void);
`106 static void flash_detach(dev_link_t *);
`
`-2-
`
`APPLE INC.
`EXHIBIT 1036 - PAGE 0002
`
`

`
`32
`
`iflash2+_mtd.c
`
`107
`108 #define MAX_CELLS
`109
`110 /* A flash region is composed of one or more "cells", where we allow
`111 simultaneous erases if they are in different cells */
`112 typedef struct flash_region_t {
`region;
`113
`region_info_t
`cell_size;
`114
`u_int
`struct flash_cell_t {
`115
`state;
`116
`u_int
`erase_time;
`117
`k_time_t
`erase_addr;
`118
`u_int
`erase_retries;
`119
`u_int
`} cell[MAX_CELLS];
`120
`121 } flash_region_t;
`122
`123 typedef struct flash_dev_t {
`link;
`124
`dev_link_t
`Base;
`125
`caddr_t
`Size;
`126
`u_int
`window_handle_t ESRwin;
`127
`ESRbase;
`128
`caddr_t
`vpp_usage;
`129
`int
`vpp_start;
`130
`k_time_t
`vpp_timeout;
`131
`struct timer_list
`*flash[2*CISTPL_MAX_DEVICES];
`132
`flash_region_t
`133 } flash_dev_t;
`134
`0x01
`135 #define FLASH_PENDING
`0x02
`136 #define FLASH_ERASING
`137 #define FLASH_ERASE_SUSPEND 0x04
`138
`139 static dev_info_t dev_info = "iflash2+_mtd";
`140
`141 static dev_link_t *dev_list = NULL;
`142
`143 /*====================================================================*/
`144
`145 static void cs_error(client_handle_t handle, int func, int ret)
`146 {
`147
`148
`149 }
`150
`151 #ifdef BENCHMARK
`152 static inline k_time_t uticks(void)
`153 {
`154
`155
`156
`157
`158
`159
`
`k_time_t count;
`outb_p(0x00, 0x43);
`count = inb_p(0x40);
`count |= inb(0x40) << 8;
`count = ((LATCH-1) - count) * 10000;
`count = (count + LATCH/2) / LATCH;
`
`error_info_t err = { func, ret };
`CardServices(ReportError, handle, &err);
`
`-3-
`
`APPLE INC.
`EXHIBIT 1036 - PAGE 0003
`
`

`
`count += jiffies * 10000;
`return count;
`
`iflash2+_mtd.c
`
`if (do_sleep)
`wsleeptimeout(queue, 1);
`else
`udelay(50);
`
`160
`161
`162 }
`163 #endif
`164
`165 /*======================================================================
`166
`167 Low level routines for programming the flash card.
`168
`169 ======================================================================*/
`170
`171 static void sleep_or_spin(wait_queue_head_t *queue)
`172 {
`173
`174
`175
`176
`177 }
`178
`179 static void log_esr(char *s, volatile u_short *esr)
`180 {
`181
`182
`183
`184
`185
`186
`187
`188
`189
`190 }
`191
`192 static void abort_cmd(volatile u_short *esr)
`193 {
`194
`195
`196
`197
`198
`199
`200
`201
`202
`203
`204 }
`205
`206 static int set_rdy_mode(volatile u_short *esr, u_short mode)
`207 {
`208
`209
`210
`211
`212
`
`writew(IF_ABORT, esr);
`writew(IF_READ_ESR, esr);
`for (i = 0; i < max_tries; i++)
`if ((readw(esr+4) & GSR_SLEEP) == GSR_SLEEP) break;
`if (i == max_tries)
`printk(KERN_NOTICE "iflash2+_mtd: abort cmd failed!\n");
`writew(IF_READ_ARRAY, esr);
`writew(IF_CLEAR_CSR, esr);
`
`u_short CSR, GSR, BSR;
`
`writew(IF_READ_CSR, esr);
`CSR = readw(esr);
`writew(IF_READ_ESR, esr);
`BSR = readw(esr+2);
`GSR = readw(esr+4);
`printk("%sCSR = 0x%04x, BSR = 0x%04x, GSR = 0x%04x\n",
`(s ? s : KERN_NOTICE), CSR, BSR, GSR);
`
`u_short i;
`
`u_short i, j;
`
`DEBUG(3, "iflash2+_mtd: set_rdy_mode(%04x)\n", mode);
`for (j = 0; j < retry_limit; j++) {
`writew(IF_READ_ESR, esr);
`
`-4-
`
`APPLE INC.
`EXHIBIT 1036 - PAGE 0004
`
`

`
`iflash2+_mtd.c
`
`for (i = 0; i < max_tries; i++)
`213
`if (!(readw(esr+4) & GSR_QUEUE_FULL)) break;
`214
`if (i == max_tries)
`215
`goto failed;
`216
`writew(IF_RDY_MODE, esr);
`217
`writew(mode, esr);
`218
`writew(IF_READ_ESR, esr);
`219
`for (i = 0; i < max_tries; i++)
`220
`if ((readw(esr+4) & GSR_WR_READY) == GSR_WR_READY) break;
`221
`if (i == max_tries)
`222
`goto failed;
`223
`if (!(readw(esr+4) & GSR_OP_ERR))
`224
`return CS_SUCCESS;
`225
`writew(IF_READ_ARRAY, esr);
`226
`writew(IF_CLEAR_CSR, esr);
`227
`}
`228
`229 failed:
`printk(KERN_NOTICE "iflash2+_mtd: set_rdy_mode failed!\n");
`230
`log_esr(NULL, esr);
`231
`return CS_GENERAL_FAILURE;
`232
`233 }
`234
`235 static int check_write(wait_queue_head_t *queue, volatile u_short *esr)
`236 {
`237
`238
`239
`240
`241
`242
`243
`244
`245
`246
`247
`248
`249
`250
`251
`252 }
`253
`254 static int page_setup(wait_queue_head_t *queue, volatile u_short *esr,
`volatile u_short *address, u_short count)
`255
`256 {
`257
`258
`259
`260
`261
`262
`263
`264
`265
`
`u_long end = jiffies + write_timeout;
`writew(IF_READ_ESR, esr);
`while (((readw(esr+2) & BSR_READY) != BSR_READY) &&
`(jiffies < end))
`sleep_or_spin(queue);
`if ((readw(esr+2) & BSR_READY) != BSR_READY) {
`printk(KERN_NOTICE "iflash2+_mtd: check_write: timed out!\n");
`log_esr(NULL, esr);
`return CS_GENERAL_FAILURE;
`}
`if (readw(esr+2) & BSR_FAILED) {
`log_esr(KERN_DEBUG "write error: ", esr);
`return CS_WRITE_FAILURE;
`} else
`return CS_SUCCESS;
`
`u_long end = jiffies + write_timeout;
`u_short nw;
`writew(IF_READ_ESR, esr);
`while (((readw(esr+4) & GSR_PAGE_AVAIL) != GSR_PAGE_AVAIL) &&
`(jiffies < end))
`sleep_or_spin(queue);
`if ((readw(esr+4) & GSR_PAGE_AVAIL) != GSR_PAGE_AVAIL) {
`printk(KERN_NOTICE "iflash2+_mtd: page_setup timed out\n");
`log_esr(NULL, esr);
`
`-5-
`
`APPLE INC.
`EXHIBIT 1036 - PAGE 0005
`
`

`
`iflash2+_mtd.c
`
`return CS_GENERAL_FAILURE;
`}
`
`nw = count >> 1;
`if (nw == 0) {
`/* Special case of single byte write */
`writeb(LOW(IF_SINGLE_LOAD), address);
`} else {
`writew(IF_SEQ_LOAD, address);
`/* Tricky: split count into low bytes and high bytes */
`nw = (count-nw-1) | ((nw-1) << 8);
`if ((u_long)address & 2) {
`writew(0, address);
`writew(nw, address);
`} else {
`writew(nw, address);
`writew(0, address);
`
`}
`}
`return CS_SUCCESS;
`
`u_short nw;
`u_short i;
`
`266
`267
`268
`269
`270
`271
`272
`273
`274
`275
`276
`277
`278
`279
`280
`281
`282
`283
`284
`285
`286 }
`287
`288 static int page_write(volatile u_short *esr, volatile u_short *address,
`u_short count)
`289
`290 {
`291
`292
`293
`294
`295
`296
`297
`298
`299
`300
`301
`302
`303
`304
`305
`306
`307
`308
`309
`310
`311
`312
`313
`314
`315
`316
`317
`318
`
`writew(IF_READ_ESR, esr);
`for (i = 0; i < max_tries; i++)
`if (!(readw(esr+2) & BSR_QUEUE_FULL)) break;
`if (i == max_tries) {
`printk(KERN_NOTICE "iflash2+_mtd: page_write timed out\n");
`log_esr(NULL, esr);
`return CS_GENERAL_FAILURE;
`}
`nw = count >> 1;
`if (nw == 0) {
`writeb(LOW(IF_PAGE_WRITE), address);
`writeb(0, address);
`writeb(0, address);
`} else {
`writew(IF_PAGE_WRITE, address);
`/* Tricky: split count into low bytes and high bytes */
`nw = (count-nw-1) | ((nw-1) << 8);
`if ((u_long)address & 2) {
`writew(0, address);
`writew(nw, address);
`} else {
`writew(nw, address);
`writew(0, address);
`
`}
`}
`
`-6-
`
`APPLE INC.
`EXHIBIT 1036 - PAGE 0006
`
`

`
`return CS_SUCCESS;
`
`iflash2+_mtd.c
`
`u_short CSR;
`writew(IF_READ_CSR, address);
`CSR = readw(address);
`if ((CSR & CSR_WR_READY) != CSR_WR_READY) {
`return CS_BUSY;
`} else if (CSR & (CSR_ERA_ERR | CSR_VPP_LOW | CSR_WR_ERR)) {
`log_esr(KERN_NOTICE "erase error: ", address);
`return CS_WRITE_FAILURE;
`} else
`return CS_SUCCESS;
`
`writew(IF_BLOCK_ERASE, address);
`writew(IF_CONFIRM, address);
`
`319
`320 }
`321
`322 static void block_erase(volatile u_short *address)
`323 {
`324
`325
`326 }
`327
`328 static int check_erase(volatile u_short *address)
`329 {
`330
`331
`332
`333
`334
`335
`336
`337
`338
`339
`340 }
`341
`342 static int suspend_erase(volatile u_short *esr)
`343 {
`344
`345
`346
`347
`348
`349
`350
`351
`352
`353
`354
`355
`356
`357
`358 }
`359
`360 static void resume_erase(volatile u_short *esr)
`361 {
`362
`363
`364
`365
`366
`367 }
`368
`369 static void reset_block(volatile u_short *esr)
`370 {
`371
`
`u_short i;
`
`DEBUG(1, "iflash2+_mtd: suspending erase...\n");
`writew(IF_ERASE_SUSPEND, esr);
`writew(IF_READ_ESR, esr);
`for (i = 0; i < max_tries; i++)
`if ((readw(esr+4) & GSR_WR_READY) == GSR_WR_READY) break;
`if (i == max_tries) {
`printk(KERN_NOTICE "iflash2+_mtd: suspend_erase timed out\n");
`log_esr(NULL, esr);
`return CS_GENERAL_FAILURE;
`}
`writew(IF_READ_ARRAY, esr);
`return CS_SUCCESS;
`
`DEBUG(1, "iflash2+_mtd: resuming erase...\n");
`writew(IF_READ_ESR, esr);
`/* Only give resume signal if the erase is really suspended */
`if (readw(esr+4) & GSR_OP_SUSPEND)
`writew(IF_CONFIRM, esr);
`
`writew(IF_READ_ARRAY, esr);
`
`-7-
`
`APPLE INC.
`EXHIBIT 1036 - PAGE 0007
`
`

`
`writew(IF_CLEAR_CSR, esr);
`
`iflash2+_mtd.c
`
`mtd_mod_win_t mod;
`mod.Attributes = WIN_MEMORY_TYPE_AM;
`mod.AccessSpeed = 250;
`mod.CardOffset = 0x4000;
`MTDHelperEntry(MTDModifyWindow, win, &mod);
`writeb((set) ? WP_BLKEN : 0, base+CISREG_WP);
`
`372
`373 }
`374
`375 /*====================================================================*/
`376
`377 static void set_global_lock(window_handle_t win,
`volatile caddr_t base, int set)
`378
`379 {
`380
`381
`382
`383
`384
`385
`386 }
`387
`388 /*======================================================================
`389
`390 Vpp management functions. The vpp_setup() function checks to
`391 see if Vpp is available for the specified device. If not, it
`392 turns on Vpp. The vpp_shutdown() function is scheduled to turn
`393 Vpp off after an interval of inactivity.
`394
`395 vpp_setup() assumes that it will be called at the top of a
`396 request handler, and that it can use the MTD_REQ_TIMEOUT flag
`397 to tell if it has already been called for this particular
`398 request, so that it can count Vpp users.
`399
`400 A handler should call vpp_shutdown() once for each request that
`401 does a vpp_setup().
`402
`403 ======================================================================*/
`404
`405 static int vpp_setup(dev_link_t *link, mtd_request_t *req)
`406 {
`407
`408
`409
`410
`411
`412
`413
`414
`415
`416
`417
`418
`419
`420
`421
`422
`423
`424
`
`/* First time for this request? */
`if (!(req->Function & MTD_REQ_TIMEOUT)) {
`/* If no other users, kill shutdown timer and apply power */
`if (++dev->vpp_usage == 1) {
`if (!del_timer(&dev->vpp_timeout)) {
`DEBUG(1, "iflash2+_mtd: raising Vpp...\n");
`dev->vpp_start = jiffies;
`vpp_req.Vpp1 = vpp_req.Vpp2 = 120;
`MTDHelperEntry(MTDSetVpp, link->handle, &vpp_req);
`}
`
`flash_dev_t *dev = (flash_dev_t *)link->priv;
`mtd_vpp_req_t vpp_req;
`
`}
`}
`/* Wait for Vpp to settle if it was just applied */
`if (jiffies < dev->vpp_start + vpp_settle) {
`req->Status = MTD_WAITTIMER;
`
`-8-
`
`APPLE INC.
`EXHIBIT 1036 - PAGE 0008
`
`

`
`iflash2+_mtd.c
`
`req->Timeout = vpp_settle * 1000 / HZ;
`return 1;
`}
`return 0;
`
`dev_link_t *link = (dev_link_t *)arg;
`flash_dev_t *dev;
`mtd_vpp_req_t req;
`
`DEBUG(1, "iflash2+_mtd: lowering Vpp...\n");
`dev = (flash_dev_t *)link->priv;
`dev->vpp_timeout.expires = 0;
`req.Vpp1 = req.Vpp2 = 0;
`MTDHelperEntry(MTDSetVpp, link->handle, &req);
`
`flash_dev_t *dev;
`dev = (flash_dev_t *)link->priv;
`dev->vpp_usage--;
`if (dev->vpp_usage == 0) {
`dev->vpp_timeout.expires = jiffies + vpp_timeout_period;
`add_timer(&dev->vpp_timeout);
`}
`
`425
`426
`427
`428
`429 }
`430
`431 static void vpp_off(u_long arg)
`432 {
`433
`434
`435
`436
`437
`438
`439
`440
`441
`442 }
`443
`444 static void vpp_shutdown(dev_link_t *link)
`445 {
`446
`447
`448
`449
`450
`451
`452
`453 }
`454
`455 /*======================================================================
`456
`457 flash_attach() creates an "instance" of the driver, allocating
`458 local data structures for one device. The device is registered
`459 with Card Services.
`460
`461 ======================================================================*/
`462
`463 static dev_link_t *flash_attach(void)
`464 {
`465
`466
`467
`468
`469
`470
`471
`472
`473
`474
`475
`476
`477
`
`client_reg_t client_reg;
`dev_link_t *link;
`flash_dev_t *dev;
`int ret;
`
`DEBUG(0, "iflash2+_mtd: flash_attach()\n");
`
`/* Create new memory card device */
`dev = kmalloc(sizeof(*dev), GFP_KERNEL);
`if (!dev) return NULL;
`memset(dev, 0, sizeof(*dev));
`link = &dev->link; link->priv = dev;
`
`-9-
`
`APPLE INC.
`EXHIBIT 1036 - PAGE 0009
`
`

`
`link->release.function = &flash_release;
`link->release.data = (u_long)link;
`init_waitqueue_head(&link->pending);
`
`dev->vpp_timeout.function = vpp_off;
`dev->vpp_timeout.data = (u_long)link;
`
`iflash2+_mtd.c
`
`/* Register with Card Services */
`link->next = dev_list;
`dev_list = link;
`client_reg.dev_info = &dev_info;
`client_reg.Attributes = INFO_MTD_CLIENT | INFO_CARD_SHARE;
`client_reg.EventMask =
`CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
`CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
`CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME |
`CS_EVENT_READY_CHANGE;
`client_reg.event_handler = &flash_event;
`client_reg.Version = 0x0210;
`client_reg.event_callback_args.client_data = link;
`ret = CardServices(RegisterClient, &link->handle, &client_reg);
`if (ret != 0) {
`cs_error(link->handle, RegisterClient, ret);
`flash_detach(link);
`return NULL;
`}
`
`478
`479
`480
`481
`482
`483
`484
`485
`486
`487
`488
`489
`490
`491
`492
`493
`494
`495
`496
`497
`498
`499
`500
`501
`502
`503
`504
`return link;
`505
`506 } /* flash_attach */
`507
`508 /*======================================================================
`509
`510 This deletes a driver "instance". The device is de-registered
`511 with Card Services. If it has been released, all local data
`512 structures are freed. Otherwise, the structures will be freed
`513 when the device is released.
`514
`515 ======================================================================*/
`516
`517 static void flash_detach(dev_link_t *link)
`518 {
`519
`520
`521
`522
`523
`524
`525
`526
`527
`528
`529
`530
`
`dev_link_t **linkp;
`int ret;
`
`DEBUG(0, "iflash2+_mtd: flash_detach(0x%p)\n", link);
`
`/* Locate device structure */
`for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
`if (*linkp == link) break;
`if (*linkp == NULL)
`return;
`
`del_timer(&link->release);
`
`-10-
`
`APPLE INC.
`EXHIBIT 1036 - PAGE 0010
`
`

`
`if (link->state & DEV_CONFIG)
`flash_release((u_long)link);
`
`iflash2+_mtd.c
`
`if (link->handle) {
`ret = CardServices(DeregisterClient, link->handle);
`if (ret != CS_SUCCESS)
`cs_error(link->handle, DeregisterClient, ret);
`
`}
`
`/* Unlink device structure, free bits */
`*linkp = link->next;
`kfree(link->priv);
`
`531
`532
`533
`534
`535
`536
`537
`538
`539
`540
`541
`542
`543
`544 } /* flash_detach */
`545
`546 /*======================================================================
`547
`548 flash_config() is scheduled to run after a CARD_INSERTION event
`549 is received, to bind the MTD to appropriate memory regions.
`550
`551 ======================================================================*/
`552
`553 static void printk_size(u_int sz)
`554 {
`555
`556
`557
`558
`559
`560
`561 }
`562
`563 static void flash_config(dev_link_t *link)
`564 {
`565
`566
`567
`568
`569
`570
`571
`572
`573
`574
`575
`576
`577
`578
`579
`580
`581
`582
`583
`
`/* Allocate a small memory window */
`if (word_width)
`req.Attributes = WIN_DATA_WIDTH_16;
`else
`req.Attributes = WIN_DATA_WIDTH_8;
`req.Base = req.Size = 0;
`req.AccessSpeed = mem_speed;
`link->win = (window_handle_t)handle;
`ret = MTDHelperEntry(MTDRequestWindow, &link->win, &req);
`if (ret != 0) {
`
`if (sz & 0x3ff)
`printk("%u bytes", sz);
`else if (sz & 0x0fffff)
`printk("%u kb", sz >> 10);
`else
`printk("%u mb", sz >> 20);
`
`client_handle_t handle = link->handle;
`flash_dev_t *dev = link->priv;
`win_req_t req;
`mtd_reg_t reg;
`region_info_t region;
`int i, attr, ret;
`
`DEBUG(0, "iflash2+_mtd: flash_config(0x%p)\n", link);
`
`-11-
`
`APPLE INC.
`EXHIBIT 1036 - PAGE 0011
`
`

`
`iflash2+_mtd.c
`
`584
`585
`586
`587
`588
`589
`590
`591
`592
`593
`594
`595
`596
`597
`598
`599
`600
`601
`602
`603
`604
`605
`606
`607
`608
`609
`610
`611
`612
`613
`614
`615
`616
`617
`618
`619
`620
`621
`622
`623
`624
`625
`626
`627
`628
`629
`630
`631
`632
`633
`634
`635
`636
`
`cs_error(handle, RequestWindow, ret);
`link->state &= ~DEV_CONFIG_PENDING;
`flash_release((u_long)link);
`return;
`}
`dev->Base = ioremap(req.Base, req.Size);
`dev->Size = req.Size;
`
`/* Allocate a memory window for ESR accesses*/
`req.Base = 0;
`dev->ESRwin = (window_handle_t)handle;
`ret = MTDHelperEntry(MTDRequestWindow, &dev->ESRwin, &req);
`if (ret != 0) {
`cs_error(handle, RequestWindow, ret);
`link->state &= ~DEV_CONFIG_PENDING;
`flash_release((u_long)link);
`return;
`}
`dev->ESRbase = ioremap(req.Base, req.Size);
`
`link->state |= DEV_CONFIG;
`
`/* Grab info for all the memory regions we can access */
`i = 0;
`for (attr = 0; attr < 2; attr++) {
`region.Attributes = attr ? REGION_TYPE_AM : REGION_TYPE_CM;
`ret = CardServices(GetFirstRegion, handle, &region);
`while (ret == CS_SUCCESS) {
`reg.Attributes = region.Attributes;
`reg.Offset = region.CardOffset;
`dev->flash[i] = kmalloc(sizeof(struct flash_region_t),
`GFP_KERNEL);
`if (!dev->flash[i]) break;
`reg.MediaID = (u_long)dev->flash[i];
`ret = CardServices(RegisterMTD, handle, &reg);
`if (ret != 0) {
`kfree(dev->flash[i]);
`break;
`}
`printk(KERN_INFO "iflash2+_mtd: %s at 0x%x, ",
`attr ? "attr" : "common", region.CardOffset);
`printk_size(region.RegionSize);
`printk(", ");
`printk_size(region.BlockSize);
`printk(" blocks, %u ns\n", region.AccessSpeed);
`memset(dev->flash[i], 0, sizeof(struct flash_region_t));
`dev->flash[i]->region = region;
`/* Distinguish between 4MB..20MB cards and 40MB cards */
`if (region.RegionSize > 0x1400000)
`dev->flash[i]->cell_size = 0x800000; /* 8MB components */
`else
`dev->flash[i]->cell_size = 0x400000; /* 4MB components */
`i++;
`
`-12-
`
`APPLE INC.
`EXHIBIT 1036 - PAGE 0012
`
`

`
`ret = CardServices(GetNextRegion, handle, &region);
`
`iflash2+_mtd.c
`
`}
`}
`dev->flash[i] = NULL;
`
`dev_link_t *link = (dev_link_t *)arg;
`flash_dev_t *dev = link->priv;
`int i;
`
`DEBUG(0, "iflash2+_mtd: flash_release(0x%p)\n", link);
`
`link->state &= ~DEV_CONFIG;
`if (link->win) {
`iounmap(dev->Base);
`i = MTDHelperEntry(MTDReleaseWindow, link->win);
`if (i != CS_SUCCESS)
`cs_error(link->handle, ReleaseWindow, i);
`
`}
`if (dev->ESRwin) {
`iounmap(dev->ESRbase);
`i = MTDHelperEntry(MTDReleaseWindow, dev->ESRwin);
`if (i != CS_SUCCESS)
`cs_error(link->handle, ReleaseWindow, i);
`
`637
`638
`639
`640
`641
`642 } /* flash_config */
`643
`644 /*======================================================================
`645
`646 After a card is removed, flash_release() will release the memory
`647 window allocated for this socket.
`648
`649 ======================================================================*/
`650
`651 static void flash_release(u_long arg)
`652 {
`653
`654
`655
`656
`657
`658
`659
`660
`661
`662
`663
`664
`665
`666
`667
`668
`669
`670
`671
`672
`673
`674
`675
`676
`677
`678
`679
`680
`681 } /* flash_release */
`682
`683 /*======================================================================
`684
`685 The read request handler. This handler supports suspending
`686 current erase requests. Reading from a block that is currently
`687 erasing is undefined.
`688
`689 ======================================================================*/
`
`}
`if (dev->vpp_usage == 0)
`del_timer(&dev->vpp_timeout);
`vpp_off((u_long)link);
`for (i = 0; (i < 2*CISTPL_MAX_DEVICES) && dev->flash[i]; i++)
`kfree(dev->flash[i]);
`
`if (link->state & DEV_STALE_LINK)
`flash_detach(link);
`
`-13-
`
`APPLE INC.
`EXHIBIT 1036 - PAGE 0013
`
`

`
`iflash2+_mtd.c
`
`DEBUG(2, "iflash2+_mtd: flash_read(0x%p, 0x%lx, 0x%p, 0x%x, "
`"0x%x)\n", link, req->MediaID, buf, req->SrcCardOffset,
`req->TransferLength);
`
`flash = (flash_region_t *)(req->MediaID);
`region = &flash->region;
`if ((req->SrcCardOffset / region->BlockSize) !=
`((req->SrcCardOffset+req->TransferLength-1) / region->BlockSize))
`return CS_BAD_SIZE;
`if (region->Attributes & REGION_TYPE_AM)
`mod.Attributes = WIN_MEMORY_TYPE_AM;
`else
`mod.Attributes = WIN_MEMORY_TYPE_CM;
`mod.AccessSpeed = region->AccessSpeed;
`
`690
`691 static int flash_read(dev_link_t *link, char *buf, mtd_request_t *req)
`692 {
`flash_dev_t *dev = (flash_dev_t *)link->priv;
`693
`flash_region_t *flash;
`694
`region_info_t *region;
`695
`mtd_mod_win_t mod;
`696
`u_int from, length, nb, cell;
`697
`int ret;
`698
`699 #ifdef BENCHMARK
`k_time_t time;
`700
`701 #endif
`702
`703
`704
`705
`706
`707
`708
`709
`710
`711
`712
`713
`714
`715
`716
`717
`718
`719
`720
`721
`722
`723
`724
`725
`726
`727
`728
`729
`730
`731
`732
`733
`734
`735
`736
`737
`738
`739
`ret = CS_SUCCESS;
`740
`741 #ifdef BENCHMARK
`time = uticks();
`742
`
`/* Suspend an in-progress block erase */
`cell = (req->SrcCardOffset - region->CardOffset) / flash->cell_size;
`if (flash->cell[cell].state & FLASH_ERASING) {
`if ((flash->cell[cell].erase_addr / region->BlockSize) ==
`(req->SrcCardOffset / region->BlockSize)) {
`DEBUG(1, "iflash2+_mtd: delaying read...\n");
`req->Status = MTD_WAITREQ;
`return CS_BUSY;
`
`}
`link->state |= DEV_BUSY;
`mod.CardOffset = flash->cell[cell].erase_addr;
`ret = MTDHelperEntry(MTDModifyWindow, dev->ESRwin, &mod);
`if (ret != CS_SUCCESS) goto done;
`ret = suspend_erase((u_short *)dev->ESRbase);
`if (ret != CS_SUCCESS) goto done;
`flash->cell[cell].state |= FLASH_ERASE_SUSPEND;
`} else
`link->state |= DEV_BUSY;
`
`mod.CardOffset = req->SrcCardOffset & ~(dev->Size-1);
`from = req->SrcCardOffset & (dev->Size-1);
`
`-14-
`
`APPLE INC.
`EXHIBIT 1036 - PAGE 0014
`
`

`
`iflash2+_mtd.c
`
`if (req->Function & MTD_REQ_KERNEL)
`copy_from_pc(buf, &dev->Base[from], nb);
`
`else
`
`copy_pc_to_user(buf, &dev->Base[from], nb);
`
`buf += nb;
`from = 0;
`mod.CardOffset += dev->Size;
`}
`
`ret = MTDHelperEntry(MTDModifyWindow, link->win, &mod);
`if (ret != CS_SUCCESS) goto done;
`nb = (from+length > dev->Size) ? dev->Size-from : length;
`
`743 #endif
`for (length = req->TransferLength; length > 0; length -= nb) {
`744
`745
`746
`747
`748
`749
`750
`751
`752
`753
`754
`755
`756
`757
`758
`759
`760 #ifdef BENCHMARK
`time = uticks() - time;
`761
`if (time < 10000000)
`762
`DEBUG(3, "iflash2+_mtd: read complete, time = %ld,"
`763
`" avg = %ld ns/word, rate = %ld kb/sec\n", time,
`764
`time*2000/req->TransferLength,
`765
`req->TransferLength*977/time);
`766
`767 #endif
`768
`769 done:
`if (flash->cell[cell].state & FLASH_ERASE_SUSPEND) {
`770
`resume_erase((u_short *)dev->ESRbase);
`771
`flash->cell[cell].state &= ~FLASH_ERASE_SUSPEND;
`772
`}
`773
`link->state &= ~DEV_BUSY;
`774
`return ret;
`775
`776 } /* flash_read */
`777
`778 /*======================================================================
`779
`780 basic_write() handles a write that fits completely within a
`781 memory window that has already been set up. It does a series
`782 of pipelined page buffer writes.
`783
`784 ======================================================================*/
`785
`786 static int basic_write(wait_queue_head_t *queue, char *esr, char *dest,
`char *buf, u_int nb, u_int is_krnl)
`787
`788 {
`789
`790
`791
`792
`793
`794
`795
`
`u_short npb;
`int ret;
`
`/* Enable interrupts on write complete */
`ret = set_rdy_mode((u_short *)esr, IF_RDY_LEVEL);
`if (ret != CS_SUCCESS) return ret;
`
`-15-
`
`APPLE INC.
`EXHIBIT 1036 - PAGE 0015
`
`

`
`iflash2+_mtd.c
`
`}
`ret = page_write((u_short *)esr, (u_short *)dest, 1);
`if (ret != CS_SUCCESS) return ret;
`dest++; buf++; nb--;
`}
`
`for (; nb > 0; nb -= npb) {
`/* npb = # of bytes to write to page buffer */
`npb = (nb > 512) ? 512 : nb;
`/* sleep until page buffer is free */
`ret = page_setup(queue, (u_short *)esr, (u_short *)dest, npb);
`if (ret != CS_SUCCESS) return ret;
`
`if (is_krnl)
`copy_to_pc(dest, buf, npb);
`
`else
`
`copy_user_to_pc(dest, buf, npb);
`
`ret = page_write((u_short *)esr, (u_short *)dest, npb);
`if (ret != CS_SUCCESS) return ret;
`check_write(queue, (u_short *)esr);
`
`/* Fix for mis-aligned writes */
`if ((u_long)dest & 1) {
`DEBUG(2, "iflash2+_mtd: odd address fixup at 0x%p\n", dest);
`ret = page_setup(queue, (u_short *)esr, (u_short *)dest, 1);
`if (ret != CS_SUCCESS) return ret;
`if (is_krnl)
`writeb(*buf, dest);
`else {
`char c;
`get_user(c, buf);
`writeb(c, dest);
`
`796
`797
`798
`799
`800
`801
`802
`803
`804
`805
`806
`807
`808
`809
`810
`811
`812
`813
`814
`815
`816
`817
`818
`819
`820
`821
`822
`823
`824
`825
`826
`827
`828
`829
`830
`831
`832
`833
`834
`835 }
`836
`837 /*======================================================================
`838
`839 The write request handler. The Series 2+ cards support automatic
`840 erase suspend for writes.
`841
`842 ======================================================================*/
`843
`844 static int flash_write(dev_link_t *link, char *buf, mtd_request_t *req)
`845 {
`846
`847
`848
`
`dest += npb;
`buf += npb;
`}
`
`/* sleep until block is ready */
`return check_write(queue, (u_short *)esr);
`
`flash_dev_t *dev = (flash_dev_t *)link->priv;
`mtd_mod_win_t mod;
`mtd_rdy_req_t rdy;
`
`-16-
`
`APPLE INC.
`EXHIBIT 1036 - PAGE 0016
`
`

`
`iflash2+_mtd.c
`
`DEBUG(2, "iflash2+_mtd: flash_write(0x%p, 0x%lx, "
`"0x%p, 0x%x, 0x%x)\n", link, req->MediaID, buf,
`req->DestCardOffset, req->TransferLength);
`
`/* Check card write protect status */
`ret = CardServices(GetStatus, link->handle, &status);
`if (ret != CS_SUCCESS) {
`cs_error(link->handle, GetStatus, ret);
`return CS_GENERAL_FAILURE;
`}
`if (status.CardState & CS_EVENT_WRITE_PROTECT)
`return CS_WRITE_PROTECTED;
`
`flash = (flash_region_t *)(req->MediaID);
`region = &flash->region;
`if ((req->DestCardOffset / region->BlockSize) !=
`((req->DestCardOffset+req->TransferLength-1) / region->BlockSize))
`return CS_BAD_SIZE;
`
`/* Is this cell being erased or written? */
`cell = (req->DestCardOffset - region->CardOffset) / flash->cell_size;
`if (flash->cell[cell].state & FLASH_ERASING) {
`DEBUG(1, "iflash2+_mtd: delaying write...\n");
`req->Status = MTD_WAITREQ;
`return CS_BUSY;
`}
`link->state |= DEV_BUSY;
`
`flash_region_t *flash;
`849
`region_info_t *region;
`850
`u_int from, length, nb, retry, cell;
`851
`cs_status_t status;
`852
`int ret;
`853
`854 #ifdef BENCHMARK
`k_time_t time;
`855
`856 #endif
`857
`858
`859
`860
`861
`862
`863
`864
`865
`866
`867
`868
`869
`870
`871
`872
`873
`874
`875
`876
`877
`878
`879
`880
`881
`882
`883
`884
`885
`886
`887
`888
`889
`890
`891
`892
`893
`894
`895
`896
`897
`898
`899
`900
`901
`
`if (vpp_setup(link, req) != 0)
`return CS_BUSY;
`
`if (region->Attributes & REGION_TYPE_AM)
`mod.Attributes = WIN_MEMORY_TYPE_AM;
`else
`mod.Attributes = WIN_MEMORY_TYPE_CM;
`mod.AccessSpeed = region->AccessSpeed;
`
`/* Set up window for ESR accesses */
`mod.CardOffset = req->DestCardOffset & ~(region->BlockSize-1);
`ret = MTDHelperEntry(MTDModifyWindow, dev->ESRwin, &mod);
`if (ret != CS_SUCCESS) goto done;
`
`rdy.Mask = CS_EVENT_READY_CHANGE;
`MTDHelperEntry(MTDRDYMask, link->handle, &rdy);
`
`-17-
`
`APPLE INC.
`EXHIBIT 1036 - PAGE 0017
`
`

`
`iflash2+_mtd.c
`
`for (length = req->TransferLength ; length > 0; length -= nb) {
`ret = MTDHelperEntry(MTDModifyWindow, link->win, &mod);
`if (ret != CS_SUCCESS) goto done;
`
`nb = (from+length > dev->Size) ? dev->Size-from : length;
`
`}
`if (retry == retry_limit) {
`printk(KERN_NOTICE "iflash2+_mtd: write at 0x%06x failed:"
`" too many retries!\n", mod.CardOffset);
`goto done;
`
`}
`
`buf += nb;
`from = 0;
`mod.CardOffset += dev->Size;
`}
`
`for (retry = 0; retry < retry_limit; retry++) {
`ret = basic_write(&link->pending, dev->ESRbase,
`dev->Base+from, buf, nb,
`(req->Function & MTD_REQ_KERNEL));
`if (ret == CS_SUCCESS)
`break;
`abort_cmd((u_short *)dev->ESRbase);
`
`902
`903 #ifdef BENCHMARK
`time = uticks();
`904
`905 #endif
`mod.CardOffset = req->DestCardOffset & ~(dev->Size-1);
`906
`from = req->DestCardOffset & (dev->Size-1);
`907
`908
`909
`910
`911
`912
`913
`914
`915
`916
`917
`918
`919
`920
`921
`922
`923
`924
`925
`926
`927
`928
`929
`930
`931
`93

This document is available on Docket Alarm but you must sign up to view it.


Or .

Accessing this document will incur an additional charge of $.

After purchase, you can access this document again without charge.

Accept $ Charge
throbber

Still Working On It

This document is taking longer than usual to download. This can happen if we need to contact the court directly to obtain the document and their servers are running slowly.

Give it another minute or two to complete, and then try the refresh button.

throbber

A few More Minutes ... Still Working

It can take up to 5 minutes for us to download a document if the court servers are running slowly.

Thank you for your continued patience.

This document could not be displayed.

We could not find this document within its docket. Please go back to the docket page and check the link. If that does not work, go back to the docket and refresh it to pull the newest information.

Your account does not support viewing this document.

You need a Paid Account to view this document. Click here to change your account type.

Your account does not support viewing this document.

Set your membership status to view this document.

With a Docket Alarm membership, you'll get a whole lot more, including:

  • Up-to-date information for this case.
  • Email alerts whenever there is an update.
  • Full text search for other cases.
  • Get email alerts whenever a new case matches your search.

Become a Member

One Moment Please

The filing “” is large (MB) and is being downloaded.

Please refresh this page in a few minutes to see if the filing has been downloaded. The filing will also be emailed to you when the download completes.

Your document is on its way!

If you do not receive the document in five minutes, contact support at support@docketalarm.com.

Sealed Document

We are unable to display this document, it may be under a court ordered seal.

If you have proper credentials to access the file, you may proceed directly to the court's system using your government issued username and password.


Access Government Site

We are redirecting you
to a mobile optimized page.





Document Unreadable or Corrupt

Refresh this Document
Go to the Docket

We are unable to display this document.

Refresh this Document
Go to the Docket