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

📄 ide-taskfile.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		return ide_stopped;	}	/* Still data left to transfer. */	ide_pio_datablock(drive, rq, 1);	ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL);	return ide_started;}ide_startstop_t pre_task_out_intr (ide_drive_t *drive, struct request *rq){	ide_startstop_t startstop;	if (ide_wait_stat(&startstop, drive, DATA_READY,			  drive->bad_wstat, WAIT_DRQ)) {		printk(KERN_ERR "%s: no DRQ after issuing %sWRITE%s\n",				drive->name,				drive->hwif->data_phase ? "MULT" : "",				drive->addressing ? "_EXT" : "");		return startstop;	}	if (!drive->unmask)		local_irq_disable();	ide_set_handler(drive, &task_out_intr, WAIT_WORSTCASE, NULL);	ide_pio_datablock(drive, rq, 1);	return ide_started;}EXPORT_SYMBOL(pre_task_out_intr);static int ide_diag_taskfile(ide_drive_t *drive, ide_task_t *args, unsigned long data_size, u8 *buf){	struct request rq;	memset(&rq, 0, sizeof(rq));	rq.ref_count = 1;	rq.cmd_type = REQ_TYPE_ATA_TASKFILE;	rq.buffer = buf;	/*	 * (ks) We transfer currently only whole sectors.	 * This is suffient for now.  But, it would be great,	 * if we would find a solution to transfer any size.	 * To support special commands like READ LONG.	 */	if (args->command_type != IDE_DRIVE_TASK_NO_DATA) {		if (data_size == 0)			rq.nr_sectors = (args->hobRegister[IDE_NSECTOR_OFFSET] << 8) | args->tfRegister[IDE_NSECTOR_OFFSET];		else			rq.nr_sectors = data_size / SECTOR_SIZE;		if (!rq.nr_sectors) {			printk(KERN_ERR "%s: in/out command without data\n",					drive->name);			return -EFAULT;		}		rq.hard_nr_sectors = rq.nr_sectors;		rq.hard_cur_sectors = rq.current_nr_sectors = rq.nr_sectors;		if (args->command_type == IDE_DRIVE_TASK_RAW_WRITE)			rq.cmd_flags |= REQ_RW;	}	rq.special = args;	args->rq = &rq;	return ide_do_drive_cmd(drive, &rq, ide_wait);}int ide_raw_taskfile (ide_drive_t *drive, ide_task_t *args, u8 *buf){	return ide_diag_taskfile(drive, args, 0, buf);}EXPORT_SYMBOL(ide_raw_taskfile);#ifdef CONFIG_IDE_TASK_IOCTLint ide_taskfile_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg){	ide_task_request_t	*req_task;	ide_task_t		args;	u8 *outbuf		= NULL;	u8 *inbuf		= NULL;	task_ioreg_t *argsptr	= args.tfRegister;	task_ioreg_t *hobsptr	= args.hobRegister;	int err			= 0;	int tasksize		= sizeof(struct ide_task_request_s);	unsigned int taskin	= 0;	unsigned int taskout	= 0;	u8 io_32bit		= drive->io_32bit;	char __user *buf = (char __user *)arg;//	printk("IDE Taskfile ...\n");	req_task = kzalloc(tasksize, GFP_KERNEL);	if (req_task == NULL) return -ENOMEM;	if (copy_from_user(req_task, buf, tasksize)) {		kfree(req_task);		return -EFAULT;	}	taskout = req_task->out_size;	taskin  = req_task->in_size;		if (taskin > 65536 || taskout > 65536) {		err = -EINVAL;		goto abort;	}	if (taskout) {		int outtotal = tasksize;		outbuf = kzalloc(taskout, GFP_KERNEL);		if (outbuf == NULL) {			err = -ENOMEM;			goto abort;		}		if (copy_from_user(outbuf, buf + outtotal, taskout)) {			err = -EFAULT;			goto abort;		}	}	if (taskin) {		int intotal = tasksize + taskout;		inbuf = kzalloc(taskin, GFP_KERNEL);		if (inbuf == NULL) {			err = -ENOMEM;			goto abort;		}		if (copy_from_user(inbuf, buf + intotal, taskin)) {			err = -EFAULT;			goto abort;		}	}	memset(&args, 0, sizeof(ide_task_t));	memcpy(argsptr, req_task->io_ports, HDIO_DRIVE_TASK_HDR_SIZE);	memcpy(hobsptr, req_task->hob_ports, HDIO_DRIVE_HOB_HDR_SIZE);	args.tf_in_flags  = req_task->in_flags;	args.tf_out_flags = req_task->out_flags;	args.data_phase   = req_task->data_phase;	args.command_type = req_task->req_cmd;	drive->io_32bit = 0;	switch(req_task->data_phase) {		case TASKFILE_OUT_DMAQ:		case TASKFILE_OUT_DMA:			err = ide_diag_taskfile(drive, &args, taskout, outbuf);			break;		case TASKFILE_IN_DMAQ:		case TASKFILE_IN_DMA:			err = ide_diag_taskfile(drive, &args, taskin, inbuf);			break;		case TASKFILE_MULTI_OUT:			if (!drive->mult_count) {				/* (hs): give up if multcount is not set */				printk(KERN_ERR "%s: %s Multimode Write " \					"multcount is not set\n",					drive->name, __FUNCTION__);				err = -EPERM;				goto abort;			}			/* fall through */		case TASKFILE_OUT:			args.prehandler = &pre_task_out_intr;			args.handler = &task_out_intr;			err = ide_diag_taskfile(drive, &args, taskout, outbuf);			break;		case TASKFILE_MULTI_IN:			if (!drive->mult_count) {				/* (hs): give up if multcount is not set */				printk(KERN_ERR "%s: %s Multimode Read failure " \					"multcount is not set\n",					drive->name, __FUNCTION__);				err = -EPERM;				goto abort;			}			/* fall through */		case TASKFILE_IN:			args.handler = &task_in_intr;			err = ide_diag_taskfile(drive, &args, taskin, inbuf);			break;		case TASKFILE_NO_DATA:			args.handler = &task_no_data_intr;			err = ide_diag_taskfile(drive, &args, 0, NULL);			break;		default:			err = -EFAULT;			goto abort;	}	memcpy(req_task->io_ports, &(args.tfRegister), HDIO_DRIVE_TASK_HDR_SIZE);	memcpy(req_task->hob_ports, &(args.hobRegister), HDIO_DRIVE_HOB_HDR_SIZE);	req_task->in_flags  = args.tf_in_flags;	req_task->out_flags = args.tf_out_flags;	if (copy_to_user(buf, req_task, tasksize)) {		err = -EFAULT;		goto abort;	}	if (taskout) {		int outtotal = tasksize;		if (copy_to_user(buf + outtotal, outbuf, taskout)) {			err = -EFAULT;			goto abort;		}	}	if (taskin) {		int intotal = tasksize + taskout;		if (copy_to_user(buf + intotal, inbuf, taskin)) {			err = -EFAULT;			goto abort;		}	}abort:	kfree(req_task);	kfree(outbuf);	kfree(inbuf);//	printk("IDE Taskfile ioctl ended. rc = %i\n", err);	drive->io_32bit = io_32bit;	return err;}#endifint ide_wait_cmd (ide_drive_t *drive, u8 cmd, u8 nsect, u8 feature, u8 sectors, u8 *buf){	struct request rq;	u8 buffer[4];	if (!buf)		buf = buffer;	memset(buf, 0, 4 + SECTOR_WORDS * 4 * sectors);	ide_init_drive_cmd(&rq);	rq.buffer = buf;	*buf++ = cmd;	*buf++ = nsect;	*buf++ = feature;	*buf++ = sectors;	return ide_do_drive_cmd(drive, &rq, ide_wait);}int ide_cmd_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg){	int err = 0;	u8 args[4], *argbuf = args;	u8 xfer_rate = 0;	int argsize = 4;	ide_task_t tfargs;	if (NULL == (void *) arg) {		struct request rq;		ide_init_drive_cmd(&rq);		return ide_do_drive_cmd(drive, &rq, ide_wait);	}	if (copy_from_user(args, (void __user *)arg, 4))		return -EFAULT;	memset(&tfargs, 0, sizeof(ide_task_t));	tfargs.tfRegister[IDE_FEATURE_OFFSET] = args[2];	tfargs.tfRegister[IDE_NSECTOR_OFFSET] = args[3];	tfargs.tfRegister[IDE_SECTOR_OFFSET]  = args[1];	tfargs.tfRegister[IDE_LCYL_OFFSET]    = 0x00;	tfargs.tfRegister[IDE_HCYL_OFFSET]    = 0x00;	tfargs.tfRegister[IDE_SELECT_OFFSET]  = 0x00;	tfargs.tfRegister[IDE_COMMAND_OFFSET] = args[0];	if (args[3]) {		argsize = 4 + (SECTOR_WORDS * 4 * args[3]);		argbuf = kzalloc(argsize, GFP_KERNEL);		if (argbuf == NULL)			return -ENOMEM;	}	if (set_transfer(drive, &tfargs)) {		xfer_rate = args[1];		if (ide_ata66_check(drive, &tfargs))			goto abort;	}	err = ide_wait_cmd(drive, args[0], args[1], args[2], args[3], argbuf);	if (!err && xfer_rate) {		/* active-retuning-calls future */		ide_set_xfer_rate(drive, xfer_rate);		ide_driveid_update(drive);	}abort:	if (copy_to_user((void __user *)arg, argbuf, argsize))		err = -EFAULT;	if (argsize > 4)		kfree(argbuf);	return err;}static int ide_wait_cmd_task(ide_drive_t *drive, u8 *buf){	struct request rq;	ide_init_drive_cmd(&rq);	rq.cmd_type = REQ_TYPE_ATA_TASK;	rq.buffer = buf;	return ide_do_drive_cmd(drive, &rq, ide_wait);}int ide_task_ioctl (ide_drive_t *drive, unsigned int cmd, unsigned long arg){	void __user *p = (void __user *)arg;	int err = 0;	u8 args[7], *argbuf = args;	int argsize = 7;	if (copy_from_user(args, p, 7))		return -EFAULT;	err = ide_wait_cmd_task(drive, argbuf);	if (copy_to_user(p, argbuf, argsize))		err = -EFAULT;	return err;}/* * NOTICE: This is additions from IBM to provide a discrete interface, * for selective taskregister access operations.  Nice JOB Klaus!!! * Glad to be able to work and co-develop this with you and IBM. */ide_startstop_t flagged_taskfile (ide_drive_t *drive, ide_task_t *task){	ide_hwif_t *hwif	= HWIF(drive);	task_struct_t *taskfile	= (task_struct_t *) task->tfRegister;	hob_struct_t *hobfile	= (hob_struct_t *) task->hobRegister;	if (task->data_phase == TASKFILE_MULTI_IN ||	    task->data_phase == TASKFILE_MULTI_OUT) {		if (!drive->mult_count) {			printk(KERN_ERR "%s: multimode not set!\n", drive->name);			return ide_stopped;		}	}	/*	 * (ks) Check taskfile in flags.	 * If set, then execute as it is defined.	 * If not set, then define default settings.	 * The default values are:	 *	read all taskfile registers (except data)	 *	read the hob registers (sector, nsector, lcyl, hcyl)	 */	if (task->tf_in_flags.all == 0) {		task->tf_in_flags.all = IDE_TASKFILE_STD_IN_FLAGS;		if (drive->addressing == 1)			task->tf_in_flags.all |= (IDE_HOB_STD_IN_FLAGS  << 8);        }	/* ALL Command Block Executions SHALL clear nIEN, unless otherwise */	if (IDE_CONTROL_REG)		/* clear nIEN */		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);	SELECT_MASK(drive, 0);	if (task->tf_out_flags.b.data) {		u16 data =  taskfile->data + (hobfile->data << 8);		hwif->OUTW(data, IDE_DATA_REG);	}	/* (ks) send hob registers first */	if (task->tf_out_flags.b.nsector_hob)		hwif->OUTB(hobfile->sector_count, IDE_NSECTOR_REG);	if (task->tf_out_flags.b.sector_hob)		hwif->OUTB(hobfile->sector_number, IDE_SECTOR_REG);	if (task->tf_out_flags.b.lcyl_hob)		hwif->OUTB(hobfile->low_cylinder, IDE_LCYL_REG);	if (task->tf_out_flags.b.hcyl_hob)		hwif->OUTB(hobfile->high_cylinder, IDE_HCYL_REG);	/* (ks) Send now the standard registers */	if (task->tf_out_flags.b.error_feature)		hwif->OUTB(taskfile->feature, IDE_FEATURE_REG);	/* refers to number of sectors to transfer */	if (task->tf_out_flags.b.nsector)		hwif->OUTB(taskfile->sector_count, IDE_NSECTOR_REG);	/* refers to sector offset or start sector */	if (task->tf_out_flags.b.sector)		hwif->OUTB(taskfile->sector_number, IDE_SECTOR_REG);	if (task->tf_out_flags.b.lcyl)		hwif->OUTB(taskfile->low_cylinder, IDE_LCYL_REG);	if (task->tf_out_flags.b.hcyl)		hwif->OUTB(taskfile->high_cylinder, IDE_HCYL_REG);        /*	 * (ks) In the flagged taskfile approch, we will use all specified	 * registers and the register value will not be changed, except the	 * select bit (master/slave) in the drive_head register. We must make	 * sure that the desired drive is selected.	 */	hwif->OUTB(taskfile->device_head | drive->select.all, IDE_SELECT_REG);	switch(task->data_phase) {   	        case TASKFILE_OUT_DMAQ:		case TASKFILE_OUT_DMA:		case TASKFILE_IN_DMAQ:		case TASKFILE_IN_DMA:			if (!drive->using_dma)				break;			if (!hwif->dma_setup(drive)) {				hwif->dma_exec_cmd(drive, taskfile->command);				hwif->dma_start(drive);				return ide_started;			}			break;	        default: 			if (task->handler == NULL)				return ide_stopped;			/* Issue the command */			if (task->prehandler) {				hwif->OUTBSYNC(drive, taskfile->command, IDE_COMMAND_REG);				ndelay(400);	/* FIXME */				return task->prehandler(drive, task->rq);			}			ide_execute_command(drive, taskfile->command, task->handler, WAIT_WORSTCASE, NULL);			return ide_started;	}	return ide_stopped;}

⌨️ 快捷键说明

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