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

📄 floppy.c.txt

📁 Linux块设备驱动分析与模拟实现
💻 TXT
📖 第 1 页 / 共 4 页
字号:
1045                 }
1046                 sector = block % floppy->sect;
1047                 block /= floppy->sect;
1048                 head = block % floppy->head;
1049                 track = block / floppy->head;
1050                 seek_track = track << floppy->stretch;
1051                 if (CURRENT->cmd == READ)
1052                         command = FD_READ;
1053                 else if (CURRENT->cmd == WRITE)
1054                         command = FD_WRITE;
1055                 else {
1056                         printk("do_fd_request: unknown command\n");
1057                         request_done(0);
1058                         goto repeat;
1059                 }
1060         } else {
1061                 if (current_drive != (format_req.device & 3))
1062                         current_track = NO_TRACK;
1063                 current_drive = format_req.device & 3;
1064                 if (((unsigned) format_req.track) >= floppy->track ||
1065                     (format_req.head & 0xfffe) || probing) {
1066                         request_done(0);
1067                         goto repeat;
1068                 }
1069                 head = format_req.head;
1070                 track = format_req.track;
1071                 seek_track = track << floppy->stretch;
1072                 if (seek_track == buffer_track) buffer_track = -1;
1073                 command = FD_FORMAT;
1074                 setup_format_params();
1075         }
1076         timer_table[FLOPPY_TIMER].expires = jiffies+10*HZ;
1077         timer_active |= 1 << FLOPPY_TIMER;
1078         if ((seek_track == buffer_track) &&
1079          (current_drive == buffer_drive)) {
1080                 buffer_area = floppy_track_buffer +
1081                         ((sector + head*floppy->sect)<<9);
1082                 if (command == FD_READ) {
1083                         copy_buffer(buffer_area,CURRENT->buffer);
1084                         request_done(1);
1085                         goto repeat;
1086                 } else if (command == FD_WRITE)
1087                         copy_buffer(CURRENT->buffer,buffer_area);
1088         }
1089         if (seek_track != current_track)
1090                 seek = 1;
1091         sector++;
1092         del_timer(motor_off_timer + current_drive);
1093         floppy_on(current_drive);
1094 }
1095 
1096 void do_fd_request(void)
1097 {
1098         cli();
1099         while (fdc_busy) sleep_on(&fdc_wait);
1100         fdc_busy = 1;
1101         sti();
1102         redo_fd_request();
1103 }
1104 
1105 static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
1106     unsigned long param)
1107 {
1108         int i,drive,cnt,okay;
1109         struct floppy_struct *this_floppy;
1110 
1111         switch (cmd) {
1112                 RO_IOCTLS(inode->i_rdev,param);
1113         }
1114         drive = MINOR(inode->i_rdev);
1115         switch (cmd) {
1116                 case FDFMTBEG:
1117                         if (!suser())
1118                                 return -EPERM;
1119                         return 0;
1120                 case FDFMTEND:
1121                         if (!suser())
1122                                 return -EPERM;
1123                         cli();
1124                         fake_change |= 1 << (drive & 3);
1125                         sti();
1126                         drive &= 3;
1127                         cmd = FDCLRPRM;
1128                         break;
1129                 case FDGETPRM:
1130                         if (drive > 3) this_floppy = &floppy_type[drive >> 2];
1131                         else if ((this_floppy = current_type[drive & 3]) == NULL)
1132                                     return -ENODEV;
1133                         i = verify_area(VERIFY_WRITE,(void *) param,sizeof(struct floppy_struct));
1134                         if (i)
1135                                 return i;
1136                         for (cnt = 0; cnt < sizeof(struct floppy_struct); cnt++)
1137                                 put_fs_byte(((char *) this_floppy)[cnt],
1138                                     (char *) param+cnt);
1139                         return 0;
1140                 case FDFMTTRK:
1141                         if (!suser())
1142                                 return -EPERM;
1143                         if (fd_ref[drive & 3] != 1)
1144                                 return -EBUSY;
1145                         cli();
1146                         while (format_status != FORMAT_NONE)
1147                                 sleep_on(&format_done);
1148                         for (cnt = 0; cnt < sizeof(struct format_descr); cnt++)
1149                                 ((char *) &format_req)[cnt] = get_fs_byte(
1150                                     (char *) param+cnt);
1151                         format_req.device = drive;
1152                         format_status = FORMAT_WAIT;
1153                         format_errors = 0;
1154                         while (format_status != FORMAT_OKAY && format_status !=
1155                             FORMAT_ERROR) {
1156                                 if (fdc_busy) sleep_on(&fdc_wait);
1157                                 else {
1158                                         fdc_busy = 1;
1159                                         redo_fd_request();
1160                                 }
1161                         }
1162                         while (format_status != FORMAT_OKAY && format_status !=
1163                             FORMAT_ERROR)
1164                                 sleep_on(&format_done);
1165                         sti();
1166                         okay = format_status == FORMAT_OKAY;
1167                         format_status = FORMAT_NONE;
1168                         floppy_off(drive & 3);
1169                         wake_up(&format_done);
1170                         return okay ? 0 : -EIO;
1171                 case FDFLUSH:
1172                         if (!permission(inode, 2))
1173                                 return -EPERM;
1174                         cli();
1175                         fake_change |= 1 << (drive & 3);
1176                         sti();
1177                         check_disk_change(inode->i_rdev);
1178                         return 0;
1179         }
1180         if (!suser())
1181                 return -EPERM;
1182         if (drive < 0 || drive > 3)
1183                 return -EINVAL;
1184         switch (cmd) {
1185                 case FDCLRPRM:
1186                         current_type[drive] = NULL;
1187                         floppy_sizes[drive] = MAX_DISK_SIZE;
1188                         keep_data[drive] = 0;
1189                         break;
1190                 case FDSETPRM:
1191                 case FDDEFPRM:
1192                         memcpy_fromfs(user_params+drive,
1193                                 (void *) param,
1194                                 sizeof(struct floppy_struct));
1195                         current_type[drive] = &user_params[drive];
1196                         floppy_sizes[drive] = user_params[drive].size >> 1;
1197                         if (cmd == FDDEFPRM)
1198                                 keep_data[drive] = -1;
1199                         else {
1200                                 cli();
1201                                 while (fdc_busy) sleep_on(&fdc_wait);
1202                                 fdc_busy = 1;
1203                                 sti();
1204                                 outb_p((current_DOR & 0xfc) | drive |
1205                                     (0x10 << drive),FD_DOR);
1206                                 for (cnt = 0; cnt < 1000; cnt++) __asm__("nop");
1207                                 if (inb(FD_DIR) & 0x80)
1208                                         keep_data[drive] = 1;
1209                                 else
1210                                         keep_data[drive] = 0;
1211                                 outb_p(current_DOR,FD_DOR);
1212                                 fdc_busy = 0;
1213                                 wake_up(&fdc_wait);
1214                         }
1215                         break;
1216                 case FDMSGON:
1217                         ftd_msg[drive] = 1;
1218                         break;
1219                 case FDMSGOFF:
1220                         ftd_msg[drive] = 0;
1221                         break;
1222                 case FDSETEMSGTRESH:
1223                         min_report_error_cnt[drive] = (unsigned short) (param & 0x0f);
1224                         break;
1225                 default:
1226                         return -EINVAL;
1227         }
1228         return 0;
1229 }
1230 
1231 #define CMOS_READ(addr) ({ \
1232 outb_p(addr,0x70); \
1233 inb_p(0x71); \
1234 })
1235 
1236 static struct floppy_struct *find_base(int drive,int code)
1237 {
1238         struct floppy_struct *base;
1239 
1240         if (code > 0 && code < 5) {
1241                 base = &floppy_types[(code-1)*2];
1242                 printk("fd%d is %s",drive,base->name);
1243                 return base;
1244         }
1245         printk("fd%d is unknown type %d",drive,code);
1246         return NULL;
1247 }
1248 
1249 static void config_types(void)
1250 {
1251         printk("Floppy drive(s): ");
1252         base_type[0] = find_base(0,(CMOS_READ(0x10) >> 4) & 15);
1253         if (((CMOS_READ(0x14) >> 6) & 1) == 0)
1254                 base_type[1] = NULL;
1255         else {
1256                 printk(", ");
1257                 base_type[1] = find_base(1,CMOS_READ(0x10) & 15);
1258         }
1259         base_type[2] = base_type[3] = NULL;
1260         printk("\n");
1261 }
1262 
1263 /*
1264  * floppy_open check for aliasing (/dev/fd0 can be the same as
1265  * /dev/PS0 etc), and disallows simultaneous access to the same
1266  * drive with different device numbers.
1267  */
1268 static int floppy_open(struct inode * inode, struct file * filp)
1269 {
1270         int drive;
1271         int old_dev;
1272 
1273         drive = inode->i_rdev & 3;
1274         old_dev = fd_device[drive];
1275         if (fd_ref[drive])
1276                 if (old_dev != inode->i_rdev)
1277                         return -EBUSY;
1278         fd_ref[drive]++;
1279         fd_device[drive] = inode->i_rdev;
1280         buffer_drive = buffer_track = -1;
1281         if (old_dev && old_dev != inode->i_rdev)
1282                 invalidate_buffers(old_dev);
1283         if (filp && filp->f_mode)
1284                 check_disk_change(inode->i_rdev);
1285         return 0;
1286 }
1287 
1288 static void floppy_release(struct inode * inode, struct file * filp)
1289 {
1290         sync_dev(inode->i_rdev);
1291         if (!fd_ref[inode->i_rdev & 3]--) {
1292                 printk("floppy_release with fd_ref == 0");
1293                 fd_ref[inode->i_rdev & 3] = 0;
1294         }
1295 }
1296 
1297 static struct file_operations floppy_fops = {
1298         NULL,                   /* lseek - default */
1299         block_read,             /* read - general block-dev read */
1300         block_write,            /* write - general block-dev write */
1301         NULL,                   /* readdir - bad */
1302         NULL,                   /* select */
1303         fd_ioctl,               /* ioctl */
1304         NULL,                   /* mmap */
1305         floppy_open,            /* open */
1306         floppy_release,         /* release */
1307         block_fsync             /* fsync */
1308 };
1309 
1310 
1311 /*
1312  * The version command is not supposed to generate an interrupt, but
1313  * my FDC does, except when booting in SVGA screen mode.
1314  * When it does generate an interrupt, it doesn't return any status bytes.
1315  * It appears to have something to do with the version command...
1316  *
1317  * This should never be called, because of the reset after the version check.
1318  */
1319 static void ignore_interrupt(void)
1320 {
1321         printk(DEVICE_NAME ": weird interrupt ignored (%d)\n", result());
1322         reset = 1;
1323         CLEAR_INTR;     /* ignore only once */
1324 }
1325 
1326 
1327 static void floppy_interrupt(int unused)
1328 {
1329         void (*handler)(void) = DEVICE_INTR;
1330 
1331         DEVICE_INTR = NULL;
1332         if (!handler)
1333                 handler = unexpected_floppy_interrupt;
1334         handler();
1335 }
1336 
1337 /*
1338  * This is the floppy IRQ description. The SA_INTERRUPT in sa_flags
1339  * means we run the IRQ-handler with interrupts disabled.
1340  */
1341 static struct sigaction floppy_sigaction = {
1342         floppy_interrupt,
1343         0,
1344         SA_INTERRUPT,
1345         NULL
1346 };
1347 
1348 void floppy_init(void)
1349 {
1350         outb(current_DOR,FD_DOR);
1351         if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) {
1352                 printk("Unable to get major %d for floppy\n",MAJOR_NR);
1353                 return;
1354         }
1355         blk_size[MAJOR_NR] = floppy_sizes;
1356         blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
1357         timer_table[FLOPPY_TIMER].fn = floppy_shutdown;
1358         timer_active &= ~(1 << FLOPPY_TIMER);
1359         config_types();
1360         if (irqaction(FLOPPY_IRQ,&floppy_sigaction))
1361                 printk("Unable to grab IRQ%d for the floppy driver\n", FLOPPY_IRQ);
1362         if (request_dma(FLOPPY_DMA))
1363                 printk("Unable to grab DMA%d for the floppy driver\n", FLOPPY_DMA);
1364         /* Try to determine the floppy controller type */
1365         DEVICE_INTR = ignore_interrupt; /* don't ask ... */
1366         output_byte(FD_VERSION);        /* get FDC version code */
1367         if (result() != 1) {
1368                 printk(DEVICE_NAME ": FDC failed to return version byte\n");
1369                 fdc_version = FDC_TYPE_STD;
1370         } else
1371                 fdc_version = reply_buffer[0];
1372         if (fdc_version != FDC_TYPE_STD) 
1373                 printk(DEVICE_NAME ": FDC version 0x%x\n", fdc_version);
1374 #ifndef FDC_FIFO_UNTESTED
1375         fdc_version = FDC_TYPE_STD;     /* force std fdc type; can't test other. */
1376 #endif
1377 
1378         /* Not all FDCs seem to be able to handle the version command
1379          * properly, so force a reset for the standard FDC clones,
1380          * to avoid interrupt garbage.
1381          */
1382 
1383         if (fdc_version == FDC_TYPE_STD) {
1384                 initial_reset_flag = 1;
1385                 reset_floppy();
1386         }
1387 }
1388 

⌨️ 快捷键说明

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