📄 acsi_slm.c
字号:
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 + -