📄 cm206.c
字号:
int cm206_media_changed(struct cdrom_device_info * cdi, int disc_nr) { if (cd != NULL) { int r; get_drive_status(); /* ensure cd->media_changed OK */ r = cd->media_changed; cd->media_changed = 0; /* clear bit */ return r; } else return -EIO;}/* The new generic cdrom support. Routines should be concise, most of the logic should be in cdrom.c *//* returns number of times device is in use */int cm206_open_files(struct cdrom_device_info * cdi) { if (cd) return cd->openfiles; return -1;}/* controls tray movement */int cm206_tray_move(struct cdrom_device_info * cdi, int position) { if (position) { /* 1: eject */ type_0_command(c_open_tray,1); invalidate_toc(); } else type_0_command(c_close_tray, 1); /* 0: close */ return 0;}/* gives current state of the drive */int cm206_drive_status(struct cdrom_device_info * cdi, int slot_nr){ get_drive_status(); if (cd->dsb & dsb_tray_not_closed) return CDS_TRAY_OPEN; if (!(cd->dsb & dsb_disc_present)) return CDS_NO_DISC; if (cd->dsb & dsb_drive_not_ready) return CDS_DRIVE_NOT_READY; return CDS_DISC_OK;} /* locks or unlocks door lock==1: lock; return 0 upon success */int cm206_lock_door(struct cdrom_device_info * cdi, int lock){ uch command = (lock) ? c_lock_tray : c_unlock_tray; type_0_command(command, 1); /* wait and get dsb */ /* the logic calculates the success, 0 means successful */ return lock ^ ((cd->dsb & dsb_tray_locked) != 0);} /* Although a session start should be in LBA format, we return it in MSF format because it is slightly easier, and the new generic ioctl will take care of the necessary conversion. */int cm206_get_last_session(struct cdrom_device_info * cdi, struct cdrom_multisession * mssp) { if (!FIRST_TRACK) get_disc_status(); if (mssp != NULL) { if (DISC_STATUS & cds_multi_session) { /* multi-session */ mssp->addr.msf.frame = cd->disc_status[3]; mssp->addr.msf.second = cd->disc_status[4]; mssp->addr.msf.minute = cd->disc_status[5]; mssp->addr_format = CDROM_MSF; mssp->xa_flag = 1; } else { mssp->xa_flag = 0; } return 1; } return 0;}int cm206_get_upc(struct cdrom_device_info * cdi, struct cdrom_mcn * mcn){ uch upc[10]; char * ret = mcn->medium_catalog_number; int i; if (type_1_command(c_read_upc, 10, upc)) return -EIO; for (i=0; i<13; i++) { int w=i/2+1, r=i%2; if (r) ret[i] = 0x30 | (upc[w] & 0x0f); else ret[i] = 0x30 | ((upc[w] >> 4) & 0x0f); } ret[13] = '\0'; return 0;} int cm206_reset(struct cdrom_device_info * cdi){ stop_read(); reset_cm260(); outw(dc_normal | dc_break | READ_AHEAD, r_data_control); mdelay(1); /* 750 musec minimum */ outw(dc_normal | READ_AHEAD, r_data_control); cd->sector_last = -1; /* flag no data buffered */ cd->adapter_last = -1; invalidate_toc(); return 0;}int cm206_select_speed(struct cdrom_device_info * cdi, int speed){ int r; switch (speed) { case 0: r = type_0_command(c_auto_mode, 1); break; case 1: r = type_0_command(c_force_1x, 1); break; case 2: r = type_0_command(c_force_2x, 1); break; default: return -1; } if (r<0) return r; else return 1;}static struct cdrom_device_ops cm206_dops = { open: cm206_open, release: cm206_release, drive_status: cm206_drive_status, media_changed: cm206_media_changed, tray_move: cm206_tray_move, lock_door: cm206_lock_door, select_speed: cm206_select_speed, get_last_session: cm206_get_last_session, get_mcn: cm206_get_upc, reset: cm206_reset, audio_ioctl: cm206_audio_ioctl, dev_ioctl: cm206_ioctl, capability: CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_MULTI_SESSION | CDC_MEDIA_CHANGED | CDC_MCN | CDC_PLAY_AUDIO | CDC_SELECT_SPEED | CDC_IOCTLS | CDC_DRIVE_STATUS, n_minors: 1,};static struct cdrom_device_info cm206_info = { ops: &cm206_dops, speed: 2, capacity: 1, name: "cm206",};/* This routine gets called during initialization if things go wrong, * can be used in cleanup_module as well. */static void cleanup(int level){ switch (level) { case 4: if (unregister_cdrom(&cm206_info)) { printk("Can't unregister cdrom cm206\n"); return; } if (devfs_unregister_blkdev(MAJOR_NR, "cm206")) { printk("Can't unregister major cm206\n"); return; } blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR)); case 3: free_irq(cm206_irq, NULL); case 2: case 1: kfree(cd); release_region(cm206_base, 16); default: }}/* This function probes for the adapter card. It returns the base address if it has found the adapter card. One can specify a base port to probe specifically, or 0 which means span all possible bases. Linus says it is too dangerous to use writes for probing, so we stick with pure reads for a while. Hope that 8 possible ranges, check_region, 15 bits of one port and 6 of another make things likely enough to accept the region on the first hit... */int __init probe_base_port(int base){ int b=0x300, e=0x370; /* this is the range of start addresses */ volatile int fool, i; if (base) b=e=base; for (base=b; base<=e; base += 0x10) { if (check_region(base, 0x10)) continue; for (i=0; i<3; i++) fool = inw(base+2); /* empty possibly uart_receive_buffer */ if((inw(base+6) & 0xffef) != 0x0001 || /* line_status */ (inw(base) & 0xad00) != 0) /* data status */ continue; return(base); } return 0;}#if !defined(MODULE) || defined(AUTO_PROBE_MODULE)/* Probe for irq# nr. If nr==0, probe for all possible irq's. */int __init probe_irq(int nr){ int irqs, irq; outw(dc_normal | READ_AHEAD, r_data_control); /* disable irq-generation */ sti(); irqs = probe_irq_on(); reset_cm260(); /* causes interrupt */ udelay(100); /* wait for it */ irq = probe_irq_off(irqs); outw(dc_normal | READ_AHEAD, r_data_control); /* services interrupt */ if (nr && irq!=nr && irq>0) return 0; /* wrong interrupt happened */ else return irq;}#endifint __init cm206_init(void){ uch e=0; long int size=sizeof(struct cm206_struct); printk(KERN_INFO "cm206 cdrom driver " REVISION); cm206_base = probe_base_port(auto_probe ? 0 : cm206_base); if (!cm206_base) { printk(" can't find adapter!\n"); return -EIO; } printk(" adapter at 0x%x", cm206_base); request_region(cm206_base, 16, "cm206"); cd = (struct cm206_struct *) kmalloc(size, GFP_KERNEL); if (!cd) return -EIO; /* Now we have found the adaptor card, try to reset it. As we have * found out earlier, this process generates an interrupt as well, * so we might just exploit that fact for irq probing! */#if !defined(MODULE) || defined(AUTO_PROBE_MODULE) cm206_irq = probe_irq(auto_probe ? 0 : cm206_irq); if (cm206_irq<=0) { printk("can't find IRQ!\n"); cleanup(1); return -EIO; } else printk(" IRQ %d found\n", cm206_irq);#else cli(); reset_cm260(); /* Now, the problem here is that reset_cm260 can generate an interrupt. It seems that this can cause a kernel oops some time later. So we wait a while and `service' this interrupt. */ mdelay(1); outw(dc_normal | READ_AHEAD, r_data_control); sti(); printk(" using IRQ %d\n", cm206_irq);#endif if (send_receive_polled(c_drive_configuration) != c_drive_configuration) { printk(KERN_INFO " drive not there\n"); cleanup(1); return -EIO; } e = send_receive_polled(c_gimme); printk(KERN_INFO "Firmware revision %d", e & dcf_revision_code); if (e & dcf_transfer_rate) printk(" double"); else printk(" single"); printk(" speed drive"); if (e & dcf_motorized_tray) printk(", motorized tray"); if (request_irq(cm206_irq, cm206_interrupt, 0, "cm206", NULL)) { printk("\nUnable to reserve IRQ---aborted\n"); cleanup(2); return -EIO; } printk(".\n"); if (devfs_register_blkdev(MAJOR_NR, "cm206", &cdrom_fops) != 0) { printk(KERN_INFO "Cannot register for major %d!\n", MAJOR_NR); cleanup(3); return -EIO; } cm206_info.dev = MKDEV(MAJOR_NR,0); if (register_cdrom(&cm206_info) != 0) { printk(KERN_INFO "Cannot register for cdrom %d!\n", MAJOR_NR); cleanup(3); return -EIO; } blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), DEVICE_REQUEST); blksize_size[MAJOR_NR] = cm206_blocksizes; read_ahead[MAJOR_NR] = 16; /* reads ahead what? */ init_bh(CM206_BH, cm206_bh); memset(cd, 0, sizeof(*cd)); /* give'm some reasonable value */ cd->sector_last = -1; /* flag no data buffered */ cd->adapter_last = -1; cd->timer.function = cm206_timeout; cd->max_sectors = (inw(r_data_status) & ds_ram_size) ? 24 : 97; printk(KERN_INFO "%d kB adapter memory available, " " %ld bytes kernel memory used.\n", cd->max_sectors*2, size); return 0;}#ifdef MODULEstatic void __init parse_options(void){ int i; for (i=0; i<2; i++) { if (0x300 <= cm206[i] && i<= 0x370 && cm206[i] % 0x10 == 0) { cm206_base = cm206[i]; auto_probe=0; } else if (3 <= cm206[i] && cm206[i] <= 15) { cm206_irq = cm206[i]; auto_probe=0; } }}int __cm206_init(void){ parse_options();#if !defined(AUTO_PROBE_MODULE) auto_probe=0;#endif return cm206_init();}void __exit cm206_exit(void){ cleanup(4); printk(KERN_INFO "cm206 removed\n");}module_init(__cm206_init);module_exit(cm206_exit); #else /* !MODULE *//* This setup function accepts either `auto' or numbers in the range * 3--11 (for irq) or 0x300--0x370 (for base port) or both. */static int __init cm206_setup(char *s){ int i, p[4]; (void)get_options(s, ARRAY_SIZE(p), p); if (!strcmp(s, "auto")) auto_probe=1; for(i=1; i<=p[0]; i++) { if (0x300 <= p[i] && i<= 0x370 && p[i] % 0x10 == 0) { cm206_base = p[i]; auto_probe = 0; } else if (3 <= p[i] && p[i] <= 15) { cm206_irq = p[i]; auto_probe = 0; } } return 1;}__setup("cm206=", cm206_setup);#endif /* !MODULE *//* * Local variables: * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -m486 -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h -c -o cm206.o cm206.c" * End: */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -