diff options
Diffstat (limited to 'drivers')
97 files changed, 3248 insertions, 3606 deletions
diff --git a/drivers/atm/Kconfig b/drivers/atm/Kconfig index 5b4fab2..bb4ae628 100644 --- a/drivers/atm/Kconfig +++ b/drivers/atm/Kconfig @@ -142,7 +142,7 @@ config ATM_ENI_BURST_RX_2W config ATM_FIRESTREAM tristate "Fujitsu FireStream (FS50/FS155) " - depends on PCI + depends on PCI && VIRT_TO_BUS help Driver for the Fujitsu FireStream 155 (MB86697) and FireStream 50 (MB86695) ATM PCI chips. @@ -152,7 +152,7 @@ config ATM_FIRESTREAM config ATM_ZATM tristate "ZeitNet ZN1221/ZN1225" - depends on PCI + depends on PCI && VIRT_TO_BUS help Driver for the ZeitNet ZN1221 (MMF) and ZN1225 (UTP-5) 155 Mbps ATM adapters. @@ -240,7 +240,7 @@ config ATM_IDT77252_USE_SUNI config ATM_AMBASSADOR tristate "Madge Ambassador (Collage PCI 155 Server)" - depends on PCI + depends on PCI && VIRT_TO_BUS select BITREVERSE help This is a driver for ATMizer based ATM card produced by Madge @@ -265,7 +265,7 @@ config ATM_AMBASSADOR_DEBUG config ATM_HORIZON tristate "Madge Horizon [Ultra] (Collage PCI 25 and Collage PCI 155 Client)" - depends on PCI + depends on PCI && VIRT_TO_BUS help This is a driver for the Horizon chipset ATM adapter cards once produced by Madge Networks Ltd. Say Y (or M to compile as a module diff --git a/drivers/auxdisplay/Kconfig b/drivers/auxdisplay/Kconfig index ea4fe3e..de2fcce 100644 --- a/drivers/auxdisplay/Kconfig +++ b/drivers/auxdisplay/Kconfig @@ -5,8 +5,11 @@ # Auxiliary display drivers configuration. # -menu "Auxiliary Display support" +menuconfig AUXDISPLAY depends on PARPORT + bool "Auxiliary Display support" + +if AUXDISPLAY && PARPORT config KS0108 tristate "KS0108 LCD Controller" @@ -111,4 +114,5 @@ config CFAG12864B_RATE If you compile this as a module, you can still override this value using the module parameters. -endmenu + +endif # AUXDISPLAY diff --git a/drivers/base/dmapool.c b/drivers/base/dmapool.c index 91970e9..7647abf 100644 --- a/drivers/base/dmapool.c +++ b/drivers/base/dmapool.c @@ -127,7 +127,7 @@ dma_pool_create (const char *name, struct device *dev, } else if (allocation < size) return NULL; - if (!(retval = kmalloc (sizeof *retval, GFP_KERNEL))) + if (!(retval = kmalloc_node (sizeof *retval, GFP_KERNEL, dev_to_node(dev)))) return retval; strlcpy (retval->name, name, sizeof retval->name); diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig index 6e23af1..c5a6157 100644 --- a/drivers/block/Kconfig +++ b/drivers/block/Kconfig @@ -59,17 +59,6 @@ config AMIGA_Z2RAM To compile this driver as a module, choose M here: the module will be called z2ram. -config ATARI_SLM - tristate "Atari SLM laser printer support" - depends on ATARI - help - If you have an Atari SLM laser printer, say Y to include support for - it in the kernel. Otherwise, say N. This driver is also available as - a module ( = code which can be inserted in and removed from the - running kernel whenever you want). The module will be called - acsi_slm. Be warned: the driver needs much ST-RAM and can cause - problems due to that fact! - config BLK_DEV_XD tristate "XT hard disk support" depends on ISA && ISA_DMA_API @@ -113,7 +102,7 @@ source "drivers/block/paride/Kconfig" config BLK_CPQ_DA tristate "Compaq SMART2 support" - depends on PCI + depends on PCI && VIRT_TO_BUS help This is the driver for Compaq Smart Array controllers. Everyone using these boards should say Y here. See the file @@ -423,6 +412,13 @@ config ATA_OVER_ETH This driver provides Support for ATA over Ethernet block devices like the Coraid EtherDrive (R) Storage Blade. +config SUNVDC + tristate "Sun Virtual Disk Client support" + depends on SUN_LDOMS + help + Support for virtual disk devices as a client under Sun + Logical Domains. + source "drivers/s390/block/Kconfig" endif # BLK_DEV diff --git a/drivers/block/Makefile b/drivers/block/Makefile index e5f98ac..7926be8 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -9,7 +9,6 @@ obj-$(CONFIG_MAC_FLOPPY) += swim3.o obj-$(CONFIG_BLK_DEV_FD) += floppy.o obj-$(CONFIG_AMIGA_FLOPPY) += amiflop.o obj-$(CONFIG_ATARI_FLOPPY) += ataflop.o -obj-$(CONFIG_ATARI_SLM) += acsi_slm.o obj-$(CONFIG_AMIGA_Z2RAM) += z2ram.o obj-$(CONFIG_BLK_DEV_RAM) += rd.o obj-$(CONFIG_BLK_DEV_LOOP) += loop.o @@ -19,6 +18,7 @@ obj-$(CONFIG_BLK_CPQ_DA) += cpqarray.o obj-$(CONFIG_BLK_CPQ_CISS_DA) += cciss.o obj-$(CONFIG_BLK_DEV_DAC960) += DAC960.o obj-$(CONFIG_CDROM_PKTCDVD) += pktcdvd.o +obj-$(CONFIG_SUNVDC) += sunvdc.o obj-$(CONFIG_BLK_DEV_UMEM) += umem.o obj-$(CONFIG_BLK_DEV_NBD) += nbd.o diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c deleted file mode 100644 index 1d9d9b4..0000000 --- a/drivers/block/acsi_slm.c +++ /dev/null @@ -1,1032 +0,0 @@ -/* - * acsi_slm.c -- Device driver for the Atari SLM laser printer - * - * Copyright 1995 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de> - * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file COPYING in the main directory of this archive for - * more details. - * - */ - -/* - -Notes: - -The major number for SLM printers is 28 (like ACSI), but as a character -device, not block device. The minor number is the number of the printer (if -you have more than one SLM; currently max. 2 (#define-constant) SLMs are -supported). The device can be opened for reading and writing. If reading it, -you get some status infos (MODE SENSE data). Writing mode is used for the data -to be printed. Some ioctls allow to get the printer status and to tune printer -modes and some internal variables. - -A special problem of the SLM driver is the timing and thus the buffering of -the print data. The problem is that all the data for one page must be present -in memory when printing starts, else --when swapping occurs-- the timing could -not be guaranteed. There are several ways to assure this: - - 1) Reserve a buffer of 1196k (maximum page size) statically by - atari_stram_alloc(). The data are collected there until they're complete, - and then printing starts. Since the buffer is reserved, no further - considerations about memory and swapping are needed. So this is the - simplest method, but it needs a lot of memory for just the SLM. - - An striking advantage of this method is (supposed the SLM_CONT_CNT_REPROG - method works, see there), that there are no timing problems with the DMA - anymore. - - 2) The other method would be to reserve the buffer dynamically each time - printing is required. I could think of looking at mem_map where the - largest unallocted ST-RAM area is, taking the area, and then extending it - by swapping out the neighbored pages, until the needed size is reached. - This requires some mm hacking, but seems possible. The only obstacle could - be pages that cannot be swapped out (reserved pages)... - - 3) Another possibility would be to leave the real data in user space and to - work with two dribble buffers of about 32k in the driver: While the one - buffer is DMAed to the SLM, the other can be filled with new data. But - to keep the timing, that requires that the user data remain in memory and - are not swapped out. Requires mm hacking, too, but maybe not so bad as - method 2). - -*/ - -#include <linux/module.h> - -#include <linux/errno.h> -#include <linux/sched.h> -#include <linux/timer.h> -#include <linux/fs.h> -#include <linux/major.h> -#include <linux/kernel.h> -#include <linux/delay.h> -#include <linux/interrupt.h> -#include <linux/time.h> -#include <linux/mm.h> -#include <linux/slab.h> - -#include <asm/pgtable.h> -#include <asm/system.h> -#include <asm/uaccess.h> -#include <asm/atarihw.h> -#include <asm/atariints.h> -#include <asm/atari_acsi.h> -#include <asm/atari_stdma.h> -#include <asm/atari_stram.h> -#include <asm/atari_SLM.h> - - -#undef DEBUG - -/* Define this if the page data are continuous in physical memory. That - * requires less reprogramming of the ST-DMA */ -#define SLM_CONTINUOUS_DMA - -/* Use continuous reprogramming of the ST-DMA counter register. This is - * --strictly speaking-- not allowed, Atari recommends not to look at the - * counter register while a DMA is going on. But I don't know if that applies - * only for reading the register, or also writing to it. Writing only works - * fine for me... The advantage is that the timing becomes absolutely - * uncritical: Just update each, say 200ms, the counter reg to its maximum, - * and the DMA will work until the status byte interrupt occurs. - */ -#define SLM_CONT_CNT_REPROG - -#define CMDSET_TARG_LUN(cmd,targ,lun) \ - do { \ - cmd[0] = (cmd[0] & ~0xe0) | (targ)<<5; \ - cmd[1] = (cmd[1] & ~0xe0) | (lun)<<5; \ - } while(0) - -#define START_TIMER(to) mod_timer(&slm_timer, jiffies + (to)) -#define STOP_TIMER() del_timer(&slm_timer) - - -static char slmreqsense_cmd[6] = { 0x03, 0, 0, 0, 0, 0 }; -static char slmprint_cmd[6] = { 0x0a, 0, 0, 0, 0, 0 }; -static char slminquiry_cmd[6] = { 0x12, 0, 0, 0, 0, 0x80 }; -static char slmmsense_cmd[6] = { 0x1a, 0, 0, 0, 255, 0 }; -#if 0 -static char slmmselect_cmd[6] = { 0x15, 0, 0, 0, 0, 0 }; -#endif - - -#define MAX_SLM 2 - -static struct slm { - unsigned target; /* target number */ - unsigned lun; /* LUN in target controller */ - atomic_t wr_ok; /* set to 0 if output part busy */ - atomic_t rd_ok; /* set to 0 if status part busy */ -} slm_info[MAX_SLM]; - -int N_SLM_Printers = 0; - -/* printer buffer */ -static unsigned char *SLMBuffer; /* start of buffer */ -static unsigned char *BufferP; /* current position in buffer */ -static int BufferSize; /* length of buffer for page size */ - -typedef enum { IDLE, FILLING, PRINTING } SLMSTATE; -static SLMSTATE SLMState; -static int SLMBufOwner; /* SLM# currently using the buffer */ - -/* DMA variables */ -#ifndef SLM_CONT_CNT_REPROG -static unsigned long SLMCurAddr; /* current base addr of DMA chunk */ -static unsigned long SLMEndAddr; /* expected end addr */ -static unsigned long SLMSliceSize; /* size of one DMA chunk */ -#endif -static int SLMError; - -/* wait queues */ -static DECLARE_WAIT_QUEUE_HEAD(slm_wait); /* waiting for buffer */ -static DECLARE_WAIT_QUEUE_HEAD(print_wait); /* waiting for printing finished */ - -/* status codes */ -#define SLMSTAT_OK 0x00 -#define SLMSTAT_ORNERY 0x02 -#define SLMSTAT_TONER 0x03 -#define SLMSTAT_WARMUP 0x04 -#define SLMSTAT_PAPER 0x05 -#define SLMSTAT_DRUM 0x06 -#define SLMSTAT_INJAM 0x07 -#define SLMSTAT_THRJAM 0x08 -#define SLMSTAT_OUTJAM 0x09 -#define SLMSTAT_COVER 0x0a -#define SLMSTAT_FUSER 0x0b -#define SLMSTAT_IMAGER 0x0c -#define SLMSTAT_MOTOR 0x0d -#define SLMSTAT_VIDEO 0x0e -#define SLMSTAT_SYSTO 0x10 -#define SLMSTAT_OPCODE 0x12 -#define SLMSTAT_DEVNUM 0x15 -#define SLMSTAT_PARAM 0x1a -#define SLMSTAT_ACSITO 0x1b /* driver defined */ -#define SLMSTAT_NOTALL 0x1c /* driver defined */ - -static char *SLMErrors[] = { - /* 0x00 */ "OK and ready", - /* 0x01 */ NULL, - /* 0x02 */ "ornery printer", - /* 0x03 */ "toner empty", - /* 0x04 */ "warming up", - /* 0x05 */ "paper empty", - /* 0x06 */ "drum empty", - /* 0x07 */ "input jam", - /* 0x08 */ "through jam", - /* 0x09 */ "output jam", - /* 0x0a */ "cover open", - /* 0x0b */ "fuser malfunction", - /* 0x0c */ "imager malfunction", - /* 0x0d */ "motor malfunction", - /* 0x0e */ "video malfunction", - /* 0x0f */ NULL, - /* 0x10 */ "printer system timeout", - /* 0x11 */ NULL, - /* 0x12 */ "invalid operation code", - /* 0x13 */ NULL, - /* 0x14 */ NULL, - /* 0x15 */ "invalid device number", - /* 0x16 */ NULL, - /* 0x17 */ NULL, - /* 0x18 */ NULL, - /* 0x19 */ NULL, - /* 0x1a */ "invalid parameter list", - /* 0x1b */ "ACSI timeout", - /* 0x1c */ "not all printed" -}; - -#define N_ERRORS (sizeof(SLMErrors)/sizeof(*SLMErrors)) - -/* real (driver caused) error? */ -#define IS_REAL_ERROR(x) (x > 0x10) - - -static struct { - char *name; - int w, h; -} StdPageSize[] = { - { "Letter", 2400, 3180 }, - { "Legal", 2400, 4080 }, - { "A4", 2336, 3386 }, - { "B5", 2016, 2914 } -}; - -#define N_STD_SIZES (sizeof(StdPageSize)/sizeof(*StdPageSize)) - -#define SLM_BUFFER_SIZE (2336*3386/8) /* A4 for now */ -#define SLM_DMA_AMOUNT 255 /* #sectors to program the DMA for */ - -#ifdef SLM_CONTINUOUS_DMA -# define SLM_DMA_INT_OFFSET 0 /* DMA goes until seccnt 0, no offs */ -# define SLM_DMA_END_OFFSET 32 /* 32 Byte ST-DMA FIFO */ -# define SLM_SLICE_SIZE(w) (255*512) -#else -# define SLM_DMA_INT_OFFSET 32 /* 32 Byte ST-DMA FIFO */ -# define SLM_DMA_END_OFFSET 32 /* 32 Byte ST-DMA FIFO */ -# define SLM_SLICE_SIZE(w) ((254*512)/(w/8)*(w/8)) -#endif - -/* calculate the number of jiffies to wait for 'n' bytes */ -#ifdef SLM_CONT_CNT_REPROG -#define DMA_TIME_FOR(n) 50 -#define DMA_STARTUP_TIME 0 -#else -#define DMA_TIME_FOR(n) (n/1400-1) -#define DMA_STARTUP_TIME 650 -#endif - -/***************************** Prototypes *****************************/ - -static char *slm_errstr( int stat ); -static int slm_getstats( char *buffer, int device ); -static ssize_t slm_read( struct file* file, char *buf, size_t count, loff_t - *ppos ); -static void start_print( int device ); -static irqreturn_t slm_interrupt(int irc, void *data); -static void slm_test_ready( unsigned long dummy ); -static void set_dma_addr( unsigned long paddr ); -static unsigned long get_dma_addr( void ); -static ssize_t slm_write( struct file *file, const char *buf, size_t count, - loff_t *ppos ); -static int slm_ioctl( struct inode *inode, struct file *file, unsigned int - cmd, unsigned long arg ); -static int slm_open( struct inode *inode, struct file *file ); -static int slm_release( struct inode *inode, struct file *file ); -static int slm_req_sense( int device ); -static int slm_mode_sense( int device, char *buffer, int abs_flag ); -#if 0 -static int slm_mode_select( int device, char *buffer, int len, int - default_flag ); -#endif -static int slm_get_pagesize( int device, int *w, int *h ); - -/************************* End of Prototypes **************************/ - - -static DEFINE_TIMER(slm_timer, slm_test_ready, 0, 0); - -static const struct file_operations slm_fops = { - .owner = THIS_MODULE, - .read = slm_read, - .write = slm_write, - .ioctl = slm_ioctl, - .open = slm_open, - .release = slm_release, -}; - - -/* ---------------------------------------------------------------------- */ -/* Status Functions */ - - -static char *slm_errstr( int stat ) - -{ char *p; - static char str[22]; - - stat &= 0x1f; - if (stat >= 0 && stat < N_ERRORS && (p = SLMErrors[stat])) - return( p ); - sprintf( str, "unknown status 0x%02x", stat ); - return( str ); -} - - -static int slm_getstats( char *buffer, int device ) - -{ int len = 0, stat, i, w, h; - unsigned char buf[256]; - - stat = slm_mode_sense( device, buf, 0 ); - if (IS_REAL_ERROR(stat)) - return( -EIO ); - -#define SHORTDATA(i) ((buf[i] << 8) | buf[i+1]) -#define BOOLDATA(i,mask) ((buf[i] & mask) ? "on" : "off") - - w = SHORTDATA( 3 ); - h = SHORTDATA( 1 ); - - len += sprintf( buffer+len, "Status\t\t%s\n", - slm_errstr( stat ) ); - len += sprintf( buffer+len, "Page Size\t%dx%d", - w, h ); - - for( i = 0; i < N_STD_SIZES; ++i ) { - if (w == StdPageSize[i].w && h == StdPageSize[i].h) - break; - } - if (i < N_STD_SIZES) - len += sprintf( buffer+len, " (%s)", StdPageSize[i].name ); - buffer[len++] = '\n'; - - len += sprintf( buffer+len, "Top/Left Margin\t%d/%d\n", - SHORTDATA( 5 ), SHORTDATA( 7 ) ); - len += sprintf( buffer+len, "Manual Feed\t%s\n", - BOOLDATA( 9, 0x01 ) ); - len += sprintf( buffer+len, "Input Select\t%d\n", - (buf[9] >> 1) & 7 ); - len += sprintf( buffer+len, "Auto Select\t%s\n", - BOOLDATA( 9, 0x10 ) ); - len += sprintf( buffer+len, "Prefeed Paper\t%s\n", - BOOLDATA( 9, 0x20 ) ); - len += sprintf( buffer+len, "Thick Pixels\t%s\n", - BOOLDATA( 9, 0x40 ) ); - len += sprintf( buffer+len, "H/V Resol.\t%d/%d dpi\n", - SHORTDATA( 12 ), SHORTDATA( 10 ) ); - len += sprintf( buffer+len, "System Timeout\t%d\n", - buf[14] ); - len += sprintf( buffer+len, "Scan Time\t%d\n", - SHORTDATA( 15 ) ); - len += sprintf( buffer+len, "Page Count\t%d\n", - SHORTDATA( 17 ) ); - len += sprintf( buffer+len, "In/Out Cap.\t%d/%d\n", - SHORTDATA( 19 ), SHORTDATA( 21 ) ); - len += sprintf( buffer+len, "Stagger Output\t%s\n", - BOOLDATA( 23, 0x01 ) ); - len += sprintf( buffer+len, "Output Select\t%d\n", - (buf[23] >> 1) & 7 ); - len += sprintf( buffer+len, "Duplex Print\t%s\n", - BOOLDATA( 23, 0x10 ) ); - len += sprintf( buffer+len, "Color Sep.\t%s\n", - BOOLDATA( 23, 0x20 ) ); - - return( len ); -} - - -static ssize_t slm_read( struct file *file, char *buf, size_t count, - loff_t *ppos ) - -{ - struct inode *node = file->f_path.dentry->d_inode; - unsigned long page; - int length; - int end; - - if (!(page = __get_free_page( GFP_KERNEL ))) - return( -ENOMEM ); - - length = slm_getstats( (char *)page, iminor(node) ); - if (length < 0) { - count = length; - goto out; - } - if (file->f_pos >= length) { - count = 0; - goto out; - } - if (count + file->f_pos > length) - count = length - file->f_pos; - end = count + file->f_pos; - if (copy_to_user(buf, (char *)page + file->f_pos, count)) { - count = -EFAULT; - goto out; - } - file->f_pos = end; -out: free_page( page ); - return( count ); -} - - -/* ---------------------------------------------------------------------- */ -/* Printing */ - - -static void start_print( int device ) - -{ struct slm *sip = &slm_info[device]; - unsigned char *cmd; - unsigned long paddr; - int i; - - stdma_lock( slm_interrupt, NULL ); - - CMDSET_TARG_LUN( slmprint_cmd, sip->target, sip->lun ); - cmd = slmprint_cmd; - paddr = virt_to_phys( SLMBuffer ); - dma_cache_maintenance( paddr, virt_to_phys(BufferP)-paddr, 1 ); - DISABLE_IRQ(); - - /* Low on A1 */ - dma_wd.dma_mode_status = 0x88; - MFPDELAY(); - - /* send the command bytes except the last */ - for( i = 0; i < 5; ++i ) { - DMA_LONG_WRITE( *cmd++, 0x8a ); - udelay(20); - if (!acsi_wait_for_IRQ( HZ/2 )) { - SLMError = 1; - return; /* timeout */ - } - } - /* last command byte */ - DMA_LONG_WRITE( *cmd++, 0x82 ); - MFPDELAY(); - /* set DMA address */ - set_dma_addr( paddr ); - /* program DMA for write and select sector counter reg */ - dma_wd.dma_mode_status = 0x192; - MFPDELAY(); - /* program for 255*512 bytes and start DMA */ - DMA_LONG_WRITE( SLM_DMA_AMOUNT, 0x112 ); - -#ifndef SLM_CONT_CNT_REPROG - SLMCurAddr = paddr; - SLMEndAddr = paddr + SLMSliceSize + SLM_DMA_INT_OFFSET; -#endif - START_TIMER( DMA_STARTUP_TIME + DMA_TIME_FOR( SLMSliceSize )); -#if !defined(SLM_CONT_CNT_REPROG) && defined(DEBUG) - printk( "SLM: CurAddr=%#lx EndAddr=%#lx timer=%ld\n", - SLMCurAddr, SLMEndAddr, DMA_TIME_FOR( SLMSliceSize ) ); -#endif - - ENABLE_IRQ(); -} - - -/* Only called when an error happened or at the end of a page */ - -static irqreturn_t slm_interrupt(int irc, void *data) - -{ unsigned long addr; - int stat; - - STOP_TIMER(); - addr = get_dma_addr(); - stat = acsi_getstatus(); - SLMError = (stat < 0) ? SLMSTAT_ACSITO : - (addr < virt_to_phys(BufferP)) ? SLMSTAT_NOTALL : - stat; - - dma_wd.dma_mode_status = 0x80; - MFPDELAY(); -#ifdef DEBUG - printk( "SLM: interrupt, addr=%#lx, error=%d\n", addr, SLMError ); -#endif - - wake_up( &print_wait ); - stdma_release(); - ENABLE_IRQ(); - return IRQ_HANDLED; -} - - -static void slm_test_ready( unsigned long dummy ) - -{ -#ifdef SLM_CONT_CNT_REPROG - /* program for 255*512 bytes again */ - dma_wd.fdc_acces_seccount = SLM_DMA_AMOUNT; - START_TIMER( DMA_TIME_FOR(0) ); -#ifdef DEBUG - printk( "SLM: reprogramming timer for %d jiffies, addr=%#lx\n", - DMA_TIME_FOR(0), get_dma_addr() ); -#endif - -#else /* !SLM_CONT_CNT_REPROG */ - - unsigned long flags, addr; - int d, ti; -#ifdef DEBUG - struct timeval start_tm, end_tm; - int did_wait = 0; -#endif - - local_irq_save(flags); - - addr = get_dma_addr(); - if ((d = SLMEndAddr - addr) > 0) { - local_irq_restore(flags); - - /* slice not yet finished, decide whether to start another timer or to - * busy-wait */ - ti = DMA_TIME_FOR( d ); - if (ti > 0) { -#ifdef DEBUG - printk( "SLM: reprogramming timer for %d jiffies, rest %d bytes\n", - ti, d ); -#endif - START_TIMER( ti ); - return; - } - /* wait for desired end address to be reached */ -#ifdef DEBUG - do_gettimeofday( &start_tm ); - 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_path.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 ); -} -#endif - - -static 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; - - 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) -{ - if (unregister_chrdev( ACSI_MAJOR, "slm" ) != 0) - printk( KERN_ERR "acsi_slm: cleanup_module failed\n"); - atari_stram_free( SLMBuffer ); -} -#endif diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index c575fb1..c129510 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -122,17 +122,12 @@ static int sock_xmit(struct socket *sock, int send, void *buf, int size, int result; struct msghdr msg; struct kvec iov; - unsigned long flags; - sigset_t oldset; + sigset_t blocked, oldset; /* Allow interception of SIGKILL only * Don't allow other signals to interrupt the transmission */ - spin_lock_irqsave(¤t->sighand->siglock, flags); - oldset = current->blocked; - sigfillset(¤t->blocked); - sigdelsetmask(¤t->blocked, sigmask(SIGKILL)); - recalc_sigpending(); - spin_unlock_irqrestore(¤t->sighand->siglock, flags); + siginitsetinv(&blocked, sigmask(SIGKILL)); + sigprocmask(SIG_SETMASK, &blocked, &oldset); do { sock->sk->sk_allocation = GFP_NOIO; @@ -151,11 +146,9 @@ static int sock_xmit(struct socket *sock, int send, void *buf, int size, if (signal_pending(current)) { siginfo_t info; - spin_lock_irqsave(¤t->sighand->siglock, flags); printk(KERN_WARNING "nbd (pid %d: %s) got signal %d\n", - current->pid, current->comm, - dequeue_signal(current, ¤t->blocked, &info)); - spin_unlock_irqrestore(¤t->sighand->siglock, flags); + current->pid, current->comm, + dequeue_signal_lock(current, ¤t->blocked, &info)); result = -EINTR; break; } @@ -169,10 +162,7 @@ static int sock_xmit(struct socket *sock, int send, void *buf, int size, buf += result; } while (size > 0); - spin_lock_irqsave(¤t->sighand->siglock, flags); - current->blocked = oldset; - recalc_sigpending(); - spin_unlock_irqrestore(¤t->sighand->siglock, flags); + sigprocmask(SIG_SETMASK, &oldset, NULL); return result; } diff --git a/drivers/block/pktcdvd.c b/drivers/block/pktcdvd.c index ce64e86..7c294a4 100644 --- a/drivers/block/pktcdvd.c +++ b/drivers/block/pktcdvd.c @@ -1652,9 +1652,6 @@ static int kcdrwd(void *foobar) } } - if (signal_pending(current)) { - flush_signals(current); - } if (kthread_should_stop()) break; } diff --git a/drivers/block/sunvdc.c b/drivers/block/sunvdc.c new file mode 100644 index 0000000..0f5e3ca --- /dev/null +++ b/drivers/block/sunvdc.c @@ -0,0 +1,972 @@ +/* sunvdc.c: Sun LDOM Virtual Disk Client. + * + * Copyright (C) 2007 David S. Miller <davem@davemloft.net> + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/blkdev.h> +#include <linux/hdreg.h> +#include <linux/genhd.h> +#include <linux/slab.h> +#include <linux/spinlock.h> +#include <linux/completion.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/list.h> + +#include <asm/vio.h> +#include <asm/ldc.h> + +#define DRV_MODULE_NAME "sunvdc" +#define PFX DRV_MODULE_NAME ": " +#define DRV_MODULE_VERSION "1.0" +#define DRV_MODULE_RELDATE "June 25, 2007" + +static char version[] __devinitdata = + DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; +MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); +MODULE_DESCRIPTION("Sun LDOM virtual disk client driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_MODULE_VERSION); + +#define VDC_TX_RING_SIZE 256 + +#define WAITING_FOR_LINK_UP 0x01 +#define WAITING_FOR_TX_SPACE 0x02 +#define WAITING_FOR_GEN_CMD 0x04 +#define WAITING_FOR_ANY -1 + +struct vdc_req_entry { + struct request *req; +}; + +struct vdc_port { + struct vio_driver_state vio; + + struct vdc *vp; + + struct gendisk *disk; + + struct vdc_completion *cmp; + + u64 req_id; + u64 seq; + struct vdc_req_entry rq_arr[VDC_TX_RING_SIZE]; + + unsigned long ring_cookies; + + u64 max_xfer_size; + u32 vdisk_block_size; + + /* The server fills these in for us in the disk attribute + * ACK packet. + */ + u64 operations; + u32 vdisk_size; + u8 vdisk_type; + u8 dev_no; + + char disk_name[32]; + + struct vio_disk_geom geom; + struct vio_disk_vtoc label; + + struct list_head list; +}; + +static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio) +{ + return container_of(vio, struct vdc_port, vio); +} + +struct vdc { + /* Protects prot_list. */ + spinlock_t lock; + + struct vio_dev *dev; + + struct list_head port_list; +}; + +/* Ordered from largest major to lowest */ +static struct vio_version vdc_versions[] = { + { .major = 1, .minor = 0 }, +}; + +#define VDCBLK_NAME "vdisk" +static int vdc_major; +#define PARTITION_SHIFT 3 + +static inline u32 vdc_tx_dring_avail(struct vio_dring_state *dr) +{ + return vio_dring_avail(dr, VDC_TX_RING_SIZE); +} + +static int vdc_getgeo(struct block_device *bdev, struct hd_geometry *geo) +{ + struct gendisk *disk = bdev->bd_disk; + struct vdc_port *port = disk->private_data; + + geo->heads = (u8) port->geom.num_hd; + geo->sectors = (u8) port->geom.num_sec; + geo->cylinders = port->geom.num_cyl; + + return 0; +} + +static struct block_device_operations vdc_fops = { + .owner = THIS_MODULE, + .getgeo = vdc_getgeo, +}; + +static void vdc_finish(struct vio_driver_state *vio, int err, int waiting_for) +{ + if (vio->cmp && + (waiting_for == -1 || + vio->cmp->waiting_for == waiting_for)) { + vio->cmp->err = err; + complete(&vio->cmp->com); + vio->cmp = NULL; + } +} + +static void vdc_handshake_complete(struct vio_driver_state *vio) +{ + vdc_finish(vio, 0, WAITING_FOR_LINK_UP); +} + +static int vdc_handle_unknown(struct vdc_port *port, void *arg) +{ + struct vio_msg_tag *pkt = arg; + + printk(KERN_ERR PFX "Received unknown msg [%02x:%02x:%04x:%08x]\n", + pkt->type, pkt->stype, pkt->stype_env, pkt->sid); + printk(KERN_ERR PFX "Resetting connection.\n"); + + ldc_disconnect(port->vio.lp); + + return -ECONNRESET; +} + +static int vdc_send_attr(struct vio_driver_state *vio) +{ + struct vdc_port *port = to_vdc_port(vio); + struct vio_disk_attr_info pkt; + + memset(&pkt, 0, sizeof(pkt)); + + pkt.tag.type = VIO_TYPE_CTRL; + pkt.tag.stype = VIO_SUBTYPE_INFO; + pkt.tag.stype_env = VIO_ATTR_INFO; + pkt.tag.sid = vio_send_sid(vio); + + pkt.xfer_mode = VIO_DRING_MODE; + pkt.vdisk_block_size = port->vdisk_block_size; + pkt.max_xfer_size = port->max_xfer_size; + + viodbg(HS, "SEND ATTR xfer_mode[0x%x] blksz[%u] max_xfer[%lu]\n", + pkt.xfer_mode, pkt.vdisk_block_size, pkt.max_xfer_size); + + return vio_ldc_send(&port->vio, &pkt, sizeof(pkt)); +} + +static int vdc_handle_attr(struct vio_driver_state *vio, void *arg) +{ + struct vdc_port *port = to_vdc_port(vio); + struct vio_disk_attr_info *pkt = arg; + + viodbg(HS, "GOT ATTR stype[0x%x] ops[%lx] disk_size[%lu] disk_type[%x] " + "xfer_mode[0x%x] blksz[%u] max_xfer[%lu]\n", + pkt->tag.stype, pkt->operations, + pkt->vdisk_size, pkt->vdisk_type, + pkt->xfer_mode, pkt->vdisk_block_size, + pkt->max_xfer_size); + + if (pkt->tag.stype == VIO_SUBTYPE_ACK) { + switch (pkt->vdisk_type) { + case VD_DISK_TYPE_DISK: + case VD_DISK_TYPE_SLICE: + break; + + default: + printk(KERN_ERR PFX "%s: Bogus vdisk_type 0x%x\n", + vio->name, pkt->vdisk_type); + return -ECONNRESET; + } + + if (pkt->vdisk_block_size > port->vdisk_block_size) { + printk(KERN_ERR PFX "%s: BLOCK size increased " + "%u --> %u\n", + vio->name, + port->vdisk_block_size, pkt->vdisk_block_size); + return -ECONNRESET; + } + + port->operations = pkt->operations; + port->vdisk_size = pkt->vdisk_size; + port->vdisk_type = pkt->vdisk_type; + if (pkt->max_xfer_size < port->max_xfer_size) + port->max_xfer_size = pkt->max_xfer_size; + port->vdisk_block_size = pkt->vdisk_block_size; + return 0; + } else { + printk(KERN_ERR PFX "%s: Attribute NACK\n", vio->name); + + return -ECONNRESET; + } +} + +static void vdc_end_special(struct vdc_port *port, struct vio_disk_desc *desc) +{ + int err = desc->status; + + vdc_finish(&port->vio, -err, WAITING_FOR_GEN_CMD); +} + +static void vdc_end_request(struct request *req, int uptodate, int num_sectors) +{ + if (end_that_request_first(req, uptodate, num_sectors)) + return; + add_disk_randomness(req->rq_disk); + end_that_request_last(req, uptodate); +} + +static void vdc_end_one(struct vdc_port *port, struct vio_dring_state *dr, + unsigned int index) +{ + struct vio_disk_desc *desc = vio_dring_entry(dr, index); + struct vdc_req_entry *rqe = &port->rq_arr[index]; + struct request *req; + + if (unlikely(desc->hdr.state != VIO_DESC_DONE)) + return; + + ldc_unmap(port->vio.lp, desc->cookies, desc->ncookies); + desc->hdr.state = VIO_DESC_FREE; + dr->cons = (index + 1) & (VDC_TX_RING_SIZE - 1); + + req = rqe->req; + if (req == NULL) { + vdc_end_special(port, desc); + return; + } + + rqe->req = NULL; + + vdc_end_request(req, !desc->status, desc->size >> 9); + + if (blk_queue_stopped(port->disk->queue)) + blk_start_queue(port->disk->queue); +} + +static int vdc_ack(struct vdc_port *port, void *msgbuf) +{ + struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING]; + struct vio_dring_data *pkt = msgbuf; + + if (unlikely(pkt->dring_ident != dr->ident || + pkt->start_idx != pkt->end_idx || + pkt->start_idx >= VDC_TX_RING_SIZE)) + return 0; + + vdc_end_one(port, dr, pkt->start_idx); + + return 0; +} + +static int vdc_nack(struct vdc_port *port, void *msgbuf) +{ + /* XXX Implement me XXX */ + return 0; +} + +static void vdc_event(void *arg, int event) +{ + struct vdc_port *port = arg; + struct vio_driver_state *vio = &port->vio; + unsigned long flags; + int err; + + spin_lock_irqsave(&vio->lock, flags); + + if (unlikely(event == LDC_EVENT_RESET || + event == LDC_EVENT_UP)) { + vio_link_state_change(vio, event); + spin_unlock_irqrestore(&vio->lock, flags); + return; + } + + if (unlikely(event != LDC_EVENT_DATA_READY)) { + printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event); + spin_unlock_irqrestore(&vio->lock, flags); + return; + } + + err = 0; + while (1) { + union { + struct vio_msg_tag tag; + u64 raw[8]; + } msgbuf; + + err = ldc_read(vio->lp, &msgbuf, sizeof(msgbuf)); + if (unlikely(err < 0)) { + if (err == -ECONNRESET) + vio_conn_reset(vio); + break; + } + if (err == 0) + break; + viodbg(DATA, "TAG [%02x:%02x:%04x:%08x]\n", + msgbuf.tag.type, + msgbuf.tag.stype, + msgbuf.tag.stype_env, + msgbuf.tag.sid); + err = vio_validate_sid(vio, &msgbuf.tag); + if (err < 0) + break; + + if (likely(msgbuf.tag.type == VIO_TYPE_DATA)) { + if (msgbuf.tag.stype == VIO_SUBTYPE_ACK) + err = vdc_ack(port, &msgbuf); + else if (msgbuf.tag.stype == VIO_SUBTYPE_NACK) + err = vdc_nack(port, &msgbuf); + else + err = vdc_handle_unknown(port, &msgbuf); + } else if (msgbuf.tag.type == VIO_TYPE_CTRL) { + err = vio_control_pkt_engine(vio, &msgbuf); + } else { + err = vdc_handle_unknown(port, &msgbuf); + } + if (err < 0) + break; + } + if (err < 0) + vdc_finish(&port->vio, err, WAITING_FOR_ANY); + spin_unlock_irqrestore(&vio->lock, flags); +} + +static int __vdc_tx_trigger(struct vdc_port *port) +{ + struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING]; + struct vio_dring_data hdr = { + .tag = { + .type = VIO_TYPE_DATA, + .stype = VIO_SUBTYPE_INFO, + .stype_env = VIO_DRING_DATA, + .sid = vio_send_sid(&port->vio), + }, + .dring_ident = dr->ident, + .start_idx = dr->prod, + .end_idx = dr->prod, + }; + int err, delay; + + hdr.seq = dr->snd_nxt; + delay = 1; + do { + err = vio_ldc_send(&port->vio, &hdr, sizeof(hdr)); + if (err > 0) { + dr->snd_nxt++; + break; + } + udelay(delay); + if ((delay <<= 1) > 128) + delay = 128; + } while (err == -EAGAIN); + + return err; +} + +static int __send_request(struct request *req) +{ + struct vdc_port *port = req->rq_disk->private_data; + struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING]; + struct scatterlist sg[port->ring_cookies]; + struct vdc_req_entry *rqe; + struct vio_disk_desc *desc; + unsigned int map_perm; + int nsg, err, i; + u64 len; + u8 op; + + map_perm = LDC_MAP_SHADOW | LDC_MAP_DIRECT | LDC_MAP_IO; + + if (rq_data_dir(req) == READ) { + map_perm |= LDC_MAP_W; + op = VD_OP_BREAD; + } else { + map_perm |= LDC_MAP_R; + op = VD_OP_BWRITE; + } + + nsg = blk_rq_map_sg(req->q, req, sg); + + len = 0; + for (i = 0; i < nsg; i++) + len += sg[i].length; + + if (unlikely(vdc_tx_dring_avail(dr) < 1)) { + blk_stop_queue(port->disk->queue); + err = -ENOMEM; + goto out; + } + + desc = vio_dring_cur(dr); + + err = ldc_map_sg(port->vio.lp, sg, nsg, + desc->cookies, port->ring_cookies, + map_perm); + if (err < 0) { + printk(KERN_ERR PFX "ldc_map_sg() failure, err=%d.\n", err); + return err; + } + + rqe = &port->rq_arr[dr->prod]; + rqe->req = req; + + desc->hdr.ack = VIO_ACK_ENABLE; + desc->req_id = port->req_id; + desc->operation = op; + if (port->vdisk_type == VD_DISK_TYPE_DISK) { + desc->slice = 2; + } else { + desc->slice = 0; + } + desc->status = ~0; + desc->offset = (req->sector << 9) / port->vdisk_block_size; + desc->size = len; + desc->ncookies = err; + + /* This has to be a non-SMP write barrier because we are writing + * to memory which is shared with the peer LDOM. + */ + wmb(); + desc->hdr.state = VIO_DESC_READY; + + err = __vdc_tx_trigger(port); + if (err < 0) { + printk(KERN_ERR PFX "vdc_tx_trigger() failure, err=%d\n", err); + } else { + port->req_id++; + dr->prod = (dr->prod + 1) & (VDC_TX_RING_SIZE - 1); + } +out: + + return err; +} + +static void do_vdc_request(request_queue_t *q) +{ + while (1) { + struct request *req = elv_next_request(q); + + if (!req) + break; + + blkdev_dequeue_request(req); + if (__send_request(req) < 0) + vdc_end_request(req, 0, req->hard_nr_sectors); + } +} + +static int generic_request(struct vdc_port *port, u8 op, void *buf, int len) +{ + struct vio_dring_state *dr; + struct vio_completion comp; + struct vio_disk_desc *desc; + unsigned int map_perm; + unsigned long flags; + int op_len, err; + void *req_buf; + + if (!(((u64)1 << ((u64)op - 1)) & port->operations)) + return -EOPNOTSUPP; + + switch (op) { + case VD_OP_BREAD: + case VD_OP_BWRITE: + default: + return -EINVAL; + + case VD_OP_FLUSH: + op_len = 0; + map_perm = 0; + break; + + case VD_OP_GET_WCE: + op_len = sizeof(u32); + map_perm = LDC_MAP_W; + break; + + case VD_OP_SET_WCE: + op_len = sizeof(u32); + map_perm = LDC_MAP_R; + break; + + case VD_OP_GET_VTOC: + op_len = sizeof(struct vio_disk_vtoc); + map_perm = LDC_MAP_W; + break; + + case VD_OP_SET_VTOC: + op_len = sizeof(struct vio_disk_vtoc); + map_perm = LDC_MAP_R; + break; + + case VD_OP_GET_DISKGEOM: + op_len = sizeof(struct vio_disk_geom); + map_perm = LDC_MAP_W; + break; + + case VD_OP_SET_DISKGEOM: + op_len = sizeof(struct vio_disk_geom); + map_perm = LDC_MAP_R; + break; + + case VD_OP_SCSICMD: + op_len = 16; + map_perm = LDC_MAP_RW; + break; + + case VD_OP_GET_DEVID: + op_len = sizeof(struct vio_disk_devid); + map_perm = LDC_MAP_W; + break; + + case VD_OP_GET_EFI: + case VD_OP_SET_EFI: + return -EOPNOTSUPP; + break; + }; + + map_perm |= LDC_MAP_SHADOW | LDC_MAP_DIRECT | LDC_MAP_IO; + + op_len = (op_len + 7) & ~7; + req_buf = kzalloc(op_len, GFP_KERNEL); + if (!req_buf) + return -ENOMEM; + + if (len > op_len) + len = op_len; + + if (map_perm & LDC_MAP_R) + memcpy(req_buf, buf, len); + + spin_lock_irqsave(&port->vio.lock, flags); + + dr = &port->vio.drings[VIO_DRIVER_TX_RING]; + + /* XXX If we want to use this code generically we have to + * XXX handle TX ring exhaustion etc. + */ + desc = vio_dring_cur(dr); + + err = ldc_map_single(port->vio.lp, req_buf, op_len, + desc->cookies, port->ring_cookies, + map_perm); + if (err < 0) { + spin_unlock_irqrestore(&port->vio.lock, flags); + kfree(req_buf); + return err; + } + + init_completion(&comp.com); + comp.waiting_for = WAITING_FOR_GEN_CMD; + port->vio.cmp = ∁ + + desc->hdr.ack = VIO_ACK_ENABLE; + desc->req_id = port->req_id; + desc->operation = op; + desc->slice = 0; + desc->status = ~0; + desc->offset = 0; + desc->size = op_len; + desc->ncookies = err; + + /* This has to be a non-SMP write barrier because we are writing + * to memory which is shared with the peer LDOM. + */ + wmb(); + desc->hdr.state = VIO_DESC_READY; + + err = __vdc_tx_trigger(port); + if (err >= 0) { + port->req_id++; + dr->prod = (dr->prod + 1) & (VDC_TX_RING_SIZE - 1); + spin_unlock_irqrestore(&port->vio.lock, flags); + + wait_for_completion(&comp.com); + err = comp.err; + } else { + port->vio.cmp = NULL; + spin_unlock_irqrestore(&port->vio.lock, flags); + } + + if (map_perm & LDC_MAP_W) + memcpy(buf, req_buf, len); + + kfree(req_buf); + + return err; +} + +static int __devinit vdc_alloc_tx_ring(struct vdc_port *port) +{ + struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING]; + unsigned long len, entry_size; + int ncookies; + void *dring; + + entry_size = sizeof(struct vio_disk_desc) + + (sizeof(struct ldc_trans_cookie) * port->ring_cookies); + len = (VDC_TX_RING_SIZE * entry_size); + + ncookies = VIO_MAX_RING_COOKIES; + dring = ldc_alloc_exp_dring(port->vio.lp, len, + dr->cookies, &ncookies, + (LDC_MAP_SHADOW | + LDC_MAP_DIRECT | + LDC_MAP_RW)); + if (IS_ERR(dring)) + return PTR_ERR(dring); + + dr->base = dring; + dr->entry_size = entry_size; + dr->num_entries = VDC_TX_RING_SIZE; + dr->prod = dr->cons = 0; + dr->pending = VDC_TX_RING_SIZE; + dr->ncookies = ncookies; + + return 0; +} + +static void vdc_free_tx_ring(struct vdc_port *port) +{ + struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING]; + + if (dr->base) { + ldc_free_exp_dring(port->vio.lp, dr->base, + (dr->entry_size * dr->num_entries), + dr->cookies, dr->ncookies); + dr->base = NULL; + dr->entry_size = 0; + dr->num_entries = 0; + dr->pending = 0; + dr->ncookies = 0; + } +} + +static int probe_disk(struct vdc_port *port) +{ + struct vio_completion comp; + struct request_queue *q; + struct gendisk *g; + int err; + + init_completion(&comp.com); + comp.err = 0; + comp.waiting_for = WAITING_FOR_LINK_UP; + port->vio.cmp = ∁ + + vio_port_up(&port->vio); + + wait_for_completion(&comp.com); + if (comp.err) + return comp.err; + + err = generic_request(port, VD_OP_GET_VTOC, + &port->label, sizeof(port->label)); + if (err < 0) { + printk(KERN_ERR PFX "VD_OP_GET_VTOC returns error %d\n", err); + return err; + } + + err = generic_request(port, VD_OP_GET_DISKGEOM, + &port->geom, sizeof(port->geom)); + if (err < 0) { + printk(KERN_ERR PFX "VD_OP_GET_DISKGEOM returns " + "error %d\n", err); + return err; + } + + port->vdisk_size = ((u64)port->geom.num_cyl * + (u64)port->geom.num_hd * + (u64)port->geom.num_sec); + + q = blk_init_queue(do_vdc_request, &port->vio.lock); + if (!q) { + printk(KERN_ERR PFX "%s: Could not allocate queue.\n", + port->vio.name); + return -ENOMEM; + } + g = alloc_disk(1 << PARTITION_SHIFT); + if (!g) { + printk(KERN_ERR PFX "%s: Could not allocate gendisk.\n", + port->vio.name); + blk_cleanup_queue(q); + return -ENOMEM; + } + + port->disk = g; + + blk_queue_max_hw_segments(q, port->ring_cookies); + blk_queue_max_phys_segments(q, port->ring_cookies); + blk_queue_max_sectors(q, port->max_xfer_size); + g->major = vdc_major; + g->first_minor = port->dev_no << PARTITION_SHIFT; + strcpy(g->disk_name, port->disk_name); + + g->fops = &vdc_fops; + g->queue = q; + g->private_data = port; + g->driverfs_dev = &port->vio.vdev->dev; + + set_capacity(g, port->vdisk_size); + + printk(KERN_INFO PFX "%s: %u sectors (%u MB)\n", + g->disk_name, + port->vdisk_size, (port->vdisk_size >> (20 - 9))); + + add_disk(g); + + return 0; +} + +static struct ldc_channel_config vdc_ldc_cfg = { + .event = vdc_event, + .mtu = 64, + .mode = LDC_MODE_UNRELIABLE, +}; + +static struct vio_driver_ops vdc_vio_ops = { + .send_attr = vdc_send_attr, + .handle_attr = vdc_handle_attr, + .handshake_complete = vdc_handshake_complete, +}; + +static int __devinit vdc_port_probe(struct vio_dev *vdev, + const struct vio_device_id *id) +{ + struct mdesc_handle *hp; + struct vdc_port *port; + unsigned long flags; + struct vdc *vp; + const u64 *port_id; + int err; + + vp = dev_get_drvdata(vdev->dev.parent); + if (!vp) { + printk(KERN_ERR PFX "Cannot find port parent vdc.\n"); + return -ENODEV; + } + + hp = mdesc_grab(); + + port_id = mdesc_get_property(hp, vdev->mp, "id", NULL); + err = -ENODEV; + if (!port_id) { + printk(KERN_ERR PFX "Port lacks id property.\n"); + goto err_out_release_mdesc; + } + if ((*port_id << PARTITION_SHIFT) & ~(u64)MINORMASK) { + printk(KERN_ERR PFX "Port id [%lu] too large.\n", *port_id); + goto err_out_release_mdesc; + } + + port = kzalloc(sizeof(*port), GFP_KERNEL); + err = -ENOMEM; + if (!port) { + printk(KERN_ERR PFX "Cannot allocate vdc_port.\n"); + goto err_out_release_mdesc; + } + + port->vp = vp; + port->dev_no = *port_id; + + if (port->dev_no >= 26) + snprintf(port->disk_name, sizeof(port->disk_name), + VDCBLK_NAME "%c%c", + 'a' + (port->dev_no / 26) - 1, + 'a' + (port->dev_no % 26)); + else + snprintf(port->disk_name, sizeof(port->disk_name), + VDCBLK_NAME "%c", 'a' + (port->dev_no % 26)); + + err = vio_driver_init(&port->vio, vdev, VDEV_DISK, + vdc_versions, ARRAY_SIZE(vdc_versions), + &vdc_vio_ops, port->disk_name); + if (err) + goto err_out_free_port; + + port->vdisk_block_size = 512; + port->max_xfer_size = ((128 * 1024) / port->vdisk_block_size); + port->ring_cookies = ((port->max_xfer_size * + port->vdisk_block_size) / PAGE_SIZE) + 2; + + err = vio_ldc_alloc(&port->vio, &vdc_ldc_cfg, port); + if (err) + goto err_out_free_port; + + err = vdc_alloc_tx_ring(port); + if (err) + goto err_out_free_ldc; + + err = probe_disk(port); + if (err) + goto err_out_free_tx_ring; + + INIT_LIST_HEAD(&port->list); + + spin_lock_irqsave(&vp->lock, flags); + list_add(&port->list, &vp->port_list); + spin_unlock_irqrestore(&vp->lock, flags); + + dev_set_drvdata(&vdev->dev, port); + + mdesc_release(hp); + + return 0; + +err_out_free_tx_ring: + vdc_free_tx_ring(port); + +err_out_free_ldc: + vio_ldc_free(&port->vio); + +err_out_free_port: + kfree(port); + +err_out_release_mdesc: + mdesc_release(hp); + return err; +} + +static int vdc_port_remove(struct vio_dev *vdev) +{ + struct vdc_port *port = dev_get_drvdata(&vdev->dev); + + if (port) { + del_timer_sync(&port->vio.timer); + + vdc_free_tx_ring(port); + vio_ldc_free(&port->vio); + + dev_set_drvdata(&vdev->dev, NULL); + + kfree(port); + } + return 0; +} + +static struct vio_device_id vdc_port_match[] = { + { + .type = "vdc-port", + }, + {}, +}; +MODULE_DEVICE_TABLE(vio, vdc_match); + +static struct vio_driver vdc_port_driver = { + .id_table = vdc_port_match, + .probe = vdc_port_probe, + .remove = vdc_port_remove, + .driver = { + .name = "vdc_port", + .owner = THIS_MODULE, + } +}; + +static int __devinit vdc_probe(struct vio_dev *vdev, + const struct vio_device_id *id) +{ + static int vdc_version_printed; + struct vdc *vp; + + if (vdc_version_printed++ == 0) + printk(KERN_INFO "%s", version); + + vp = kzalloc(sizeof(struct vdc), GFP_KERNEL); + if (!vp) + return -ENOMEM; + + spin_lock_init(&vp->lock); + vp->dev = vdev; + INIT_LIST_HEAD(&vp->port_list); + + dev_set_drvdata(&vdev->dev, vp); + + return 0; +} + +static int vdc_remove(struct vio_dev *vdev) +{ + + struct vdc *vp = dev_get_drvdata(&vdev->dev); + + if (vp) { + kfree(vp); + dev_set_drvdata(&vdev->dev, NULL); + } + return 0; +} + +static struct vio_device_id vdc_match[] = { + { + .type = "block", + }, + {}, +}; +MODULE_DEVICE_TABLE(vio, vdc_match); + +static struct vio_driver vdc_driver = { + .id_table = vdc_match, + .probe = vdc_probe, + .remove = vdc_remove, + .driver = { + .name = "vdc", + .owner = THIS_MODULE, + } +}; + +static int __init vdc_init(void) +{ + int err; + + err = register_blkdev(0, VDCBLK_NAME); + if (err < 0) + goto out_err; + + vdc_major = err; + err = vio_register_driver(&vdc_driver); + if (err) + goto out_unregister_blkdev; + + err = vio_register_driver(&vdc_port_driver); + if (err) + goto out_unregister_vdc; + + return 0; + +out_unregister_vdc: + vio_unregister_driver(&vdc_driver); + +out_unregister_blkdev: + unregister_blkdev(vdc_major, VDCBLK_NAME); + vdc_major = 0; + +out_err: + return err; +} + +static void __exit vdc_exit(void) +{ + vio_unregister_driver(&vdc_port_driver); + vio_unregister_driver(&vdc_driver); + unregister_blkdev(vdc_major, VDCBLK_NAME); +} + +module_init(vdc_init); +module_exit(vdc_exit); diff --git a/drivers/block/umem.c b/drivers/block/umem.c index 6f5d620..dec74bd 100644 --- a/drivers/block/umem.c +++ b/drivers/block/umem.c @@ -105,12 +105,6 @@ struct cardinfo { unsigned long csr_base; unsigned char __iomem *csr_remap; unsigned long csr_len; -#ifdef CONFIG_MM_MAP_MEMORY - unsigned long mem_base; - unsigned char __iomem *mem_remap; - unsigned long mem_len; -#endif - unsigned int win_size; /* PCI window size */ unsigned int mm_size; /* size in kbytes */ @@ -872,10 +866,6 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i card->csr_base = pci_resource_start(dev, 0); card->csr_len = pci_resource_len(dev, 0); -#ifdef CONFIG_MM_MAP_MEMORY - card->mem_base = pci_resource_start(dev, 1); - card->mem_len = pci_resource_len(dev, 1); -#endif printk(KERN_INFO "Micro Memory(tm) controller #%d found at %02x:%02x (PCI Mem Module (Battery Backup))\n", card->card_number, dev->bus->number, dev->devfn); @@ -903,27 +893,6 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i printk(KERN_INFO "MM%d: CSR 0x%08lx -> 0x%p (0x%lx)\n", card->card_number, card->csr_base, card->csr_remap, card->csr_len); -#ifdef CONFIG_MM_MAP_MEMORY - if (!request_mem_region(card->mem_base, card->mem_len, "Micro Memory")) { - printk(KERN_ERR "MM%d: Unable to request memory region\n", card->card_number); - ret = -ENOMEM; - - goto failed_req_mem; - } - - if (!(card->mem_remap = ioremap(card->mem_base, cards->mem_len))) { - printk(KERN_ERR "MM%d: Unable to remap memory region\n", card->card_number); - ret = -ENOMEM; - - goto failed_remap_mem; - } - - printk(KERN_INFO "MM%d: MEM 0x%8lx -> 0x%8lx (0x%lx)\n", card->card_number, - card->mem_base, card->mem_remap, card->mem_len); -#else - printk(KERN_INFO "MM%d: MEM area not remapped (CONFIG_MM_MAP_MEMORY not set)\n", - card->card_number); -#endif switch(card->dev->device) { case 0x5415: card->flags |= UM_FLAG_NO_BYTE_STATUS | UM_FLAG_NO_BATTREG; @@ -1091,12 +1060,6 @@ static int __devinit mm_pci_probe(struct pci_dev *dev, const struct pci_device_i card->mm_pages[1].desc, card->mm_pages[1].page_dma); failed_magic: -#ifdef CONFIG_MM_MAP_MEMORY - iounmap(card->mem_remap); - failed_remap_mem: - release_mem_region(card->mem_base, card->mem_len); - failed_req_mem: -#endif iounmap(card->csr_remap); failed_remap_csr: release_mem_region(card->csr_base, card->csr_len); @@ -1116,10 +1079,6 @@ static void mm_pci_remove(struct pci_dev *dev) tasklet_kill(&card->tasklet); iounmap(card->csr_remap); release_mem_region(card->csr_base, card->csr_len); -#ifdef CONFIG_MM_MAP_MEMORY - iounmap(card->mem_remap); - release_mem_region(card->mem_base, card->mem_len); -#endif free_irq(card->irq, card); if (card->mm_pages[0].desc) @@ -1133,23 +1092,18 @@ static void mm_pci_remove(struct pci_dev *dev) blk_cleanup_queue(card->queue); } -static const struct pci_device_id mm_pci_ids[] = { { - .vendor = PCI_VENDOR_ID_MICRO_MEMORY, - .device = PCI_DEVICE_ID_MICRO_MEMORY_5415CN, - }, { - .vendor = PCI_VENDOR_ID_MICRO_MEMORY, - .device = PCI_DEVICE_ID_MICRO_MEMORY_5425CN, - }, { - .vendor = PCI_VENDOR_ID_MICRO_MEMORY, - .device = PCI_DEVICE_ID_MICRO_MEMORY_6155, - }, { +static const struct pci_device_id mm_pci_ids[] = { + {PCI_DEVICE(PCI_VENDOR_ID_MICRO_MEMORY,PCI_DEVICE_ID_MICRO_MEMORY_5415CN)}, + {PCI_DEVICE(PCI_VENDOR_ID_MICRO_MEMORY,PCI_DEVICE_ID_MICRO_MEMORY_5425CN)}, + {PCI_DEVICE(PCI_VENDOR_ID_MICRO_MEMORY,PCI_DEVICE_ID_MICRO_MEMORY_6155)}, + { .vendor = 0x8086, .device = 0xB555, .subvendor= 0x1332, .subdevice= 0x5460, .class = 0x050000, .class_mask= 0, - }, { /* end: all zeroes */ } + }, { /* end: all zeroes */ } }; MODULE_DEVICE_TABLE(pci, mm_pci_ids); diff --git a/drivers/block/z2ram.c b/drivers/block/z2ram.c index 7cc2685..2abf94c 100644 --- a/drivers/block/z2ram.c +++ b/drivers/block/z2ram.c @@ -44,9 +44,6 @@ extern int m68k_realnum_memory; extern struct mem_info m68k_memory[NUM_MEMINFO]; -#define TRUE (1) -#define FALSE (0) - #define Z2MINOR_COMBINED (0) #define Z2MINOR_Z2ONLY (1) #define Z2MINOR_CHIPONLY (2) diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index f664868..ec9dc3d 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -979,15 +979,14 @@ config GPIO_VR41XX depends on CPU_VR41XX config RAW_DRIVER - tristate "RAW driver (/dev/raw/rawN) (OBSOLETE)" + tristate "RAW driver (/dev/raw/rawN)" depends on BLOCK help - The raw driver permits block devices to be bound to /dev/raw/rawN. - Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O. + The raw driver permits block devices to be bound to /dev/raw/rawN. + Once bound, I/O against /dev/raw/rawN uses efficient zero-copy I/O. See the raw(8) manpage for more details. - The raw driver is deprecated and will be removed soon. - Applications should simply open the device (eg /dev/hda1) + Applications should preferably open the device (eg /dev/hda1) with the O_DIRECT flag. config MAX_RAW_DEVS diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 2f56ecc..f2996a9 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -15,6 +15,7 @@ obj-y += misc.o obj-$(CONFIG_VT) += vt_ioctl.o vc_screen.o consolemap.o \ consolemap_deftbl.o selection.o keyboard.o obj-$(CONFIG_HW_CONSOLE) += vt.o defkeymap.o +obj-$(CONFIG_AUDIT) += tty_audit.o obj-$(CONFIG_MAGIC_SYSRQ) += sysrq.o obj-$(CONFIG_ESPSERIAL) += esp.o obj-$(CONFIG_MVME147_SCC) += generic_serial.o vme_scc.o diff --git a/drivers/char/amiserial.c b/drivers/char/amiserial.c index 4eaceab..7b02bf1 100644 --- a/drivers/char/amiserial.c +++ b/drivers/char/amiserial.c @@ -738,6 +738,7 @@ static void change_speed(struct async_struct *info, } /* If the quotient is zero refuse the change */ if (!quot && old_termios) { + /* FIXME: Will need updating for new tty in the end */ info->tty->termios->c_cflag &= ~CBAUD; info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD); baud = tty_get_baud_rate(info->tty); @@ -783,7 +784,6 @@ static void change_speed(struct async_struct *info, /* * Set up parity check flag */ -#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) info->read_status_mask = UART_LSR_OE | UART_LSR_DR; if (I_INPCK(info->tty)) @@ -1367,11 +1367,6 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) unsigned long flags; unsigned int cflag = tty->termios->c_cflag; - if ( (cflag == old_termios->c_cflag) - && ( RELEVANT_IFLAG(tty->termios->c_iflag) - == RELEVANT_IFLAG(old_termios->c_iflag))) - return; - change_speed(info, old_termios); /* Handle transition to B0 status */ diff --git a/drivers/char/consolemap.c b/drivers/char/consolemap.c index fd40b95..4b3916f 100644 --- a/drivers/char/consolemap.c +++ b/drivers/char/consolemap.c @@ -177,6 +177,7 @@ struct uni_pagedir { unsigned long refcount; unsigned long sum; unsigned char *inverse_translations[4]; + u16 *inverse_trans_unicode; int readonly; }; @@ -207,6 +208,41 @@ static void set_inverse_transl(struct vc_data *conp, struct uni_pagedir *p, int } } +static void set_inverse_trans_unicode(struct vc_data *conp, + struct uni_pagedir *p) +{ + int i, j, k, glyph; + u16 **p1, *p2; + u16 *q; + + if (!p) return; + q = p->inverse_trans_unicode; + if (!q) { + q = p->inverse_trans_unicode = + kmalloc(MAX_GLYPH * sizeof(u16), GFP_KERNEL); + if (!q) + return; + } + memset(q, 0, MAX_GLYPH * sizeof(u16)); + + for (i = 0; i < 32; i++) { + p1 = p->uni_pgdir[i]; + if (!p1) + continue; + for (j = 0; j < 32; j++) { + p2 = p1[j]; + if (!p2) + continue; + for (k = 0; k < 64; k++) { + glyph = p2[k]; + if (glyph >= 0 && glyph < MAX_GLYPH + && q[glyph] < 32) + q[glyph] = (i << 11) + (j << 6) + k; + } + } + } +} + unsigned short *set_translate(int m, struct vc_data *vc) { inv_translate[vc->vc_num] = m; @@ -217,19 +253,29 @@ unsigned short *set_translate(int m, struct vc_data *vc) * Inverse translation is impossible for several reasons: * 1. The font<->character maps are not 1-1. * 2. The text may have been written while a different translation map - * was active, or using Unicode. + * was active. * Still, it is now possible to a certain extent to cut and paste non-ASCII. */ -unsigned char inverse_translate(struct vc_data *conp, int glyph) +u16 inverse_translate(struct vc_data *conp, int glyph, int use_unicode) { struct uni_pagedir *p; + int m; if (glyph < 0 || glyph >= MAX_GLYPH) return 0; - else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc) || - !p->inverse_translations[inv_translate[conp->vc_num]]) + else if (!(p = (struct uni_pagedir *)*conp->vc_uni_pagedir_loc)) return glyph; - else - return p->inverse_translations[inv_translate[conp->vc_num]][glyph]; + else if (use_unicode) { + if (!p->inverse_trans_unicode) + return glyph; + else + return p->inverse_trans_unicode[glyph]; + } else { + m = inv_translate[conp->vc_num]; + if (!p->inverse_translations[m]) + return glyph; + else + return p->inverse_translations[m][glyph]; + } } static void update_user_maps(void) @@ -243,6 +289,7 @@ static void update_user_maps(void) p = (struct uni_pagedir *)*vc_cons[i].d->vc_uni_pagedir_loc; if (p && p != q) { set_inverse_transl(vc_cons[i].d, p, USER_MAP); + set_inverse_trans_unicode(vc_cons[i].d, p); q = p; } } @@ -353,6 +400,10 @@ static void con_release_unimap(struct uni_pagedir *p) kfree(p->inverse_translations[i]); p->inverse_translations[i] = NULL; } + if (p->inverse_trans_unicode) { + kfree(p->inverse_trans_unicode); + p->inverse_trans_unicode = NULL; + } } void con_free_unimap(struct vc_data *vc) @@ -511,6 +562,7 @@ int con_set_unimap(struct vc_data *vc, ushort ct, struct unipair __user *list) for (i = 0; i <= 3; i++) set_inverse_transl(vc, p, i); /* Update all inverse translations */ + set_inverse_trans_unicode(vc, p); return err; } @@ -561,6 +613,7 @@ int con_set_default_unimap(struct vc_data *vc) for (i = 0; i <= 3; i++) set_inverse_transl(vc, p, i); /* Update all inverse translations */ + set_inverse_trans_unicode(vc, p); dflt = p; return err; } @@ -617,6 +670,19 @@ void con_protect_unimap(struct vc_data *vc, int rdonly) p->readonly = rdonly; } +/* may be called during an interrupt */ +u32 conv_8bit_to_uni(unsigned char c) +{ + /* + * Always use USER_MAP. This function is used by the keyboard, + * which shouldn't be affected by G0/G1 switching, etc. + * If the user map still contains default values, i.e. the + * direct-to-font mapping, then assume user is using Latin1. + */ + unsigned short uni = translations[USER_MAP][c]; + return uni == (0xf000 | c) ? c : uni; +} + int conv_uni_to_pc(struct vc_data *conp, long ucs) { diff --git a/drivers/char/cyclades.c b/drivers/char/cyclades.c index ca376b9..e04005b 100644 --- a/drivers/char/cyclades.c +++ b/drivers/char/cyclades.c @@ -4127,10 +4127,6 @@ static void cy_set_termios(struct tty_struct *tty, struct ktermios *old_termios) printk(KERN_DEBUG "cyc:cy_set_termios ttyC%d\n", info->line); #endif - if (tty->termios->c_cflag == old_termios->c_cflag && - (tty->termios->c_iflag & (IXON | IXANY)) == - (old_termios->c_iflag & (IXON | IXANY))) - return; set_line_char(info); if ((old_termios->c_cflag & CRTSCTS) && diff --git a/drivers/char/esp.c b/drivers/char/esp.c index d1bfbaa..74cd511 100644 --- a/drivers/char/esp.c +++ b/drivers/char/esp.c @@ -1121,8 +1121,6 @@ static void change_speed(struct esp_struct *info) /* * Set up parity check flag */ -#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) - info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR; if (I_INPCK(info->tty)) info->read_status_mask |= UART_LSR_FE | UART_LSR_PE; @@ -1920,11 +1918,6 @@ static void rs_set_termios(struct tty_struct *tty, struct ktermios *old_termios) struct esp_struct *info = (struct esp_struct *)tty->driver_data; unsigned long flags; - if ( (tty->termios->c_cflag == old_termios->c_cflag) - && ( RELEVANT_IFLAG(tty->termios->c_iflag) - == RELEVANT_IFLAG(old_termios->c_iflag))) - return; - change_speed(info); spin_lock_irqsave(&info->lock, flags); diff --git a/drivers/char/generic_serial.c b/drivers/char/generic_serial.c index 8ea0275..8facf3e 100644 --- a/drivers/char/generic_serial.c +++ b/drivers/char/generic_serial.c @@ -43,16 +43,6 @@ static int gs_debug; #define func_enter() gs_dprintk (GS_DEBUG_FLOW, "gs: enter %s\n", __FUNCTION__) #define func_exit() gs_dprintk (GS_DEBUG_FLOW, "gs: exit %s\n", __FUNCTION__) -#define NEW_WRITE_LOCKING 1 -#if NEW_WRITE_LOCKING -#define DECL /* Nothing */ -#define LOCKIT mutex_lock(& port->port_write_mutex); -#define RELEASEIT mutex_unlock(&port->port_write_mutex); -#else -#define DECL unsigned long flags; -#define LOCKIT save_flags (flags);cli () -#define RELEASEIT restore_flags (flags) -#endif #define RS_EVENT_WRITE_WAKEUP 1 @@ -62,7 +52,6 @@ module_param(gs_debug, int, 0644); void gs_put_char(struct tty_struct * tty, unsigned char ch) { struct gs_port *port; - DECL func_enter (); @@ -75,11 +64,11 @@ void gs_put_char(struct tty_struct * tty, unsigned char ch) if (! (port->flags & ASYNC_INITIALIZED)) return; /* Take a lock on the serial tranmit buffer! */ - LOCKIT; + mutex_lock(& port->port_write_mutex); if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) { /* Sorry, buffer is full, drop character. Update statistics???? -- REW */ - RELEASEIT; + mutex_unlock(&port->port_write_mutex); return; } @@ -87,13 +76,11 @@ void gs_put_char(struct tty_struct * tty, unsigned char ch) port->xmit_head &= SERIAL_XMIT_SIZE - 1; port->xmit_cnt++; /* Characters in buffer */ - RELEASEIT; + mutex_unlock(&port->port_write_mutex); func_exit (); } -#ifdef NEW_WRITE_LOCKING - /* > Problems to take into account are: > -1- Interrupts that empty part of the buffer. @@ -166,90 +153,6 @@ int gs_write(struct tty_struct * tty, func_exit (); return total; } -#else -/* -> Problems to take into account are: -> -1- Interrupts that empty part of the buffer. -> -2- page faults on the access to userspace. -> -3- Other processes that are also trying to do a "write". -*/ - -int gs_write(struct tty_struct * tty, - const unsigned char *buf, int count) -{ - struct gs_port *port; - int c, total = 0; - int t; - unsigned long flags; - - func_enter (); - - /* The standard serial driver returns 0 in this case. - That sounds to me as "No error, I just didn't get to writing any - bytes. Feel free to try again." - The "official" way to write n bytes from buf is: - - for (nwritten = 0;nwritten < n;nwritten += rv) { - rv = write (fd, buf+nwritten, n-nwritten); - if (rv < 0) break; // Error: bail out. // - } - - which will loop endlessly in this case. The manual page for write - agrees with me. In practise almost everybody writes - "write (fd, buf,n);" but some people might have had to deal with - incomplete writes in the past and correctly implemented it by now... - */ - - if (!tty) return -EIO; - - port = tty->driver_data; - if (!port || !port->xmit_buf) - return -EIO; - - local_save_flags(flags); - while (1) { - cli(); - c = count; - - /* This is safe because we "OWN" the "head". Noone else can - change the "head": we own the port_write_mutex. */ - /* Don't overrun the end of the buffer */ - t = SERIAL_XMIT_SIZE - port->xmit_head; - if (t < c) c = t; - - /* This is safe because the xmit_cnt can only decrease. This - would increase "t", so we might copy too little chars. */ - /* Don't copy past the "head" of the buffer */ - t = SERIAL_XMIT_SIZE - 1 - port->xmit_cnt; - if (t < c) c = t; - - /* Can't copy more? break out! */ - if (c <= 0) { - local_restore_flags(flags); - break; - } - memcpy(port->xmit_buf + port->xmit_head, buf, c); - port->xmit_head = ((port->xmit_head + c) & - (SERIAL_XMIT_SIZE-1)); - port->xmit_cnt += c; - local_restore_flags(flags); - buf += c; - count -= c; - total += c; - } - - if (port->xmit_cnt && - !tty->stopped && - !tty->hw_stopped && - !(port->flags & GS_TX_INTEN)) { - port->flags |= GS_TX_INTEN; - port->rd->enable_tx_interrupts (port); - } - func_exit (); - return total; -} - -#endif @@ -737,23 +640,6 @@ void gs_set_termios (struct tty_struct * tty, gs_dprintk (GS_DEBUG_TERMIOS, "termios structure (%p):\n", tiosp); } - /* This is an optimization that is only allowed for dumb cards */ - /* Smart cards require knowledge of iflags and oflags too: that - might change hardware cooking mode.... */ - if (old_termios) { - if( (tiosp->c_iflag == old_termios->c_iflag) - && (tiosp->c_oflag == old_termios->c_oflag) - && (tiosp->c_cflag == old_termios->c_cflag) - && (tiosp->c_lflag == old_termios->c_lflag) - && (tiosp->c_line == old_termios->c_line) - && (memcmp(tiosp->c_cc, old_termios->c_cc, NCC) == 0)) { - gs_dprintk(GS_DEBUG_TERMIOS, "gs_set_termios: optimized away\n"); - return /* 0 */; - } - } else - gs_dprintk(GS_DEBUG_TERMIOS, "gs_set_termios: no old_termios: " - "no optimization\n"); - if(old_termios && (gs_debug & GS_DEBUG_TERMIOS)) { if(tiosp->c_iflag != old_termios->c_iflag) printk("c_iflag changed\n"); if(tiosp->c_oflag != old_termios->c_oflag) printk("c_oflag changed\n"); diff --git a/drivers/char/genrtc.c b/drivers/char/genrtc.c index 9e1fc02..69f0a29 100644 --- a/drivers/char/genrtc.c +++ b/drivers/char/genrtc.c @@ -173,7 +173,6 @@ static void gen_rtc_interrupt(unsigned long arg) static ssize_t gen_rtc_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - DECLARE_WAITQUEUE(wait, current); unsigned long data; ssize_t retval; @@ -183,18 +182,10 @@ static ssize_t gen_rtc_read(struct file *file, char __user *buf, if (file->f_flags & O_NONBLOCK && !gen_rtc_irq_data) return -EAGAIN; - add_wait_queue(&gen_rtc_wait, &wait); - retval = -ERESTARTSYS; - - while (1) { - set_current_state(TASK_INTERRUPTIBLE); - data = xchg(&gen_rtc_irq_data, 0); - if (data) - break; - if (signal_pending(current)) - goto out; - schedule(); - } + retval = wait_event_interruptible(gen_rtc_wait, + (data = xchg(&gen_rtc_irq_data, 0))); + if (retval) + goto out; /* first test allows optimizer to nuke this case for 32-bit machines */ if (sizeof (int) != sizeof (long) && count == sizeof (unsigned int)) { @@ -206,10 +197,7 @@ static ssize_t gen_rtc_read(struct file *file, char __user *buf, retval = put_user(data, (unsigned long __user *)buf) ?: sizeof(unsigned long); } - out: - __set_current_state(TASK_RUNNING); - remove_wait_queue(&gen_rtc_wait, &wait); - +out: return retval; } diff --git a/drivers/char/hw_random/intel-rng.c b/drivers/char/hw_random/intel-rng.c index 4ae9811..753f460 100644 --- a/drivers/char/hw_random/intel-rng.c +++ b/drivers/char/hw_random/intel-rng.c @@ -296,12 +296,10 @@ static int __init intel_init_hw_struct(struct intel_rng_hw *intel_rng_hw, (BIOS_CNTL_LOCK_ENABLE_MASK|BIOS_CNTL_WRITE_ENABLE_MASK)) == BIOS_CNTL_LOCK_ENABLE_MASK) { static __initdata /*const*/ char warning[] = - KERN_WARNING PFX "Firmware space is locked read-only. " - KERN_WARNING PFX "If you can't or\n don't want to " - KERN_WARNING PFX "disable this in firmware setup, and " - KERN_WARNING PFX "if\n you are certain that your " - KERN_WARNING PFX "system has a functional\n RNG, try" - KERN_WARNING PFX "using the 'no_fwh_detect' option.\n"; + KERN_WARNING PFX "Firmware space is locked read-only. If you can't or\n" + KERN_WARNING PFX "don't want to disable this in firmware setup, and if\n" + KERN_WARNING PFX "you are certain that your system has a functional\n" + KERN_WARNING PFX "RNG, try using the 'no_fwh_detect' option.\n"; if (no_fwh_detect) return -ENODEV; diff --git a/drivers/char/ip2/i2ellis.c b/drivers/char/ip2/i2ellis.c index dd761a1..61ef013 100644 --- a/drivers/char/ip2/i2ellis.c +++ b/drivers/char/ip2/i2ellis.c @@ -43,8 +43,6 @@ static void iiEnableMailIrqIIEX(i2eBordStrPtr); static void iiWriteMaskII(i2eBordStrPtr, unsigned char); static void iiWriteMaskIIEX(i2eBordStrPtr, unsigned char); -static void ii2DelayTimer(unsigned int); -static void ii2DelayWakeup(unsigned long id); static void ii2Nop(void); //*************** @@ -55,8 +53,6 @@ static int ii2Safe; // Safe I/O address for delay routine static int iiDelayed; // Set when the iiResetDelay function is // called. Cleared when ANY board is reset. -static struct timer_list * pDelayTimer; // Used by iiDelayTimer -static wait_queue_head_t pDelayWait; // Used by iiDelayTimer static rwlock_t Dl_spinlock; //******** @@ -86,9 +82,6 @@ static rwlock_t Dl_spinlock; static void iiEllisInit(void) { - pDelayTimer = kmalloc ( sizeof (struct timer_list), GFP_KERNEL ); - init_timer(pDelayTimer); - init_waitqueue_head(&pDelayWait); LOCK_INIT(&Dl_spinlock); } @@ -106,7 +99,6 @@ iiEllisInit(void) static void iiEllisCleanup(void) { - kfree(pDelayTimer); } //****************************************************************************** @@ -560,19 +552,6 @@ iiInitialize(i2eBordStrPtr pB) COMPLETE(pB, I2EE_GOOD); } -//======================================================= -// Delay Routines -// -// iiDelayIO -// iiNop -//======================================================= - -static void -ii2DelayWakeup(unsigned long id) -{ - wake_up_interruptible ( &pDelayWait ); -} - //****************************************************************************** // Function: ii2DelayTimer(mseconds) // Parameters: mseconds - number of milliseconds to delay @@ -594,28 +573,7 @@ ii2DelayWakeup(unsigned long id) static void ii2DelayTimer(unsigned int mseconds) { - wait_queue_t wait; - - init_waitqueue_entry(&wait, current); - - init_timer ( pDelayTimer ); - - add_wait_queue(&pDelayWait, &wait); - - set_current_state( TASK_INTERRUPTIBLE ); - - pDelayTimer->expires = jiffies + ( mseconds + 9 ) / 10; - pDelayTimer->function = ii2DelayWakeup; - pDelayTimer->data = 0; - - add_timer ( pDelayTimer ); - - schedule(); - - set_current_state( TASK_RUNNING ); - remove_wait_queue(&pDelayWait, &wait); - - del_timer ( pDelayTimer ); + msleep_interruptible(mseconds); } #if 0 diff --git a/drivers/char/ipmi/Kconfig b/drivers/char/ipmi/Kconfig index b894f67..0baa8fa 100644 --- a/drivers/char/ipmi/Kconfig +++ b/drivers/char/ipmi/Kconfig @@ -2,11 +2,9 @@ # IPMI device configuration # -menu "IPMI" - depends on HAS_IOMEM - -config IPMI_HANDLER +menuconfig IPMI_HANDLER tristate 'IPMI top-level message handler' + depends on HAS_IOMEM help This enables the central IPMI message handler, required for IPMI to work. @@ -18,9 +16,10 @@ config IPMI_HANDLER If unsure, say N. +if IPMI_HANDLER + config IPMI_PANIC_EVENT bool 'Generate a panic event to all BMCs on a panic' - depends on IPMI_HANDLER help When a panic occurs, this will cause the IPMI message handler to generate an IPMI event describing the panic to each interface @@ -40,14 +39,12 @@ config IPMI_PANIC_STRING config IPMI_DEVICE_INTERFACE tristate 'Device interface for IPMI' - depends on IPMI_HANDLER help This provides an IOCTL interface to the IPMI message handler so userland processes may use IPMI. It supports poll() and select(). config IPMI_SI tristate 'IPMI System Interface handler' - depends on IPMI_HANDLER help Provides a driver for System Interfaces (KCS, SMIC, BT). Currently, only KCS and SMIC are supported. If @@ -55,15 +52,13 @@ config IPMI_SI config IPMI_WATCHDOG tristate 'IPMI Watchdog Timer' - depends on IPMI_HANDLER help This enables the IPMI watchdog timer. config IPMI_POWEROFF tristate 'IPMI Poweroff' - depends on IPMI_HANDLER help This enables a function to power off the system with IPMI if the IPMI management controller is capable of this. -endmenu +endif # IPMI_HANDLER diff --git a/drivers/char/ipmi/ipmi_poweroff.c b/drivers/char/ipmi/ipmi_poweroff.c index e02893b..b86186d 100644 --- a/drivers/char/ipmi/ipmi_poweroff.c +++ b/drivers/char/ipmi/ipmi_poweroff.c @@ -679,7 +679,7 @@ static int ipmi_poweroff_init (void) { int rv; - printk ("Copyright (C) 2004 MontaVista Software -" + printk (KERN_INFO "Copyright (C) 2004 MontaVista Software -" " IPMI Powerdown via sys_reboot.\n"); if (poweroff_powercycle) diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c index 78e1b96..4edfdda 100644 --- a/drivers/char/ipmi/ipmi_si_intf.c +++ b/drivers/char/ipmi/ipmi_si_intf.c @@ -2857,7 +2857,7 @@ static int try_smi_init(struct smi_info *new_smi) mutex_unlock(&smi_infos_lock); - printk(" IPMI %s interface initialized\n",si_to_str[new_smi->si_type]); + printk(KERN_INFO "IPMI %s interface initialized\n",si_to_str[new_smi->si_type]); return 0; diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c index 7b279d1..8094099 100644 --- a/drivers/char/istallion.c +++ b/drivers/char/istallion.c @@ -1753,9 +1753,6 @@ static void stli_settermios(struct tty_struct *tty, struct ktermios *old) return; tiosp = tty->termios; - if ((tiosp->c_cflag == old->c_cflag) && - (tiosp->c_iflag == old->c_iflag)) - return; stli_mkasyport(portp, &aport, tiosp); stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0); diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index 90965b4..2ce0af1 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -24,6 +24,7 @@ * 21-08-02: Converted to input API, major cleanup. (Vojtech Pavlik) */ +#include <linux/consolemap.h> #include <linux/module.h> #include <linux/sched.h> #include <linux/tty.h> @@ -308,10 +309,9 @@ static void applkey(struct vc_data *vc, int key, char mode) * Many other routines do put_queue, but I think either * they produce ASCII, or they produce some user-assigned * string, and in both cases we might assume that it is - * in utf-8 already. UTF-8 is defined for words of up to 31 bits, - * but we need only 16 bits here + * in utf-8 already. */ -static void to_utf8(struct vc_data *vc, ushort c) +static void to_utf8(struct vc_data *vc, uint c) { if (c < 0x80) /* 0******* */ @@ -320,11 +320,21 @@ static void to_utf8(struct vc_data *vc, ushort c) /* 110***** 10****** */ put_queue(vc, 0xc0 | (c >> 6)); put_queue(vc, 0x80 | (c & 0x3f)); - } else { + } else if (c < 0x10000) { + if (c >= 0xD800 && c < 0xE000) + return; + if (c == 0xFFFF) + return; /* 1110**** 10****** 10****** */ put_queue(vc, 0xe0 | (c >> 12)); put_queue(vc, 0x80 | ((c >> 6) & 0x3f)); put_queue(vc, 0x80 | (c & 0x3f)); + } else if (c < 0x110000) { + /* 11110*** 10****** 10****** 10****** */ + put_queue(vc, 0xf0 | (c >> 18)); + put_queue(vc, 0x80 | ((c >> 12) & 0x3f)); + put_queue(vc, 0x80 | ((c >> 6) & 0x3f)); + put_queue(vc, 0x80 | (c & 0x3f)); } } @@ -393,7 +403,7 @@ static unsigned int handle_diacr(struct vc_data *vc, unsigned int ch) return d; if (kbd->kbdmode == VC_UNICODE) - to_utf8(vc, d); + to_utf8(vc, conv_8bit_to_uni(d)); else if (d < 0x100) put_queue(vc, d); @@ -407,7 +417,7 @@ static void fn_enter(struct vc_data *vc) { if (diacr) { if (kbd->kbdmode == VC_UNICODE) - to_utf8(vc, diacr); + to_utf8(vc, conv_8bit_to_uni(diacr)); else if (diacr < 0x100) put_queue(vc, diacr); diacr = 0; @@ -617,7 +627,7 @@ static void k_unicode(struct vc_data *vc, unsigned int value, char up_flag) return; } if (kbd->kbdmode == VC_UNICODE) - to_utf8(vc, value); + to_utf8(vc, conv_8bit_to_uni(value)); else if (value < 0x100) put_queue(vc, value); } @@ -775,7 +785,7 @@ static void k_shift(struct vc_data *vc, unsigned char value, char up_flag) /* kludge */ if (up_flag && shift_state != old_state && npadch != -1) { if (kbd->kbdmode == VC_UNICODE) - to_utf8(vc, npadch & 0xffff); + to_utf8(vc, npadch); else put_queue(vc, npadch & 0xff); npadch = -1; diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 4e6fb96..71c8cd7 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -67,25 +67,13 @@ extern int pmu_device_init(void); #ifdef CONFIG_PROC_FS static void *misc_seq_start(struct seq_file *seq, loff_t *pos) { - struct miscdevice *p; - loff_t off = 0; - mutex_lock(&misc_mtx); - list_for_each_entry(p, &misc_list, list) { - if (*pos == off++) - return p; - } - return NULL; + return seq_list_start(&misc_list, *pos); } static void *misc_seq_next(struct seq_file *seq, void *v, loff_t *pos) { - struct list_head *n = ((struct miscdevice *)v)->list.next; - - ++*pos; - - return (n != &misc_list) ? list_entry(n, struct miscdevice, list) - : NULL; + return seq_list_next(v, &misc_list, pos); } static void misc_seq_stop(struct seq_file *seq, void *v) @@ -95,7 +83,7 @@ static void misc_seq_stop(struct seq_file *seq, void *v) static int misc_seq_show(struct seq_file *seq, void *v) { - const struct miscdevice *p = v; + const struct miscdevice *p = list_entry(v, struct miscdevice, list); seq_printf(seq, "%3i %s\n", p->minor, p->name ? p->name : ""); return 0; diff --git a/drivers/char/mspec.c b/drivers/char/mspec.c index 7ac3061..c716ef0 100644 --- a/drivers/char/mspec.c +++ b/drivers/char/mspec.c @@ -265,7 +265,7 @@ mspec_mmap(struct file *file, struct vm_area_struct *vma, int type) vdata->refcnt = ATOMIC_INIT(1); vma->vm_private_data = vdata; - vma->vm_flags |= (VM_IO | VM_LOCKED | VM_RESERVED | VM_PFNMAP); + vma->vm_flags |= (VM_IO | VM_RESERVED | VM_PFNMAP); if (vdata->type == MSPEC_FETCHOP || vdata->type == MSPEC_UNCACHED) vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_ops = &mspec_vm_ops; diff --git a/drivers/char/mxser.c b/drivers/char/mxser.c index 5953a45..2aee3fe 100644 --- a/drivers/char/mxser.c +++ b/drivers/char/mxser.c @@ -90,8 +90,6 @@ #define UART_MCR_AFE 0x20 #define UART_LSR_SPECIAL 0x1E -#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|\ - IXON|IXOFF)) #define IRQ_T(info) ((info->flags & ASYNC_SHARE_IRQ) ? IRQF_SHARED : IRQF_DISABLED) @@ -1729,16 +1727,12 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi struct mxser_struct *info = tty->driver_data; unsigned long flags; - if ((tty->termios->c_cflag != old_termios->c_cflag) || - (RELEVANT_IFLAG(tty->termios->c_iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) { + mxser_change_speed(info, old_termios); - mxser_change_speed(info, old_termios); - - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { - tty->hw_stopped = 0; - mxser_start(tty); - } + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + mxser_start(tty); } /* Handle sw stopped */ diff --git a/drivers/char/mxser_new.c b/drivers/char/mxser_new.c index 6cde448..6a56393 100644 --- a/drivers/char/mxser_new.c +++ b/drivers/char/mxser_new.c @@ -72,8 +72,6 @@ #define UART_MCR_AFE 0x20 #define UART_LSR_SPECIAL 0x1E -#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|\ - IXON|IXOFF)) #define C168_ASIC_ID 1 #define C104_ASIC_ID 2 @@ -1560,7 +1558,7 @@ static int mxser_ioctl_special(unsigned int cmd, void __user *argp) return -EFAULT; return 0; case MOXA_ASPP_MON_EXT: { - int status, p, shiftbit; + int p, shiftbit; unsigned long opmode; unsigned cflag, iflag; @@ -1990,18 +1988,14 @@ static void mxser_set_termios(struct tty_struct *tty, struct ktermios *old_termi struct mxser_port *info = tty->driver_data; unsigned long flags; - if ((tty->termios->c_cflag != old_termios->c_cflag) || - (RELEVANT_IFLAG(tty->termios->c_iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) { - - spin_lock_irqsave(&info->slock, flags); - mxser_change_speed(info, old_termios); - spin_unlock_irqrestore(&info->slock, flags); + spin_lock_irqsave(&info->slock, flags); + mxser_change_speed(info, old_termios); + spin_unlock_irqrestore(&info->slock, flags); - if ((old_termios->c_cflag & CRTSCTS) && - !(tty->termios->c_cflag & CRTSCTS)) { - tty->hw_stopped = 0; - mxser_start(tty); - } + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + mxser_start(tty); } /* Handle sw stopped */ diff --git a/drivers/char/n_hdlc.c b/drivers/char/n_hdlc.c index 337a87f..e8332f3 100644 --- a/drivers/char/n_hdlc.c +++ b/drivers/char/n_hdlc.c @@ -400,7 +400,12 @@ static void n_hdlc_send_frames(struct n_hdlc *n_hdlc, struct tty_struct *tty) /* Send the next block of data to device */ tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); actual = tty->driver->write(tty, tbuf->buf, tbuf->count); - + + /* rollback was possible and has been done */ + if (actual == -ERESTARTSYS) { + n_hdlc->tbuf = tbuf; + break; + } /* if transmit error, throw frame away by */ /* pretending it was accepted by driver */ if (actual < 0) @@ -780,13 +785,14 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp, poll_wait(filp, &tty->write_wait, wait); /* set bits for operations that won't block */ - if(n_hdlc->rx_buf_list.head) + if (n_hdlc->rx_buf_list.head) mask |= POLLIN | POLLRDNORM; /* readable */ if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) mask |= POLLHUP; - if(tty_hung_up_p(filp)) + if (tty_hung_up_p(filp)) mask |= POLLHUP; - if(n_hdlc->tx_free_buf_list.head) + if (!tty_is_writelocked(tty) && + n_hdlc->tx_free_buf_list.head) mask |= POLLOUT | POLLWRNORM; /* writable */ } return mask; @@ -861,7 +867,7 @@ static void n_hdlc_buf_put(struct n_hdlc_buf_list *list, spin_lock_irqsave(&list->spinlock,flags); buf->link=NULL; - if(list->tail) + if (list->tail) list->tail->link = buf; else list->head = buf; diff --git a/drivers/char/n_r3964.c b/drivers/char/n_r3964.c index 14557a4..6b918b8 100644 --- a/drivers/char/n_r3964.c +++ b/drivers/char/n_r3964.c @@ -1071,8 +1071,6 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, struct r3964_client_info *pClient; struct r3964_message *pMsg; struct r3964_client_message theMsg; - DECLARE_WAITQUEUE(wait, current); - int count; TRACE_L("read()"); @@ -1086,16 +1084,8 @@ static ssize_t r3964_read(struct tty_struct *tty, struct file *file, return -EAGAIN; } /* block until there is a message: */ - add_wait_queue(&pInfo->read_wait, &wait); -repeat: - __set_current_state(TASK_INTERRUPTIBLE); - pMsg = remove_msg(pInfo, pClient); - if (!pMsg && !signal_pending(current)) { - schedule(); - goto repeat; - } - __set_current_state(TASK_RUNNING); - remove_wait_queue(&pInfo->read_wait, &wait); + wait_event_interruptible(pInfo->read_wait, + (pMsg = remove_msg(pInfo, pClient))); } /* If we still haven't got a message, we must have been signalled */ diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 154f422..0380569 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -45,6 +45,8 @@ #include <linux/slab.h> #include <linux/poll.h> #include <linux/bitops.h> +#include <linux/audit.h> +#include <linux/file.h> #include <asm/uaccess.h> #include <asm/system.h> @@ -78,6 +80,13 @@ static inline void free_buf(unsigned char *buf) free_page((unsigned long) buf); } +static inline int tty_put_user(struct tty_struct *tty, unsigned char x, + unsigned char __user *ptr) +{ + tty_audit_add_data(tty, &x, 1); + return put_user(x, ptr); +} + /** * n_tty_set__room - receive space * @tty: terminal @@ -1153,6 +1162,7 @@ static int copy_from_read_buf(struct tty_struct *tty, if (n) { retval = copy_to_user(*b, &tty->read_buf[tty->read_tail], n); n -= retval; + tty_audit_add_data(tty, &tty->read_buf[tty->read_tail], n); spin_lock_irqsave(&tty->read_lock, flags); tty->read_tail = (tty->read_tail + n) & (N_TTY_BUF_SIZE-1); tty->read_cnt -= n; @@ -1279,7 +1289,7 @@ do_it_again: break; cs = tty->link->ctrl_status; tty->link->ctrl_status = 0; - if (put_user(cs, b++)) { + if (tty_put_user(tty, cs, b++)) { retval = -EFAULT; b--; break; @@ -1321,7 +1331,7 @@ do_it_again: /* Deal with packet mode. */ if (tty->packet && b == buf) { - if (put_user(TIOCPKT_DATA, b++)) { + if (tty_put_user(tty, TIOCPKT_DATA, b++)) { retval = -EFAULT; b--; break; @@ -1352,15 +1362,17 @@ do_it_again: spin_unlock_irqrestore(&tty->read_lock, flags); if (!eol || (c != __DISABLED_CHAR)) { - if (put_user(c, b++)) { + if (tty_put_user(tty, c, b++)) { retval = -EFAULT; b--; break; } nr--; } - if (eol) + if (eol) { + tty_audit_push(tty); break; + } } if (retval) break; @@ -1538,7 +1550,8 @@ static unsigned int normal_poll(struct tty_struct * tty, struct file * file, pol else tty->minimum_to_wake = 1; } - if (tty->driver->chars_in_buffer(tty) < WAKEUP_CHARS && + if (!tty_is_writelocked(tty) && + tty->driver->chars_in_buffer(tty) < WAKEUP_CHARS && tty->driver->write_room(tty) > 0) mask |= POLLOUT | POLLWRNORM; return mask; diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index 204deaa..98dec38 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -42,19 +42,12 @@ #define PC 1 #define ATARI 2 -#define COBALT 3 /* select machine configuration */ #if defined(CONFIG_ATARI) # define MACH ATARI #elif defined(__i386__) || defined(__x86_64__) || defined(__arm__) /* and others?? */ -#define MACH PC -# if defined(CONFIG_COBALT) -# include <linux/cobalt-nvram.h> -# define MACH COBALT -# else -# define MACH PC -# endif +# define MACH PC #else # error Cannot build nvram driver for this machine configuration. #endif @@ -76,18 +69,6 @@ #endif -#if MACH == COBALT - -#define CHECK_DRIVER_INIT() 1 - -#define NVRAM_BYTES (128-NVRAM_FIRST_BYTE) - -#define mach_check_checksum cobalt_check_checksum -#define mach_set_checksum cobalt_set_checksum -#define mach_proc_infos cobalt_proc_infos - -#endif - #if MACH == ATARI /* Special parameters for RTC in Atari machines */ @@ -604,177 +585,6 @@ pc_proc_infos(unsigned char *nvram, char *buffer, int *len, #endif /* MACH == PC */ -#if MACH == COBALT - -/* the cobalt CMOS has a wider range of its checksum */ -static int cobalt_check_checksum(void) -{ - int i; - unsigned short sum = 0; - unsigned short expect; - - for (i = COBT_CMOS_CKS_START; i <= COBT_CMOS_CKS_END; ++i) { - if ((i == COBT_CMOS_CHECKSUM) || (i == (COBT_CMOS_CHECKSUM+1))) - continue; - - sum += __nvram_read_byte(i); - } - expect = __nvram_read_byte(COBT_CMOS_CHECKSUM) << 8 | - __nvram_read_byte(COBT_CMOS_CHECKSUM+1); - return ((sum & 0xffff) == expect); -} - -static void cobalt_set_checksum(void) -{ - int i; - unsigned short sum = 0; - - for (i = COBT_CMOS_CKS_START; i <= COBT_CMOS_CKS_END; ++i) { - if ((i == COBT_CMOS_CHECKSUM) || (i == (COBT_CMOS_CHECKSUM+1))) - continue; - - sum += __nvram_read_byte(i); - } - - __nvram_write_byte(sum >> 8, COBT_CMOS_CHECKSUM); - __nvram_write_byte(sum & 0xff, COBT_CMOS_CHECKSUM+1); -} - -#ifdef CONFIG_PROC_FS - -static int cobalt_proc_infos(unsigned char *nvram, char *buffer, int *len, - off_t *begin, off_t offset, int size) -{ - int i; - unsigned int checksum; - unsigned int flags; - char sernum[14]; - char *key = "cNoEbTaWlOtR!"; - unsigned char bto_csum; - - spin_lock_irq(&rtc_lock); - checksum = __nvram_check_checksum(); - spin_unlock_irq(&rtc_lock); - - PRINT_PROC("Checksum status: %svalid\n", checksum ? "" : "not "); - - flags = nvram[COBT_CMOS_FLAG_BYTE_0] << 8 - | nvram[COBT_CMOS_FLAG_BYTE_1]; - - PRINT_PROC("Console: %s\n", - flags & COBT_CMOS_CONSOLE_FLAG ? "on": "off"); - - PRINT_PROC("Firmware Debug Messages: %s\n", - flags & COBT_CMOS_DEBUG_FLAG ? "on": "off"); - - PRINT_PROC("Auto Prompt: %s\n", - flags & COBT_CMOS_AUTO_PROMPT_FLAG ? "on": "off"); - - PRINT_PROC("Shutdown Status: %s\n", - flags & COBT_CMOS_CLEAN_BOOT_FLAG ? "clean": "dirty"); - - PRINT_PROC("Hardware Probe: %s\n", - flags & COBT_CMOS_HW_NOPROBE_FLAG ? "partial": "full"); - - PRINT_PROC("System Fault: %sdetected\n", - flags & COBT_CMOS_SYSFAULT_FLAG ? "": "not "); - - PRINT_PROC("Panic on OOPS: %s\n", - flags & COBT_CMOS_OOPSPANIC_FLAG ? "yes": "no"); - - PRINT_PROC("Delayed Cache Initialization: %s\n", - flags & COBT_CMOS_DELAY_CACHE_FLAG ? "yes": "no"); - - PRINT_PROC("Show Logo at Boot: %s\n", - flags & COBT_CMOS_NOLOGO_FLAG ? "no": "yes"); - - PRINT_PROC("Boot Method: "); - switch (nvram[COBT_CMOS_BOOT_METHOD]) { - case COBT_CMOS_BOOT_METHOD_DISK: - PRINT_PROC("disk\n"); - break; - - case COBT_CMOS_BOOT_METHOD_ROM: - PRINT_PROC("rom\n"); - break; - - case COBT_CMOS_BOOT_METHOD_NET: - PRINT_PROC("net\n"); - break; - - default: - PRINT_PROC("unknown\n"); - break; - } - - PRINT_PROC("Primary Boot Device: %d:%d\n", - nvram[COBT_CMOS_BOOT_DEV0_MAJ], - nvram[COBT_CMOS_BOOT_DEV0_MIN] ); - PRINT_PROC("Secondary Boot Device: %d:%d\n", - nvram[COBT_CMOS_BOOT_DEV1_MAJ], - nvram[COBT_CMOS_BOOT_DEV1_MIN] ); - PRINT_PROC("Tertiary Boot Device: %d:%d\n", - nvram[COBT_CMOS_BOOT_DEV2_MAJ], - nvram[COBT_CMOS_BOOT_DEV2_MIN] ); - - PRINT_PROC("Uptime: %d\n", - nvram[COBT_CMOS_UPTIME_0] << 24 | - nvram[COBT_CMOS_UPTIME_1] << 16 | - nvram[COBT_CMOS_UPTIME_2] << 8 | - nvram[COBT_CMOS_UPTIME_3]); - - PRINT_PROC("Boot Count: %d\n", - nvram[COBT_CMOS_BOOTCOUNT_0] << 24 | - nvram[COBT_CMOS_BOOTCOUNT_1] << 16 | - nvram[COBT_CMOS_BOOTCOUNT_2] << 8 | - nvram[COBT_CMOS_BOOTCOUNT_3]); - - /* 13 bytes of serial num */ - for (i=0 ; i<13 ; i++) { - sernum[i] = nvram[COBT_CMOS_SYS_SERNUM_0 + i]; - } - sernum[13] = '\0'; - - checksum = 0; - for (i=0 ; i<13 ; i++) { - checksum += sernum[i] ^ key[i]; - } - checksum = ((checksum & 0x7f) ^ (0xd6)) & 0xff; - - PRINT_PROC("Serial Number: %s", sernum); - if (checksum != nvram[COBT_CMOS_SYS_SERNUM_CSUM]) { - PRINT_PROC(" (invalid checksum)"); - } - PRINT_PROC("\n"); - - PRINT_PROC("Rom Revison: %d.%d.%d\n", nvram[COBT_CMOS_ROM_REV_MAJ], - nvram[COBT_CMOS_ROM_REV_MIN], nvram[COBT_CMOS_ROM_REV_REV]); - - PRINT_PROC("BTO Server: %d.%d.%d.%d", nvram[COBT_CMOS_BTO_IP_0], - nvram[COBT_CMOS_BTO_IP_1], nvram[COBT_CMOS_BTO_IP_2], - nvram[COBT_CMOS_BTO_IP_3]); - bto_csum = nvram[COBT_CMOS_BTO_IP_0] + nvram[COBT_CMOS_BTO_IP_1] - + nvram[COBT_CMOS_BTO_IP_2] + nvram[COBT_CMOS_BTO_IP_3]; - if (bto_csum != nvram[COBT_CMOS_BTO_IP_CSUM]) { - PRINT_PROC(" (invalid checksum)"); - } - PRINT_PROC("\n"); - - if (flags & COBT_CMOS_VERSION_FLAG - && nvram[COBT_CMOS_VERSION] >= COBT_CMOS_VER_BTOCODE) { - PRINT_PROC("BTO Code: 0x%x\n", - nvram[COBT_CMOS_BTO_CODE_0] << 24 | - nvram[COBT_CMOS_BTO_CODE_1] << 16 | - nvram[COBT_CMOS_BTO_CODE_2] << 8 | - nvram[COBT_CMOS_BTO_CODE_3]); - } - - return 1; -} -#endif /* CONFIG_PROC_FS */ - -#endif /* MACH == COBALT */ - #if MACH == ATARI static int diff --git a/drivers/char/rocket.c b/drivers/char/rocket.c index a3fd7e7..0270080 100644 --- a/drivers/char/rocket.c +++ b/drivers/char/rocket.c @@ -1702,7 +1702,8 @@ static int rp_write(struct tty_struct *tty, if (count <= 0 || rocket_paranoia_check(info, "rp_write")) return 0; - mutex_lock_interruptible(&info->write_mtx); + if (mutex_lock_interruptible(&info->write_mtx)) + return -ERESTARTSYS; #ifdef ROCKET_DEBUG_WRITE printk(KERN_INFO "rp_write %d chars...", count); diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 20380a2..22cf7aa 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -1159,7 +1159,8 @@ static void rtc_dropped_irq(unsigned long data) spin_unlock_irq(&rtc_lock); - printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", freq); + if (printk_ratelimit()) + printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", freq); /* Now we have new data */ wake_up_interruptible(&rtc_wait); diff --git a/drivers/char/selection.c b/drivers/char/selection.c index a69f094..d63f5cc 100644 --- a/drivers/char/selection.c +++ b/drivers/char/selection.c @@ -20,6 +20,7 @@ #include <asm/uaccess.h> +#include <linux/kbd_kern.h> #include <linux/vt_kern.h> #include <linux/consolemap.h> #include <linux/selection.h> @@ -34,6 +35,7 @@ extern void poke_blanked_console(void); /* Variables for selection control. */ /* Use a dynamic buffer, instead of static (Dec 1994) */ struct vc_data *sel_cons; /* must not be deallocated */ +static int use_unicode; static volatile int sel_start = -1; /* cleared by clear_selection */ static int sel_end; static int sel_buffer_lth; @@ -54,10 +56,11 @@ static inline void highlight_pointer(const int where) complement_pos(sel_cons, where); } -static unsigned char +static u16 sel_pos(int n) { - return inverse_translate(sel_cons, screen_glyph(sel_cons, n)); + return inverse_translate(sel_cons, screen_glyph(sel_cons, n), + use_unicode); } /* remove the current selection highlight, if any, @@ -86,8 +89,8 @@ static u32 inwordLut[8]={ 0xFF7FFFFF /* latin-1 accented letters, not division sign */ }; -static inline int inword(const unsigned char c) { - return ( inwordLut[c>>5] >> (c & 0x1F) ) & 1; +static inline int inword(const u16 c) { + return c > 0xff || (( inwordLut[c>>5] >> (c & 0x1F) ) & 1); } /* set inwordLut contents. Invoked by ioctl(). */ @@ -108,13 +111,36 @@ static inline unsigned short limit(const unsigned short v, const unsigned short return (v > u) ? u : v; } +/* stores the char in UTF8 and returns the number of bytes used (1-3) */ +static int store_utf8(u16 c, char *p) +{ + if (c < 0x80) { + /* 0******* */ + p[0] = c; + return 1; + } else if (c < 0x800) { + /* 110***** 10****** */ + p[0] = 0xc0 | (c >> 6); + p[1] = 0x80 | (c & 0x3f); + return 2; + } else { + /* 1110**** 10****** 10****** */ + p[0] = 0xe0 | (c >> 12); + p[1] = 0x80 | ((c >> 6) & 0x3f); + p[2] = 0x80 | (c & 0x3f); + return 3; + } +} + /* set the current selection. Invoked by ioctl() or by kernel code. */ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *tty) { struct vc_data *vc = vc_cons[fg_console].d; int sel_mode, new_sel_start, new_sel_end, spc; char *bp, *obp; - int i, ps, pe; + int i, ps, pe, multiplier; + u16 c; + struct kbd_struct *kbd = kbd_table + fg_console; poke_blanked_console(); @@ -158,6 +184,7 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t clear_selection(); sel_cons = vc_cons[fg_console].d; } + use_unicode = kbd && kbd->kbdmode == VC_UNICODE; switch (sel_mode) { @@ -240,7 +267,8 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t sel_end = new_sel_end; /* Allocate a new buffer before freeing the old one ... */ - bp = kmalloc((sel_end-sel_start)/2+1, GFP_KERNEL); + multiplier = use_unicode ? 3 : 1; /* chars can take up to 3 bytes */ + bp = kmalloc((sel_end-sel_start)/2*multiplier+1, GFP_KERNEL); if (!bp) { printk(KERN_WARNING "selection: kmalloc() failed\n"); clear_selection(); @@ -251,8 +279,12 @@ int set_selection(const struct tiocl_selection __user *sel, struct tty_struct *t obp = bp; for (i = sel_start; i <= sel_end; i += 2) { - *bp = sel_pos(i); - if (!isspace(*bp++)) + c = sel_pos(i); + if (use_unicode) + bp += store_utf8(c, bp); + else + *bp++ = c; + if (!isspace(c)) obp = bp; if (! ((i + 2) % vc->vc_size_row)) { /* strip trailing blanks from line and add newline, diff --git a/drivers/char/sonypi.c b/drivers/char/sonypi.c index 3ef593a..73037a4 100644 --- a/drivers/char/sonypi.c +++ b/drivers/char/sonypi.c @@ -885,53 +885,6 @@ found: return IRQ_HANDLED; } -/* External camera command (exported to the motion eye v4l driver) */ -int sonypi_camera_command(int command, u8 value) -{ - if (!camera) - return -EIO; - - mutex_lock(&sonypi_device.lock); - - switch (command) { - case SONYPI_COMMAND_SETCAMERA: - if (value) - sonypi_camera_on(); - else - sonypi_camera_off(); - break; - case SONYPI_COMMAND_SETCAMERABRIGHTNESS: - sonypi_set(SONYPI_CAMERA_BRIGHTNESS, value); - break; - case SONYPI_COMMAND_SETCAMERACONTRAST: - sonypi_set(SONYPI_CAMERA_CONTRAST, value); - break; - case SONYPI_COMMAND_SETCAMERAHUE: - sonypi_set(SONYPI_CAMERA_HUE, value); - break; - case SONYPI_COMMAND_SETCAMERACOLOR: - sonypi_set(SONYPI_CAMERA_COLOR, value); - break; - case SONYPI_COMMAND_SETCAMERASHARPNESS: - sonypi_set(SONYPI_CAMERA_SHARPNESS, value); - break; - case SONYPI_COMMAND_SETCAMERAPICTURE: - sonypi_set(SONYPI_CAMERA_PICTURE, value); - break; - case SONYPI_COMMAND_SETCAMERAAGC: - sonypi_set(SONYPI_CAMERA_AGC, value); - break; - default: - printk(KERN_ERR "sonypi: sonypi_camera_command invalid: %d\n", - command); - break; - } - mutex_unlock(&sonypi_device.lock); - return 0; -} - -EXPORT_SYMBOL(sonypi_camera_command); - static int sonypi_misc_fasync(int fd, struct file *filp, int on) { int retval; diff --git a/drivers/char/synclink.c b/drivers/char/synclink.c index f02a079..f53e51d 100644 --- a/drivers/char/synclink.c +++ b/drivers/char/synclink.c @@ -160,8 +160,6 @@ typedef struct _DMABUFFERENTRY #define IO_PIN_SHUTDOWN_LIMIT 100 -#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) - struct _input_signal_events { int ri_up; int ri_down; @@ -3064,12 +3062,6 @@ static void mgsl_set_termios(struct tty_struct *tty, struct ktermios *old_termio printk("%s(%d):mgsl_set_termios %s\n", __FILE__,__LINE__, tty->driver->name ); - /* just return if nothing has changed */ - if ((tty->termios->c_cflag == old_termios->c_cflag) - && (RELEVANT_IFLAG(tty->termios->c_iflag) - == RELEVANT_IFLAG(old_termios->c_iflag))) - return; - mgsl_change_params(info); /* Handle transition to B0 status */ diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 02b49bc..428b514 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -144,8 +144,6 @@ MODULE_PARM_DESC(dosyncppp, "Enable synchronous net device, 0=disable 1=enable") /* * tty support and callbacks */ -#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) - static struct tty_driver *serial_driver; static int open(struct tty_struct *tty, struct file * filp); @@ -823,12 +821,6 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) DBGINFO(("%s set_termios\n", tty->driver->name)); - /* just return if nothing has changed */ - if ((tty->termios->c_cflag == old_termios->c_cflag) - && (RELEVANT_IFLAG(tty->termios->c_iflag) - == RELEVANT_IFLAG(old_termios->c_iflag))) - return; - change_params(info); /* Handle transition to B0 status */ diff --git a/drivers/char/synclinkmp.c b/drivers/char/synclinkmp.c index ef93d05..a65407b 100644 --- a/drivers/char/synclinkmp.c +++ b/drivers/char/synclinkmp.c @@ -135,8 +135,6 @@ typedef struct _SCADESC_EX #define IO_PIN_SHUTDOWN_LIMIT 100 -#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) - struct _input_signal_events { int ri_up; int ri_down; @@ -927,12 +925,6 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios) printk("%s(%d):%s set_termios()\n", __FILE__,__LINE__, tty->driver->name ); - /* just return if nothing has changed */ - if ((tty->termios->c_cflag == old_termios->c_cflag) - && (RELEVANT_IFLAG(tty->termios->c_iflag) - == RELEVANT_IFLAG(old_termios->c_iflag))) - return; - change_params(info); /* Handle transition to B0 status */ diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig index dc4e1ff..8f3f762 100644 --- a/drivers/char/tpm/Kconfig +++ b/drivers/char/tpm/Kconfig @@ -2,11 +2,9 @@ # TPM device configuration # -menu "TPM devices" - depends on HAS_IOMEM - -config TCG_TPM +menuconfig TCG_TPM tristate "TPM Hardware Support" + depends on HAS_IOMEM depends on EXPERIMENTAL ---help--- If you have a TPM security chip in your system, which @@ -21,9 +19,11 @@ config TCG_TPM Note: For more TPM drivers enable CONFIG_PNP, CONFIG_ACPI and CONFIG_PNPACPI. +if TCG_TPM + config TCG_TIS tristate "TPM Interface Specification 1.2 Interface" - depends on TCG_TPM && PNPACPI + depends on PNPACPI ---help--- If you have a TPM security chip that is compliant with the TCG TIS 1.2 TPM specification say Yes and it will be accessible @@ -32,7 +32,7 @@ config TCG_TIS config TCG_NSC tristate "National Semiconductor TPM Interface" - depends on TCG_TPM && PNPACPI + depends on PNPACPI ---help--- If you have a TPM security chip from National Semiconductor say Yes and it will be accessible from within Linux. To @@ -41,7 +41,6 @@ config TCG_NSC config TCG_ATMEL tristate "Atmel TPM Interface" - depends on TCG_TPM ---help--- If you have a TPM security chip from Atmel say Yes and it will be accessible from within Linux. To compile this driver @@ -49,7 +48,7 @@ config TCG_ATMEL config TCG_INFINEON tristate "Infineon Technologies TPM Interface" - depends on TCG_TPM && PNPACPI + depends on PNPACPI ---help--- If you have a TPM security chip from Infineon Technologies (either SLD 9630 TT 1.1 or SLB 9635 TT 1.2) say Yes and it @@ -59,5 +58,4 @@ config TCG_INFINEON Further information on this driver and the supported hardware can be found at http://www.prosec.rub.de/tpm -endmenu - +endif # TCG_TPM diff --git a/drivers/char/tty_audit.c b/drivers/char/tty_audit.c new file mode 100644 index 0000000..d222012 --- /dev/null +++ b/drivers/char/tty_audit.c @@ -0,0 +1,345 @@ +/* + * Creating audit events from TTY input. + * + * Copyright (C) 2007 Red Hat, Inc. All rights reserved. This copyrighted + * material is made available to anyone wishing to use, modify, copy, or + * redistribute it subject to the terms and conditions of the GNU General + * Public License v.2. + * + * Authors: Miloslav Trmac <mitr@redhat.com> + */ + +#include <linux/audit.h> +#include <linux/file.h> +#include <linux/tty.h> + +struct tty_audit_buf { + atomic_t count; + struct mutex mutex; /* Protects all data below */ + int major, minor; /* The TTY which the data is from */ + unsigned icanon:1; + size_t valid; + unsigned char *data; /* Allocated size N_TTY_BUF_SIZE */ +}; + +static struct tty_audit_buf *tty_audit_buf_alloc(int major, int minor, + int icanon) +{ + struct tty_audit_buf *buf; + + buf = kmalloc(sizeof (*buf), GFP_KERNEL); + if (!buf) + goto err; + if (PAGE_SIZE != N_TTY_BUF_SIZE) + buf->data = kmalloc(N_TTY_BUF_SIZE, GFP_KERNEL); + else + buf->data = (unsigned char *)__get_free_page(GFP_KERNEL); + if (!buf->data) + goto err_buf; + atomic_set(&buf->count, 1); + mutex_init(&buf->mutex); + buf->major = major; + buf->minor = minor; + buf->icanon = icanon; + buf->valid = 0; + return buf; + +err_buf: + kfree(buf); +err: + return NULL; +} + +static void tty_audit_buf_free(struct tty_audit_buf *buf) +{ + WARN_ON(buf->valid != 0); + if (PAGE_SIZE != N_TTY_BUF_SIZE) + kfree(buf->data); + else + free_page((unsigned long)buf->data); + kfree(buf); +} + +static void tty_audit_buf_put(struct tty_audit_buf *buf) +{ + if (atomic_dec_and_test(&buf->count)) + tty_audit_buf_free(buf); +} + +/** + * tty_audit_buf_push - Push buffered data out + * + * Generate an audit message from the contents of @buf, which is owned by + * @tsk with @loginuid. @buf->mutex must be locked. + */ +static void tty_audit_buf_push(struct task_struct *tsk, uid_t loginuid, + struct tty_audit_buf *buf) +{ + struct audit_buffer *ab; + + if (buf->valid == 0) + return; + if (audit_enabled == 0) + return; + ab = audit_log_start(NULL, GFP_KERNEL, AUDIT_TTY); + if (ab) { + char name[sizeof(tsk->comm)]; + + audit_log_format(ab, "tty pid=%u uid=%u auid=%u major=%d " + "minor=%d comm=", tsk->pid, tsk->uid, + loginuid, buf->major, buf->minor); + get_task_comm(name, tsk); + audit_log_untrustedstring(ab, name); + audit_log_format(ab, " data="); + audit_log_n_untrustedstring(ab, buf->valid, buf->data); + audit_log_end(ab); + } + buf->valid = 0; +} + +/** + * tty_audit_buf_push_current - Push buffered data out + * + * Generate an audit message from the contents of @buf, which is owned by + * the current task. @buf->mutex must be locked. + */ +static void tty_audit_buf_push_current(struct tty_audit_buf *buf) +{ + tty_audit_buf_push(current, audit_get_loginuid(current->audit_context), + buf); +} + +/** + * tty_audit_exit - Handle a task exit + * + * Make sure all buffered data is written out and deallocate the buffer. + * Only needs to be called if current->signal->tty_audit_buf != %NULL. + */ +void tty_audit_exit(void) +{ + struct tty_audit_buf *buf; + + spin_lock_irq(¤t->sighand->siglock); + buf = current->signal->tty_audit_buf; + current->signal->tty_audit_buf = NULL; + spin_unlock_irq(¤t->sighand->siglock); + if (!buf) + return; + + mutex_lock(&buf->mutex); + tty_audit_buf_push_current(buf); + mutex_unlock(&buf->mutex); + + tty_audit_buf_put(buf); +} + +/** + * tty_audit_fork - Copy TTY audit state for a new task + * + * Set up TTY audit state in @sig from current. @sig needs no locking. + */ +void tty_audit_fork(struct signal_struct *sig) +{ + spin_lock_irq(¤t->sighand->siglock); + sig->audit_tty = current->signal->audit_tty; + spin_unlock_irq(¤t->sighand->siglock); + sig->tty_audit_buf = NULL; +} + +/** + * tty_audit_push_task - Flush task's pending audit data + */ +void tty_audit_push_task(struct task_struct *tsk, uid_t loginuid) +{ + struct tty_audit_buf *buf; + + spin_lock_irq(&tsk->sighand->siglock); + buf = tsk->signal->tty_audit_buf; + if (buf) + atomic_inc(&buf->count); + spin_unlock_irq(&tsk->sighand->siglock); + if (!buf) + return; + + mutex_lock(&buf->mutex); + tty_audit_buf_push(tsk, loginuid, buf); + mutex_unlock(&buf->mutex); + + tty_audit_buf_put(buf); +} + +/** + * tty_audit_buf_get - Get an audit buffer. + * + * Get an audit buffer for @tty, allocate it if necessary. Return %NULL + * if TTY auditing is disabled or out of memory. Otherwise, return a new + * reference to the buffer. + */ +static struct tty_audit_buf *tty_audit_buf_get(struct tty_struct *tty) +{ + struct tty_audit_buf *buf, *buf2; + + buf = NULL; + buf2 = NULL; + spin_lock_irq(¤t->sighand->siglock); + if (likely(!current->signal->audit_tty)) + goto out; + buf = current->signal->tty_audit_buf; + if (buf) { + atomic_inc(&buf->count); + goto out; + } + spin_unlock_irq(¤t->sighand->siglock); + + buf2 = tty_audit_buf_alloc(tty->driver->major, + tty->driver->minor_start + tty->index, + tty->icanon); + if (buf2 == NULL) { + audit_log_lost("out of memory in TTY auditing"); + return NULL; + } + + spin_lock_irq(¤t->sighand->siglock); + if (!current->signal->audit_tty) + goto out; + buf = current->signal->tty_audit_buf; + if (!buf) { + current->signal->tty_audit_buf = buf2; + buf = buf2; + buf2 = NULL; + } + atomic_inc(&buf->count); + /* Fall through */ + out: + spin_unlock_irq(¤t->sighand->siglock); + if (buf2) + tty_audit_buf_free(buf2); + return buf; +} + +/** + * tty_audit_add_data - Add data for TTY auditing. + * + * Audit @data of @size from @tty, if necessary. + */ +void tty_audit_add_data(struct tty_struct *tty, unsigned char *data, + size_t size) +{ + struct tty_audit_buf *buf; + int major, minor; + + if (unlikely(size == 0)) + return; + + buf = tty_audit_buf_get(tty); + if (!buf) + return; + + mutex_lock(&buf->mutex); + major = tty->driver->major; + minor = tty->driver->minor_start + tty->index; + if (buf->major != major || buf->minor != minor + || buf->icanon != tty->icanon) { + tty_audit_buf_push_current(buf); + buf->major = major; + buf->minor = minor; + buf->icanon = tty->icanon; + } + do { + size_t run; + + run = N_TTY_BUF_SIZE - buf->valid; + if (run > size) + run = size; + memcpy(buf->data + buf->valid, data, run); + buf->valid += run; + data += run; + size -= run; + if (buf->valid == N_TTY_BUF_SIZE) + tty_audit_buf_push_current(buf); + } while (size != 0); + mutex_unlock(&buf->mutex); + tty_audit_buf_put(buf); +} + +/** + * tty_audit_push - Push buffered data out + * + * Make sure no audit data is pending for @tty on the current process. + */ +void tty_audit_push(struct tty_struct *tty) +{ + struct tty_audit_buf *buf; + + spin_lock_irq(¤t->sighand->siglock); + if (likely(!current->signal->audit_tty)) { + spin_unlock_irq(¤t->sighand->siglock); + return; + } + buf = current->signal->tty_audit_buf; + if (buf) + atomic_inc(&buf->count); + spin_unlock_irq(¤t->sighand->siglock); + + if (buf) { + int major, minor; + + major = tty->driver->major; + minor = tty->driver->minor_start + tty->index; + mutex_lock(&buf->mutex); + if (buf->major == major && buf->minor == minor) + tty_audit_buf_push_current(buf); + mutex_unlock(&buf->mutex); + tty_audit_buf_put(buf); + } +} + +/** + * tty_audit_opening - A TTY is being opened. + * + * As a special hack, tasks that close all their TTYs and open new ones + * are assumed to be system daemons (e.g. getty) and auditing is + * automatically disabled for them. + */ +void tty_audit_opening(void) +{ + int disable; + + disable = 1; + spin_lock_irq(¤t->sighand->siglock); + if (current->signal->audit_tty == 0) + disable = 0; + spin_unlock_irq(¤t->sighand->siglock); + if (!disable) + return; + + task_lock(current); + if (current->files) { + struct fdtable *fdt; + unsigned i; + + /* + * We don't take a ref to the file, so we must hold ->file_lock + * instead. + */ + spin_lock(¤t->files->file_lock); + fdt = files_fdtable(current->files); + for (i = 0; i < fdt->max_fds; i++) { + struct file *filp; + + filp = fcheck_files(current->files, i); + if (filp && is_tty(filp)) { + disable = 0; + break; + } + } + spin_unlock(¤t->files->file_lock); + } + task_unlock(current); + if (!disable) + return; + + spin_lock_irq(¤t->sighand->siglock); + current->signal->audit_tty = 0; + spin_unlock_irq(¤t->sighand->siglock); +} diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index a96f26a..de37ebc 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -1503,6 +1503,15 @@ int tty_hung_up_p(struct file * filp) EXPORT_SYMBOL(tty_hung_up_p); +/** + * is_tty - checker whether file is a TTY + */ +int is_tty(struct file *filp) +{ + return filp->f_op->read == tty_read + || filp->f_op->read == hung_up_tty_read; +} + static void session_clear_tty(struct pid *session) { struct task_struct *p; @@ -1726,6 +1735,23 @@ static ssize_t tty_read(struct file * file, char __user * buf, size_t count, return i; } +void tty_write_unlock(struct tty_struct *tty) +{ + mutex_unlock(&tty->atomic_write_lock); + wake_up_interruptible(&tty->write_wait); +} + +int tty_write_lock(struct tty_struct *tty, int ndelay) +{ + if (!mutex_trylock(&tty->atomic_write_lock)) { + if (ndelay) + return -EAGAIN; + if (mutex_lock_interruptible(&tty->atomic_write_lock)) + return -ERESTARTSYS; + } + return 0; +} + /* * Split writes up in sane blocksizes to avoid * denial-of-service type attacks @@ -1737,13 +1763,12 @@ static inline ssize_t do_tty_write( const char __user *buf, size_t count) { - ssize_t ret = 0, written = 0; + ssize_t ret, written = 0; unsigned int chunk; - /* FIXME: O_NDELAY ... */ - if (mutex_lock_interruptible(&tty->atomic_write_lock)) { - return -ERESTARTSYS; - } + ret = tty_write_lock(tty, file->f_flags & O_NDELAY); + if (ret < 0) + return ret; /* * We chunk up writes into a temporary buffer. This @@ -1776,8 +1801,8 @@ static inline ssize_t do_tty_write( buf = kmalloc(chunk, GFP_KERNEL); if (!buf) { - mutex_unlock(&tty->atomic_write_lock); - return -ENOMEM; + ret = -ENOMEM; + goto out; } kfree(tty->write_buf); tty->write_cnt = chunk; @@ -1812,7 +1837,8 @@ static inline ssize_t do_tty_write( inode->i_mtime = current_fs_time(inode->i_sb); ret = written; } - mutex_unlock(&tty->atomic_write_lock); +out: + tty_write_unlock(tty); return ret; } @@ -2016,11 +2042,9 @@ static int init_dev(struct tty_driver *driver, int idx, } if (!*ltp_loc) { - ltp = (struct ktermios *) kmalloc(sizeof(struct ktermios), - GFP_KERNEL); + ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL); if (!ltp) goto free_mem_out; - memset(ltp, 0, sizeof(struct ktermios)); } if (driver->type == TTY_DRIVER_TYPE_PTY) { @@ -2049,11 +2073,9 @@ static int init_dev(struct tty_driver *driver, int idx, } if (!*o_ltp_loc) { - o_ltp = (struct ktermios *) - kmalloc(sizeof(struct ktermios), GFP_KERNEL); + o_ltp = kzalloc(sizeof(struct ktermios), GFP_KERNEL); if (!o_ltp) goto free_mem_out; - memset(o_ltp, 0, sizeof(struct ktermios)); } /* @@ -2660,6 +2682,7 @@ got_driver: __proc_set_tty(current, tty); spin_unlock_irq(¤t->sighand->siglock); mutex_unlock(&tty_mutex); + tty_audit_opening(); return 0; } @@ -2722,8 +2745,10 @@ static int ptmx_open(struct inode * inode, struct file * filp) check_tty_count(tty, "tty_open"); retval = ptm_driver->open(tty, filp); - if (!retval) + if (!retval) { + tty_audit_opening(); return 0; + } out1: release_dev(filp); return retval; @@ -3163,14 +3188,13 @@ static int tiocsetd(struct tty_struct *tty, int __user *p) static int send_break(struct tty_struct *tty, unsigned int duration) { - if (mutex_lock_interruptible(&tty->atomic_write_lock)) + if (tty_write_lock(tty, 0) < 0) return -EINTR; tty->driver->break_ctl(tty, -1); - if (!signal_pending(current)) { + if (!signal_pending(current)) msleep_interruptible(duration); - } tty->driver->break_ctl(tty, 0); - mutex_unlock(&tty->atomic_write_lock); + tty_write_unlock(tty); if (signal_pending(current)) return -EINTR; return 0; @@ -3739,9 +3763,8 @@ struct tty_driver *alloc_tty_driver(int lines) { struct tty_driver *driver; - driver = kmalloc(sizeof(struct tty_driver), GFP_KERNEL); + driver = kzalloc(sizeof(struct tty_driver), GFP_KERNEL); if (driver) { - memset(driver, 0, sizeof(struct tty_driver)); driver->magic = TTY_DRIVER_MAGIC; driver->num = lines; /* later we'll move allocation of tables here */ diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c index fd471cb..3423e9ee 100644 --- a/drivers/char/tty_ioctl.c +++ b/drivers/char/tty_ioctl.c @@ -52,8 +52,6 @@ void tty_wait_until_sent(struct tty_struct * tty, long timeout) { - DECLARE_WAITQUEUE(wait, current); - #ifdef TTY_DEBUG_WAIT_UNTIL_SENT char buf[64]; @@ -61,26 +59,13 @@ void tty_wait_until_sent(struct tty_struct * tty, long timeout) #endif if (!tty->driver->chars_in_buffer) return; - add_wait_queue(&tty->write_wait, &wait); if (!timeout) timeout = MAX_SCHEDULE_TIMEOUT; - do { -#ifdef TTY_DEBUG_WAIT_UNTIL_SENT - printk(KERN_DEBUG "waiting %s...(%d)\n", tty_name(tty, buf), - tty->driver->chars_in_buffer(tty)); -#endif - set_current_state(TASK_INTERRUPTIBLE); - if (signal_pending(current)) - goto stop_waiting; - if (!tty->driver->chars_in_buffer(tty)) - break; - timeout = schedule_timeout(timeout); - } while (timeout); + if (wait_event_interruptible_timeout(tty->write_wait, + !tty->driver->chars_in_buffer(tty), timeout)) + return; if (tty->driver->wait_until_sent) tty->driver->wait_until_sent(tty, timeout); -stop_waiting: - set_current_state(TASK_RUNNING); - remove_wait_queue(&tty->write_wait, &wait); } EXPORT_SYMBOL(tty_wait_until_sent); @@ -276,13 +261,12 @@ void tty_termios_encode_baud_rate(struct ktermios *termios, speed_t ibaud, speed termios->c_cflag |= (baud_bits[i] << IBSHIFT); ifound = i; } - } - while(++i < n_baud_table); + } while (++i < n_baud_table); if (ofound == -1) termios->c_cflag |= BOTHER; /* Set exact input bits only if the input and output differ or the user already did */ - if (ifound == -1 && (ibaud != obaud || ibinput)) + if (ifound == -1 && (ibaud != obaud || ibinput)) termios->c_cflag |= (BOTHER << IBSHIFT); } @@ -575,7 +559,7 @@ static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb) return -EFAULT; mutex_lock(&tty->termios_mutex); - termios = *tty->termios; + termios = *tty->termios; termios.c_cc[VERASE] = tmp.sg_erase; termios.c_cc[VKILL] = tmp.sg_kill; set_sgflags(&termios, tmp.sg_flags); @@ -667,7 +651,7 @@ static int send_prio_char(struct tty_struct *tty, char ch) return 0; } - if (mutex_lock_interruptible(&tty->atomic_write_lock)) + if (tty_write_lock(tty, 0) < 0) return -ERESTARTSYS; if (was_stopped) @@ -675,7 +659,7 @@ static int send_prio_char(struct tty_struct *tty, char ch) tty->driver->write(tty, &ch, 1); if (was_stopped) stop_tty(tty); - mutex_unlock(&tty->atomic_write_lock); + tty_write_unlock(tty); return 0; } diff --git a/drivers/connector/Kconfig b/drivers/connector/Kconfig index e0bdc0d..100bfd42 100644 --- a/drivers/connector/Kconfig +++ b/drivers/connector/Kconfig @@ -1,6 +1,5 @@ -menu "Connector - unified userspace <-> kernelspace linker" -config CONNECTOR +menuconfig CONNECTOR tristate "Connector - unified userspace <-> kernelspace linker" depends on NET ---help--- @@ -10,6 +9,8 @@ config CONNECTOR Connector support can also be built as a module. If so, the module will be called cn.ko. +if CONNECTOR + config PROC_EVENTS boolean "Report process events to userspace" depends on CONNECTOR=y @@ -18,4 +19,4 @@ config PROC_EVENTS Provide a connector that reports process events to userspace. Send events such as fork, exec, id change (uid, gid, suid, etc), and exit. -endmenu +endif # CONNECTOR diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig index bb90cbd..84ebfcc 100644 --- a/drivers/crypto/Kconfig +++ b/drivers/crypto/Kconfig @@ -1,4 +1,9 @@ -menu "Hardware crypto devices" + +menuconfig CRYPTO_HW + bool "Hardware crypto devices" + default y + +if CRYPTO_HW config CRYPTO_DEV_PADLOCK tristate "Support for VIA PadLock ACE" @@ -78,4 +83,4 @@ config ZCRYPT_MONOLITHIC that contains all parts of the crypto device driver (ap bus, request router and all the card drivers). -endmenu +endif # CRYPTO_HW diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig index b31756d..8f670da 100644 --- a/drivers/dma/Kconfig +++ b/drivers/dma/Kconfig @@ -3,7 +3,7 @@ # menu "DMA Engine support" - depends on !S390 + depends on HAS_DMA config DMA_ENGINE bool "Support for DMA engines" diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig index 807c402..debf1d8 100644 --- a/drivers/edac/Kconfig +++ b/drivers/edac/Kconfig @@ -6,11 +6,9 @@ # $Id: Kconfig,v 1.4.2.7 2005/07/08 22:05:38 dsp_llnl Exp $ # -menu 'EDAC - error detection and reporting (RAS) (EXPERIMENTAL)' +menuconfig EDAC + tristate "EDAC - error detection and reporting (EXPERIMENTAL)" depends on HAS_IOMEM - -config EDAC - tristate "EDAC core system error reporting (EXPERIMENTAL)" depends on X86 && EXPERIMENTAL help EDAC is designed to report errors in the core system. @@ -30,13 +28,12 @@ config EDAC There is also a mailing list for the EDAC project, which can be found via the sourceforge page. +if EDAC comment "Reporting subsystems" - depends on EDAC config EDAC_DEBUG bool "Debugging" - depends on EDAC help This turns on debugging information for the entire EDAC sub-system. You can insert module with "debug_level=x", current @@ -45,7 +42,6 @@ config EDAC_DEBUG config EDAC_MM_EDAC tristate "Main Memory EDAC (Error Detection And Correction) reporting" - depends on EDAC default y help Some systems are able to detect and correct errors in main @@ -100,15 +96,13 @@ config EDAC_R82600 choice prompt "Error detecting method" - depends on EDAC default EDAC_POLL config EDAC_POLL bool "Poll for errors" - depends on EDAC help Poll the chipset periodically to detect errors. endchoice -endmenu +endif # EDAC diff --git a/drivers/firmware/edd.c b/drivers/firmware/edd.c index 1523227..0fb730e 100644 --- a/drivers/firmware/edd.c +++ b/drivers/firmware/edd.c @@ -669,7 +669,7 @@ edd_get_pci_dev(struct edd_device *edev) struct edd_info *info = edd_dev_get_info(edev); if (edd_dev_is_type(edev, "PCI")) { - return pci_find_slot(info->params.interface_path.pci.bus, + return pci_get_bus_and_slot(info->params.interface_path.pci.bus, PCI_DEVFN(info->params.interface_path.pci.slot, info->params.interface_path.pci. function)); @@ -682,9 +682,12 @@ edd_create_symlink_to_pcidev(struct edd_device *edev) { struct pci_dev *pci_dev = edd_get_pci_dev(edev); + int ret; if (!pci_dev) return 1; - return sysfs_create_link(&edev->kobj,&pci_dev->dev.kobj,"pci_dev"); + ret = sysfs_create_link(&edev->kobj,&pci_dev->dev.kobj,"pci_dev"); + pci_dev_put(pci_dev); + return ret; } static inline void diff --git a/drivers/firmware/pcdp.c b/drivers/firmware/pcdp.c index 2b4b76e..58e9f8e 100644 --- a/drivers/firmware/pcdp.c +++ b/drivers/firmware/pcdp.c @@ -15,6 +15,7 @@ #include <linux/console.h> #include <linux/efi.h> #include <linux/serial.h> +#include <linux/serial_8250.h> #include <asm/vga.h> #include "pcdp.h" @@ -27,7 +28,7 @@ setup_serial_console(struct pcdp_uart *uart) char parity; mmio = (uart->addr.space_id == ACPI_ADR_SPACE_SYSTEM_MEMORY); - p += sprintf(p, "console=uart,%s,0x%lx", + p += sprintf(p, "uart8250,%s,0x%lx", mmio ? "mmio" : "io", uart->addr.address); if (uart->baud) { p += sprintf(p, ",%lu", uart->baud); @@ -41,7 +42,8 @@ setup_serial_console(struct pcdp_uart *uart) } } - return early_serial_console_init(options); + add_preferred_console("uart", 8250, &options[9]); + return setup_early_serial8250_console(options); #else return -ENODEV; #endif diff --git a/drivers/macintosh/adb.c b/drivers/macintosh/adb.c index adfea3c..bc77c5e 100644 --- a/drivers/macintosh/adb.c +++ b/drivers/macintosh/adb.c @@ -248,21 +248,15 @@ static int adb_scan_bus(void) static int adb_probe_task(void *x) { - sigset_t blocked; - strcpy(current->comm, "kadbprobe"); - sigfillset(&blocked); - sigprocmask(SIG_BLOCK, &blocked, NULL); - flush_signals(current); - printk(KERN_INFO "adb: starting probe task...\n"); do_adb_reset_bus(); printk(KERN_INFO "adb: finished probe task...\n"); - + adb_probe_task_pid = 0; up(&adb_probe_mutex); - + return 0; } diff --git a/drivers/message/i2o/Kconfig b/drivers/message/i2o/Kconfig index f4ac21e..5afa0e3 100644 --- a/drivers/message/i2o/Kconfig +++ b/drivers/message/i2o/Kconfig @@ -1,9 +1,6 @@ -menu "I2O device support" - depends on PCI - -config I2O - tristate "I2O support" +menuconfig I2O + tristate "I2O device support" depends on PCI ---help--- The Intelligent Input/Output (I2O) architecture allows hardware @@ -25,9 +22,10 @@ config I2O If unsure, say N. +if I2O + config I2O_LCT_NOTIFY_ON_CHANGES bool "Enable LCT notification" - depends on I2O default y ---help--- Only say N here if you have a I2O controller from SUN. The SUN @@ -39,7 +37,6 @@ config I2O_LCT_NOTIFY_ON_CHANGES config I2O_EXT_ADAPTEC bool "Enable Adaptec extensions" - depends on I2O default y ---help--- Say Y for support of raidutils for Adaptec I2O controllers. You also @@ -57,7 +54,7 @@ config I2O_EXT_ADAPTEC_DMA64 config I2O_CONFIG tristate "I2O Configuration support" - depends on I2O + depends on VIRT_TO_BUS ---help--- Say Y for support of the configuration interface for the I2O adapters. If you have a RAID controller from Adaptec and you want to use the @@ -78,7 +75,6 @@ config I2O_CONFIG_OLD_IOCTL config I2O_BUS tristate "I2O Bus Adapter OSM" - depends on I2O ---help--- Include support for the I2O Bus Adapter OSM. The Bus Adapter OSM provides access to the busses on the I2O controller. The main purpose @@ -89,7 +85,7 @@ config I2O_BUS config I2O_BLOCK tristate "I2O Block OSM" - depends on I2O && BLOCK + depends on BLOCK ---help--- Include support for the I2O Block OSM. The Block OSM presents disk and other structured block devices to the operating system. If you @@ -102,7 +98,7 @@ config I2O_BLOCK config I2O_SCSI tristate "I2O SCSI OSM" - depends on I2O && SCSI + depends on SCSI ---help--- Allows direct SCSI access to SCSI devices on a SCSI or FibreChannel I2O controller. You can use both the SCSI and Block OSM together if @@ -114,7 +110,6 @@ config I2O_SCSI config I2O_PROC tristate "I2O /proc support" - depends on I2O ---help--- If you say Y here and to "/proc file system support", you will be able to read I2O related information from the virtual directory @@ -123,5 +118,4 @@ config I2O_PROC To compile this support as a module, choose M here: the module will be called i2o_proc. -endmenu - +endif # I2O diff --git a/drivers/message/i2o/device.c b/drivers/message/i2o/device.c index 611adc3..489d7c5 100644 --- a/drivers/message/i2o/device.c +++ b/drivers/message/i2o/device.c @@ -62,7 +62,7 @@ int i2o_device_claim(struct i2o_device *dev) { int rc = 0; - down(&dev->lock); + mutex_lock(&dev->lock); rc = i2o_device_issue_claim(dev, I2O_CMD_UTIL_CLAIM, I2O_CLAIM_PRIMARY); if (!rc) @@ -72,7 +72,7 @@ int i2o_device_claim(struct i2o_device *dev) pr_debug("i2o: claim of device %d failed %d\n", dev->lct_data.tid, rc); - up(&dev->lock); + mutex_unlock(&dev->lock); return rc; } @@ -96,7 +96,7 @@ int i2o_device_claim_release(struct i2o_device *dev) int tries; int rc = 0; - down(&dev->lock); + mutex_lock(&dev->lock); /* * If the controller takes a nonblocking approach to @@ -118,7 +118,7 @@ int i2o_device_claim_release(struct i2o_device *dev) pr_debug("i2o: claim release of device %d failed %d\n", dev->lct_data.tid, rc); - up(&dev->lock); + mutex_unlock(&dev->lock); return rc; } @@ -198,7 +198,7 @@ static struct i2o_device *i2o_device_alloc(void) return ERR_PTR(-ENOMEM); INIT_LIST_HEAD(&dev->list); - init_MUTEX(&dev->lock); + mutex_init(&dev->lock); dev->device.bus = &i2o_bus_type; dev->device.release = &i2o_device_release; @@ -326,7 +326,7 @@ int i2o_device_parse_lct(struct i2o_controller *c) u16 table_size; u32 buf; - down(&c->lct_lock); + mutex_lock(&c->lct_lock); kfree(c->lct); @@ -335,7 +335,7 @@ int i2o_device_parse_lct(struct i2o_controller *c) lct = c->lct = kmalloc(table_size * 4, GFP_KERNEL); if (!lct) { - up(&c->lct_lock); + mutex_unlock(&c->lct_lock); return -ENOMEM; } @@ -408,7 +408,7 @@ int i2o_device_parse_lct(struct i2o_controller *c) i2o_device_remove(dev); } - up(&c->lct_lock); + mutex_unlock(&c->lct_lock); return 0; } diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c index 5278aad..c13b932 100644 --- a/drivers/message/i2o/exec-osm.c +++ b/drivers/message/i2o/exec-osm.c @@ -537,7 +537,7 @@ static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind) struct device *dev; struct i2o_message *msg; - down(&c->lct_lock); + mutex_lock(&c->lct_lock); dev = &c->pdev->dev; @@ -561,7 +561,7 @@ static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind) i2o_msg_post(c, msg); - up(&c->lct_lock); + mutex_unlock(&c->lct_lock); return 0; }; diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c index 3305c12..a1ec16a 100644 --- a/drivers/message/i2o/iop.c +++ b/drivers/message/i2o/iop.c @@ -1067,7 +1067,7 @@ struct i2o_controller *i2o_iop_alloc(void) INIT_LIST_HEAD(&c->devices); spin_lock_init(&c->lock); - init_MUTEX(&c->lct_lock); + mutex_init(&c->lct_lock); device_initialize(&c->device); diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index bd601ef..a92b872 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -2,7 +2,11 @@ # Misc strange devices # -menu "Misc devices" +menuconfig MISC_DEVICES + bool "Misc devices" + default y + +if MISC_DEVICES config IBM_ASM tristate "Device driver for IBM RSA service processor" @@ -192,4 +196,4 @@ config THINKPAD_ACPI_BAY If you are not sure, say Y here. -endmenu +endif # MISC_DEVICES diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index 8ee0321..9623eaf 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c @@ -1917,7 +1917,8 @@ end: */ static int sony_pic_disable(struct acpi_device *device) { - if (ACPI_FAILURE(acpi_evaluate_object(device->handle, "_DIS", 0, NULL))) + if (ACPI_FAILURE(acpi_evaluate_object(device->handle, + "_DIS", NULL, NULL))) return -ENXIO; dprintk("Device disabled\n"); diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index d17d64e..713ab05 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -405,22 +405,6 @@ config ATARILANCE on the AMD Lance chipset: RieblCard (with or without battery), or PAMCard VME (also the version by Rhotron, with different addresses). -config ATARI_BIONET - tristate "BioNet-100 support" - depends on ATARI && ATARI_ACSI && BROKEN - help - Say Y to include support for BioData's BioNet-100 Ethernet adapter - for the ACSI port. The driver works (has to work...) with a polled - I/O scheme, so it's rather slow :-( - -config ATARI_PAMSNET - tristate "PAMsNet support" - depends on ATARI && ATARI_ACSI && BROKEN - help - Say Y to include support for the PAMsNet Ethernet adapter for the - ACSI port ("ACSI node"). The driver works (has to work...) with a - polled I/O scheme, so it's rather slow :-( - config SUN3LANCE tristate "Sun3/Sun3x on-board LANCE support" depends on SUN3 || SUN3X @@ -604,6 +588,12 @@ config CASSINI Support for the Sun Cassini chip, aka Sun GigaSwift Ethernet. See also <http://www.sun.com/products-n-solutions/hardware/docs/pdf/817-4341-10.pdf> +config SUNVNET + tristate "Sun Virtual Network support" + depends on SUN_LDOMS + help + Support for virtual network devices under Sun Logical Domains. + config NET_VENDOR_3COM bool "3COM cards" depends on ISA || EISA || MCA || PCI diff --git a/drivers/net/Makefile b/drivers/net/Makefile index c26b867..eb41676 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -34,6 +34,7 @@ obj-$(CONFIG_SUNBMAC) += sunbmac.o obj-$(CONFIG_MYRI_SBUS) += myri_sbus.o obj-$(CONFIG_SUNGEM) += sungem.o sungem_phy.o obj-$(CONFIG_CASSINI) += cassini.o +obj-$(CONFIG_SUNVNET) += sunvnet.o obj-$(CONFIG_MACE) += mace.o obj-$(CONFIG_BMAC) += bmac.o @@ -180,8 +181,6 @@ obj-$(CONFIG_MIPS_SIM_NET) += mipsnet.o obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o obj-$(CONFIG_DECLANCE) += declance.o obj-$(CONFIG_ATARILANCE) += atarilance.o -obj-$(CONFIG_ATARI_BIONET) += atari_bionet.o -obj-$(CONFIG_ATARI_PAMSNET) += atari_pamsnet.o obj-$(CONFIG_A2065) += a2065.o obj-$(CONFIG_HYDRA) += hydra.o obj-$(CONFIG_ARIADNE) += ariadne.o diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 1c3e293..3b79c6c 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -75,8 +75,6 @@ extern struct net_device *atarilance_probe(int unit); extern struct net_device *sun3lance_probe(int unit); extern struct net_device *sun3_82586_probe(int unit); extern struct net_device *apne_probe(int unit); -extern struct net_device *bionet_probe(int unit); -extern struct net_device *pamsnet_probe(int unit); extern struct net_device *cs89x0_probe(int unit); extern struct net_device *hplance_probe(int unit); extern struct net_device *bagetlance_probe(int unit); @@ -264,12 +262,6 @@ static struct devprobe2 m68k_probes[] __initdata = { #ifdef CONFIG_APNE /* A1200 PCMCIA NE2000 */ {apne_probe, 0}, #endif -#ifdef CONFIG_ATARI_BIONET /* Atari Bionet Ethernet board */ - {bionet_probe, 0}, -#endif -#ifdef CONFIG_ATARI_PAMSNET /* Atari PAMsNet Ethernet board */ - {pamsnet_probe, 0}, -#endif #ifdef CONFIG_MVME147_NET /* MVME147 internal Ethernet */ {mvme147lance_probe, 0}, #endif diff --git a/drivers/net/atari_bionet.c b/drivers/net/atari_bionet.c deleted file mode 100644 index 3d87bd2..0000000 --- a/drivers/net/atari_bionet.c +++ /dev/null @@ -1,675 +0,0 @@ -/* bionet.c BioNet-100 device driver for linux68k. - * - * Version: @(#)bionet.c 1.0 02/06/96 - * - * Author: Hartmut Laue <laue@ifk-mp.uni-kiel.de> - * and Torsten Narjes <narjes@ifk-mp.uni-kiel.de> - * - * Little adaptions for integration into pl7 by Roman Hodek - * - * Some changes in bionet_poll_rx by Karl-Heinz Lohner - * - What is it ? - ------------ - This driver controls the BIONET-100 LAN-Adapter which connects - an ATARI ST/TT via the ACSI-port to an Ethernet-based network. - - This version can be compiled as a loadable module (See the - compile command at the bottom of this file). - At load time, you can optionally set the debugging level and the - fastest response time on the command line of 'insmod'. - - 'bionet_debug' - controls the amount of diagnostic messages: - 0 : no messages - >0 : see code for meaning of printed messages - - 'bionet_min_poll_time' (always >=1) - gives the time (in jiffies) between polls. Low values - increase the system load (beware!) - - When loaded, a net device with the name 'bio0' becomes available, - which can be controlled with the usual 'ifconfig' command. - - It is possible to compile this driver into the kernel like other - (net) drivers. For this purpose, some source files (e.g. config-files - makefiles, Space.c) must be changed accordingly. (You may refer to - other drivers how to do it.) In this case, the device will be detected - at boot time and (probably) appear as 'eth0'. - - This code is based on several sources: - - The driver code for a parallel port ethernet adapter by - Donald Becker (see file 'atp.c' from the PC linux distribution) - - The ACSI code by Roman Hodek for the ATARI-ACSI harddisk support - and DMA handling. - - Very limited information about moving packets in and out of the - BIONET-adapter from the TCP package for TOS by BioData GmbH. - - Theory of Operation - ------------------- - Because the ATARI DMA port is usually shared between several - devices (eg. harddisk, floppy) we cannot block the ACSI bus - while waiting for interrupts. Therefore we use a polling mechanism - to fetch packets from the adapter. For the same reason, we send - packets without checking that the previous packet has been sent to - the LAN. We rely on the higher levels of the networking code to detect - missing packets and resend them. - - Before we access the ATARI DMA controller, we check if another - process is using the DMA. If not, we lock the DMA, perform one or - more packet transfers and unlock the DMA before returning. - We do not use 'stdma_lock' unconditionally because it is unclear - if the networking code can be set to sleep, which will happen if - another (possibly slow) device is using the DMA controller. - - The polling is done via timer interrupts which periodically - 'simulate' an interrupt from the Ethernet adapter. The time (in jiffies) - between polls varies depending on an estimate of the net activity. - The allowed range is given by the variable 'bionet_min_poll_time' - for the lower (fastest) limit and the constant 'MAX_POLL_TIME' - for the higher (slowest) limit. - - Whenever a packet arrives, we switch to fastest response by setting - the polling time to its lowest limit. If the following poll fails, - because no packets have arrived, we increase the time for the next - poll. When the net activity is low, the polling time effectively - stays at its maximum value, resulting in the lowest load for the - machine. - */ - -#define MAX_POLL_TIME 10 - -static char version[] = - "bionet.c:v1.0 06-feb-96 (c) Hartmut Laue.\n"; - -#include <linux/module.h> - -#include <linux/errno.h> -#include <linux/kernel.h> -#include <linux/jiffies.h> -#include <linux/types.h> -#include <linux/fcntl.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/in.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/delay.h> -#include <linux/timer.h> -#include <linux/init.h> -#include <linux/bitops.h> - -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> - -#include <asm/setup.h> -#include <asm/pgtable.h> -#include <asm/system.h> -#include <asm/io.h> -#include <asm/dma.h> -#include <asm/atarihw.h> -#include <asm/atariints.h> -#include <asm/atari_acsi.h> -#include <asm/atari_stdma.h> - - -/* use 0 for production, 1 for verification, >2 for debug - */ -#ifndef NET_DEBUG -#define NET_DEBUG 0 -#endif -/* - * Global variable 'bionet_debug'. Can be set at load time by 'insmod' - */ -unsigned int bionet_debug = NET_DEBUG; -module_param(bionet_debug, int, 0); -MODULE_PARM_DESC(bionet_debug, "bionet debug level (0-2)"); -MODULE_LICENSE("GPL"); - -static unsigned int bionet_min_poll_time = 2; - - -/* Information that need to be kept for each board. - */ -struct net_local { - struct net_device_stats stats; - long open_time; /* for debugging */ - int poll_time; /* polling time varies with net load */ -}; - -static struct nic_pkt_s { /* packet format */ - unsigned char status; - unsigned char dummy; - unsigned char l_lo, l_hi; - unsigned char buffer[3000]; -} *nic_packet; -unsigned char *phys_nic_packet; - -/* Index to functions, as function prototypes. - */ -static int bionet_open(struct net_device *dev); -static int bionet_send_packet(struct sk_buff *skb, struct net_device *dev); -static void bionet_poll_rx(struct net_device *); -static int bionet_close(struct net_device *dev); -static struct net_device_stats *net_get_stats(struct net_device *dev); -static void bionet_tick(unsigned long); - -static DEFINE_TIMER(bionet_timer, bionet_tick, 0, 0); - -#define STRAM_ADDR(a) (((a) & 0xff000000) == 0) - -/* The following routines access the ethernet board connected to the - * ACSI port via the st_dma chip. - */ -#define NODE_ADR 0x60 - -#define C_READ 8 -#define C_WRITE 0x0a -#define C_GETEA 0x0f -#define C_SETCR 0x0e - -static int -sendcmd(unsigned int a0, unsigned int mod, unsigned int cmd) { - unsigned int c; - - dma_wd.dma_mode_status = (mod | ((a0) ? 2 : 0) | 0x88); - dma_wd.fdc_acces_seccount = cmd; - dma_wd.dma_mode_status = (mod | 0x8a); - - if( !acsi_wait_for_IRQ(HZ/2) ) /* wait for cmd ack */ - return -1; /* timeout */ - - c = dma_wd.fdc_acces_seccount; - return (c & 0xff); -} - - -static void -set_status(int cr) { - sendcmd(0,0x100,NODE_ADR | C_SETCR); /* CMD: SET CR */ - sendcmd(1,0x100,cr); - - dma_wd.dma_mode_status = 0x80; -} - -static int -get_status(unsigned char *adr) { - int i,c; - - DISABLE_IRQ(); - c = sendcmd(0,0x00,NODE_ADR | C_GETEA); /* CMD: GET ETH ADR*/ - if( c < 0 ) goto gsend; - - /* now read status bytes */ - - for (i=0; i<6; i++) { - dma_wd.fdc_acces_seccount = 0; /* request next byte */ - - if( !acsi_wait_for_IRQ(HZ/2) ) { /* wait for cmd ack */ - c = -1; - goto gsend; /* timeout */ - } - c = dma_wd.fdc_acces_seccount; - *adr++ = (unsigned char)c; - } - c = 1; -gsend: - dma_wd.dma_mode_status = 0x80; - return c; -} - -static irqreturn_t -bionet_intr(int irq, void *data) { - return IRQ_HANDLED; -} - - -static int -get_frame(unsigned long paddr, int odd) { - int c; - unsigned long flags; - - DISABLE_IRQ(); - local_irq_save(flags); - - dma_wd.dma_mode_status = 0x9a; - dma_wd.dma_mode_status = 0x19a; - dma_wd.dma_mode_status = 0x9a; - dma_wd.fdc_acces_seccount = 0x04; /* sector count (was 5) */ - dma_wd.dma_lo = (unsigned char)paddr; - paddr >>= 8; - dma_wd.dma_md = (unsigned char)paddr; - paddr >>= 8; - dma_wd.dma_hi = (unsigned char)paddr; - local_irq_restore(flags); - - c = sendcmd(0,0x00,NODE_ADR | C_READ); /* CMD: READ */ - if( c < 128 ) goto rend; - - /* now read block */ - - c = sendcmd(1,0x00,odd); /* odd flag for address shift */ - dma_wd.dma_mode_status = 0x0a; - - if( !acsi_wait_for_IRQ(100) ) { /* wait for DMA to complete */ - c = -1; - goto rend; - } - dma_wd.dma_mode_status = 0x8a; - dma_wd.dma_mode_status = 0x18a; - dma_wd.dma_mode_status = 0x8a; - c = dma_wd.fdc_acces_seccount; - - dma_wd.dma_mode_status = 0x88; - c = dma_wd.fdc_acces_seccount; - c = 1; - -rend: - dma_wd.dma_mode_status = 0x80; - udelay(40); - acsi_wait_for_noIRQ(20); - return c; -} - - -static int -hardware_send_packet(unsigned long paddr, int cnt) { - unsigned int c; - unsigned long flags; - - DISABLE_IRQ(); - local_irq_save(flags); - - dma_wd.dma_mode_status = 0x19a; - dma_wd.dma_mode_status = 0x9a; - dma_wd.dma_mode_status = 0x19a; - dma_wd.dma_lo = (unsigned char)paddr; - paddr >>= 8; - dma_wd.dma_md = (unsigned char)paddr; - paddr >>= 8; - dma_wd.dma_hi = (unsigned char)paddr; - - dma_wd.fdc_acces_seccount = 0x4; /* sector count */ - local_irq_restore(flags); - - c = sendcmd(0,0x100,NODE_ADR | C_WRITE); /* CMD: WRITE */ - c = sendcmd(1,0x100,cnt&0xff); - c = sendcmd(1,0x100,cnt>>8); - - /* now write block */ - - dma_wd.dma_mode_status = 0x10a; /* DMA enable */ - if( !acsi_wait_for_IRQ(100) ) /* wait for DMA to complete */ - goto end; - - dma_wd.dma_mode_status = 0x19a; /* DMA disable ! */ - c = dma_wd.fdc_acces_seccount; - -end: - c = sendcmd(1,0x100,0); - c = sendcmd(1,0x100,0); - - dma_wd.dma_mode_status = 0x180; - udelay(40); - acsi_wait_for_noIRQ(20); - return( c & 0x02); -} - - -/* Check for a network adaptor of this type, and return '0' if one exists. - */ -struct net_device * __init bionet_probe(int unit) -{ - struct net_device *dev; - unsigned char station_addr[6]; - static unsigned version_printed; - static int no_more_found; /* avoid "Probing for..." printed 4 times */ - int i; - int err; - - if (!MACH_IS_ATARI || no_more_found) - return ERR_PTR(-ENODEV); - - dev = alloc_etherdev(sizeof(struct net_local)); - if (!dev) - return ERR_PTR(-ENOMEM); - if (unit >= 0) { - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - } - SET_MODULE_OWNER(dev); - - printk("Probing for BioNet 100 Adapter...\n"); - - stdma_lock(bionet_intr, NULL); - i = get_status(station_addr); /* Read the station address PROM. */ - ENABLE_IRQ(); - stdma_release(); - - /* Check the first three octets of the S.A. for the manufactor's code. - */ - - if( i < 0 - || station_addr[0] != 'B' - || station_addr[1] != 'I' - || station_addr[2] != 'O' ) { - no_more_found = 1; - printk( "No BioNet 100 found.\n" ); - free_netdev(dev); - return ERR_PTR(-ENODEV); - } - - if (bionet_debug > 0 && version_printed++ == 0) - printk(version); - - printk("%s: %s found, eth-addr: %02x-%02x-%02x:%02x-%02x-%02x.\n", - dev->name, "BioNet 100", - station_addr[0], station_addr[1], station_addr[2], - station_addr[3], station_addr[4], station_addr[5]); - - /* Initialize the device structure. */ - - nic_packet = (struct nic_pkt_s *)acsi_buffer; - phys_nic_packet = (unsigned char *)phys_acsi_buffer; - if (bionet_debug > 0) { - printk("nic_packet at 0x%p, phys at 0x%p\n", - nic_packet, phys_nic_packet ); - } - - dev->open = bionet_open; - dev->stop = bionet_close; - dev->hard_start_xmit = bionet_send_packet; - dev->get_stats = net_get_stats; - - /* Fill in the fields of the device structure with ethernet-generic - * values. This should be in a common file instead of per-driver. - */ - - for (i = 0; i < ETH_ALEN; i++) { -#if 0 - dev->broadcast[i] = 0xff; -#endif - dev->dev_addr[i] = station_addr[i]; - } - err = register_netdev(dev); - if (!err) - return dev; - free_netdev(dev); - return ERR_PTR(err); -} - -/* Open/initialize the board. This is called (in the current kernel) - sometime after booting when the 'ifconfig' program is run. - - This routine should set everything up anew at each open, even - registers that "should" only need to be set once at boot, so that - there is non-reboot way to recover if something goes wrong. - */ -static int -bionet_open(struct net_device *dev) { - struct net_local *lp = netdev_priv(dev); - - if (bionet_debug > 0) - printk("bionet_open\n"); - stdma_lock(bionet_intr, NULL); - - /* Reset the hardware here. - */ - set_status(4); - lp->open_time = 0; /*jiffies*/ - lp->poll_time = MAX_POLL_TIME; - - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - - stdma_release(); - bionet_timer.data = (long)dev; - bionet_timer.expires = jiffies + lp->poll_time; - add_timer(&bionet_timer); - return 0; -} - -static int -bionet_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct net_local *lp = netdev_priv(dev); - unsigned long flags; - - /* Block a timer-based transmit from overlapping. This could better be - * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. - */ - local_irq_save(flags); - - if (stdma_islocked()) { - local_irq_restore(flags); - lp->stats.tx_errors++; - } - else { - int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - unsigned long buf = virt_to_phys(skb->data); - int stat; - - stdma_lock(bionet_intr, NULL); - local_irq_restore(flags); - if( !STRAM_ADDR(buf+length-1) ) { - skb_copy_from_linear_data(skb, nic_packet->buffer, - length); - buf = (unsigned long)&((struct nic_pkt_s *)phys_nic_packet)->buffer; - } - - if (bionet_debug >1) { - u_char *data = nic_packet->buffer, *p; - int i; - - printk( "%s: TX pkt type 0x%4x from ", dev->name, - ((u_short *)data)[6]); - - for( p = &data[6], i = 0; i < 6; i++ ) - printk("%02x%s", *p++,i != 5 ? ":" : "" ); - printk(" to "); - - for( p = data, i = 0; i < 6; i++ ) - printk("%02x%s", *p++,i != 5 ? ":" : "" "\n" ); - - printk( "%s: ", dev->name ); - printk(" data %02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x" - " %02x%02x%02x%02x len %d\n", - data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19], - data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27], - data[28], data[29], data[30], data[31], data[32], data[33], - length ); - } - dma_cache_maintenance(buf, length, 1); - - stat = hardware_send_packet(buf, length); - ENABLE_IRQ(); - stdma_release(); - - dev->trans_start = jiffies; - dev->tbusy = 0; - lp->stats.tx_packets++; - lp->stats.tx_bytes+=length; - } - dev_kfree_skb(skb); - - return 0; -} - -/* We have a good packet(s), get it/them out of the buffers. - */ -static void -bionet_poll_rx(struct net_device *dev) { - struct net_local *lp = netdev_priv(dev); - int boguscount = 10; - int pkt_len, status; - unsigned long flags; - - local_irq_save(flags); - /* ++roman: Take care at locking the ST-DMA... This must be done with ints - * off, since otherwise an int could slip in between the question and the - * locking itself, and then we'd go to sleep... And locking itself is - * necessary to keep the floppy_change timer from working with ST-DMA - * registers. */ - if (stdma_islocked()) { - local_irq_restore(flags); - return; - } - stdma_lock(bionet_intr, NULL); - DISABLE_IRQ(); - local_irq_restore(flags); - - if( lp->poll_time < MAX_POLL_TIME ) lp->poll_time++; - - while(boguscount--) { - status = get_frame((unsigned long)phys_nic_packet, 0); - - if( status == 0 ) break; - - /* Good packet... */ - - dma_cache_maintenance((unsigned long)phys_nic_packet, 1520, 0); - - pkt_len = (nic_packet->l_hi << 8) | nic_packet->l_lo; - - lp->poll_time = bionet_min_poll_time; /* fast poll */ - if( pkt_len >= 60 && pkt_len <= 1520 ) { - /* ^^^^ war 1514 KHL */ - /* Malloc up new buffer. - */ - struct sk_buff *skb = dev_alloc_skb( pkt_len + 2 ); - if (skb == NULL) { - printk("%s: Memory squeeze, dropping packet.\n", - dev->name); - lp->stats.rx_dropped++; - break; - } - - skb_reserve( skb, 2 ); /* 16 Byte align */ - skb_put( skb, pkt_len ); /* make room */ - - /* 'skb->data' points to the start of sk_buff data area. - */ - skb_copy_to_linear_data(skb, nic_packet->buffer, - pkt_len); - skb->protocol = eth_type_trans( skb, dev ); - netif_rx(skb); - dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes+=pkt_len; - - /* If any worth-while packets have been received, dev_rint() - has done a mark_bh(INET_BH) for us and will work on them - when we get to the bottom-half routine. - */ - - if (bionet_debug >1) { - u_char *data = nic_packet->buffer, *p; - int i; - - printk( "%s: RX pkt type 0x%4x from ", dev->name, - ((u_short *)data)[6]); - - - for( p = &data[6], i = 0; i < 6; i++ ) - printk("%02x%s", *p++,i != 5 ? ":" : "" ); - printk(" to "); - for( p = data, i = 0; i < 6; i++ ) - printk("%02x%s", *p++,i != 5 ? ":" : "" "\n" ); - - printk( "%s: ", dev->name ); - printk(" data %02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x %02x%02x%02x%02x" - " %02x%02x%02x%02x len %d\n", - data[12], data[13], data[14], data[15], data[16], data[17], data[18], data[19], - data[20], data[21], data[22], data[23], data[24], data[25], data[26], data[27], - data[28], data[29], data[30], data[31], data[32], data[33], - pkt_len ); - } - } - else { - printk(" Packet has wrong length: %04d bytes\n", pkt_len); - lp->stats.rx_errors++; - } - } - stdma_release(); - ENABLE_IRQ(); - return; -} - -/* bionet_tick: called by bionet_timer. Reads packets from the adapter, - * passes them to the higher layers and restarts the timer. - */ -static void -bionet_tick(unsigned long data) { - struct net_device *dev = (struct net_device *)data; - struct net_local *lp = netdev_priv(dev); - - if( bionet_debug > 0 && (lp->open_time++ & 7) == 8 ) - printk("bionet_tick: %ld\n", lp->open_time); - - if( !stdma_islocked() ) bionet_poll_rx(dev); - - bionet_timer.expires = jiffies + lp->poll_time; - add_timer(&bionet_timer); -} - -/* The inverse routine to bionet_open(). - */ -static int -bionet_close(struct net_device *dev) { - struct net_local *lp = netdev_priv(dev); - - if (bionet_debug > 0) - printk("bionet_close, open_time=%ld\n", lp->open_time); - del_timer(&bionet_timer); - stdma_lock(bionet_intr, NULL); - - set_status(0); - lp->open_time = 0; - - dev->tbusy = 1; - dev->start = 0; - - stdma_release(); - return 0; -} - -/* Get the current statistics. - This may be called with the card open or closed. - */ -static struct net_device_stats *net_get_stats(struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - return &lp->stats; -} - - -#ifdef MODULE - -static struct net_device *bio_dev; - -int init_module(void) -{ - bio_dev = bionet_probe(-1); - if (IS_ERR(bio_dev)) - return PTR_ERR(bio_dev); - return 0; -} - -void cleanup_module(void) -{ - unregister_netdev(bio_dev); - free_netdev(bio_dev); -} - -#endif /* MODULE */ - -/* Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include - -b m68k-linuxaout -Wall -Wstrict-prototypes -O2 - -fomit-frame-pointer -pipe -DMODULE -I../../net/inet -c bionet.c" - * version-control: t - * kept-new-versions: 5 - * tab-width: 8 - * End: - */ diff --git a/drivers/net/atari_pamsnet.c b/drivers/net/atari_pamsnet.c deleted file mode 100644 index f735637..0000000 --- a/drivers/net/atari_pamsnet.c +++ /dev/null @@ -1,878 +0,0 @@ -/* atari_pamsnet.c PAMsNet device driver for linux68k. - * - * Version: @(#)PAMsNet.c 0.2ß 03/31/96 - * - * Author: Torsten Lang <Torsten.Lang@ap.physik.uni-giessen.de> - * <Torsten.Lang@jung.de> - * - * This driver is based on my driver PAMSDMA.c for MiNT-Net and - * on the driver bionet.c written by - * Hartmut Laue <laue@ifk-mp.uni-kiel.de> - * and Torsten Narjes <narjes@ifk-mp.uni-kiel.de> - * - * Little adaptions for integration into pl7 by Roman Hodek - * - What is it ? - ------------ - This driver controls the PAMsNet LAN-Adapter which connects - an ATARI ST/TT via the ACSI-port to an Ethernet-based network. - - This version can be compiled as a loadable module (See the - compile command at the bottom of this file). - At load time, you can optionally set the debugging level and the - fastest response time on the command line of 'insmod'. - - 'pamsnet_debug' - controls the amount of diagnostic messages: - 0 : no messages - >0 : see code for meaning of printed messages - - 'pamsnet_min_poll_time' (always >=1) - gives the time (in jiffies) between polls. Low values - increase the system load (beware!) - - When loaded, a net device with the name 'eth?' becomes available, - which can be controlled with the usual 'ifconfig' command. - - It is possible to compile this driver into the kernel like other - (net) drivers. For this purpose, some source files (e.g. config-files - makefiles, Space.c) must be changed accordingly. (You may refer to - other drivers how to do it.) In this case, the device will be detected - at boot time and (probably) appear as 'eth0'. - - Theory of Operation - ------------------- - Because the ATARI DMA port is usually shared between several - devices (eg. harddisk, floppy) we cannot block the ACSI bus - while waiting for interrupts. Therefore we use a polling mechanism - to fetch packets from the adapter. For the same reason, we send - packets without checking that the previous packet has been sent to - the LAN. We rely on the higher levels of the networking code to detect - missing packets and resend them. - - Before we access the ATARI DMA controller, we check if another - process is using the DMA. If not, we lock the DMA, perform one or - more packet transfers and unlock the DMA before returning. - We do not use 'stdma_lock' unconditionally because it is unclear - if the networking code can be set to sleep, which will happen if - another (possibly slow) device is using the DMA controller. - - The polling is done via timer interrupts which periodically - 'simulate' an interrupt from the Ethernet adapter. The time (in jiffies) - between polls varies depending on an estimate of the net activity. - The allowed range is given by the variable 'bionet_min_poll_time' - for the lower (fastest) limit and the constant 'MAX_POLL_TIME' - for the higher (slowest) limit. - - Whenever a packet arrives, we switch to fastest response by setting - the polling time to its lowest limit. If the following poll fails, - because no packets have arrived, we increase the time for the next - poll. When the net activity is low, the polling time effectively - stays at its maximum value, resulting in the lowest load for the - machine. - */ - -#define MAX_POLL_TIME 10 - -static char *version = - "pamsnet.c:v0.2beta 30-mar-96 (c) Torsten Lang.\n"; - -#include <linux/module.h> - -#include <linux/kernel.h> -#include <linux/jiffies.h> -#include <linux/types.h> -#include <linux/fcntl.h> -#include <linux/interrupt.h> -#include <linux/ioport.h> -#include <linux/in.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/bitops.h> -#include <asm/system.h> -#include <asm/pgtable.h> -#include <asm/io.h> -#include <asm/dma.h> -#include <linux/errno.h> -#include <asm/atarihw.h> -#include <asm/atariints.h> -#include <asm/atari_stdma.h> -#include <asm/atari_acsi.h> - -#include <linux/delay.h> -#include <linux/timer.h> -#include <linux/init.h> - -#include <linux/netdevice.h> -#include <linux/etherdevice.h> -#include <linux/skbuff.h> - -#undef READ -#undef WRITE - -/* use 0 for production, 1 for verification, >2 for debug - */ -#ifndef NET_DEBUG -#define NET_DEBUG 0 -#endif -/* - * Global variable 'pamsnet_debug'. Can be set at load time by 'insmod' - */ -unsigned int pamsnet_debug = NET_DEBUG; -module_param(pamsnet_debug, int, 0); -MODULE_PARM_DESC(pamsnet_debug, "pamsnet debug enable (0-1)"); -MODULE_LICENSE("GPL"); - -static unsigned int pamsnet_min_poll_time = 2; - - -/* Information that need to be kept for each board. - */ -struct net_local { - struct net_device_stats stats; - long open_time; /* for debugging */ - int poll_time; /* polling time varies with net load */ -}; - -static struct nic_pkt_s { /* packet format */ - unsigned char buffer[2048]; -} *nic_packet = 0; -unsigned char *phys_nic_packet; - -typedef unsigned char HADDR[6]; /* 6-byte hardware address of lance */ - -/* Index to functions, as function prototypes. - */ -static void start (int target); -static int stop (int target); -static int testpkt (int target); -static int sendpkt (int target, unsigned char *buffer, int length); -static int receivepkt (int target, unsigned char *buffer); -static int inquiry (int target, unsigned char *buffer); -static HADDR *read_hw_addr(int target, unsigned char *buffer); -static void setup_dma (void *address, unsigned rw_flag, int num_blocks); -static int send_first (int target, unsigned char byte); -static int send_1_5 (int lun, unsigned char *command, int dma); -static int get_status (void); -static int calc_received (void *start_address); - -static int pamsnet_open(struct net_device *dev); -static int pamsnet_send_packet(struct sk_buff *skb, struct net_device *dev); -static void pamsnet_poll_rx(struct net_device *); -static int pamsnet_close(struct net_device *dev); -static struct net_device_stats *net_get_stats(struct net_device *dev); -static void pamsnet_tick(unsigned long); - -static irqreturn_t pamsnet_intr(int irq, void *data); - -static DEFINE_TIMER(pamsnet_timer, pamsnet_tick, 0, 0); - -#define STRAM_ADDR(a) (((a) & 0xff000000) == 0) - -typedef struct -{ - unsigned char reserved1[0x38]; - HADDR hwaddr; - unsigned char reserved2[0x1c2]; -} DMAHWADDR; - -/* - * Definitions of commands understood by the PAMs DMA adaptor. - * - * In general the DMA adaptor uses LUN 0, 5, 6 and 7 on one ID changeable - * by the PAM's Net software. - * - * LUN 0 works as a harddisk. You can boot the PAM's Net driver there. - * LUN 5 works as a harddisk and lets you access the RAM and some I/O HW - * area. In sector 0, bytes 0x38-0x3d you find the ethernet HW address - * of the adaptor. - * LUN 6 works as a harddisk and lets you access the firmware ROM. - * LUN 7 lets you send and receive packets. - * - * Some commands like the INQUIRY command work identical on all used LUNs. - * - * UNKNOWN1 seems to read some data. - * Command length is 6 bytes. - * UNKNOWN2 seems to read some data (command byte 1 must be !=0). The - * following bytes seem to be something like an allocation length. - * Command length is 6 bytes. - * READPKT reads a packet received by the DMA adaptor. - * Command length is 6 bytes. - * WRITEPKT sends a packet transferred by the following DMA phase. The length - * of the packet is transferred in command bytes 3 and 4. - * The adaptor automatically replaces the src hw address in an ethernet - * packet by its own hw address. - * Command length is 6 bytes. - * INQUIRY has the same function as the INQUIRY command supported by harddisks - * and other SCSI devices. It lets you detect which device you found - * at a given address. - * Command length is 6 bytes. - * START initializes the DMA adaptor. After this command it is able to send - * and receive packets. There is no status byte returned! - * Command length is 1 byte. - * NUMPKTS gives back the number of received packets waiting in the queue in - * the status byte. - * Command length is 1 byte. - * UNKNOWN3 - * UNKNOWN4 Function of these three commands is unknown. - * UNKNOWN5 The command length of these three commands is 1 byte. - * DESELECT immediately deselects the DMA adaptor. May important with interrupt - * driven operation. - * Command length is 1 byte. - * STOP resets the DMA adaptor. After this command packets can no longer - * be received or transferred. - * Command length is 6 byte. - */ - -enum {UNKNOWN1=3, READPKT=8, UNKNOWN2, WRITEPKT=10, INQUIRY=18, START, - NUMPKTS=22, UNKNOWN3, UNKNOWN4, UNKNOWN5, DESELECT, STOP}; - -#define READSECTOR READPKT -#define WRITESECTOR WRITEPKT - -u_char *inquire8="MV PAM's NET/GK"; - -#define DMALOW dma_wd.dma_lo -#define DMAMID dma_wd.dma_md -#define DMAHIGH dma_wd.dma_hi -#define DACCESS dma_wd.fdc_acces_seccount - -#define MFP_GPIP mfp.par_dt_reg - -/* Some useful functions */ - -#define INT (!(MFP_GPIP & 0x20)) -#define DELAY ({MFP_GPIP; MFP_GPIP; MFP_GPIP;}) -#define WRITEMODE(value) \ - ({ u_short dummy = value; \ - __asm__ volatile("movew %0, 0xFFFF8606" : : "d"(dummy)); \ - DELAY; \ - }) -#define WRITEBOTH(value1, value2) \ - ({ u_long dummy = (u_long)(value1)<<16 | (u_short)(value2); \ - __asm__ volatile("movel %0, 0xFFFF8604" : : "d"(dummy)); \ - DELAY; \ - }) - -/* Definitions for DMODE */ - -#define READ 0x000 -#define WRITE 0x100 - -#define DMA_FDC 0x080 -#define DMA_ACSI 0x000 - -#define DMA_DISABLE 0x040 - -#define SEC_COUNT 0x010 -#define DMA_WINDOW 0x000 - -#define REG_ACSI 0x008 -#define REG_FDC 0x000 - -#define A1 0x002 - -/* Timeout constants */ - -#define TIMEOUTCMD HZ/2 /* ca. 500ms */ -#define TIMEOUTDMA HZ /* ca. 1s */ -#define COMMAND_DELAY 500 /* ca. 0.5ms */ - -unsigned rw; -int lance_target = -1; -int if_up = 0; - -/* The following routines access the ethernet board connected to the - * ACSI port via the st_dma chip. - */ - -/* The following lowlevel routines work on physical addresses only and assume - * that eventually needed buffers are - * - completely located in ST RAM - * - are contigous in the physical address space - */ - -/* Setup the DMA counter */ - -static void -setup_dma (void *address, unsigned rw_flag, int num_blocks) -{ - WRITEMODE((unsigned) rw_flag | DMA_FDC | SEC_COUNT | REG_ACSI | - A1); - WRITEMODE((unsigned)(rw_flag ^ WRITE) | DMA_FDC | SEC_COUNT | REG_ACSI | - A1); - WRITEMODE((unsigned) rw_flag | DMA_FDC | SEC_COUNT | REG_ACSI | - A1); - DMALOW = (unsigned char)((unsigned long)address & 0xFF); - DMAMID = (unsigned char)(((unsigned long)address >> 8) & 0xFF); - DMAHIGH = (unsigned char)(((unsigned long)address >> 16) & 0xFF); - WRITEBOTH((unsigned)num_blocks & 0xFF, - rw_flag | DMA_FDC | DMA_WINDOW | REG_ACSI | A1); - rw = rw_flag; -} - -/* Send the first byte of an command block */ - -static int -send_first (int target, unsigned char byte) -{ - rw = READ; - acsi_delay_end(COMMAND_DELAY); - /* - * wake up ACSI - */ - WRITEMODE(DMA_FDC | DMA_WINDOW | REG_ACSI); - /* - * write command byte - */ - WRITEBOTH((target << 5) | (byte & 0x1F), DMA_FDC | - DMA_WINDOW | REG_ACSI | A1); - return (!acsi_wait_for_IRQ(TIMEOUTCMD)); -} - -/* Send the rest of an command block */ - -static int -send_1_5 (int lun, unsigned char *command, int dma) -{ - int i, j; - - for (i=0; i<5; i++) { - WRITEBOTH((!i ? (((lun & 0x7) << 5) | (command[i] & 0x1F)) - : command[i]), - rw | REG_ACSI | DMA_WINDOW | - ((i < 4) ? DMA_FDC - : (dma ? DMA_ACSI - : DMA_FDC)) | A1); - if (i < 4 && (j = !acsi_wait_for_IRQ(TIMEOUTCMD))) - return (j); - } - return (0); -} - -/* Read a status byte */ - -static int -get_status (void) -{ - WRITEMODE(DMA_FDC | DMA_WINDOW | REG_ACSI | A1); - acsi_delay_start(); - return ((int)(DACCESS & 0xFF)); -} - -/* Calculate the number of received bytes */ - -static int -calc_received (void *start_address) -{ - return (int)( - (((unsigned long)DMAHIGH << 16) | ((unsigned)DMAMID << 8) | DMALOW) - - (unsigned long)start_address); -} - -/* The following midlevel routines still work on physical addresses ... */ - -/* start() starts the PAM's DMA adaptor */ - -static void -start (int target) -{ - send_first(target, START); -} - -/* stop() stops the PAM's DMA adaptor and returns a value of zero in case of success */ - -static int -stop (int target) -{ - int ret = -1; - unsigned char cmd_buffer[5]; - - if (send_first(target, STOP)) - goto bad; - cmd_buffer[0] = cmd_buffer[1] = cmd_buffer[2] = - cmd_buffer[3] = cmd_buffer[4] = 0; - if (send_1_5(7, cmd_buffer, 0) || - !acsi_wait_for_IRQ(TIMEOUTDMA) || - get_status()) - goto bad; - ret = 0; -bad: - return (ret); -} - -/* testpkt() returns the number of received packets waiting in the queue */ - -static int -testpkt(int target) -{ - int ret = -1; - - if (send_first(target, NUMPKTS)) - goto bad; - ret = get_status(); -bad: - return (ret); -} - -/* inquiry() returns 0 when PAM's DMA found, -1 when timeout, -2 otherwise */ -/* Please note: The buffer is for internal use only but must be defined! */ - -static int -inquiry (int target, unsigned char *buffer) -{ - int ret = -1; - unsigned char *vbuffer = phys_to_virt((unsigned long)buffer); - unsigned char cmd_buffer[5]; - - if (send_first(target, INQUIRY)) - goto bad; - setup_dma(buffer, READ, 1); - vbuffer[8] = vbuffer[27] = 0; /* Avoid confusion with previous read data */ - cmd_buffer[0] = cmd_buffer[1] = cmd_buffer[2] = cmd_buffer[4] = 0; - cmd_buffer[3] = 48; - if (send_1_5(5, cmd_buffer, 1) || - !acsi_wait_for_IRQ(TIMEOUTDMA) || - get_status() || - (calc_received(buffer) < 32)) - goto bad; - dma_cache_maintenance((unsigned long)(buffer+8), 20, 0); - if (memcmp(inquire8, vbuffer+8, 20)) - goto bad; - ret = 0; -bad: - if (!!NET_DEBUG) { - vbuffer[8+20]=0; - printk("inquiry of target %d: %s\n", target, vbuffer+8); - } - return (ret); -} - -/* - * read_hw_addr() reads the sector containing the hwaddr and returns - * a pointer to it (virtual address!) or 0 in case of an error - */ - -static HADDR -*read_hw_addr(int target, unsigned char *buffer) -{ - HADDR *ret = 0; - unsigned char cmd_buffer[5]; - - if (send_first(target, READSECTOR)) - goto bad; - setup_dma(buffer, READ, 1); - cmd_buffer[0] = cmd_buffer[1] = cmd_buffer[2] = cmd_buffer[4] = 0; - cmd_buffer[3] = 1; - if (send_1_5(5, cmd_buffer, 1) || - !acsi_wait_for_IRQ(TIMEOUTDMA) || - get_status()) - goto bad; - ret = phys_to_virt((unsigned long)&(((DMAHWADDR *)buffer)->hwaddr)); - dma_cache_maintenance((unsigned long)buffer, 512, 0); -bad: - return (ret); -} - -static irqreturn_t -pamsnet_intr(int irq, void *data) -{ - return IRQ_HANDLED; -} - -/* receivepkt() loads a packet to a given buffer and returns its length */ - -static int -receivepkt (int target, unsigned char *buffer) -{ - int ret = -1; - unsigned char cmd_buffer[5]; - - if (send_first(target, READPKT)) - goto bad; - setup_dma(buffer, READ, 3); - cmd_buffer[0] = cmd_buffer[1] = cmd_buffer[2] = cmd_buffer[4] = 0; - cmd_buffer[3] = 3; - if (send_1_5(7, cmd_buffer, 1) || - !acsi_wait_for_IRQ(TIMEOUTDMA) || - get_status()) - goto bad; - ret = calc_received(buffer); -bad: - return (ret); -} - -/* sendpkt() sends a packet and returns a value of zero when the packet was sent - successfully */ - -static int -sendpkt (int target, unsigned char *buffer, int length) -{ - int ret = -1; - unsigned char cmd_buffer[5]; - - if (send_first(target, WRITEPKT)) - goto bad; - setup_dma(buffer, WRITE, 3); - cmd_buffer[0] = cmd_buffer[1] = cmd_buffer[4] = 0; - cmd_buffer[2] = length >> 8; - cmd_buffer[3] = length & 0xFF; - if (send_1_5(7, cmd_buffer, 1) || - !acsi_wait_for_IRQ(TIMEOUTDMA) || - get_status()) - goto bad; - ret = 0; -bad: - return (ret); -} - -/* The following higher level routines work on virtual addresses and convert them to - * physical addresses when passed to the lowlevel routines. It's up to the higher level - * routines to copy data from Alternate RAM to ST RAM if neccesary! - */ - -/* Check for a network adaptor of this type, and return '0' if one exists. - */ - -struct net_device * __init pamsnet_probe (int unit) -{ - struct net_device *dev; - int i; - HADDR *hwaddr; - int err; - - unsigned char station_addr[6]; - static unsigned version_printed; - /* avoid "Probing for..." printed 4 times - the driver is supporting only one adapter now! */ - static int no_more_found; - - if (no_more_found) - return ERR_PTR(-ENODEV); - no_more_found = 1; - - dev = alloc_etherdev(sizeof(struct net_local)); - if (!dev) - return ERR_PTR(-ENOMEM); - if (unit >= 0) { - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - } - SET_MODULE_OWNER(dev); - - printk("Probing for PAM's Net/GK Adapter...\n"); - - /* Allocate the DMA buffer here since we need it for probing! */ - - nic_packet = (struct nic_pkt_s *)acsi_buffer; - phys_nic_packet = (unsigned char *)phys_acsi_buffer; - if (pamsnet_debug > 0) { - printk("nic_packet at 0x%p, phys at 0x%p\n", - nic_packet, phys_nic_packet ); - } - - stdma_lock(pamsnet_intr, NULL); - DISABLE_IRQ(); - - for (i=0; i<8; i++) { - /* Do two inquiries to cover cases with strange equipment on previous ID */ - /* blocking the ACSI bus (like the SLMC804 laser printer controller... */ - inquiry(i, phys_nic_packet); - if (!inquiry(i, phys_nic_packet)) { - lance_target = i; - break; - } - } - - if (!!NET_DEBUG) - printk("ID: %d\n",i); - - if (lance_target >= 0) { - if (!(hwaddr = read_hw_addr(lance_target, phys_nic_packet))) - lance_target = -1; - else - memcpy (station_addr, hwaddr, ETH_ALEN); - } - - ENABLE_IRQ(); - stdma_release(); - - if (lance_target < 0) { - printk("No PAM's Net/GK found.\n"); - free_netdev(dev); - return ERR_PTR(-ENODEV); - } - - if (pamsnet_debug > 0 && version_printed++ == 0) - printk(version); - - printk("%s: %s found on target %01d, eth-addr: %02x:%02x:%02x:%02x:%02x:%02x.\n", - dev->name, "PAM's Net/GK", lance_target, - station_addr[0], station_addr[1], station_addr[2], - station_addr[3], station_addr[4], station_addr[5]); - - /* Initialize the device structure. */ - dev->open = pamsnet_open; - dev->stop = pamsnet_close; - dev->hard_start_xmit = pamsnet_send_packet; - dev->get_stats = net_get_stats; - - /* Fill in the fields of the device structure with ethernet-generic - * values. This should be in a common file instead of per-driver. - */ - - for (i = 0; i < ETH_ALEN; i++) { -#if 0 - dev->broadcast[i] = 0xff; -#endif - dev->dev_addr[i] = station_addr[i]; - } - err = register_netdev(dev); - if (!err) - return dev; - - free_netdev(dev); - return ERR_PTR(err); -} - -/* Open/initialize the board. This is called (in the current kernel) - sometime after booting when the 'ifconfig' program is run. - - This routine should set everything up anew at each open, even - registers that "should" only need to be set once at boot, so that - there is non-reboot way to recover if something goes wrong. - */ -static int -pamsnet_open(struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - - if (pamsnet_debug > 0) - printk("pamsnet_open\n"); - stdma_lock(pamsnet_intr, NULL); - DISABLE_IRQ(); - - /* Reset the hardware here. - */ - if (!if_up) - start(lance_target); - if_up = 1; - lp->open_time = 0; /*jiffies*/ - lp->poll_time = MAX_POLL_TIME; - - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - - ENABLE_IRQ(); - stdma_release(); - pamsnet_timer.data = (long)dev; - pamsnet_timer.expires = jiffies + lp->poll_time; - add_timer(&pamsnet_timer); - return 0; -} - -static int -pamsnet_send_packet(struct sk_buff *skb, struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - unsigned long flags; - - /* Block a timer-based transmit from overlapping. This could better be - * done with atomic_swap(1, dev->tbusy), but set_bit() works as well. - */ - local_irq_save(flags); - - if (stdma_islocked()) { - local_irq_restore(flags); - lp->stats.tx_errors++; - } - else { - int length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; - unsigned long buf = virt_to_phys(skb->data); - int stat; - - stdma_lock(pamsnet_intr, NULL); - DISABLE_IRQ(); - - local_irq_restore(flags); - if( !STRAM_ADDR(buf+length-1) ) { - skb_copy_from_linear_data(skb, nic_packet->buffer, - length); - buf = (unsigned long)phys_nic_packet; - } - - dma_cache_maintenance(buf, length, 1); - - stat = sendpkt(lance_target, (unsigned char *)buf, length); - ENABLE_IRQ(); - stdma_release(); - - dev->trans_start = jiffies; - dev->tbusy = 0; - lp->stats.tx_packets++; - lp->stats.tx_bytes+=length; - } - dev_kfree_skb(skb); - - return 0; -} - -/* We have a good packet(s), get it/them out of the buffers. - */ -static void -pamsnet_poll_rx(struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - int boguscount; - int pkt_len; - struct sk_buff *skb; - unsigned long flags; - - local_irq_save(flags); - /* ++roman: Take care at locking the ST-DMA... This must be done with ints - * off, since otherwise an int could slip in between the question and the - * locking itself, and then we'd go to sleep... And locking itself is - * necessary to keep the floppy_change timer from working with ST-DMA - * registers. */ - if (stdma_islocked()) { - local_irq_restore(flags); - return; - } - stdma_lock(pamsnet_intr, NULL); - DISABLE_IRQ(); - local_irq_restore(flags); - - boguscount = testpkt(lance_target); - if( lp->poll_time < MAX_POLL_TIME ) lp->poll_time++; - - while(boguscount--) { - pkt_len = receivepkt(lance_target, phys_nic_packet); - - if( pkt_len < 60 ) break; - - /* Good packet... */ - - dma_cache_maintenance((unsigned long)phys_nic_packet, pkt_len, 0); - - lp->poll_time = pamsnet_min_poll_time; /* fast poll */ - if( pkt_len >= 60 && pkt_len <= 2048 ) { - if (pkt_len > 1514) - pkt_len = 1514; - - /* Malloc up new buffer. - */ - skb = alloc_skb(pkt_len, GFP_ATOMIC); - if (skb == NULL) { - printk("%s: Memory squeeze, dropping packet.\n", - dev->name); - lp->stats.rx_dropped++; - break; - } - skb->len = pkt_len; - skb->dev = dev; - - /* 'skb->data' points to the start of sk_buff data area. - */ - skb_copy_to_linear_data(skb, nic_packet->buffer, - pkt_len); - netif_rx(skb); - dev->last_rx = jiffies; - lp->stats.rx_packets++; - lp->stats.rx_bytes+=pkt_len; - } - } - - /* If any worth-while packets have been received, dev_rint() - has done a mark_bh(INET_BH) for us and will work on them - when we get to the bottom-half routine. - */ - - ENABLE_IRQ(); - stdma_release(); - return; -} - -/* pamsnet_tick: called by pamsnet_timer. Reads packets from the adapter, - * passes them to the higher layers and restarts the timer. - */ -static void -pamsnet_tick(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct net_local *lp = netdev_priv(dev); - - if( pamsnet_debug > 0 && (lp->open_time++ & 7) == 8 ) - printk("pamsnet_tick: %ld\n", lp->open_time); - - pamsnet_poll_rx(dev); - - pamsnet_timer.expires = jiffies + lp->poll_time; - add_timer(&pamsnet_timer); -} - -/* The inverse routine to pamsnet_open(). - */ -static int -pamsnet_close(struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - - if (pamsnet_debug > 0) - printk("pamsnet_close, open_time=%ld\n", lp->open_time); - del_timer(&pamsnet_timer); - stdma_lock(pamsnet_intr, NULL); - DISABLE_IRQ(); - - if (if_up) - stop(lance_target); - if_up = 0; - - lp->open_time = 0; - - dev->tbusy = 1; - dev->start = 0; - - ENABLE_IRQ(); - stdma_release(); - return 0; -} - -/* Get the current statistics. - This may be called with the card open or closed. - */ -static struct net_device_stats *net_get_stats(struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - return &lp->stats; -} - - -#ifdef MODULE - -static struct net_device *pam_dev; - -int init_module(void) -{ - pam_dev = pamsnet_probe(-1); - if (IS_ERR(pam_dev)) - return PTR_ERR(pam_dev); - return 0; -} - -void cleanup_module(void) -{ - unregister_netdev(pam_dev); - free_netdev(pam_dev); -} - -#endif /* MODULE */ - -/* Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include - -b m68k-linuxaout -Wall -Wstrict-prototypes -O2 - -fomit-frame-pointer -pipe -DMODULE -I../../net/inet -c atari_pamsnet.c" - * version-control: t - * kept-new-versions: 5 - * tab-width: 8 - * End: - */ diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c new file mode 100644 index 0000000..8a667c1 --- /dev/null +++ b/drivers/net/sunvnet.c @@ -0,0 +1,1164 @@ +/* sunvnet.c: Sun LDOM Virtual Network Driver. + * + * Copyright (C) 2007 David S. Miller <davem@davemloft.net> + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/types.h> +#include <linux/slab.h> +#include <linux/delay.h> +#include <linux/init.h> +#include <linux/netdevice.h> +#include <linux/ethtool.h> +#include <linux/etherdevice.h> + +#include <asm/vio.h> +#include <asm/ldc.h> + +#include "sunvnet.h" + +#define DRV_MODULE_NAME "sunvnet" +#define PFX DRV_MODULE_NAME ": " +#define DRV_MODULE_VERSION "1.0" +#define DRV_MODULE_RELDATE "June 25, 2007" + +static char version[] __devinitdata = + DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; +MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); +MODULE_DESCRIPTION("Sun LDOM virtual network driver"); +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_MODULE_VERSION); + +/* Ordered from largest major to lowest */ +static struct vio_version vnet_versions[] = { + { .major = 1, .minor = 0 }, +}; + +static inline u32 vnet_tx_dring_avail(struct vio_dring_state *dr) +{ + return vio_dring_avail(dr, VNET_TX_RING_SIZE); +} + +static int vnet_handle_unknown(struct vnet_port *port, void *arg) +{ + struct vio_msg_tag *pkt = arg; + + printk(KERN_ERR PFX "Received unknown msg [%02x:%02x:%04x:%08x]\n", + pkt->type, pkt->stype, pkt->stype_env, pkt->sid); + printk(KERN_ERR PFX "Resetting connection.\n"); + + ldc_disconnect(port->vio.lp); + + return -ECONNRESET; +} + +static int vnet_send_attr(struct vio_driver_state *vio) +{ + struct vnet_port *port = to_vnet_port(vio); + struct net_device *dev = port->vp->dev; + struct vio_net_attr_info pkt; + int i; + + memset(&pkt, 0, sizeof(pkt)); + pkt.tag.type = VIO_TYPE_CTRL; + pkt.tag.stype = VIO_SUBTYPE_INFO; + pkt.tag.stype_env = VIO_ATTR_INFO; + pkt.tag.sid = vio_send_sid(vio); + pkt.xfer_mode = VIO_DRING_MODE; + pkt.addr_type = VNET_ADDR_ETHERMAC; + pkt.ack_freq = 0; + for (i = 0; i < 6; i++) + pkt.addr |= (u64)dev->dev_addr[i] << ((5 - i) * 8); + pkt.mtu = ETH_FRAME_LEN; + + viodbg(HS, "SEND NET ATTR xmode[0x%x] atype[0x%x] addr[%llx] " + "ackfreq[%u] mtu[%llu]\n", + pkt.xfer_mode, pkt.addr_type, + (unsigned long long) pkt.addr, + pkt.ack_freq, + (unsigned long long) pkt.mtu); + + return vio_ldc_send(vio, &pkt, sizeof(pkt)); +} + +static int handle_attr_info(struct vio_driver_state *vio, + struct vio_net_attr_info *pkt) +{ + viodbg(HS, "GOT NET ATTR INFO xmode[0x%x] atype[0x%x] addr[%llx] " + "ackfreq[%u] mtu[%llu]\n", + pkt->xfer_mode, pkt->addr_type, + (unsigned long long) pkt->addr, + pkt->ack_freq, + (unsigned long long) pkt->mtu); + + pkt->tag.sid = vio_send_sid(vio); + + if (pkt->xfer_mode != VIO_DRING_MODE || + pkt->addr_type != VNET_ADDR_ETHERMAC || + pkt->mtu != ETH_FRAME_LEN) { + viodbg(HS, "SEND NET ATTR NACK\n"); + + pkt->tag.stype = VIO_SUBTYPE_NACK; + + (void) vio_ldc_send(vio, pkt, sizeof(*pkt)); + + return -ECONNRESET; + } else { + viodbg(HS, "SEND NET ATTR ACK\n"); + + pkt->tag.stype = VIO_SUBTYPE_ACK; + + return vio_ldc_send(vio, pkt, sizeof(*pkt)); + } + +} + +static int handle_attr_ack(struct vio_driver_state *vio, + struct vio_net_attr_info *pkt) +{ + viodbg(HS, "GOT NET ATTR ACK\n"); + + return 0; +} + +static int handle_attr_nack(struct vio_driver_state *vio, + struct vio_net_attr_info *pkt) +{ + viodbg(HS, "GOT NET ATTR NACK\n"); + + return -ECONNRESET; +} + +static int vnet_handle_attr(struct vio_driver_state *vio, void *arg) +{ + struct vio_net_attr_info *pkt = arg; + + switch (pkt->tag.stype) { + case VIO_SUBTYPE_INFO: + return handle_attr_info(vio, pkt); + + case VIO_SUBTYPE_ACK: + return handle_attr_ack(vio, pkt); + + case VIO_SUBTYPE_NACK: + return handle_attr_nack(vio, pkt); + + default: + return -ECONNRESET; + } +} + +static void vnet_handshake_complete(struct vio_driver_state *vio) +{ + struct vio_dring_state *dr; + + dr = &vio->drings[VIO_DRIVER_RX_RING]; + dr->snd_nxt = dr->rcv_nxt = 1; + + dr = &vio->drings[VIO_DRIVER_TX_RING]; + dr->snd_nxt = dr->rcv_nxt = 1; +} + +/* The hypervisor interface that implements copying to/from imported + * memory from another domain requires that copies are done to 8-byte + * aligned buffers, and that the lengths of such copies are also 8-byte + * multiples. + * + * So we align skb->data to an 8-byte multiple and pad-out the data + * area so we can round the copy length up to the next multiple of + * 8 for the copy. + * + * The transmitter puts the actual start of the packet 6 bytes into + * the buffer it sends over, so that the IP headers after the ethernet + * header are aligned properly. These 6 bytes are not in the descriptor + * length, they are simply implied. This offset is represented using + * the VNET_PACKET_SKIP macro. + */ +static struct sk_buff *alloc_and_align_skb(struct net_device *dev, + unsigned int len) +{ + struct sk_buff *skb = netdev_alloc_skb(dev, len+VNET_PACKET_SKIP+8+8); + unsigned long addr, off; + + if (unlikely(!skb)) + return NULL; + + addr = (unsigned long) skb->data; + off = ((addr + 7UL) & ~7UL) - addr; + if (off) + skb_reserve(skb, off); + + return skb; +} + +static int vnet_rx_one(struct vnet_port *port, unsigned int len, + struct ldc_trans_cookie *cookies, int ncookies) +{ + struct net_device *dev = port->vp->dev; + unsigned int copy_len; + struct sk_buff *skb; + int err; + + err = -EMSGSIZE; + if (unlikely(len < ETH_ZLEN || len > ETH_FRAME_LEN)) { + dev->stats.rx_length_errors++; + goto out_dropped; + } + + skb = alloc_and_align_skb(dev, len); + err = -ENOMEM; + if (unlikely(!skb)) { + dev->stats.rx_missed_errors++; + goto out_dropped; + } + + copy_len = (len + VNET_PACKET_SKIP + 7U) & ~7U; + skb_put(skb, copy_len); + err = ldc_copy(port->vio.lp, LDC_COPY_IN, + skb->data, copy_len, 0, + cookies, ncookies); + if (unlikely(err < 0)) { + dev->stats.rx_frame_errors++; + goto out_free_skb; + } + + skb_pull(skb, VNET_PACKET_SKIP); + skb_trim(skb, len); + skb->protocol = eth_type_trans(skb, dev); + + dev->stats.rx_packets++; + dev->stats.rx_bytes += len; + + netif_rx(skb); + + return 0; + +out_free_skb: + kfree_skb(skb); + +out_dropped: + dev->stats.rx_dropped++; + return err; +} + +static int vnet_send_ack(struct vnet_port *port, struct vio_dring_state *dr, + u32 start, u32 end, u8 vio_dring_state) +{ + struct vio_dring_data hdr = { + .tag = { + .type = VIO_TYPE_DATA, + .stype = VIO_SUBTYPE_ACK, + .stype_env = VIO_DRING_DATA, + .sid = vio_send_sid(&port->vio), + }, + .dring_ident = dr->ident, + .start_idx = start, + .end_idx = end, + .state = vio_dring_state, + }; + int err, delay; + + hdr.seq = dr->snd_nxt; + delay = 1; + do { + err = vio_ldc_send(&port->vio, &hdr, sizeof(hdr)); + if (err > 0) { + dr->snd_nxt++; + break; + } + udelay(delay); + if ((delay <<= 1) > 128) + delay = 128; + } while (err == -EAGAIN); + + return err; +} + +static u32 next_idx(u32 idx, struct vio_dring_state *dr) +{ + if (++idx == dr->num_entries) + idx = 0; + return idx; +} + +static u32 prev_idx(u32 idx, struct vio_dring_state *dr) +{ + if (idx == 0) + idx = dr->num_entries - 1; + else + idx--; + + return idx; +} + +static struct vio_net_desc *get_rx_desc(struct vnet_port *port, + struct vio_dring_state *dr, + u32 index) +{ + struct vio_net_desc *desc = port->vio.desc_buf; + int err; + + err = ldc_get_dring_entry(port->vio.lp, desc, dr->entry_size, + (index * dr->entry_size), + dr->cookies, dr->ncookies); + if (err < 0) + return ERR_PTR(err); + + return desc; +} + +static int put_rx_desc(struct vnet_port *port, + struct vio_dring_state *dr, + struct vio_net_desc *desc, + u32 index) +{ + int err; + + err = ldc_put_dring_entry(port->vio.lp, desc, dr->entry_size, + (index * dr->entry_size), + dr->cookies, dr->ncookies); + if (err < 0) + return err; + + return 0; +} + +static int vnet_walk_rx_one(struct vnet_port *port, + struct vio_dring_state *dr, + u32 index, int *needs_ack) +{ + struct vio_net_desc *desc = get_rx_desc(port, dr, index); + struct vio_driver_state *vio = &port->vio; + int err; + + if (IS_ERR(desc)) + return PTR_ERR(desc); + + viodbg(DATA, "vio_walk_rx_one desc[%02x:%02x:%08x:%08x:%lx:%lx]\n", + desc->hdr.state, desc->hdr.ack, + desc->size, desc->ncookies, + desc->cookies[0].cookie_addr, + desc->cookies[0].cookie_size); + + if (desc->hdr.state != VIO_DESC_READY) + return 1; + err = vnet_rx_one(port, desc->size, desc->cookies, desc->ncookies); + if (err == -ECONNRESET) + return err; + desc->hdr.state = VIO_DESC_DONE; + err = put_rx_desc(port, dr, desc, index); + if (err < 0) + return err; + *needs_ack = desc->hdr.ack; + return 0; +} + +static int vnet_walk_rx(struct vnet_port *port, struct vio_dring_state *dr, + u32 start, u32 end) +{ + struct vio_driver_state *vio = &port->vio; + int ack_start = -1, ack_end = -1; + + end = (end == (u32) -1) ? prev_idx(start, dr) : next_idx(end, dr); + + viodbg(DATA, "vnet_walk_rx start[%08x] end[%08x]\n", start, end); + + while (start != end) { + int ack = 0, err = vnet_walk_rx_one(port, dr, start, &ack); + if (err == -ECONNRESET) + return err; + if (err != 0) + break; + if (ack_start == -1) + ack_start = start; + ack_end = start; + start = next_idx(start, dr); + if (ack && start != end) { + err = vnet_send_ack(port, dr, ack_start, ack_end, + VIO_DRING_ACTIVE); + if (err == -ECONNRESET) + return err; + ack_start = -1; + } + } + if (unlikely(ack_start == -1)) + ack_start = ack_end = prev_idx(start, dr); + return vnet_send_ack(port, dr, ack_start, ack_end, VIO_DRING_STOPPED); +} + +static int vnet_rx(struct vnet_port *port, void *msgbuf) +{ + struct vio_dring_data *pkt = msgbuf; + struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_RX_RING]; + struct vio_driver_state *vio = &port->vio; + + viodbg(DATA, "vnet_rx stype_env[%04x] seq[%016lx] rcv_nxt[%016lx]\n", + pkt->tag.stype_env, pkt->seq, dr->rcv_nxt); + + if (unlikely(pkt->tag.stype_env != VIO_DRING_DATA)) + return 0; + if (unlikely(pkt->seq != dr->rcv_nxt)) { + printk(KERN_ERR PFX "RX out of sequence seq[0x%lx] " + "rcv_nxt[0x%lx]\n", pkt->seq, dr->rcv_nxt); + return 0; + } + + dr->rcv_nxt++; + + /* XXX Validate pkt->start_idx and pkt->end_idx XXX */ + + return vnet_walk_rx(port, dr, pkt->start_idx, pkt->end_idx); +} + +static int idx_is_pending(struct vio_dring_state *dr, u32 end) +{ + u32 idx = dr->cons; + int found = 0; + + while (idx != dr->prod) { + if (idx == end) { + found = 1; + break; + } + idx = next_idx(idx, dr); + } + return found; +} + +static int vnet_ack(struct vnet_port *port, void *msgbuf) +{ + struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING]; + struct vio_dring_data *pkt = msgbuf; + struct net_device *dev; + struct vnet *vp; + u32 end; + + if (unlikely(pkt->tag.stype_env != VIO_DRING_DATA)) + return 0; + + end = pkt->end_idx; + if (unlikely(!idx_is_pending(dr, end))) + return 0; + + dr->cons = next_idx(end, dr); + + vp = port->vp; + dev = vp->dev; + if (unlikely(netif_queue_stopped(dev) && + vnet_tx_dring_avail(dr) >= VNET_TX_WAKEUP_THRESH(dr))) + return 1; + + return 0; +} + +static int vnet_nack(struct vnet_port *port, void *msgbuf) +{ + /* XXX just reset or similar XXX */ + return 0; +} + +static void maybe_tx_wakeup(struct vnet *vp) +{ + struct net_device *dev = vp->dev; + + netif_tx_lock(dev); + if (likely(netif_queue_stopped(dev))) { + struct vnet_port *port; + int wake = 1; + + list_for_each_entry(port, &vp->port_list, list) { + struct vio_dring_state *dr; + + dr = &port->vio.drings[VIO_DRIVER_TX_RING]; + if (vnet_tx_dring_avail(dr) < + VNET_TX_WAKEUP_THRESH(dr)) { + wake = 0; + break; + } + } + if (wake) + netif_wake_queue(dev); + } + netif_tx_unlock(dev); +} + +static void vnet_event(void *arg, int event) +{ + struct vnet_port *port = arg; + struct vio_driver_state *vio = &port->vio; + unsigned long flags; + int tx_wakeup, err; + + spin_lock_irqsave(&vio->lock, flags); + + if (unlikely(event == LDC_EVENT_RESET || + event == LDC_EVENT_UP)) { + vio_link_state_change(vio, event); + spin_unlock_irqrestore(&vio->lock, flags); + + return; + } + + if (unlikely(event != LDC_EVENT_DATA_READY)) { + printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event); + spin_unlock_irqrestore(&vio->lock, flags); + return; + } + + tx_wakeup = err = 0; + while (1) { + union { + struct vio_msg_tag tag; + u64 raw[8]; + } msgbuf; + + err = ldc_read(vio->lp, &msgbuf, sizeof(msgbuf)); + if (unlikely(err < 0)) { + if (err == -ECONNRESET) + vio_conn_reset(vio); + break; + } + if (err == 0) + break; + viodbg(DATA, "TAG [%02x:%02x:%04x:%08x]\n", + msgbuf.tag.type, + msgbuf.tag.stype, + msgbuf.tag.stype_env, + msgbuf.tag.sid); + err = vio_validate_sid(vio, &msgbuf.tag); + if (err < 0) + break; + + if (likely(msgbuf.tag.type == VIO_TYPE_DATA)) { + if (msgbuf.tag.stype == VIO_SUBTYPE_INFO) { + err = vnet_rx(port, &msgbuf); + } else if (msgbuf.tag.stype == VIO_SUBTYPE_ACK) { + err = vnet_ack(port, &msgbuf); + if (err > 0) + tx_wakeup |= err; + } else if (msgbuf.tag.stype == VIO_SUBTYPE_NACK) { + err = vnet_nack(port, &msgbuf); + } + } else if (msgbuf.tag.type == VIO_TYPE_CTRL) { + err = vio_control_pkt_engine(vio, &msgbuf); + if (err) + break; + } else { + err = vnet_handle_unknown(port, &msgbuf); + } + if (err == -ECONNRESET) + break; + } + spin_unlock(&vio->lock); + if (unlikely(tx_wakeup && err != -ECONNRESET)) + maybe_tx_wakeup(port->vp); + local_irq_restore(flags); +} + +static int __vnet_tx_trigger(struct vnet_port *port) +{ + struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING]; + struct vio_dring_data hdr = { + .tag = { + .type = VIO_TYPE_DATA, + .stype = VIO_SUBTYPE_INFO, + .stype_env = VIO_DRING_DATA, + .sid = vio_send_sid(&port->vio), + }, + .dring_ident = dr->ident, + .start_idx = dr->prod, + .end_idx = (u32) -1, + }; + int err, delay; + + hdr.seq = dr->snd_nxt; + delay = 1; + do { + err = vio_ldc_send(&port->vio, &hdr, sizeof(hdr)); + if (err > 0) { + dr->snd_nxt++; + break; + } + udelay(delay); + if ((delay <<= 1) > 128) + delay = 128; + } while (err == -EAGAIN); + + return err; +} + +struct vnet_port *__tx_port_find(struct vnet *vp, struct sk_buff *skb) +{ + unsigned int hash = vnet_hashfn(skb->data); + struct hlist_head *hp = &vp->port_hash[hash]; + struct hlist_node *n; + struct vnet_port *port; + + hlist_for_each_entry(port, n, hp, hash) { + if (!compare_ether_addr(port->raddr, skb->data)) + return port; + } + port = NULL; + if (!list_empty(&vp->port_list)) + port = list_entry(vp->port_list.next, struct vnet_port, list); + + return port; +} + +struct vnet_port *tx_port_find(struct vnet *vp, struct sk_buff *skb) +{ + struct vnet_port *ret; + unsigned long flags; + + spin_lock_irqsave(&vp->lock, flags); + ret = __tx_port_find(vp, skb); + spin_unlock_irqrestore(&vp->lock, flags); + + return ret; +} + +static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct vnet *vp = netdev_priv(dev); + struct vnet_port *port = tx_port_find(vp, skb); + struct vio_dring_state *dr; + struct vio_net_desc *d; + unsigned long flags; + unsigned int len; + void *tx_buf; + int i, err; + + if (unlikely(!port)) + goto out_dropped; + + spin_lock_irqsave(&port->vio.lock, flags); + + dr = &port->vio.drings[VIO_DRIVER_TX_RING]; + if (unlikely(vnet_tx_dring_avail(dr) < 2)) { + if (!netif_queue_stopped(dev)) { + netif_stop_queue(dev); + + /* This is a hard error, log it. */ + printk(KERN_ERR PFX "%s: BUG! Tx Ring full when " + "queue awake!\n", dev->name); + dev->stats.tx_errors++; + } + spin_unlock_irqrestore(&port->vio.lock, flags); + return NETDEV_TX_BUSY; + } + + d = vio_dring_cur(dr); + + tx_buf = port->tx_bufs[dr->prod].buf; + skb_copy_from_linear_data(skb, tx_buf + VNET_PACKET_SKIP, skb->len); + + len = skb->len; + if (len < ETH_ZLEN) { + len = ETH_ZLEN; + memset(tx_buf+VNET_PACKET_SKIP+skb->len, 0, len - skb->len); + } + + d->hdr.ack = VIO_ACK_ENABLE; + d->size = len; + d->ncookies = port->tx_bufs[dr->prod].ncookies; + for (i = 0; i < d->ncookies; i++) + d->cookies[i] = port->tx_bufs[dr->prod].cookies[i]; + + /* This has to be a non-SMP write barrier because we are writing + * to memory which is shared with the peer LDOM. + */ + wmb(); + + d->hdr.state = VIO_DESC_READY; + + err = __vnet_tx_trigger(port); + if (unlikely(err < 0)) { + printk(KERN_INFO PFX "%s: TX trigger error %d\n", + dev->name, err); + d->hdr.state = VIO_DESC_FREE; + dev->stats.tx_carrier_errors++; + goto out_dropped_unlock; + } + + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + + dr->prod = (dr->prod + 1) & (VNET_TX_RING_SIZE - 1); + if (unlikely(vnet_tx_dring_avail(dr) < 2)) { + netif_stop_queue(dev); + if (vnet_tx_dring_avail(dr) > VNET_TX_WAKEUP_THRESH(dr)) + netif_wake_queue(dev); + } + + spin_unlock_irqrestore(&port->vio.lock, flags); + + dev_kfree_skb(skb); + + dev->trans_start = jiffies; + return NETDEV_TX_OK; + +out_dropped_unlock: + spin_unlock_irqrestore(&port->vio.lock, flags); + +out_dropped: + dev_kfree_skb(skb); + dev->stats.tx_dropped++; + return NETDEV_TX_OK; +} + +static void vnet_tx_timeout(struct net_device *dev) +{ + /* XXX Implement me XXX */ +} + +static int vnet_open(struct net_device *dev) +{ + netif_carrier_on(dev); + netif_start_queue(dev); + + return 0; +} + +static int vnet_close(struct net_device *dev) +{ + netif_stop_queue(dev); + netif_carrier_off(dev); + + return 0; +} + +static void vnet_set_rx_mode(struct net_device *dev) +{ + /* XXX Implement multicast support XXX */ +} + +static int vnet_change_mtu(struct net_device *dev, int new_mtu) +{ + if (new_mtu != ETH_DATA_LEN) + return -EINVAL; + + dev->mtu = new_mtu; + return 0; +} + +static int vnet_set_mac_addr(struct net_device *dev, void *p) +{ + return -EINVAL; +} + +static void vnet_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + strcpy(info->driver, DRV_MODULE_NAME); + strcpy(info->version, DRV_MODULE_VERSION); +} + +static u32 vnet_get_msglevel(struct net_device *dev) +{ + struct vnet *vp = netdev_priv(dev); + return vp->msg_enable; +} + +static void vnet_set_msglevel(struct net_device *dev, u32 value) +{ + struct vnet *vp = netdev_priv(dev); + vp->msg_enable = value; +} + +static const struct ethtool_ops vnet_ethtool_ops = { + .get_drvinfo = vnet_get_drvinfo, + .get_msglevel = vnet_get_msglevel, + .set_msglevel = vnet_set_msglevel, + .get_link = ethtool_op_get_link, + .get_perm_addr = ethtool_op_get_perm_addr, +}; + +static void vnet_port_free_tx_bufs(struct vnet_port *port) +{ + struct vio_dring_state *dr; + int i; + + dr = &port->vio.drings[VIO_DRIVER_TX_RING]; + if (dr->base) { + ldc_free_exp_dring(port->vio.lp, dr->base, + (dr->entry_size * dr->num_entries), + dr->cookies, dr->ncookies); + dr->base = NULL; + dr->entry_size = 0; + dr->num_entries = 0; + dr->pending = 0; + dr->ncookies = 0; + } + + for (i = 0; i < VNET_TX_RING_SIZE; i++) { + void *buf = port->tx_bufs[i].buf; + + if (!buf) + continue; + + ldc_unmap(port->vio.lp, + port->tx_bufs[i].cookies, + port->tx_bufs[i].ncookies); + + kfree(buf); + port->tx_bufs[i].buf = NULL; + } +} + +static int __devinit vnet_port_alloc_tx_bufs(struct vnet_port *port) +{ + struct vio_dring_state *dr; + unsigned long len; + int i, err, ncookies; + void *dring; + + for (i = 0; i < VNET_TX_RING_SIZE; i++) { + void *buf = kzalloc(ETH_FRAME_LEN + 8, GFP_KERNEL); + int map_len = (ETH_FRAME_LEN + 7) & ~7; + + err = -ENOMEM; + if (!buf) { + printk(KERN_ERR "TX buffer allocation failure\n"); + goto err_out; + } + err = -EFAULT; + if ((unsigned long)buf & (8UL - 1)) { + printk(KERN_ERR "TX buffer misaligned\n"); + kfree(buf); + goto err_out; + } + + err = ldc_map_single(port->vio.lp, buf, map_len, + port->tx_bufs[i].cookies, 2, + (LDC_MAP_SHADOW | + LDC_MAP_DIRECT | + LDC_MAP_RW)); + if (err < 0) { + kfree(buf); + goto err_out; + } + port->tx_bufs[i].buf = buf; + port->tx_bufs[i].ncookies = err; + } + + dr = &port->vio.drings[VIO_DRIVER_TX_RING]; + + len = (VNET_TX_RING_SIZE * + (sizeof(struct vio_net_desc) + + (sizeof(struct ldc_trans_cookie) * 2))); + + ncookies = VIO_MAX_RING_COOKIES; + dring = ldc_alloc_exp_dring(port->vio.lp, len, + dr->cookies, &ncookies, + (LDC_MAP_SHADOW | + LDC_MAP_DIRECT | + LDC_MAP_RW)); + if (IS_ERR(dring)) { + err = PTR_ERR(dring); + goto err_out; + } + + dr->base = dring; + dr->entry_size = (sizeof(struct vio_net_desc) + + (sizeof(struct ldc_trans_cookie) * 2)); + dr->num_entries = VNET_TX_RING_SIZE; + dr->prod = dr->cons = 0; + dr->pending = VNET_TX_RING_SIZE; + dr->ncookies = ncookies; + + return 0; + +err_out: + vnet_port_free_tx_bufs(port); + + return err; +} + +static struct ldc_channel_config vnet_ldc_cfg = { + .event = vnet_event, + .mtu = 64, + .mode = LDC_MODE_UNRELIABLE, +}; + +static struct vio_driver_ops vnet_vio_ops = { + .send_attr = vnet_send_attr, + .handle_attr = vnet_handle_attr, + .handshake_complete = vnet_handshake_complete, +}; + +const char *remote_macaddr_prop = "remote-mac-address"; + +static int __devinit vnet_port_probe(struct vio_dev *vdev, + const struct vio_device_id *id) +{ + struct mdesc_handle *hp; + struct vnet_port *port; + unsigned long flags; + struct vnet *vp; + const u64 *rmac; + int len, i, err, switch_port; + + vp = dev_get_drvdata(vdev->dev.parent); + if (!vp) { + printk(KERN_ERR PFX "Cannot find port parent vnet.\n"); + return -ENODEV; + } + + hp = mdesc_grab(); + + rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len); + err = -ENODEV; + if (!rmac) { + printk(KERN_ERR PFX "Port lacks %s property.\n", + remote_macaddr_prop); + goto err_out_put_mdesc; + } + + port = kzalloc(sizeof(*port), GFP_KERNEL); + err = -ENOMEM; + if (!port) { + printk(KERN_ERR PFX "Cannot allocate vnet_port.\n"); + goto err_out_put_mdesc; + } + + for (i = 0; i < ETH_ALEN; i++) + port->raddr[i] = (*rmac >> (5 - i) * 8) & 0xff; + + port->vp = vp; + + err = vio_driver_init(&port->vio, vdev, VDEV_NETWORK, + vnet_versions, ARRAY_SIZE(vnet_versions), + &vnet_vio_ops, vp->dev->name); + if (err) + goto err_out_free_port; + + err = vio_ldc_alloc(&port->vio, &vnet_ldc_cfg, port); + if (err) + goto err_out_free_port; + + err = vnet_port_alloc_tx_bufs(port); + if (err) + goto err_out_free_ldc; + + INIT_HLIST_NODE(&port->hash); + INIT_LIST_HEAD(&port->list); + + switch_port = 0; + if (mdesc_get_property(hp, vdev->mp, "switch-port", NULL) != NULL) + switch_port = 1; + + spin_lock_irqsave(&vp->lock, flags); + if (switch_port) + list_add(&port->list, &vp->port_list); + else + list_add_tail(&port->list, &vp->port_list); + hlist_add_head(&port->hash, &vp->port_hash[vnet_hashfn(port->raddr)]); + spin_unlock_irqrestore(&vp->lock, flags); + + dev_set_drvdata(&vdev->dev, port); + + printk(KERN_INFO "%s: PORT ( remote-mac ", vp->dev->name); + for (i = 0; i < 6; i++) + printk("%2.2x%c", port->raddr[i], i == 5 ? ' ' : ':'); + if (switch_port) + printk("switch-port "); + printk(")\n"); + + vio_port_up(&port->vio); + + mdesc_release(hp); + + return 0; + +err_out_free_ldc: + vio_ldc_free(&port->vio); + +err_out_free_port: + kfree(port); + +err_out_put_mdesc: + mdesc_release(hp); + return err; +} + +static int vnet_port_remove(struct vio_dev *vdev) +{ + struct vnet_port *port = dev_get_drvdata(&vdev->dev); + + if (port) { + struct vnet *vp = port->vp; + unsigned long flags; + + del_timer_sync(&port->vio.timer); + + spin_lock_irqsave(&vp->lock, flags); + list_del(&port->list); + hlist_del(&port->hash); + spin_unlock_irqrestore(&vp->lock, flags); + + vnet_port_free_tx_bufs(port); + vio_ldc_free(&port->vio); + + dev_set_drvdata(&vdev->dev, NULL); + + kfree(port); + } + return 0; +} + +static struct vio_device_id vnet_port_match[] = { + { + .type = "vnet-port", + }, + {}, +}; +MODULE_DEVICE_TABLE(vio, vnet_match); + +static struct vio_driver vnet_port_driver = { + .id_table = vnet_port_match, + .probe = vnet_port_probe, + .remove = vnet_port_remove, + .driver = { + .name = "vnet_port", + .owner = THIS_MODULE, + } +}; + +const char *local_mac_prop = "local-mac-address"; + +static int __devinit vnet_probe(struct vio_dev *vdev, + const struct vio_device_id *id) +{ + static int vnet_version_printed; + struct mdesc_handle *hp; + struct net_device *dev; + struct vnet *vp; + const u64 *mac; + int err, i, len; + + if (vnet_version_printed++ == 0) + printk(KERN_INFO "%s", version); + + hp = mdesc_grab(); + + mac = mdesc_get_property(hp, vdev->mp, local_mac_prop, &len); + if (!mac) { + printk(KERN_ERR PFX "vnet lacks %s property.\n", + local_mac_prop); + err = -ENODEV; + goto err_out; + } + + dev = alloc_etherdev(sizeof(*vp)); + if (!dev) { + printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n"); + err = -ENOMEM; + goto err_out; + } + + for (i = 0; i < ETH_ALEN; i++) + dev->dev_addr[i] = (*mac >> (5 - i) * 8) & 0xff; + + memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); + + SET_NETDEV_DEV(dev, &vdev->dev); + + vp = netdev_priv(dev); + + spin_lock_init(&vp->lock); + vp->dev = dev; + vp->vdev = vdev; + + INIT_LIST_HEAD(&vp->port_list); + for (i = 0; i < VNET_PORT_HASH_SIZE; i++) + INIT_HLIST_HEAD(&vp->port_hash[i]); + + dev->open = vnet_open; + dev->stop = vnet_close; + dev->set_multicast_list = vnet_set_rx_mode; + dev->set_mac_address = vnet_set_mac_addr; + dev->tx_timeout = vnet_tx_timeout; + dev->ethtool_ops = &vnet_ethtool_ops; + dev->watchdog_timeo = VNET_TX_TIMEOUT; + dev->change_mtu = vnet_change_mtu; + dev->hard_start_xmit = vnet_start_xmit; + + err = register_netdev(dev); + if (err) { + printk(KERN_ERR PFX "Cannot register net device, " + "aborting.\n"); + goto err_out_free_dev; + } + + printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name); + + for (i = 0; i < 6; i++) + printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':'); + + dev_set_drvdata(&vdev->dev, vp); + + mdesc_release(hp); + + return 0; + +err_out_free_dev: + free_netdev(dev); + +err_out: + mdesc_release(hp); + return err; +} + +static int vnet_remove(struct vio_dev *vdev) +{ + + struct vnet *vp = dev_get_drvdata(&vdev->dev); + + if (vp) { + /* XXX unregister port, or at least check XXX */ + unregister_netdevice(vp->dev); + dev_set_drvdata(&vdev->dev, NULL); + } + return 0; +} + +static struct vio_device_id vnet_match[] = { + { + .type = "network", + }, + {}, +}; +MODULE_DEVICE_TABLE(vio, vnet_match); + +static struct vio_driver vnet_driver = { + .id_table = vnet_match, + .probe = vnet_probe, + .remove = vnet_remove, + .driver = { + .name = "vnet", + .owner = THIS_MODULE, + } +}; + +static int __init vnet_init(void) +{ + int err = vio_register_driver(&vnet_driver); + + if (!err) { + err = vio_register_driver(&vnet_port_driver); + if (err) + vio_unregister_driver(&vnet_driver); + } + + return err; +} + +static void __exit vnet_exit(void) +{ + vio_unregister_driver(&vnet_port_driver); + vio_unregister_driver(&vnet_driver); +} + +module_init(vnet_init); +module_exit(vnet_exit); diff --git a/drivers/net/sunvnet.h b/drivers/net/sunvnet.h new file mode 100644 index 0000000..1c88730 --- /dev/null +++ b/drivers/net/sunvnet.h @@ -0,0 +1,70 @@ +#ifndef _SUNVNET_H +#define _SUNVNET_H + +#define DESC_NCOOKIES(entry_size) \ + ((entry_size) - sizeof(struct vio_net_desc)) + +/* length of time before we decide the hardware is borked, + * and dev->tx_timeout() should be called to fix the problem + */ +#define VNET_TX_TIMEOUT (5 * HZ) + +#define VNET_TX_RING_SIZE 512 +#define VNET_TX_WAKEUP_THRESH(dr) ((dr)->pending / 4) + +/* VNET packets are sent in buffers with the first 6 bytes skipped + * so that after the ethernet header the IPv4/IPv6 headers are aligned + * properly. + */ +#define VNET_PACKET_SKIP 6 + +struct vnet_tx_entry { + void *buf; + unsigned int ncookies; + struct ldc_trans_cookie cookies[2]; +}; + +struct vnet; +struct vnet_port { + struct vio_driver_state vio; + + struct hlist_node hash; + u8 raddr[ETH_ALEN]; + + struct vnet *vp; + + struct vnet_tx_entry tx_bufs[VNET_TX_RING_SIZE]; + + struct list_head list; +}; + +static inline struct vnet_port *to_vnet_port(struct vio_driver_state *vio) +{ + return container_of(vio, struct vnet_port, vio); +} + +#define VNET_PORT_HASH_SIZE 16 +#define VNET_PORT_HASH_MASK (VNET_PORT_HASH_SIZE - 1) + +static inline unsigned int vnet_hashfn(u8 *mac) +{ + unsigned int val = mac[4] ^ mac[5]; + + return val & (VNET_PORT_HASH_MASK); +} + +struct vnet { + /* Protects port_list and port_hash. */ + spinlock_t lock; + + struct net_device *dev; + + u32 msg_enable; + struct vio_dev *vdev; + + struct list_head port_list; + + struct hlist_head port_hash[VNET_PORT_HASH_SIZE]; +}; + +#endif /* _SUNVNET_H */ diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 4fc8681..a3df09e 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -61,7 +61,7 @@ config COSA # config LANMEDIA tristate "LanMedia Corp. SSI/V.35, T1/E1, HSSI, T3 boards" - depends on PCI + depends on PCI && VIRT_TO_BUS ---help--- Driver for the following Lan Media family of serial boards: diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig index f46c69e4..09c93ff9 100644 --- a/drivers/parport/Kconfig +++ b/drivers/parport/Kconfig @@ -5,11 +5,9 @@ # Parport configuration. # -menu "Parallel port support" - depends on HAS_IOMEM - -config PARPORT +menuconfig PARPORT tristate "Parallel port support" + depends on HAS_IOMEM ---help--- If you want to use devices connected to your machine's parallel port (the connector at the computer with 25 holes), e.g. printer, ZIP @@ -33,9 +31,11 @@ config PARPORT If unsure, say Y. +if PARPORT + config PARPORT_PC tristate "PC-style hardware" - depends on PARPORT && (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV + depends on (!SPARC64 || PCI) && !SPARC32 && !M32R && !FRV ---help--- You should say Y here if you have a PC-style parallel port. All IBM PC compatible computers and some Alphas have PC-style @@ -85,7 +85,7 @@ config PARPORT_PC_PCMCIA config PARPORT_IP32 tristate "SGI IP32 builtin port (EXPERIMENTAL)" - depends on SGI_IP32 && PARPORT && EXPERIMENTAL + depends on SGI_IP32 && EXPERIMENTAL select PARPORT_NOT_PC help Say Y here if you need support for the parallel port on @@ -94,7 +94,7 @@ config PARPORT_IP32 config PARPORT_AMIGA tristate "Amiga builtin port" - depends on AMIGA && PARPORT + depends on AMIGA select PARPORT_NOT_PC help Say Y here if you need support for the parallel port hardware on @@ -103,7 +103,7 @@ config PARPORT_AMIGA config PARPORT_MFC3 tristate "Multiface III parallel port" - depends on ZORRO && PARPORT + depends on ZORRO select PARPORT_NOT_PC help Say Y here if you need parallel port support for the MFC3 card. @@ -112,7 +112,7 @@ config PARPORT_MFC3 config PARPORT_ATARI tristate "Atari hardware" - depends on ATARI && PARPORT + depends on ATARI select PARPORT_NOT_PC help Say Y here if you need support for the parallel port hardware on @@ -122,12 +122,11 @@ config PARPORT_ATARI config PARPORT_GSC tristate default GSC - depends on PARPORT select PARPORT_NOT_PC config PARPORT_SUNBPP tristate "Sparc hardware (EXPERIMENTAL)" - depends on SBUS && PARPORT && EXPERIMENTAL + depends on SBUS && EXPERIMENTAL select PARPORT_NOT_PC help This driver provides support for the bidirectional parallel port @@ -136,7 +135,6 @@ config PARPORT_SUNBPP config PARPORT_AX88796 tristate "AX88796 Parallel Port" - depends on PARPORT select PARPORT_NOT_PC help Say Y here if you need support for the parallel port hardware on @@ -148,7 +146,6 @@ config PARPORT_AX88796 config PARPORT_1284 bool "IEEE 1284 transfer modes" - depends on PARPORT help If you have a printer that supports status readback or device ID, or want to use a device that uses enhanced parallel port transfer modes @@ -159,5 +156,4 @@ config PARPORT_1284 config PARPORT_NOT_PC bool -endmenu - +endif # PARPORT diff --git a/drivers/parport/parport_pc.c b/drivers/parport/parport_pc.c index 7bfbad5..5d58ad5 100644 --- a/drivers/parport/parport_pc.c +++ b/drivers/parport/parport_pc.c @@ -2424,7 +2424,6 @@ static int __devinit sio_ite_8872_probe (struct pci_dev *pdev, int autoirq, u32 ite8872set; u32 ite8872_lpt, ite8872_lpthi; u8 ite8872_irq, type; - char *fake_name = "parport probe"; int irq; int i; @@ -2432,11 +2431,11 @@ static int __devinit sio_ite_8872_probe (struct pci_dev *pdev, int autoirq, // make sure which one chip for(i = 0; i < 5; i++) { - base_res = request_region(inta_addr[i], 0x8, fake_name); + base_res = request_region(inta_addr[i], 32, "it887x"); if (base_res) { int test; pci_write_config_dword (pdev, 0x60, - 0xe7000000 | inta_addr[i]); + 0xe5000000 | inta_addr[i]); pci_write_config_dword (pdev, 0x78, 0x00000000 | inta_addr[i]); test = inb (inta_addr[i]); diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c index 10dbdec..1b7b281 100644 --- a/drivers/pci/pci-sysfs.c +++ b/drivers/pci/pci-sysfs.c @@ -20,7 +20,7 @@ #include <linux/stat.h> #include <linux/topology.h> #include <linux/mm.h> - +#include <linux/capability.h> #include "pci.h" static int sysfs_initialized; /* = 0 */ diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index a7bce75..34b8dae0 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -22,6 +22,18 @@ EXPORT_SYMBOL(pci_root_buses); LIST_HEAD(pci_devices); +/* + * Some device drivers need know if pci is initiated. + * Basically, we think pci is not initiated when there + * is no device in list of pci_devices. + */ +int no_pci_devices(void) +{ + return list_empty(&pci_devices); +} + +EXPORT_SYMBOL(no_pci_devices); + #ifdef HAVE_PCI_LEGACY /** * pci_create_legacy_files - create legacy I/O port and memory files diff --git a/drivers/pci/proc.c b/drivers/pci/proc.c index cfa0dfe..90adc62 100644 --- a/drivers/pci/proc.c +++ b/drivers/pci/proc.c @@ -11,7 +11,7 @@ #include <linux/module.h> #include <linux/proc_fs.h> #include <linux/seq_file.h> - +#include <linux/capability.h> #include <asm/uaccess.h> #include <asm/byteorder.h> #include "pci.h" diff --git a/drivers/pci/search.c b/drivers/pci/search.c index 9f7090f..c6e79d0 100644 --- a/drivers/pci/search.c +++ b/drivers/pci/search.c @@ -202,7 +202,7 @@ static struct pci_dev * pci_find_subsys(unsigned int vendor, * can cause some machines to crash. So here we detect and flag that * situation and bail out early. */ - if (unlikely(list_empty(&pci_devices))) + if (unlikely(no_pci_devices())) return NULL; down_read(&pci_bus_sem); n = from ? from->global_list.next : pci_devices.next; @@ -277,7 +277,7 @@ pci_get_subsys(unsigned int vendor, unsigned int device, * can cause some machines to crash. So here we detect and flag that * situation and bail out early. */ - if (unlikely(list_empty(&pci_devices))) + if (unlikely(no_pci_devices())) return NULL; down_read(&pci_bus_sem); n = from ? from->global_list.next : pci_devices.next; diff --git a/drivers/pnp/Kconfig b/drivers/pnp/Kconfig index 1959cef..821933f 100644 --- a/drivers/pnp/Kconfig +++ b/drivers/pnp/Kconfig @@ -2,11 +2,9 @@ # Plug and Play configuration # -menu "Plug and Play support" - depends on HAS_IOMEM - -config PNP +menuconfig PNP bool "Plug and Play support" + depends on HAS_IOMEM depends on ISA || ACPI ---help--- Plug and Play (PnP) is a standard for peripherals which allows those @@ -22,15 +20,15 @@ config PNP If unsure, say Y. +if PNP + config PNP_DEBUG bool "PnP Debug Messages" - depends on PNP help Say Y if you want the Plug and Play Layer to print debug messages. This is useful if you are developing a PnP driver or troubleshooting. comment "Protocols" - depends on PNP source "drivers/pnp/isapnp/Kconfig" @@ -38,5 +36,4 @@ source "drivers/pnp/pnpbios/Kconfig" source "drivers/pnp/pnpacpi/Kconfig" -endmenu - +endif # PNP diff --git a/drivers/pnp/isapnp/Kconfig b/drivers/pnp/isapnp/Kconfig index 578651e..f1ef366 100644 --- a/drivers/pnp/isapnp/Kconfig +++ b/drivers/pnp/isapnp/Kconfig @@ -3,7 +3,7 @@ # config ISAPNP bool "ISA Plug and Play support" - depends on PNP && ISA + depends on ISA help Say Y here if you would like support for ISA Plug and Play devices. Some information is in <file:Documentation/isapnp.txt>. diff --git a/drivers/pnp/isapnp/core.c b/drivers/pnp/isapnp/core.c index a0b1587..914d00c 100644 --- a/drivers/pnp/isapnp/core.c +++ b/drivers/pnp/isapnp/core.c @@ -370,8 +370,6 @@ static int __init isapnp_read_tag(unsigned char *type, unsigned short *size) #if 0 printk(KERN_DEBUG "tag = 0x%x, type = 0x%x, size = %i\n", tag, *type, *size); #endif - if (type == 0) /* wrong type */ - return -1; if (*type == 0xff && *size == 0xffff) /* probably invalid data */ return -1; return 0; diff --git a/drivers/pnp/pnpbios/Kconfig b/drivers/pnp/pnpbios/Kconfig index fab848c..b986d9f 100644 --- a/drivers/pnp/pnpbios/Kconfig +++ b/drivers/pnp/pnpbios/Kconfig @@ -3,7 +3,7 @@ # config PNPBIOS bool "Plug and Play BIOS support (EXPERIMENTAL)" - depends on PNP && ISA && X86 && EXPERIMENTAL + depends on ISA && X86 && EXPERIMENTAL default n ---help--- Linux uses the PNPBIOS as defined in "Plug and Play BIOS diff --git a/drivers/sbus/char/cpwatchdog.c b/drivers/sbus/char/cpwatchdog.c index 022e869..7b5773d 100644 --- a/drivers/sbus/char/cpwatchdog.c +++ b/drivers/sbus/char/cpwatchdog.c @@ -24,6 +24,7 @@ #include <linux/ioport.h> #include <linux/timer.h> #include <linux/smp_lock.h> +#include <linux/io.h> #include <asm/irq.h> #include <asm/ebus.h> #include <asm/oplib.h> diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 9d2119b..3727231 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig @@ -545,7 +545,7 @@ config SCSI_HPTIOP config SCSI_BUSLOGIC tristate "BusLogic SCSI support" - depends on (PCI || ISA || MCA) && SCSI && ISA_DMA_API + depends on (PCI || ISA || MCA) && SCSI && ISA_DMA_API && VIRT_TO_BUS ---help--- This is support for BusLogic MultiMaster and FlashPoint SCSI Host Adapters. Consult the SCSI-HOWTO, available from diff --git a/drivers/serial/68360serial.c b/drivers/serial/68360serial.c index 68817a7..2aa6bfe 100644 --- a/drivers/serial/68360serial.c +++ b/drivers/serial/68360serial.c @@ -934,8 +934,6 @@ static void change_speed(ser_info_t *info) /* * Set up parity check flag */ -#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) - info->read_status_mask = (BD_SC_EMPTY | BD_SC_OV); if (I_INPCK(info->tty)) info->read_status_mask |= BD_SC_FR | BD_SC_PR; @@ -1527,11 +1525,6 @@ static void rs_360_set_termios(struct tty_struct *tty, struct ktermios *old_term { ser_info_t *info = (ser_info_t *)tty->driver_data; - if ( (tty->termios->c_cflag == old_termios->c_cflag) - && ( RELEVANT_IFLAG(tty->termios->c_iflag) - == RELEVANT_IFLAG(old_termios->c_iflag))) - return; - change_speed(info); #ifdef modem_control diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index c84dab0..0b3ec38 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -2514,12 +2514,18 @@ static int __init serial8250_console_setup(struct console *co, char *options) return uart_set_options(port, co, baud, parity, bits, flow); } +static int __init serial8250_console_early_setup(void) +{ + return serial8250_find_port_for_earlycon(); +} + static struct uart_driver serial8250_reg; static struct console serial8250_console = { .name = "ttyS", .write = serial8250_console_write, .device = uart_console_device, .setup = serial8250_console_setup, + .early_setup = serial8250_console_early_setup, .flags = CON_PRINTBUFFER, .index = -1, .data = &serial8250_reg, @@ -2533,7 +2539,7 @@ static int __init serial8250_console_init(void) } console_initcall(serial8250_console_init); -static int __init find_port(struct uart_port *p) +int serial8250_find_port(struct uart_port *p) { int line; struct uart_port *port; @@ -2546,26 +2552,6 @@ static int __init find_port(struct uart_port *p) return -ENODEV; } -int __init serial8250_start_console(struct uart_port *port, char *options) -{ - int line; - - line = find_port(port); - if (line < 0) - return -ENODEV; - - add_preferred_console("ttyS", line, options); - printk("Adding console on ttyS%d at %s 0x%lx (options '%s')\n", - line, port->iotype == UPIO_MEM ? "MMIO" : "I/O port", - port->iotype == UPIO_MEM ? (unsigned long) port->mapbase : - (unsigned long) port->iobase, options); - if (!(serial8250_console.flags & CON_ENABLED)) { - serial8250_console.flags &= ~CON_PRINTBUFFER; - register_console(&serial8250_console); - } - return line; -} - #define SERIAL8250_CONSOLE &serial8250_console #else #define SERIAL8250_CONSOLE NULL diff --git a/drivers/serial/8250_early.c b/drivers/serial/8250_early.c index 7e51119..947c205 100644 --- a/drivers/serial/8250_early.c +++ b/drivers/serial/8250_early.c @@ -17,13 +17,11 @@ * we locate the device directly by its MMIO or I/O port address. * * The user can specify the device directly, e.g., - * console=uart,io,0x3f8,9600n8 - * console=uart,mmio,0xff5e0000,115200n8 - * or platform code can call early_uart_console_init() to set - * the early UART device. - * - * After the normal serial driver starts, we try to locate the - * matching ttyS device and start a console there. + * earlycon=uart8250,io,0x3f8,9600n8 + * earlycon=uart8250,mmio,0xff5e0000,115200n8 + * or + * console=uart8250,io,0x3f8,9600n8 + * console=uart8250,mmio,0xff5e0000,115200n8 */ #include <linux/tty.h> @@ -32,17 +30,21 @@ #include <linux/serial_core.h> #include <linux/serial_reg.h> #include <linux/serial.h> +#include <linux/serial_8250.h> #include <asm/io.h> #include <asm/serial.h> +#ifdef CONFIG_FIX_EARLYCON_MEM +#include <asm/pgtable.h> +#include <asm/fixmap.h> +#endif -struct early_uart_device { +struct early_serial8250_device { struct uart_port port; char options[16]; /* e.g., 115200n8 */ unsigned int baud; }; -static struct early_uart_device early_device __initdata; -static int early_uart_registered __initdata; +static struct early_serial8250_device early_device; static unsigned int __init serial_in(struct uart_port *port, int offset) { @@ -80,7 +82,7 @@ static void __init putc(struct uart_port *port, int c) serial_out(port, UART_TX, c); } -static void __init early_uart_write(struct console *console, const char *s, unsigned int count) +static void __init early_serial8250_write(struct console *console, const char *s, unsigned int count) { struct uart_port *port = &early_device.port; unsigned int ier; @@ -111,7 +113,7 @@ static unsigned int __init probe_baud(struct uart_port *port) return (port->uartclk / 16) / quot; } -static void __init init_port(struct early_uart_device *device) +static void __init init_port(struct early_serial8250_device *device) { struct uart_port *port = &device->port; unsigned int divisor; @@ -130,10 +132,9 @@ static void __init init_port(struct early_uart_device *device) serial_out(port, UART_LCR, c & ~UART_LCR_DLAB); } -static int __init parse_options(struct early_uart_device *device, char *options) +static int __init parse_options(struct early_serial8250_device *device, char *options) { struct uart_port *port = &device->port; - int mapsize = 64; int mmio, length; if (!options) @@ -143,12 +144,18 @@ static int __init parse_options(struct early_uart_device *device, char *options) if (!strncmp(options, "mmio,", 5)) { port->iotype = UPIO_MEM; port->mapbase = simple_strtoul(options + 5, &options, 0); - port->membase = ioremap(port->mapbase, mapsize); +#ifdef CONFIG_FIX_EARLYCON_MEM + set_fixmap_nocache(FIX_EARLYCON_MEM_BASE, port->mapbase & PAGE_MASK); + port->membase = (void __iomem *)__fix_to_virt(FIX_EARLYCON_MEM_BASE); + port->membase += port->mapbase & ~PAGE_MASK; +#else + port->membase = ioremap(port->mapbase, 64); if (!port->membase) { printk(KERN_ERR "%s: Couldn't ioremap 0x%lx\n", __FUNCTION__, port->mapbase); return -ENOMEM; } +#endif mmio = 1; } else if (!strncmp(options, "io,", 3)) { port->iotype = UPIO_PORT; @@ -175,9 +182,16 @@ static int __init parse_options(struct early_uart_device *device, char *options) return 0; } -static int __init early_uart_setup(struct console *console, char *options) +static struct console early_serial8250_console __initdata = { + .name = "uart", + .write = early_serial8250_write, + .flags = CON_PRINTBUFFER | CON_BOOT, + .index = -1, +}; + +static int __init early_serial8250_setup(char *options) { - struct early_uart_device *device = &early_device; + struct early_serial8250_device *device = &early_device; int err; if (device->port.membase || device->port.iobase) @@ -190,61 +204,48 @@ static int __init early_uart_setup(struct console *console, char *options) return 0; } -static struct console early_uart_console __initdata = { - .name = "uart", - .write = early_uart_write, - .setup = early_uart_setup, - .flags = CON_PRINTBUFFER, - .index = -1, -}; - -static int __init early_uart_console_init(void) -{ - if (!early_uart_registered) { - register_console(&early_uart_console); - early_uart_registered = 1; - } - return 0; -} -console_initcall(early_uart_console_init); - -int __init early_serial_console_init(char *cmdline) +int __init setup_early_serial8250_console(char *cmdline) { char *options; int err; - options = strstr(cmdline, "console=uart,"); - if (!options) - return -ENODEV; + options = strstr(cmdline, "uart8250,"); + if (!options) { + options = strstr(cmdline, "uart,"); + if (!options) + return 0; + } options = strchr(cmdline, ',') + 1; - if ((err = early_uart_setup(NULL, options)) < 0) + if ((err = early_serial8250_setup(options)) < 0) return err; - return early_uart_console_init(); + + register_console(&early_serial8250_console); + + return 0; } -static int __init early_uart_console_switch(void) +int __init serial8250_find_port_for_earlycon(void) { - struct early_uart_device *device = &early_device; + struct early_serial8250_device *device = &early_device; struct uart_port *port = &device->port; - int mmio, line; + int line; + int ret; - if (!(early_uart_console.flags & CON_ENABLED)) - return 0; + if (!device->port.membase && !device->port.iobase) + return -ENODEV; - /* Try to start the normal driver on a matching line. */ - mmio = (port->iotype == UPIO_MEM); - line = serial8250_start_console(port, device->options); + line = serial8250_find_port(port); if (line < 0) - printk("No ttyS device at %s 0x%lx for console\n", - mmio ? "MMIO" : "I/O port", - mmio ? port->mapbase : - (unsigned long) port->iobase); + return -ENODEV; - unregister_console(&early_uart_console); - if (mmio) - iounmap(port->membase); + ret = update_console_cmdline("uart", 8250, + "ttyS", line, device->options); + if (ret < 0) + ret = update_console_cmdline("uart", 0, + "ttyS", line, device->options); - return 0; + return ret; } -late_initcall(early_uart_console_switch); + +early_param("earlycon", setup_early_serial8250_console); diff --git a/drivers/serial/Kconfig b/drivers/serial/Kconfig index 2adbed4..cab42cb 100644 --- a/drivers/serial/Kconfig +++ b/drivers/serial/Kconfig @@ -62,8 +62,22 @@ config SERIAL_8250_CONSOLE kernel will automatically use the first serial line, /dev/ttyS0, as system console. + you can set that using a kernel command line option such as + "console=uart8250,io,0x3f8,9600n8" + "console=uart8250,mmio,0xff5e0000,115200n8". + and it will switch to normal serial console when correponding port is + ready. + "earlycon=uart8250,io,0x3f8,9600n8" + "earlycon=uart8250,mmio,0xff5e0000,115200n8". + it will not only setup early console. + If unsure, say N. +config FIX_EARLYCON_MEM + bool + depends on X86 + default y + config SERIAL_8250_GSC tristate depends on SERIAL_8250 && GSC diff --git a/drivers/serial/atmel_serial.c b/drivers/serial/atmel_serial.c index 3320bcd..4d6b3c5 100644 --- a/drivers/serial/atmel_serial.c +++ b/drivers/serial/atmel_serial.c @@ -114,6 +114,7 @@ struct atmel_uart_port { struct uart_port uart; /* uart */ struct clk *clk; /* uart clock */ unsigned short suspended; /* is port suspended? */ + int break_active; /* break being received */ }; static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART]; @@ -252,6 +253,7 @@ static void atmel_break_ctl(struct uart_port *port, int break_state) */ static void atmel_rx_chars(struct uart_port *port) { + struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port; struct tty_struct *tty = port->info->tty; unsigned int status, ch, flg; @@ -267,13 +269,29 @@ static void atmel_rx_chars(struct uart_port *port) * note that the error handling code is * out of the main execution path */ - if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME | ATMEL_US_OVRE | ATMEL_US_RXBRK))) { + if (unlikely(status & (ATMEL_US_PARE | ATMEL_US_FRAME + | ATMEL_US_OVRE | ATMEL_US_RXBRK) + || atmel_port->break_active)) { UART_PUT_CR(port, ATMEL_US_RSTSTA); /* clear error */ - if (status & ATMEL_US_RXBRK) { + if (status & ATMEL_US_RXBRK + && !atmel_port->break_active) { status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME); /* ignore side-effect */ port->icount.brk++; + atmel_port->break_active = 1; + UART_PUT_IER(port, ATMEL_US_RXBRK); if (uart_handle_break(port)) goto ignore_char; + } else { + /* + * This is either the end-of-break + * condition or we've received at + * least one character without RXBRK + * being set. In both cases, the next + * RXBRK will indicate start-of-break. + */ + UART_PUT_IDR(port, ATMEL_US_RXBRK); + status &= ~ATMEL_US_RXBRK; + atmel_port->break_active = 0; } if (status & ATMEL_US_PARE) port->icount.parity++; @@ -352,6 +370,16 @@ static irqreturn_t atmel_interrupt(int irq, void *dev_id) /* Interrupt receive */ if (pending & ATMEL_US_RXRDY) atmel_rx_chars(port); + else if (pending & ATMEL_US_RXBRK) { + /* + * End of break detected. If it came along + * with a character, atmel_rx_chars will + * handle it. + */ + UART_PUT_CR(port, ATMEL_US_RSTSTA); + UART_PUT_IDR(port, ATMEL_US_RXBRK); + atmel_port->break_active = 0; + } // TODO: All reads to CSR will clear these interrupts! if (pending & ATMEL_US_RIIC) port->icount.rng++; diff --git a/drivers/serial/ip22zilog.c b/drivers/serial/ip22zilog.c index c3abfb3..f3257f7 100644 --- a/drivers/serial/ip22zilog.c +++ b/drivers/serial/ip22zilog.c @@ -862,6 +862,7 @@ ip22zilog_set_termios(struct uart_port *port, struct ktermios *termios, up->cflag = termios->c_cflag; ip22zilog_maybe_update_regs(up, ZILOG_CHANNEL_FROM_PORT(port)); + uart_update_timeout(port, termios->c_cflag, baud); spin_unlock_irqrestore(&up->port.lock, flags); } @@ -1017,6 +1018,8 @@ ip22serial_console_termios(struct console *con, char *options) } con->cflag = cflag | CS8; /* 8N1 */ + + uart_update_timeout(&ip22zilog_port_table[con->index].port, cflag, baud); } static int __init ip22zilog_console_setup(struct console *con, char *options) diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index 326020f..9c57486 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -1910,6 +1910,12 @@ uart_set_options(struct uart_port *port, struct console *co, if (flow == 'r') termios.c_cflag |= CRTSCTS; + /* + * some uarts on other side don't support no flow control. + * So we set * DTR in host uart to make them happy + */ + port->mctrl |= TIOCM_DTR; + port->ops->set_termios(port, &termios, NULL); co->cflag = termios.c_cflag; diff --git a/drivers/serial/sh-sci.c b/drivers/serial/sh-sci.c index 1f89496..672cd10 100644 --- a/drivers/serial/sh-sci.c +++ b/drivers/serial/sh-sci.c @@ -367,7 +367,9 @@ static void sci_init_pins_scif(struct uart_port *port, unsigned int cflag) } else { #ifdef CONFIG_CPU_SUBTYPE_SH7343 /* Nothing */ -#elif defined(CONFIG_CPU_SUBTYPE_SH7780) || defined(CONFIG_CPU_SUBTYPE_SH7785) +#elif defined(CONFIG_CPU_SUBTYPE_SH7780) || \ + defined(CONFIG_CPU_SUBTYPE_SH7785) || \ + defined(CONFIG_CPU_SUBTYPE_SHX3) ctrl_outw(0x0080, SCSPTR0); /* Set RTS = 1 */ #else ctrl_outw(0x0080, SCSPTR2); /* Set RTS = 1 */ diff --git a/drivers/serial/sh-sci.h b/drivers/serial/sh-sci.h index fb04fb5..247fb66 100644 --- a/drivers/serial/sh-sci.h +++ b/drivers/serial/sh-sci.h @@ -53,7 +53,12 @@ # define SCIF_ORER 0x0001 /* overrun error bit */ # define SCSCR_INIT(port) 0x3a /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ # define SCIF_ONLY -#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || defined(CONFIG_CPU_SUBTYPE_SH7751) +#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \ + defined(CONFIG_CPU_SUBTYPE_SH7750R) || \ + defined(CONFIG_CPU_SUBTYPE_SH7750S) || \ + defined(CONFIG_CPU_SUBTYPE_SH7091) || \ + defined(CONFIG_CPU_SUBTYPE_SH7751) || \ + defined(CONFIG_CPU_SUBTYPE_SH7751R) # define SCSPTR1 0xffe0001c /* 8 bit SCI */ # define SCSPTR2 0xFFE80020 /* 16 bit SCIF */ # define SCIF_ORER 0x0001 /* overrun error bit */ @@ -73,7 +78,7 @@ # define SCPDR 0xA4050136 /* 16 bit SCIF */ # define SCSCR_INIT(port) 0x0030 /* TIE=0,RIE=0,TE=1,RE=1 */ # define SCIF_ONLY -#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) +#elif defined(CONFIG_CPU_SUBTYPE_SH7710) || defined(CONFIG_CPU_SUBTYPE_SH7712) # define SCSPTR0 0xA4400000 /* 16 bit SCIF */ # define SCI_NPORTS 2 # define SCIF_ORER 0x0001 /* overrun error bit */ @@ -168,6 +173,14 @@ # define SCIF_ORER 0x0001 /* overrun error bit */ # define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ # define SCIF_ONLY +#elif defined(CONFIG_CPU_SUBTYPE_SHX3) +# define SCSPTR0 0xffc30020 /* 16 bit SCIF */ +# define SCSPTR1 0xffc40020 /* 16 bit SCIF */ +# define SCSPTR2 0xffc50020 /* 16 bit SCIF */ +# define SCSPTR3 0xffc60020 /* 16 bit SCIF */ +# define SCIF_ORER 0x0001 /* Overrun error bit */ +# define SCSCR_INIT(port) 0x38 /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */ +# define SCIF_ONLY #else # error CPU subtype not defined #endif @@ -177,10 +190,15 @@ #define SCI_CTRL_FLAGS_RIE 0x40 /* all */ #define SCI_CTRL_FLAGS_TE 0x20 /* all */ #define SCI_CTRL_FLAGS_RE 0x10 /* all */ -#if defined(CONFIG_CPU_SUBTYPE_SH7750) || \ - defined(CONFIG_CPU_SUBTYPE_SH7751) || \ - defined(CONFIG_CPU_SUBTYPE_SH7780) || \ - defined(CONFIG_CPU_SUBTYPE_SH7785) +#if defined(CONFIG_CPU_SUBTYPE_SH7750) || \ + defined(CONFIG_CPU_SUBTYPE_SH7091) || \ + defined(CONFIG_CPU_SUBTYPE_SH7750R) || \ + defined(CONFIG_CPU_SUBTYPE_SH7750S) || \ + defined(CONFIG_CPU_SUBTYPE_SH7751) || \ + defined(CONFIG_CPU_SUBTYPE_SH7751R) || \ + defined(CONFIG_CPU_SUBTYPE_SH7780) || \ + defined(CONFIG_CPU_SUBTYPE_SH7785) || \ + defined(CONFIG_CPU_SUBTYPE_SHX3) #define SCI_CTRL_FLAGS_REIE 0x08 /* 7750 SCIF */ #else #define SCI_CTRL_FLAGS_REIE 0 @@ -514,8 +532,12 @@ static inline void set_sh771x_scif_pfc(struct uart_port *port) } } -#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \ - defined(CONFIG_CPU_SUBTYPE_SH7751) || \ +#elif defined(CONFIG_CPU_SUBTYPE_SH7750) || \ + defined(CONFIG_CPU_SUBTYPE_SH7751) || \ + defined(CONFIG_CPU_SUBTYPE_SH7751R) || \ + defined(CONFIG_CPU_SUBTYPE_SH7750R) || \ + defined(CONFIG_CPU_SUBTYPE_SH7750S) || \ + defined(CONFIG_CPU_SUBTYPE_SH7091) || \ defined(CONFIG_CPU_SUBTYPE_SH4_202) static inline int sci_rxd_in(struct uart_port *port) { @@ -653,6 +675,18 @@ static inline int sci_rxd_in(struct uart_port *port) return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */ return 1; } +#elif defined(CONFIG_CPU_SUBTYPE_SHX3) +static inline int sci_rxd_in(struct uart_port *port) +{ + if (port->mapbase == 0xffc30000) + return ctrl_inw(SCSPTR0) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xffc40000) + return ctrl_inw(SCSPTR1) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xffc50000) + return ctrl_inw(SCSPTR2) & 0x0001 ? 1 : 0; /* SCIF */ + if (port->mapbase == 0xffc60000) + return ctrl_inw(SCSPTR3) & 0x0001 ? 1 : 0; /* SCIF */ +} #endif /* diff --git a/drivers/serial/sn_console.c b/drivers/serial/sn_console.c index a27e9e9..41fc6126 100644 --- a/drivers/serial/sn_console.c +++ b/drivers/serial/sn_console.c @@ -759,7 +759,7 @@ static void __init sn_sal_switch_to_interrupts(struct sn_cons_port *port) */ static void sn_sal_console_write(struct console *, const char *, unsigned); -static int __init sn_sal_console_setup(struct console *, char *); +static int sn_sal_console_setup(struct console *, char *); static struct uart_driver sal_console_uart; extern struct tty_driver *uart_console_device(struct console *, int *); @@ -1006,7 +1006,7 @@ sn_sal_console_write(struct console *co, const char *s, unsigned count) * here so providing it is easier. * */ -static int __init sn_sal_console_setup(struct console *co, char *options) +static int sn_sal_console_setup(struct console *co, char *options) { return 0; } diff --git a/drivers/serial/sunhv.c b/drivers/serial/sunhv.c index 96557e6..17bcca5 100644 --- a/drivers/serial/sunhv.c +++ b/drivers/serial/sunhv.c @@ -440,8 +440,16 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign { struct uart_port *port = sunhv_port; unsigned long flags; + int locked = 1; + + local_irq_save(flags); + if (port->sysrq) { + locked = 0; + } else if (oops_in_progress) { + locked = spin_trylock(&port->lock); + } else + spin_lock(&port->lock); - spin_lock_irqsave(&port->lock, flags); while (n > 0) { unsigned long ra = __pa(con_write_page); unsigned long page_bytes; @@ -469,7 +477,10 @@ static void sunhv_console_write_paged(struct console *con, const char *s, unsign ra += written; } } - spin_unlock_irqrestore(&port->lock, flags); + + if (locked) + spin_unlock(&port->lock); + local_irq_restore(flags); } static inline void sunhv_console_putchar(struct uart_port *port, char c) @@ -488,7 +499,15 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig { struct uart_port *port = sunhv_port; unsigned long flags; - int i; + int i, locked = 1; + + local_irq_save(flags); + if (port->sysrq) { + locked = 0; + } else if (oops_in_progress) { + locked = spin_trylock(&port->lock); + } else + spin_lock(&port->lock); spin_lock_irqsave(&port->lock, flags); for (i = 0; i < n; i++) { @@ -496,7 +515,10 @@ static void sunhv_console_write_bychar(struct console *con, const char *s, unsig sunhv_console_putchar(port, '\r'); sunhv_console_putchar(port, *s++); } - spin_unlock_irqrestore(&port->lock, flags); + + if (locked) + spin_unlock(&port->lock); + local_irq_restore(flags); } static struct console sunhv_console = { diff --git a/drivers/serial/sunsab.c b/drivers/serial/sunsab.c index deb9ab4..8a0f9e4 100644 --- a/drivers/serial/sunsab.c +++ b/drivers/serial/sunsab.c @@ -860,22 +860,31 @@ static int num_channels; static void sunsab_console_putchar(struct uart_port *port, int c) { struct uart_sunsab_port *up = (struct uart_sunsab_port *)port; - unsigned long flags; - - spin_lock_irqsave(&up->port.lock, flags); sunsab_tec_wait(up); writeb(c, &up->regs->w.tic); - - spin_unlock_irqrestore(&up->port.lock, flags); } static void sunsab_console_write(struct console *con, const char *s, unsigned n) { struct uart_sunsab_port *up = &sunsab_ports[con->index]; + unsigned long flags; + int locked = 1; + + local_irq_save(flags); + if (up->port.sysrq) { + locked = 0; + } else if (oops_in_progress) { + locked = spin_trylock(&up->port.lock); + } else + spin_lock(&up->port.lock); uart_console_write(&up->port, s, n, sunsab_console_putchar); sunsab_tec_wait(up); + + if (locked) + spin_unlock(&up->port.lock); + local_irq_restore(flags); } static int sunsab_console_setup(struct console *con, char *options) diff --git a/drivers/serial/sunsu.c b/drivers/serial/sunsu.c index 2a63cdb..26d720b 100644 --- a/drivers/serial/sunsu.c +++ b/drivers/serial/sunsu.c @@ -1288,7 +1288,17 @@ static void sunsu_console_write(struct console *co, const char *s, unsigned int count) { struct uart_sunsu_port *up = &sunsu_ports[co->index]; + unsigned long flags; unsigned int ier; + int locked = 1; + + local_irq_save(flags); + if (up->port.sysrq) { + locked = 0; + } else if (oops_in_progress) { + locked = spin_trylock(&up->port.lock); + } else + spin_lock(&up->port.lock); /* * First save the UER then disable the interrupts @@ -1304,6 +1314,10 @@ static void sunsu_console_write(struct console *co, const char *s, */ wait_for_xmitr(up); serial_out(up, UART_IER, ier); + + if (locked) + spin_unlock(&up->port.lock); + local_irq_restore(flags); } /* diff --git a/drivers/serial/sunzilog.c b/drivers/serial/sunzilog.c index 15b6e1c..0a3e10a 100644 --- a/drivers/serial/sunzilog.c +++ b/drivers/serial/sunzilog.c @@ -9,7 +9,7 @@ * C. Dost, Pete Zaitcev, Ted Ts'o and Alex Buell for their * work there. * - * Copyright (C) 2002, 2006 David S. Miller (davem@davemloft.net) + * Copyright (C) 2002, 2006, 2007 David S. Miller (davem@davemloft.net) */ #include <linux/module.h> @@ -1151,11 +1151,22 @@ sunzilog_console_write(struct console *con, const char *s, unsigned int count) { struct uart_sunzilog_port *up = &sunzilog_port_table[con->index]; unsigned long flags; + int locked = 1; + + local_irq_save(flags); + if (up->port.sysrq) { + locked = 0; + } else if (oops_in_progress) { + locked = spin_trylock(&up->port.lock); + } else + spin_lock(&up->port.lock); - spin_lock_irqsave(&up->port.lock, flags); uart_console_write(&up->port, s, count, sunzilog_putchar); udelay(2); - spin_unlock_irqrestore(&up->port.lock, flags); + + if (locked) + spin_unlock(&up->port.lock); + local_irq_restore(flags); } static int __init sunzilog_console_setup(struct console *con, char *options) diff --git a/drivers/telephony/Kconfig b/drivers/telephony/Kconfig index dd1d6a5..8f530e6 100644 --- a/drivers/telephony/Kconfig +++ b/drivers/telephony/Kconfig @@ -2,11 +2,9 @@ # Telephony device configuration # -menu "Telephony Support" +menuconfig PHONE + tristate "Telephony support" depends on HAS_IOMEM - -config PHONE - tristate "Linux telephony support" ---help--- Say Y here if you have a telephony card, which for example allows you to use a regular phone for voice-over-IP applications. @@ -17,9 +15,10 @@ config PHONE To compile this driver as a module, choose M here: the module will be called phonedev. +if PHONE + config PHONE_IXJ tristate "QuickNet Internet LineJack/PhoneJack support" - depends on PHONE ---help--- Say M if you have a telephony card manufactured by Quicknet Technologies, Inc. These include the Internet PhoneJACK and @@ -44,5 +43,4 @@ config PHONE_IXJ_PCMCIA cards manufactured by Quicknet Technologies, Inc. This changes the card initialization code to work with the card manager daemon. -endmenu - +endif # PHONE diff --git a/drivers/video/pvr2fb.c b/drivers/video/pvr2fb.c index df2909a..2ba959a 100644 --- a/drivers/video/pvr2fb.c +++ b/drivers/video/pvr2fb.c @@ -115,11 +115,11 @@ enum { VO_PAL, VO_NTSC, VO_VGA }; enum { PAL_ARGB1555, PAL_RGB565, PAL_ARGB4444, PAL_ARGB8888 }; struct pvr2_params { unsigned int val; char *name; }; -static struct pvr2_params cables[] __initdata = { +static struct pvr2_params cables[] __devinitdata = { { CT_VGA, "VGA" }, { CT_RGB, "RGB" }, { CT_COMPOSITE, "COMPOSITE" }, }; -static struct pvr2_params outputs[] __initdata = { +static struct pvr2_params outputs[] __devinitdata = { { VO_PAL, "PAL" }, { VO_NTSC, "NTSC" }, { VO_VGA, "VGA" }, }; @@ -147,16 +147,16 @@ static struct pvr2fb_par { static struct fb_info *fb_info; -static struct fb_fix_screeninfo pvr2_fix __initdata = { +static struct fb_fix_screeninfo pvr2_fix __devinitdata = { .id = "NEC PowerVR2", - .type = FB_TYPE_PACKED_PIXELS, - .visual = FB_VISUAL_TRUECOLOR, + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_TRUECOLOR, .ypanstep = 1, .ywrapstep = 1, - .accel = FB_ACCEL_NONE, + .accel = FB_ACCEL_NONE, }; -static struct fb_var_screeninfo pvr2_var __initdata = { +static struct fb_var_screeninfo pvr2_var __devinitdata = { .xres = 640, .yres = 480, .xres_virtual = 640, @@ -195,10 +195,6 @@ static unsigned int shdma = PVR2_CASCADE_CHAN; static unsigned int pvr2dma = ONCHIP_NR_DMA_CHANNELS; #endif -/* Interface used by the world */ - -int pvr2fb_setup(char*); - static int pvr2fb_setcolreg(unsigned int regno, unsigned int red, unsigned int green, unsigned int blue, unsigned int transp, struct fb_info *info); static int pvr2fb_blank(int blank, struct fb_info *info); @@ -227,12 +223,12 @@ static struct fb_ops pvr2fb_ops = { #ifdef CONFIG_SH_DMA .fb_write = pvr2fb_write, #endif - .fb_fillrect = cfb_fillrect, + .fb_fillrect = cfb_fillrect, .fb_copyarea = cfb_copyarea, .fb_imageblit = cfb_imageblit, }; -static struct fb_videomode pvr2_modedb[] __initdata = { +static struct fb_videomode pvr2_modedb[] __devinitdata = { /* * Broadcast video modes (PAL and NTSC). I'm unfamiliar with * PAL-M and PAL-N, but from what I've read both modes parallel PAL and @@ -252,7 +248,7 @@ static struct fb_videomode pvr2_modedb[] __initdata = { /* 640x480 @ 60hz (VGA) */ "vga_640x480", 60, 640, 480, VGA_CLK, 38, 33, 0, 18, 146, 26, 0, FB_VMODE_YWRAP - }, + }, }; #define NUM_TOTAL_MODES ARRAY_SIZE(pvr2_modedb) @@ -262,7 +258,7 @@ static struct fb_videomode pvr2_modedb[] __initdata = { #define DEFMODE_VGA 2 static int defmode = DEFMODE_NTSC; -static char *mode_option __initdata = NULL; +static char *mode_option __devinitdata = NULL; static inline void pvr2fb_set_pal_type(unsigned int type) { @@ -293,7 +289,7 @@ static void set_color_bitfields(struct fb_var_screeninfo *var) { switch (var->bits_per_pixel) { case 16: /* RGB 565 */ - pvr2fb_set_pal_type(PAL_RGB565); + pvr2fb_set_pal_type(PAL_RGB565); var->red.offset = 11; var->red.length = 5; var->green.offset = 5; var->green.length = 6; var->blue.offset = 0; var->blue.length = 5; @@ -306,7 +302,7 @@ static void set_color_bitfields(struct fb_var_screeninfo *var) var->transp.offset = 0; var->transp.length = 0; break; case 32: /* ARGB 8888 */ - pvr2fb_set_pal_type(PAL_ARGB8888); + pvr2fb_set_pal_type(PAL_ARGB8888); var->red.offset = 16; var->red.length = 8; var->green.offset = 8; var->green.length = 8; var->blue.offset = 0; var->blue.length = 8; @@ -379,13 +375,13 @@ static int pvr2fb_set_par(struct fb_info *info) var->vmode &= FB_VMODE_MASK; if (var->vmode & FB_VMODE_INTERLACED && video_output != VO_VGA) par->is_interlaced = 1; - /* + /* * XXX: Need to be more creative with this (i.e. allow doublecan for * PAL/NTSC output). */ if (var->vmode & FB_VMODE_DOUBLE && video_output == VO_VGA) par->is_doublescan = 1; - + par->hsync_total = var->left_margin + var->xres + var->right_margin + var->hsync_len; par->vsync_total = var->upper_margin + var->yres + var->lower_margin + @@ -408,7 +404,7 @@ static int pvr2fb_set_par(struct fb_info *info) } else { /* VGA mode */ /* XXX: What else needs to be checked? */ - /* + /* * XXX: We have a little freedom in VGA modes, what ranges * should be here (i.e. hsync/vsync totals, etc.)? */ @@ -419,8 +415,8 @@ static int pvr2fb_set_par(struct fb_info *info) /* Calculate the remainding offsets */ par->diwstart_h = par->borderstart_h + var->left_margin; par->diwstart_v = par->borderstart_v + var->upper_margin; - par->borderstop_h = par->diwstart_h + var->xres + - var->right_margin; + par->borderstop_h = par->diwstart_h + var->xres + + var->right_margin; par->borderstop_v = par->diwstart_v + var->yres + var->lower_margin; @@ -465,12 +461,12 @@ static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) set_color_bitfields(var); if (var->vmode & FB_VMODE_YWRAP) { - if (var->xoffset || var->yoffset < 0 || + if (var->xoffset || var->yoffset < 0 || var->yoffset >= var->yres_virtual) { var->xoffset = var->yoffset = 0; } else { if (var->xoffset > var->xres_virtual - var->xres || - var->yoffset > var->yres_virtual - var->yres || + var->yoffset > var->yres_virtual - var->yres || var->xoffset < 0 || var->yoffset < 0) var->xoffset = var->yoffset = 0; } @@ -478,7 +474,7 @@ static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) var->xoffset = var->yoffset = 0; } - /* + /* * XXX: Need to be more creative with this (i.e. allow doublecan for * PAL/NTSC output). */ @@ -507,7 +503,7 @@ static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) var->vsync_len = par->borderstop_v + (par->vsync_total - par->borderstop_v); } - + hsync_total = var->left_margin + var->xres + var->right_margin + var->hsync_len; vtotal = var->upper_margin + var->yres + var->lower_margin + @@ -531,7 +527,7 @@ static int pvr2fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) } } } - + /* Check memory sizes */ line_length = get_line_length(var->xres_virtual, var->bits_per_pixel); if (line_length * var->yres_virtual > info->fix.smem_len) @@ -552,7 +548,7 @@ static void pvr2_update_display(struct fb_info *info) DISP_DIWADDRS); } -/* +/* * Initialize the video mode. Currently, the 16bpp and 24bpp modes aren't * very stable. It's probably due to the fact that a lot of the 2D video * registers are still undocumented. @@ -592,18 +588,18 @@ static void pvr2_init_display(struct fb_info *info) /* display window start position */ fb_writel(par->diwstart_h, DISP_DIWHSTRT); fb_writel((par->diwstart_v << 16) | par->diwstart_v, DISP_DIWVSTRT); - + /* misc. settings */ fb_writel((0x16 << 16) | par->is_lowres, DISP_DIWCONF); /* clock doubler (for VGA), scan doubler, display enable */ - fb_writel(((video_output == VO_VGA) << 23) | + fb_writel(((video_output == VO_VGA) << 23) | (par->is_doublescan << 1) | 1, DISP_DIWMODE); /* bits per pixel */ fb_writel(fb_readl(DISP_DIWMODE) | (--bytesperpixel << 2), DISP_DIWMODE); - /* video enable, color sync, interlace, + /* video enable, color sync, interlace, * hsync and vsync polarity (currently unused) */ fb_writel(0x100 | ((par->is_interlaced /*|4*/) << 4), DISP_SYNCCONF); } @@ -657,7 +653,7 @@ static irqreturn_t pvr2fb_interrupt(int irq, void *dev_id) static int pvr2_init_cable(void) { if (cable_type < 0) { - fb_writel((fb_readl(PCTRA) & 0xfff0ffff) | 0x000a0000, + fb_writel((fb_readl(PCTRA) & 0xfff0ffff) | 0x000a0000, PCTRA); cable_type = (fb_readw(PDTRA) >> 8) & 3; } @@ -687,7 +683,7 @@ static ssize_t pvr2fb_write(struct fb_info *info, const char *buf, pages = kmalloc(nr_pages * sizeof(struct page *), GFP_KERNEL); if (!pages) return -ENOMEM; - + down_read(¤t->mm->mmap_sem); ret = get_user_pages(current, current->mm, (unsigned long)buf, nr_pages, WRITE, 0, pages, NULL); @@ -700,7 +696,7 @@ static ssize_t pvr2fb_write(struct fb_info *info, const char *buf, } dma_configure_channel(shdma, 0x12c1); - + dst = (unsigned long)fb_info->screen_base + *ppos; start = (unsigned long)page_address(pages[0]); end = (unsigned long)page_address(pages[nr_pages]); @@ -744,7 +740,7 @@ out_unmap: kfree(pages); return ret; -} +} #endif /* CONFIG_SH_DMA */ /** @@ -765,21 +761,21 @@ out_unmap: * in for flexibility anyways. Who knows, maybe someone has tv-out on a * PCI-based version of these things ;-) */ -static int __init pvr2fb_common_init(void) +static int __devinit pvr2fb_common_init(void) { struct pvr2fb_par *par = currentpar; unsigned long modememused, rev; fb_info->screen_base = ioremap_nocache(pvr2_fix.smem_start, pvr2_fix.smem_len); - + if (!fb_info->screen_base) { printk(KERN_ERR "pvr2fb: Failed to remap smem space\n"); goto out_err; } par->mmio_base = (unsigned long)ioremap_nocache(pvr2_fix.mmio_start, - pvr2_fix.mmio_len); + pvr2_fix.mmio_len); if (!par->mmio_base) { printk(KERN_ERR "pvr2fb: Failed to remap mmio space\n"); goto out_err; @@ -820,7 +816,7 @@ static int __init pvr2fb_common_init(void) printk("fb%d: %s (rev %ld.%ld) frame buffer device, using %ldk/%ldk of video memory\n", fb_info->node, fb_info->fix.id, (rev >> 4) & 0x0f, rev & 0x0f, modememused >> 10, (unsigned long)(fb_info->fix.smem_len >> 10)); - printk("fb%d: Mode %dx%d-%d pitch = %ld cable: %s video output: %s\n", + printk("fb%d: Mode %dx%d-%d pitch = %ld cable: %s video output: %s\n", fb_info->node, fb_info->var.xres, fb_info->var.yres, fb_info->var.bits_per_pixel, get_line_length(fb_info->var.xres, fb_info->var.bits_per_pixel), @@ -878,8 +874,8 @@ static int __init pvr2fb_dc_init(void) video_output = VO_NTSC; } } - - /* + + /* * Nothing exciting about the DC PVR2 .. only a measly 8MiB. */ pvr2_fix.smem_start = 0xa5000000; /* RAM starts here */ @@ -903,7 +899,7 @@ static int __init pvr2fb_dc_init(void) return pvr2fb_common_init(); } -static void pvr2fb_dc_exit(void) +static void __exit pvr2fb_dc_exit(void) { if (fb_info->screen_base) { iounmap(fb_info->screen_base); @@ -987,13 +983,13 @@ static int __init pvr2fb_pci_init(void) return pci_register_driver(&pvr2fb_pci_driver); } -static void pvr2fb_pci_exit(void) +static void __exit pvr2fb_pci_exit(void) { pci_unregister_driver(&pvr2fb_pci_driver); } #endif /* CONFIG_PCI */ -static int __init pvr2_get_param(const struct pvr2_params *p, const char *s, +static int __devinit pvr2_get_param(const struct pvr2_params *p, const char *s, int val, int size) { int i; @@ -1021,7 +1017,7 @@ static int __init pvr2_get_param(const struct pvr2_params *p, const char *s, */ #ifndef MODULE -int __init pvr2fb_setup(char *options) +static int __init pvr2fb_setup(char *options) { char *this_opt; char cable_arg[80]; @@ -1061,7 +1057,7 @@ static struct pvr2_board { int (*init)(void); void (*exit)(void); char name[16]; -} board_list[] = { +} board_driver[] = { #ifdef CONFIG_SH_DREAMCAST { pvr2fb_dc_init, pvr2fb_dc_exit, "Sega DC PVR2" }, #endif @@ -1071,7 +1067,7 @@ static struct pvr2_board { { 0, }, }; -int __init pvr2fb_init(void) +static int __init pvr2fb_init(void) { int i, ret = -ENODEV; int size; @@ -1095,8 +1091,8 @@ int __init pvr2fb_init(void) currentpar = (struct pvr2fb_par *)(fb_info + 1); - for (i = 0; i < ARRAY_SIZE(board_list); i++) { - struct pvr2_board *pvr_board = board_list + i; + for (i = 0; i < ARRAY_SIZE(board_driver); i++) { + struct pvr2_board *pvr_board = board_driver + i; if (!pvr_board->init) continue; @@ -1118,13 +1114,13 @@ static void __exit pvr2fb_exit(void) { int i; - for (i = 0; i < ARRAY_SIZE(board_list); i++) { - struct pvr2_board *pvr_board = board_list + i; + for (i = 0; i < ARRAY_SIZE(board_driver); i++) { + struct pvr2_board *pvr_board = board_driver + i; if (pvr_board->exit) pvr_board->exit(); } - + #ifdef CONFIG_SH_STORE_QUEUES sq_unmap(pvr2fb_map); #endif @@ -1139,4 +1135,3 @@ module_exit(pvr2fb_exit); MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>, M. R. Brown <mrbrown@0xd6.org>"); MODULE_DESCRIPTION("Framebuffer driver for NEC PowerVR 2 based graphics boards"); MODULE_LICENSE("GPL"); - diff --git a/drivers/w1/Kconfig b/drivers/w1/Kconfig index ca75b3a..6854fd6 100644 --- a/drivers/w1/Kconfig +++ b/drivers/w1/Kconfig @@ -1,8 +1,6 @@ -menu "Dallas's 1-wire bus" - depends on HAS_IOMEM - -config W1 +menuconfig W1 tristate "Dallas's 1-wire support" + depends on HAS_IOMEM ---help--- Dallas' 1-wire bus is useful to connect slow 1-pin devices such as iButtons and thermal sensors. @@ -12,8 +10,10 @@ config W1 This W1 support can also be built as a module. If so, the module will be called wire.ko. +if W1 + config W1_CON - depends on CONNECTOR && W1 + depends on CONNECTOR bool "Userspace communication over connector" default y --- help --- @@ -27,4 +27,4 @@ config W1_CON source drivers/w1/masters/Kconfig source drivers/w1/slaves/Kconfig -endmenu +endif # W1 diff --git a/drivers/w1/masters/Kconfig b/drivers/w1/masters/Kconfig index 8f77933..8236d44 100644 --- a/drivers/w1/masters/Kconfig +++ b/drivers/w1/masters/Kconfig @@ -3,11 +3,10 @@ # menu "1-wire Bus Masters" - depends on W1 config W1_MASTER_MATROX tristate "Matrox G400 transport layer for 1-wire" - depends on W1 && PCI + depends on PCI help Say Y here if you want to communicate with your 1-wire devices using Matrox's G400 GPIO pins. @@ -17,7 +16,7 @@ config W1_MASTER_MATROX config W1_MASTER_DS2490 tristate "DS2490 USB <-> W1 transport layer for 1-wire" - depends on W1 && USB + depends on USB help Say Y here if you want to have a driver for DS2490 based USB <-> W1 bridges, for example DS9490*. @@ -27,7 +26,7 @@ config W1_MASTER_DS2490 config W1_MASTER_DS2482 tristate "Maxim DS2482 I2C to 1-Wire bridge" - depends on I2C && W1 && EXPERIMENTAL + depends on I2C && EXPERIMENTAL help If you say yes here you get support for the Maxim DS2482 I2C to 1-Wire bridge. diff --git a/drivers/w1/slaves/Kconfig b/drivers/w1/slaves/Kconfig index df95d6c..3df29a1 100644 --- a/drivers/w1/slaves/Kconfig +++ b/drivers/w1/slaves/Kconfig @@ -3,25 +3,21 @@ # menu "1-wire Slaves" - depends on W1 config W1_SLAVE_THERM tristate "Thermal family implementation" - depends on W1 help Say Y here if you want to connect 1-wire thermal sensors to your wire. config W1_SLAVE_SMEM tristate "Simple 64bit memory family implementation" - depends on W1 help Say Y here if you want to connect 1-wire simple 64bit memory rom(ds2401/ds2411/ds1990*) to your wire. config W1_SLAVE_DS2433 tristate "4kb EEPROM family support (DS2433)" - depends on W1 help Say Y here if you want to use a 1-wire 4kb EEPROM family device (DS2433). |