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

📄 cm206.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
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 + -