yaffsfs.c: Fix NULL dereference in yaffs_unmount2_reldev()
[yaffs2.git] / direct / test-framework / nanddrv.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2018 Aleph One Ltd.
5  *
6  * Created by Charles Manning <charles@aleph1.co.uk>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13
14 #include "nanddrv.h"
15 #include "nand_chip.h"
16
17 int nanddrv_initialise(void)
18 {
19         return 0;
20 }
21
22 static void nanddrv_send_addr(struct nand_chip *this, int page, int offset)
23 {
24         this->set_ale(this,1);
25         if(offset >= 0){
26             this->write_cycle(this, offset & 0xff);
27             this->write_cycle(this, (offset>>8) & 0x0f);
28         }
29
30         if(page >= 0){
31             this->write_cycle(this, page & 0xff);
32             this->write_cycle(this, (page>>8) & 0xff);
33             this->write_cycle(this, (page>>16) & 0xff);
34         }
35         this->set_ale(this,0);
36 }
37
38 static void nanddrv_send_cmd(struct nand_chip *this, unsigned char cmd)
39 {
40         this->set_cle(this, 1);
41         this->write_cycle(this, cmd);
42         this->set_cle(this, 0);
43 }
44
45
46 static inline int nanddrv_status_pass(unsigned char status)
47 {
48         /* If bit 0 is zero then pass, if 1 then fail */
49         return (status & (1 << 0)) == 0;
50 }
51
52 static inline int nanddrv_status_busy(unsigned char status)
53 {
54         /* If bit 6 is zero then busy, if 1 then ready */
55         return (status & (1 << 6)) == 0;
56 }
57
58 static unsigned char nanddrv_get_status(struct nand_chip *this,
59                                         int wait_not_busy)
60 {
61         unsigned char status;
62
63         nanddrv_send_cmd(this, 0x70);
64         status = this->read_cycle(this) & 0xff;
65         if(!wait_not_busy)
66                 return status;
67         while (nanddrv_status_busy(status)) {
68                 status = this->read_cycle(this) & 0xff;
69         }
70         return status;
71 }
72
73 int nanddrv_read_tr(struct nand_chip *this, int page,
74                 struct nanddrv_transfer *tr, int n_tr)
75 {
76         unsigned char status;
77         int ncycles;
78
79         if(n_tr < 1)
80                 return 0;
81
82         nanddrv_send_cmd(this, 0x00);
83         nanddrv_send_addr(this, page, tr->offset);
84         nanddrv_send_cmd(this, 0x30);
85         status = nanddrv_get_status(this, 1);
86         if(!nanddrv_status_pass(status))
87                 return -1;
88         nanddrv_send_cmd(this, 0x30);
89         while (1) {
90                 if(this->bus_width_shift == 0) {
91                         unsigned char *buffer = tr->buffer;
92
93                         ncycles = tr->nbytes;
94                         while (ncycles> 0) {
95                                 *buffer = this->read_cycle(this);
96                                 ncycles--;
97                                 buffer++;
98                         }
99                 } else {
100                         unsigned short *buffer = (unsigned short *)tr->buffer;
101
102                         ncycles = tr->nbytes >> 1;
103                         while (ncycles> 0) {
104                                 *buffer = this->read_cycle(this);
105                                 ncycles--;
106                                 buffer++;
107                         }
108                 }
109                 n_tr--;
110                 tr++;
111                 if(n_tr < 1)
112                         break;
113                 nanddrv_send_cmd(this, 0x05);
114                 nanddrv_send_addr(this, -1, tr->offset);
115                 nanddrv_send_cmd(this, 0xE0);
116         }
117         return 0;
118 }
119
120
121 /*
122  * Program page
123  * Cmd: 0x80, 5-byte address, data bytes,  Cmd: 0x10, wait not busy
124  */
125 int nanddrv_write_tr(struct nand_chip *this, int page,
126                 struct nanddrv_transfer *tr, int n_tr)
127 {
128         unsigned char status;
129         int ncycles;
130
131         if (n_tr < 1)
132                 return 0;
133
134         nanddrv_send_cmd(this, 0x80);
135         nanddrv_send_addr(this, page, tr->offset);
136         while (1) {
137                 if(this->bus_width_shift == 0) {
138                         unsigned char *buffer = tr->buffer;
139
140                         ncycles = tr->nbytes;
141                         while (ncycles> 0) {
142                                 this->write_cycle(this, *buffer);
143                                 ncycles--;
144                                 buffer++;
145                         }
146                 } else {
147                         unsigned short *buffer = (unsigned short *)tr->buffer;
148
149                         ncycles = tr->nbytes >> 1;
150                         while (ncycles> 0) {
151                                 this->write_cycle(this, *buffer);
152                                 ncycles--;
153                                 buffer++;
154                         }
155                 }
156                 n_tr--;
157                 tr++;
158                 if (n_tr < 1)
159                         break;
160                 nanddrv_send_cmd(this, 0x85);
161                 nanddrv_send_addr(this, -1, tr->offset);
162         }
163
164         if(this->power_check && this->power_check(this) < 0)
165                 return -1;
166
167         nanddrv_send_cmd(this, 0x10);
168         status = nanddrv_get_status(this, 1);
169         if(nanddrv_status_pass(status))
170                 return 0;
171         return -1;
172 }
173
174 /*
175  * Block erase
176  * Cmd: 0x60, 3-byte address, cmd: 0xD0. Wait not busy.
177  */
178 int nanddrv_erase(struct nand_chip *this, int block)
179 {
180         unsigned char status;
181
182         nanddrv_send_cmd(this, 0x60);
183         nanddrv_send_addr(this, block * this->pages_per_block, -1);
184
185         if(this->power_check && this->power_check(this) < 0)
186                 return -1;
187
188         nanddrv_send_cmd(this, 0xD0);
189         status = nanddrv_get_status(this, 1);
190         if(nanddrv_status_pass(status))
191                 return 0;
192         return -1;
193 }
194
195
196