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

📄 acsi_slm.c

📁 Linux块设备驱动源码
💻 C
📖 第 1 页 / 共 2 页
字号:
		did_wait = 1;#endif		local_irq_disable();		while( get_dma_addr() < SLMEndAddr )			barrier();	}	/* slice finished, start next one */	SLMCurAddr += SLMSliceSize;#ifdef SLM_CONTINUOUS_DMA	/* program for 255*512 bytes again */	dma_wd.fdc_acces_seccount = SLM_DMA_AMOUNT;#else	/* set DMA address;	 * add 2 bytes for the ones in the SLM controller FIFO! */	set_dma_addr( SLMCurAddr + 2 );	/* toggle DMA to write and select sector counter reg */	dma_wd.dma_mode_status = 0x92;	MFPDELAY();	dma_wd.dma_mode_status = 0x192;	MFPDELAY();	/* program for 255*512 bytes and start DMA */	DMA_LONG_WRITE( SLM_DMA_AMOUNT, 0x112 );#endif		local_irq_restore(flags);#ifdef DEBUG	if (did_wait) {		int ms;		do_gettimeofday( &end_tm );		ms = (end_tm.tv_sec*1000000+end_tm.tv_usec) -			 (start_tm.tv_sec*1000000+start_tm.tv_usec); 		printk( "SLM: did %ld.%ld ms busy waiting for %d bytes\n",				ms/1000, ms%1000, d );	}	else		printk( "SLM: didn't wait (!)\n" );#endif	if ((unsigned char *)PTOV( SLMCurAddr + SLMSliceSize ) >= BufferP) {		/* will be last slice, no timer necessary */#ifdef DEBUG		printk( "SLM: CurAddr=%#lx EndAddr=%#lx last slice -> no timer\n",				SLMCurAddr, SLMEndAddr );#endif	}	else {		/* not last slice */		SLMEndAddr = SLMCurAddr + SLMSliceSize + SLM_DMA_INT_OFFSET;		START_TIMER( DMA_TIME_FOR( SLMSliceSize ));#ifdef DEBUG		printk( "SLM: CurAddr=%#lx EndAddr=%#lx timer=%ld\n",				SLMCurAddr, SLMEndAddr, DMA_TIME_FOR( SLMSliceSize ) );#endif	}#endif /* SLM_CONT_CNT_REPROG */}static void set_dma_addr( unsigned long paddr ){	unsigned long flags;	local_irq_save(flags);	dma_wd.dma_lo = (unsigned char)paddr;	paddr >>= 8;	MFPDELAY();	dma_wd.dma_md = (unsigned char)paddr;	paddr >>= 8;	MFPDELAY();	if (ATARIHW_PRESENT( EXTD_DMA ))		st_dma_ext_dmahi = (unsigned short)paddr;	else		dma_wd.dma_hi = (unsigned char)paddr;	MFPDELAY();	local_irq_restore(flags);}static unsigned long get_dma_addr( void ){	unsigned long	addr;		addr = dma_wd.dma_lo & 0xff;	MFPDELAY();	addr |= (dma_wd.dma_md & 0xff) << 8;	MFPDELAY();	addr |= (dma_wd.dma_hi & 0xff) << 16;	MFPDELAY();	return( addr );}static ssize_t slm_write( struct file *file, const char *buf, size_t count,						  loff_t *ppos ){	struct inode *node = file->f_dentry->d_inode;	int		device = iminor(node);	int		n, filled, w, h;	while( SLMState == PRINTING ||		   (SLMState == FILLING && SLMBufOwner != device) ) {		interruptible_sleep_on( &slm_wait );		if (signal_pending(current))			return( -ERESTARTSYS );	}	if (SLMState == IDLE) {		/* first data of page: get current page size  */		if (slm_get_pagesize( device, &w, &h ))			return( -EIO );		BufferSize = w*h/8;		if (BufferSize > SLM_BUFFER_SIZE)			return( -ENOMEM );		SLMState = FILLING;		SLMBufOwner = device;	}	n = count;	filled = BufferP - SLMBuffer;	if (filled + n > BufferSize)		n = BufferSize - filled;	if (copy_from_user(BufferP, buf, n))		return -EFAULT;	BufferP += n;	filled += n;	if (filled == BufferSize) {		/* Check the paper size again! The user may have switched it in the		 * time between starting the data and finishing them. Would end up in		 * a trashy page... */		if (slm_get_pagesize( device, &w, &h ))			return( -EIO );		if (BufferSize != w*h/8) {			printk( KERN_NOTICE "slm%d: page size changed while printing\n",					device );			return( -EAGAIN );		}		SLMState = PRINTING;		/* choose a slice size that is a multiple of the line size */#ifndef SLM_CONT_CNT_REPROG		SLMSliceSize = SLM_SLICE_SIZE(w);#endif				start_print( device );		sleep_on( &print_wait );		if (SLMError && IS_REAL_ERROR(SLMError)) {			printk( KERN_ERR "slm%d: %s\n", device, slm_errstr(SLMError) );			n = -EIO;		}		SLMState = IDLE;		BufferP = SLMBuffer;		wake_up_interruptible( &slm_wait );	}		return( n );}/* ---------------------------------------------------------------------- *//*							   ioctl Functions							  */static int slm_ioctl( struct inode *inode, struct file *file,					  unsigned int cmd, unsigned long arg ){	int		device = iminor(inode), err;		/* I can think of setting:	 *  - manual feed	 *  - paper format	 *  - copy count	 *  - ...	 * but haven't implemented that yet :-)	 * BTW, has anybody better docs about the MODE SENSE/MODE SELECT data?	 */	switch( cmd ) {	  case SLMIORESET:		/* reset buffer, i.e. empty the buffer */		if (!(file->f_mode & 2))			return( -EINVAL );		if (SLMState == PRINTING)			return( -EBUSY );		SLMState = IDLE;		BufferP = SLMBuffer;		wake_up_interruptible( &slm_wait );		return( 0 );			  case SLMIOGSTAT: {	/* get status */		int stat;		char *str;		stat = slm_req_sense( device );		if (arg) {			str = slm_errstr( stat );			if (put_user(stat,    	    	    	    	     (long *)&((struct SLM_status *)arg)->stat))    	    	    	    	return -EFAULT;			if (copy_to_user( ((struct SLM_status *)arg)->str, str,						 strlen(str) + 1))				return -EFAULT;		}		return( stat );	  }			  case SLMIOGPSIZE: {	/* get paper size */		int w, h;				if ((err = slm_get_pagesize( device, &w, &h ))) return( err );		    	    	if (put_user(w, (long *)&((struct SLM_paper_size *)arg)->width))			return -EFAULT;		if (put_user(h, (long *)&((struct SLM_paper_size *)arg)->height))			return -EFAULT;		return( 0 );	  }			  case SLMIOGMFEED:	/* get manual feed */		return( -EINVAL );	  case SLMIOSPSIZE:	/* set paper size */		return( -EINVAL );	  case SLMIOSMFEED:	/* set manual feed */		return( -EINVAL );	}	return( -EINVAL );}/* ---------------------------------------------------------------------- *//*							 Opening and Closing						  */static int slm_open( struct inode *inode, struct file *file ){	int device;	struct slm *sip;		device = iminor(inode);	if (device >= N_SLM_Printers)		return( -ENXIO );	sip = &slm_info[device];	if (file->f_mode & 2) {		/* open for writing is exclusive */		if ( !atomic_dec_and_test(&sip->wr_ok) ) {			atomic_inc(&sip->wr_ok);				return( -EBUSY );		}	}	if (file->f_mode & 1) {		/* open for reading is exclusive */                if ( !atomic_dec_and_test(&sip->rd_ok) ) {                        atomic_inc(&sip->rd_ok);                        return( -EBUSY );                }	}	return( 0 );}static int slm_release( struct inode *inode, struct file *file ){	int device;	struct slm *sip;		device = iminor(inode);	sip = &slm_info[device];	if (file->f_mode & 2)		atomic_inc( &sip->wr_ok );	if (file->f_mode & 1)		atomic_inc( &sip->rd_ok );		return( 0 );}/* ---------------------------------------------------------------------- *//*						 ACSI Primitives for the SLM					  */static int slm_req_sense( int device ){	int			stat, rv;	struct slm *sip = &slm_info[device];		stdma_lock( NULL, NULL );	CMDSET_TARG_LUN( slmreqsense_cmd, sip->target, sip->lun );	if (!acsicmd_nodma( slmreqsense_cmd, 0 ) ||		(stat = acsi_getstatus()) < 0)		rv = SLMSTAT_ACSITO;	else		rv = stat & 0x1f;	ENABLE_IRQ();	stdma_release();	return( rv );}static int slm_mode_sense( int device, char *buffer, int abs_flag ){	unsigned char	stat, len;	int				rv = 0;	struct slm		*sip = &slm_info[device];		stdma_lock( NULL, NULL );	CMDSET_TARG_LUN( slmmsense_cmd, sip->target, sip->lun );	slmmsense_cmd[5] = abs_flag ? 0x80 : 0;	if (!acsicmd_nodma( slmmsense_cmd, 0 )) {		rv = SLMSTAT_ACSITO;		goto the_end;	}	if (!acsi_extstatus( &stat, 1 )) {		acsi_end_extstatus();		rv = SLMSTAT_ACSITO;		goto the_end;	}		if (!acsi_extstatus( &len, 1 )) {		acsi_end_extstatus();		rv = SLMSTAT_ACSITO;		goto the_end;	}	buffer[0] = len;	if (!acsi_extstatus( buffer+1, len )) {		acsi_end_extstatus();		rv = SLMSTAT_ACSITO;		goto the_end;	}		acsi_end_extstatus();	rv = stat & 0x1f;  the_end:	ENABLE_IRQ();	stdma_release();	return( rv );}#if 0/* currently unused */static int slm_mode_select( int device, char *buffer, int len,							int default_flag ){	int			stat, rv;	struct slm	*sip = &slm_info[device];		stdma_lock( NULL, NULL );	CMDSET_TARG_LUN( slmmselect_cmd, sip->target, sip->lun );	slmmselect_cmd[5] = default_flag ? 0x80 : 0;	if (!acsicmd_nodma( slmmselect_cmd, 0 )) {		rv = SLMSTAT_ACSITO;		goto the_end;	}	if (!default_flag) {		unsigned char c = len;		if (!acsi_extcmd( &c, 1 )) {			rv = SLMSTAT_ACSITO;			goto the_end;		}		if (!acsi_extcmd( buffer, len )) {			rv = SLMSTAT_ACSITO;			goto the_end;		}	}		stat = acsi_getstatus();	rv = (stat < 0 ? SLMSTAT_ACSITO : stat);  the_end:	ENABLE_IRQ();	stdma_release();	return( rv );}#endifstatic int slm_get_pagesize( int device, int *w, int *h ){	char	buf[256];	int		stat;		stat = slm_mode_sense( device, buf, 0 );	ENABLE_IRQ();	stdma_release();	if (stat != SLMSTAT_OK)		return( -EIO );	*w = (buf[3] << 8) | buf[4];	*h = (buf[1] << 8) | buf[2];	return( 0 );}/* ---------------------------------------------------------------------- *//*								Initialization							  */int attach_slm( int target, int lun ){	static int	did_register;	int			len;	if (N_SLM_Printers >= MAX_SLM) {		printk( KERN_WARNING "Too much SLMs\n" );		return( 0 );	}		/* do an INQUIRY */	udelay(100);	CMDSET_TARG_LUN( slminquiry_cmd, target, lun );	if (!acsicmd_nodma( slminquiry_cmd, 0 )) {	  inq_timeout:		printk( KERN_ERR "SLM inquiry command timed out.\n" );	  inq_fail:		acsi_end_extstatus();		return( 0 );	}	/* read status and header of return data */	if (!acsi_extstatus( SLMBuffer, 6 ))		goto inq_timeout;	if (SLMBuffer[1] != 2) { /* device type == printer? */		printk( KERN_ERR "SLM inquiry returned device type != printer\n" );		goto inq_fail;	}	len = SLMBuffer[5];		/* read id string */	if (!acsi_extstatus( SLMBuffer, len ))		goto inq_timeout;	acsi_end_extstatus();	SLMBuffer[len] = 0;	if (!did_register) {		did_register = 1;	}	slm_info[N_SLM_Printers].target = target;	slm_info[N_SLM_Printers].lun    = lun;	atomic_set(&slm_info[N_SLM_Printers].wr_ok, 1 ); 	atomic_set(&slm_info[N_SLM_Printers].rd_ok, 1 );		printk( KERN_INFO "  Printer: %s\n", SLMBuffer );	printk( KERN_INFO "Detected slm%d at id %d lun %d\n",			N_SLM_Printers, target, lun );	N_SLM_Printers++;	return( 1 );}int slm_init( void ){	int i;	if (register_chrdev( ACSI_MAJOR, "slm", &slm_fops )) {		printk( KERN_ERR "Unable to get major %d for ACSI SLM\n", ACSI_MAJOR );		return -EBUSY;	}		if (!(SLMBuffer = atari_stram_alloc( SLM_BUFFER_SIZE, "SLM" ))) {		printk( KERN_ERR "Unable to get SLM ST-Ram buffer.\n" );		unregister_chrdev( ACSI_MAJOR, "slm" );		return -ENOMEM;	}	BufferP = SLMBuffer;	SLMState = IDLE;		devfs_mk_dir("slm");	for (i = 0; i < MAX_SLM; i++) {		devfs_mk_cdev(MKDEV(ACSI_MAJOR, i),				S_IFCHR|S_IRUSR|S_IWUSR, "slm/%d", i);	}	return 0;}#ifdef MODULE/* from acsi.c */void acsi_attach_SLMs( int (*attach_func)( int, int ) );int init_module(void){	int err;	if ((err = slm_init()))		return( err );	/* This calls attach_slm() for every target/lun where acsi.c detected a	 * printer */	acsi_attach_SLMs( attach_slm );	return( 0 );}void cleanup_module(void){	int i;	for (i = 0; i < MAX_SLM; i++)		devfs_remove("slm/%d", i);	devfs_remove("slm");	if (unregister_chrdev( ACSI_MAJOR, "slm" ) != 0)		printk( KERN_ERR "acsi_slm: cleanup_module failed\n");	atari_stram_free( SLMBuffer );}#endif

⌨️ 快捷键说明

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