PS2SDK
PS2 Homebrew Libraries
cache.c
1 /*
2 # _____ ___ ____ ___ ____
3 # ____| | ____| | | |____|
4 # | ___| |____ ___| ____| | \ PS2DEV Open Source Project.
5 #-----------------------------------------------------------------------
6 # Copyright 2001-2004, ps2dev - http://www.ps2dev.org
7 # Licenced under Academic Free License version 2.0
8 # Review ps2sdk README & LICENSE files for further details.
9 #
10 # APA cache manipulation routines
11 */
12 
13 #include <errno.h>
14 #include <iomanX.h>
15 #ifdef _IOP
16 #include <sysclib.h>
17 #else
18 #include <string.h>
19 #endif
20 #include <stdio.h>
21 #include <hdd-ioctl.h>
22 
23 #include "libapa.h"
24 
25 // Globals
26 static apa_cache_t *cacheBuf;
27 static int cacheSize;
28 
29 int apaCacheInit(u32 size)
30 {
31  apa_header_t *header;
32  unsigned int i;
33 
34  cacheSize=size; // save size ;)
35  if((header=(apa_header_t *)apaAllocMem(size*sizeof(apa_header_t)))){
36  cacheBuf=apaAllocMem((size+1)*sizeof(apa_cache_t));
37  if(cacheBuf==NULL)
38  return -ENOMEM;
39  }
40  else
41  return -ENOMEM;
42  // setup cache header...
43  memset(cacheBuf, 0, (size+1)*sizeof(apa_cache_t));
44  cacheBuf->next=cacheBuf;
45  cacheBuf->tail=cacheBuf;
46  for(i=1; i<size+1;i++, header++){
47  cacheBuf[i].header=header;
48  cacheBuf[i].device=-1;
49  apaCacheLink(cacheBuf->tail, &cacheBuf[i]);
50  }
51  return 0;
52 }
53 
54 int apaCacheDeinit(void)
55 {
56 #if 0
57  unsigned int i;
58 
59  for(i=1; i<cacheSize+1;i++){
60  // !!! This code performs multiple frees
61  apaFreeMem(cacheBuf[i].header);
62  }
63 #else
64  // Unofficial: Free once at the head of the list
65  if (cacheSize > 1)
66  {
67  apaFreeMem(cacheBuf[1].header);
68  }
69 #endif
70  apaFreeMem(cacheBuf);
71  return 0;
72 }
73 
74 void apaCacheLink(apa_cache_t *clink, apa_cache_t *cnew)
75 {
76  cnew->tail=clink;
77  cnew->next=clink->next;
78  clink->next->tail=cnew;
79  clink->next=cnew;
80 }
81 
82 apa_cache_t *apaCacheUnLink(apa_cache_t *clink)
83 {
84  clink->tail->next=clink->next;
85  clink->next->tail=clink->tail;
86  return clink;
87 }
88 
89 int apaCacheTransfer(apa_cache_t *clink, int type)
90 {
91  int err;
92  if(type)
93  err=apaWriteHeader(clink->device, clink->header, clink->sector);
94  else// 0
95  err=apaReadHeader(clink->device, clink->header, clink->sector);
96 
97  if(err)
98  {
99  APA_PRINTF(APA_DRV_NAME": error: disk err %d on device %ld, sector %ld, type %d\n",
100  err, clink->device, clink->sector, type);
101  if(type==0)// save any read error's..
102  apaSaveError(clink->device, clink->header, APA_SECTOR_SECTOR_ERROR, clink->sector);
103  }
104  clink->flags&=~APA_CACHE_FLAG_DIRTY;
105  return err;
106 }
107 
108 void apaCacheFlushDirty(apa_cache_t *clink)
109 {
110  if(clink->flags&APA_CACHE_FLAG_DIRTY)
111  apaCacheTransfer(clink, APA_IO_MODE_WRITE);
112 }
113 
114 int apaCacheFlushAllDirty(s32 device)
115 {
116  int i;
117  // flush apal
118  for(i=1;i<cacheSize+1;i++){
119  if((cacheBuf[i].flags & APA_CACHE_FLAG_DIRTY) && cacheBuf[i].device==device)
120  apaJournalWrite(&cacheBuf[i]);
121  }
122  apaJournalFlush(device);
123  // flush apa
124  for(i=1;i<cacheSize+1;i++){
125  if((cacheBuf[i].flags & APA_CACHE_FLAG_DIRTY) && cacheBuf[i].device==device)
126  apaCacheTransfer(&cacheBuf[i], APA_IO_MODE_WRITE);
127  }
128  return apaJournalReset(device);
129 }
130 
131 apa_cache_t *apaCacheGetHeader(s32 device, u32 sector, u32 mode, int *result)
132 {
133  apa_cache_t *clink=NULL;
134  int i;
135 
136  *result=0;
137  for(i=1;i<cacheSize+1;i++){
138  if(cacheBuf[i].sector==sector &&
139  cacheBuf[i].device==device){
140  clink=&cacheBuf[i];
141  break;
142  }
143  }
144  if(clink!=NULL) {
145  // cached ver was found :)
146  if(clink->nused==0)
147  clink=apaCacheUnLink(clink);
148  clink->nused++;
149  return clink;
150  }
151  if((cacheBuf->tail==cacheBuf) &&
152  (cacheBuf->tail==cacheBuf->tail->next)){
153  APA_PRINTF(APA_DRV_NAME": error: free buffer empty\n");
154  }
155  else
156  {
157  clink=cacheBuf->next;
158  if(clink->flags & APA_CACHE_FLAG_DIRTY)
159  APA_PRINTF(APA_DRV_NAME": error: dirty buffer allocated\n");
160  clink->flags=0;
161  clink->nused=1;
162  clink->device=device;
163  clink->sector=sector;
164  clink=apaCacheUnLink(clink);
165  }
166  if(clink==NULL)
167  {
168  *result=-ENOMEM;
169  return NULL;
170  }
171  if(!mode)
172  {
173  if((*result=apaCacheTransfer(clink, APA_IO_MODE_READ))<0){
174  clink->nused=0;
175  clink->device=-1;
176  apaCacheLink(cacheBuf, clink);
177  clink=NULL;
178  }
179  }
180  return clink;
181 }
182 
183 void apaCacheFree(apa_cache_t *clink)
184 {
185  if(clink==NULL){
186  APA_PRINTF(APA_DRV_NAME": error: null buffer returned\n");
187  return;
188  }
189  if(clink->nused==0){
190  APA_PRINTF(APA_DRV_NAME": error: unused cache returned\n");
191  return;
192  }
193  if(clink->flags & APA_CACHE_FLAG_DIRTY)
194  APA_PRINTF(APA_DRV_NAME": error: dirty buffer returned\n");
195  clink->nused--;
196  if(clink->nused==0)
197  apaCacheLink(cacheBuf->tail, clink);
198  return;
199 }
200 
201 apa_cache_t *apaCacheAlloc(void)
202 {
203  apa_cache_t *cnext;
204 
205  if((cacheBuf->tail==cacheBuf) &&
206  (cacheBuf->tail==cacheBuf->tail->next)){
207  APA_PRINTF(APA_DRV_NAME": error: free buffer empty\n");
208  return NULL;
209  }
210  cnext=cacheBuf->next;
211  if(cnext->flags & APA_CACHE_FLAG_DIRTY)
212  APA_PRINTF(APA_DRV_NAME": error: dirty buffer allocated\n");
213  cnext->nused=1;
214  cnext->flags=0;
215  cnext->device=-1;
216  cnext->sector=-1;
217  return apaCacheUnLink(cnext);
218 }
iomanX.h
apa_header_t
Definition: libapa.h:62
sysclib.h
ENOMEM
#define ENOMEM
Definition: errno.h:43
sapa_cache
Definition: libapa.h:120
hdd-ioctl.h
stdio.h
errno.h