1 | /* NOTE: |
---|
2 | * THIS CODE IS NOT READY FOR USE YET!!! |
---|
3 | */ |
---|
4 | #include "config.h" |
---|
5 | #include "cpuio.h" |
---|
6 | #include "genlib.h" |
---|
7 | #include "stddefs.h" |
---|
8 | #include "timer.h" |
---|
9 | #include "omap3530.h" |
---|
10 | #include "sd.h" |
---|
11 | |
---|
12 | |
---|
13 | #define MMCTMOUT 2000 |
---|
14 | |
---|
15 | /* This code is included here just for simulating the SD |
---|
16 | * interface (temporarily if a real one isn't ready. In a real system, |
---|
17 | * the INCLUDE_SD_DUMMY_FUNCS definition would be off. |
---|
18 | */ |
---|
19 | int |
---|
20 | xsdCmd(unsigned long cmd, unsigned short argh, unsigned short argl) |
---|
21 | { |
---|
22 | vulong stat, rsp; |
---|
23 | struct elapsed_tmr tmr; |
---|
24 | |
---|
25 | printf("sdCmd(0x%08lx) (cmd=%d)\n",cmd,(cmd & 0x3f000000) >> 24); |
---|
26 | |
---|
27 | startElapsedTimer(&tmr,MMCTMOUT); // Wait for command line not-in-use |
---|
28 | while(MMC1_REG(MMCHS_PSTATE) & CMDI) { |
---|
29 | if(msecElapsed(&tmr)) { |
---|
30 | printf("sdInit: CMDI timeout\n"); |
---|
31 | return(-1); |
---|
32 | } |
---|
33 | } |
---|
34 | |
---|
35 | MMC1_REG(MMCHS_ARG) = ((argh << 16) | argl); |
---|
36 | MMC1_REG(MMCHS_IE) = 0xfffffeff; |
---|
37 | MMC1_REG(MMCHS_CMD) = cmd; |
---|
38 | |
---|
39 | again: |
---|
40 | stat = MMC1_REG(MMCHS_STAT); |
---|
41 | if (stat & CTO) { |
---|
42 | if (stat & CCRC) |
---|
43 | printf("cmdline in use\n"); |
---|
44 | else |
---|
45 | printf("CTO1 CCRC0\n"); |
---|
46 | MMC1_REG(MMCHS_SYSCTL) |= SRC; |
---|
47 | startElapsedTimer(&tmr,MMCTMOUT); |
---|
48 | while(MMC1_REG(MMCHS_SYSCTL) & SRC) { |
---|
49 | if(msecElapsed(&tmr)) |
---|
50 | printf("sdInit: SRC timeout\n"); |
---|
51 | } |
---|
52 | return(-1); |
---|
53 | } |
---|
54 | if ((stat & CC) == 0) |
---|
55 | goto again; |
---|
56 | |
---|
57 | cmd = MMC1_REG(MMCHS_CMD); |
---|
58 | if ((cmd & RSPTYPE) == RSPTYPE_NONE) { |
---|
59 | printf("Success!\n"); |
---|
60 | return(0); |
---|
61 | } |
---|
62 | |
---|
63 | if ((cmd & RSPTYPE) == RSPTYPE_136) { |
---|
64 | rsp = MMC1_REG(MMCHS_RSP10); |
---|
65 | printf("RSP0: %04x, RSP1: %04x\n", |
---|
66 | rsp & 0xffff,(rsp & 0xffff0000) >> 16); |
---|
67 | rsp = MMC1_REG(MMCHS_RSP32); |
---|
68 | printf("RSP2: %04x, RSP3: %04x\n", |
---|
69 | rsp & 0xffff,(rsp & 0xffff0000) >> 16); |
---|
70 | rsp = MMC1_REG(MMCHS_RSP54); |
---|
71 | printf("RSP4: %04x, RSP5: %04x\n", |
---|
72 | rsp & 0xffff,(rsp & 0xffff0000) >> 16); |
---|
73 | rsp = MMC1_REG(MMCHS_RSP76); |
---|
74 | printf("RSP6: %04x, RSP7: %04x\n", |
---|
75 | rsp & 0xffff,(rsp & 0xffff0000) >> 16); |
---|
76 | } |
---|
77 | if ((cmd & RSPTYPE) == RSPTYPE_48) { |
---|
78 | rsp = MMC1_REG(MMCHS_RSP10); |
---|
79 | printf("RSP0: %04x, RSP1: %04x\n", |
---|
80 | rsp & 0xffff,(rsp & 0xffff0000) >> 16); |
---|
81 | rsp = MMC1_REG(MMCHS_RSP32); |
---|
82 | printf("RSP2: %04x, RSP3: %04x\n", |
---|
83 | rsp & 0xffff,(rsp & 0xffff0000) >> 16); |
---|
84 | } |
---|
85 | if ((cmd & RSPTYPE) == RSPTYPE_48BSY) { |
---|
86 | rsp = MMC1_REG(MMCHS_RSP10); |
---|
87 | printf("RSP0: %04x, RSP1: %04x\n", |
---|
88 | rsp & 0xffff,(rsp & 0xffff0000) >> 16); |
---|
89 | rsp = MMC1_REG(MMCHS_RSP32); |
---|
90 | printf("RSP2: %04x, RSP3: %04x\n", |
---|
91 | rsp & 0xffff,(rsp & 0xffff0000) >> 16); |
---|
92 | } |
---|
93 | |
---|
94 | return(0); |
---|
95 | } |
---|
96 | |
---|
97 | int |
---|
98 | sdCmd(unsigned long cmd, unsigned short argh, unsigned short argl) |
---|
99 | { |
---|
100 | vulong stat, arg; |
---|
101 | struct elapsed_tmr tmr; |
---|
102 | |
---|
103 | printf("sdCmd(0x%08lx) (cmd=%d)\n",cmd,(cmd & 0x3f000000) >> 24); |
---|
104 | |
---|
105 | MMC1_REG(MMCHS_STAT) = 0xffffffff; |
---|
106 | MMC1_REG(MMCHS_BLK) = NBLK(1) | BLEN(512); |
---|
107 | MMC1_REG(MMCHS_SYSCTL) &= ~DTOMSK; |
---|
108 | MMC1_REG(MMCHS_SYSCTL) |= DTO(14); |
---|
109 | |
---|
110 | startElapsedTimer(&tmr,MMCTMOUT); // Wait for command line not-in-use |
---|
111 | while(MMC1_REG(MMCHS_PSTATE) & CMDI) { |
---|
112 | if(msecElapsed(&tmr)) { |
---|
113 | printf("sdCmd: CMDI timeout\n"); |
---|
114 | return(-1); |
---|
115 | } |
---|
116 | monDelay(1); |
---|
117 | } |
---|
118 | |
---|
119 | arg = argh; |
---|
120 | arg <<= 16; |
---|
121 | arg |= argl; |
---|
122 | MMC1_REG(MMCHS_ARG) = arg; |
---|
123 | MMC1_REG(MMCHS_IE) = 0xfffffeff; |
---|
124 | MMC1_REG(MMCHS_CMD) = cmd; |
---|
125 | |
---|
126 | startElapsedTimer(&tmr,MMCTMOUT); |
---|
127 | do { |
---|
128 | stat = MMC1_REG(MMCHS_STAT); |
---|
129 | if (stat & CTO) { |
---|
130 | if (stat & CCRC) |
---|
131 | printf("CCRC1\n"); |
---|
132 | else |
---|
133 | printf("CTO1 CCRC0\n"); |
---|
134 | MMC1_REG(MMCHS_SYSCTL) |= SRC; |
---|
135 | startElapsedTimer(&tmr,MMCTMOUT); |
---|
136 | while(MMC1_REG(MMCHS_SYSCTL) & SRC) { |
---|
137 | if(msecElapsed(&tmr)) |
---|
138 | printf("sdCmd: SRC timeout\n"); |
---|
139 | } |
---|
140 | return(-1); |
---|
141 | } |
---|
142 | if(msecElapsed(&tmr)) { |
---|
143 | printf("sdCmd: CC timeout\n"); |
---|
144 | return(-1); |
---|
145 | } |
---|
146 | monDelay(1); |
---|
147 | } while ((stat & CC) == 0); |
---|
148 | |
---|
149 | stat = MMC1_REG(MMCHS_STAT); |
---|
150 | if (stat & CCRC) |
---|
151 | printf("Cmd crc\n"); |
---|
152 | if (stat & DCRC) |
---|
153 | printf("Data crc\n"); |
---|
154 | if (stat & CERR) { |
---|
155 | printf("Card error 0x%lx\n",stat); |
---|
156 | return(-1); |
---|
157 | } |
---|
158 | if (stat & CTO) { |
---|
159 | printf("CTO set!\n"); |
---|
160 | return(-1); |
---|
161 | } |
---|
162 | if (stat & CC) { |
---|
163 | printf("Success!\n"); |
---|
164 | return(0); |
---|
165 | } |
---|
166 | else { |
---|
167 | printf("Didn't complete!\n"); |
---|
168 | return(-1); |
---|
169 | } |
---|
170 | } |
---|
171 | |
---|
172 | int |
---|
173 | sdClkSet(int clkval) |
---|
174 | { |
---|
175 | vulong reg; |
---|
176 | struct elapsed_tmr tmr; |
---|
177 | |
---|
178 | MMC1_REG(MMCHS_SYSCTL) &= ~CEN; |
---|
179 | reg = MMC1_REG(MMCHS_SYSCTL); |
---|
180 | reg &= ~CLKDMSK; |
---|
181 | reg |= CLKD(96000/clkval); |
---|
182 | MMC1_REG(MMCHS_SYSCTL) = reg; |
---|
183 | |
---|
184 | startElapsedTimer(&tmr,MMCTMOUT); // Wait for clock stable |
---|
185 | while((MMC1_REG(MMCHS_SYSCTL) & ICS) == 0) { |
---|
186 | if(msecElapsed(&tmr)) { |
---|
187 | printf("sdClkSet: ICS timeout\n"); |
---|
188 | return(-1); |
---|
189 | } |
---|
190 | monDelay(1); |
---|
191 | } |
---|
192 | MMC1_REG(MMCHS_SYSCTL) |= CEN; |
---|
193 | startElapsedTimer(&tmr,MMCTMOUT); // Wait for clock stable |
---|
194 | while((MMC1_REG(MMCHS_SYSCTL) & CEN) == 0) { |
---|
195 | if(msecElapsed(&tmr)) { |
---|
196 | printf("sdClkSet: ICS timeout\n"); |
---|
197 | return(-1); |
---|
198 | } |
---|
199 | monDelay(1); |
---|
200 | } |
---|
201 | return(0); |
---|
202 | } |
---|
203 | |
---|
204 | /* sdInit(): |
---|
205 | * This function is called by the "sd init" command on the command line. |
---|
206 | * Where applicable, the text refers to the section in the Sept 2008 |
---|
207 | * Technical Reference Manual (TRM) from which I got the code/functionality. |
---|
208 | */ |
---|
209 | int |
---|
210 | sdInit(int interface, int verbose) |
---|
211 | { |
---|
212 | int i, pbiasretry = 0; |
---|
213 | vulong reg; |
---|
214 | struct elapsed_tmr tmr; |
---|
215 | |
---|
216 | /* There's only one interface on the CSB740, so reject anything |
---|
217 | * other than interface 0... |
---|
218 | */ |
---|
219 | if (interface != 0) |
---|
220 | return(-1); |
---|
221 | |
---|
222 | /******************************* |
---|
223 | * |
---|
224 | * Clock configuration: |
---|
225 | * (TRM 22.5.1.1) |
---|
226 | */ |
---|
227 | *(vulong *)CM_ICLKEN1_CORE |= EN_MMC1; // Configure interface and |
---|
228 | *(vulong *)CM_FCLKEN1_CORE |= EN_MMC1; // functional clocks. |
---|
229 | |
---|
230 | /******************************* |
---|
231 | * |
---|
232 | * Not really sure what this is... apparently some kind of clock steering. |
---|
233 | * I tried both setting the bit and clearing it. Made no difference. |
---|
234 | * In both cases the clock was present on the CLK pin. |
---|
235 | */ |
---|
236 | *(vulong *)CONTROL_DEVCONF0 |= MMCSDIO1ADPCLKISEL; |
---|
237 | |
---|
238 | /******************************** |
---|
239 | * |
---|
240 | * Set up BIAS (this allows the pins to run at 1.8 or 3.0 volts I think). |
---|
241 | * This is configured as 0606 in rom_reset.S (i don't think thats right). |
---|
242 | * Note: The CSB703 ties this interface to 3.3 volts. |
---|
243 | * TRM 22.5.3 |
---|
244 | * TRM 7.5.2 and flowchart in figure 7-24... |
---|
245 | */ |
---|
246 | pbias_retry: |
---|
247 | *(vulong *)CONTROL_PBIAS_LITE = PBIAS_LITE_VMMC1_52MHZ; |
---|
248 | monDelay(100); |
---|
249 | *(vulong *)CONTROL_PBIAS_LITE |= MMC_PWR_STABLE; |
---|
250 | monDelay(100); |
---|
251 | if (*(vulong *)CONTROL_PBIAS_LITE & PBIAS_LITE_MMC1_ERROR) { |
---|
252 | *(vulong *)CONTROL_PBIAS_LITE &= (~MMC_PWR_STABLE); |
---|
253 | monDelay(100); |
---|
254 | if (pbiasretry++ < 3) { |
---|
255 | goto pbias_retry; |
---|
256 | } |
---|
257 | else { |
---|
258 | printf("sdInit: PBIAS timeout\n"); |
---|
259 | return(-1); |
---|
260 | } |
---|
261 | } |
---|
262 | |
---|
263 | #if 0 |
---|
264 | /******************************* |
---|
265 | * |
---|
266 | * These registers are things I found when scouring the TRM for "MMC". |
---|
267 | * I don't think they have any affect on basic startup of the interface |
---|
268 | * so they are removed for now... |
---|
269 | */ |
---|
270 | *(vulong *)CM_AUTOIDLE1_CORE &= ~AUTO_MMC1; // Disable auto clock enable |
---|
271 | *(vulong *)PM_WKEN1_CORE &= ~EN_MMC1; // Disable wakeup event |
---|
272 | *(vulong *)PM_MPUGRPSEL1_CORE &= ~GRPSEL_MMC1; // Disable mpu-group wakeup |
---|
273 | *(vulong *)PM_IVA2GRPSEL1_CORE &= ~GRPSEL_MMC1; // Disable iva2-group wakeup |
---|
274 | *(vulong *)PM_WKST1_CORE &= ~EN_MMC1; // Clear wakeup status |
---|
275 | #endif |
---|
276 | |
---|
277 | /******************************* |
---|
278 | * |
---|
279 | * Issue soft reset and wait for completion... |
---|
280 | * (TRM 22.5.1.2) |
---|
281 | */ |
---|
282 | MMC1_REG(MMCHS_SYSCONFIG) |= SRESET; // Software reset |
---|
283 | if ((MMC1_REG(MMCHS_SYSSTATUS) & RESETDONE) == 0) |
---|
284 | printf("Good, RESETDONE is low here\n"); |
---|
285 | |
---|
286 | startElapsedTimer(&tmr,MMCTMOUT); // Wait for completion |
---|
287 | while((MMC1_REG(MMCHS_SYSSTATUS) & RESETDONE) == 0) { |
---|
288 | if(msecElapsed(&tmr)) { |
---|
289 | printf("sdInit: SRST failed\n"); |
---|
290 | return(-1); |
---|
291 | } |
---|
292 | } |
---|
293 | /******************************** |
---|
294 | * |
---|
295 | * Set SRA bit, then wait for it to clear. |
---|
296 | */ |
---|
297 | MMC1_REG(MMCHS_SYSCTL) |= SRA; |
---|
298 | startElapsedTimer(&tmr,MMCTMOUT); |
---|
299 | while((MMC1_REG(MMCHS_SYSCTL) & SRA)) { |
---|
300 | if(msecElapsed(&tmr)) { |
---|
301 | printf("sdInit: SRA timeout\n"); |
---|
302 | return(-1); |
---|
303 | } |
---|
304 | } |
---|
305 | |
---|
306 | startElapsedTimer(&tmr,MMCTMOUT); // Wait for debounce stable. |
---|
307 | while((MMC1_REG(MMCHS_PSTATE) & DEBOUNCE) != DEBOUNCE) { |
---|
308 | if(msecElapsed(&tmr)) { |
---|
309 | printf("sdInit: DEBOUNCE timeout\n"); |
---|
310 | return(-1); |
---|
311 | } |
---|
312 | } |
---|
313 | |
---|
314 | /******************************* |
---|
315 | * |
---|
316 | * Establish hardware capabilities: |
---|
317 | * TRM 22.5.1.3 |
---|
318 | */ |
---|
319 | reg = MMC1_REG(MMCHS_CAPA); |
---|
320 | reg &= ~(VS18 | VS30 | VS33); |
---|
321 | reg |= VS18; |
---|
322 | MMC1_REG(MMCHS_CAPA) = reg; |
---|
323 | |
---|
324 | #if 0 |
---|
325 | /******************************** |
---|
326 | * |
---|
327 | * Enable wakeup mode (don't think I need this, tried both ways) |
---|
328 | * TRM 22.5.1.4 |
---|
329 | */ |
---|
330 | MMC1_REG(MMCHS_SYSCONFIG) |= ENWAKEUP; |
---|
331 | MMC1_REG(MMCHS_HCTL) |= IWE; |
---|
332 | #endif |
---|
333 | |
---|
334 | /******************************** |
---|
335 | * |
---|
336 | * MMC Host and Bus Configuration |
---|
337 | * TRM 22.5.1.5 |
---|
338 | */ |
---|
339 | //MMC1_REG(MMCHS_CON) = |
---|
340 | MMC1_REG(MMCHS_HCTL) &= ~SVDS; |
---|
341 | MMC1_REG(MMCHS_HCTL) |= SVDS18; |
---|
342 | monDelay(10); |
---|
343 | MMC1_REG(MMCHS_HCTL) |= SDBP; |
---|
344 | monDelay(100); |
---|
345 | |
---|
346 | startElapsedTimer(&tmr,MMCTMOUT); // Wait for SVDS verification |
---|
347 | while((MMC1_REG(MMCHS_HCTL) & SDBP) == 0) { |
---|
348 | if(msecElapsed(&tmr)) { |
---|
349 | printf("sdInit: SDBP timeout\n"); |
---|
350 | return(-1); |
---|
351 | } |
---|
352 | } |
---|
353 | |
---|
354 | MMC1_REG(MMCHS_SYSCTL) |= ICE; // Enable internal clock |
---|
355 | |
---|
356 | MMC1_REG(MMCHS_SYSCTL) &= ~CLKDMSK; // Set clock divisor: |
---|
357 | MMC1_REG(MMCHS_SYSCTL) |= CLKD(960); // (should be <= 80Khz initially) |
---|
358 | |
---|
359 | startElapsedTimer(&tmr,MMCTMOUT); // Wait for clock stable |
---|
360 | while((MMC1_REG(MMCHS_SYSCTL) & ICS) == 0) { |
---|
361 | if(msecElapsed(&tmr)) { |
---|
362 | printf("sdInit: ICS timeout\n"); |
---|
363 | return(-1); |
---|
364 | } |
---|
365 | } |
---|
366 | |
---|
367 | /* I set these two bits with the hope that the clock will be |
---|
368 | * active even if there is no card installed (so I atleast can |
---|
369 | * see *some* activity). |
---|
370 | */ |
---|
371 | MMC1_REG(MMCHS_SYSCTL) |= CEN; // External clock enable |
---|
372 | #if 0 |
---|
373 | MMC1_REG(MMCHS_CON) |= CLKEXTFREE; |
---|
374 | |
---|
375 | reg = MMC1_REG(MMCHS_SYSCONFIG); |
---|
376 | reg &= ~SIDLEMODEMSK; |
---|
377 | reg &= ~CLKACTIVITYMSK; |
---|
378 | reg &= ~AUTOIDLE; |
---|
379 | reg |= (SIDLEMODE(1) | CLKACTIVITY(3)); |
---|
380 | MMC1_REG(MMCHS_SYSCONFIG) = reg; |
---|
381 | #endif |
---|
382 | |
---|
383 | /******************************** |
---|
384 | * |
---|
385 | * Set the INIT bit to send an initialization stream to the card... |
---|
386 | * (top of left flowchart in TRM section 22.5.2.1) |
---|
387 | */ |
---|
388 | MMC1_REG(MMCHS_CON) |= MMCINIT; |
---|
389 | for(i=0;i<10;i++) { |
---|
390 | sdCmd(CMD(0) | RSPTYPE_NONE,0,0); |
---|
391 | monDelay(2); |
---|
392 | } |
---|
393 | MMC1_REG(MMCHS_CON) &= ~MMCINIT; |
---|
394 | MMC1_REG(MMCHS_STAT) = 0xffffffff; |
---|
395 | |
---|
396 | if (sdClkSet(400) != 0) |
---|
397 | return(-1); |
---|
398 | |
---|
399 | /* this is the get_card_type() function in the code from TI... |
---|
400 | */ |
---|
401 | if (sdCmd(CMD(55) | RSPTYPE_48,0,0) < 0) { |
---|
402 | printf("Card type = MMC\n"); |
---|
403 | MMC1_REG(MMCHS_CON) |= ODE; |
---|
404 | } |
---|
405 | else { |
---|
406 | if ((MMC1_REG(MMCHS_RSP10) & 0xffff) == 0x0120) { |
---|
407 | printf("Card type = SD\n"); |
---|
408 | } |
---|
409 | else { |
---|
410 | printf("Card type = MMC_CARD\n"); |
---|
411 | MMC1_REG(MMCHS_CON) |= ODE; |
---|
412 | } |
---|
413 | } |
---|
414 | |
---|
415 | |
---|
416 | #if 0 |
---|
417 | /******************************** |
---|
418 | * |
---|
419 | * Send Command 5 |
---|
420 | * (top of right flowchart in TRM section 22.5.2.1) |
---|
421 | */ |
---|
422 | sdCmd(CMD(5) | RSPTYPE_NONE,0,0); |
---|
423 | |
---|
424 | startElapsedTimer(&tmr,MMCTMOUT); |
---|
425 | do { |
---|
426 | reg = MMC1_REG(MMCHS_STAT); |
---|
427 | if (reg & CC) { |
---|
428 | /* For now we assume only SD cards... */ |
---|
429 | printf("SDIO detected!!! Shouldn't be here!\n"); |
---|
430 | return(-1); |
---|
431 | } |
---|
432 | if(msecElapsed(&tmr)) { |
---|
433 | printf("sdInit: CTO timeout1\n"); |
---|
434 | return(-1); |
---|
435 | } |
---|
436 | |
---|
437 | } while((reg & CTO) == 0); |
---|
438 | |
---|
439 | /******************************** |
---|
440 | * |
---|
441 | * Set SRC bit, then wait for it to clear. |
---|
442 | * (midway down right flowchart in TRM section 22.5.2.1) |
---|
443 | */ |
---|
444 | MMC1_REG(MMCHS_SYSCTL) |= SRC; |
---|
445 | startElapsedTimer(&tmr,MMCTMOUT); |
---|
446 | while((MMC1_REG(MMCHS_SYSCTL) & SRC)) { |
---|
447 | if(msecElapsed(&tmr)) { |
---|
448 | printf("sdInit: SRC timeout\n"); |
---|
449 | return(-1); |
---|
450 | } |
---|
451 | } |
---|
452 | |
---|
453 | sdCmd(CMD(8) | RSPTYPE_NONE,0,0); |
---|
454 | |
---|
455 | startElapsedTimer(&tmr,MMCTMOUT); |
---|
456 | do { |
---|
457 | reg = MMC1_REG(MMCHS_STAT); |
---|
458 | if (reg & CC) { |
---|
459 | /* For now we assume only SD cards... */ |
---|
460 | printf("SD BINGO!!! This is where we want to be!\n"); |
---|
461 | return(0); |
---|
462 | } |
---|
463 | if(msecElapsed(&tmr)) { |
---|
464 | printf("sdInit: CTO timeout2\n"); |
---|
465 | return(-1); |
---|
466 | } |
---|
467 | |
---|
468 | } while((reg & CTO) == 0); |
---|
469 | |
---|
470 | /* For now we assume only SD cards... */ |
---|
471 | printf("MMC detected!!! Shouldn't be here!\n"); |
---|
472 | #endif |
---|
473 | return(-1); |
---|
474 | } |
---|
475 | |
---|
476 | int |
---|
477 | sdRead(int interface, char *buf, int blk, int blkcnt) |
---|
478 | { |
---|
479 | char *from; |
---|
480 | int size; |
---|
481 | |
---|
482 | if (interface != 0) |
---|
483 | return(-1); |
---|
484 | |
---|
485 | from = (char *)(blk * SD_BLKSIZE); |
---|
486 | size = blkcnt * SD_BLKSIZE; |
---|
487 | memcpy(buf,from,size); |
---|
488 | return(0); |
---|
489 | } |
---|
490 | |
---|
491 | int |
---|
492 | sdWrite(int interface, char *buf, int blk, int blkcnt) |
---|
493 | { |
---|
494 | char *to; |
---|
495 | int size; |
---|
496 | |
---|
497 | if (interface != 0) |
---|
498 | return(-1); |
---|
499 | |
---|
500 | to = (char *)(blk * SD_BLKSIZE); |
---|
501 | size = blkcnt * SD_BLKSIZE; |
---|
502 | memcpy(to,buf,size); |
---|
503 | return(0); |
---|
504 | } |
---|
505 | |
---|