⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 xd.c.txt

📁 Linux块设备驱动分析与模拟实现
💻 TXT
📖 第 1 页 / 共 3 页
字号:
224 
225                                                         return (0);
226                                                 }
227                                                 break;
228                         case BLKFLSBUF:
229                                 if(!suser())  return -EACCES;
230                                 if(!inode->i_rdev) return -EINVAL;
231                                 fsync_dev(inode->i_rdev);
232                                 invalidate_buffers(inode->i_rdev);
233                                 return 0;
234                                 
235                         case BLKRRPART:         return (xd_reread_partitions(inode->i_rdev));
236                         RO_IOCTLS(inode->i_rdev,arg);
237                 }
238         return (-EINVAL);
239 }
240 
241 /* xd_release: release the device */
242 static void xd_release (struct inode *inode, struct file *file)
243 {
244         int dev = DEVICE_NR(MINOR(inode->i_rdev));
245 
246         if (dev < xd_drives) {
247                 sync_dev(dev);
248                 xd_access[dev]--;
249         }
250 }
251 
252 /* xd_reread_partitions: rereads the partition table from a drive */
253 static int xd_reread_partitions(int dev)
254 {
255         int target = DEVICE_NR(MINOR(dev)),start = target << xd_gendisk.minor_shift,partition;
256 
257         cli(); xd_valid[target] = (xd_access[target] != 1); sti();
258         if (xd_valid[target])
259                 return (-EBUSY);
260 
261         for (partition = xd_gendisk.max_p - 1; partition >= 0; partition--) {
262                 sync_dev(MAJOR_NR << 8 | start | partition);
263                 invalidate_inodes(MAJOR_NR << 8 | start | partition);
264                 invalidate_buffers(MAJOR_NR << 8 | start | partition);
265                 xd_gendisk.part[start + partition].start_sect = 0;
266                 xd_gendisk.part[start + partition].nr_sects = 0;
267         };
268 
269         xd_gendisk.part[start].nr_sects = xd_info[target].heads * xd_info[target].cylinders * xd_info[target].sectors;
270         resetup_one_dev(&xd_gendisk,target);
271 
272         xd_valid[target] = 1;
273         wake_up(&xd_wait_open);
274 
275         return (0);
276 }
277 
278 /* xd_readwrite: handle a read/write request */
279 static int xd_readwrite (u_char operation,u_char drive,char *buffer,u_int block,u_int count)
280 {
281         u_char cmdblk[6],sense[4];
282         u_short track,cylinder;
283         u_char head,sector,control,mode,temp;
284         
285 #ifdef DEBUG_READWRITE
286         printk("xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count);
287 #endif /* DEBUG_READWRITE */
288 
289         control = xd_info[drive].control;
290         while (count) {
291                 temp = count < xd_maxsectors ? count : xd_maxsectors;
292 
293                 track = block / xd_info[drive].sectors;
294                 head = track % xd_info[drive].heads;
295                 cylinder = track / xd_info[drive].heads;
296                 sector = block % xd_info[drive].sectors;
297 
298 #ifdef DEBUG_READWRITE
299                 printk("xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp);
300 #endif /* DEBUG_READWRITE */
301 
302                 mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u_char *)buffer,temp * 0x200);
303                 xd_build(cmdblk,operation == READ ? CMD_READ : CMD_WRITE,drive,head,cylinder,sector,temp & 0xFF,control);
304 
305                 switch (xd_command(cmdblk,mode,(u_char *) buffer,(u_char *) buffer,sense,XD_TIMEOUT)) {
306                         case 1: printk("xd_readwrite: timeout, recalibrating drive\n"); xd_recalibrate(drive); return (0);
307                         case 2: switch ((sense[0] & 0x30) >> 4) {
308                                         case 0: printk("xd_readwrite: drive error, code = 0x%X",sense[0] & 0x0F); break;
309                                         case 1: printk("xd_readwrite: controller error, code = 0x%X",sense[0] & 0x0F); break;
310                                         case 2: printk("xd_readwrite: command error, code = 0x%X",sense[0] & 0x0F); break;
311                                         case 3: printk("xd_readwrite: miscellaneous error, code = 0x%X",sense[0] & 0x0F); break;
312                                 }
313                                 if (sense[0] & 0x80)
314                                         printk(" - drive = %d, head = %d, cylinder = %d, sector = %d\n",sense[1] & 0xE0,sense[1] & 0x1F,((sense[2] & 0xC0) << 2) | sense[3],sense[2] & 0x3F);
315                                 else
316                                         printk(" - no valid disk address\n");
317                                 return (0);
318                 }
319                 count -= temp, buffer += temp * 0x200, block += temp;
320         }
321         return (1);
322 }
323 
324 /* xd_recalibrate: recalibrate a given drive and reset controller if necessary */
325 static void xd_recalibrate (u_char drive)
326 {
327         u_char cmdblk[6];
328         
329         xd_build(cmdblk,CMD_RECALIBRATE,drive,0,0,0,0,0);
330         if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8))
331                 printk("xd_recalibrate: warning! error recalibrating, controller may be unstable\n");
332 }
333 
334 /* xd_interrupt_handler: interrupt service routine */
335 static void xd_interrupt_handler (int unused)
336 {
337         if (inb(XD_STATUS) & STAT_INTERRUPT) {                                                  /* check if it was our device */
338 #ifdef DEBUG_OTHER
339                 printk("xd_interrupt_handler: interrupt detected\n");
340 #endif /* DEBUG_OTHER */
341                 outb(0,XD_CONTROL);                                                             /* acknowledge interrupt */
342                 wake_up(&xd_wait_int);                                                          /* and wake up sleeping processes */
343         }
344         else
345                 printk("xd_interrupt_handler: unexpected interrupt\n");
346 }
347 
348 /* xd_dma: set up the DMA controller for a data transfer */
349 static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count)
350 {
351         if (buffer < ((u_char *) 0x1000000 - count)) {          /* transfer to address < 16M? */
352                 if (((u_int) buffer & 0xFFFF0000) != ((u_int) buffer + count) & 0xFFFF0000) {
353 #ifdef DEBUG_OTHER
354                         printk("xd_setup_dma: using PIO, transfer overlaps 64k boundary\n");
355 #endif /* DEBUG_OTHER */
356                         return (PIO_MODE);
357                 }
358                 disable_dma(xd_dma);
359                 clear_dma_ff(xd_dma);
360                 set_dma_mode(xd_dma,mode);
361                 set_dma_addr(xd_dma,(u_int) buffer);
362                 set_dma_count(xd_dma,count);
363 
364                 return (DMA_MODE);                      /* use DMA and INT */
365         }
366 #ifdef DEBUG_OTHER
367         printk("xd_setup_dma: using PIO, cannot DMA above 16 meg\n");
368 #endif /* DEBUG_OTHER */
369         return (PIO_MODE);
370 }
371 
372 /* xd_build: put stuff into an array in a format suitable for the controller */
373 static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control)
374 {
375         cmdblk[0] = command;
376         cmdblk[1] = ((drive & 0x07) << 5) | (head & 0x1F);
377         cmdblk[2] = ((cylinder & 0x300) >> 2) | (sector & 0x3F);
378         cmdblk[3] = cylinder & 0xFF;
379         cmdblk[4] = count;
380         cmdblk[5] = control;
381         
382         return (cmdblk);
383 }
384 
385 /* xd_waitport: waits until port & mask == flags or a timeout occurs. return 1 for a timeout */
386 static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout)
387 {
388         u_long expiry = jiffies + timeout;
389 
390         while (((inb(port) & mask) != flags) && (jiffies < expiry))
391                 ;
392 
393         return (jiffies >= expiry);
394 }
395 
396 /* xd_command: handle all data transfers necessary for a single command */
397 static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout)
398 {
399         u_char cmdblk[6],csb,complete = 0;
400 
401 #ifdef DEBUG_COMMAND
402         printk("xd_command: command = 0x%X, mode = 0x%X, indata = 0x%X, outdata = 0x%X, sense = 0x%X\n",command,mode,indata,outdata,sense);
403 #endif /* DEBUG_COMMAND */
404 
405         outb(0,XD_SELECT);
406         outb(mode,XD_CONTROL);
407 
408         if (xd_waitport(XD_STATUS,STAT_SELECT,STAT_SELECT,timeout))
409                 return (1);
410         
411         while (!complete) {
412                 if (xd_waitport(XD_STATUS,STAT_READY,STAT_READY,timeout))
413                         return (1);
414                 switch (inb(XD_STATUS) & (STAT_COMMAND | STAT_INPUT)) {
415                         case 0:                 if (mode == DMA_MODE) {
416                                                         enable_dma(xd_dma);
417                                                         sleep_on(&xd_wait_int);
418                                                         disable_dma(xd_dma);
419                                                 }
420                                                 else
421                                                         outb(outdata ? *outdata++ : 0,XD_DATA);
422                                                 break;
423                         case STAT_INPUT:        if (mode == DMA_MODE) {
424                                                         enable_dma(xd_dma);
425                                                         sleep_on(&xd_wait_int);
426                                                         disable_dma(xd_dma);
427                                                 }
428                                                 else
429                                                         if (indata)
430                                                                 *indata++ = inb(XD_DATA);
431                                                         else
432                                                                 inb(XD_DATA);
433                                                 break;
434                         case STAT_COMMAND:      outb(command ? *command++ : 0,XD_DATA); break;
435                         case STAT_COMMAND
436                              | STAT_INPUT:      complete = 1; break;
437                 }
438         }
439         csb = inb(XD_DATA);
440 
441         if (xd_waitport(XD_STATUS,0,STAT_SELECT,timeout))                                       /* wait until deselected */
442                 return (1);
443 
444         if (csb & CSB_ERROR) {                                                                  /* read sense data if error */
445                 xd_build(cmdblk,CMD_SENSE,(csb & CSB_LUN) >> 5,0,0,0,0,0);
446                 if (xd_command(cmdblk,0,sense,0,0,XD_TIMEOUT))

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -