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

📄 sym53c500_cs.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		break;	case 0x07:		/* MESSAGE-IN */		VDEB(printk("SYM53C500: Message-In phase\n"));		curSC->SCp.phase = message_in;		curSC->SCp.Status = inb(port_base + SCSI_FIFO);		curSC->SCp.Message = inb(port_base + SCSI_FIFO);		VDEB(printk("SCSI FIFO size=%d\n", inb(port_base + FIFO_FLAGS) & 0x1f));		DEB(printk("Status = %02x  Message = %02x\n", curSC->SCp.Status, curSC->SCp.Message));		if (curSC->SCp.Message == SAVE_POINTERS || curSC->SCp.Message == DISCONNECT) {			outb(SET_ATN, port_base + CMD_REG);	/* Reject message */			DEB(printk("Discarding SAVE_POINTERS message\n"));		}		outb(MSG_ACCEPT, port_base + CMD_REG);		break;	}out:	spin_unlock_irqrestore(dev->host_lock, flags);	return IRQ_HANDLED;idle_out:	curSC->SCp.phase = idle;	curSC->scsi_done(curSC);	goto out;}static voidSYM53C500_release(dev_link_t *link){	struct scsi_info_t *info = link->priv;	struct Scsi_Host *shost = info->host;	DEBUG(0, "SYM53C500_release(0x%p)\n", link);	/*	*  Do this before releasing/freeing resources.	*/	scsi_remove_host(shost);	/*	*  Interrupts getting hosed on card removal.  Try	*  the following code, mostly from qlogicfas.c.	*/	if (shost->irq)		free_irq(shost->irq, shost);	if (shost->dma_channel != 0xff)		free_dma(shost->dma_channel);	if (shost->io_port && shost->n_io_port)		release_region(shost->io_port, shost->n_io_port);	link->dev = NULL;	pcmcia_release_configuration(link->handle);	pcmcia_release_io(link->handle, &link->io);	pcmcia_release_irq(link->handle, &link->irq);	link->state &= ~DEV_CONFIG;	scsi_host_put(shost);} /* SYM53C500_release */static const char*SYM53C500_info(struct Scsi_Host *SChost){	static char info_msg[256];	struct sym53c500_data *data =	    (struct sym53c500_data *)SChost->hostdata;	DEB(printk("SYM53C500_info called\n"));	(void)snprintf(info_msg, sizeof(info_msg),	    "SYM53C500 at 0x%lx, IRQ %d, %s PIO mode.", 	    SChost->io_port, SChost->irq, data->fast_pio ? "fast" : "slow");	return (info_msg);}static int SYM53C500_queue(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *)){	int i;	int port_base = SCpnt->device->host->io_port;	struct sym53c500_data *data =	    (struct sym53c500_data *)SCpnt->device->host->hostdata;	VDEB(printk("SYM53C500_queue called\n"));	DEB(printk("cmd=%02x, cmd_len=%02x, target=%02x, lun=%02x, bufflen=%d\n", 	    SCpnt->cmnd[0], SCpnt->cmd_len, SCpnt->device->id, 	    SCpnt->device->lun,  SCpnt->request_bufflen));	VDEB(for (i = 0; i < SCpnt->cmd_len; i++)	    printk("cmd[%d]=%02x  ", i, SCpnt->cmnd[i]));	VDEB(printk("\n"));	data->current_SC = SCpnt;	data->current_SC->scsi_done = done;	data->current_SC->SCp.phase = command_ph;	data->current_SC->SCp.Status = 0;	data->current_SC->SCp.Message = 0;	/* We are locked here already by the mid layer */	REG0(port_base);	outb(SCpnt->device->id, port_base + DEST_ID);	/* set destination */	outb(FLUSH_FIFO, port_base + CMD_REG);	/* reset the fifos */	for (i = 0; i < SCpnt->cmd_len; i++) {		outb(SCpnt->cmnd[i], port_base + SCSI_FIFO);	}	outb(SELECT_NO_ATN, port_base + CMD_REG);	return 0;}static int SYM53C500_host_reset(struct scsi_cmnd *SCpnt){	int port_base = SCpnt->device->host->io_port;	DEB(printk("SYM53C500_host_reset called\n"));	SYM53C500_int_host_reset(port_base);	return SUCCESS;}static int SYM53C500_biosparm(struct scsi_device *disk,    struct block_device *dev,    sector_t capacity, int *info_array){	int size;	DEB(printk("SYM53C500_biosparm called\n"));	size = capacity;	info_array[0] = 64;		/* heads */	info_array[1] = 32;		/* sectors */	info_array[2] = size >> 11;	/* cylinders */	if (info_array[2] > 1024) {	/* big disk */		info_array[0] = 255;		info_array[1] = 63;		info_array[2] = size / (255 * 63);	}	return 0;}static ssize_tSYM53C500_show_pio(struct class_device *cdev, char *buf){	struct Scsi_Host *SHp = class_to_shost(cdev);	struct sym53c500_data *data =	    (struct sym53c500_data *)SHp->hostdata;	return snprintf(buf, 4, "%d\n", data->fast_pio);}static ssize_tSYM53C500_store_pio(struct class_device *cdev, const char *buf, size_t count){	int pio;	struct Scsi_Host *SHp = class_to_shost(cdev);	struct sym53c500_data *data =	    (struct sym53c500_data *)SHp->hostdata;	pio = simple_strtoul(buf, NULL, 0);	if (pio == 0 || pio == 1) {		data->fast_pio = pio;		return count;	}	else		return -EINVAL;}/**  SCSI HBA device attributes we want to*  make available via sysfs.*/static struct class_device_attribute SYM53C500_pio_attr = {	.attr = {		.name = "fast_pio",		.mode = (S_IRUGO | S_IWUSR),	},	.show = SYM53C500_show_pio,	.store = SYM53C500_store_pio,};static struct class_device_attribute *SYM53C500_shost_attrs[] = {	&SYM53C500_pio_attr,	NULL,};/**  scsi_host_template initializer*/static struct scsi_host_template sym53c500_driver_template = {     .module			= THIS_MODULE,     .name			= "SYM53C500",     .info			= SYM53C500_info,     .queuecommand		= SYM53C500_queue,     .eh_host_reset_handler	= SYM53C500_host_reset,     .bios_param		= SYM53C500_biosparm,     .proc_name			= "SYM53C500",     .can_queue			= 1,     .this_id			= 7,     .sg_tablesize		= 32,     .cmd_per_lun		= 1,     .use_clustering		= ENABLE_CLUSTERING,     .shost_attrs		= SYM53C500_shost_attrs};#define CS_CHECK(fn, ret) \do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)static voidSYM53C500_config(dev_link_t *link){	client_handle_t handle = link->handle;	struct scsi_info_t *info = link->priv;	tuple_t tuple;	cisparse_t parse;	int i, last_ret, last_fn;	int irq_level, port_base;	unsigned short tuple_data[32];	struct Scsi_Host *host;	struct scsi_host_template *tpnt = &sym53c500_driver_template;	struct sym53c500_data *data;	DEBUG(0, "SYM53C500_config(0x%p)\n", link);	tuple.TupleData = (cisdata_t *)tuple_data;	tuple.TupleDataMax = 64;	tuple.TupleOffset = 0;	tuple.DesiredTuple = CISTPL_CONFIG;	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));	CS_CHECK(GetTupleData, pcmcia_get_tuple_data(handle, &tuple));	CS_CHECK(ParseTuple, pcmcia_parse_tuple(handle, &tuple, &parse));	link->conf.ConfigBase = parse.config.base;	tuple.DesiredTuple = CISTPL_MANFID;	if ((pcmcia_get_first_tuple(handle, &tuple) == CS_SUCCESS) &&	    (pcmcia_get_tuple_data(handle, &tuple) == CS_SUCCESS))		info->manf_id = le16_to_cpu(tuple.TupleData[0]);	/* Configure card */	link->state |= DEV_CONFIG;	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;	CS_CHECK(GetFirstTuple, pcmcia_get_first_tuple(handle, &tuple));	while (1) {		if (pcmcia_get_tuple_data(handle, &tuple) != 0 ||		    pcmcia_parse_tuple(handle, &tuple, &parse) != 0)			goto next_entry;		link->conf.ConfigIndex = parse.cftable_entry.index;		link->io.BasePort1 = parse.cftable_entry.io.win[0].base;		link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;		if (link->io.BasePort1 != 0) {			i = pcmcia_request_io(handle, &link->io);			if (i == CS_SUCCESS)				break;		}next_entry:		CS_CHECK(GetNextTuple, pcmcia_get_next_tuple(handle, &tuple));	}	CS_CHECK(RequestIRQ, pcmcia_request_irq(handle, &link->irq));	CS_CHECK(RequestConfiguration, pcmcia_request_configuration(handle, &link->conf));	/*	*  That's the trouble with copying liberally from another driver.	*  Some things probably aren't relevant, and I suspect this entire	*  section dealing with manufacturer IDs can be scrapped.	--rct	*/	if ((info->manf_id == MANFID_MACNICA) ||	    (info->manf_id == MANFID_PIONEER) ||	    (info->manf_id == 0x0098)) {		/* set ATAcmd */		outb(0xb4, link->io.BasePort1 + 0xd);		outb(0x24, link->io.BasePort1 + 0x9);		outb(0x04, link->io.BasePort1 + 0xd);	}	/*	*  irq_level == 0 implies tpnt->can_queue == 0, which	*  is not supported in 2.6.  Thus, only irq_level > 0	*  will be allowed.	*	*  Possible port_base values are as follows:	*	*	0x130, 0x230, 0x280, 0x290,	*	0x320, 0x330, 0x340, 0x350	*/	port_base = link->io.BasePort1;	irq_level = link->irq.AssignedIRQ;	DEB(printk("SYM53C500: port_base=0x%x, irq=%d, fast_pio=%d\n",	    port_base, irq_level, USE_FAST_PIO);)	chip_init(port_base);	host = scsi_host_alloc(tpnt, sizeof(struct sym53c500_data));	if (!host) {		printk("SYM53C500: Unable to register host, giving up.\n");		goto err_release;	}	data = (struct sym53c500_data *)host->hostdata;	if (irq_level > 0) {		if (request_irq(irq_level, SYM53C500_intr, 0, "SYM53C500", host)) {			printk("SYM53C500: unable to allocate IRQ %d\n", irq_level);			goto err_free_scsi;		}		DEB(printk("SYM53C500: allocated IRQ %d\n", irq_level));	} else if (irq_level == 0) {		DEB(printk("SYM53C500: No interrupts detected\n"));		goto err_free_scsi;	} else {		DEB(printk("SYM53C500: Shouldn't get here!\n"));		goto err_free_scsi;	}	host->unique_id = port_base;	host->irq = irq_level;	host->io_port = port_base;	host->n_io_port = 0x10;	host->dma_channel = -1;	/*	*  Note fast_pio is set to USE_FAST_PIO by	*  default, but can be changed via "sysfs".	*/	data->fast_pio = USE_FAST_PIO;	sprintf(info->node.dev_name, "scsi%d", host->host_no);	link->dev = &info->node;	info->host = host;	if (scsi_add_host(host, NULL))		goto err_free_irq;	scsi_scan_host(host);	goto out;	/* SUCCESS */err_free_irq:	free_irq(irq_level, host);err_free_scsi:	scsi_host_put(host);err_release:	release_region(port_base, 0x10);	printk(KERN_INFO "sym53c500_cs: no SCSI devices found\n");out:	link->state &= ~DEV_CONFIG_PENDING;	return;cs_failed:	cs_error(link->handle, last_fn, last_ret);	SYM53C500_release(link);	return;} /* SYM53C500_config */static intSYM53C500_event(event_t event, int priority, event_callback_args_t *args){	dev_link_t *link = args->client_data;	struct scsi_info_t *info = link->priv;	DEBUG(1, "SYM53C500_event(0x%06x)\n", event);	switch (event) {	case CS_EVENT_CARD_REMOVAL:		link->state &= ~DEV_PRESENT;		if (link->state & DEV_CONFIG)			SYM53C500_release(link);		break;	case CS_EVENT_CARD_INSERTION:		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;		SYM53C500_config(link);		break;	case CS_EVENT_PM_SUSPEND:		link->state |= DEV_SUSPEND;		/* Fall through... */	case CS_EVENT_RESET_PHYSICAL:		if (link->state & DEV_CONFIG)			pcmcia_release_configuration(link->handle);		break;	case CS_EVENT_PM_RESUME:		link->state &= ~DEV_SUSPEND;		/* Fall through... */	case CS_EVENT_CARD_RESET:		if (link->state & DEV_CONFIG) {			pcmcia_request_configuration(link->handle, &link->conf);			/* See earlier comment about manufacturer IDs. */			if ((info->manf_id == MANFID_MACNICA) ||			    (info->manf_id == MANFID_PIONEER) ||			    (info->manf_id == 0x0098)) {				outb(0x80, link->io.BasePort1 + 0xd);				outb(0x24, link->io.BasePort1 + 0x9);				outb(0x04, link->io.BasePort1 + 0xd);			}			/*			*  If things don't work after a "resume",			*  this is a good place to start looking.			*/			SYM53C500_int_host_reset(link->io.BasePort1);		}		break;	}	return 0;} /* SYM53C500_event */static voidSYM53C500_detach(dev_link_t *link){	dev_link_t **linkp;	DEBUG(0, "SYM53C500_detach(0x%p)\n", link);	/* Locate device structure */	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)		if (*linkp == link)			break;	if (*linkp == NULL)		return;	if (link->state & DEV_CONFIG)		SYM53C500_release(link);	if (link->handle)		pcmcia_deregister_client(link->handle);	/* Unlink device structure, free bits. */	*linkp = link->next;	kfree(link->priv);	link->priv = NULL;} /* SYM53C500_detach */static dev_link_t *SYM53C500_attach(void){	struct scsi_info_t *info;	client_reg_t client_reg;	dev_link_t *link;	int i, ret;	DEBUG(0, "SYM53C500_attach()\n");	/* Create new SCSI device */	info = kmalloc(sizeof(*info), GFP_KERNEL);	if (!info)		return NULL;	memset(info, 0, sizeof(*info));	link = &info->link;	link->priv = info;	link->io.NumPorts1 = 16;	link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;	link->io.IOAddrLines = 10;	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;	link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;	if (irq_list[0] == -1)		link->irq.IRQInfo2 = irq_mask;	else		for (i = 0; i < 4; i++)			link->irq.IRQInfo2 |= 1 << irq_list[i];	link->conf.Attributes = CONF_ENABLE_IRQ;	link->conf.Vcc = 50;	link->conf.IntType = INT_MEMORY_AND_IO;	link->conf.Present = PRESENT_OPTION;	/* Register with Card Services */	link->next = dev_list;	dev_list = link;	client_reg.dev_info = &dev_info;	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;	client_reg.event_handler = &SYM53C500_event;	client_reg.EventMask = CS_EVENT_RESET_REQUEST | CS_EVENT_CARD_RESET |	    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |	    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;	client_reg.Version = 0x0210;	client_reg.event_callback_args.client_data = link;	ret = pcmcia_register_client(&link->handle, &client_reg);	if (ret != 0) {		cs_error(link->handle, RegisterClient, ret);		SYM53C500_detach(link);		return NULL;	}	return link;} /* SYM53C500_attach */MODULE_AUTHOR("Bob Tracy <rct@frus.com>");MODULE_DESCRIPTION("SYM53C500 PCMCIA SCSI driver");MODULE_LICENSE("GPL");static struct pcmcia_driver sym53c500_cs_driver = {	.owner		= THIS_MODULE,	.drv		= {		.name	= "sym53c500_cs",	},	.attach		= SYM53C500_attach,	.detach		= SYM53C500_detach,};static int __initinit_sym53c500_cs(void){	return pcmcia_register_driver(&sym53c500_cs_driver);}static void __exitexit_sym53c500_cs(void){	pcmcia_unregister_driver(&sym53c500_cs_driver);}module_init(init_sym53c500_cs);module_exit(exit_sym53c500_cs);

⌨️ 快捷键说明

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