nckernel  0.1
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
fdc.c
Go to the documentation of this file.
1 #include <sys/types.h>
2 #include <stddef.h> /* restricted */
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h> /* memcpy */
6 #include <stdint.h> /* intptr_t */
7 #include <unistd.h> /* sysconf */
8 #include <stropts.h>
9 #include <stddef.h>
10 #include <stdarg.h>
11 #include <time.h>
12 #include <errno.h>
13 #include <list.h>
14 #include <pthread.h>
15 #include <semaphore.h>
16 
17 #include <object.h>
18 #include <vfs.h>
19 #include <device.h>
20 #include <dma.h>
21 #include <fdc.h>
22 #include <fdc_ctrl.h>
23 #include <fdc_single.h>
24 
25 #include <zone.h>
26 #include <page_frame.h>
27 #include <onetime_map.h>
28 
29 #include <debug.h>
30 #include <util.h>
31 
33 
42 static inline void fdc_dma_init(enum fdc_dma_dir_t dir,
43  unsigned long address, int count)
44 {
45  unsigned long mode;
46 
47  mode = DMA_MODE_SINGLE;
48 
49  switch (dir) {
50  case FDC_DMA_READ:
51  mode |= DMA_MODE_TX_WRITE;
52  break;
53  case FDC_DMA_WRITE:
54  mode |= DMA_MODE_TX_READ;
55  break;
56  default:
57  return;
58  }
59 
60  dma_init(DMA_CH2, mode, address, count);
61 }
62 
63 static inline int read_data(off_t offset, struct fdc_context *priv, void *buf, size_t size)
64 {
65  int c;
66  int h;
67  int s;
68  int ret;
69 
70  LBA_TO_CHS(offset / FD_BLKSZ, h, c, s);
71 
72  ret = fdc_seek(priv, c, h);
73  if (ret < 0) {
74  goto out;
75  }
76 
77  ret = fdc_read_id(priv, h);
78  if (ret < 0) {
79  goto out;
80  }
81 
82  fdc_dma_init(FDC_DMA_READ, (unsigned long)buf, size);
83  ret = fdc_read_sector(priv, c, h, s);
84  if (ret < 0) {
85  goto out;
86  }
87 
88  ret = dma_is_done(DMA_CH2);
89 
90 out:
91  return ret;
92 }
93 
94 static inline int write_data(off_t offset, struct fdc_context *priv, void *buf, size_t size)
95 {
96  int c;
97  int h;
98  int s;
99  int ret;
100 
101  LBA_TO_CHS(offset / FD_BLKSZ, h, c, s);
102 
103  ret = fdc_seek(priv, c, h);
104  if (ret < 0) {
105  goto out;
106  }
107 
108  fdc_dma_init(FDC_DMA_WRITE, (unsigned long)buf, size);
109  ret = fdc_write_sector(priv, c, h, s);
110  if (ret < 0) {
111  goto out;
112  }
113 
114  ret = dma_is_done(DMA_CH2);
115 
116 out:
117  return ret;
118 }
119 
120 off_t fdc_lseek(struct ninfo *ninfo, struct nctx *ctx, off_t offset, int whence)
121 {
122  pthread_mutex_lock(&s_lock);
123  switch (whence) {
124  case SEEK_SET:
125  ctx->offset = offset;
126  break;
127  case SEEK_CUR:
128  ctx->offset += offset;
129  break;
130  case SEEK_END:
131  ctx->offset = ninfo->size + offset;
132  break;
133  default:
134  pthread_mutex_unlock(&s_lock);
135  return (off_t)-1;
136  }
137 
138  pthread_mutex_unlock(&s_lock);
139  return ctx->offset;
140 }
141 
142 int fdc_read(struct ninfo *ninfo, struct nctx *ctx, void *buf, size_t size)
143 {
144  struct fdc_context *priv;
145  void *pma;
146  char *vma;
147  off_t off;
148  off_t gap;
149  ssize_t sz;
150  char *ptr;
151  int ret;
152 
153  priv = ctx->priv;
154 
155  pma = page_frame_alloc(ZONE_BASE, 1);
156  if (!pma) {
157  printf("Failed to allocate page frame\n");
158  return -ENOMEM;
159  }
160 
161  vma = onetime_map(pma);
162  if (!vma) {
163  printf("Failed to do onetime mapping\n");
164  page_frame_free(pma);
165  return -EFAULT;
166  }
167 
168  pthread_mutex_lock(&s_lock);
169  gap = ctx->offset % FD_BLKSZ;
170  off = ctx->offset - gap;
171  ptr = buf;
172 
173  do {
174  ret = read_data(off, priv, pma, FD_BLKSZ);
175  if (ret < 0) {
176  printf("Failed to read data\n");
177  break;
178  }
179 
180  sz = FD_BLKSZ - gap;
181  sz = (size > sz) ? sz : size;
182  memcpy(ptr, vma + gap, sz);
183  ptr += sz;
184  size -= sz;
185  off += FD_BLKSZ;
186  gap = 0;
187  } while (size > 0);
188 
189  ctx->offset += ((uint32_t)ptr - (uint32_t)buf);
190  pthread_mutex_unlock(&s_lock);
191 
192  onetime_unmap(vma);
193  page_frame_free(pma);
194  return ((uint32_t)ptr - (uint32_t)buf);
195 }
196 
197 int fdc_write(struct ninfo *ninfo, struct nctx *ctx,
198  const void *buf, size_t size)
199 {
200  struct fdc_context *priv;
201  void *pma;
202  char *vma;
203  off_t off;
204  off_t gap;
205  size_t sz;
206  char *ptr;
207  int ret;
208 
209  priv = ctx->priv;
210 
211  pma = page_frame_alloc(ZONE_BASE, 1);
212  if (!pma) {
213  return -ENOMEM;
214  }
215 
216  vma = onetime_map(pma);
217  if (!vma) {
218  page_frame_free(pma);
219  return -EFAULT;
220  }
221 
222  pthread_mutex_lock(&s_lock);
223  gap = ctx->offset % FD_BLKSZ;
224  off = ctx->offset - gap;
225  ptr = (char *)buf;
226 
227  do {
228  ret = read_data(off, priv, pma, FD_BLKSZ);
229  if (ret < 0) {
230  break;
231  }
232 
233  sz = FD_BLKSZ - gap;
234  sz = (size > sz) ? sz : size;
235  memcpy(vma + gap, ptr, sz);
236 
237  ret = write_data(off, priv, pma, FD_BLKSZ);
238  if (ret < 0) {
239  break;
240  }
241 
242  ptr += sz;
243  size -= sz;
244  off += FD_BLKSZ;
245  gap = 0;
246  } while (size > 0);
247 
248  ctx->offset += ((uint32_t)ptr - (uint32_t)buf);
249  pthread_mutex_unlock(&s_lock);
250 
251  onetime_unmap(vma);
252  page_frame_free(pma);
253  return ((uint32_t)ptr - (uint32_t)buf);
254 }
255 
256 int fdc_ioctl(struct ninfo *ninfo, struct nctx *ctx, int request, va_list va)
257 {
258  struct fdc_context *priv;
259  unsigned char *val;
260  int ret;
261 
262  priv = ctx->priv;
263 
264  switch (request) {
265  case I_GETINFO:
266  val = va_arg(va, unsigned char *);
267  pthread_mutex_lock(&s_lock);
268  ret = fdc_version(priv, val);
269  pthread_mutex_unlock(&s_lock);
270  break;
271  default:
272  ret = -EINVAL;
273  break;
274  }
275 
276  return ret;
277 }
278 
279 int fdc_close(struct ninfo *ninfo, struct nctx *ctx)
280 {
281  fdc_motor_off(ctx->priv);
282 
283  pthread_mutex_lock(&s_lock);
284  fdc_fini_ctrl(ctx->priv);
285  pthread_mutex_unlock(&s_lock);
286 
287  free(ctx->priv);
288  ctx->priv = NULL;
289  return 0;
290 }
291 
292 int fdc_open(struct ninfo *ninfo, struct nctx *ctx)
293 {
294  int ret;
295  struct fdc_context *priv;
296  struct ninfo_dev *dev;
297 
298  dev = ninfo->priv;
299 
300  priv = malloc(sizeof(*priv));
301  if (!priv) {
302  return -ENOMEM;
303  }
304 
305  pthread_mutex_lock(&s_lock);
306  ret = fdc_init_ctrl(priv, MINOR(dev->device));
307  pthread_mutex_unlock(&s_lock);
308  if (ret < 0) {
309  free(priv);
310  return ret;
311  }
312 
313  ctx->priv = priv;
314  ctx->offset = 0;
315 
316  fdc_motor_on(priv);
317  return 0;
318 }
319 
320 static struct ninfo_ops fdc_ops = {
321  .open = fdc_open,
322  .close = fdc_close,
323  .lseek = fdc_lseek,
324  .read = fdc_read,
325  .write = fdc_write,
326  .ioctl = fdc_ioctl,
327 };
328 
329 int fdc_init(void)
330 {
331  struct ninfo *ninfo;
332  struct ninfo *parent;
333 
334  parent = vfs_get_ninfo(NULL, NULL, "/dev");
335  if (!parent) {
336  return -EINVAL;
337  }
338 
339  ninfo = vfs_new_dev_ninfo(NULL, parent, "fda", DEVICE_FDA, &fdc_ops);
340  if (!ninfo) {
341  return -EINVAL;
342  }
343 
344  /* TODO: fdc signle 은 어디서 소멸 시키지? */
345  fdc_single_init();
346  return 0;
347 }
348 
349 /* End of a file */