diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/arch/i386/Kconfig linux-2.6.11/arch/i386/Kconfig --- linux.vanilla-2.6.11/arch/i386/Kconfig 2005-03-05 15:16:59.000000000 +0000 +++ linux-2.6.11/arch/i386/Kconfig 2005-03-05 15:28:14.000000000 +0000 @@ -330,6 +330,14 @@ endchoice +config X86_HZ + int "Clock Tick Rate" + default 1000 if !(M386 || M486 || M586 || M586TSC || M586MMX) + default 100 if (M386 || M486 || M586 || M586TSC || M586MMX) + help + Select the kernel clock tick rate in interrupts per second. + Slower processors should choose 100; everything else 1000. + config X86_GENERIC bool "Generic x86 support" help diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/arch/i386/kernel/Makefile linux-2.6.11/arch/i386/kernel/Makefile --- linux.vanilla-2.6.11/arch/i386/kernel/Makefile 2005-03-05 15:14:58.000000000 +0000 +++ linux-2.6.11/arch/i386/kernel/Makefile 2005-03-05 15:28:53.000000000 +0000 @@ -33,7 +33,7 @@ obj-$(CONFIG_EFI) += efi.o efi_stub.o obj-$(CONFIG_EARLY_PRINTK) += early_printk.o -EXTRA_AFLAGS := -traditional +EXTRA_AFLAGS := -traditional -m32 obj-$(CONFIG_SCx200) += scx200.o @@ -51,7 +51,7 @@ export CPPFLAGS_vsyscall.lds += -P -C -U$(ARCH) -vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1 +vsyscall-flags = -m32 -shared -s -Wl,-soname=linux-gate.so.1 SYSCFLAGS_vsyscall-sysenter.so = $(vsyscall-flags) SYSCFLAGS_vsyscall-int80.so = $(vsyscall-flags) @@ -66,6 +66,6 @@ $(obj)/built-in.o: $(obj)/vsyscall-syms.o $(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o -SYSCFLAGS_vsyscall-syms.o = -r +SYSCFLAGS_vsyscall-syms.o = -m32 -r $(obj)/vsyscall-syms.o: $(src)/vsyscall.lds $(obj)/vsyscall-sysenter.o FORCE $(call if_changed,syscall) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/arch/i386/Makefile linux-2.6.11/arch/i386/Makefile --- linux.vanilla-2.6.11/arch/i386/Makefile 2005-03-05 15:14:58.000000000 +0000 +++ linux-2.6.11/arch/i386/Makefile 2005-03-05 15:29:36.000000000 +0000 @@ -20,7 +20,7 @@ LDFLAGS_vmlinux := CHECKFLAGS += -D__i386__ -CFLAGS += -pipe -msoft-float +CFLAGS += -pipe -msoft-float -m32 # prevent gcc from keeping the stack 16 byte aligned CFLAGS += $(call cc-option,-mpreferred-stack-boundary=2) @@ -113,7 +113,7 @@ drivers-$(CONFIG_PM) += arch/i386/power/ CFLAGS += $(mflags-y) -AFLAGS += $(mflags-y) +AFLAGS += $(mflags-y) -m32 boot := arch/i386/boot diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/arch/ppc64/kernel/irq.c linux-2.6.11/arch/ppc64/kernel/irq.c --- linux.vanilla-2.6.11/arch/ppc64/kernel/irq.c 2005-03-05 15:16:59.000000000 +0000 +++ linux-2.6.11/arch/ppc64/kernel/irq.c 2005-03-05 15:30:01.000000000 +0000 @@ -215,7 +215,7 @@ spin_lock(&desc->lock); if (!noirqdebug) - note_interrupt(irq, desc, action_ret); + note_interrupt(irq, desc, action_ret, regs); if (likely(!(desc->status & IRQ_PENDING))) break; desc->status &= ~IRQ_PENDING; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/Documentation/kernel-parameters.txt linux-2.6.11/Documentation/kernel-parameters.txt --- linux.vanilla-2.6.11/Documentation/kernel-parameters.txt 2005-03-05 15:16:59.000000000 +0000 +++ linux-2.6.11/Documentation/kernel-parameters.txt 2005-03-05 16:07:51.000000000 +0000 @@ -587,6 +587,17 @@ ips= [HW,SCSI] Adaptec / IBM ServeRAID controller See header of drivers/scsi/ips.c. + irqfixup [HW] + When an interrupt is not handled search all handlers + for it. Intended to get systems with badly broken + firmware running. + + irqpoll [HW] + When an interrupt is not handled search all handlers + for it. Also check all handlers each timer + interrupt. Intended to get systems with badly broken + firmware running. + isapnp= [ISAPNP] Format: , , , diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/Documentation/sysctl/kernel.txt linux-2.6.11/Documentation/sysctl/kernel.txt --- linux.vanilla-2.6.11/Documentation/sysctl/kernel.txt 2005-03-05 15:14:55.000000000 +0000 +++ linux-2.6.11/Documentation/sysctl/kernel.txt 2005-03-05 15:30:46.000000000 +0000 @@ -49,6 +49,7 @@ - shmmax [ sysv ipc ] - shmmni - stop-a [ SPARC only ] +- suid_dumpable - sysrq ==> Documentation/sysrq.txt - tainted - threads-max @@ -300,6 +301,25 @@ ============================================================== +suid_dumpable: + +This value can be used to query and set the core dump mode for setuid +or otherwise protected/tainted binaries. The modes are + +0 - (default) - traditional behaviour. Any process which has changed + privilege levels or is execute only will not be dumped +1 - (debug) - all processes dump core when possible. The core dump is + owned by the current user and no security is applied. This is + intended for system debugging situations only. +2 - (suidsafe) - any binary which normally not be dumped is dumped + readable by root only. This allows the end user to remove + such a dump but not access it directly. For security reasons + core dumps in this mode will not overwrite one another or + other files. This mode is appropriate when adminstrators are + attempting to debug problems in a normal environment. + +============================================================== + tainted: Non-zero if the kernel has been tainted. Numeric values, which diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/Documentation/tty.txt linux-2.6.11/Documentation/tty.txt --- linux.vanilla-2.6.11/Documentation/tty.txt 2005-03-05 15:14:56.000000000 +0000 +++ linux-2.6.11/Documentation/tty.txt 2005-03-05 15:30:59.000000000 +0000 @@ -93,6 +93,11 @@ ldisc must be careful about setting order and to handle unexpected calls. Must not sleep. + The driver is forbidden from calling this directly + from the ->write call from the ldisc as the ldisc + is permitted to call the driver write method from + this function. In such a situation defer it. + Locking diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/cdrom/cdrom.c linux-2.6.11/drivers/cdrom/cdrom.c --- linux.vanilla-2.6.11/drivers/cdrom/cdrom.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/cdrom/cdrom.c 2005-03-05 15:31:30.000000000 +0000 @@ -1131,7 +1131,8 @@ This ensures that the drive gets unlocked after a mount fails. This is a goto to avoid bloating the driver with redundant code. */ clean_up_and_return: - cdinfo(CD_WARNING, "open failed.\n"); + /* Don't log this, its a perfectly normal user occurence */ + /* cdinfo(CD_WARNING, "open failed.\n"); */ if (CDROM_CAN(CDC_LOCK) && cdi->options & CDO_LOCK) { cdo->lock_door(cdi, 0); cdinfo(CD_OPEN, "door unlocked.\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/char/esp.c linux-2.6.11/drivers/char/esp.c --- linux.vanilla-2.6.11/drivers/char/esp.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/char/esp.c 2005-03-08 13:02:04.000000000 +0000 @@ -129,8 +129,6 @@ #undef SERIAL_DEBUG_OPEN #undef SERIAL_DEBUG_FLOW -#define _INLINE_ inline - #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) #define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ tty->name, (info->flags), serial_driver.refcount,info->count,tty->count,s) @@ -211,15 +209,14 @@ if (serial_paranoia_check(info, tty->name, "rs_stop")) return; - - save_flags(flags); cli(); + + spin_lock_irqsave(&info->lock, flags); if (info->IER & UART_IER_THRI) { info->IER &= ~UART_IER_THRI; serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); serial_out(info, UART_ESI_CMD2, info->IER); } - - restore_flags(flags); + spin_unlock_irqrestore(&info->lock, flags); } static void rs_start(struct tty_struct *tty) @@ -230,13 +227,13 @@ if (serial_paranoia_check(info, tty->name, "rs_start")) return; - save_flags(flags); cli(); + spin_lock_irqsave(&info->lock, flags); if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) { info->IER |= UART_IER_THRI; serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); serial_out(info, UART_ESI_CMD2, info->IER); } - restore_flags(flags); + spin_unlock_irqrestore(&info->lock, flags); } /* @@ -264,34 +261,41 @@ * This routine is used by the interrupt handler to schedule * processing in the software interrupt portion of the driver. */ -static _INLINE_ void rs_sched_event(struct esp_struct *info, +static inline void rs_sched_event(struct esp_struct *info, int event) { info->event |= 1 << event; schedule_work(&info->tqueue); } -static _INLINE_ struct esp_pio_buffer *get_pio_buffer(void) +static DEFINE_SPINLOCK(pio_lock); + +static inline struct esp_pio_buffer *get_pio_buffer(void) { struct esp_pio_buffer *buf; + unsigned long flags; + spin_lock_irqsave(&pio_lock, flags); if (free_pio_buf) { buf = free_pio_buf; free_pio_buf = buf->next; } else { buf = kmalloc(sizeof(struct esp_pio_buffer), GFP_ATOMIC); } - + spin_unlock_irqrestore(&pio_lock, flags); return buf; } -static _INLINE_ void release_pio_buffer(struct esp_pio_buffer *buf) +static inline void release_pio_buffer(struct esp_pio_buffer *buf) { + unsigned long flags; + spin_lock_irqsave(&pio_lock, flags); buf->next = free_pio_buf; free_pio_buf = buf; + spin_unlock_irqrestore(&pio_lock, flags); } -static _INLINE_ void receive_chars_pio(struct esp_struct *info, int num_bytes) +static inline void receive_chars_pio(struct esp_struct *info, int num_bytes) { struct tty_struct *tty = info->tty; int i; @@ -311,8 +315,6 @@ return; } - sti(); - status_mask = (info->read_status_mask >> 2) & 0x07; for (i = 0; i < num_bytes - 1; i += 2) { @@ -329,8 +331,6 @@ (serial_in(info, UART_ESI_RWS) >> 3) & status_mask; } - cli(); - /* make sure everything is still ok since interrupts were enabled */ tty = info->tty; @@ -371,7 +371,7 @@ release_pio_buffer(err_buf); } -static _INLINE_ void receive_chars_dma(struct esp_struct *info, int num_bytes) +static inline void receive_chars_dma(struct esp_struct *info, int num_bytes) { unsigned long flags; info->stat_flags &= ~ESP_STAT_RX_TIMEOUT; @@ -390,7 +390,7 @@ serial_out(info, UART_ESI_CMD1, ESI_START_DMA_RX); } -static _INLINE_ void receive_chars_dma_done(struct esp_struct *info, +static inline void receive_chars_dma_done(struct esp_struct *info, int status) { struct tty_struct *tty = info->tty; @@ -450,7 +450,9 @@ dma_bytes = 0; } -static _INLINE_ void transmit_chars_pio(struct esp_struct *info, +/* Caller must hold info->lock */ + +static inline void transmit_chars_pio(struct esp_struct *info, int space_avail) { int i; @@ -478,8 +480,6 @@ info->xmit_tail = (info->xmit_tail + space_avail) & (ESP_XMIT_SIZE - 1); - sti(); - for (i = 0; i < space_avail - 1; i += 2) { outw(*((unsigned short *)(pio_buf->data + i)), info->port + UART_ESI_TX); @@ -489,8 +489,6 @@ serial_out(info, UART_ESI_TX, pio_buf->data[space_avail - 1]); - cli(); - if (info->xmit_cnt) { serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL); @@ -520,7 +518,8 @@ release_pio_buffer(pio_buf); } -static _INLINE_ void transmit_chars_dma(struct esp_struct *info, int num_bytes) +/* Caller must hold info->lock */ +static inline void transmit_chars_dma(struct esp_struct *info, int num_bytes) { unsigned long flags; @@ -567,7 +566,7 @@ serial_out(info, UART_ESI_CMD1, ESI_START_DMA_TX); } -static _INLINE_ void transmit_chars_dma_done(struct esp_struct *info) +static inline void transmit_chars_dma_done(struct esp_struct *info) { int num_bytes; unsigned long flags; @@ -601,7 +600,7 @@ } } -static _INLINE_ void check_modem_status(struct esp_struct *info) +static inline void check_modem_status(struct esp_struct *info) { int status; @@ -654,10 +653,10 @@ err_status = 0; scratch = serial_in(info, UART_ESI_SID); - cli(); + spin_lock(&info->lock); if (!info->tty) { - sti(); + spin_unlock(&info->lock); return IRQ_NONE; } @@ -740,7 +739,7 @@ #ifdef SERIAL_DEBUG_INTR printk("end.\n"); #endif - sti(); + spin_unlock(&info->lock); return IRQ_HANDLED; } @@ -789,10 +788,12 @@ * figure out the appropriate timeout for an interrupt chain, routines * to initialize and startup a serial port, and routines to shutdown a * serial port. Useful stuff like that. + * + * Caller should hold lock * --------------------------------------------------------------- */ -static _INLINE_ void esp_basic_init(struct esp_struct * info) +static inline void esp_basic_init(struct esp_struct * info) { /* put ESPC in enhanced mode */ serial_out(info, UART_ESI_CMD1, ESI_SET_MODE); @@ -859,13 +860,13 @@ int retval=0; unsigned int num_chars; - save_flags(flags); cli(); + spin_lock_irqsave(&info->lock, flags); if (info->flags & ASYNC_INITIALIZED) goto out; if (!info->xmit_buf) { - info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_KERNEL); + info->xmit_buf = (unsigned char *)get_zeroed_page(GFP_ATOMIC); retval = -ENOMEM; if (!info->xmit_buf) goto out; @@ -900,6 +901,8 @@ if (info->stat_flags & ESP_STAT_NEVER_DMA) info->stat_flags |= ESP_STAT_USE_PIO; + + spin_unlock_irqrestore(&info->lock, flags); /* * Allocate the IRQ @@ -915,7 +918,7 @@ &info->tty->flags); retval = 0; } - goto out; + goto out_unlocked; } if (!(info->stat_flags & ESP_STAT_USE_PIO) && !dma_buffer) { @@ -935,6 +938,8 @@ } info->MCR = UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2; + + spin_lock_irqsave(&info->lock, flags); serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART); serial_out(info, UART_ESI_CMD2, UART_MCR); serial_out(info, UART_ESI_CMD2, info->MCR); @@ -951,6 +956,7 @@ if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + spin_unlock_irqrestore(&info->lock, flags); /* * Set up the tty->alt_speed kludge @@ -970,10 +976,12 @@ * set the speed of the serial port */ change_speed(info); - info->flags |= ASYNC_INITIALIZED; - retval = 0; -out: restore_flags(flags); + return 0; + +out: + spin_unlock_irqrestore(&info->lock, flags); +out_unlocked: return retval; } @@ -993,8 +1001,7 @@ info->irq); #endif - save_flags(flags); cli(); /* Disable interrupts */ - + spin_lock_irqsave(&info->lock, flags); /* * clear delta_msr_wait queue to avoid mem leaks: we may free the irq * here so the queue might never be waken up @@ -1003,7 +1010,7 @@ wake_up_interruptible(&info->break_wait); /* stop a DMA transfer on the port being closed */ - + /* DMA lock is higher priority always */ if (info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) { f=claim_dma_lock(); disable_dma(dma); @@ -1058,7 +1065,7 @@ set_bit(TTY_IO_ERROR, &info->tty->flags); info->flags &= ~ASYNC_INITIALIZED; - restore_flags(flags); + spin_unlock_irqrestore(&info->lock, flags); } /* @@ -1172,7 +1179,7 @@ if (I_IXOFF(info->tty)) flow1 |= 0x81; - save_flags(flags); cli(); + spin_lock_irqsave(&info->lock, flags); /* set baud */ serial_out(info, UART_ESI_CMD1, ESI_SET_BAUD); serial_out(info, UART_ESI_CMD2, quot >> 8); @@ -1218,8 +1225,8 @@ serial_out(info, UART_ESI_CMD2, info->config.flow_off); serial_out(info, UART_ESI_CMD2, info->config.flow_on >> 8); serial_out(info, UART_ESI_CMD2, info->config.flow_on); - - restore_flags(flags); + + spin_unlock_irqrestore(&info->lock, flags); } static void rs_put_char(struct tty_struct *tty, unsigned char ch) @@ -1233,16 +1240,13 @@ if (!tty || !info->xmit_buf) return; - save_flags(flags); cli(); - if (info->xmit_cnt >= ESP_XMIT_SIZE - 1) { - restore_flags(flags); - return; + spin_lock_irqsave(&info->lock, flags); + if (info->xmit_cnt < ESP_XMIT_SIZE - 1) { + info->xmit_buf[info->xmit_head++] = ch; + info->xmit_head &= ESP_XMIT_SIZE-1; + info->xmit_cnt++; } - - info->xmit_buf[info->xmit_head++] = ch; - info->xmit_head &= ESP_XMIT_SIZE-1; - info->xmit_cnt++; - restore_flags(flags); + spin_unlock_irqrestore(&info->lock, flags); } static void rs_flush_chars(struct tty_struct *tty) @@ -1253,16 +1257,18 @@ if (serial_paranoia_check(info, tty->name, "rs_flush_chars")) return; + spin_lock_irqsave(&info->lock, flags); + if (info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf) - return; + goto out; - save_flags(flags); cli(); if (!(info->IER & UART_IER_THRI)) { info->IER |= UART_IER_THRI; serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); serial_out(info, UART_ESI_CMD2, info->IER); } - restore_flags(flags); +out: + spin_unlock_irqrestore(&info->lock, flags); } static int rs_write(struct tty_struct * tty, @@ -1305,7 +1311,7 @@ ret += c; } - save_flags(flags); cli(); + spin_lock_irqsave(&info->lock, flags); if (info->xmit_cnt && !tty->stopped && !(info->IER & UART_IER_THRI)) { info->IER |= UART_IER_THRI; @@ -1313,7 +1319,7 @@ serial_out(info, UART_ESI_CMD2, info->IER); } - restore_flags(flags); + spin_unlock_irqrestore(&info->lock, flags); return ret; } @@ -1321,12 +1327,17 @@ { struct esp_struct *info = (struct esp_struct *)tty->driver_data; int ret; + unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_write_room")) return 0; + + spin_lock_irqsave(&info->lock, flags); + ret = ESP_XMIT_SIZE - info->xmit_cnt - 1; if (ret < 0) ret = 0; + spin_unlock_irqrestore(&info->lock, flags); return ret; } @@ -1342,12 +1353,13 @@ static void rs_flush_buffer(struct tty_struct *tty) { struct esp_struct *info = (struct esp_struct *)tty->driver_data; + unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_flush_buffer")) return; - cli(); + spin_lock_irqsave(&info->lock, flags); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; - sti(); + spin_unlock_irqrestore(&info->lock, flags); tty_wakeup(tty); } @@ -1362,6 +1374,7 @@ static void rs_throttle(struct tty_struct * tty) { struct esp_struct *info = (struct esp_struct *)tty->driver_data; + unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; @@ -1371,19 +1384,20 @@ if (serial_paranoia_check(info, tty->name, "rs_throttle")) return; - - cli(); + + spin_lock_irqsave(&info->lock, flags); info->IER &= ~UART_IER_RDI; serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); serial_out(info, UART_ESI_CMD2, info->IER); serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT); serial_out(info, UART_ESI_CMD2, 0x00); - sti(); + spin_unlock_irqrestore(&info->lock, flags); } static void rs_unthrottle(struct tty_struct * tty) { struct esp_struct *info = (struct esp_struct *)tty->driver_data; + unsigned long flags; #ifdef SERIAL_DEBUG_THROTTLE char buf[64]; @@ -1394,13 +1408,13 @@ if (serial_paranoia_check(info, tty->name, "rs_unthrottle")) return; - cli(); + spin_lock_irqsave(&info->lock, flags); info->IER |= UART_IER_RDI; serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); serial_out(info, UART_ESI_CMD2, info->IER); serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT); serial_out(info, UART_ESI_CMD2, info->config.rx_timeout); - sti(); + spin_unlock_irqrestore(&info->lock, flags); } /* @@ -1573,6 +1587,7 @@ unsigned int change_dma; int retval = 0; struct esp_struct *current_async; + unsigned long flags; /* Perhaps a non-sysadmin user should be able to do some of these */ /* operations. I haven't decided yet. */ @@ -1628,12 +1643,14 @@ /* all ports must use the same DMA channel */ + spin_lock_irqsave(&info->lock, flags); current_async = ports; while (current_async) { esp_basic_init(current_async); current_async = current_async->next_port; } + spin_unlock_irqrestore(&info->lock, flags); } else { /* DMA mode to PIO mode only */ @@ -1641,8 +1658,10 @@ return -EBUSY; shutdown(info); + spin_lock_irqsave(&info->lock, flags); info->stat_flags |= ESP_STAT_NEVER_DMA; esp_basic_init(info); + spin_unlock_irqrestore(&info->lock, flags); } } @@ -1654,13 +1673,14 @@ info->config.flow_off = new_config.flow_off; info->config.flow_on = new_config.flow_on; - save_flags(flags); cli(); + + spin_lock_irqsave(&info->lock, flags); serial_out(info, UART_ESI_CMD1, ESI_SET_FLOW_LVL); serial_out(info, UART_ESI_CMD2, new_config.flow_off >> 8); serial_out(info, UART_ESI_CMD2, new_config.flow_off); serial_out(info, UART_ESI_CMD2, new_config.flow_on >> 8); serial_out(info, UART_ESI_CMD2, new_config.flow_on); - restore_flags(flags); + spin_unlock_irqrestore(&info->lock, flags); } if ((new_config.rx_trigger != info->config.rx_trigger) || @@ -1669,7 +1689,7 @@ info->config.rx_trigger = new_config.rx_trigger; info->config.tx_trigger = new_config.tx_trigger; - save_flags(flags); cli(); + spin_lock_irqsave(&info->lock, flags); serial_out(info, UART_ESI_CMD1, ESI_SET_TRIGGER); serial_out(info, UART_ESI_CMD2, new_config.rx_trigger >> 8); @@ -1677,14 +1697,14 @@ serial_out(info, UART_ESI_CMD2, new_config.tx_trigger >> 8); serial_out(info, UART_ESI_CMD2, new_config.tx_trigger); - restore_flags(flags); + spin_unlock_irqrestore(&info->lock, flags); } if (new_config.rx_timeout != info->config.rx_timeout) { unsigned long flags; info->config.rx_timeout = new_config.rx_timeout; - save_flags(flags); cli(); + spin_lock_irqsave(&info->lock, flags); if (info->IER & UART_IER_RDI) { serial_out(info, UART_ESI_CMD1, @@ -1693,7 +1713,7 @@ new_config.rx_timeout); } - restore_flags(flags); + spin_unlock_irqrestore(&info->lock, flags); } if (!(info->flags & ASYNC_INITIALIZED)) @@ -1716,11 +1736,12 @@ { unsigned char status; unsigned int result; + unsigned long flags; - cli(); + spin_lock_irqsave(&info->lock, flags); serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT); status = serial_in(info, UART_ESI_STAT1); - sti(); + spin_unlock_irqrestore(&info->lock, flags); result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0); return put_user(result,value); } @@ -1730,6 +1751,7 @@ { struct esp_struct * info = (struct esp_struct *)tty->driver_data; unsigned char control, status; + unsigned long flags; if (serial_paranoia_check(info, tty->name, __FUNCTION__)) return -ENODEV; @@ -1737,10 +1759,12 @@ return -EIO; control = info->MCR; - cli(); + + spin_lock_irqsave(&info->lock, flags); serial_out(info, UART_ESI_CMD1, ESI_GET_UART_STAT); status = serial_in(info, UART_ESI_STAT2); - sti(); + spin_unlock_irqrestore(&info->lock, flags); + return ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) @@ -1753,13 +1777,14 @@ unsigned int set, unsigned int clear) { struct esp_struct * info = (struct esp_struct *)tty->driver_data; + unsigned long flags; if (serial_paranoia_check(info, tty->name, __FUNCTION__)) return -ENODEV; if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; - cli(); + spin_lock_irqsave(&info->lock, flags); if (set & TIOCM_RTS) info->MCR |= UART_MCR_RTS; @@ -1774,7 +1799,8 @@ serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART); serial_out(info, UART_ESI_CMD2, UART_MCR); serial_out(info, UART_ESI_CMD2, info->MCR); - sti(); + + spin_unlock_irqrestore(&info->lock, flags); return 0; } @@ -1789,17 +1815,20 @@ if (serial_paranoia_check(info, tty->name, "esp_break")) return; - save_flags(flags); cli(); if (break_state == -1) { + spin_lock_irqsave(&info->lock, flags); serial_out(info, UART_ESI_CMD1, ESI_ISSUE_BREAK); serial_out(info, UART_ESI_CMD2, 0x01); + spin_unlock_irqrestore(&info->lock, flags); + /* FIXME - new style wait needed here */ interruptible_sleep_on(&info->break_wait); } else { + spin_lock_irqsave(&info->lock, flags); serial_out(info, UART_ESI_CMD1, ESI_ISSUE_BREAK); serial_out(info, UART_ESI_CMD2, 0x00); + spin_unlock_irqrestore(&info->lock, flags); } - restore_flags(flags); } static int rs_ioctl(struct tty_struct *tty, struct file * file, @@ -1809,6 +1838,7 @@ struct async_icount cprev, cnow; /* kernel counter temps */ struct serial_icounter_struct __user *p_cuser; /* user space */ void __user *argp = (void __user *)arg; + unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_ioctl")) return -ENODEV; @@ -1849,17 +1879,18 @@ * Caller should use TIOCGICOUNT to see which one it was */ case TIOCMIWAIT: - cli(); + spin_lock_irqsave(&info->lock, flags); cprev = info->icount; /* note the counters on entry */ - sti(); + spin_unlock_irqrestore(&info->lock, flags); while (1) { + /* FIXME: convert to new style wakeup */ interruptible_sleep_on(&info->delta_msr_wait); /* see if a signal did it */ if (signal_pending(current)) return -ERESTARTSYS; - cli(); + spin_lock_irqsave(&info->lock, flags); cnow = info->icount; /* atomic copy */ - sti(); + spin_unlock_irqrestore(&info->lock, flags); if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && cnow.dcd == cprev.dcd && @@ -1886,9 +1917,9 @@ * RI where only 0->1 is counted. */ case TIOCGICOUNT: - cli(); + spin_lock_irqsave(&info->lock, flags); cnow = info->icount; - sti(); + spin_unlock_irqrestore(&info->lock, flags); p_cuser = argp; if (put_user(cnow.cts, &p_cuser->cts) || put_user(cnow.dsr, &p_cuser->dsr) || @@ -1911,53 +1942,42 @@ static void rs_set_termios(struct tty_struct *tty, struct termios *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; + return; change_speed(info); + spin_lock_irqsave(&info->lock, flags); + /* Handle transition to B0 status */ if ((old_termios->c_cflag & CBAUD) && !(tty->termios->c_cflag & CBAUD)) { info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS); - cli(); serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART); serial_out(info, UART_ESI_CMD2, UART_MCR); serial_out(info, UART_ESI_CMD2, info->MCR); - sti(); } /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && (tty->termios->c_cflag & CBAUD)) { info->MCR |= (UART_MCR_DTR | UART_MCR_RTS); - cli(); serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART); serial_out(info, UART_ESI_CMD2, UART_MCR); serial_out(info, UART_ESI_CMD2, info->MCR); - sti(); } + spin_unlock_irqrestore(&info->lock, flags); + /* Handle turning of CRTSCTS */ if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { rs_start(tty); } - -#if 0 - /* - * No need to wake up processes in open wait, since they - * sample the CLOCAL flag once, and don't recheck it. - * XXX It's not clear whether the current behavior is correct - * or not. Hence, this may change..... - */ - if (!(old_termios->c_cflag & CLOCAL) && - (tty->termios->c_cflag & CLOCAL)) - wake_up_interruptible(&info->open_wait); -#endif } /* @@ -1978,7 +1998,7 @@ if (!info || serial_paranoia_check(info, tty->name, "rs_close")) return; - save_flags(flags); cli(); + spin_lock_irqsave(&info->lock, flags); if (tty_hung_up_p(filp)) { DBG_CNT("before DEC-hung"); @@ -2010,6 +2030,8 @@ goto out; } info->flags |= ASYNC_CLOSING; + + spin_unlock_irqrestore(&info->lock, flags); /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. @@ -2027,12 +2049,16 @@ info->IER &= ~UART_IER_RDI; info->read_status_mask &= ~UART_LSR_DR; if (info->flags & ASYNC_INITIALIZED) { + + spin_lock_irqsave(&info->lock, flags); serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK); serial_out(info, UART_ESI_CMD2, info->IER); /* disable receive timeout */ serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT); serial_out(info, UART_ESI_CMD2, 0x00); + + spin_unlock_irqrestore(&info->lock, flags); /* * Before we drop DTR, make sure the UART transmitter @@ -2057,8 +2083,10 @@ } info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); + return; + out: - restore_flags(flags); + spin_unlock_irqrestore(&info->lock, flags); } static void rs_wait_until_sent(struct tty_struct *tty, int timeout) @@ -2076,12 +2104,14 @@ if (!char_time) char_time = 1; - save_flags(flags); cli(); + spin_lock_irqsave(&info->lock, flags); serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL); while ((serial_in(info, UART_ESI_STAT1) != 0x03) || (serial_in(info, UART_ESI_STAT2) != 0xff)) { + + spin_unlock_irqrestore(&info->lock, flags); msleep_interruptible(jiffies_to_msecs(char_time)); if (signal_pending(current)) @@ -2090,11 +2120,11 @@ if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; + spin_lock_irqsave(&info->lock, flags); serial_out(info, UART_ESI_CMD1, ESI_NO_COMMAND); serial_out(info, UART_ESI_CMD1, ESI_GET_TX_AVAIL); } - - restore_flags(flags); + spin_unlock_irqrestore(&info->lock, flags); set_current_state(TASK_RUNNING); } @@ -2174,15 +2204,11 @@ printk("block_til_ready before block: ttys%d, count = %d\n", info->line, info->count); #endif - save_flags(flags); - cli(); + spin_lock_irqsave(&info->lock, flags); if (!tty_hung_up_p(filp)) info->count--; - restore_flags(flags); info->blocked_open++; while (1) { - save_flags(flags); - cli(); if ((tty->termios->c_cflag & CBAUD)) { unsigned int scratch; @@ -2194,7 +2220,6 @@ serial_out(info, UART_ESI_CMD2, scratch | UART_MCR_DTR | UART_MCR_RTS); } - restore_flags(flags); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) { @@ -2224,13 +2249,16 @@ printk("block_til_ready blocking: ttys%d, count = %d\n", info->line, info->count); #endif + spin_unlock_irqrestore(&info->lock, flags); schedule(); + spin_lock_irqsave(&info->lock, flags); } set_current_state(TASK_RUNNING); remove_wait_queue(&info->open_wait, &wait); if (!tty_hung_up_p(filp)) info->count++; info->blocked_open--; + spin_unlock_irqrestore(&info->lock, flags); #ifdef SERIAL_DEBUG_OPEN printk("block_til_ready after blocking: ttys%d, count = %d\n", info->line, info->count); @@ -2251,6 +2279,7 @@ { struct esp_struct *info; int retval, line; + unsigned long flags; line = tty->index; if ((line < 0) || (line >= NR_PORTS)) @@ -2262,7 +2291,7 @@ while (info && (info->line != line)) info = info->next_port; - + if (!info) { serial_paranoia_check(info, tty->name, "esp_open"); return -ENODEV; @@ -2271,6 +2300,7 @@ #ifdef SERIAL_DEBUG_OPEN printk("esp_open %s, count = %d\n", tty->name, info->count); #endif + spin_lock_irqsave(&info->lock, flags); info->count++; tty->driver_data = info; info->tty = tty; @@ -2317,7 +2347,7 @@ * driver. */ -static _INLINE_ void show_serial_version(void) +static inline void show_serial_version(void) { printk(KERN_INFO "%s version %s (DMA %u)\n", serial_name, serial_version, dma); @@ -2327,7 +2357,7 @@ * This routine is called by espserial_init() to initialize a specific serial * port. */ -static _INLINE_ int autoconfig(struct esp_struct * info) +static inline int autoconfig(struct esp_struct * info) { int port_detected = 0; unsigned long flags; @@ -2335,8 +2365,7 @@ if (!request_region(info->port, REGION_SIZE, "esp serial")) return -EIO; - save_flags(flags); cli(); - + spin_lock_irqsave(&info->lock, flags); /* * Check for ESP card */ @@ -2372,7 +2401,7 @@ if (!port_detected) release_region(info->port, REGION_SIZE); - restore_flags(flags); + spin_unlock_irqrestore(&info->lock, flags); return (port_detected); } @@ -2513,6 +2542,7 @@ init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->delta_msr_wait); init_waitqueue_head(&info->break_wait); + spin_lock_init(&info->lock); ports = info; printk(KERN_INFO "ttyP%d at 0x%04x (irq = %d) is an ESP ", info->line, info->port, info->irq); @@ -2563,18 +2593,14 @@ static void __exit espserial_exit(void) { - unsigned long flags; int e1; struct esp_struct *temp_async; struct esp_pio_buffer *pio_buf; /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ - save_flags(flags); - cli(); if ((e1 = tty_unregister_driver(esp_driver))) printk("SERIAL: failed to unregister serial driver (%d)\n", e1); - restore_flags(flags); put_tty_driver(esp_driver); while (ports) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/char/Kconfig linux-2.6.11/drivers/char/Kconfig --- linux.vanilla-2.6.11/drivers/char/Kconfig 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/char/Kconfig 2005-03-08 12:55:52.000000000 +0000 @@ -170,7 +170,7 @@ config ESPSERIAL tristate "Hayes ESP serial port support" - depends on SERIAL_NONSTANDARD && ISA && BROKEN_ON_SMP + depends on SERIAL_NONSTANDARD help This is a driver which supports Hayes ESP serial ports. Both single port cards and multiport cards are supported. Make sure to read diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/char/stallion.c linux-2.6.11/drivers/char/stallion.c --- linux.vanilla-2.6.11/drivers/char/stallion.c 2005-03-05 15:15:06.000000000 +0000 +++ linux-2.6.11/drivers/char/stallion.c 2005-03-05 15:32:33.000000000 +0000 @@ -174,14 +174,6 @@ */ static char stl_unwanted[SC26198_RXFIFOSIZE]; -/* - * Keep track of what interrupts we have requested for us. - * We don't need to request an interrupt twice if it is being - * shared with another Stallion board. - */ -static int stl_gotintrs[STL_MAXBRDS]; -static int stl_numintrs; - /*****************************************************************************/ static stlbrd_t *stl_brds[STL_MAXBRDS]; @@ -504,7 +496,6 @@ static int stl_brdinit(stlbrd_t *brdp); static int stl_initports(stlbrd_t *brdp, stlpanel_t *panelp); -static int stl_mapirq(int irq, char *name); static int stl_getserial(stlport_t *portp, struct serial_struct __user *sp); static int stl_setserial(stlport_t *portp, struct serial_struct __user *sp); static int stl_getbrdstats(combrd_t __user *bp); @@ -513,11 +504,11 @@ static int stl_getportstruct(stlport_t __user *arg); static int stl_getbrdstruct(stlbrd_t __user *arg); static int stl_waitcarrier(stlport_t *portp, struct file *filp); -static void stl_eiointr(stlbrd_t *brdp); -static void stl_echatintr(stlbrd_t *brdp); -static void stl_echmcaintr(stlbrd_t *brdp); -static void stl_echpciintr(stlbrd_t *brdp); -static void stl_echpci64intr(stlbrd_t *brdp); +static int stl_eiointr(stlbrd_t *brdp); +static int stl_echatintr(stlbrd_t *brdp); +static int stl_echmcaintr(stlbrd_t *brdp); +static int stl_echpciintr(stlbrd_t *brdp); +static int stl_echpci64intr(stlbrd_t *brdp); static void stl_offintr(void *private); static void *stl_memalloc(int len); static stlbrd_t *stl_allocbrd(void); @@ -807,6 +798,9 @@ for (i = 0; (i < stl_nrbrds); i++) { if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL) continue; + + free_irq(brdp->irq, brdp); + for (j = 0; (j < STL_MAXPANELS); j++) { panelp = brdp->panels[j]; if (panelp == (stlpanel_t *) NULL) @@ -832,9 +826,6 @@ stl_brds[i] = (stlbrd_t *) NULL; } - for (i = 0; (i < stl_numintrs); i++) - free_irq(stl_gotintrs[i], NULL); - restore_flags(flags); } @@ -1992,23 +1983,14 @@ static irqreturn_t stl_intr(int irq, void *dev_id, struct pt_regs *regs) { - stlbrd_t *brdp; - int i; - int handled = 0; + stlbrd_t *brdp = (stlbrd_t *) dev_id; #ifdef DEBUG - printk("stl_intr(irq=%d,regs=%x)\n", irq, (int) regs); + printk("stl_intr(brdp=%x,irq=%d,regs=%x)\n", (int) brdp, irq, + (int) regs); #endif - for (i = 0; (i < stl_nrbrds); i++) { - if ((brdp = stl_brds[i]) == (stlbrd_t *) NULL) - continue; - if (brdp->state == 0) - continue; - handled = 1; - (* brdp->isr)(brdp); - } - return IRQ_RETVAL(handled); + return IRQ_RETVAL((* brdp->isr)(brdp)); } /*****************************************************************************/ @@ -2017,15 +1999,19 @@ * Interrupt service routine for EasyIO board types. */ -static void stl_eiointr(stlbrd_t *brdp) +static int stl_eiointr(stlbrd_t *brdp) { stlpanel_t *panelp; unsigned int iobase; + int handled = 0; panelp = brdp->panels[0]; iobase = panelp->iobase; - while (inb(brdp->iostatus) & EIO_INTRPEND) + while (inb(brdp->iostatus) & EIO_INTRPEND) { + handled = 1; (* panelp->isr)(panelp, iobase); + } + return handled; } /*****************************************************************************/ @@ -2034,15 +2020,17 @@ * Interrupt service routine for ECH-AT board types. */ -static void stl_echatintr(stlbrd_t *brdp) +static int stl_echatintr(stlbrd_t *brdp) { stlpanel_t *panelp; unsigned int ioaddr; int bnknr; + int handled = 0; outb((brdp->ioctrlval | ECH_BRDENABLE), brdp->ioctrl); while (inb(brdp->iostatus) & ECH_INTRPEND) { + handled = 1; for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { ioaddr = brdp->bnkstataddr[bnknr]; if (inb(ioaddr) & ECH_PNLINTRPEND) { @@ -2053,6 +2041,8 @@ } outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl); + + return handled; } /*****************************************************************************/ @@ -2061,13 +2051,15 @@ * Interrupt service routine for ECH-MCA board types. */ -static void stl_echmcaintr(stlbrd_t *brdp) +static int stl_echmcaintr(stlbrd_t *brdp) { stlpanel_t *panelp; unsigned int ioaddr; int bnknr; + int handled = 0; while (inb(brdp->iostatus) & ECH_INTRPEND) { + handled = 1; for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { ioaddr = brdp->bnkstataddr[bnknr]; if (inb(ioaddr) & ECH_PNLINTRPEND) { @@ -2076,6 +2068,7 @@ } } } + return handled; } /*****************************************************************************/ @@ -2084,11 +2077,12 @@ * Interrupt service routine for ECH-PCI board types. */ -static void stl_echpciintr(stlbrd_t *brdp) +static int stl_echpciintr(stlbrd_t *brdp) { stlpanel_t *panelp; unsigned int ioaddr; int bnknr, recheck; + int handled = 0; while (1) { recheck = 0; @@ -2099,11 +2093,13 @@ panelp = brdp->bnk2panel[bnknr]; (* panelp->isr)(panelp, (ioaddr & 0xfffc)); recheck++; + handled = 1; } } if (! recheck) break; } + return handled; } /*****************************************************************************/ @@ -2112,13 +2108,15 @@ * Interrupt service routine for ECH-8/64-PCI board types. */ -static void stl_echpci64intr(stlbrd_t *brdp) +static int stl_echpci64intr(stlbrd_t *brdp) { stlpanel_t *panelp; unsigned int ioaddr; int bnknr; + int handled = 0; while (inb(brdp->ioctrl) & 0x1) { + handled = 1; for (bnknr = 0; (bnknr < brdp->nrbnks); bnknr++) { ioaddr = brdp->bnkstataddr[bnknr]; if (inb(ioaddr) & ECH_PNLINTRPEND) { @@ -2127,6 +2125,8 @@ } } } + + return handled; } /*****************************************************************************/ @@ -2174,39 +2174,6 @@ /*****************************************************************************/ /* - * Map in interrupt vector to this driver. Check that we don't - * already have this vector mapped, we might be sharing this - * interrupt across multiple boards. - */ - -static int __init stl_mapirq(int irq, char *name) -{ - int rc, i; - -#ifdef DEBUG - printk("stl_mapirq(irq=%d,name=%s)\n", irq, name); -#endif - - rc = 0; - for (i = 0; (i < stl_numintrs); i++) { - if (stl_gotintrs[i] == irq) - break; - } - if (i >= stl_numintrs) { - if (request_irq(irq, stl_intr, SA_SHIRQ, name, NULL) != 0) { - printk("STALLION: failed to register interrupt " - "routine for %s irq=%d\n", name, irq); - rc = -ENODEV; - } else { - stl_gotintrs[stl_numintrs++] = irq; - } - } - return(rc); -} - -/*****************************************************************************/ - -/* * Initialize all the ports on a panel. */ @@ -2389,7 +2356,13 @@ brdp->nrpanels = 1; brdp->state |= BRD_FOUND; brdp->hwid = status; - rc = stl_mapirq(brdp->irq, name); + if (request_irq(brdp->irq, stl_intr, SA_SHIRQ, name, brdp) != 0) { + printk("STALLION: failed to register interrupt " + "routine for %s irq=%d\n", name, brdp->irq); + rc = -ENODEV; + } else { + rc = 0; + } return(rc); } @@ -2594,7 +2567,14 @@ outb((brdp->ioctrlval | ECH_BRDDISABLE), brdp->ioctrl); brdp->state |= BRD_FOUND; - i = stl_mapirq(brdp->irq, name); + if (request_irq(brdp->irq, stl_intr, SA_SHIRQ, name, brdp) != 0) { + printk("STALLION: failed to register interrupt " + "routine for %s irq=%d\n", name, brdp->irq); + i = -ENODEV; + } else { + i = 0; + } + return(i); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/arm/icside.c linux-2.6.11/drivers/ide/arm/icside.c --- linux.vanilla-2.6.11/drivers/ide/arm/icside.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/arm/icside.c 2005-03-06 14:46:16.000000000 +0000 @@ -502,9 +502,9 @@ hwif->ide_dma_off_quietly = icside_dma_off_quietly; hwif->ide_dma_host_on = icside_dma_host_on; hwif->ide_dma_on = icside_dma_on; - hwif->dma_setup = icside_dma_setup; - hwif->dma_exec_cmd = icside_dma_exec_cmd; - hwif->dma_start = icside_dma_start; + hwif->ide_dma_setup = icside_dma_setup; + hwif->ide_dma_exec_cmd = icside_dma_exec_cmd; + hwif->ide_dma_start = icside_dma_start; hwif->ide_dma_end = icside_dma_end; hwif->ide_dma_test_irq = icside_dma_test_irq; hwif->ide_dma_timeout = icside_dma_timeout; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/cris/ide-v10.c linux-2.6.11/drivers/ide/cris/ide-v10.c --- linux.vanilla-2.6.11/drivers/ide/cris/ide-v10.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/cris/ide-v10.c 2005-03-06 14:46:16.000000000 +0000 @@ -332,9 +332,9 @@ hwif->atapi_output_bytes = &e100_atapi_output_bytes; hwif->ide_dma_check = &e100_dma_check; hwif->ide_dma_end = &e100_dma_end; - hwif->dma_setup = &e100_dma_setup; - hwif->dma_exec_cmd = &e100_dma_exec_cmd; - hwif->dma_start = &e100_dma_start; + hwif->ide_dma_setup = &e100_dma_setup; + hwif->ide_dma_exec_cmd = &e100_dma_exec_cmd; + hwif->ide_dma_start = &e100_dma_start; hwif->OUTB = &etrax100_ide_outb; hwif->OUTW = &etrax100_ide_outw; hwif->OUTBSYNC = &etrax100_ide_outbsync; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/ide.c linux-2.6.11/drivers/ide/ide.c --- linux.vanilla-2.6.11/drivers/ide/ide.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/ide.c 2005-03-06 15:00:57.000000000 +0000 @@ -175,7 +175,8 @@ static int initializing; /* set while initializing built-in drivers */ DECLARE_MUTEX(ide_cfg_sem); - __cacheline_aligned_in_smp DEFINE_SPINLOCK(ide_lock); +EXPORT_SYMBOL_GPL(ide_cfg_sem); +__cacheline_aligned_in_smp DEFINE_SPINLOCK(ide_lock); #ifdef CONFIG_BLK_DEV_IDEPCI static int ide_scan_direction; /* THIS was formerly 2.2.x pci=reverse */ @@ -205,11 +206,13 @@ static void init_hwif_data(ide_hwif_t *hwif, unsigned int index) { unsigned int unit; + unsigned int key = hwif->key; /* bulk initialize hwif & drive info with zeros */ memset(hwif, 0, sizeof(ide_hwif_t)); /* fill in any non-zero initial values */ + hwif->key = key + 1; /* Protected by ide_cfg_sem */ hwif->index = index; hwif->major = ide_hwif_to_major[index]; @@ -320,6 +323,92 @@ #endif } +/* + * ide_drive_from_key - turn key into drive + * @kval: persistent key + * + * Convert a key into a drive. Currently the key is packed as + * [keyval] << 16 | hwif << 8 | drive_num. Caller must hold + * ide_settings_sem for the duration of the returned reference + */ + +ide_drive_t *ide_drive_from_key(void *kval) +{ + unsigned long key = (unsigned long) kval; + int idx = (key >> 8) & 0xFF; + int drive = key & 3; + ide_hwif_t *hwif = &ide_hwifs[idx]; + ide_drive_t *ret; + + key >>= 16; + + if(hwif->configured == 0 || hwif->present == 0 || hwif->drives[drive].dead || hwif->key != key) + ret = NULL; + else + ret = &ide_hwifs[idx].drives[drive]; + + return ret; +} + +EXPORT_SYMBOL_GPL(ide_drive_from_key); + +/* + * ide_drive_to_key - turn drive to persistent key + * @drive: drive to use + * + * Convert drive into a key. Currently the key is packed as + * [keyval] << 16 | hwif << 8 | drive_num. Caller must hold + * ide_settings_sem for the duration of the returned reference + */ + +void *ide_drive_to_key(ide_drive_t *drive) +{ + ide_hwif_t *hwif = HWIF(drive); + unsigned long val; + + val = (hwif->index << 8) | (hwif->key << 16) | drive->select.b.unit; + return (void *)val; +} + +/* + * ide_hwif_from_key - turn key into hwif + * @kval: persistent key + * + * Convert a key into a drive. Currently the key is packed as + * [keyval] << 16 | hwif << 8 | drive_num. Caller must hold + * ide_settings_sem for the duration of the returned reference + */ + +ide_hwif_t *ide_hwif_from_key(void *kval) +{ + unsigned long key = (unsigned long) kval; + int idx = (key >> 8) & 0xFF; + ide_hwif_t *hwif = &ide_hwifs[idx]; + + key >>= 16; + + if(hwif->configured == 0 || hwif->present == 0 || hwif->key != key) + return NULL; + return hwif; +} + +/* + * ide_hwif_to_key - turn drive to persistent key + * @hwif: hwif to use + * + * Convert drive into a key. Currently the key is packed as + * [keyval] << 16 | hwif << 8 | drive_num. Caller must hold + * ide_settings_sem for the duration of the returned reference + */ + +void *ide_hwif_to_key(ide_hwif_t *hwif) +{ + unsigned long val; + + val = (hwif->index << 8) | (hwif->key << 16); + return (void *)val; +} + /** * ide_system_bus_speed - guess bus speed * @@ -368,11 +457,16 @@ } /* - * drives_lock protects the list of drives, drivers_lock the - * list of drivers. Currently nobody takes both at once. + * drives_lock protects the list of drives, drivers lock the + * list of drivers. Currently nobody takes both at once. + * drivers_sem guards the drivers_list for readers that may + * sleep. It must be taken before drivers_lock. Take drivers_sem + * before ide_setting_sem and idecfg_sem before either of the + * others. */ static DEFINE_SPINLOCK(drives_lock); +static DECLARE_MUTEX(drivers_sem); static DEFINE_SPINLOCK(drivers_lock); static LIST_HEAD(drivers); @@ -382,7 +476,7 @@ { struct list_head *p; loff_t l = *pos; - spin_lock(&drivers_lock); + down(&drivers_sem); list_for_each(p, &drivers) if (!l--) return list_entry(p, ide_driver_t, drivers); @@ -398,7 +492,7 @@ static void m_stop(struct seq_file *m, void *v) { - spin_unlock(&drivers_lock); + up(&drivers_sem); } static int show_driver(struct seq_file *m, void *v) @@ -562,9 +656,9 @@ hwif->atapi_input_bytes = tmp_hwif->atapi_input_bytes; hwif->atapi_output_bytes = tmp_hwif->atapi_output_bytes; - hwif->dma_setup = tmp_hwif->dma_setup; - hwif->dma_exec_cmd = tmp_hwif->dma_exec_cmd; - hwif->dma_start = tmp_hwif->dma_start; + hwif->ide_dma_setup = tmp_hwif->ide_dma_setup; + hwif->ide_dma_exec_cmd = tmp_hwif->ide_dma_exec_cmd; + hwif->ide_dma_start = tmp_hwif->ide_dma_start; hwif->ide_dma_end = tmp_hwif->ide_dma_end; hwif->ide_dma_check = tmp_hwif->ide_dma_check; hwif->ide_dma_on = tmp_hwif->ide_dma_on; @@ -617,14 +711,16 @@ } /** - * ide_unregister - free an ide interface - * @index: index of interface (will change soon to a pointer) + * __ide_unregister_hwif - free an ide interface + * @hwif: interface to unregister * * Perform the final unregister of an IDE interface. At the moment * we don't refcount interfaces so this will also get split up. * * Locking: - * The caller must not hold the IDE locks + * The caller must not hold the IDE locks except for ide_cfg_sem + * which must be held. + * * The drive present/vanishing is not yet properly locked * Take care with the callbacks. These have been split to avoid * deadlocking the IDE layer. The shutdown callback is called @@ -634,26 +730,39 @@ * isnt yet done btw). After we commit to the final kill we * call the cleanup callback with the ide locks held. * + * An interface can be in four states we care about + * - It can be busy (drive or driver thinks its active). No unload + * - It can be unconfigured - which means its already gone + * - It can be configured and present - a full interface + * - It can be configured and not present - pci configured but no drives + * so logically absent. + * * Unregister restores the hwif structures to the default state. - * This is raving bonkers. */ -void ide_unregister(unsigned int index) +int __ide_unregister_hwif(ide_hwif_t *hwif) { - ide_drive_t *drive; - ide_hwif_t *hwif, *g; + ide_drive_t *drive = NULL; /* keep compiler happy */ + ide_hwif_t *g; static ide_hwif_t tmp_hwif; /* protected by ide_cfg_sem */ ide_hwgroup_t *hwgroup; int irq_count = 0, unit, i; - - BUG_ON(index >= MAX_HWIFS); + int was_present; + int ret = 0; + int index = hwif->index; BUG_ON(in_interrupt()); BUG_ON(irqs_disabled()); - down(&ide_cfg_sem); + + /* Make sure nobody sneaks in via the proc interface */ + down(&ide_setting_sem); + + /* Now ensure nobody gets in for I/O while we clean up and + do the busy check. If busy is set then the device is still + open and we must stop */ spin_lock_irq(&ide_lock); - hwif = &ide_hwifs[index]; - if (!hwif->present) + + if (!hwif->configured) goto abort; for (unit = 0; unit < MAX_DRIVES; ++unit) { drive = &hwif->drives[unit]; @@ -663,9 +772,17 @@ goto abort; drive->dead = 1; } + /* + * Protect against new users. From this point the hwif + * is not present so cannot be opened by a new I/O source. + * This also invalidates key driven access from procfs + */ + + was_present = hwif->present; hwif->present = 0; spin_unlock_irq(&ide_lock); + up(&ide_setting_sem); for (unit = 0; unit < MAX_DRIVES; ++unit) { drive = &hwif->drives[unit]; @@ -676,27 +793,35 @@ destroy_proc_ide_interface(hwif); + spin_lock_irq(&ide_lock); hwgroup = hwif->hwgroup; - /* - * free the irq if we were the only hwif using it - */ - g = hwgroup->hwif; - do { - if (g->irq == hwif->irq) - ++irq_count; - g = g->next; - } while (g != hwgroup->hwif); - if (irq_count == 1) + if(hwgroup) + { + /* + * free the irq if we were the only hwif using it + */ + g = hwgroup->hwif; + do { + if (g->irq == hwif->irq) + ++irq_count; + g = g->next; + } while (g != hwgroup->hwif); + } + spin_unlock_irq(&ide_lock); + + if (irq_count == 1 && hwgroup) free_irq(hwif->irq, hwgroup); - spin_lock_irq(&ide_lock); /* * Note that we only release the standard ports, * and do not even try to handle any extra ports * allocated for weird IDE interface chipsets. + * + * FIXME: should defer this I think */ - ide_hwif_release_regions(hwif); + if(was_present) + ide_hwif_release_regions(hwif); /* * Remove us from the hwgroup, and free * the hwgroup if we were the only member @@ -709,6 +834,14 @@ } if (!drive->present) continue; + + /* + * The hwgroup chain is IRQ touched. We must protect + * walking this from an IDE event for another device + * in the chain + */ + + spin_lock_irq(&ide_lock); if (drive == drive->next) { /* special case: last drive from hwgroup. */ BUG_ON(hwgroup->drive != drive); @@ -725,47 +858,67 @@ hwgroup->hwif = HWIF(hwgroup->drive); } } + spin_unlock_irq(&ide_lock); + + /* + * The rest of the cleanup is private + */ + BUG_ON(hwgroup->drive == drive); if (drive->id != NULL) { kfree(drive->id); drive->id = NULL; } drive->present = 0; - /* Messed up locking ... */ - spin_unlock_irq(&ide_lock); blk_cleanup_queue(drive->queue); device_unregister(&drive->gendev); down(&drive->gendev_rel_sem); - spin_lock_irq(&ide_lock); drive->queue = NULL; } - if (hwif->next == hwif) { - BUG_ON(hwgroup->hwif != hwif); - kfree(hwgroup); - } else { - /* There is another interface in hwgroup. - * Unlink us, and set hwgroup->drive and ->hwif to - * something sane. - */ - g = hwgroup->hwif; - while (g->next != hwif) - g = g->next; - g->next = hwif->next; - if (hwgroup->hwif == hwif) { - /* Chose a random hwif for hwgroup->hwif. - * It's guaranteed that there are no drives - * left in the hwgroup. + /* + * Lock against hwgroup walkers including interrupts off other + * IDE devices wile we unhook ourselves. + */ + + spin_lock_irq(&ide_lock); + + if (hwgroup) + { + if (hwif->next == hwif) { + BUG_ON(hwgroup->hwif != hwif); + kfree(hwgroup); + } else { + /* There is another interface in hwgroup. + * Unlink us, and set hwgroup->drive and ->hwif to + * something sane. */ - BUG_ON(hwgroup->drive != NULL); - hwgroup->hwif = g; + g = hwgroup->hwif; + while (g->next != hwif) + g = g->next; + g->next = hwif->next; + if (hwgroup->hwif == hwif) { + /* Chose a random hwif for hwgroup->hwif. + * It's guaranteed that there are no drives + * left in the hwgroup. + */ + BUG_ON(hwgroup->drive != NULL); + hwgroup->hwif = g; + } + BUG_ON(hwgroup->hwif == hwif); } - BUG_ON(hwgroup->hwif == hwif); } - - /* More messed up locking ... */ spin_unlock_irq(&ide_lock); - device_unregister(&hwif->gendev); - down(&hwif->gendev_rel_sem); + + /* + * PCI interfaces with no devices don't exist in the device + * tree so don't unregister them. + */ + + if(was_present) + { + device_unregister(&hwif->gendev); + down(&hwif->gendev_rel_sem); + } /* * Remove us from the kernel's knowledge @@ -780,6 +933,13 @@ unregister_blkdev(hwif->major, hwif->name); spin_lock_irq(&ide_lock); + /* + * Let the driver free up private objects + */ + + if(hwif->remove) + hwif->remove(hwif); + if (hwif->dma_base) { (void) ide_release_dma(hwif); @@ -791,6 +951,7 @@ hwif->dma_vendor3 = 0; hwif->dma_prdtable = 0; } + hwif->chipset = ide_unknown; /* copy original settings */ tmp_hwif = *hwif; @@ -799,15 +960,58 @@ init_hwif_data(hwif, index); init_hwif_default(hwif, index); + hwif->configured = 0; + ide_hwif_restore(hwif, &tmp_hwif); + + spin_unlock_irq(&ide_lock); + return 0; abort: + if(hwif->configured) + { + printk("Unregister %d fail %d %d\n", index, drive->usage, DRIVER(drive)->busy); + ret = -EBUSY; + } + else + { + printk("No such hwif!\n"); + ret = -ENOENT; + } spin_unlock_irq(&ide_lock); - up(&ide_cfg_sem); + up(&ide_setting_sem); + return ret; } -EXPORT_SYMBOL(ide_unregister); +EXPORT_SYMBOL_GPL(__ide_unregister_hwif); + +/** + * ide_unregister_hwif - free an ide interface + * @hwif: interface to unregister + * + * Perform the final unregister of an IDE interface. At the moment + * we don't refcount interfaces so this will also get split up. + * Unregister restores the hwif structures to the default state. + * + * No locks should be held on entry. When an unregister must + * be done atomically with a register see __ide_unregister_hwif + * and hold the ide_cfg_sem yourself. + */ + +int ide_unregister_hwif(ide_hwif_t *hwif) +{ + int ret; + + /* This protects two things. Firstly it serializes the + shutdown sequence, secondly it protects us from + races while we are killing off a device */ + down(&ide_cfg_sem); + ret = __ide_unregister_hwif(hwif); + up(&ide_cfg_sem); + return ret; +} +EXPORT_SYMBOL_GPL(ide_unregister_hwif); /** * ide_setup_ports - set up IDE interface ports @@ -869,7 +1073,12 @@ * @fixup: fixup function * * Register an IDE interface, specifying exactly the registers etc. - * Set init=1 iff calling before probes have taken place. + * Set init=1 iff calling before probes have taken place. The + * ide_cfg_sem protects this against races. + * + * Invokes a fixup function after the probe and before device attachment + * that can be used by the driver to amend settings or to work around + * hardware funnies. * * Returns -1 on error. */ @@ -879,6 +1088,8 @@ int index, retry = 1; ide_hwif_t *hwif; + down(&ide_cfg_sem); + do { for (index = 0; index < MAX_HWIFS; ++index) { hwif = &ide_hwifs[index]; @@ -889,28 +1100,36 @@ hwif = &ide_hwifs[index]; if (hwif->hold) continue; - if ((!hwif->present && !hwif->mate && !initializing) || + if ((!hwif->configured && !hwif->mate && !initializing) || (!hwif->hw.io_ports[IDE_DATA_OFFSET] && initializing)) goto found; } - for (index = 0; index < MAX_HWIFS; index++) - ide_unregister(index); + /* FIXME- this check should die as should the retry loop */ + for (index = 0; index < MAX_HWIFS; index++) { + hwif = &ide_hwifs[index]; + __ide_unregister_hwif(hwif); + } } while (retry--); + + up(&ide_cfg_sem); return -1; found: - if (hwif->present) - ide_unregister(index); + /* FIXME: do we really need this case */ + if (hwif->configured) + __ide_unregister_hwif(hwif); else if (!hwif->hold) { init_hwif_data(hwif, index); init_hwif_default(hwif, index); } - if (hwif->present) + if (hwif->configured) return -1; + hwif->configured = 1; memcpy(&hwif->hw, hw, sizeof(*hw)); memcpy(hwif->io_ports, hwif->hw.io_ports, sizeof(hwif->hw.io_ports)); hwif->irq = hw->irq; hwif->noprobe = 0; hwif->chipset = hw->chipset; + up(&ide_cfg_sem); if (!initializing) { probe_hwif_init_with_fixup(hwif, fixup); @@ -954,21 +1173,21 @@ * @set: setting * * Removes the setting named from the device if it is present. - * The function takes the settings_lock to protect against - * parallel changes. This function must not be called from IRQ - * context. Returns 0 on success or -1 on failure. + * This function must not be called from IRQ context. Returns 0 + * on success or -1 on failure. * * BUGS: This code is seriously over-engineered. There is also * magic about how the driver specific features are setup. If * a driver is attached we assume the driver settings are auto * remove. + * + * The caller must hold settings_lock */ int ide_add_setting (ide_drive_t *drive, const char *name, int rw, int read_ioctl, int write_ioctl, int data_type, int min, int max, int mul_factor, int div_factor, void *data, ide_procset_t *set) { ide_settings_t **p = (ide_settings_t **) &drive->settings, *setting = NULL; - down(&ide_setting_sem); while ((*p) && strcmp((*p)->name, name) < 0) p = &((*p)->next); if ((setting = kmalloc(sizeof(*setting), GFP_KERNEL)) == NULL) @@ -992,10 +1211,8 @@ if (drive->driver != &idedefault_driver) setting->auto_remove = 1; *p = setting; - up(&ide_setting_sem); return 0; abort: - up(&ide_setting_sem); if (setting) kfree(setting); return -1; @@ -1004,7 +1221,7 @@ EXPORT_SYMBOL(ide_add_setting); /** - * __ide_remove_setting - remove an ide setting option + * ide_remove_setting - remove an ide setting option * @drive: drive to use * @name: setting name * @@ -1012,7 +1229,7 @@ * The caller must hold the setting semaphore. */ -static void __ide_remove_setting (ide_drive_t *drive, char *name) +static void ide_remove_setting (ide_drive_t *drive, char *name) { ide_settings_t **p, *setting; @@ -1090,7 +1307,7 @@ setting = drive->settings; while (setting) { if (setting->auto_remove) { - __ide_remove_setting(drive, setting->name); + ide_remove_setting(drive, setting->name); goto repeat; } setting = setting->next; @@ -1289,6 +1506,7 @@ void ide_add_generic_settings (ide_drive_t *drive) { + down(&ide_setting_sem); /* * drive setting name read/write access read ioctl write ioctl data type min max mul_factor div_factor data pointer set function */ @@ -1301,6 +1519,8 @@ ide_add_setting(drive, "init_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->init_speed, NULL); ide_add_setting(drive, "current_speed", SETTING_RW, -1, -1, TYPE_BYTE, 0, 70, 1, 1, &drive->current_speed, set_xfer_rate); ide_add_setting(drive, "number", SETTING_RW, -1, -1, TYPE_BYTE, 0, 3, 1, 1, &drive->dn, NULL); + + up(&ide_setting_sem); } /** @@ -1357,28 +1577,30 @@ * A return of zero indicates attachment to a driver, of one * attachment to the default driver. * - * Takes drivers_lock. + * Takes the driver list lock and the ide_settings semaphore. */ int ata_attach(ide_drive_t *drive) { struct list_head *p; - spin_lock(&drivers_lock); + down(&drivers_sem); + down(&ide_setting_sem); list_for_each(p, &drivers) { ide_driver_t *driver = list_entry(p, ide_driver_t, drivers); if (!try_module_get(driver->owner)) continue; - spin_unlock(&drivers_lock); if (driver->attach(drive) == 0) { module_put(driver->owner); drive->gendev.driver = &driver->gen_driver; + up(&ide_setting_sem); + up(&drivers_sem); return 0; } - spin_lock(&drivers_lock); module_put(driver->owner); } drive->gendev.driver = &idedefault_driver.gen_driver; - spin_unlock(&drivers_lock); + up(&ide_setting_sem); + up(&drivers_sem); if(idedefault_driver.attach(drive) != 0) panic("ide: default attach failed"); return 1; @@ -1504,6 +1726,7 @@ case HDIO_SCAN_HWIF: { hw_regs_t hw; + ide_hwif_t *hwif; int args[3]; if (!capable(CAP_SYS_RAWIO)) return -EACCES; if (copy_from_user(args, p, 3 * sizeof(int))) @@ -1512,14 +1735,18 @@ ide_init_hwif_ports(&hw, (unsigned long) args[0], (unsigned long) args[1], NULL); hw.irq = args[2]; - if (ide_register_hw(&hw, NULL) == -1) + if (ide_register_hw(&hw, &hwif) == -1) return -EIO; + hwif->user_dev = 1; return 0; } case HDIO_UNREGISTER_HWIF: if (!capable(CAP_SYS_RAWIO)) return -EACCES; - /* (arg > MAX_HWIFS) checked in function */ - ide_unregister(arg); + if(arg > MAX_HWIFS || arg < 0) + return -EINVAL; + if(!ide_hwifs[arg].user_dev) + return -EINVAL; + return ide_unregister_hwif(&ide_hwifs[arg]); return 0; case HDIO_SET_NICE: if (!capable(CAP_SYS_ADMIN)) return -EACCES; @@ -1758,10 +1985,10 @@ goto do_serialize; case -6: /* "autotune" */ drive->autotune = IDE_TUNE_AUTO; - goto obsolete_option; + goto done; case -7: /* "noautotune" */ drive->autotune = IDE_TUNE_NOAUTO; - goto obsolete_option; + goto done; case -9: /* "swapdata" */ case -10: /* "bswap" */ drive->bswap = 1; @@ -1893,30 +2120,30 @@ case -7: /* ata66 */ #ifdef CONFIG_BLK_DEV_IDEPCI hwif->udma_four = 1; - goto obsolete_option; + goto done; #else goto bad_hwif; #endif case -6: /* dma */ hwif->autodma = 1; - goto obsolete_option; + goto done; case -5: /* "reset" */ hwif->reset = 1; - goto obsolete_option; + goto done; case -4: /* "noautotune" */ hwif->drives[0].autotune = IDE_TUNE_NOAUTO; hwif->drives[1].autotune = IDE_TUNE_NOAUTO; - goto obsolete_option; + goto done; case -3: /* "autotune" */ hwif->drives[0].autotune = IDE_TUNE_AUTO; hwif->drives[1].autotune = IDE_TUNE_AUTO; - goto obsolete_option; + goto done; case -2: /* "serialize" */ do_serialize: hwif->mate = &ide_hwifs[hw^1]; hwif->mate->mate = hwif; hwif->serialized = hwif->mate->serialized = 1; - goto obsolete_option; + goto done; case -1: /* "noprobe" */ hwif->noprobe = 1; @@ -1933,7 +2160,7 @@ hwif->irq = vals[2]; hwif->noprobe = 0; hwif->chipset = ide_forced; - goto obsolete_option; + goto done; case 0: goto bad_option; default: @@ -1944,9 +2171,6 @@ bad_option: printk(" -- BAD OPTION\n"); return 1; -obsolete_option: - printk(" -- OBSOLETE OPTION, WILL BE REMOVED SOON!\n"); - return 1; bad_hwif: printk("-- NOT SUPPORTED ON ide%d", hw); done: @@ -2110,8 +2334,8 @@ } #ifdef CONFIG_PROC_FS if (drive->driver != &idedefault_driver) { - ide_add_proc_entries(drive->proc, generic_subdriver_entries, drive); - ide_add_proc_entries(drive->proc, driver->proc, drive); + ide_add_proc_entries(drive->proc, generic_subdriver_entries, ide_drive_to_key(drive)); + ide_add_proc_entries(drive->proc, driver->proc, ide_drive_to_key(drive)); } #endif return 0; @@ -2136,6 +2360,7 @@ int ide_unregister_subdriver (ide_drive_t *drive) { unsigned long flags; + ide_proc_entry_t *dir; down(&ide_setting_sem); spin_lock_irqsave(&ide_lock, flags); @@ -2144,13 +2369,14 @@ up(&ide_setting_sem); return 1; } + dir = DRIVER(drive)->proc; + drive->driver = &idedefault_driver; + spin_unlock_irqrestore(&ide_lock, flags); #ifdef CONFIG_PROC_FS - ide_remove_proc_entries(drive->proc, DRIVER(drive)->proc); + ide_remove_proc_entries(drive->proc, dir); ide_remove_proc_entries(drive->proc, generic_subdriver_entries); #endif auto_remove_settings(drive); - drive->driver = &idedefault_driver; - spin_unlock_irqrestore(&ide_lock, flags); up(&ide_setting_sem); spin_lock(&drives_lock); list_del_init(&drive->list); @@ -2176,7 +2402,8 @@ * on the IDE bus in case any should be attached to the * driver we have just registered. If so attach them. * - * Takes drivers_lock and drives_lock. + * Takes the drivers and drives lock. Should take the + * ide_sem but doesn't - FIXME ?? */ int ide_register_driver(ide_driver_t *driver) @@ -2187,9 +2414,11 @@ setup_driver_defaults(driver); + down(&drivers_sem); spin_lock(&drivers_lock); list_add(&driver->drivers, &drivers); spin_unlock(&drivers_lock); + up(&drivers_sem); INIT_LIST_HEAD(&list); spin_lock(&drives_lock); @@ -2225,9 +2454,11 @@ { ide_drive_t *drive; + down(&drivers_sem); spin_lock(&drivers_lock); list_del(&driver->drivers); spin_unlock(&drivers_lock); + up(&drivers_sem); driver_unregister(&driver->gen_driver); @@ -2341,7 +2572,7 @@ int index; for (index = 0; index < MAX_HWIFS; ++index) - ide_unregister(index); + ide_unregister_hwif(&ide_hwifs[index]); #ifdef CONFIG_PROC_FS proc_ide_destroy(); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/ide-cd.c linux-2.6.11/drivers/ide/ide-cd.c --- linux.vanilla-2.6.11/drivers/ide/ide-cd.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/ide-cd.c 2005-03-06 17:10:23.000000000 +0000 @@ -366,7 +366,8 @@ * we cannot reliably check if drive can auto-close */ if (rq->cmd[0] == GPCMD_START_STOP_UNIT && sense->asc == 0x24) - log = 0; + break; + log = 1; break; case UNIT_ATTENTION: /* @@ -388,6 +389,10 @@ struct request *failed_command, struct request_sense *sense) { + unsigned long sector; + unsigned long bio_sectors; + unsigned long valid; + if (!cdrom_log_sense(drive, failed_command, sense)) return; @@ -400,13 +405,43 @@ if (sense->sense_key == 0x05 && sense->asc == 0x24) return; + if (sense->error_code == 0x70) { /* Current Error */ + switch(sense->sense_key) { + case MEDIUM_ERROR: + case VOLUME_OVERFLOW: + case ILLEGAL_REQUEST: + if(!sense->valid) + break; + if(failed_command == NULL || !blk_fs_request(failed_command)) + break; + sector = (sense->information[0] << 24) | + (sense->information[1] << 16) | + (sense->information[2] << 8) | + (sense->information[3]); + + bio_sectors = bio_sectors(failed_command->bio); + if(bio_sectors < 4) + bio_sectors = 4; + if(drive->queue->hardsect_size == 2048) + sector <<= 2; /* Device sector size is 2K */ + sector &= ~(bio_sectors -1); + valid = (sector - failed_command->sector) << 9; + + if(valid < 0) + valid = 0; + if(sector < get_capacity(drive->disk) && + drive->probed_capacity - sector < 4 * 75) { + set_capacity(drive->disk, sector); + } + } + } #if VERBOSE_IDE_CD_ERRORS { int i; const char *s; char buf[80]; - printk ("ATAPI device %s:\n", drive->name); + printk (KERN_ERR "ATAPI device %s:\n", drive->name); if (sense->error_code==0x70) printk(" Error: "); else if (sense->error_code==0x71) @@ -579,17 +614,22 @@ sense = failed->sense; failed->sense_len = rq->sense_len; } - + cdrom_analyze_sense_data(drive, failed, sense); /* * now end failed request */ - spin_lock_irqsave(&ide_lock, flags); - end_that_request_chunk(failed, 0, failed->data_len); - end_that_request_last(failed); - spin_unlock_irqrestore(&ide_lock, flags); + if(blk_fs_request(failed)) { + if(ide_end_dequeued_request(drive, failed, 0, failed->hard_nr_sectors)) + BUG(); + } else { + spin_lock_irqsave(&ide_lock, flags); + end_that_request_chunk(failed, 0, failed->data_len); + end_that_request_last(failed); + spin_unlock_irqrestore(&ide_lock, flags); + } } - - cdrom_analyze_sense_data(drive, failed, sense); + else + cdrom_analyze_sense_data(drive, NULL , sense); } if (!rq->current_nr_sectors && blk_fs_request(rq)) @@ -603,6 +643,13 @@ ide_end_request(drive, uptodate, nsectors); } +static void ide_dump_status_no_sense(ide_drive_t *drive, const char *msg, u8 stat) +{ + if(stat & 0x80) + return; + ide_dump_status(drive, msg, stat); +} + /* Returns 0 if the request should be continued. Returns 1 if the request was ended. */ static int cdrom_decode_status(ide_drive_t *drive, int good_stat, int *stat_ret) @@ -731,16 +778,16 @@ sense_key == DATA_PROTECT) { /* No point in retrying after an illegal request or data protect error.*/ - ide_dump_status (drive, "command error", stat); + ide_dump_status_no_sense (drive, "command error", stat); do_end_request = 1; } else if (sense_key == MEDIUM_ERROR) { /* No point in re-trying a zillion times on a bad * sector... If we got here the error is not correctable */ - ide_dump_status (drive, "media error (bad sector)", stat); + ide_dump_status_no_sense (drive, "media error (bad sector)", stat); do_end_request = 1; } else if (sense_key == BLANK_CHECK) { /* Disk appears blank ?? */ - ide_dump_status (drive, "media error (blank)", stat); + ide_dump_status_no_sense (drive, "media error (blank)", stat); do_end_request = 1; } else if ((err & ~ABRT_ERR) != 0) { /* Go to the default handler @@ -752,13 +799,27 @@ do_end_request = 1; } - if (do_end_request) - cdrom_end_request(drive, 0); + /* End a request through request sense analysis when we have + sense data. We need this in order to perform end of media + processing */ + + if (do_end_request) { + if (stat & ERR_STAT) { + unsigned long flags; + spin_lock_irqsave(&ide_lock, flags); + blkdev_dequeue_request(rq); + HWGROUP(drive)->rq = NULL; + spin_unlock_irqrestore(&ide_lock, flags); - /* If we got a CHECK_CONDITION status, - queue a request sense command. */ - if ((stat & ERR_STAT) != 0) - cdrom_queue_request_sense(drive, NULL, NULL); + cdrom_queue_request_sense(drive, rq->sense, rq); + } + else cdrom_end_request(drive, 0); + } else { + /* If we got a CHECK_CONDITION status, + queue a request sense command. */ + if (stat & ERR_STAT) + cdrom_queue_request_sense(drive, NULL, NULL); + } } else { blk_dump_rq_flags(rq, "ide-cd: bad rq"); cdrom_end_request(drive, 0); @@ -816,7 +877,7 @@ return startstop; if (info->dma) - info->dma = !hwif->dma_setup(drive); + info->dma = !hwif->ide_dma_setup(drive); /* Set up the controller registers. */ /* FIXME: for Virtual DMA we must check harder */ @@ -892,7 +953,7 @@ /* Start the DMA if need be */ if (info->dma) - hwif->dma_start(drive); + hwif->ide_dma_start(drive); return ide_started; } @@ -1464,8 +1525,7 @@ } -static -int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq) +static int cdrom_queue_packet_command(ide_drive_t *drive, struct request *rq) { struct request_sense sense; int retries = 10; @@ -2202,6 +2262,9 @@ toc->capacity = 0x1fffff; set_capacity(drive->disk, toc->capacity * sectors_per_frame); + /* Save a private copy of te TOC capacity for error handling */ + drive->probed_capacity = toc->capacity * sectors_per_frame; + blk_queue_hardsect_size(drive->queue, sectors_per_frame << SECTOR_BITS); @@ -2322,6 +2385,7 @@ if (!stat && (last_written > toc->capacity)) { toc->capacity = last_written; set_capacity(drive->disk, toc->capacity * sectors_per_frame); + drive->probed_capacity = toc->capacity * sectors_per_frame; } /* Remember that we've read this stuff. */ @@ -2674,14 +2738,11 @@ * any other way to detect this... */ if (sense.sense_key == NOT_READY) { - if (sense.asc == 0x3a) { - if (sense.ascq == 1) - return CDS_NO_DISC; - else if (sense.ascq == 0 || sense.ascq == 2) - return CDS_TRAY_OPEN; - } + if (sense.asc == 0x3a && sense.ascq == 1) + return CDS_NO_DISC; + else + return CDS_TRAY_OPEN; } - return CDS_DRIVE_NOT_READY; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/ide-disk.c linux-2.6.11/drivers/ide/ide-disk.c --- linux.vanilla-2.6.11/drivers/ide/ide-disk.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/ide-disk.c 2005-03-06 14:47:22.000000000 +0000 @@ -84,6 +84,10 @@ { unsigned long lba_sects, chs_sects, head, tail; + /* No non-LBA info .. so valid! */ + if (id->cyls == 0) + return 1; + /* * The ATA spec tells large drives to return * C/H/S = 16383/16/63 independent of their size. @@ -210,7 +214,7 @@ } if (dma) { - if (!hwif->dma_setup(drive)) { + if (!hwif->ide_dma_setup(drive)) { if (rq_data_dir(rq)) { command = lba48 ? WIN_WRITEDMA_EXT : WIN_WRITEDMA; if (drive->vdma) @@ -220,8 +224,8 @@ if (drive->vdma) command = lba48 ? WIN_READ_EXT: WIN_READ; } - hwif->dma_exec_cmd(drive, command); - hwif->dma_start(drive); + hwif->ide_dma_exec_cmd(drive, command); + hwif->ide_dma_start(drive); return ide_started; } /* fallback to PIO */ @@ -438,13 +442,14 @@ static inline void idedisk_check_hpa(ide_drive_t *drive) { - unsigned long long capacity, set_max; + unsigned long long capacity, set_max = 0; int lba48 = idedisk_supports_lba48(drive->id); + capacity = drive->capacity64; if (lba48) set_max = idedisk_read_native_max_address_ext(drive); - else + if (set_max == 0) /* LBA28 or LBA48 failed */ set_max = idedisk_read_native_max_address(drive); if (set_max <= capacity) @@ -457,7 +462,8 @@ capacity, sectors_to_MB(capacity), set_max, sectors_to_MB(set_max)); - if (lba48) + /* Some maxtor support LBA48 but do not accept LBA48 set max... */ + if (lba48 || set_max < (1ULL << 28)) set_max = idedisk_set_max_address_ext(drive, set_max); else set_max = idedisk_set_max_address(drive, set_max); @@ -635,24 +641,30 @@ static int proc_idedisk_read_cache (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *) data; + ide_drive_t *drive; char *out = page; int len; - if (drive->id_read) + down(&ide_cfg_sem); + drive = ide_drive_from_key(data); + if (drive && drive->id_read) len = sprintf(out,"%i\n", drive->id->buf_size / 2); else len = sprintf(out,"(none)\n"); + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } static int proc_idedisk_read_smart_thresholds (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *)data; + ide_drive_t *drive; int len = 0, i = 0; - if (!get_smart_thresholds(drive, page)) { + down(&ide_cfg_sem); + + drive = ide_drive_from_key(data); + if (drive && !get_smart_thresholds(drive, page)) { unsigned short *val = (unsigned short *) page; char *out = ((char *)val) + (SECTOR_WORDS * 4); page = out; @@ -662,16 +674,20 @@ } while (i < (SECTOR_WORDS * 2)); len = out - page; } + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } static int proc_idedisk_read_smart_values (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *)data; + ide_drive_t *drive; int len = 0, i = 0; - if (!get_smart_values(drive, page)) { + down(&ide_cfg_sem); + + drive = ide_drive_from_key(data); + if (drive && !get_smart_values(drive, page)) { unsigned short *val = (unsigned short *) page; char *out = ((char *)val) + (SECTOR_WORDS * 4); page = out; @@ -681,6 +697,7 @@ } while (i < (SECTOR_WORDS * 2)); len = out - page; } + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } @@ -1053,8 +1070,9 @@ if (id->buf_size) printk (" w/%dKiB Cache", id->buf_size/2); - printk(", CHS=%d/%d/%d", - drive->bios_cyl, drive->bios_head, drive->bios_sect); + if(drive->bios_cyl) + printk(", CHS=%d/%d/%d", + drive->bios_cyl, drive->bios_head, drive->bios_sect); if (drive->using_dma) ide_dma_verbose(drive); printk("\n"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/ide-dma.c linux-2.6.11/drivers/ide/ide-dma.c --- linux.vanilla-2.6.11/drivers/ide/ide-dma.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/ide-dma.c 2005-03-06 14:47:39.000000000 +0000 @@ -132,7 +132,6 @@ { "SAMSUNG CD-ROM SC-148C", "ALL" }, { "SAMSUNG CD-ROM SC", "ALL" }, { "SanDisk SDP3B-64" , "ALL" }, - { "SAMSUNG CD-ROM SN-124", "ALL" }, { "ATAPI CD-ROM DRIVE 40X MAXIMUM", "ALL" }, { "_NEC DV5800A", "ALL" }, { NULL , NULL } @@ -922,12 +921,12 @@ hwif->ide_dma_host_on = &__ide_dma_host_on; if (!hwif->ide_dma_check) hwif->ide_dma_check = &__ide_dma_check; - if (!hwif->dma_setup) - hwif->dma_setup = &ide_dma_setup; - if (!hwif->dma_exec_cmd) - hwif->dma_exec_cmd = &ide_dma_exec_cmd; - if (!hwif->dma_start) - hwif->dma_start = &ide_dma_start; + if (!hwif->ide_dma_setup) + hwif->ide_dma_setup = &ide_dma_setup; + if (!hwif->ide_dma_exec_cmd) + hwif->ide_dma_exec_cmd = &ide_dma_exec_cmd; + if (!hwif->ide_dma_start) + hwif->ide_dma_start = &ide_dma_start; if (!hwif->ide_dma_end) hwif->ide_dma_end = &__ide_dma_end; if (!hwif->ide_dma_test_irq) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/ide-floppy.c linux-2.6.11/drivers/ide/ide-floppy.c --- linux.vanilla-2.6.11/drivers/ide/ide-floppy.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/ide-floppy.c 2005-03-06 15:12:01.000000000 +0000 @@ -1066,7 +1066,7 @@ feature.all = 0; if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) - feature.b.dma = !hwif->dma_setup(drive); + feature.b.dma = !hwif->ide_dma_setup(drive); if (IDE_CONTROL_REG) HWIF(drive)->OUTB(drive->ctl, IDE_CONTROL_REG); @@ -1078,7 +1078,7 @@ if (feature.b.dma) { /* Begin DMA, if necessary */ set_bit(PC_DMA_IN_PROGRESS, &pc->flags); - hwif->dma_start(drive); + hwif->ide_dma_start(drive); } /* Can we transfer the packet when we get the interrupt or wait? */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/ide-io.c linux-2.6.11/drivers/ide/ide-io.c --- linux.vanilla-2.6.11/drivers/ide/ide-io.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/ide-io.c 2005-03-06 17:13:05.000000000 +0000 @@ -190,6 +190,62 @@ EXPORT_SYMBOL(ide_end_request); /** + * ide_end_dequeued_request - complete an IDE I/O + * @drive: IDE device for the I/O + * @uptodate: + * @nr_sectors: number of sectors completed + * + * Complete an I/O that is no longer on the request queue. This + * typically occurs when we pull the request and issue a REQUEST_SENSE. + * We must still finish the old request but we must not tamper with the + * queue in the meantime. + * + * NOTE: This path does not handle barrier, but barrier is not supported + * on ide-cd anyway. + */ + +int ide_end_dequeued_request(ide_drive_t *drive, struct request *rq, + int uptodate, int nr_sectors) +{ + unsigned long flags; + int ret = 1; + + spin_lock_irqsave(&ide_lock, flags); + + BUG_ON(!(rq->flags & REQ_STARTED)); + + /* + * if failfast is set on a request, override number of sectors and + * complete the whole request right now + */ + if (blk_noretry_request(rq) && end_io_error(uptodate)) + nr_sectors = rq->hard_nr_sectors; + + if (!blk_fs_request(rq) && end_io_error(uptodate) && !rq->errors) + rq->errors = -EIO; + + /* + * decide whether to reenable DMA -- 3 is a random magic for now, + * if we DMA timeout more than 3 times, just stay in PIO + */ + if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) { + drive->state = 0; + HWGROUP(drive)->hwif->ide_dma_on(drive); + } + + if (!end_that_request_first(rq, uptodate, nr_sectors)) { + add_disk_randomness(rq->rq_disk); + if (blk_rq_tagged(rq)) + blk_queue_end_tag(drive->queue, rq); + end_that_request_last(rq); + ret = 0; + } + spin_unlock_irqrestore(&ide_lock, flags); + return ret; +} +EXPORT_SYMBOL_GPL(ide_end_dequeued_request); + +/** * ide_complete_pm_request - end the current Power Management request * @drive: target drive * @rq: request @@ -1442,7 +1498,13 @@ spin_unlock_irqrestore(&ide_lock, flags); return IRQ_NONE; } - + if (hwif->polling) { + /* We took an interrupt during a polled drive retune. + This should go away eventually when that code uses + the polling logic like do_reset1 */ + spin_unlock_irqrestore(&ide_lock, flags); + return IRQ_HANDLED; + } if ((handler = hwgroup->handler) == NULL || hwgroup->polling) { /* * Not expecting an interrupt from this drive. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/ide-iops.c linux-2.6.11/drivers/ide/ide-iops.c --- linux.vanilla-2.6.11/drivers/ide/ide-iops.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/ide-iops.c 2005-03-06 15:13:38.000000000 +0000 @@ -107,6 +107,74 @@ EXPORT_SYMBOL(default_hwif_iops); /* + * Interface removed + */ + +static u8 ide_no_inb(unsigned long port) +{ + return 0xFF; +} + +static u16 ide_no_inw (unsigned long port) +{ + return 0xFFFF; +} + +static void ide_no_insw (unsigned long port, void *addr, u32 count) +{ +} + +static u32 ide_no_inl (unsigned long port) +{ + return 0xFFFFFFFF; +} + +static void ide_no_insl (unsigned long port, void *addr, u32 count) +{ +} + +static void ide_no_outb (u8 val, unsigned long port) +{ +} + +static void ide_no_outbsync (ide_drive_t *drive, u8 addr, unsigned long port) +{ +} + +static void ide_no_outw (u16 val, unsigned long port) +{ +} + +static void ide_no_outsw (unsigned long port, void *addr, u32 count) +{ +} + +static void ide_no_outl (u32 val, unsigned long port) +{ +} + +static void ide_no_outsl (unsigned long port, void *addr, u32 count) +{ +} + +void removed_hwif_iops (ide_hwif_t *hwif) +{ + hwif->OUTB = ide_no_outb; + hwif->OUTBSYNC = ide_no_outbsync; + hwif->OUTW = ide_no_outw; + hwif->OUTL = ide_no_outl; + hwif->OUTSW = ide_no_outsw; + hwif->OUTSL = ide_no_outsl; + hwif->INB = ide_no_inb; + hwif->INW = ide_no_inw; + hwif->INL = ide_no_inl; + hwif->INSW = ide_no_insw; + hwif->INSL = ide_no_insl; +} + +EXPORT_SYMBOL(removed_hwif_iops); + +/* * MMIO operations, typically used for SATA controllers */ @@ -601,44 +669,15 @@ */ u8 eighty_ninty_three (ide_drive_t *drive) { -#if 0 - if (!HWIF(drive)->udma_four) + if(HWIF(drive)->udma_four == 0) + return 0; + if (!(drive->id->hw_config & 0x6000)) return 0; - - if (drive->id->major_rev_num) { - int hssbd = 0; - int i; - /* - * Determine highest Supported SPEC - */ - for (i=1; i<=15; i++) - if (drive->id->major_rev_num & (1<id->hw_config & 0x4000) && -#endif /* CONFIG_IDEDMA_IVB */ - (drive->id->hw_config & 0x6000)) ? 1 : 0); - -#else - - return ((u8) ((HWIF(drive)->udma_four) && #ifndef CONFIG_IDEDMA_IVB - (drive->id->hw_config & 0x4000) && + if(!(drive->id->hw_config & 0x4000)) + return 0; #endif /* CONFIG_IDEDMA_IVB */ - (drive->id->hw_config & 0x6000)) ? 1 : 0); -#endif + return 1; } EXPORT_SYMBOL(eighty_ninty_three); @@ -796,6 +835,11 @@ * It is gone.......... * * const char *msg == consider adding for verbose errors. + * + * Beware. If we timed out from a series of CRC errors and the timer + * expiry caused a switch to PIO mode and we take an IRQ as the drive times + * out about the same moment we may be entering this function with a + * pending interrupt. */ int ide_config_drive_speed (ide_drive_t *drive, u8 speed) { @@ -813,20 +857,20 @@ /* * Don't use ide_wait_cmd here - it will - * attempt to set_geometry and recalibrate, - * but for some reason these don't work at - * this point (lost interrupt). - */ - /* - * Select the drive, and issue the SETFEATURES command + * attempt to set_geometry and recalibrate, We can't + * do that here as we may be in the IRQ handler already + * + * Select the drive, and issue the SETFEATURES command in + * polled mode. */ disable_irq_nosync(hwif->irq); /* - * FIXME: we race against the running IRQ here if + * We race against the running IRQ here if * this is called from non IRQ context. If we use - * disable_irq() we hang on the error path. Work - * is needed. + * disable_irq() we hang on the error path. Instead we + * must let the core code know the hwif is doing a polling + * recovery. */ udelay(1); @@ -837,23 +881,43 @@ hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG); hwif->OUTB(speed, IDE_NSECTOR_REG); hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG); - hwif->OUTB(WIN_SETFEATURES, IDE_COMMAND_REG); - if ((IDE_CONTROL_REG) && (drive->quirk_list == 2)) + hwif->OUTBSYNC(drive, WIN_SETFEATURES, IDE_COMMAND_REG); + /* The status bits are not valid for 400nS */ + udelay(1); + + /* Drive status is now valid which means we can allow interrupts + to occur as they will see the drive as busy and will not + interfere erroneously. IRQ's for this drive will also be off + providing control and quirks allow for it */ + + if ((IDE_CONTROL_REG) && drive->quirk_list == 2) hwif->OUTB(drive->ctl, IDE_CONTROL_REG); udelay(1); + + /* + * Tell the interrupt layer that we are doing polled recovery. + * Eventually this should use the same mechanism do_reset does + * internally. + */ + + hwif->polling = 1; + /* * Wait for drive to become non-BUSY */ if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) { - unsigned long flags, timeout; - local_irq_set(flags); + unsigned long timeout; + /* FIXME */ +/* spin_unlock_irq(&ide_lock); */ timeout = jiffies + WAIT_CMD; while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) { if (time_after(jiffies, timeout)) break; } - local_irq_restore(flags); +/* spin_lock_irq(&ide_lock); */ } + + hwif->polling = 0; /* * Allow status to settle, then read it again. @@ -1163,7 +1227,8 @@ pre_reset(drive); SELECT_DRIVE(drive); udelay (20); - hwif->OUTB(WIN_SRST, IDE_COMMAND_REG); + hwif->OUTBSYNC(drive, WIN_SRST, IDE_COMMAND_REG); + ndelay(400); hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE; hwgroup->polling = 1; __ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/ide-pnp.c linux-2.6.11/drivers/ide/ide-pnp.c --- linux.vanilla-2.6.11/drivers/ide/ide-pnp.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/ide-pnp.c 2005-03-06 14:48:23.000000000 +0000 @@ -19,6 +19,7 @@ #include #include #include +#include /* Add your devices here :)) */ static struct pnp_device_id idepnp_devices[] = { @@ -57,7 +58,11 @@ { ide_hwif_t *hwif = pnp_get_drvdata(dev); if (hwif) { - ide_unregister(hwif->index); + /* FIXME: will want pushing into a helper workqueue */ + while(ide_unregister_hwif(hwif) < 0) { + removed_hwif_iops(hwif); + msleep(1000); + } } else printk(KERN_ERR "idepnp: Unable to remove device, please report.\n"); } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/ide-probe.c linux-2.6.11/drivers/ide/ide-probe.c --- linux.vanilla-2.6.11/drivers/ide/ide-probe.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/ide-probe.c 2005-03-06 14:48:30.000000000 +0000 @@ -614,6 +614,7 @@ } hwif->gendev.release = hwif_release_dev; device_register(&hwif->gendev); + hwif->configured = 1; } static int wait_hwif_ready(ide_hwif_t *hwif) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/ide-proc.c linux-2.6.11/drivers/ide/ide-proc.c --- linux.vanilla-2.6.11/drivers/ide/ide-proc.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/ide-proc.c 2005-03-06 15:15:35.000000000 +0000 @@ -42,68 +42,86 @@ static int proc_ide_read_imodel (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_hwif_t *hwif = (ide_hwif_t *) data; + ide_hwif_t *hwif; int len; - const char *name; + const char *name = ""; - /* - * Neither ide_unknown nor ide_forced should be set at this point. - */ - switch (hwif->chipset) { - case ide_generic: name = "generic"; break; - case ide_pci: name = "pci"; break; - case ide_cmd640: name = "cmd640"; break; - case ide_dtc2278: name = "dtc2278"; break; - case ide_ali14xx: name = "ali14xx"; break; - case ide_qd65xx: name = "qd65xx"; break; - case ide_umc8672: name = "umc8672"; break; - case ide_ht6560b: name = "ht6560b"; break; - case ide_rz1000: name = "rz1000"; break; - case ide_trm290: name = "trm290"; break; - case ide_cmd646: name = "cmd646"; break; - case ide_cy82c693: name = "cy82c693"; break; - case ide_4drives: name = "4drives"; break; - case ide_pmac: name = "mac-io"; break; - default: name = "(unknown)"; break; + down(&ide_cfg_sem); + hwif = ide_hwif_from_key(data); + if(hwif) { + /* + * Neither ide_unknown nor ide_forced should be set at this point. + */ + switch (hwif->chipset) { + case ide_generic: name = "generic"; break; + case ide_pci: name = "pci"; break; + case ide_cmd640: name = "cmd640"; break; + case ide_dtc2278: name = "dtc2278"; break; + case ide_ali14xx: name = "ali14xx"; break; + case ide_qd65xx: name = "qd65xx"; break; + case ide_umc8672: name = "umc8672"; break; + case ide_ht6560b: name = "ht6560b"; break; + case ide_rz1000: name = "rz1000"; break; + case ide_trm290: name = "trm290"; break; + case ide_cmd646: name = "cmd646"; break; + case ide_cy82c693: name = "cy82c693"; break; + case ide_4drives: name = "4drives"; break; + case ide_pmac: name = "mac-io"; break; + default: name = "(unknown)"; break; + } } len = sprintf(page, "%s\n", name); + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } static int proc_ide_read_mate (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_hwif_t *hwif = (ide_hwif_t *) data; + ide_hwif_t *hwif; int len; + down(&ide_cfg_sem); + hwif = ide_hwif_from_key(data); if (hwif && hwif->mate && hwif->mate->present) len = sprintf(page, "%s\n", hwif->mate->name); else len = sprintf(page, "(none)\n"); + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } static int proc_ide_read_channel (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_hwif_t *hwif = (ide_hwif_t *) data; - int len; + ide_hwif_t *hwif; + int len = 0; - page[0] = hwif->channel ? '1' : '0'; - page[1] = '\n'; - len = 2; + down(&ide_cfg_sem); + hwif = ide_hwif_from_key(data); + if(hwif) { + page[0] = hwif->channel ? '1' : '0'; + page[1] = '\n'; + len = 2; + } + else + page[0] = '\n'; + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } static int proc_ide_read_identify (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *)data; + ide_drive_t *drive; int len = 0, i = 0; int err = 0; len = sprintf(page, "\n"); + down(&ide_cfg_sem); + drive = ide_drive_from_key(data); + if (drive) { unsigned short *val = (unsigned short *) page; @@ -121,6 +139,7 @@ len = out - page; } } + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } @@ -139,13 +158,22 @@ static int proc_ide_read_settings (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *) data; - ide_settings_t *setting = (ide_settings_t *) drive->settings; + ide_drive_t *drive; + ide_settings_t *setting; char *out = page; int len, rc, mul_factor, div_factor; proc_ide_settings_warn(); + down(&ide_cfg_sem); + drive = ide_drive_from_key(data); + + if(drive == NULL) { + up(&ide_cfg_sem); + return -EIO; + } + + setting = (ide_settings_t *) drive->settings; down(&ide_setting_sem); out += sprintf(out, "name\t\t\tvalue\t\tmin\t\tmax\t\tmode\n"); out += sprintf(out, "----\t\t\t-----\t\t---\t\t---\t\t----\n"); @@ -167,15 +195,16 @@ } len = out - page; up(&ide_setting_sem); + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } #define MAX_LEN 30 -static int proc_ide_write_settings(struct file *file, const char __user *buffer, +static int do_proc_ide_write_settings(struct file *file, const char __user *buffer, unsigned long count, void *data) { - ide_drive_t *drive = (ide_drive_t *) data; + ide_drive_t *drive = ide_drive_from_key(data); char name[MAX_LEN + 1]; int for_real = 0; unsigned long n; @@ -184,6 +213,9 @@ if (!capable(CAP_SYS_ADMIN)) return -EACCES; + + if (drive == NULL) + return -EIO; proc_ide_settings_warn(); @@ -266,30 +298,55 @@ return -EINVAL; } +static int proc_ide_write_settings(struct file *file, const char __user *buffer, + unsigned long count, void *data) +{ + int ret; + + down(&ide_cfg_sem); + ret = do_proc_ide_write_settings(file, buffer, count, data); + up(&ide_cfg_sem); + return ret; +} + int proc_ide_read_capacity (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *) data; + ide_drive_t *drive; int len; + drive = ide_drive_from_key(data); + if(drive == NULL) { + up(&ide_cfg_sem); + return -EIO; + } + len = sprintf(page,"%llu\n", (long long) (DRIVER(drive)->capacity(drive))); + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } int proc_ide_read_geometry (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *) data; + ide_drive_t *drive; char *out = page; int len; + down(&ide_cfg_sem); + drive = ide_drive_from_key(data); + if(drive == NULL) { + up(&ide_cfg_sem); + return -EIO; + } out += sprintf(out,"physical %d/%d/%d\n", drive->cyl, drive->head, drive->sect); out += sprintf(out,"logical %d/%d/%d\n", drive->bios_cyl, drive->bios_head, drive->bios_sect); len = out - page; + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } @@ -298,52 +355,60 @@ static int proc_ide_read_dmodel (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *) data; - struct hd_driveid *id = drive->id; + ide_drive_t *drive; + struct hd_driveid *id; int len; + down(&ide_cfg_sem); + drive = ide_drive_from_key(data); + if(drive == NULL) { + up(&ide_cfg_sem); + return -EIO; + } + + id = drive->id; len = sprintf(page, "%.40s\n", (id && id->model[0]) ? (char *)id->model : "(none)"); + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } static int proc_ide_read_driver (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *) data; - ide_driver_t *driver = drive->driver; + ide_drive_t *drive; + ide_driver_t *driver; int len; + down(&ide_cfg_sem); + drive = ide_drive_from_key(data); + if(drive == NULL) { + up(&ide_cfg_sem); + return -EIO; + } + + driver = drive->driver; + len = sprintf(page, "%s version %s\n", driver->name, driver->version); + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } -static int proc_ide_write_driver - (struct file *file, const char __user *buffer, unsigned long count, void *data) -{ - ide_drive_t *drive = (ide_drive_t *) data; - char name[32]; - - if (!capable(CAP_SYS_ADMIN)) - return -EACCES; - if (count > 31) - count = 31; - if (copy_from_user(name, buffer, count)) - return -EFAULT; - name[count] = '\0'; - if (ide_replace_subdriver(drive, name)) - return -EINVAL; - return count; -} - static int proc_ide_read_media (char *page, char **start, off_t off, int count, int *eof, void *data) { - ide_drive_t *drive = (ide_drive_t *) data; + ide_drive_t *drive; const char *media; int len; + down(&ide_cfg_sem); + drive = ide_drive_from_key(data); + if(drive == NULL) { + up(&ide_cfg_sem); + return -EIO; + } + switch (drive->media) { case ide_disk: media = "disk\n"; break; @@ -358,11 +423,12 @@ } strcpy(page,media); len = strlen(media); + up(&ide_cfg_sem); PROC_IDE_READ_RETURN(page,start,off,count,eof,len); } static ide_proc_entry_t generic_drive_entries[] = { - { "driver", S_IFREG|S_IRUGO, proc_ide_read_driver, proc_ide_write_driver }, + { "driver", S_IFREG|S_IRUGO, proc_ide_read_driver, NULL }, { "identify", S_IFREG|S_IRUSR, proc_ide_read_identify, NULL }, { "media", S_IFREG|S_IRUGO, proc_ide_read_media, NULL }, { "model", S_IFREG|S_IRUGO, proc_ide_read_dmodel, NULL }, @@ -414,7 +480,7 @@ drive->proc = proc_mkdir(drive->name, parent); if (drive->proc) - ide_add_proc_entries(drive->proc, generic_drive_entries, drive); + ide_add_proc_entries(drive->proc, generic_drive_entries, ide_drive_to_key(drive)); sprintf(name,"ide%d/%s", (drive->name[2]-'a')/2, drive->name); ent = proc_symlink(drive->name, proc_ide_root, name); if (!ent) return; @@ -465,7 +531,7 @@ hwif->proc = proc_mkdir(hwif->name, proc_ide_root); if (!hwif->proc) return; - ide_add_proc_entries(hwif->proc, hwif_entries, hwif); + ide_add_proc_entries(hwif->proc, hwif_entries, ide_hwif_to_key(hwif)); } create_proc_ide_drives(hwif); } @@ -482,6 +548,8 @@ EXPORT_SYMBOL_GPL(ide_pci_create_host_proc); #endif +EXPORT_SYMBOL_GPL(destroy_proc_ide_interface); + void destroy_proc_ide_interface(ide_hwif_t *hwif) { if (hwif->proc) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/ide-tape.c linux-2.6.11/drivers/ide/ide-tape.c --- linux.vanilla-2.6.11/drivers/ide/ide-tape.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/ide-tape.c 2005-03-06 14:48:38.000000000 +0000 @@ -2067,7 +2067,7 @@ #ifdef CONFIG_BLK_DEV_IDEDMA /* Begin DMA, if necessary */ if (test_bit(PC_DMA_IN_PROGRESS, &pc->flags)) - hwif->dma_start(drive); + hwif->ide_dma_start(drive); #endif /* Send the actual packet */ HWIF(drive)->atapi_output_bytes(drive, pc->c, 12); @@ -2136,7 +2136,7 @@ (void)__ide_dma_off(drive); } if (test_bit(PC_DMA_RECOMMENDED, &pc->flags) && drive->using_dma) - dma_ok = !hwif->dma_setup(drive); + dma_ok = !hwif->ide_dma_setup(drive); if (IDE_CONTROL_REG) hwif->OUTB(drive->ctl, IDE_CONTROL_REG); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/ide-taskfile.c linux-2.6.11/drivers/ide/ide-taskfile.c --- linux.vanilla-2.6.11/drivers/ide/ide-taskfile.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/ide-taskfile.c 2005-03-06 14:48:50.000000000 +0000 @@ -147,9 +147,9 @@ case WIN_READDMA: case WIN_READDMA_EXT: case WIN_IDENTIFY_DMA: - if (!hwif->dma_setup(drive)) { - hwif->dma_exec_cmd(drive, taskfile->command); - hwif->dma_start(drive); + if (!hwif->ide_dma_setup(drive)) { + hwif->ide_dma_exec_cmd(drive, taskfile->command); + hwif->ide_dma_start(drive); return ide_started; } break; @@ -863,9 +863,9 @@ case TASKFILE_OUT_DMA: case TASKFILE_IN_DMAQ: case TASKFILE_IN_DMA: - hwif->dma_setup(drive); - hwif->dma_exec_cmd(drive, taskfile->command); - hwif->dma_start(drive); + hwif->ide_dma_setup(drive); + hwif->ide_dma_exec_cmd(drive, taskfile->command); + hwif->ide_dma_start(drive); break; default: diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/Kconfig linux-2.6.11/drivers/ide/Kconfig --- linux.vanilla-2.6.11/drivers/ide/Kconfig 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/Kconfig 2005-03-06 14:48:57.000000000 +0000 @@ -166,6 +166,13 @@ Support for outboard IDE disks, tape drives, and CD-ROM drives connected through a PCMCIA card. +config BLK_DEV_DELKIN + tristate "Cardbus IDE support (Delkin/ASKA/Workbit)" + depends on PCMCIA && PCI + help + Support for Delkin, ASKA, and Workbit Cardbus CompactFlash + Adapters. This may also work for similar SD and XD adapters. + config BLK_DEV_IDECD tristate "Include IDE/ATAPI CDROM support" ---help--- @@ -607,6 +614,12 @@ ; picture of the board at . +config BLK_DEV_IT821X + tristate "IT821X IDE support" + help + This driver adds support for the ITE 8211 IDE controller and the + IT 8212 IDE RAID controller in both RAID and pass-through mode. + config BLK_DEV_NS87415 tristate "NS87415 chipset support" help diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/legacy/ide-cs.c linux-2.6.11/drivers/ide/legacy/ide-cs.c --- linux.vanilla-2.6.11/drivers/ide/legacy/ide-cs.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/legacy/ide-cs.c 2005-03-06 14:48:57.000000000 +0000 @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -85,6 +86,7 @@ int ndev; dev_node_t node; int hd; + ide_hwif_t *hwif; } ide_info_t; static void ide_release(dev_link_t *); @@ -188,14 +190,14 @@ } /* ide_detach */ -static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq) +static int idecs_register(unsigned long io, unsigned long ctl, unsigned long irq, ide_hwif_t **hwif) { hw_regs_t hw; memset(&hw, 0, sizeof(hw)); ide_init_hwif_ports(&hw, io, ctl, NULL); hw.irq = irq; hw.chipset = ide_pci; - return ide_register_hw_with_fixup(&hw, NULL, ide_undecoded_slave); + return ide_register_hw_with_fixup(&hw, hwif, ide_undecoded_slave); } /*====================================================================== @@ -213,6 +215,7 @@ { client_handle_t handle = link->handle; ide_info_t *info = link->priv; + ide_hwif_t *hwif; tuple_t tuple; struct { u_short buf[128]; @@ -332,22 +335,24 @@ if (is_kme) outb(0x81, ctl_base+1); - /* retry registration in case device is still spinning up */ + /* retry registration in case device is still spinning up + + FIXME: now handled by IDE layer... ?? */ + for (hd = -1, i = 0; i < 10; i++) { - hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ); + hd = idecs_register(io_base, ctl_base, link->irq.AssignedIRQ, &hwif); if (hd >= 0) break; if (link->io.NumPorts1 == 0x20) { outb(0x02, ctl_base + 0x10); hd = idecs_register(io_base + 0x10, ctl_base + 0x10, - link->irq.AssignedIRQ); + link->irq.AssignedIRQ, &hwif); if (hd >= 0) { io_base += 0x10; ctl_base += 0x10; break; } } - __set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(HZ/10); + msleep(100); } if (hd < 0) { @@ -362,6 +367,7 @@ info->node.major = ide_major[hd]; info->node.minor = 0; info->hd = hd; + info->hwif = hwif; link->dev = &info->node; printk(KERN_INFO "ide-cs: %s: Vcc = %d.%d, Vpp = %d.%d\n", info->node.dev_name, link->conf.Vcc / 10, link->conf.Vcc % 10, @@ -398,9 +404,11 @@ DEBUG(0, "ide_release(0x%p)\n", link); if (info->ndev) { - /* FIXME: if this fails we need to queue the cleanup somehow - -- need to investigate the required PCMCIA magic */ - ide_unregister(info->hd); + /* Wait for the interface to cease to be busy */ + while(ide_unregister_hwif(info->hwif) < 0) { + removed_hwif_iops(info->hwif); + msleep(1000); + } } info->ndev = 0; link->dev = NULL; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/pci/alim15x3.c linux-2.6.11/drivers/ide/pci/alim15x3.c --- linux.vanilla-2.6.11/drivers/ide/pci/alim15x3.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/pci/alim15x3.c 2005-03-06 14:49:06.000000000 +0000 @@ -775,7 +775,7 @@ * M1543C or newer for DMAing */ hwif->ide_dma_check = &ali15x3_config_drive_for_dma; - hwif->dma_setup = &ali15x3_dma_setup; + hwif->ide_dma_setup = &ali15x3_dma_setup; if (!noautodma) hwif->autodma = 1; if (!(hwif->udma_four)) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/pci/cs5520.c linux-2.6.11/drivers/ide/pci/cs5520.c --- linux.vanilla-2.6.11/drivers/ide/pci/cs5520.c 2005-03-05 15:15:06.000000000 +0000 +++ linux-2.6.11/drivers/ide/pci/cs5520.c 2005-03-06 15:16:06.000000000 +0000 @@ -158,10 +158,11 @@ * DMA channel */ -static int cs5520_dma_on(ide_drive_t *drive) +static int cs5520_dma_setup(ide_drive_t *drive) { - drive->vdma = 1; - return 0; + /* If DMA setup works then VDMA on */ + drive->vdma = ide_dma_setup(drive) ? 1: 0; + return drive->vdma; } static void __devinit init_hwif_cs5520(ide_hwif_t *hwif) @@ -169,7 +170,7 @@ hwif->tuneproc = &cs5520_tune_drive; hwif->speedproc = &cs5520_tune_chipset; hwif->ide_dma_check = &cs5520_config_drive_xfer_rate; - hwif->ide_dma_on = &cs5520_dma_on; + hwif->ide_dma_setup = &cs5520_dma_setup; if(!noautodma) hwif->autodma = 1; @@ -224,7 +225,7 @@ if(pci_enable_device_bars(dev, 1<<2)) { printk(KERN_WARNING "%s: Unable to enable 55x0.\n", d->name); - return 1; + return -EBUSY; } pci_set_master(dev); if (pci_set_dma_mask(dev, 0xFFFFFFFF)) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/pci/delkin_cb.c linux-2.6.11/drivers/ide/pci/delkin_cb.c --- linux.vanilla-2.6.11/drivers/ide/pci/delkin_cb.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.11/drivers/ide/pci/delkin_cb.c 2005-03-06 14:49:21.000000000 +0000 @@ -0,0 +1,140 @@ +/* + * linux/drivers/ide/pci/delkin_cb.c + * + * Created 20 Oct 2004 by Mark Lord + * + * Basic support for Delkin/ASKA/Workbit Cardbus CompactFlash adapter + * + * Modeled after the 16-bit PCMCIA driver: ide-cs.c + * + * This is slightly peculiar, in that it is a PCI driver, + * but is NOT an IDE PCI driver -- the IDE layer does not directly + * support hot insertion/removal of PCI interfaces, so this driver + * is unable to use the IDE PCI interfaces. Instead, it uses the + * same interfaces as the ide-cs (PCMCIA) driver uses. + * On the plus side, the driver is also smaller/simpler this way. + * + * 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. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * No chip documentation has yet been found, + * so these configuration values were pulled from + * a running Win98 system using "debug". + * This gives around 3MByte/second read performance, + * which is about 2/3 of what the chip is capable of. + * + * There is also a 4KByte mmio region on the card, + * but its purpose has yet to be reverse-engineered. + */ +static const u8 setup[] = { + 0x00, 0x05, 0xbe, 0x01, 0x20, 0x8f, 0x00, 0x00, + 0xa4, 0x1f, 0xb3, 0x1b, 0x00, 0x00, 0x00, 0x80, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa4, 0x83, 0x02, 0x13, +}; + +static int __devinit +delkin_cb_probe (struct pci_dev *dev, const struct pci_device_id *id) +{ + unsigned long base; + hw_regs_t hw; + ide_hwif_t *hwif = NULL; + ide_drive_t *drive; + int i, rc; + + rc = pci_enable_device(dev); + if (rc) { + printk(KERN_ERR "delkin_cb: pci_enable_device failed (%d)\n", rc); + return rc; + } + rc = pci_request_regions(dev, "delkin_cb"); + if (rc) { + printk(KERN_ERR "delkin_cb: pci_request_regions failed (%d)\n", rc); + pci_disable_device(dev); + return rc; + } + base = pci_resource_start(dev, 0); + outb(0x02, base + 0x1e); /* set nIEN to block interrupts */ + inb(base + 0x17); /* read status to clear interrupts */ + for (i = 0; i < sizeof(setup); ++i) { + if (setup[i]) + outb(setup[i], base + i); + } + pci_release_regions(dev); /* IDE layer handles regions itself */ + + memset(&hw, 0, sizeof(hw)); + ide_std_init_ports(&hw, base + 0x10, base + 0x1e); + hw.irq = dev->irq; + hw.chipset = ide_pci; /* this enables IRQ sharing */ + + rc = ide_register_hw_with_fixup(&hw, &hwif, ide_undecoded_slave); + if (rc < 0) { + printk(KERN_ERR "delkin_cb: ide_register_hw failed (%d)\n", rc); + pci_disable_device(dev); + return -ENODEV; + } + pci_set_drvdata(dev, hwif); + hwif->pci_dev = dev; + drive = &hwif->drives[0]; + if (drive->present) { + drive->io_32bit = 1; + drive->unmask = 1; + } + return 0; +} + +static void +delkin_cb_remove (struct pci_dev *dev) +{ + ide_hwif_t *hwif = pci_get_drvdata(dev); + + if (hwif) + ide_unregister_hwif(hwif); + pci_disable_device(dev); +} + +static struct pci_device_id delkin_cb_pci_tbl[] __devinitdata = { + { PCI_VENDOR_ID_WORKBIT, PCI_DEVICE_ID_WORKBIT_CB, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { 0, }, +}; +MODULE_DEVICE_TABLE(pci, delkin_cb_pci_tbl); + +static struct pci_driver driver = { + .name = "Delkin/ASKA/Workbit Cardbus IDE", + .id_table = delkin_cb_pci_tbl, + .probe = delkin_cb_probe, + .remove = delkin_cb_remove, +}; + +static int +delkin_cb_init (void) +{ + return pci_module_init(&driver); +} + +static void +delkin_cb_exit (void) +{ + pci_unregister_driver(&driver); +} + +module_init(delkin_cb_init); +module_exit(delkin_cb_exit); + +MODULE_AUTHOR("Mark Lord"); +MODULE_DESCRIPTION("Basic support for Delkin/ASKA/Workbit Cardbus IDE"); +MODULE_LICENSE("GPL"); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/pci/generic.c linux-2.6.11/drivers/ide/pci/generic.c --- linux.vanilla-2.6.11/drivers/ide/pci/generic.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/pci/generic.c 2005-03-06 18:16:59.000000000 +0000 @@ -39,6 +39,17 @@ #include +static int ide_generic_all; /* Set to claim all devices */ + +static int __init ide_generic_all_on(char *unused) +{ + ide_generic_all = 1; + printk(KERN_INFO "IDE generic will claim all unknown PCI IDE storage controllers.\n"); + return 1; +} + +__setup("all-generic-ide", ide_generic_all_on); + static void __devinit init_hwif_generic (ide_hwif_t *hwif) { switch(hwif->pci_dev->device) { @@ -78,79 +89,85 @@ static ide_pci_device_t generic_chipsets[] __devinitdata = { { /* 0 */ + .name = "Unknown", + .init_hwif = init_hwif_generic, + .channels = 2, + .autodma = AUTODMA, + .bootable = ON_BOARD, + },{ /* 1 */ .name = "NS87410", .init_hwif = init_hwif_generic, .channels = 2, .autodma = AUTODMA, .enablebits = {{0x43,0x08,0x08}, {0x47,0x08,0x08}}, .bootable = ON_BOARD, - },{ /* 1 */ + },{ /* 2 */ .name = "SAMURAI", .init_hwif = init_hwif_generic, .channels = 2, .autodma = AUTODMA, .bootable = ON_BOARD, - },{ /* 2 */ + },{ /* 3 */ .name = "HT6565", .init_hwif = init_hwif_generic, .channels = 2, .autodma = AUTODMA, .bootable = ON_BOARD, - },{ /* 3 */ + },{ /* 4 */ .name = "UM8673F", .init_hwif = init_hwif_generic, .channels = 2, .autodma = NODMA, .bootable = ON_BOARD, - },{ /* 4 */ + },{ /* 5 */ .name = "UM8886A", .init_hwif = init_hwif_generic, .channels = 2, .autodma = NODMA, .bootable = ON_BOARD, - },{ /* 5 */ + },{ /* 6 */ .name = "UM8886BF", .init_hwif = init_hwif_generic, .channels = 2, .autodma = NODMA, .bootable = ON_BOARD, - },{ /* 6 */ + },{ /* 7 */ .name = "HINT_IDE", .init_hwif = init_hwif_generic, .channels = 2, .autodma = AUTODMA, .bootable = ON_BOARD, - },{ /* 7 */ + },{ /* 8 */ .name = "VIA_IDE", .init_hwif = init_hwif_generic, .channels = 2, .autodma = NOAUTODMA, .bootable = ON_BOARD, - },{ /* 8 */ + },{ /* 9 */ .name = "OPTI621V", .init_hwif = init_hwif_generic, .channels = 2, .autodma = NOAUTODMA, .bootable = ON_BOARD, - },{ /* 9 */ + },{ /* 10 */ .name = "VIA8237SATA", .init_hwif = init_hwif_generic, .channels = 2, .autodma = AUTODMA, .bootable = OFF_BOARD, - },{ /* 10 */ + },{ /* 11 */ .name = "Piccolo0102", .init_hwif = init_hwif_generic, .channels = 2, .autodma = NOAUTODMA, .bootable = ON_BOARD, - },{ /* 11 */ + },{ /* 12 */ .name = "Piccolo0103", .init_hwif = init_hwif_generic, .channels = 2, .autodma = NOAUTODMA, .bootable = ON_BOARD, - },{ /* 12 */ + },{ /* 13 */ .name = "Piccolo0105", .init_hwif = init_hwif_generic, .channels = 2, @@ -174,6 +191,10 @@ u16 command; int ret = -ENODEV; + /* Don't use the generic entry unless instructed to do so */ + if (id->driver_data == 0 && ide_generic_all == 0) + goto out; + if (dev->vendor == PCI_VENDOR_ID_UMC && dev->device == PCI_DEVICE_ID_UMC_UM8886A && (!(PCI_FUNC(dev->devfn) & 1))) @@ -194,22 +215,29 @@ return ret; } +static void __devexit generic_remove_one(struct pci_dev *dev) +{ + ide_pci_remove_hwifs(dev); +} + static struct pci_device_id generic_pci_tbl[] = { - { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, - { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, - { PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, - { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, - { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, - { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5}, - { PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6}, - { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7}, - { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8}, + { PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_87410, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, + { PCI_VENDOR_ID_PCTECH, PCI_DEVICE_ID_PCTECH_SAMURAI_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, + { PCI_VENDOR_ID_HOLTEK, PCI_DEVICE_ID_HOLTEK_6565, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, + { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8673F, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, + { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5}, + { PCI_VENDOR_ID_UMC, PCI_DEVICE_ID_UMC_UM8886BF, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 6}, + { PCI_VENDOR_ID_HINT, PCI_DEVICE_ID_HINT_VXPROII_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 7}, + { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C561, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8}, + { PCI_VENDOR_ID_OPTI, PCI_DEVICE_ID_OPTI_82C558, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9}, #ifdef CONFIG_BLK_DEV_IDE_SATA - { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 9}, + { PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8237_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10}, #endif - { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 10}, - { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11}, - { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12}, + { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 11}, + { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 12}, + { PCI_VENDOR_ID_TOSHIBA,PCI_DEVICE_ID_TOSHIBA_PICCOLO_2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 13}, + /* Must come last. If you add entries adjust this table appropriately and the init_one code */ + { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE << 8, 0xFFFFFF00UL, 0}, { 0, }, }; MODULE_DEVICE_TABLE(pci, generic_pci_tbl); @@ -218,6 +246,7 @@ .name = "PCI_IDE", .id_table = generic_pci_tbl, .probe = generic_init_one, + .remove = generic_remove_one, }; static int generic_ide_init(void) @@ -227,6 +256,13 @@ module_init(generic_ide_init); +static void generic_ide_exit(void) +{ + return ide_pci_unregister_driver(&driver); +} + +module_exit(generic_ide_exit); + MODULE_AUTHOR("Andre Hedrick"); MODULE_DESCRIPTION("PCI driver module for generic PCI IDE"); MODULE_LICENSE("GPL"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/pci/hpt366.c linux-2.6.11/drivers/ide/pci/hpt366.c --- linux.vanilla-2.6.11/drivers/ide/pci/hpt366.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/pci/hpt366.c 2005-03-06 17:38:20.000000000 +0000 @@ -10,6 +10,11 @@ * donation of an ABit BP6 mainboard, processor, and memory acellerated * development and support. * + * + * Highpoint have their own driver (source except for the raid part) + * available from http://www.highpoint-tech.com/hpt3xx-opensource-v131.tgz + * This may be useful to anyone wanting to work on the mainstream hpt IDE. + * * Note that final HPT370 support was done by force extraction of GPL. * * - add function for getting/setting power status of drive @@ -446,44 +451,29 @@ #define F_LOW_PCI_50 0x2d #define F_LOW_PCI_66 0x42 -/* FIXME: compare with driver's code before removing */ -#if 0 - if (hpt_minimum_revision(dev, 3)) { - u8 cbl; - cbl = inb(iobase + 0x7b); - outb(cbl | 1, iobase + 0x7b); - outb(cbl & ~1, iobase + 0x7b); - cbl = inb(iobase + 0x7a); - p += sprintf(p, "Cable: ATA-%d" - " ATA-%d\n", - (cbl & 0x02) ? 33 : 66, - (cbl & 0x01) ? 33 : 66); - p += sprintf(p, "\n"); - } - { - u8 c2, c3; - /* older revs don't have these registers mapped - * into io space */ - pci_read_config_byte(dev, 0x43, &c0); - pci_read_config_byte(dev, 0x47, &c1); - pci_read_config_byte(dev, 0x4b, &c2); - pci_read_config_byte(dev, 0x4f, &c3); - - p += sprintf(p, "Mode: %s %s" - " %s %s\n", - (c0 & 0x10) ? "UDMA" : (c0 & 0x20) ? "DMA " : - (c0 & 0x80) ? "PIO " : "off ", - (c1 & 0x10) ? "UDMA" : (c1 & 0x20) ? "DMA " : - (c1 & 0x80) ? "PIO " : "off ", - (c2 & 0x10) ? "UDMA" : (c2 & 0x20) ? "DMA " : - (c2 & 0x80) ? "PIO " : "off ", - (c3 & 0x10) ? "UDMA" : (c3 & 0x20) ? "DMA " : - (c3 & 0x80) ? "PIO " : "off "); - } - } -#endif +/* + * Hold all the highpoint quirks and revision information in one + * place. + */ + +struct hpt_info +{ + u8 max_mode; /* Speeds allowed */ + int revision; /* Chipset revision */ + int flags; /* Chipset properties */ +#define PLL_MODE 1 +#define IS_372N 2 + /* Speed table */ + struct chipset_bus_clock_list_entry *speed; +}; -static u32 hpt_revision (struct pci_dev *dev) +/* + * This wants fixing so that we do everything not by classrev + * (which breaks on the newest chips) but by creating an + * enumeration of chip variants and using that + */ + +static __devinit u32 hpt_revision (struct pci_dev *dev) { u32 class_rev; pci_read_config_dword(dev, PCI_CLASS_REVISION, &class_rev); @@ -507,37 +497,33 @@ return class_rev; } -static u32 hpt_minimum_revision (struct pci_dev *dev, int revision) -{ - unsigned int class_rev = hpt_revision(dev); - revision--; - return ((int) (class_rev > revision) ? 1 : 0); -} - static int check_in_drive_lists(ide_drive_t *drive, const char **list); static u8 hpt3xx_ratemask (ide_drive_t *drive) { - struct pci_dev *dev = HWIF(drive)->pci_dev; + ide_hwif_t *hwif = drive->hwif; + struct hpt_info *info = ide_get_hwifdata(hwif); u8 mode = 0; - if (hpt_minimum_revision(dev, 8)) { /* HPT374 */ + /* FIXME: TODO - move this to set info->mode once at boot */ + + if (info->revision >= 8) { /* HPT374 */ mode = (HPT374_ALLOW_ATA133_6) ? 4 : 3; - } else if (hpt_minimum_revision(dev, 7)) { /* HPT371 */ + } else if (info->revision >= 7) { /* HPT371 */ mode = (HPT371_ALLOW_ATA133_6) ? 4 : 3; - } else if (hpt_minimum_revision(dev, 6)) { /* HPT302 */ + } else if (info->revision >= 6) { /* HPT302 */ mode = (HPT302_ALLOW_ATA133_6) ? 4 : 3; - } else if (hpt_minimum_revision(dev, 5)) { /* HPT372 */ + } else if (info->revision >= 5) { /* HPT372 */ mode = (HPT372_ALLOW_ATA133_6) ? 4 : 3; - } else if (hpt_minimum_revision(dev, 4)) { /* HPT370A */ + } else if (info->revision >= 4) { /* HPT370A */ mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2; - } else if (hpt_minimum_revision(dev, 3)) { /* HPT370 */ + } else if (info->revision >= 3) { /* HPT370 */ mode = (HPT370_ALLOW_ATA100_5) ? 3 : 2; mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : mode; } else { /* HPT366 and HPT368 */ mode = (check_in_drive_lists(drive, bad_ata33)) ? 0 : 2; } - if (!eighty_ninty_three(drive) && (mode)) + if (!eighty_ninty_three(drive) && mode) mode = min(mode, (u8)1); return mode; } @@ -549,7 +535,8 @@ static u8 hpt3xx_ratefilter (ide_drive_t *drive, u8 speed) { - struct pci_dev *dev = HWIF(drive)->pci_dev; + ide_hwif_t *hwif = drive->hwif; + struct hpt_info *info = ide_get_hwifdata(hwif); u8 mode = hpt3xx_ratemask(drive); if (drive->media != ide_disk) @@ -561,7 +548,7 @@ break; case 0x03: speed = min(speed, (u8)XFER_UDMA_5); - if (hpt_minimum_revision(dev, 5)) + if (info->revision >= 5) break; if (check_in_drive_lists(drive, bad_ata100_5)) speed = min(speed, (u8)XFER_UDMA_4); @@ -571,7 +558,7 @@ /* * CHECK ME, Does this need to be set to 5 ?? */ - if (hpt_minimum_revision(dev, 3)) + if (info->revision >= 3) break; if ((check_in_drive_lists(drive, bad_ata66_4)) || (!(HPT366_ALLOW_ATA66_4))) @@ -585,7 +572,7 @@ /* * CHECK ME, Does this need to be set to 5 ?? */ - if (hpt_minimum_revision(dev, 3)) + if (info->revision >= 3) break; if (check_in_drive_lists(drive, bad_ata33)) speed = min(speed, (u8)XFER_MW_DMA_2); @@ -624,11 +611,12 @@ static int hpt36x_tune_chipset(ide_drive_t *drive, u8 xferspeed) { - struct pci_dev *dev = HWIF(drive)->pci_dev; + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = hwif->pci_dev; + struct hpt_info *info = ide_get_hwifdata(hwif); u8 speed = hpt3xx_ratefilter(drive, xferspeed); -// u8 speed = ide_rate_filter(hpt3xx_ratemask(drive), xferspeed); u8 regtime = (drive->select.b.unit & 0x01) ? 0x44 : 0x40; - u8 regfast = (HWIF(drive)->channel) ? 0x55 : 0x51; + u8 regfast = (hwif->channel) ? 0x55 : 0x51; u8 drive_fast = 0; u32 reg1 = 0, reg2 = 0; @@ -636,16 +624,11 @@ * Disable the "fast interrupt" prediction. */ pci_read_config_byte(dev, regfast, &drive_fast); -#if 0 - if (drive_fast & 0x02) - pci_write_config_byte(dev, regfast, drive_fast & ~0x20); -#else if (drive_fast & 0x80) pci_write_config_byte(dev, regfast, drive_fast & ~0x80); -#endif - reg2 = pci_bus_clock_list(speed, - (struct chipset_bus_clock_list_entry *) pci_get_drvdata(dev)); + reg2 = pci_bus_clock_list(speed, info->speed); + /* * Disable on-chip PIO FIFO/buffer * (to avoid problems handling I/O errors later) @@ -665,10 +648,11 @@ static int hpt370_tune_chipset(ide_drive_t *drive, u8 xferspeed) { - struct pci_dev *dev = HWIF(drive)->pci_dev; + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = hwif->pci_dev; + struct hpt_info *info = ide_get_hwifdata(hwif); u8 speed = hpt3xx_ratefilter(drive, xferspeed); -// u8 speed = ide_rate_filter(hpt3xx_ratemask(drive), xferspeed); - u8 regfast = (HWIF(drive)->channel) ? 0x55 : 0x51; + u8 regfast = (drive->hwif->channel) ? 0x55 : 0x51; u8 drive_pci = 0x40 + (drive->dn * 4); u8 new_fast = 0, drive_fast = 0; u32 list_conf = 0, drive_conf = 0; @@ -693,17 +677,13 @@ if (new_fast != drive_fast) pci_write_config_byte(dev, regfast, new_fast); - list_conf = pci_bus_clock_list(speed, - (struct chipset_bus_clock_list_entry *) - pci_get_drvdata(dev)); + list_conf = pci_bus_clock_list(speed, info->speed); pci_read_config_dword(dev, drive_pci, &drive_conf); list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask); - if (speed < XFER_MW_DMA_0) { + if (speed < XFER_MW_DMA_0) list_conf &= ~0x80000000; /* Disable on-chip PIO FIFO/buffer */ - } - pci_write_config_dword(dev, drive_pci, list_conf); return ide_config_drive_speed(drive, speed); @@ -711,10 +691,11 @@ static int hpt372_tune_chipset(ide_drive_t *drive, u8 xferspeed) { - struct pci_dev *dev = HWIF(drive)->pci_dev; + ide_hwif_t *hwif = drive->hwif; + struct pci_dev *dev = hwif->pci_dev; + struct hpt_info *info = ide_get_hwifdata(hwif); u8 speed = hpt3xx_ratefilter(drive, xferspeed); -// u8 speed = ide_rate_filter(hpt3xx_ratemask(drive), xferspeed); - u8 regfast = (HWIF(drive)->channel) ? 0x55 : 0x51; + u8 regfast = (drive->hwif->channel) ? 0x55 : 0x51; u8 drive_fast = 0, drive_pci = 0x40 + (drive->dn * 4); u32 list_conf = 0, drive_conf = 0; u32 conf_mask = (speed >= XFER_MW_DMA_0) ? 0xc0000000 : 0x30070000; @@ -726,10 +707,8 @@ pci_read_config_byte(dev, regfast, &drive_fast); drive_fast &= ~0x07; pci_write_config_byte(dev, regfast, drive_fast); - - list_conf = pci_bus_clock_list(speed, - (struct chipset_bus_clock_list_entry *) - pci_get_drvdata(dev)); + + list_conf = pci_bus_clock_list(speed, info->speed); pci_read_config_dword(dev, drive_pci, &drive_conf); list_conf = (list_conf & ~conf_mask) | (drive_conf & conf_mask); if (speed < XFER_MW_DMA_0) @@ -741,19 +720,14 @@ static int hpt3xx_tune_chipset (ide_drive_t *drive, u8 speed) { - struct pci_dev *dev = HWIF(drive)->pci_dev; + ide_hwif_t *hwif = drive->hwif; + struct hpt_info *info = ide_get_hwifdata(hwif); - if (hpt_minimum_revision(dev, 8)) + if (info->revision >= 8) return hpt372_tune_chipset(drive, speed); /* not a typo */ -#if 0 - else if (hpt_minimum_revision(dev, 7)) - hpt371_tune_chipset(drive, speed); - else if (hpt_minimum_revision(dev, 6)) - hpt302_tune_chipset(drive, speed); -#endif - else if (hpt_minimum_revision(dev, 5)) + else if (info->revision >= 5) return hpt372_tune_chipset(drive, speed); - else if (hpt_minimum_revision(dev, 3)) + else if (info->revision >= 3) return hpt370_tune_chipset(drive, speed); else /* hpt368: hpt_minimum_revision(dev, 2) */ return hpt36x_tune_chipset(drive, speed); @@ -779,8 +753,14 @@ static int config_chipset_for_dma (ide_drive_t *drive) { u8 speed = ide_dma_speed(drive, hpt3xx_ratemask(drive)); - - if (!(speed)) + ide_hwif_t *hwif = drive->hwif; + struct hpt_info *info = ide_get_hwifdata(hwif); + + if (!speed) + return 0; + + /* If we don't have any timings we can't do a lot */ + if (info->speed == NULL) return 0; (void) hpt3xx_tune_chipset(drive, speed); @@ -794,7 +774,7 @@ static void hpt3xx_intrproc (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; if (drive->quirk_list) return; @@ -804,24 +784,26 @@ static void hpt3xx_maskproc (ide_drive_t *drive, int mask) { - struct pci_dev *dev = HWIF(drive)->pci_dev; + ide_hwif_t *hwif = drive->hwif; + struct hpt_info *info = ide_get_hwifdata(hwif); + struct pci_dev *dev = hwif->pci_dev; if (drive->quirk_list) { - if (hpt_minimum_revision(dev,3)) { + if (info->revision >= 3) { u8 reg5a = 0; pci_read_config_byte(dev, 0x5a, ®5a); if (((reg5a & 0x10) >> 4) != mask) pci_write_config_byte(dev, 0x5a, mask ? (reg5a | 0x10) : (reg5a & ~0x10)); } else { if (mask) { - disable_irq(HWIF(drive)->irq); + disable_irq(hwif->irq); } else { - enable_irq(HWIF(drive)->irq); + enable_irq(hwif->irq); } } } else { if (IDE_CONTROL_REG) - HWIF(drive)->OUTB(mask ? (drive->ctl | 2) : + hwif->OUTB(mask ? (drive->ctl | 2) : (drive->ctl & ~2), IDE_CONTROL_REG); } @@ -829,12 +811,12 @@ static int hpt366_config_drive_xfer_rate (ide_drive_t *drive) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct hd_driveid *id = drive->id; drive->init_speed = 0; - if (id && (id->capability & 1) && drive->autodma) { + if ((id->capability & 1) && drive->autodma) { if (ide_use_dma(drive)) { if (config_chipset_for_dma(drive)) @@ -868,15 +850,6 @@ drive->name, __FUNCTION__, reg50h, reg52h, reg5ah); if (reg5ah & 0x10) pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10); -#if 0 - /* how about we flush and reset, mmmkay? */ - pci_write_config_byte(dev, 0x51, 0x1F); - /* fall through to a reset */ - case dma_start: - case ide_dma_end: - /* reset the chips state over and over.. */ - pci_write_config_byte(dev, 0x51, 0x13); -#endif return __ide_dma_lostirq(drive); } @@ -919,7 +892,7 @@ u8 dma_stat = 0, dma_cmd = 0; pci_read_config_byte(HWIF(drive)->pci_dev, reginfo, &bfifo); - printk("%s: %d bytes in FIFO\n", drive->name, bfifo); + printk(KERN_DEBUG "%s: %d bytes in FIFO\n", drive->name, bfifo); hpt370_clear_engine(drive); /* get dma command mode */ dma_cmd = hwif->INB(hwif->dma_command); @@ -1047,15 +1020,6 @@ static void hpt3xx_reset (ide_drive_t *drive) { -#if 0 - unsigned long high_16 = pci_resource_start(HWIF(drive)->pci_dev, 4); - u8 reset = (HWIF(drive)->channel) ? 0x80 : 0x40; - u8 reg59h = 0; - - pci_read_config_byte(HWIF(drive)->pci_dev, 0x59, ®59h); - pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h|reset); - pci_write_config_byte(HWIF(drive)->pci_dev, 0x59, reg59h); -#endif } static int hpt3xx_tristate (ide_drive_t * drive, int state) @@ -1065,8 +1029,6 @@ u8 reg59h = 0, reset = (hwif->channel) ? 0x80 : 0x40; u8 regXXh = 0, state_reg= (hwif->channel) ? 0x57 : 0x53; -// hwif->bus_state = state; - pci_read_config_byte(dev, 0x59, ®59h); pci_read_config_byte(dev, state_reg, ®XXh); @@ -1093,7 +1055,7 @@ #define TRISTATE_BIT 0x8000 static int hpt370_busproc(ide_drive_t * drive, int state) { - ide_hwif_t *hwif = HWIF(drive); + ide_hwif_t *hwif = drive->hwif; struct pci_dev *dev = hwif->pci_dev; u8 tristate = 0, resetmask = 0, bus_reg = 0; u16 tri_reg; @@ -1148,33 +1110,44 @@ return 0; } -static int __devinit init_hpt37x(struct pci_dev *dev) +static void __devinit hpt366_clocking(ide_hwif_t *hwif) { + u32 reg1 = 0; + struct hpt_info *info = ide_get_hwifdata(hwif); + + pci_read_config_dword(hwif->pci_dev, 0x40, ®1); + + /* detect bus speed by looking at control reg timing: */ + switch((reg1 >> 8) & 7) { + case 5: + info->speed = forty_base_hpt366; + break; + case 9: + info->speed = twenty_five_base_hpt366; + break; + case 7: + default: + info->speed = thirty_three_base_hpt366; + break; + } +} + +static void __devinit hpt37x_clocking(ide_hwif_t *hwif) +{ + struct hpt_info *info = ide_get_hwifdata(hwif); + struct pci_device *dev = hwif->pci_dev; int adjust, i; u16 freq; u32 pll; u8 reg5bh; - u8 reg5ah = 0; - unsigned long dmabase = pci_resource_start(dev, 4); - u8 did, rid; - int is_372n = 0; - - pci_read_config_byte(dev, 0x5a, ®5ah); - /* interrupt force enable */ - pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10)); - - if(dmabase) - { - did = inb(dmabase + 0x22); - rid = inb(dmabase + 0x28); - if((did == 4 && rid == 6) || (did == 5 && rid > 1)) - is_372n = 1; - } - /* * default to pci clock. make sure MA15/16 are set to output - * to prevent drives having problems with 40-pin cables. + * to prevent drives having problems with 40-pin cables. Needed + * for some drives such as IBM-DTLA which will not enter ready + * state on reset when PDIAG is a input. + * + * ToDo: should we set 0x21 when using PLL mode ? */ pci_write_config_byte(dev, 0x5b, 0x23); @@ -1197,9 +1170,7 @@ * Currently we always set up the PLL for the 372N */ - pci_set_drvdata(dev, NULL); - - if(is_372n) + if(info->flags & IS_372N) { printk(KERN_INFO "hpt: HPT372N detected, using 372N timing.\n"); if(freq < 0x55) @@ -1227,39 +1198,38 @@ pll = F_LOW_PCI_66; if (pll == F_LOW_PCI_33) { - if (hpt_minimum_revision(dev,8)) - pci_set_drvdata(dev, (void *) thirty_three_base_hpt374); - else if (hpt_minimum_revision(dev,5)) - pci_set_drvdata(dev, (void *) thirty_three_base_hpt372); - else if (hpt_minimum_revision(dev,4)) - pci_set_drvdata(dev, (void *) thirty_three_base_hpt370a); + if (info->revision >= 8) + info->speed = thirty_three_base_hpt374; + else if (info->revision >= 5) + info->speed = thirty_three_base_hpt372; + else if (info->revision >= 4) + info->speed = thirty_three_base_hpt370a; else - pci_set_drvdata(dev, (void *) thirty_three_base_hpt370); - printk("HPT37X: using 33MHz PCI clock\n"); + info->speed = thirty_three_base_hpt370; + printk(KERN_DEBUG "HPT37X: using 33MHz PCI clock\n"); } else if (pll == F_LOW_PCI_40) { /* Unsupported */ } else if (pll == F_LOW_PCI_50) { - if (hpt_minimum_revision(dev,8)) - pci_set_drvdata(dev, (void *) fifty_base_hpt370a); - else if (hpt_minimum_revision(dev,5)) - pci_set_drvdata(dev, (void *) fifty_base_hpt372); - else if (hpt_minimum_revision(dev,4)) - pci_set_drvdata(dev, (void *) fifty_base_hpt370a); + if (info->revision >= 8) + info->speed = fifty_base_hpt370a; + else if (info->revision >= 5) + info->speed = fifty_base_hpt372; + else if (info->revision >= 4) + info->speed = fifty_base_hpt370a; else - pci_set_drvdata(dev, (void *) fifty_base_hpt370a); - printk("HPT37X: using 50MHz PCI clock\n"); + info->speed = fifty_base_hpt370a; + printk(KERN_DEBUG "HPT37X: using 50MHz PCI clock\n"); } else { - if (hpt_minimum_revision(dev,8)) - { + if (info->revision >= 8) { printk(KERN_ERR "HPT37x: 66MHz timings are not supported.\n"); } - else if (hpt_minimum_revision(dev,5)) - pci_set_drvdata(dev, (void *) sixty_six_base_hpt372); - else if (hpt_minimum_revision(dev,4)) - pci_set_drvdata(dev, (void *) sixty_six_base_hpt370a); + else if (info->revision >= 5) + info->speed = sixty_six_base_hpt372; + else if (info->revision >= 4) + info->speed = sixty_six_base_hpt370a; else - pci_set_drvdata(dev, (void *) sixty_six_base_hpt370); - printk("HPT37X: using 66MHz PCI clock\n"); + info->speed = sixty_six_base_hpt370; + printk(KERN_DEBUG "HPT37X: using 66MHz PCI clock\n"); } } @@ -1269,11 +1239,19 @@ * result in slow reads when using a 33MHz PCI clock. we also * don't like to use the PLL because it will cause glitches * on PRST/SRST when the HPT state engine gets reset. + * + * ToDo: Use 66MHz PLL when ATA133 devices are present on a + * 372 device so we can get ATA133 support */ - if (pci_get_drvdata(dev)) + if (info->speed) goto init_hpt37X_done; + + info->flags |= PLL_MODE; /* + * FIXME: make this work correctly, esp with 372N as per + * reference driver code. + * * adjust PLL based upon PCI clock, enable it, and wait for * stabilization. */ @@ -1298,14 +1276,14 @@ pci_write_config_dword(dev, 0x5c, pll & ~0x100); pci_write_config_byte(dev, 0x5b, 0x21); - if (hpt_minimum_revision(dev,8)) - pci_set_drvdata(dev, (void *) fifty_base_hpt370a); - else if (hpt_minimum_revision(dev,5)) - pci_set_drvdata(dev, (void *) fifty_base_hpt372); - else if (hpt_minimum_revision(dev,4)) - pci_set_drvdata(dev, (void *) fifty_base_hpt370a); + if (info->revision >= 8) + info->speed = fifty_base_hpt370a; + else if (info->revision >= 5) + info->speed = fifty_base_hpt372; + else if (info->revision >= 4) + info->speed = fifty_base_hpt370a; else - pci_set_drvdata(dev, (void *) fifty_base_hpt370a); + info->speed = fifty_base_hpt370a; printk("HPT37X: using 50MHz internal PLL\n"); goto init_hpt37X_done; } @@ -1318,10 +1296,22 @@ } init_hpt37X_done: + if (!info->speed) + printk(KERN_ERR "HPT37X%s: unknown bus timing [%d %d].\n", + (info->flags & IS_372N)?"N":"", pll, freq); /* reset state engine */ pci_write_config_byte(dev, 0x50, 0x37); pci_write_config_byte(dev, 0x54, 0x37); udelay(100); +} + +static int __devinit init_hpt37x(struct pci_dev *dev) +{ + u8 reg5ah; + + pci_read_config_byte(dev, 0x5a, ®5ah); + /* interrupt force enable */ + pci_write_config_byte(dev, 0x5a, (reg5ah & ~0x10)); return 0; } @@ -1338,59 +1328,27 @@ pci_write_config_byte(dev, 0x51, drive_fast & ~0x80); pci_read_config_dword(dev, 0x40, ®1); - /* detect bus speed by looking at control reg timing: */ - switch((reg1 >> 8) & 7) { - case 5: - pci_set_drvdata(dev, (void *) forty_base_hpt366); - break; - case 9: - pci_set_drvdata(dev, (void *) twenty_five_base_hpt366); - break; - case 7: - default: - pci_set_drvdata(dev, (void *) thirty_three_base_hpt366); - break; - } - - if (!pci_get_drvdata(dev)) - { - printk(KERN_ERR "hpt366: unknown bus timing.\n"); - pci_set_drvdata(dev, NULL); - } return 0; } static unsigned int __devinit init_chipset_hpt366(struct pci_dev *dev, const char *name) { int ret = 0; - u8 test = 0; - + /* FIXME: Not portable */ if (dev->resource[PCI_ROM_RESOURCE].start) pci_write_config_byte(dev, PCI_ROM_ADDRESS, dev->resource[PCI_ROM_RESOURCE].start | PCI_ROM_ADDRESS_ENABLE); - pci_read_config_byte(dev, PCI_CACHE_LINE_SIZE, &test); - if (test != (L1_CACHE_BYTES / 4)) - pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, - (L1_CACHE_BYTES / 4)); - - pci_read_config_byte(dev, PCI_LATENCY_TIMER, &test); - if (test != 0x78) - pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78); - - pci_read_config_byte(dev, PCI_MIN_GNT, &test); - if (test != 0x08) - pci_write_config_byte(dev, PCI_MIN_GNT, 0x08); - - pci_read_config_byte(dev, PCI_MAX_LAT, &test); - if (test != 0x08) - pci_write_config_byte(dev, PCI_MAX_LAT, 0x08); + pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, (L1_CACHE_BYTES / 4)); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x78); + pci_write_config_byte(dev, PCI_MIN_GNT, 0x08); + pci_write_config_byte(dev, PCI_MAX_LAT, 0x08); - if (hpt_minimum_revision(dev, 3)) { + if (hpt_revision(dev) >= 3) ret = init_hpt37x(dev); - } else { - ret =init_hpt366(dev); - } + else + ret = init_hpt366(dev); + if (ret) return ret; @@ -1400,27 +1358,16 @@ static void __devinit init_hwif_hpt366(ide_hwif_t *hwif) { struct pci_dev *dev = hwif->pci_dev; + struct hpt_info *info = ide_get_hwifdata(hwif); u8 ata66 = 0, regmask = (hwif->channel) ? 0x01 : 0x02; - u8 did, rid; - unsigned long dmabase = hwif->dma_base; - int is_372n = 0; - if(dmabase) - { - did = inb(dmabase + 0x22); - rid = inb(dmabase + 0x28); - - if((did == 4 && rid == 6) || (did == 5 && rid > 1)) - is_372n = 1; - } - hwif->tuneproc = &hpt3xx_tune_drive; hwif->speedproc = &hpt3xx_tune_chipset; hwif->quirkproc = &hpt3xx_quirkproc; hwif->intrproc = &hpt3xx_intrproc; hwif->maskproc = &hpt3xx_maskproc; - if(is_372n) + if(info->flags & IS_372N) hwif->rw_disk = &hpt372n_rw_disk; /* @@ -1428,7 +1375,7 @@ * address lines to access an external eeprom. To read valid * cable detect state the pins must be enabled as inputs. */ - if (hpt_minimum_revision(dev, 8) && PCI_FUNC(dev->devfn) & 1) { + if (info->revision >= 8 && (PCI_FUNC(dev->devfn) & 1)) { /* * HPT374 PCI function 1 * - set bit 15 of reg 0x52 to enable TCBLID as input @@ -1443,7 +1390,7 @@ pci_read_config_byte(dev, 0x5a, &ata66); pci_write_config_word(dev, 0x52, mcr3); pci_write_config_word(dev, 0x56, mcr6); - } else if (hpt_minimum_revision(dev, 3)) { + } else if (info->revision >= 3) { /* * HPT370/372 and 374 pcifn 0 * - clear bit 0 of 0x5b to enable P/SCBLID as inputs @@ -1470,7 +1417,7 @@ hwif->serialized = hwif->mate->serialized = 1; #endif - if (hpt_minimum_revision(dev,3)) { + if (info->revision >= 3) { u8 reg5ah = 0; pci_write_config_byte(dev, 0x5a, reg5ah & ~0x10); /* @@ -1480,8 +1427,7 @@ */ hwif->resetproc = &hpt3xx_reset; hwif->busproc = &hpt370_busproc; -// hwif->drives[0].autotune = hwif->drives[1].autotune = 1; - } else if (hpt_minimum_revision(dev,2)) { + } else if (info->revision >= 2) { hwif->resetproc = &hpt3xx_reset; hwif->busproc = &hpt3xx_tristate; } else { @@ -1502,18 +1448,18 @@ hwif->udma_four = ((ata66 & regmask) ? 0 : 1); hwif->ide_dma_check = &hpt366_config_drive_xfer_rate; - if (hpt_minimum_revision(dev,8)) { + if (info->revision >= 8) { hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq; hwif->ide_dma_end = &hpt374_ide_dma_end; - } else if (hpt_minimum_revision(dev,5)) { + } else if (info->revision >= 5) { hwif->ide_dma_test_irq = &hpt374_ide_dma_test_irq; hwif->ide_dma_end = &hpt374_ide_dma_end; - } else if (hpt_minimum_revision(dev,3)) { - hwif->dma_start = &hpt370_ide_dma_start; + } else if (info->revision >= 3) { + hwif->ide_dma_start = &hpt370_ide_dma_start; hwif->ide_dma_end = &hpt370_ide_dma_end; hwif->ide_dma_timeout = &hpt370_ide_dma_timeout; hwif->ide_dma_lostirq = &hpt370_ide_dma_lostirq; - } else if (hpt_minimum_revision(dev,2)) + } else if (info->revision >= 2) hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq; else hwif->ide_dma_lostirq = &hpt366_ide_dma_lostirq; @@ -1526,6 +1472,7 @@ static void __devinit init_dma_hpt366(ide_hwif_t *hwif, unsigned long dmabase) { + struct hpt_info *info = ide_get_hwifdata(hwif); u8 masterdma = 0, slavedma = 0; u8 dma_new = 0, dma_old = 0; u8 primary = hwif->channel ? 0x4b : 0x43; @@ -1535,8 +1482,7 @@ if (!dmabase) return; - if(pci_get_drvdata(hwif->pci_dev) == NULL) - { + if(info->speed == NULL) { printk(KERN_WARNING "hpt: no known IDE timings, disabling DMA.\n"); return; } @@ -1559,6 +1505,40 @@ ide_setup_dma(hwif, dmabase, 8); } +/* + * We "borrow" this hook in order to set the data structures + * up early enough before dma or init_hwif calls are made. + */ + +static void __devinit init_iops_hpt366(ide_hwif_t *hwif) +{ + struct hpt_info *info = kmalloc(sizeof(struct hpt_info), GFP_KERNEL); + unsigned long dmabase = pci_resource_start(hwif->pci_dev, 4); + u8 did, rid; + + if(info == NULL) { + printk(KERN_WARNING "hpt366: out of memory.\n"); + return; + } + memset(info, 0, sizeof(struct hpt_info)); + ide_set_hwifdata(hwif, info); + + if(dmabase) { + did = inb(dmabase + 0x22); + rid = inb(dmabase + 0x28); + + if((did == 4 && rid == 6) || (did == 5 && rid > 1)) + info->flags |= IS_372N; + } + + info->revision = hpt_revision(hwif->pci_dev); + + if (info->revision >= 3) + hpt37x_clocking(hwif); + else + hpt366_clocking(hwif); +} + static int __devinit init_setup_hpt374(struct pci_dev *dev, ide_pci_device_t *d) { struct pci_dev *findev = NULL; @@ -1646,6 +1626,7 @@ .name = "HPT366", .init_setup = init_setup_hpt366, .init_chipset = init_chipset_hpt366, + .init_iops = init_iops_hpt366, .init_hwif = init_hwif_hpt366, .init_dma = init_dma_hpt366, .channels = 2, @@ -1656,6 +1637,7 @@ .name = "HPT372A", .init_setup = init_setup_hpt37x, .init_chipset = init_chipset_hpt366, + .init_iops = init_iops_hpt366, .init_hwif = init_hwif_hpt366, .init_dma = init_dma_hpt366, .channels = 2, @@ -1665,6 +1647,7 @@ .name = "HPT302", .init_setup = init_setup_hpt37x, .init_chipset = init_chipset_hpt366, + .init_iops = init_iops_hpt366, .init_hwif = init_hwif_hpt366, .init_dma = init_dma_hpt366, .channels = 2, @@ -1674,6 +1657,7 @@ .name = "HPT371", .init_setup = init_setup_hpt37x, .init_chipset = init_chipset_hpt366, + .init_iops = init_iops_hpt366, .init_hwif = init_hwif_hpt366, .init_dma = init_dma_hpt366, .channels = 2, @@ -1683,6 +1667,7 @@ .name = "HPT374", .init_setup = init_setup_hpt374, .init_chipset = init_chipset_hpt366, + .init_iops = init_iops_hpt366, .init_hwif = init_hwif_hpt366, .init_dma = init_dma_hpt366, .channels = 2, /* 4 */ @@ -1692,6 +1677,7 @@ .name = "HPT372N", .init_setup = init_setup_hpt37x, .init_chipset = init_chipset_hpt366, + .init_iops = init_iops_hpt366, .init_hwif = init_hwif_hpt366, .init_dma = init_dma_hpt366, .channels = 2, /* 4 */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/pci/it821x.c linux-2.6.11/drivers/ide/pci/it821x.c --- linux.vanilla-2.6.11/drivers/ide/pci/it821x.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.11/drivers/ide/pci/it821x.c 2005-03-06 14:53:31.000000000 +0000 @@ -0,0 +1,812 @@ + +/* + * linux/drivers/ide/pci/it821x.c Version 0.09 December 2004 + * + * Copyright (C) 2004 Red Hat + * + * May be copied or modified under the terms of the GNU General Public License + * Based in part on the ITE vendor provided SCSI driver. + * + * Documentation available from + * http://www.ite.com.tw/pc/IT8212F_V04.pdf + * Some other documents are NDA. + * + * The ITE8212 isn't exactly a standard IDE controller. It has two + * modes. In pass through mode then it is an IDE controller. In its smart + * mode its actually quite a capable hardware raid controller disguised + * as an IDE controller. Smart mode only understands DMA read/write and + * identify, none of the fancier commands apply. The IT8211 is identical + * in other respects but lacks the raid mode. + * + * Errata: + * o Rev 0x10 also requires master/slave hold the same DMA timings and + * cannot do ATAPI MWDMA. + * o The identify data for raid volumes lacks CHS info (technically ok) + * but also fails to set the LBA28 and other bits. We fix these in + * the IDE probe quirk code. + * o If you write LBA48 sized I/O's (ie > 256 sector) in smart mode + * raid then the controller firmware dies + * o Smart mode without RAID doesn't clear all the necessary identify + * bits to reduce the command set to the one used + * + * This has a few impacts on the driver + * - In pass through mode we do all the work you would expect + * - In smart mode the clocking set up is done by the controller generally + * but we must watch the other limits and filter. + * - There are a few extra vendor commands that actually talk to the + * controller but only work PIO with no IRQ. + * + * Vendor areas of the identify block in smart mode are used for the + * timing and policy set up. Each HDD in raid mode also has a serial + * block on the disk. The hardware extra commands are get/set chip status, + * rebuild, get rebuild status. + * + * In Linux the driver supports pass through mode as if the device was + * just another IDE controller. If the smart mode is running then + * volumes are managed by the controller firmware and each IDE "disk" + * is a raid volume. Even more cute - the controller can do automated + * hotplug and rebuild. + * + * The pass through controller itself is a little demented. It has a + * flaw that it has a single set of PIO/MWDMA timings per channel so + * non UDMA devices restrict each others performance. It also has a + * single clock source per channel so mixed UDMA100/133 performance + * isn't perfect and we have to pick a clock. Thankfully none of this + * matters in smart mode. ATAPI DMA is not currently supported. + * + * It seems the smart mode is a win for RAID1/RAID10 but otherwise not. + * + * TODO + * - ATAPI UDMA is ok but not MWDMA it seems + * - RAID configuration ioctls + * - Move to libata once it grows up + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +struct it821x_dev +{ + unsigned int smart:1, /* Are we in smart raid mode */ + timing10:1; /* Rev 0x10 */ + u8 clock_mode; /* 0, ATA_50 or ATA_66 */ + u8 want[2][2]; /* Mode/Pri log for master slave */ + /* We need these for switching the clock when DMA goes on/off + The high byte is the 66Mhz timing */ + u16 pio[2]; /* Cached PIO values */ + u16 mwdma[2]; /* Cached MWDMA values */ + u16 udma[2]; /* Cached UDMA values (per drive) */ +}; + +#define ATA_66 0 +#define ATA_50 1 +#define ATA_ANY 2 + +#define UDMA_OFF 0 +#define MWDMA_OFF 0 + +/* + * We allow users to force the card into non raid mode without + * flashing the alternative BIOS. This is also neccessary right now + * for embedded platforms that cannot run a PC BIOS but are using this + * device. + */ + +static int it8212_noraid; + +/** + * it821x_program - program the PIO/MWDMA registers + * @drive: drive to tune + * + * Program the PIO/MWDMA timing for this channel according to the + * current clock. + */ + +static void it821x_program(ide_drive_t *drive, u16 timing) +{ + ide_hwif_t *hwif = drive->hwif; + struct it821x_dev *itdev = ide_get_hwifdata(hwif); + int channel = hwif->channel; + u8 conf; + + /* Program PIO/MWDMA timing bits */ + if(itdev->clock_mode == ATA_66) + conf = timing >> 8; + else + conf = timing & 0xFF; + pci_write_config_byte(hwif->pci_dev, 0x54 + 4 * channel, conf); +} + +/** + * it821x_program_udma - program the UDMA registers + * @drive: drive to tune + * + * Program the UDMA timing for this drive according to the + * current clock. + */ + +static void it821x_program_udma(ide_drive_t *drive, u16 timing) +{ + ide_hwif_t *hwif = drive->hwif; + struct it821x_dev *itdev = ide_get_hwifdata(hwif); + int channel = hwif->channel; + int unit = drive->select.b.unit; + u8 conf; + + /* Program UDMA timing bits */ + if(itdev->clock_mode == ATA_66) + conf = timing >> 8; + else + conf = timing & 0xFF; + if(itdev->timing10 == 0) + pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel + unit, conf); + else { + pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel, conf); + pci_write_config_byte(hwif->pci_dev, 0x56 + 4 * channel + 1, conf); + } +} + + +/** + * it821x_clock_strategy + * @hwif: hardware interface + * + * Select between the 50 and 66Mhz base clocks to get the best + * results for this interface. + */ + +static void it821x_clock_strategy(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + struct it821x_dev *itdev = ide_get_hwifdata(hwif); + + u8 unit = drive->select.b.unit; + ide_drive_t *pair = &hwif->drives[1-unit]; + + int clock, altclock; + u8 v; + int sel = 0; + + if(itdev->want[0][0] > itdev->want[1][0]) { + clock = itdev->want[0][1]; + altclock = itdev->want[1][1]; + } else { + clock = itdev->want[1][1]; + altclock = itdev->want[0][1]; + } + + /* Master doesn't care does the slave ? */ + if(clock == ATA_ANY) + clock = altclock; + + /* Nobody cares - keep the same clock */ + if(clock == ATA_ANY) + return; + /* No change */ + if(clock == itdev->clock_mode) + return; + + /* Load this into the controller ? */ + if(clock == ATA_66) + itdev->clock_mode = ATA_66; + else { + itdev->clock_mode = ATA_50; + sel = 1; + } + pci_read_config_byte(hwif->pci_dev, 0x50, &v); + v &= ~(1 << (1 + hwif->channel)); + v |= sel << (1 + hwif->channel); + pci_write_config_byte(hwif->pci_dev, 0x50, v); + + /* + * Reprogram the UDMA/PIO of the pair drive for the switch + * MWDMA will be dealt with by the dma switcher + */ + if(pair && itdev->udma[1-unit] != UDMA_OFF) { + it821x_program_udma(pair, itdev->udma[1-unit]); + it821x_program(pair, itdev->pio[1-unit]); + } + /* + * Reprogram the UDMA/PIO of our drive for the switch. + * MWDMA will be dealt with by the dma switcher + */ + if(itdev->udma[unit] != UDMA_OFF) { + it821x_program_udma(drive, itdev->udma[unit]); + it821x_program(drive, itdev->pio[unit]); + } +} + +/** + * it821x_ratemask - Compute available modes + * @drive: IDE drive + * + * Compute the available speeds for the devices on the interface. This + * is all modes to ATA133 clipped by drive cable setup. + */ + +static u8 it821x_ratemask (ide_drive_t *drive) +{ + u8 mode = 4; + if (!eighty_ninty_three(drive)) + mode = min(mode, (u8)1); + return mode; +} + +/** + * it821x_tuneproc - tune a drive + * @drive: drive to tune + * @mode_wanted: the target operating mode + * + * Load the timing settings for this device mode into the + * controller. By the time we are called the mode has been + * modified as neccessary to handle the absence of seperate + * master/slave timers for MWDMA/PIO. + * + * This code is only used in pass through mode. + */ + +static void it821x_tuneproc (ide_drive_t *drive, byte mode_wanted) +{ + ide_hwif_t *hwif = drive->hwif; + struct it821x_dev *itdev = ide_get_hwifdata(hwif); + int unit = drive->select.b.unit; + + /* Spec says 89 ref driver uses 88 */ + static u16 pio[] = { 0xAA88, 0xA382, 0xA181, 0x3332, 0x3121 }; + static u8 pio_want[] = { ATA_66, ATA_66, ATA_66, ATA_66, ATA_ANY }; + + if(itdev->smart) + return; + + /* We prefer 66Mhz clock for PIO 0-3, don't care for PIO4 */ + itdev->want[unit][1] = pio_want[mode_wanted]; + itdev->want[unit][0] = 1; /* PIO is lowest priority */ + itdev->pio[unit] = pio[mode_wanted]; + it821x_clock_strategy(drive); + it821x_program(drive, itdev->pio[unit]); +} + +/** + * it821x_tune_mwdma - tune a channel for MWDMA + * @drive: drive to set up + * @mode_wanted: the target operating mode + * + * Load the timing settings for this device mode into the + * controller when doing MWDMA in pass through mode. The caller + * must manage the whole lack of per device MWDMA/PIO timings and + * the shared MWDMA/PIO timing register. + */ + +static void it821x_tune_mwdma (ide_drive_t *drive, byte mode_wanted) +{ + ide_hwif_t *hwif = drive->hwif; + struct it821x_dev *itdev = (void *)ide_get_hwifdata(hwif); + int unit = drive->select.b.unit; + int channel = hwif->channel; + u8 conf; + + static u16 dma[] = { 0x8866, 0x3222, 0x3121 }; + static u8 mwdma_want[] = { ATA_ANY, ATA_66, ATA_ANY }; + + itdev->want[unit][1] = mwdma_want[mode_wanted]; + itdev->want[unit][0] = 2; /* MWDMA is low priority */ + itdev->mwdma[unit] = dma[mode_wanted]; + itdev->udma[unit] = UDMA_OFF; + + /* UDMA bits off - Revision 0x10 do them in pairs */ + pci_read_config_byte(hwif->pci_dev, 0x50, &conf); + if(itdev->timing10) + conf |= channel ? 0x60: 0x18; + else + conf |= 1 << (3 + 2 * channel + unit); + pci_write_config_byte(hwif->pci_dev, 0x50, conf); + + it821x_clock_strategy(drive); + /* FIXME: do we need to program this ? */ + /* it821x_program(drive, itdev->mwdma[unit]); */ +} + +/** + * it821x_tune_udma - tune a channel for UDMA + * @drive: drive to set up + * @mode_wanted: the target operating mode + * + * Load the timing settings for this device mode into the + * controller when doing UDMA modes in pass through. + */ + +static void it821x_tune_udma (ide_drive_t *drive, byte mode_wanted) +{ + ide_hwif_t *hwif = drive->hwif; + struct it821x_dev *itdev = ide_get_hwifdata(hwif); + int unit = drive->select.b.unit; + int channel = hwif->channel; + u8 conf; + + static u16 udma[] = { 0x4433, 0x4231, 0x3121, 0x2121, 0x1111, 0x2211, 0x1111 }; + static u8 udma_want[] = { ATA_ANY, ATA_50, ATA_ANY, ATA_66, ATA_66, ATA_50, ATA_66 }; + + itdev->want[unit][1] = udma_want[mode_wanted]; + itdev->want[unit][0] = 3; /* UDMA is high priority */ + itdev->mwdma[unit] = MWDMA_OFF; + itdev->udma[unit] = udma[mode_wanted]; + if(mode_wanted >= 5) + itdev->udma[unit] |= 0x8080; /* UDMA 5/6 select on */ + + /* UDMA on. Again revision 0x10 must do the pair */ + pci_read_config_byte(hwif->pci_dev, 0x50, &conf); + if(itdev->timing10) + conf &= channel ? 0x9F: 0xE7; + else + conf &= ~ (1 << (3 + 2 * channel + unit)); + pci_write_config_byte(hwif->pci_dev, 0x50, conf); + + it821x_clock_strategy(drive); + it821x_program_udma(drive, itdev->udma[unit]); + +} + +/** + * config_it821x_chipset_for_pio - set drive timings + * @drive: drive to tune + * @speed we want + * + * Compute the best pio mode we can for a given device. We must + * pick a speed that does not cause problems with the other device + * on the cable. + */ + +static void config_it821x_chipset_for_pio (ide_drive_t *drive, byte set_speed) +{ + u8 unit = drive->select.b.unit; + ide_hwif_t *hwif = drive->hwif; + ide_drive_t *pair = &hwif->drives[1-unit]; + u8 speed = 0, set_pio = ide_get_best_pio_mode(drive, 255, 5, NULL); + u8 pair_pio; + + /* We have to deal with this mess in pairs */ + if(pair != NULL) { + pair_pio = ide_get_best_pio_mode(pair, 255, 5, NULL); + /* Trim PIO to the slowest of the master/slave */ + if(pair_pio < set_pio) + set_pio = pair_pio; + } + it821x_tuneproc(drive, set_pio); + speed = XFER_PIO_0 + set_pio; + /* XXX - We trim to the lowest of the pair so the other drive + will always be fine at this point until we do hotplug passthru */ + + if (set_speed) + (void) ide_config_drive_speed(drive, speed); +} + +/** + * it821x_dma_read - DMA hook + * @drive: drive for DMA + * + * The IT821x has a single timing register for MWDMA and for PIO + * operations. As we flip back and forth we have to reload the + * clock. In addition the rev 0x10 device only works if the same + * timing value is loaded into the master and slave UDMA clock + * so we must also reload that. + * + * FIXME: we could figure out in advance if we need to do reloads + */ + +static void it821x_dma_start(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + struct it821x_dev *itdev = ide_get_hwifdata(hwif); + int unit = drive->select.b.unit; + if(itdev->mwdma[unit] != MWDMA_OFF) + it821x_program(drive, itdev->mwdma[unit]); + else if(itdev->udma[unit] != UDMA_OFF && itdev->timing10) + it821x_program_udma(drive, itdev->udma[unit]); + ide_dma_start(drive); +} + +/** + * it821x_dma_write - DMA hook + * @drive: drive for DMA stop + * + * The IT821x has a single timing register for MWDMA and for PIO + * operations. As we flip back and forth we have to reload the + * clock. + */ + +static int it821x_dma_end(ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + int unit = drive->select.b.unit; + struct it821x_dev *itdev = ide_get_hwifdata(hwif); + int ret = __ide_dma_end(drive); + if(itdev->mwdma[unit] != MWDMA_OFF) + it821x_program(drive, itdev->pio[unit]); + return ret; +} + + +/** + * it821x_tune_chipset - set controller timings + * @drive: Drive to set up + * @xferspeed: speed we want to achieve + * + * Tune the ITE chipset for the desired mode. If we can't achieve + * the desired mode then tune for a lower one, but ultimately + * make the thing work. + */ + +static int it821x_tune_chipset (ide_drive_t *drive, byte xferspeed) +{ + + ide_hwif_t *hwif = drive->hwif; + struct it821x_dev *itdev = ide_get_hwifdata(hwif); + u8 speed = ide_rate_filter(it821x_ratemask(drive), xferspeed); + + if(!itdev->smart) { + switch(speed) { + case XFER_PIO_4: + case XFER_PIO_3: + case XFER_PIO_2: + case XFER_PIO_1: + case XFER_PIO_0: + it821x_tuneproc(drive, (speed - XFER_PIO_0)); + break; + /* MWDMA tuning is really hard because our MWDMA and PIO + timings are kept in the same place. We can switch in the + host dma on/off callbacks */ + case XFER_MW_DMA_2: + case XFER_MW_DMA_1: + case XFER_MW_DMA_0: + it821x_tune_mwdma(drive, (speed - XFER_MW_DMA_0)); + break; + case XFER_UDMA_6: + case XFER_UDMA_5: + case XFER_UDMA_4: + case XFER_UDMA_3: + case XFER_UDMA_2: + case XFER_UDMA_1: + case XFER_UDMA_0: + it821x_tune_udma(drive, (speed - XFER_UDMA_0)); + break; + default: + return 1; + } + } + /* + * In smart mode the clocking is done by the host controller + * snooping the mode we picked. The rest of it is not our problem + */ + return ide_config_drive_speed(drive, speed); +} + +/** + * config_chipset_for_dma - configure for DMA + * @drive: drive to configure + * + * Called by the IDE layer when it wants the timings set up. + */ + +static int config_chipset_for_dma (ide_drive_t *drive) +{ + u8 speed = ide_dma_speed(drive, it821x_ratemask(drive)); + + config_it821x_chipset_for_pio(drive, !speed); + it821x_tune_chipset(drive, speed); + return ide_dma_enable(drive); +} + +/** + * it821x_configure_drive_for_dma - set up for DMA transfers + * @drive: drive we are going to set up + * + * Set up the drive for DMA, tune the controller and drive as + * required. If the drive isn't suitable for DMA or we hit + * other problems then we will drop down to PIO and set up + * PIO appropriately + */ + +static int it821x_config_drive_for_dma (ide_drive_t *drive) +{ + ide_hwif_t *hwif = drive->hwif; + + if (ide_use_dma(drive)) { + if (config_chipset_for_dma(drive)) + return hwif->ide_dma_on(drive); + } + config_it821x_chipset_for_pio(drive, 1); + return hwif->ide_dma_off_quietly(drive); +} + +/** + * ata66_it821x - check for 80 pin cable + * @hwif: interface to check + * + * Check for the presence of an ATA66 capable cable on the + * interface. Problematic as it seems some cards don't have + * the needed logic onboard. + */ + +static unsigned int __devinit ata66_it821x(ide_hwif_t *hwif) +{ + /* The reference driver also only does disk side */ + return 1; +} + +/** + * it821x_fixup - post init callback + * @hwif: interface + * + * This callback is run after the drives have been probed but + * before anything gets attached. It allows drivers to do any + * final tuning that is needed, or fixups to work around bugs. + */ + +static void __devinit it821x_fixups(ide_hwif_t *hwif) +{ + struct it821x_dev *itdev = ide_get_hwifdata(hwif); + int i; + + if(!itdev->smart) { + /* + * If we are in pass through mode then not much + * needs to be done, but we do bother to clear the + * IRQ mask as we may well be in PIO (eg rev 0x10) + * for now and we know unmasking is safe on this chipset. + */ + for (i = 0; i < 2; i++) { + ide_drive_t *drive = &hwif->drives[i]; + if(drive->present) + drive->unmask = 1; + } + return; + } + /* + * Perform fixups on smart mode. We need to "lose" some + * capabilities the firmware lacks but does not filter, and + * also patch up some capability bits that it forgets to set + * in RAID mode. + */ + + for(i = 0; i < 2; i++) { + ide_drive_t *drive = &hwif->drives[i]; + struct hd_driveid *id; + u16 *idbits; + + if(!drive->present) + continue; + id = drive->id; + idbits = (u16 *)drive->id; + + /* Check for RAID v native */ + if(strstr(id->model, "Integrated Technology Express")) { + /* In raid mode the ident block is slightly buggy + We need to set the bits so that the IDE layer knows + LBA28. LBA48 and DMA ar valid */ + id->capability |= 3; /* LBA28, DMA */ + id->command_set_2 |= 0x0400; /* LBA48 valid */ + id->cfs_enable_2 |= 0x0400; /* LBA48 on */ + /* Reporting logic */ + printk(KERN_INFO "%s: IT8212 %sRAID %d volume", + drive->name, + idbits[147] ? "Bootable ":"", + idbits[129]); + if(idbits[129] != 1) + printk("(%dK stripe)", idbits[146]); + printk(".\n"); + /* Now the core code will have wrongly decided no DMA + so we need to fix this */ + hwif->ide_dma_off_quietly(drive); +#ifdef CONFIG_IDEDMA_ONLYDISK + if (drive->media == ide_disk) +#endif + hwif->ide_dma_check(drive); + } else { + /* Non RAID volume. Fixups to stop the core code + doing unsupported things */ + id->field_valid &= 1; + id->queue_depth = 0; + id->command_set_1 = 0; + id->command_set_2 &= 0xC400; + id->cfsse &= 0xC000; + id->cfs_enable_1 = 0; + id->cfs_enable_2 &= 0xC400; + id->csf_default &= 0xC000; + id->word127 = 0; + id->dlf = 0; + id->csfo = 0; + id->cfa_power = 0; + printk(KERN_INFO "%s: Performing identify fixups.\n", + drive->name); + } + } + +} + +/** + * init_hwif_it821x - set up hwif structs + * @hwif: interface to set up + * + * We do the basic set up of the interface structure. The IT8212 + * requires several custom handlers so we override the default + * ide DMA handlers appropriately + */ + +static void __devinit init_hwif_it821x(ide_hwif_t *hwif) +{ + struct it821x_dev *idev = kmalloc(sizeof(struct it821x_dev), GFP_KERNEL); + u8 conf; + + if(idev == NULL) { + printk(KERN_ERR "it821x: out of memory, falling back to legacy behaviour.\n"); + goto fallback; + } + memset(idev, 0, sizeof(struct it821x_dev)); + ide_set_hwifdata(hwif, idev); + + pci_read_config_byte(hwif->pci_dev, 0x50, &conf); + if(conf & 1) { + idev->smart = 1; + hwif->atapi_dma = 0; + /* Long I/O's although allowed in LBA48 space cause the + onboard firmware to enter the twighlight zone */ + hwif->rqsize = 256; + } + + /* Pull the current clocks from 0x50 also */ + if (conf & (1 << (1 + hwif->channel))) + idev->clock_mode = ATA_50; + else + idev->clock_mode = ATA_66; + + idev->want[0][1] = ATA_ANY; + idev->want[1][1] = ATA_ANY; + + /* + * Not in the docs but according to the reference driver + * this is neccessary. + */ + + pci_read_config_byte(hwif->pci_dev, 0x08, &conf); + if(conf == 0x10) { + idev->timing10 = 1; + hwif->atapi_dma = 0; + if(!idev->smart) + printk(KERN_WARNING "it821x: Revision 0x10, workarounds activated.\n"); + } + + hwif->speedproc = &it821x_tune_chipset; + hwif->tuneproc = &it821x_tuneproc; + + /* MWDMA/PIO clock switching for pass through mode */ + if(!idev->smart) { + hwif->ide_dma_start = &it821x_dma_start; + hwif->ide_dma_end = &it821x_dma_end; + } + + hwif->drives[0].autotune = 1; + hwif->drives[1].autotune = 1; + + if (!hwif->dma_base) + goto fallback; + + hwif->ultra_mask = 0x7f; + hwif->mwdma_mask = 0x07; + hwif->swdma_mask = 0x07; + + hwif->ide_dma_check = &it821x_config_drive_for_dma; + if (!(hwif->udma_four)) + hwif->udma_four = ata66_it821x(hwif); + + /* + * The BIOS often doesn't set up DMA on this controller + * so we always do it. + */ + + hwif->autodma = 1; + hwif->drives[0].autodma = hwif->autodma; + hwif->drives[1].autodma = hwif->autodma; + return; +fallback: + hwif->autodma = 0; + return; +} + +static void __devinit it8212_disable_raid(struct pci_dev *dev) +{ + /* Reset local CPU, and set BIOS not ready */ + pci_write_config_byte(dev, 0x5E, 0x01); + + /* Set to bypass mode, and reset PCI bus */ + pci_write_config_byte(dev, 0x50, 0x00); + pci_write_config_word(dev, PCI_COMMAND, + PCI_COMMAND_PARITY | PCI_COMMAND_IO | + PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); + pci_write_config_word(dev, 0x40, 0xA0F3); + + pci_write_config_dword(dev,0x4C, 0x02040204); + pci_write_config_byte(dev, 0x42, 0x36); + pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0); +} + +static unsigned int __devinit init_chipset_it821x(struct pci_dev *dev, const char *name) +{ + u8 conf; + static char *mode[2] = { "pass through", "smart" }; + + /* Force the card into bypass mode if so requested */ + if (it8212_noraid) { + printk(KERN_INFO "it8212: forcing bypass mode.\n"); + it8212_disable_raid(dev); + } + pci_read_config_byte(dev, 0x50, &conf); + printk(KERN_INFO "it821x: controller in %s mode.\n", mode[conf & 1]); + return 0; +} + + +#define DECLARE_ITE_DEV(name_str) \ + { \ + .name = name_str, \ + .init_chipset = init_chipset_it821x, \ + .init_hwif = init_hwif_it821x, \ + .channels = 2, \ + .autodma = AUTODMA, \ + .bootable = ON_BOARD, \ + .fixup = it821x_fixups \ + } + +static ide_pci_device_t it821x_chipsets[] __devinitdata = { + /* 0 */ DECLARE_ITE_DEV("IT8212"), +}; + +/** + * it821x_init_one - pci layer discovery entry + * @dev: PCI device + * @id: ident table entry + * + * Called by the PCI code when it finds an ITE821x controller. + * We then use the IDE PCI generic helper to do most of the work. + */ + +static int __devinit it821x_init_one(struct pci_dev *dev, const struct pci_device_id *id) +{ + ide_setup_pci_device(dev, &it821x_chipsets[id->driver_data]); + return 0; +} + +static struct pci_device_id it821x_pci_tbl[] = { + { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_ITE, PCI_DEVICE_ID_ITE_8212, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { 0, }, +}; + +MODULE_DEVICE_TABLE(pci, it821x_pci_tbl); + +static struct pci_driver driver = { + .name = "ITE821x IDE", + .id_table = it821x_pci_tbl, + .probe = it821x_init_one, +}; + +static int __init it821x_ide_init(void) +{ + return ide_pci_register_driver(&driver); +} + +module_init(it821x_ide_init); + +module_param_named(noraid, it8212_noraid, int, S_IRUGO); +MODULE_PARM_DESC(it8212_noraid, "Force card into bypass mode"); + +MODULE_AUTHOR("Alan Cox"); +MODULE_DESCRIPTION("PCI driver module for the ITE 821x"); +MODULE_LICENSE("GPL"); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/pci/Makefile linux-2.6.11/drivers/ide/pci/Makefile --- linux.vanilla-2.6.11/drivers/ide/pci/Makefile 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/pci/Makefile 2005-03-06 14:53:31.000000000 +0000 @@ -8,10 +8,12 @@ obj-$(CONFIG_BLK_DEV_CS5530) += cs5530.o obj-$(CONFIG_BLK_DEV_SC1200) += sc1200.o obj-$(CONFIG_BLK_DEV_CY82C693) += cy82c693.o +obj-$(CONFIG_BLK_DEV_DELKIN) += delkin_cb.o obj-$(CONFIG_BLK_DEV_HPT34X) += hpt34x.o obj-$(CONFIG_BLK_DEV_HPT366) += hpt366.o #obj-$(CONFIG_BLK_DEV_HPT37X) += hpt37x.o obj-$(CONFIG_BLK_DEV_IT8172) += it8172.o +obj-$(CONFIG_BLK_DEV_IT821X) += it821x.o obj-$(CONFIG_BLK_DEV_NS87415) += ns87415.o obj-$(CONFIG_BLK_DEV_OPTI621) += opti621.o obj-$(CONFIG_BLK_DEV_PDC202XX_OLD) += pdc202xx_old.o diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/pci/ns87415.c linux-2.6.11/drivers/ide/pci/ns87415.c --- linux.vanilla-2.6.11/drivers/ide/pci/ns87415.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/pci/ns87415.c 2005-03-06 14:53:31.000000000 +0000 @@ -265,7 +265,7 @@ return; hwif->OUTB(0x60, hwif->dma_status); - hwif->dma_setup = &ns87415_ide_dma_setup; + hwif->ide_dma_setup = &ns87415_ide_dma_setup; hwif->ide_dma_check = &ns87415_ide_dma_check; hwif->ide_dma_end = &ns87415_ide_dma_end; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/pci/pdc202xx_old.c linux-2.6.11/drivers/ide/pci/pdc202xx_old.c --- linux.vanilla-2.6.11/drivers/ide/pci/pdc202xx_old.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/pci/pdc202xx_old.c 2005-03-06 14:53:37.000000000 +0000 @@ -644,7 +644,7 @@ if (hwif->pci_dev->device != PCI_DEVICE_ID_PROMISE_20246) { if (!(hwif->udma_four)) hwif->udma_four = (pdc202xx_old_cable_detect(hwif)) ? 0 : 1; - hwif->dma_start = &pdc202xx_old_ide_dma_start; + hwif->ide_dma_start = &pdc202xx_old_ide_dma_start; hwif->ide_dma_end = &pdc202xx_old_ide_dma_end; } hwif->ide_dma_test_irq = &pdc202xx_old_ide_dma_test_irq; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/pci/sgiioc4.c linux-2.6.11/drivers/ide/pci/sgiioc4.c --- linux.vanilla-2.6.11/drivers/ide/pci/sgiioc4.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/pci/sgiioc4.c 2005-03-06 14:53:54.000000000 +0000 @@ -600,8 +600,8 @@ hwif->quirkproc = NULL; hwif->busproc = NULL; - hwif->dma_setup = &sgiioc4_ide_dma_setup; - hwif->dma_start = &sgiioc4_ide_dma_start; + hwif->ide_dma_setup = &sgiioc4_ide_dma_setup; + hwif->ide_dma_start = &sgiioc4_ide_dma_start; hwif->ide_dma_end = &sgiioc4_ide_dma_end; hwif->ide_dma_check = &sgiioc4_ide_dma_check; hwif->ide_dma_on = &sgiioc4_ide_dma_on; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/pci/siimage.c linux-2.6.11/drivers/ide/pci/siimage.c --- linux.vanilla-2.6.11/drivers/ide/pci/siimage.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/pci/siimage.c 2005-03-08 11:42:29.000000000 +0000 @@ -48,6 +48,8 @@ { case PCI_DEVICE_ID_SII_3112: case PCI_DEVICE_ID_SII_1210SA: + case PCI_DEVICE_ID_ATI_IXP300_SATA: + case PCI_DEVICE_ID_ATI_IXP400_SATA: return 1; case PCI_DEVICE_ID_SII_680: return 0; @@ -1088,7 +1090,9 @@ static ide_pci_device_t siimage_chipsets[] __devinitdata = { /* 0 */ DECLARE_SII_DEV("SiI680"), /* 1 */ DECLARE_SII_DEV("SiI3112 Serial ATA"), - /* 2 */ DECLARE_SII_DEV("Adaptec AAR-1210SA") + /* 2 */ DECLARE_SII_DEV("Adaptec AAR-1210SA"), + /* 3 */ DECLARE_SII_DEV("ATI IXP300"), + /* 4 */ DECLARE_SII_DEV("ATI IXP400") }; /** @@ -1110,6 +1114,8 @@ #ifdef CONFIG_BLK_DEV_IDE_SATA { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, { PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_SII_1210SA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4}, #endif { 0, }, }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/pci/sl82c105.c linux-2.6.11/drivers/ide/pci/sl82c105.c --- linux.vanilla-2.6.11/drivers/ide/pci/sl82c105.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/pci/sl82c105.c 2005-03-06 14:54:07.000000000 +0000 @@ -467,7 +467,7 @@ hwif->ide_dma_on = &sl82c105_ide_dma_on; hwif->ide_dma_off_quietly = &sl82c105_ide_dma_off_quietly; hwif->ide_dma_lostirq = &sl82c105_ide_dma_lost_irq; - hwif->dma_start = &sl82c105_ide_dma_start; + hwif->ide_dma_start = &sl82c105_ide_dma_start; hwif->ide_dma_timeout = &sl82c105_ide_dma_timeout; if (!noautodma) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/pci/trm290.c linux-2.6.11/drivers/ide/pci/trm290.c --- linux.vanilla-2.6.11/drivers/ide/pci/trm290.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/pci/trm290.c 2005-03-06 14:54:07.000000000 +0000 @@ -256,6 +256,7 @@ u8 reg = 0; struct pci_dev *dev = hwif->pci_dev; + /* FIXME: does this device support PIO LBA48 ? */ hwif->no_lba48 = 1; hwif->chipset = ide_trm290; cfgbase = pci_resource_start(dev, 4); @@ -292,9 +293,9 @@ ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 3); #ifdef CONFIG_BLK_DEV_IDEDMA - hwif->dma_setup = &trm290_ide_dma_setup; - hwif->dma_exec_cmd = &trm290_ide_dma_exec_cmd; - hwif->dma_start = &trm290_ide_dma_start; + hwif->ide_dma_setup = &trm290_ide_dma_setup; + hwif->ide_dma_exec_cmd = &trm290_ide_dma_exec_cmd; + hwif->ide_dma_start = &trm290_ide_dma_start; hwif->ide_dma_end = &trm290_ide_dma_end; hwif->ide_dma_test_irq = &trm290_ide_dma_test_irq; #endif /* CONFIG_BLK_DEV_IDEDMA */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/ppc/pmac.c linux-2.6.11/drivers/ide/ppc/pmac.c --- linux.vanilla-2.6.11/drivers/ide/ppc/pmac.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/ppc/pmac.c 2005-03-06 14:54:07.000000000 +0000 @@ -2016,9 +2016,9 @@ hwif->ide_dma_off_quietly = &__ide_dma_off_quietly; hwif->ide_dma_on = &__ide_dma_on; hwif->ide_dma_check = &pmac_ide_dma_check; - hwif->dma_setup = &pmac_ide_dma_setup; - hwif->dma_exec_cmd = &pmac_ide_dma_exec_cmd; - hwif->dma_start = &pmac_ide_dma_start; + hwif->ide_dma_setup = &pmac_ide_dma_setup; + hwif->ide_dma_exec_cmd = &pmac_ide_dma_exec_cmd; + hwif->ide_dma_start = &pmac_ide_dma_start; hwif->ide_dma_end = &pmac_ide_dma_end; hwif->ide_dma_test_irq = &pmac_ide_dma_test_irq; hwif->ide_dma_host_off = &pmac_ide_dma_host_off; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/ide/setup-pci.c linux-2.6.11/drivers/ide/setup-pci.c --- linux.vanilla-2.6.11/drivers/ide/setup-pci.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/ide/setup-pci.c 2005-03-06 17:21:10.000000000 +0000 @@ -1,7 +1,8 @@ /* - * linux/drivers/ide/setup-pci.c Version 1.10 2002/08/19 + * linux/drivers/ide/setup-pci.c Version 1.14 2004/08/10 * * Copyright (c) 1998-2000 Andre Hedrick + * Copyright (c) 2004 Red Hat * * Copyright (c) 1995-1998 Mark Lord * May be copied or modified under the terms of the GNU General Public License @@ -11,6 +12,7 @@ * Use pci_set_master * Fix misreporting of I/O v MMIO problems * Initial fixups for simplex devices + * Hot unplug paths */ /* @@ -28,6 +30,7 @@ #include #include #include +#include #include #include @@ -43,7 +46,7 @@ * Match a PCI IDE port against an entry in ide_hwifs[], * based on io_base port if possible. Return the matching hwif, * or a new hwif. If we find an error (clashing, out of devices, etc) - * return NULL + * return NULL. The caller must hold the ide_cfg_sem. * * FIXME: we need to handle mmio matches here too */ @@ -88,6 +91,8 @@ * * Unless there is a bootable card that does not use the standard * ports 1f0/170 (the ide0/ide1 defaults). The (bootable) flag. + * + * FIXME: migrate use of ide_unknown to also use ->configured */ if (bootable) { for (h = 0; h < MAX_HWIFS; ++h) { @@ -426,8 +431,18 @@ ctl = port ? 0x374 : 0x3f4; base = port ? 0x170 : 0x1f0; } + + /* + * Protect against a hwif being unloaded as we attach to it + */ + down(&ide_cfg_sem); + if ((hwif = ide_match_hwif(base, d->bootable, d->name)) == NULL) + { + up(&ide_cfg_sem); return NULL; /* no room in ide_hwifs[] */ + } + if (hwif->io_ports[IDE_DATA_OFFSET] != base || hwif->io_ports[IDE_CONTROL_OFFSET] != (ctl | 2)) { memset(&hwif->hw, 0, sizeof(hwif->hw)); @@ -444,6 +459,9 @@ hwif->pci_dev = dev; hwif->cds = (struct ide_pci_device_s *) d; hwif->channel = port; + hwif->configured = 1; + + up(&ide_cfg_sem); if (!hwif->irq) hwif->irq = irq; @@ -767,7 +785,7 @@ for (j = 0; j < 2; j++) { if ((idx[j] & 0xf0) != 0xf0) - probe_hwif_init(ide_hwifs + idx[j]); + probe_hwif_init_with_fixup(ide_hwifs + idx[j], d->fixup); } } @@ -778,6 +796,64 @@ EXPORT_SYMBOL_GPL(ide_setup_pci_devices); + +static int ide_pci_try_unregister(struct pci_dev *dev) +{ + int i; + int err = 0; + ide_hwif_t *hwif = ide_hwifs; + + for(i = 0; i < MAX_HWIFS; i++) { + if(hwif->configured && hwif->pci_dev == dev) + err |= __ide_unregister_hwif(hwif); + i++; + hwif++; + } + return err; +} + +/** + * ide_pci_remove_hwifs - remove PCI interfaces + * @dev: PCI device + * + * Remove any hwif attached to this PCI device. This will call + * back the various hwif->remove functions. In order to get the + * best results when delays occur we kill the iops before we + * potentially start blocking for long periods untangling the + * IDE layer. + * + * Takes the ide_cfg_sem in order to protect against races with + * new/old hwifs. Calls functions that take all the other locks + * so should be called with no locks held. + */ + +void ide_pci_remove_hwifs(struct pci_dev *dev) +{ + int i; + ide_hwif_t *hwif = ide_hwifs; + int err; + + down(&ide_cfg_sem); + + err = ide_pci_try_unregister(dev); + + if(err < 0) { + printk(KERN_ERR "ide: PCI interfaces busy during hotplug. Waiting....\n"); + for(i = 0; i < MAX_HWIFS; i++) { + if(hwif->configured && hwif->pci_dev == dev) + removed_hwif_iops(hwif); + i++; + hwif++; + } + } + /* Should drop this out to a work queue I think ? */ + while(ide_pci_try_unregister(dev) < 0) + msleep(1000); + up(&ide_cfg_sem); +} + +EXPORT_SYMBOL_GPL(ide_pci_remove_hwifs); + /* * Module interfaces */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/input/keyboard/atkbd.c linux-2.6.11/drivers/input/keyboard/atkbd.c --- linux.vanilla-2.6.11/drivers/input/keyboard/atkbd.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/input/keyboard/atkbd.c 2005-03-05 16:10:39.000000000 +0000 @@ -340,9 +340,13 @@ break; case ATKBD_KEY_UNKNOWN: if (data == ATKBD_RET_ACK || data == ATKBD_RET_NAK) { +#if 0 +/* Quite a few key switchers and other tools trigger this and it confuses + people who can do nothing about it */ printk(KERN_WARNING "atkbd.c: Spurious %s on %s. Some program, " "like XFree86, might be trying access hardware directly.\n", data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys); +#endif } else { printk(KERN_WARNING "atkbd.c: Unknown key %s " "(%s set %d, code %#x on %s).\n", diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/input/serio/i8042.c linux-2.6.11/drivers/input/serio/i8042.c --- linux.vanilla-2.6.11/drivers/input/serio/i8042.c 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/input/serio/i8042.c 2005-03-06 17:30:37.000000000 +0000 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -673,6 +674,71 @@ } +static int i8042_spank_usb(void) +{ + struct pci_dev *usb = NULL; + int found = 0; + u16 word; + unsigned long addr; + unsigned long len; + int i; + + while((usb = pci_get_class((PCI_CLASS_SERIAL_USB << 8), usb)) != NULL) + { + /* UHCI controller not in legacy ? */ + + pci_read_config_word(usb, 0xC0, &word); + if(word & 0x2000) + continue; + + /* Check it is enabled. If the port is active in legacy mode + then this will be mapped already */ + + for(i = 0; i < PCI_ROM_RESOURCE; i++) + { + if (!(pci_resource_flags (usb, i) & IORESOURCE_IO)) + continue; + } + if(i == PCI_ROM_RESOURCE) + continue; + + /* + * Retrieve the bits + */ + + addr = pci_resource_start(usb, i); + len = pci_resource_len (usb, i); + + /* + * Check its configured and not in use + */ + if(addr == 0) + continue; + if (request_region(addr, len, "usb whackamole")) + continue; + + /* + * Kick the problem controller out of legacy mode + * so things like the E750x don't break + */ + + outw(0, addr + 4); /* IRQ Mask */ + outw(4, addr); /* Reset */ + msleep(20); + outw(0, addr); + + msleep(20); + /* Now take if off the BIOS */ + pci_write_config_word(usb, 0xC0, 0x2000); + release_region(addr, len); + + pci_dev_put(usb); + + found = 1; + } + return found; +} + /* * i8042_controller init initializes the i8042 controller, and, * most importantly, sets it into non-xlated mode if that's @@ -681,6 +747,7 @@ static int i8042_controller_init(void) { + int tries = 0; unsigned long flags; /* @@ -710,9 +777,15 @@ * Save the CTR for restoral on unload / reboot. */ - if (i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) { - printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n"); - return -1; + while(i8042_command(&i8042_ctr, I8042_CMD_CTL_RCTR)) { + if(tries > 3 || !i8042_spank_usb()) + { + printk(KERN_ERR "i8042.c: Can't read CTR while initializing i8042.\n"); + return -1; + } + printk(KERN_WARNING "i8042.c: Can't read CTR, disabling USB legacy and retrying.\n"); + i8042_flush(); + tries++; } i8042_initial_ctr = i8042_ctr; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/input/serio/i8042-x86ia64io.h linux-2.6.11/drivers/input/serio/i8042-x86ia64io.h --- linux.vanilla-2.6.11/drivers/input/serio/i8042-x86ia64io.h 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/input/serio/i8042-x86ia64io.h 2005-03-09 17:09:10.441288264 +0000 @@ -88,7 +88,7 @@ }; #endif -#ifdef CONFIG_ACPI +#if defined(__ia64__) && defined(CONFIG_ACPI) #include #include @@ -281,7 +281,7 @@ i8042_kbd_irq = I8042_MAP_IRQ(1); i8042_aux_irq = I8042_MAP_IRQ(12); -#ifdef CONFIG_ACPI +#if defined(__ia64__) && defined(CONFIG_ACPI) if (i8042_acpi_init()) return -1; #endif @@ -300,7 +300,7 @@ static inline void i8042_platform_exit(void) { -#ifdef CONFIG_ACPI +#if defined(__ia64__) && defined(CONFIG_ACPI) i8042_acpi_exit(); #endif } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/macintosh/mediabay.c linux-2.6.11/drivers/macintosh/mediabay.c --- linux.vanilla-2.6.11/drivers/macintosh/mediabay.c 2005-03-05 15:15:07.000000000 +0000 +++ linux-2.6.11/drivers/macintosh/mediabay.c 2005-03-06 17:21:36.000000000 +0000 @@ -82,6 +82,7 @@ #ifdef CONFIG_BLK_DEV_IDE void __iomem *cd_base; int cd_index; + ide_hwif_t *cd_hwif; int cd_irq; int cd_retry; #endif @@ -569,7 +570,7 @@ ide_init_hwif_ports(&hw, (unsigned long) bay->cd_base, (unsigned long) 0, NULL); hw.irq = bay->cd_irq; hw.chipset = ide_pmac; - bay->cd_index = ide_register_hw(&hw, NULL); + bay->cd_index = ide_register_hw(&hw, &bay->cd_hwif); pmu_resume(); } if (bay->cd_index == -1) { @@ -600,7 +601,7 @@ if (bay->cd_index >= 0) { printk(KERN_DEBUG "Unregistering mb %d ide, index:%d\n", i, bay->cd_index); - ide_unregister(bay->cd_index); + ide_unregister_hwif(bay->cd_hwif); bay->cd_index = -1; } if (bay->cd_retry) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/md/raid6altivec.uc linux-2.6.11/drivers/md/raid6altivec.uc --- linux.vanilla-2.6.11/drivers/md/raid6altivec.uc 2005-03-05 15:17:01.000000000 +0000 +++ linux-2.6.11/drivers/md/raid6altivec.uc 2005-03-09 17:09:10.457285832 +0000 @@ -108,7 +108,11 @@ int raid6_have_altivec(void) { /* This assumes either all CPUs have Altivec or none does */ +#ifdef CONFIG_PPC64 return cur_cpu_spec->cpu_features & CPU_FTR_ALTIVEC; +#else + return cur_cpu_spec[0]->cpu_features & CPU_FTR_ALTIVEC; +#endif } #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/net/pcnet32.c linux-2.6.11/drivers/net/pcnet32.c --- linux.vanilla-2.6.11/drivers/net/pcnet32.c 2005-03-05 15:15:10.000000000 +0000 +++ linux-2.6.11/drivers/net/pcnet32.c 2005-03-05 16:12:01.000000000 +0000 @@ -1429,26 +1429,32 @@ val |= 0x10; lp->a.write_csr (ioaddr, 124, val); - /* 24 Jun 2004 according AMD, in order to change the PHY, - * DANAS (or DISPM for 79C976) must be set; then select the speed, - * duplex, and/or enable auto negotiation, and clear DANAS */ - if (lp->mii && !(lp->options & PCNET32_PORT_ASEL)) { - lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080); - /* disable Auto Negotiation, set 10Mpbs, HD */ - val = lp->a.read_bcr(ioaddr, 32) & ~0xb8; - if (lp->options & PCNET32_PORT_FD) - val |= 0x10; - if (lp->options & PCNET32_PORT_100) - val |= 0x08; - lp->a.write_bcr (ioaddr, 32, val); + /* Skip PHY selection on AT2701FX, looses link otherwise */ + if(lp->pci_dev->subsystem_vendor == PCI_VENDOR_ID_AT && + lp->pci_dev->subsystem_device == PCI_SUBDEVICE_ID_AT_2701FX ) { + printk(KERN_DEBUG "pcnet32: Skipping PHY selection.\n"); } else { - if (lp->options & PCNET32_PORT_ASEL) { - lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080); - /* enable auto negotiate, setup, disable fd */ - val = lp->a.read_bcr(ioaddr, 32) & ~0x98; - val |= 0x20; - lp->a.write_bcr(ioaddr, 32, val); - } + /* 24 Jun 2004 according AMD, in order to change the PHY, + * DANAS (or DISPM for 79C976) must be set; then select the speed, + * duplex, and/or enable auto negotiation, and clear DANAS */ + if (lp->mii && !(lp->options & PCNET32_PORT_ASEL)) { + lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080); + /* disable Auto Negotiation, set 10Mpbs, HD */ + val = lp->a.read_bcr(ioaddr, 32) & ~0xb8; + if (lp->options & PCNET32_PORT_FD) + val |= 0x10; + if (lp->options & PCNET32_PORT_100) + val |= 0x08; + lp->a.write_bcr (ioaddr, 32, val); + } else { + if (lp->options & PCNET32_PORT_ASEL) { + lp->a.write_bcr(ioaddr, 32, lp->a.read_bcr(ioaddr, 32) | 0x0080); + /* enable auto negotiate, setup, disable fd */ + val = lp->a.read_bcr(ioaddr, 32) & ~0x98; + val |= 0x20; + lp->a.write_bcr(ioaddr, 32, val); + } + } } #ifdef DO_DXSUFLO diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/net/tulip/media.c linux-2.6.11/drivers/net/tulip/media.c --- linux.vanilla-2.6.11/drivers/net/tulip/media.c 2005-03-05 15:17:02.000000000 +0000 +++ linux-2.6.11/drivers/net/tulip/media.c 2005-03-06 17:23:44.000000000 +0000 @@ -88,7 +88,7 @@ value = ioread32(ioaddr + CSR9); iowrite32(value & 0xFFEFFFFF, ioaddr + CSR9); - value = (phy_id << 21) | (location << 16) | 0x80000000; + value = (phy_id << 21) | (location << 16) | 0x08000000; iowrite32(value, ioaddr + CSR10); while(--i > 0) { @@ -166,7 +166,7 @@ value = ioread32(ioaddr + CSR9); iowrite32(value & 0xFFEFFFFF, ioaddr + CSR9); - value = (phy_id << 21) | (location << 16) | 0x40000000 | (val & 0xFFFF); + value = (phy_id << 21) | (location << 16) | 0x04000000 | (val & 0xFFFF); iowrite32(value, ioaddr + CSR10); while(--i > 0) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/net/tulip/tulip_core.c linux-2.6.11/drivers/net/tulip/tulip_core.c --- linux.vanilla-2.6.11/drivers/net/tulip/tulip_core.c 2005-03-05 15:17:02.000000000 +0000 +++ linux-2.6.11/drivers/net/tulip/tulip_core.c 2005-03-06 17:24:44.000000000 +0000 @@ -1102,15 +1102,18 @@ entry = tp->cur_tx++ % TX_RING_SIZE; if (entry != 0) { - /* Avoid a chip errata by prefixing a dummy entry. */ - tp->tx_buffers[entry].skb = NULL; - tp->tx_buffers[entry].mapping = 0; - tp->tx_ring[entry].length = - (entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP) : 0; - tp->tx_ring[entry].buffer1 = 0; - /* Must set DescOwned later to avoid race with chip */ - dummy = entry; - entry = tp->cur_tx++ % TX_RING_SIZE; + /* Avoid a chip errata by prefixing a dummy entry. Don't do + this on the ULI526X as it triggers a different problem */ + if (!(tp->chip_id == ULI526X && (tp->revision = 0x40 || tp->revision == 0x50))) { + tp->tx_buffers[entry].skb = NULL; + tp->tx_buffers[entry].mapping = 0; + tp->tx_ring[entry].length = + (entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP) : 0; + tp->tx_ring[entry].buffer1 = 0; + /* Must set DescOwned later to avoid race with chip */ + dummy = entry; + entry = tp->cur_tx++ % TX_RING_SIZE; + } } tp->tx_buffers[entry].skb = NULL; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/pci/pci.ids linux-2.6.11/drivers/pci/pci.ids --- linux.vanilla-2.6.11/drivers/pci/pci.ids 2005-03-05 15:17:04.000000000 +0000 +++ linux-2.6.11/drivers/pci/pci.ids 2005-03-05 16:13:05.000000000 +0000 @@ -4397,6 +4397,10 @@ 8030 AEC6712S SCSI 8040 AEC6712D SCSI 8050 AEC6712SUW SCSI + 8060 AEC6712 + 8080 AEC67160 + 8081 AEC67160S + 808A AEC67162 1192 Densan Company Ltd 1193 Zeitnet Inc. 0001 1221 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/scsi/atp870u.c linux-2.6.11/drivers/scsi/atp870u.c --- linux.vanilla-2.6.11/drivers/scsi/atp870u.c 2005-03-05 15:15:13.000000000 +0000 +++ linux-2.6.11/drivers/scsi/atp870u.c 2005-03-05 16:14:06.000000000 +0000 @@ -1,4 +1,4 @@ -/* +/* * Copyright (C) 1997 Wu Ching Chen * 2.1.x update (C) 1998 Krzysztof G. Baranowski * 2.5.x update (C) 2002 Red Hat @@ -13,8 +13,9 @@ * fix disconnect bug 2000/12/21 * support atp880 chip lvd u160 2001/05/15 * fix prd table bug 2001/09/12 (7.1) + * + * atp885 support add by ACARD Hao Ping Lian 2005/01/05 */ - #include #include #include @@ -38,39 +39,54 @@ #include "atp870u.h" static struct scsi_host_template atp870u_template; -static void send_s870(struct Scsi_Host *host); +void send_s870(struct atp_unit *dev,unsigned char c); +void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c); +void tscam_885(void); - -static irqreturn_t atp870u_intr_handle(int irq, void *dev_id, - struct pt_regs *regs) +static irqreturn_t atp870u_intr_handle(int irq, void *dev_id, struct pt_regs *regs) { unsigned long flags; unsigned short int tmpcip, id; - unsigned char i, j, target_id, lun; + unsigned char i, j, c, target_id, lun,cmdp; unsigned char *prd; - struct scsi_cmnd *workrequ; - unsigned int workportu, tmport; - unsigned long adrcntu, k; + struct scsi_cmnd *workreq; + unsigned int workport, tmport, tmport1; + unsigned long adrcnt, k; +#ifdef ED_DBGP + unsigned long l; +#endif int errstus; struct Scsi_Host *host = dev_id; struct atp_unit *dev = (struct atp_unit *)&host->hostdata; - dev->in_int = 1; - workportu = dev->ioport; - tmport = workportu; - - if (dev->working != 0) { - tmport += 0x1f; + for (c = 0; c < 2; c++) { + tmport = dev->ioport[c] + 0x1f; j = inb(tmport); - if ((j & 0x80) == 0) { - dev->in_int = 0; - return IRQ_NONE; - } - - tmpcip = dev->pciport; - if ((inb(tmpcip) & 0x08) != 0) { + if ((j & 0x80) != 0) + { + goto ch_sel; + } + dev->in_int[c] = 0; + } + return IRQ_NONE; +ch_sel: +#ifdef ED_DBGP + printk("atp870u_intr_handle enter\n"); +#endif + dev->in_int[c] = 1; + cmdp = inb(dev->ioport[c] + 0x10); + workport = dev->ioport[c]; + if (dev->working[c] != 0) { + if (dev->dev_id == ATP885_DEVID) { + tmport1 = workport + 0x16; + if ((inb(tmport1) & 0x80) == 0) + outb((inb(tmport1) | 0x80), tmport1); + } + tmpcip = dev->pciport[c]; + if ((inb(tmpcip) & 0x08) != 0) + { tmpcip += 0x2; - for (k = 0; k < 1000; k++) { + for (k=0; k < 1000; k++) { if ((inb(tmpcip) & 0x08) == 0) { goto stop_dma; } @@ -80,18 +96,24 @@ } } stop_dma: - tmpcip = dev->pciport; + tmpcip = dev->pciport[c]; outb(0x00, tmpcip); tmport -= 0x08; - + i = inb(tmport); + + if (dev->dev_id == ATP885_DEVID) { + tmpcip += 2; + outb(0x06, tmpcip); + tmpcip -= 2; + } tmport -= 0x02; target_id = inb(tmport); tmport += 0x02; /* - * Remap wide devices onto id numbers + * Remap wide devices onto id numbers */ if ((target_id & 0x40) != 0) { @@ -101,332 +123,460 @@ } if ((j & 0x40) != 0) { - if (dev->last_cmd == 0xff) { - dev->last_cmd = target_id; - } - dev->last_cmd |= 0x40; - } - + if (dev->last_cmd[c] == 0xff) { + dev->last_cmd[c] = target_id; + } + dev->last_cmd[c] |= 0x40; + } + if (dev->dev_id == ATP885_DEVID) + dev->r1f[c][target_id] |= j; +#ifdef ED_DBGP + printk("atp870u_intr_handle status = %x\n",i); +#endif if (i == 0x85) { - if ((dev->last_cmd & 0xf0) != 0x40) { - dev->last_cmd = 0xff; + if ((dev->last_cmd[c] & 0xf0) != 0x40) { + dev->last_cmd[c] = 0xff; + } + if (dev->dev_id == ATP885_DEVID) { + tmport -= 0x05; + adrcnt = 0; + ((unsigned char *) &adrcnt)[2] = inb(tmport++); + ((unsigned char *) &adrcnt)[1] = inb(tmport++); + ((unsigned char *) &adrcnt)[0] = inb(tmport); + if (dev->id[c][target_id].last_len != adrcnt) + { + k = dev->id[c][target_id].last_len; + k -= adrcnt; + dev->id[c][target_id].tran_len = k; + dev->id[c][target_id].last_len = adrcnt; + } +#ifdef ED_DBGP + printk("tmport = %x dev->id[c][target_id].last_len = %d dev->id[c][target_id].tran_len = %d\n",tmport,dev->id[c][target_id].last_len,dev->id[c][target_id].tran_len); +#endif } + /* * Flip wide - */ - if (dev->wide_idu != 0) { - tmport = workportu + 0x1b; + */ + if (dev->wide_id[c] != 0) { + tmport = workport + 0x1b; outb(0x01, tmport); while ((inb(tmport) & 0x01) != 0x01) { outb(0x01, tmport); } - } + } /* - * Issue more commands + * Issue more commands */ - spin_lock_irqsave(dev->host->host_lock, flags); - if (((dev->quhdu != dev->quendu) || (dev->last_cmd != 0xff)) && (dev->in_snd == 0)) { - send_s870(host); + spin_lock_irqsave(dev->host->host_lock, flags); + if (((dev->quhd[c] != dev->quend[c]) || (dev->last_cmd[c] != 0xff)) && + (dev->in_snd[c] == 0)) { +#ifdef ED_DBGP + printk("Call sent_s870\n"); +#endif + send_s870(dev,c); } spin_unlock_irqrestore(dev->host->host_lock, flags); /* - * Done + * Done */ - dev->in_int = 0; - goto out; + dev->in_int[c] = 0; +#ifdef ED_DBGP + printk("Status 0x85 return\n"); +#endif + goto handled; } if (i == 0x40) { - dev->last_cmd |= 0x40; - dev->in_int = 0; - goto out; + dev->last_cmd[c] |= 0x40; + dev->in_int[c] = 0; + goto handled; } if (i == 0x21) { - if ((dev->last_cmd & 0xf0) != 0x40) { - dev->last_cmd = 0xff; + if ((dev->last_cmd[c] & 0xf0) != 0x40) { + dev->last_cmd[c] = 0xff; } tmport -= 0x05; - adrcntu = 0; - ((unsigned char *) &adrcntu)[2] = inb(tmport++); - ((unsigned char *) &adrcntu)[1] = inb(tmport++); - ((unsigned char *) &adrcntu)[0] = inb(tmport); - k = dev->id[target_id].last_lenu; - k -= adrcntu; - dev->id[target_id].tran_lenu = k; - dev->id[target_id].last_lenu = adrcntu; + adrcnt = 0; + ((unsigned char *) &adrcnt)[2] = inb(tmport++); + ((unsigned char *) &adrcnt)[1] = inb(tmport++); + ((unsigned char *) &adrcnt)[0] = inb(tmport); + k = dev->id[c][target_id].last_len; + k -= adrcnt; + dev->id[c][target_id].tran_len = k; + dev->id[c][target_id].last_len = adrcnt; tmport -= 0x04; outb(0x41, tmport); tmport += 0x08; outb(0x08, tmport); - dev->in_int = 0; - goto out; + dev->in_int[c] = 0; + goto handled; + } + + if (dev->dev_id == ATP885_DEVID) { + if ((i == 0x4c) || (i == 0x4d) || (i == 0x8c) || (i == 0x8d)) { + if ((i == 0x4c) || (i == 0x8c)) + i=0x48; + else + i=0x49; + } + } if ((i == 0x80) || (i == 0x8f)) { +#ifdef ED_DBGP + printk(KERN_DEBUG "Device reselect\n"); +#endif lun = 0; tmport -= 0x07; - j = inb(tmport); - if (j == 0x44 || i == 0x80) { + if (cmdp == 0x44 || i==0x80) { tmport += 0x0d; lun = inb(tmport) & 0x07; } else { - if ((dev->last_cmd & 0xf0) != 0x40) { - dev->last_cmd = 0xff; + if ((dev->last_cmd[c] & 0xf0) != 0x40) { + dev->last_cmd[c] = 0xff; } - if (j == 0x41) { + if (cmdp == 0x41) { +#ifdef ED_DBGP + printk("cmdp = 0x41\n"); +#endif tmport += 0x02; - adrcntu = 0; - ((unsigned char *) &adrcntu)[2] = inb(tmport++); - ((unsigned char *) &adrcntu)[1] = inb(tmport++); - ((unsigned char *) &adrcntu)[0] = inb(tmport); - k = dev->id[target_id].last_lenu; - k -= adrcntu; - dev->id[target_id].tran_lenu = k; - dev->id[target_id].last_lenu = adrcntu; + adrcnt = 0; + ((unsigned char *) &adrcnt)[2] = inb(tmport++); + ((unsigned char *) &adrcnt)[1] = inb(tmport++); + ((unsigned char *) &adrcnt)[0] = inb(tmport); + k = dev->id[c][target_id].last_len; + k -= adrcnt; + dev->id[c][target_id].tran_len = k; + dev->id[c][target_id].last_len = adrcnt; tmport += 0x04; outb(0x08, tmport); - dev->in_int = 0; - goto out; + dev->in_int[c] = 0; + goto handled; } else { +#ifdef ED_DBGP + printk("cmdp != 0x41\n"); +#endif outb(0x46, tmport); - dev->id[target_id].dirctu = 0x00; + dev->id[c][target_id].dirct = 0x00; tmport += 0x02; outb(0x00, tmport++); outb(0x00, tmport++); outb(0x00, tmport++); tmport += 0x03; outb(0x08, tmport); - dev->in_int = 0; - goto out; + dev->in_int[c] = 0; + goto handled; } } - if (dev->last_cmd != 0xff) { - dev->last_cmd |= 0x40; + if (dev->last_cmd[c] != 0xff) { + dev->last_cmd[c] |= 0x40; } - tmport = workportu + 0x10; - outb(0x45, tmport); - tmport += 0x06; + if (dev->dev_id == ATP885_DEVID) { + j = inb(dev->baseport + 0x29) & 0xfe; + outb(j, dev->baseport + 0x29); + tmport = workport + 0x16; + } else { + tmport = workport + 0x10; + outb(0x45, tmport); + tmport += 0x06; + } + target_id = inb(tmport); /* - * Remap wide identifiers + * Remap wide identifiers */ if ((target_id & 0x10) != 0) { target_id = (target_id & 0x07) | 0x08; } else { target_id &= 0x07; } - workrequ = dev->id[target_id].curr_req; - tmport = workportu + 0x0f; + if (dev->dev_id == ATP885_DEVID) { + tmport = workport + 0x10; + outb(0x45, tmport); + } + workreq = dev->id[c][target_id].curr_req; +#ifdef ED_DBGP + printk(KERN_DEBUG "Channel = %d ID = %d LUN = %d CDB",c,workreq->device->id,workreq->device->lun); + for(l=0;lcmd_len;l++) + { + printk(KERN_DEBUG " %x",workreq->cmnd[l]); + } +#endif + + tmport = workport + 0x0f; outb(lun, tmport); tmport += 0x02; - outb(dev->id[target_id].devspu, tmport++); - adrcntu = dev->id[target_id].tran_lenu; - k = dev->id[target_id].last_lenu; + outb(dev->id[c][target_id].devsp, tmport++); + adrcnt = dev->id[c][target_id].tran_len; + k = dev->id[c][target_id].last_len; + outb(((unsigned char *) &k)[2], tmport++); outb(((unsigned char *) &k)[1], tmport++); outb(((unsigned char *) &k)[0], tmport++); +#ifdef ED_DBGP + printk("k %x, k[0] 0x%x k[1] 0x%x k[2] 0x%x\n", k, inb(tmport-1), inb(tmport-2), inb(tmport-3)); +#endif /* Remap wide */ j = target_id; if (target_id > 7) { j = (j & 0x07) | 0x40; } /* Add direction */ - j |= dev->id[target_id].dirctu; + j |= dev->id[c][target_id].dirct; outb(j, tmport++); - outb(0x80, tmport); - - /* enable 32 bit fifo transfer */ - if (dev->deviceid != 0x8081) { - tmport = workportu + 0x3a; - if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) { - outb((unsigned char) ((inb(tmport) & 0xf3) | 0x08), tmport); - } else { - outb((unsigned char) (inb(tmport) & 0xf3), tmport); + outb(0x80,tmport); + + /* enable 32 bit fifo transfer */ + if (dev->dev_id == ATP885_DEVID) { + tmpcip = dev->pciport[c] + 1; + i=inb(tmpcip) & 0xf3; + //j=workreq->cmnd[0]; + if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) { + i |= 0x0c; } - } else { - tmport = workportu - 0x05; - if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) { + outb(i,tmpcip); + } else if ((dev->dev_id == ATP880_DEVID1) || + (dev->dev_id == ATP880_DEVID2) ) { + tmport = workport - 0x05; + if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) { outb((unsigned char) ((inb(tmport) & 0x3f) | 0xc0), tmport); } else { outb((unsigned char) (inb(tmport) & 0x3f), tmport); } - } - - tmport = workportu + 0x1b; + } else { + tmport = workport + 0x3a; + if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) { + outb((unsigned char) ((inb(tmport) & 0xf3) | 0x08), tmport); + } else { + outb((unsigned char) (inb(tmport) & 0xf3), tmport); + } + } + tmport = workport + 0x1b; j = 0; id = 1; id = id << target_id; /* - * Is this a wide device + * Is this a wide device */ - if ((id & dev->wide_idu) != 0) { + if ((id & dev->wide_id[c]) != 0) { j |= 0x01; } outb(j, tmport); while ((inb(tmport) & 0x01) != j) { - outb(j, tmport); + outb(j,tmport); } - - if (dev->id[target_id].last_lenu == 0) { - tmport = workportu + 0x18; + if (dev->id[c][target_id].last_len == 0) { + tmport = workport + 0x18; outb(0x08, tmport); - dev->in_int = 0; - goto out; - } - prd = dev->id[target_id].prd_posu; - while (adrcntu != 0) { - id = ((unsigned short int *) (prd))[2]; + dev->in_int[c] = 0; +#ifdef ED_DBGP + printk("dev->id[c][target_id].last_len = 0\n"); +#endif + goto handled; + } +#ifdef ED_DBGP + printk("target_id = %d adrcnt = %d\n",target_id,adrcnt); +#endif + prd = dev->id[c][target_id].prd_pos; + while (adrcnt != 0) { + id = ((unsigned short int *)prd)[2]; if (id == 0) { k = 0x10000; } else { k = id; } - if (k > adrcntu) { - ((unsigned short int *) (prd))[2] = (unsigned short int) - (k - adrcntu); - ((unsigned long *) (prd))[0] += adrcntu; - adrcntu = 0; - dev->id[target_id].prd_posu = prd; + if (k > adrcnt) { + ((unsigned short int *)prd)[2] = (unsigned short int) + (k - adrcnt); + ((unsigned long *)prd)[0] += adrcnt; + adrcnt = 0; + dev->id[c][target_id].prd_pos = prd; } else { - adrcntu -= k; - dev->id[target_id].prdaddru += 0x08; + adrcnt -= k; + dev->id[c][target_id].prdaddr += 0x08; prd += 0x08; - if (adrcntu == 0) { - dev->id[target_id].prd_posu = prd; + if (adrcnt == 0) { + dev->id[c][target_id].prd_pos = prd; } - } + } } - tmpcip = dev->pciport + 0x04; - outl(dev->id[target_id].prdaddru, tmpcip); - tmpcip -= 0x02; - outb(0x06, tmpcip); - outb(0x00, tmpcip); - tmpcip -= 0x02; - tmport = workportu + 0x18; + tmpcip = dev->pciport[c] + 0x04; + outl(dev->id[c][target_id].prdaddr, tmpcip); +#ifdef ED_DBGP + printk("dev->id[%d][%d].prdaddr 0x%8x\n", c, target_id, dev->id[c][target_id].prdaddr); +#endif + if (dev->dev_id == ATP885_DEVID) { + tmpcip -= 0x04; + } else { + tmpcip -= 0x02; + outb(0x06, tmpcip); + outb(0x00, tmpcip); + tmpcip -= 0x02; + } + tmport = workport + 0x18; /* - * Check transfer direction + * Check transfer direction */ - if (dev->id[target_id].dirctu != 0) { + if (dev->id[c][target_id].dirct != 0) { outb(0x08, tmport); outb(0x01, tmpcip); - dev->in_int = 0; - goto out; + dev->in_int[c] = 0; +#ifdef ED_DBGP + printk("status 0x80 return dirct != 0\n"); +#endif + goto handled; } outb(0x08, tmport); outb(0x09, tmpcip); - dev->in_int = 0; - goto out; + dev->in_int[c] = 0; +#ifdef ED_DBGP + printk("status 0x80 return dirct = 0\n"); +#endif + goto handled; } /* - * Current scsi request on this target + * Current scsi request on this target */ - workrequ = dev->id[target_id].curr_req; + workreq = dev->id[c][target_id].curr_req; if (i == 0x42) { - if ((dev->last_cmd & 0xf0) != 0x40) { - dev->last_cmd = 0xff; + if ((dev->last_cmd[c] & 0xf0) != 0x40) + { + dev->last_cmd[c] = 0xff; } errstus = 0x02; - workrequ->result = errstus; + workreq->result = errstus; goto go_42; } if (i == 0x16) { - if ((dev->last_cmd & 0xf0) != 0x40) { - dev->last_cmd = 0xff; + if ((dev->last_cmd[c] & 0xf0) != 0x40) { + dev->last_cmd[c] = 0xff; } errstus = 0; tmport -= 0x08; errstus = inb(tmport); - workrequ->result = errstus; + if (((dev->r1f[c][target_id] & 0x10) != 0)&&(dev->dev_id==ATP885_DEVID)) { + printk(KERN_WARNING "AEC67162 CRC ERROR !\n"); + errstus = 0x02; + } + workreq->result = errstus; go_42: + if (dev->dev_id == ATP885_DEVID) { + j = inb(dev->baseport + 0x29) | 0x01; + outb(j, dev->baseport + 0x29); + } /* - * Complete the command + * Complete the command */ - - if (workrequ->use_sg) { + if (workreq->use_sg) { pci_unmap_sg(dev->pdev, - (struct scatterlist *)workrequ->buffer, - workrequ->use_sg, - workrequ->sc_data_direction); - } else if (workrequ->request_bufflen && - workrequ->sc_data_direction != DMA_NONE) { + (struct scatterlist *)workreq->buffer, + workreq->use_sg, + workreq->sc_data_direction); + } else if (workreq->request_bufflen && + workreq->sc_data_direction != DMA_NONE) { pci_unmap_single(dev->pdev, - workrequ->SCp.dma_handle, - workrequ->request_bufflen, - workrequ->sc_data_direction); - } + workreq->SCp.dma_handle, + workreq->request_bufflen, + workreq->sc_data_direction); + } spin_lock_irqsave(dev->host->host_lock, flags); - (*workrequ->scsi_done) (workrequ); - + (*workreq->scsi_done) (workreq); +#ifdef ED_DBGP + printk("workreq->scsi_done\n"); +#endif /* - * Clear it off the queue + * Clear it off the queue */ - dev->id[target_id].curr_req = NULL; - dev->working--; + dev->id[c][target_id].curr_req = 0; + dev->working[c]--; spin_unlock_irqrestore(dev->host->host_lock, flags); /* * Take it back wide */ - if (dev->wide_idu != 0) { - tmport = workportu + 0x1b; + if (dev->wide_id[c] != 0) { + tmport = workport + 0x1b; outb(0x01, tmport); while ((inb(tmport) & 0x01) != 0x01) { outb(0x01, tmport); - } - } + } + } /* - * If there is stuff to send and nothing going then send it + * If there is stuff to send and nothing going then send it */ spin_lock_irqsave(dev->host->host_lock, flags); - if (((dev->last_cmd != 0xff) || (dev->quhdu != dev->quendu)) && (dev->in_snd == 0)) { - send_s870(host); + if (((dev->last_cmd[c] != 0xff) || (dev->quhd[c] != dev->quend[c])) && + (dev->in_snd[c] == 0)) { +#ifdef ED_DBGP + printk("Call sent_s870(scsi_done)\n"); +#endif + send_s870(dev,c); } spin_unlock_irqrestore(dev->host->host_lock, flags); - dev->in_int = 0; - goto out; + dev->in_int[c] = 0; + goto handled; } - if ((dev->last_cmd & 0xf0) != 0x40) { - dev->last_cmd = 0xff; + if ((dev->last_cmd[c] & 0xf0) != 0x40) { + dev->last_cmd[c] = 0xff; } if (i == 0x4f) { i = 0x89; } i &= 0x0f; if (i == 0x09) { - tmpcip = tmpcip + 4; - outl(dev->id[target_id].prdaddru, tmpcip); + tmpcip += 4; + outl(dev->id[c][target_id].prdaddr, tmpcip); tmpcip = tmpcip - 2; outb(0x06, tmpcip); outb(0x00, tmpcip); tmpcip = tmpcip - 2; - tmport = workportu + 0x10; + tmport = workport + 0x10; outb(0x41, tmport); - dev->id[target_id].dirctu = 0x00; - tmport += 0x08; + if (dev->dev_id == ATP885_DEVID) { + tmport += 2; + k = dev->id[c][target_id].last_len; + outb((unsigned char) (((unsigned char *) (&k))[2]), tmport++); + outb((unsigned char) (((unsigned char *) (&k))[1]), tmport++); + outb((unsigned char) (((unsigned char *) (&k))[0]), tmport); + dev->id[c][target_id].dirct = 0x00; + tmport += 0x04; + } else { + dev->id[c][target_id].dirct = 0x00; + tmport += 0x08; + } outb(0x08, tmport); outb(0x09, tmpcip); - dev->in_int = 0; - goto out; + dev->in_int[c] = 0; + goto handled; } if (i == 0x08) { - tmpcip = tmpcip + 4; - outl(dev->id[target_id].prdaddru, tmpcip); + tmpcip += 4; + outl(dev->id[c][target_id].prdaddr, tmpcip); tmpcip = tmpcip - 2; outb(0x06, tmpcip); outb(0x00, tmpcip); tmpcip = tmpcip - 2; - tmport = workportu + 0x10; + tmport = workport + 0x10; outb(0x41, tmport); - tmport += 0x05; + if (dev->dev_id == ATP885_DEVID) { + tmport += 2; + k = dev->id[c][target_id].last_len; + outb((unsigned char) (((unsigned char *) (&k))[2]), tmport++); + outb((unsigned char) (((unsigned char *) (&k))[1]), tmport++); + outb((unsigned char) (((unsigned char *) (&k))[0]), tmport++); + } else { + tmport += 5; + } outb((unsigned char) (inb(tmport) | 0x20), tmport); - dev->id[target_id].dirctu = 0x20; + dev->id[c][target_id].dirct = 0x20; tmport += 0x03; outb(0x08, tmport); outb(0x01, tmpcip); - dev->in_int = 0; - goto out; + dev->in_int[c] = 0; + goto handled; } tmport -= 0x07; if (i == 0x0a) { @@ -434,25 +584,29 @@ } else { outb(0x46, tmport); } - dev->id[target_id].dirctu = 0x00; + dev->id[c][target_id].dirct = 0x00; tmport += 0x02; outb(0x00, tmport++); outb(0x00, tmport++); outb(0x00, tmport++); tmport += 0x03; outb(0x08, tmport); - dev->in_int = 0; - goto out; + dev->in_int[c] = 0; + goto handled; } else { -// tmport = workportu + 0x17; -// inb(tmport); -// dev->working = 0; - dev->in_int = 0; +// tmport = workport + 0x17; +// inb(tmport); +// dev->working[c] = 0; + dev->in_int[c] = 0; + goto handled; } -out: + +handled: +#ifdef ED_DBGP + printk("atp870u_intr_handle exit\n"); +#endif return IRQ_HANDLED; } - /** * atp870u_queuecommand - Queue SCSI command * @req_p: request block @@ -460,24 +614,30 @@ * * Queue a command to the ATP queue. Called with the host lock held. */ - -static int atp870u_queuecommand(struct scsi_cmnd *req_p, - void (*done) (struct scsi_cmnd *)) +int atp870u_queuecommand(struct scsi_cmnd * req_p, void (*done) (struct scsi_cmnd *)) { - unsigned short int m; - unsigned int tmport; - struct Scsi_Host *host; + unsigned char c; + unsigned int tmport,m; struct atp_unit *dev; + struct Scsi_Host *host; - if (req_p->device->channel != 0) { + c = req_p->device->channel; + req_p->sense_buffer[0]=0; + req_p->resid = 0; + if (req_p->device->channel > 1) { req_p->result = 0x00040000; done(req_p); +#ifdef ED_DBGP + printk("atp870u_queuecommand : req_p->device->channel > 1\n"); +#endif return 0; - }; + } host = req_p->device->host; dev = (struct atp_unit *)&host->hostdata; - + + + m = 1; m = m << req_p->device->id; @@ -485,44 +645,60 @@ * Fake a timeout for missing targets */ - if ((m & dev->active_idu) == 0) { + if ((m & dev->active_id[c]) == 0) { req_p->result = 0x00040000; done(req_p); return 0; } + if (done) { req_p->scsi_done = done; } else { - printk(KERN_WARNING "atp870u_queuecommand: done can't be NULL\n"); +#ifdef ED_DBGP + printk( "atp870u_queuecommand: done can't be NULL\n"); +#endif req_p->result = 0; done(req_p); return 0; } + /* - * Count new command + * Count new command */ - - dev->quendu++; - if (dev->quendu >= qcnt) { - dev->quendu = 0; + dev->quend[c]++; + if (dev->quend[c] >= qcnt) { + dev->quend[c] = 0; } + /* - * Check queue state + * Check queue state */ - if (dev->quhdu == dev->quendu) { - if (dev->quendu == 0) { - dev->quendu = qcnt; - } - dev->quendu--; + if (dev->quhd[c] == dev->quend[c]) { + if (dev->quend[c] == 0) { + dev->quend[c] = qcnt; + } +#ifdef ED_DBGP + printk("atp870u_queuecommand : dev->quhd[c] == dev->quend[c]\n"); +#endif + dev->quend[c]--; req_p->result = 0x00020000; - done(req_p); + done(req_p); return 0; } - dev->querequ[dev->quendu] = req_p; - tmport = dev->ioport + 0x1c; - if ((inb(tmport) == 0) && (dev->in_int == 0) && (dev->in_snd == 0)) { - send_s870(host); - } + dev->quereq[c][dev->quend[c]] = req_p; + tmport = dev->ioport[c] + 0x1c; +#ifdef ED_DBGP + printk("dev->ioport[c] = %x inb(tmport) = %x dev->in_int[%d] = %d dev->in_snd[%d] = %d\n",dev->ioport[c],inb(tmport),c,dev->in_int[c],c,dev->in_snd[c]); +#endif + if ((inb(tmport) == 0) && (dev->in_int[c] == 0) && (dev->in_snd[c] == 0)) { +#ifdef ED_DBGP + printk("Call sent_s870(atp870u_queuecommand)\n"); +#endif + send_s870(dev,c); + } +#ifdef ED_DBGP + printk("atp870u_queuecommand : exit\n"); +#endif return 0; } @@ -535,194 +711,270 @@ * * Caller holds the host lock. */ - -static void send_s870(struct Scsi_Host *host) +void send_s870(struct atp_unit *dev,unsigned char c) { unsigned int tmport; - struct scsi_cmnd *workrequ; - unsigned int i; - unsigned char j, target_id; + struct scsi_cmnd *workreq; + unsigned int i;//,k; + unsigned char j, target_id; unsigned char *prd; unsigned short int tmpcip, w; - unsigned long l; - dma_addr_t bttl; - unsigned int workportu; + unsigned long l, bttl = 0; + unsigned int workport; struct scatterlist *sgpnt; - struct atp_unit *dev = (struct atp_unit *)&host->hostdata; - int sg_count; + unsigned long sg_count; - if (dev->in_snd != 0) { - return; - } - dev->in_snd = 1; - if ((dev->last_cmd != 0xff) && ((dev->last_cmd & 0x40) != 0)) { - dev->last_cmd &= 0x0f; - workrequ = dev->id[dev->last_cmd].curr_req; - if (workrequ != NULL) { /* check NULL pointer */ - goto cmd_subp; - } - dev->last_cmd = 0xff; - if (dev->quhdu == dev->quendu) { - dev->in_snd = 0; - return; - } - } - if ((dev->last_cmd != 0xff) && (dev->working != 0)) { - dev->in_snd = 0; + if (dev->in_snd[c] != 0) { +#ifdef ED_DBGP + printk("cmnd in_snd\n"); +#endif return; } - dev->working++; - j = dev->quhdu; - dev->quhdu++; - if (dev->quhdu >= qcnt) { - dev->quhdu = 0; - } - workrequ = dev->querequ[dev->quhdu]; - if (dev->id[workrequ->device->id].curr_req == 0) { - dev->id[workrequ->device->id].curr_req = workrequ; - dev->last_cmd = workrequ->device->id; +#ifdef ED_DBGP + printk("Sent_s870 enter\n"); +#endif + dev->in_snd[c] = 1; + if ((dev->last_cmd[c] != 0xff) && ((dev->last_cmd[c] & 0x40) != 0)) { + dev->last_cmd[c] &= 0x0f; + workreq = dev->id[c][dev->last_cmd[c]].curr_req; + if (workreq != NULL) { /* check NULL pointer */ + goto cmd_subp; + } + dev->last_cmd[c] = 0xff; + if (dev->quhd[c] == dev->quend[c]) { + dev->in_snd[c] = 0; + return ; + } + } + if ((dev->last_cmd[c] != 0xff) && (dev->working[c] != 0)) { + dev->in_snd[c] = 0; + return ; + } + dev->working[c]++; + j = dev->quhd[c]; + dev->quhd[c]++; + if (dev->quhd[c] >= qcnt) { + dev->quhd[c] = 0; + } + workreq = dev->quereq[c][dev->quhd[c]]; + if (dev->id[c][workreq->device->id].curr_req == 0) { + dev->id[c][workreq->device->id].curr_req = workreq; + dev->last_cmd[c] = workreq->device->id; goto cmd_subp; - } - dev->quhdu = j; - dev->working--; - dev->in_snd = 0; + } + dev->quhd[c] = j; + dev->working[c]--; + dev->in_snd[c] = 0; return; cmd_subp: - workportu = dev->ioport; - tmport = workportu + 0x1f; + workport = dev->ioport[c]; + tmport = workport + 0x1f; if ((inb(tmport) & 0xb0) != 0) { goto abortsnd; } - tmport = workportu + 0x1c; + tmport = workport + 0x1c; if (inb(tmport) == 0) { goto oktosend; } abortsnd: - dev->last_cmd |= 0x40; - dev->in_snd = 0; +#ifdef ED_DBGP + printk("Abort to Send\n"); +#endif + dev->last_cmd[c] |= 0x40; + dev->in_snd[c] = 0; return; oktosend: - memcpy(&dev->ata_cdbu[0], &workrequ->cmnd[0], workrequ->cmd_len); - if (dev->ata_cdbu[0] == READ_CAPACITY) { - if (workrequ->request_bufflen > 8) { - workrequ->request_bufflen = 0x08; +#ifdef ED_DBGP + printk("OK to Send\n"); + printk("CDB"); + for(i=0;icmd_len;i++) { + printk(" %x",workreq->cmnd[i]); + } + printk("\nChannel = %d ID = %d LUN = %d\n",c,workreq->device->id,workreq->device->lun); +#endif + if (dev->dev_id == ATP885_DEVID) { + j = inb(dev->baseport + 0x29) & 0xfe; + outb(j, dev->baseport + 0x29); + dev->r1f[c][workreq->device->id] = 0; + } + + if (workreq->cmnd[0] == READ_CAPACITY) { + if (workreq->request_bufflen > 8) { + workreq->request_bufflen = 0x08; } } - if (dev->ata_cdbu[0] == 0x00) { - workrequ->request_bufflen = 0; + if (workreq->cmnd[0] == 0x00) { + workreq->request_bufflen = 0; } - tmport = workportu + 0x1b; + tmport = workport + 0x1b; j = 0; - target_id = workrequ->device->id; + target_id = workreq->device->id; /* - * Wide ? + * Wide ? */ w = 1; w = w << target_id; - if ((w & dev->wide_idu) != 0) { + if ((w & dev->wide_id[c]) != 0) { j |= 0x01; } outb(j, tmport); while ((inb(tmport) & 0x01) != j) { - outb(j, tmport); + outb(j,tmport); +#ifdef ED_DBGP + printk("send_s870 while loop 1\n"); +#endif } - /* - * Write the command + * Write the command */ - tmport = workportu; - outb(workrequ->cmd_len, tmport++); + tmport = workport; + outb(workreq->cmd_len, tmport++); outb(0x2c, tmport++); - outb(0xcf, tmport++); - for (i = 0; i < workrequ->cmd_len; i++) { - outb(dev->ata_cdbu[i], tmport++); + if (dev->dev_id == ATP885_DEVID) { + outb(0x7f, tmport++); + } else { + outb(0xcf, tmport++); + } + for (i = 0; i < workreq->cmd_len; i++) { + outb(workreq->cmnd[i], tmport++); } - tmport = workportu + 0x0f; - outb(workrequ->device->lun, tmport); + tmport = workport + 0x0f; + outb(workreq->device->lun, tmport); tmport += 0x02; /* - * Write the target + * Write the target */ - outb(dev->id[target_id].devspu, tmport++); - + outb(dev->id[c][target_id].devsp, tmport++); +#ifdef ED_DBGP + printk("dev->id[%d][%d].devsp = %2x\n",c,target_id,dev->id[c][target_id].devsp); +#endif /* - * Figure out the transfer size + * Figure out the transfer size */ - if (workrequ->use_sg) { + if (workreq->use_sg) { +#ifdef ED_DBGP + printk("Using SGL\n"); +#endif l = 0; - sgpnt = (struct scatterlist *) workrequ->request_buffer; - sg_count = pci_map_sg(dev->pdev, sgpnt, workrequ->use_sg, - workrequ->sc_data_direction); - for (i = 0; i < workrequ->use_sg; i++) { - if (sgpnt[i].length == 0 || workrequ->use_sg > ATP870U_SCATTER) { + + sgpnt = (struct scatterlist *) workreq->request_buffer; + sg_count = pci_map_sg(dev->pdev, sgpnt, workreq->use_sg, + workreq->sc_data_direction); + + for (i = 0; i < workreq->use_sg; i++) { + if (sgpnt[i].length == 0 || workreq->use_sg > ATP870U_SCATTER) { panic("Foooooooood fight!"); } l += sgpnt[i].length; } - } else if(workrequ->request_bufflen && workrequ->sc_data_direction != PCI_DMA_NONE) { - workrequ->SCp.dma_handle = pci_map_single(dev->pdev, - workrequ->request_buffer, - workrequ->request_bufflen, - workrequ->sc_data_direction); - l = workrequ->request_bufflen; - } - else l = 0; +#ifdef ED_DBGP + printk( "send_s870: workreq->use_sg %d, sg_count %d l %8ld\n", workreq->use_sg, sg_count, l); +#endif + } else if(workreq->request_bufflen && workreq->sc_data_direction != PCI_DMA_NONE) { +#ifdef ED_DBGP + printk("Not using SGL\n"); +#endif + workreq->SCp.dma_handle = pci_map_single(dev->pdev, workreq->request_buffer, + workreq->request_bufflen, + workreq->sc_data_direction); + l = workreq->request_bufflen; +#ifdef ED_DBGP + printk( "send_s870: workreq->use_sg %d, l %8ld\n", workreq->use_sg, l); +#endif + } else l = 0; /* - * Write transfer size + * Write transfer size */ outb((unsigned char) (((unsigned char *) (&l))[2]), tmport++); outb((unsigned char) (((unsigned char *) (&l))[1]), tmport++); outb((unsigned char) (((unsigned char *) (&l))[0]), tmport++); - j = target_id; - dev->id[j].last_lenu = l; - dev->id[j].tran_lenu = 0; + j = target_id; + dev->id[c][j].last_len = l; + dev->id[c][j].tran_len = 0; +#ifdef ED_DBGP + printk("dev->id[%2d][%2d].last_len = %d\n",c,j,dev->id[c][j].last_len); +#endif /* - * Flip the wide bits + * Flip the wide bits */ if ((j & 0x08) != 0) { j = (j & 0x07) | 0x40; } /* - * Check transfer direction + * Check transfer direction */ - if (workrequ->sc_data_direction == DMA_TO_DEVICE) { + if (workreq->sc_data_direction == DMA_TO_DEVICE) { outb((unsigned char) (j | 0x20), tmport++); } else { outb(j, tmport++); } outb((unsigned char) (inb(tmport) | 0x80), tmport); outb(0x80, tmport); - tmport = workportu + 0x1c; - dev->id[target_id].dirctu = 0; + tmport = workport + 0x1c; + dev->id[c][target_id].dirct = 0; if (l == 0) { if (inb(tmport) == 0) { - tmport = workportu + 0x18; + tmport = workport + 0x18; +#ifdef ED_DBGP + printk("change SCSI_CMD_REG 0x08\n"); +#endif outb(0x08, tmport); } else { - dev->last_cmd |= 0x40; + dev->last_cmd[c] |= 0x40; } - dev->in_snd = 0; + dev->in_snd[c] = 0; return; } - tmpcip = dev->pciport; - prd = dev->id[target_id].prd_tableu; - dev->id[target_id].prd_posu = prd; + tmpcip = dev->pciport[c]; + prd = dev->id[c][target_id].prd_table; + dev->id[c][target_id].prd_pos = prd; /* - * Now write the request list. Either as scatter/gather or as - * a linear chain. + * Now write the request list. Either as scatter/gather or as + * a linear chain. */ - if (workrequ->use_sg) { - sgpnt = (struct scatterlist *) workrequ->request_buffer; + if (workreq->use_sg) { + sgpnt = (struct scatterlist *) workreq->request_buffer; i = 0; - for (j = 0; j < workrequ->use_sg; j++) { + for (j = 0; j < workreq->use_sg; j++) { bttl = sg_dma_address(&sgpnt[j]); - l = sg_dma_len(&sgpnt[j]); + l=sg_dma_len(&sgpnt[j]); +#ifdef ED_DBGP + printk("1. bttl %x, l %x\n",bttl, l); +#endif while (l > 0x10000) { + (((u16 *) (prd))[i + 3]) = 0x0000; + (((u16 *) (prd))[i + 2]) = 0x0000; + (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl); + l -= 0x10000; + bttl += 0x10000; + i += 0x04; + } + (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl); + (((u16 *) (prd))[i + 2]) = cpu_to_le16(l); + (((u16 *) (prd))[i + 3]) = 0; + i += 0x04; + } + (((u16 *) (prd))[i - 1]) = cpu_to_le16(0x8000); +#ifdef ED_DBGP + printk("prd %4x %4x %4x %4x\n",(((unsigned short int *)prd)[0]),(((unsigned short int *)prd)[1]),(((unsigned short int *)prd)[2]),(((unsigned short int *)prd)[3])); + printk("2. bttl %x, l %x\n",bttl, l); +#endif + } else { + /* + * For a linear request write a chain of blocks + */ + bttl = workreq->SCp.dma_handle; + l = workreq->request_bufflen; + i = 0; +#ifdef ED_DBGP + printk("3. bttl %x, l %x\n",bttl, l); +#endif + while (l > 0x10000) { (((u16 *) (prd))[i + 3]) = 0x0000; (((u16 *) (prd))[i + 2]) = 0x0000; (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl); @@ -730,76 +982,84 @@ bttl += 0x10000; i += 0x04; } - (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl); + (((u16 *) (prd))[i + 3]) = cpu_to_le16(0x8000); (((u16 *) (prd))[i + 2]) = cpu_to_le16(l); - (((u16 *) (prd))[i + 3]) = 0; - i += 0x04; - } - (((u16 *) (prd))[i - 1]) = cpu_to_le16(0x8000); - } else { - /* - * For a linear request write a chain of blocks - */ - bttl = workrequ->SCp.dma_handle; - l = workrequ->request_bufflen; - i = 0; - while (l > 0x10000) { - (((u16 *) (prd))[i + 3]) = 0x0000; - (((u16 *) (prd))[i + 2]) = 0x0000; - (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl); - l -= 0x10000; - bttl += 0x10000; - i += 0x04; - } - (((u16 *) (prd))[i + 3]) = cpu_to_le16(0x8000); - (((u16 *) (prd))[i + 2]) = cpu_to_le16(l); - (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl); - } - tmpcip = tmpcip + 4; - dev->id[target_id].prdaddru = dev->id[target_id].prd_phys; - outl(dev->id[target_id].prd_phys, tmpcip); + (((u32 *) (prd))[i >> 1]) = cpu_to_le32(bttl); +#ifdef ED_DBGP + printk("prd %4x %4x %4x %4x\n",(((unsigned short int *)prd)[0]),(((unsigned short int *)prd)[1]),(((unsigned short int *)prd)[2]),(((unsigned short int *)prd)[3])); + printk("4. bttl %x, l %x\n",bttl, l); +#endif + + } + tmpcip += 4; +#ifdef ED_DBGP + printk("send_s870: prdaddr_1 0x%8x\n", dev->id[c][target_id].prdaddr); +#endif + dev->id[c][target_id].prdaddr = virt_to_bus(dev->id[c][target_id].prd_table); +#ifdef ED_DBGP + printk("send_s870: prdaddr_2 0x%8x tmpcip %x target_id %d\n", dev->id[c][target_id].prdaddr,tmpcip,target_id); +#endif + outl(dev->id[c][target_id].prdaddr, tmpcip); tmpcip = tmpcip - 2; outb(0x06, tmpcip); outb(0x00, tmpcip); - tmpcip = tmpcip - 2; - - if (dev->deviceid != 0x8081) { - tmport = workportu + 0x3a; - if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) { - outb((inb(tmport) & 0xf3) | 0x08, tmport); - } else { - outb(inb(tmport) & 0xf3, tmport); - } - } else { - tmport = workportu - 0x05; - if ((dev->ata_cdbu[0] == 0x08) || (dev->ata_cdbu[0] == 0x28) || (dev->ata_cdbu[0] == 0x0a) || (dev->ata_cdbu[0] == 0x2a)) { + if (dev->dev_id == ATP885_DEVID) { + tmpcip--; + j=inb(tmpcip) & 0xf3; + if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || + (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) { + j |= 0x0c; + } + outb(j,tmpcip); + tmpcip--; + } else if ((dev->dev_id == ATP880_DEVID1) || + (dev->dev_id == ATP880_DEVID2)) { + tmpcip =tmpcip -2; + tmport = workport - 0x05; + if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) { outb((unsigned char) ((inb(tmport) & 0x3f) | 0xc0), tmport); } else { outb((unsigned char) (inb(tmport) & 0x3f), tmport); - } - } - tmport = workportu + 0x1c; + } + } else { + tmpcip =tmpcip -2; + tmport = workport + 0x3a; + if ((workreq->cmnd[0] == 0x08) || (workreq->cmnd[0] == 0x28) || (workreq->cmnd[0] == 0x0a) || (workreq->cmnd[0] == 0x2a)) { + outb((inb(tmport) & 0xf3) | 0x08, tmport); + } else { + outb(inb(tmport) & 0xf3, tmport); + } + } + tmport = workport + 0x1c; - if (workrequ->sc_data_direction == DMA_TO_DEVICE) { - dev->id[target_id].dirctu = 0x20; + if(workreq->sc_data_direction == DMA_TO_DEVICE) { + dev->id[c][target_id].dirct = 0x20; if (inb(tmport) == 0) { - tmport = workportu + 0x18; + tmport = workport + 0x18; outb(0x08, tmport); outb(0x01, tmpcip); +#ifdef ED_DBGP + printk( "start DMA(to target)\n"); +#endif } else { - dev->last_cmd |= 0x40; + dev->last_cmd[c] |= 0x40; } - dev->in_snd = 0; + dev->in_snd[c] = 0; return; } - if (inb(tmport) == 0) { - tmport = workportu + 0x18; + if (inb(tmport) == 0) { + tmport = workport + 0x18; outb(0x08, tmport); outb(0x09, tmpcip); +#ifdef ED_DBGP + printk( "start DMA(to host)\n"); +#endif } else { - dev->last_cmd |= 0x40; + dev->last_cmd[c] |= 0x40; } - dev->in_snd = 0; + dev->in_snd[c] = 0; + return; + } static unsigned char fun_scam(struct atp_unit *dev, unsigned short int *val) @@ -808,7 +1068,7 @@ unsigned short int i, k; unsigned char j; - tmport = dev->ioport + 0x1c; + tmport = dev->ioport[0] + 0x1c; outw(*val, tmport); FUN_D7: for (i = 0; i < 10; i++) { /* stable >= bus settle delay(400 ns) */ @@ -863,24 +1123,24 @@ } */ - tmport = dev->ioport + 1; + tmport = dev->ioport[0] + 1; outb(0x08, tmport++); outb(0x7f, tmport); - tmport = dev->ioport + 0x11; + tmport = dev->ioport[0] + 0x11; outb(0x20, tmport); if ((dev->scam_on & 0x40) == 0) { return; } m = 1; - m <<= dev->host_idu; + m <<= dev->host_id[0]; j = 16; - if (dev->chip_veru < 4) { + if (dev->chip_ver < 4) { m |= 0xff00; j = 8; } assignid_map = m; - tmport = dev->ioport + 0x02; + tmport = dev->ioport[0] + 0x02; outb(0x02, tmport++); /* 2*2=4ms,3EH 2/32*3E=3.9ms */ outb(0, tmport++); outb(0, tmport++); @@ -895,7 +1155,7 @@ if ((m & assignid_map) != 0) { continue; } - tmport = dev->ioport + 0x0f; + tmport = dev->ioport[0] + 0x0f; outb(0, tmport++); tmport += 0x02; outb(0, tmport++); @@ -907,14 +1167,14 @@ k = i; } outb(k, tmport++); - tmport = dev->ioport + 0x1b; - if (dev->chip_veru == 4) { + tmport = dev->ioport[0] + 0x1b; + if (dev->chip_ver == 4) { outb(0x01, tmport); } else { outb(0x00, tmport); } wait_rdyok: - tmport = dev->ioport + 0x18; + tmport = dev->ioport[0] + 0x18; outb(0x09, tmport); tmport += 0x07; @@ -925,22 +1185,22 @@ if ((k == 0x85) || (k == 0x42)) { continue; } - tmport = dev->ioport + 0x10; + tmport = dev->ioport[0] + 0x10; outb(0x41, tmport); goto wait_rdyok; } assignid_map |= m; } - tmport = dev->ioport + 0x02; + tmport = dev->ioport[0] + 0x02; outb(0x7f, tmport); - tmport = dev->ioport + 0x1b; + tmport = dev->ioport[0] + 0x1b; outb(0x02, tmport); outb(0, 0x80); val = 0x0080; /* bsy */ - tmport = dev->ioport + 0x1c; + tmport = dev->ioport[0] + 0x1c; outw(val, tmport); val |= 0x0040; /* sel */ outw(val, tmport); @@ -984,7 +1244,7 @@ if ((inb(tmport) & 0x80) == 0x00) { /* bsy ? */ outw(0, tmport--); outb(0, tmport); - tmport = dev->ioport + 0x15; + tmport = dev->ioport[0] + 0x15; outb(0, tmport); tmport += 0x03; outb(0x09, tmport); @@ -1085,7 +1345,7 @@ } -static void is870(struct Scsi_Host *host, unsigned int wkport) +void is870(struct atp_unit *dev, unsigned int wkport) { unsigned int tmport; unsigned char i, j, k, rmb, n; @@ -1097,26 +1357,25 @@ static unsigned char synu[6] = { 0x80, 1, 3, 1, 0x0c, 0x0e }; static unsigned char synw[6] = { 0x80, 1, 3, 1, 0x0c, 0x07 }; static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 }; - struct atp_unit *dev = (struct atp_unit *)&host->hostdata; - + tmport = wkport + 0x3a; outb((unsigned char) (inb(tmport) | 0x10), tmport); for (i = 0; i < 16; i++) { - if ((dev->chip_veru != 4) && (i > 7)) { + if ((dev->chip_ver != 4) && (i > 7)) { break; } m = 1; m = m << i; - if ((m & dev->active_idu) != 0) { + if ((m & dev->active_id[0]) != 0) { continue; } - if (i == dev->host_idu) { - printk(KERN_INFO " ID: %2d Host Adapter\n", dev->host_idu); + if (i == dev->host_id[0]) { + printk(KERN_INFO " ID: %2d Host Adapter\n", dev->host_id[0]); continue; } tmport = wkport + 0x1b; - if (dev->chip_veru == 4) { + if (dev->chip_ver == 4) { outb(0x01, tmport); } else { outb(0x00, tmport); @@ -1133,7 +1392,7 @@ tmport += 0x06; outb(0, tmport); tmport += 0x02; - outb(dev->id[i].devspu, tmport++); + outb(dev->id[0][i].devsp, tmport++); outb(0, tmport++); outb(satn[6], tmport++); outb(satn[7], tmport++); @@ -1152,7 +1411,7 @@ continue; } while (inb(tmport) != 0x8e); - dev->active_idu |= m; + dev->active_id[0] |= m; tmport = wkport + 0x10; outb(0x30, tmport); @@ -1182,7 +1441,7 @@ tmport += 0x07; outb(0, tmport); tmport += 0x02; - outb(dev->id[i].devspu, tmport++); + outb(dev->id[0][i].devsp, tmport++); outb(0, tmport++); outb(inqd[6], tmport++); outb(inqd[7], tmport++); @@ -1196,7 +1455,7 @@ } while (inb(tmport) != 0x8e); tmport = wkport + 0x1b; - if (dev->chip_veru == 4) { + if (dev->chip_ver == 4) { outb(0x00, tmport); } tmport = wkport + 0x18; @@ -1236,16 +1495,16 @@ inq_ok: mbuf[36] = 0; printk(KERN_INFO " ID: %2d %s\n", i, &mbuf[8]); - dev->id[i].devtypeu = mbuf[0]; + dev->id[0][i].devtype = mbuf[0]; rmb = mbuf[1]; n = mbuf[7]; - if (dev->chip_veru != 4) { + if (dev->chip_ver != 4) { goto not_wide; } if ((mbuf[7] & 0x60) == 0) { goto not_wide; } - if ((dev->global_map & 0x20) == 0) { + if ((dev->global_map[0] & 0x20) == 0) { goto not_wide; } tmport = wkport + 0x1b; @@ -1260,7 +1519,7 @@ tmport += 0x06; outb(0, tmport); tmport += 0x02; - outb(dev->id[i].devspu, tmport++); + outb(dev->id[0][i].devsp, tmport++); outb(0, tmport++); outb(satn[6], tmport++); outb(satn[7], tmport++); @@ -1386,16 +1645,16 @@ } m = 1; m = m << i; - dev->wide_idu |= m; + dev->wide_id[0] |= m; not_wide: - if ((dev->id[i].devtypeu == 0x00) || (dev->id[i].devtypeu == 0x07) || ((dev->id[i].devtypeu == 0x05) && ((n & 0x10) != 0))) { + if ((dev->id[0][i].devtype == 0x00) || (dev->id[0][i].devtype == 0x07) || ((dev->id[0][i].devtype == 0x05) && ((n & 0x10) != 0))) { goto set_sync; } continue; set_sync: tmport = wkport + 0x1b; j = 0; - if ((m & dev->wide_idu) != 0) { + if ((m & dev->wide_id[0]) != 0) { j |= 0x01; } outb(j, tmport); @@ -1409,7 +1668,7 @@ tmport += 0x06; outb(0, tmport); tmport += 0x02; - outb(dev->id[i].devspu, tmport++); + outb(dev->id[0][i].devsp, tmport++); outb(0, tmport++); outb(satn[6], tmport++); outb(satn[7], tmport++); @@ -1434,10 +1693,10 @@ while ((inb(tmport) & 0x80) == 0) { if ((inb(tmport) & 0x01) != 0) { tmport -= 0x06; - if ((m & dev->wide_idu) != 0) { + if ((m & dev->wide_id[0]) != 0) { outb(synw[j++], tmport); } else { - if ((m & dev->ultra_map) != 0) { + if ((m & dev->ultra_map[0]) != 0) { outb(synu[j++], tmport); } else { outb(synn[j++], tmport); @@ -1551,7 +1810,7 @@ if (mbuf[4] > 0x0c) { mbuf[4] = 0x0c; } - dev->id[i].devspu = mbuf[4]; + dev->id[0][i].devsp = mbuf[4]; if ((mbuf[3] < 0x0d) && (rmb == 0)) { j = 0xa0; goto set_syn_ok; @@ -1570,13 +1829,13 @@ } j = 0x60; set_syn_ok: - dev->id[i].devspu = (dev->id[i].devspu & 0x0f) | j; + dev->id[0][i].devsp = (dev->id[0][i].devsp & 0x0f) | j; } tmport = wkport + 0x3a; outb((unsigned char) (inb(tmport) & 0xef), tmport); } -static void is880(struct Scsi_Host *host, unsigned int wkport) +static void is880(struct atp_unit *dev, unsigned int wkport) { unsigned int tmport; unsigned char i, j, k, rmb, n, lvdmode; @@ -1590,18 +1849,17 @@ unsigned char synuw[6] = { 0x80, 1, 3, 1, 0x0a, 0x0e }; static unsigned char wide[6] = { 0x80, 1, 2, 3, 1, 0 }; static unsigned char u3[9] = { 0x80, 1, 6, 4, 0x09, 00, 0x0e, 0x01, 0x02 }; - struct atp_unit *dev = (struct atp_unit *)&host->hostdata; lvdmode = inb(wkport + 0x3f) & 0x40; for (i = 0; i < 16; i++) { m = 1; m = m << i; - if ((m & dev->active_idu) != 0) { + if ((m & dev->active_id[0]) != 0) { continue; } - if (i == dev->host_idu) { - printk(KERN_INFO " ID: %2d Host Adapter\n", dev->host_idu); + if (i == dev->host_id[0]) { + printk(KERN_INFO " ID: %2d Host Adapter\n", dev->host_id[0]); continue; } tmport = wkport + 0x5b; @@ -1618,7 +1876,7 @@ tmport += 0x06; outb(0, tmport); tmport += 0x02; - outb(dev->id[i].devspu, tmport++); + outb(dev->id[0][i].devsp, tmport++); outb(0, tmport++); outb(satn[6], tmport++); outb(satn[7], tmport++); @@ -1637,7 +1895,7 @@ continue; } while (inb(tmport) != 0x8e); - dev->active_idu |= m; + dev->active_id[0] |= m; tmport = wkport + 0x50; outb(0x30, tmport); @@ -1667,7 +1925,7 @@ tmport += 0x07; outb(0, tmport); tmport += 0x02; - outb(dev->id[i].devspu, tmport++); + outb(dev->id[0][i].devsp, tmport++); outb(0, tmport++); outb(inqd[6], tmport++); outb(inqd[7], tmport++); @@ -1719,19 +1977,19 @@ inq_ok: mbuf[36] = 0; printk(KERN_INFO " ID: %2d %s\n", i, &mbuf[8]); - dev->id[i].devtypeu = mbuf[0]; + dev->id[0][i].devtype = mbuf[0]; rmb = mbuf[1]; n = mbuf[7]; if ((mbuf[7] & 0x60) == 0) { goto not_wide; } - if ((i < 8) && ((dev->global_map & 0x20) == 0)) { + if ((i < 8) && ((dev->global_map[0] & 0x20) == 0)) { goto not_wide; } if (lvdmode == 0) { goto chg_wide; } - if (dev->sp[i] != 0x04) // force u2 + if (dev->sp[0][i] != 0x04) // force u2 { goto chg_wide; } @@ -1748,7 +2006,7 @@ tmport += 0x06; outb(0, tmport); tmport += 0x02; - outb(dev->id[i].devspu, tmport++); + outb(dev->id[0][i].devsp, tmport++); outb(0, tmport++); outb(satn[6], tmport++); outb(satn[7], tmport++); @@ -1872,8 +2130,8 @@ if (mbuf[3] == 0x09) { m = 1; m = m << i; - dev->wide_idu |= m; - dev->id[i].devspu = 0xce; + dev->wide_id[0] |= m; + dev->id[0][i].devsp = 0xce; continue; } chg_wide: @@ -1889,7 +2147,7 @@ tmport += 0x06; outb(0, tmport); tmport += 0x02; - outb(dev->id[i].devspu, tmport++); + outb(dev->id[0][i].devsp, tmport++); outb(0, tmport++); outb(satn[6], tmport++); outb(satn[7], tmport++); @@ -2015,29 +2273,29 @@ } m = 1; m = m << i; - dev->wide_idu |= m; + dev->wide_id[0] |= m; not_wide: - if ((dev->id[i].devtypeu == 0x00) || (dev->id[i].devtypeu == 0x07) || ((dev->id[i].devtypeu == 0x05) && ((n & 0x10) != 0))) { + if ((dev->id[0][i].devtype == 0x00) || (dev->id[0][i].devtype == 0x07) || ((dev->id[0][i].devtype == 0x05) && ((n & 0x10) != 0))) { m = 1; m = m << i; - if ((dev->async & m) != 0) { + if ((dev->async[0] & m) != 0) { goto set_sync; } } continue; set_sync: - if (dev->sp[i] == 0x02) { + if (dev->sp[0][i] == 0x02) { synu[4] = 0x0c; synuw[4] = 0x0c; } else { - if (dev->sp[i] >= 0x03) { + if (dev->sp[0][i] >= 0x03) { synu[4] = 0x0a; synuw[4] = 0x0a; } } tmport = wkport + 0x5b; j = 0; - if ((m & dev->wide_idu) != 0) { + if ((m & dev->wide_id[0]) != 0) { j |= 0x01; } outb(j, tmport); @@ -2051,7 +2309,7 @@ tmport += 0x06; outb(0, tmport); tmport += 0x02; - outb(dev->id[i].devspu, tmport++); + outb(dev->id[0][i].devsp, tmport++); outb(0, tmport++); outb(satn[6], tmport++); outb(satn[7], tmport++); @@ -2076,14 +2334,14 @@ while ((inb(tmport) & 0x80) == 0) { if ((inb(tmport) & 0x01) != 0) { tmport -= 0x06; - if ((m & dev->wide_idu) != 0) { - if ((m & dev->ultra_map) != 0) { + if ((m & dev->wide_id[0]) != 0) { + if ((m & dev->ultra_map[0]) != 0) { outb(synuw[j++], tmport); } else { outb(synw[j++], tmport); } } else { - if ((m & dev->ultra_map) != 0) { + if ((m & dev->ultra_map[0]) != 0) { outb(synu[j++], tmport); } else { outb(synn[j++], tmport); @@ -2197,7 +2455,7 @@ if (mbuf[4] > 0x0e) { mbuf[4] = 0x0e; } - dev->id[i].devspu = mbuf[4]; + dev->id[0][i].devsp = mbuf[4]; if (mbuf[3] < 0x0c) { j = 0xb0; goto set_syn_ok; @@ -2220,249 +2478,179 @@ } j = 0x60; set_syn_ok: - dev->id[i].devspu = (dev->id[i].devspu & 0x0f) | j; + dev->id[0][i].devsp = (dev->id[0][i].devsp & 0x0f) | j; } } static void atp870u_free_tables(struct Scsi_Host *host) { struct atp_unit *atp_dev = (struct atp_unit *)&host->hostdata; - int k; - - for (k = 0; k < 16; k++) { - if (!atp_dev->id[k].prd_tableu) - continue; - pci_free_consistent(atp_dev->pdev, 1024, atp_dev->id[k].prd_tableu, - atp_dev->id[k].prd_phys); - atp_dev->id[k].prd_tableu = NULL; + int j, k; + for (j=0; j < 2; j++) { + for (k = 0; k < 16; k++) { + if (!atp_dev->id[j][k].prd_table) + continue; + pci_free_consistent(atp_dev->pdev, 1024, atp_dev->id[j][k].prd_table, atp_dev->id[j][k].prdaddr); + atp_dev->id[j][k].prd_table = NULL; + } } } static int atp870u_init_tables(struct Scsi_Host *host) { - struct atp_unit *dev = (struct atp_unit *)&host->hostdata; - int k, i; - - for (i = k = 0; k < 16; k++) { - dev->id[k].prd_tableu = pci_alloc_consistent(dev->pdev, 1024, &dev->id[k].prd_phys); - if (!dev->id[k].prd_tableu) { - atp870u_free_tables(host); - return -ENOMEM; - } - dev->id[k].devspu = 0x20; - dev->id[k].devtypeu = 0; - dev->id[k].curr_req = NULL; - } - dev->active_idu = 0; - dev->wide_idu = 0; - dev->host_idu = 0x07; - dev->quhdu = 0; - dev->quendu = 0; - dev->chip_veru = 0; - dev->last_cmd = 0xff; - dev->in_snd = 0; - dev->in_int = 0; - for (k = 0; k < qcnt; k++) { - dev->querequ[k] = NULL; - } - for (k = 0; k < 16; k++) { - dev->id[k].curr_req = NULL; - dev->sp[k] = 0x04; + struct atp_unit *atp_dev = (struct atp_unit *)&host->hostdata; + int c,k; + for(c=0;c < 2;c++) { + for(k=0;k<16;k++) { + atp_dev->id[c][k].prd_table = pci_alloc_consistent(atp_dev->pdev, 1024, &(atp_dev->id[c][k].prdaddr)); + if (!atp_dev->id[c][k].prd_table) { + printk("atp870u_init_tables fail\n"); + atp870u_free_tables(host); + return -ENOMEM; + } + atp_dev->id[c][k].devsp=0x20; + atp_dev->id[c][k].devtype = 0x7f; + atp_dev->id[c][k].curr_req = NULL; + } + + atp_dev->active_id[c] = 0; + atp_dev->wide_id[c] = 0; + atp_dev->host_id[c] = 0x07; + atp_dev->quhd[c] = 0; + atp_dev->quend[c] = 0; + atp_dev->last_cmd[c] = 0xff; + atp_dev->in_snd[c] = 0; + atp_dev->in_int[c] = 0; + + for (k = 0; k < qcnt; k++) { + atp_dev->quereq[c][k] = NULL; + } + for (k = 0; k < 16; k++) { + atp_dev->id[c][k].curr_req = NULL; + atp_dev->sp[c][k] = 0x04; + } } return 0; } /* return non-zero on detection */ -static int atp870u_probe(struct pci_dev *dev, const struct pci_device_id *ent) +static int atp870u_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - unsigned char k, m; + unsigned char k, m, c; unsigned long flags; - unsigned int base_io, error, tmport; + unsigned int base_io, tmport, error,n; unsigned char host_id; - unsigned short n; - struct Scsi_Host *shpnt; + struct Scsi_Host *shpnt = NULL; struct atp_unit atp_dev, *p; - static int count; - - if (pci_enable_device(dev)) + unsigned char setupdata[2][16]; + int count = 0; + + if (pci_enable_device(pdev)) return -EIO; - if (pci_set_dma_mask(dev, 0xFFFFFFFFUL)) { - printk(KERN_ERR "atp870u: 32bit DMA mask required but not available.\n"); - return -EIO; - } - + if (!pci_set_dma_mask(pdev, 0xFFFFFFUL)) { + printk(KERN_INFO "atp870u: use 32bit DMA mask.\n"); + } else { + printk(KERN_ERR "atp870u: DMA mask required but not available.\n"); + return -EIO; + } + memset(&atp_dev, 0, sizeof atp_dev); - /* * It's probably easier to weed out some revisions like * this than via the PCI device table */ if (ent->device == PCI_DEVICE_ID_ARTOP_AEC7610) { - error = pci_read_config_byte(dev, PCI_CLASS_REVISION, &atp_dev.chip_veru); - if (atp_dev.chip_veru < 2) + error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atp_dev.chip_ver); + if (atp_dev.chip_ver < 2) return -EIO; } switch (ent->device) { - case 0x8081: case PCI_DEVICE_ID_ARTOP_AEC7612UW: case PCI_DEVICE_ID_ARTOP_AEC7612SUW: - atp_dev.chip_veru = 0x04; + case ATP880_DEVID1: + case ATP880_DEVID2: + case ATP885_DEVID: + atp_dev.chip_ver = 0x04; default: break; } + base_io = pci_resource_start(pdev, 0); + base_io &= 0xfffffff8; + + if ((ent->device == ATP880_DEVID1)||(ent->device == ATP880_DEVID2)) { + error = pci_read_config_byte(pdev, PCI_CLASS_REVISION, &atp_dev.chip_ver); + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0x80);//JCC082803 - base_io = pci_resource_start(dev, 0); - - if (ent->device != 0x8081) { - error = pci_read_config_byte(dev, 0x49, &host_id); - base_io &= 0xfffffff8; - - printk(KERN_INFO " ACARD AEC-671X PCI Ultra/W SCSI-3 Host Adapter: %d " - "IO:%x, IRQ:%d.\n", count, base_io, dev->irq); - - atp_dev.unit = count; - atp_dev.ioport = base_io; - atp_dev.pciport = base_io + 0x20; - atp_dev.deviceid = ent->device; - host_id &= 0x07; - atp_dev.host_idu = host_id; - tmport = base_io + 0x22; - atp_dev.scam_on = inb(tmport); - tmport += 0x0b; - atp_dev.global_map = inb(tmport++); - atp_dev.ultra_map = inw(tmport); - - if (atp_dev.ultra_map == 0) { - atp_dev.scam_on = 0x00; - atp_dev.global_map = 0x20; - atp_dev.ultra_map = 0xffff; - } - - shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit)); - if (!shpnt) - return -ENOMEM; - - p = (struct atp_unit *)&shpnt->hostdata; - - atp_dev.host = shpnt; - atp_dev.pdev = dev; - pci_set_drvdata(dev, p); - memcpy(p, &atp_dev, sizeof atp_dev); - if (atp870u_init_tables(shpnt) < 0) - goto unregister; - - if (request_irq(dev->irq, atp870u_intr_handle, SA_SHIRQ, "atp870u", shpnt)) { - printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", dev->irq); - goto free_tables; - } - - spin_lock_irqsave(shpnt->host_lock, flags); - if (atp_dev.chip_veru > 0x07) { /* check if atp876 chip then enable terminator */ - tmport = base_io + 0x3e; - outb(0x00, tmport); - } - - tmport = base_io + 0x3a; - k = (inb(tmport) & 0xf3) | 0x10; - outb(k, tmport); - outb((k & 0xdf), tmport); - mdelay(32); - outb(k, tmport); - mdelay(32); - tmport = base_io; - outb((host_id | 0x08), tmport); - tmport += 0x18; - outb(0, tmport); - tmport += 0x07; - while ((inb(tmport) & 0x80) == 0) - mdelay(1); - - tmport -= 0x08; - inb(tmport); - tmport = base_io + 1; - outb(8, tmport++); - outb(0x7f, tmport); - tmport = base_io + 0x11; - outb(0x20, tmport); - - tscam(shpnt); - is870(shpnt, base_io); - tmport = base_io + 0x3a; - outb((inb(tmport) & 0xef), tmport); - tmport++; - outb((inb(tmport) | 0x20), tmport); - } else { - base_io &= 0xfffffff8; host_id = inb(base_io + 0x39); host_id >>= 0x04; printk(KERN_INFO " ACARD AEC-67160 PCI Ultra3 LVD Host Adapter: %d" - " IO:%x, IRQ:%d.\n", count, base_io, dev->irq); - atp_dev.ioport = base_io + 0x40; - atp_dev.pciport = base_io + 0x28; - atp_dev.deviceid = ent->device; - atp_dev.host_idu = host_id; + " IO:%x, IRQ:%d.\n", count, base_io, pdev->irq); + atp_dev.ioport[0] = base_io + 0x40; + atp_dev.pciport[0] = base_io + 0x28; + atp_dev.dev_id = ent->device; + atp_dev.host_id[0] = host_id; tmport = base_io + 0x22; atp_dev.scam_on = inb(tmport); tmport += 0x13; - atp_dev.global_map = inb(tmport); + atp_dev.global_map[0] = inb(tmport); tmport += 0x07; - atp_dev.ultra_map = inw(tmport); + atp_dev.ultra_map[0] = inw(tmport); n = 0x3f09; -next_fblk: +next_fblk_880: if (n >= 0x4000) - goto flash_ok; + goto flash_ok_880; m = 0; outw(n, base_io + 0x34); n += 0x0002; if (inb(base_io + 0x30) == 0xff) - goto flash_ok; + goto flash_ok_880; - atp_dev.sp[m++] = inb(base_io + 0x30); - atp_dev.sp[m++] = inb(base_io + 0x31); - atp_dev.sp[m++] = inb(base_io + 0x32); - atp_dev.sp[m++] = inb(base_io + 0x33); + atp_dev.sp[0][m++] = inb(base_io + 0x30); + atp_dev.sp[0][m++] = inb(base_io + 0x31); + atp_dev.sp[0][m++] = inb(base_io + 0x32); + atp_dev.sp[0][m++] = inb(base_io + 0x33); outw(n, base_io + 0x34); n += 0x0002; - atp_dev.sp[m++] = inb(base_io + 0x30); - atp_dev.sp[m++] = inb(base_io + 0x31); - atp_dev.sp[m++] = inb(base_io + 0x32); - atp_dev.sp[m++] = inb(base_io + 0x33); + atp_dev.sp[0][m++] = inb(base_io + 0x30); + atp_dev.sp[0][m++] = inb(base_io + 0x31); + atp_dev.sp[0][m++] = inb(base_io + 0x32); + atp_dev.sp[0][m++] = inb(base_io + 0x33); outw(n, base_io + 0x34); n += 0x0002; - atp_dev.sp[m++] = inb(base_io + 0x30); - atp_dev.sp[m++] = inb(base_io + 0x31); - atp_dev.sp[m++] = inb(base_io + 0x32); - atp_dev.sp[m++] = inb(base_io + 0x33); + atp_dev.sp[0][m++] = inb(base_io + 0x30); + atp_dev.sp[0][m++] = inb(base_io + 0x31); + atp_dev.sp[0][m++] = inb(base_io + 0x32); + atp_dev.sp[0][m++] = inb(base_io + 0x33); outw(n, base_io + 0x34); n += 0x0002; - atp_dev.sp[m++] = inb(base_io + 0x30); - atp_dev.sp[m++] = inb(base_io + 0x31); - atp_dev.sp[m++] = inb(base_io + 0x32); - atp_dev.sp[m++] = inb(base_io + 0x33); + atp_dev.sp[0][m++] = inb(base_io + 0x30); + atp_dev.sp[0][m++] = inb(base_io + 0x31); + atp_dev.sp[0][m++] = inb(base_io + 0x32); + atp_dev.sp[0][m++] = inb(base_io + 0x33); n += 0x0018; - goto next_fblk; -flash_ok: + goto next_fblk_880; +flash_ok_880: outw(0, base_io + 0x34); - atp_dev.ultra_map = 0; - atp_dev.async = 0; + atp_dev.ultra_map[0] = 0; + atp_dev.async[0] = 0; for (k = 0; k < 16; k++) { n = 1; n = n << k; - if (atp_dev.sp[k] > 1) { - atp_dev.ultra_map |= n; + if (atp_dev.sp[0][k] > 1) { + atp_dev.ultra_map[0] |= n; } else { - if (atp_dev.sp[k] == 0) - atp_dev.async |= n; + if (atp_dev.sp[0][k] == 0) + atp_dev.async[0] |= n; } } - atp_dev.async = ~(atp_dev.async); - outb(atp_dev.global_map, base_io + 0x35); + atp_dev.async[0] = ~(atp_dev.async[0]); + outb(atp_dev.global_map[0], base_io + 0x35); shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit)); if (!shpnt) @@ -2471,16 +2659,16 @@ p = (struct atp_unit *)&shpnt->hostdata; atp_dev.host = shpnt; - atp_dev.pdev = dev; - pci_set_drvdata(dev, p); + atp_dev.pdev = pdev; + pci_set_drvdata(pdev, p); memcpy(p, &atp_dev, sizeof atp_dev); if (atp870u_init_tables(shpnt) < 0) { printk(KERN_ERR "Unable to allocate tables for Acard controller\n"); goto unregister; } - if (request_irq(dev->irq, atp870u_intr_handle, SA_SHIRQ, "atp870u", shpnt)) { - printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", dev->irq); + if (request_irq(pdev->irq, atp870u_intr_handle, SA_SHIRQ, "atp880i", shpnt)) { + printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", pdev->irq); goto free_tables; } @@ -2513,96 +2701,354 @@ outb(0x20, tmport); tscam(shpnt); - is880(shpnt, base_io); + is880(p, base_io); tmport = base_io + 0x38; outb(0xb0, tmport); - } - - if (p->chip_veru == 4) shpnt->max_id = 16; - - shpnt->this_id = host_id; - shpnt->unique_id = base_io; - shpnt->io_port = base_io; - if (ent->device == 0x8081) { + shpnt->this_id = host_id; + shpnt->unique_id = base_io; + shpnt->io_port = base_io; shpnt->n_io_port = 0x60; /* Number of bytes of I/O space used */ + shpnt->irq = pdev->irq; + } else if (ent->device == ATP885_DEVID) { + printk(KERN_INFO " ACARD AEC-67162 PCI Ultra3 LVD Host Adapter: IO:%x, IRQ:%d.\n" + , base_io, pdev->irq); + + atp_dev.pdev = pdev; + atp_dev.dev_id = ent->device; + atp_dev.baseport = base_io; + atp_dev.ioport[0] = base_io + 0x80; + atp_dev.ioport[1] = base_io + 0xc0; + atp_dev.pciport[0] = base_io + 0x40; + atp_dev.pciport[1] = base_io + 0x50; + + shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit)); + if (!shpnt) + return -ENOMEM; + + p = (struct atp_unit *)&shpnt->hostdata; + + atp_dev.host = shpnt; + atp_dev.pdev = pdev; + pci_set_drvdata(pdev, p); + memcpy(p, &atp_dev, sizeof(struct atp_unit)); + if (atp870u_init_tables(shpnt) < 0) + goto unregister; + +#ifdef ED_DBGP + printk("request_irq() shpnt %p hostdata %p\n", shpnt, p); +#endif + if (request_irq(pdev->irq, atp870u_intr_handle, SA_SHIRQ, "atp870u", shpnt)) { + printk(KERN_ERR "Unable to allocate IRQ for Acard controller.\n"); + goto free_tables; + } + + spin_lock_irqsave(shpnt->host_lock, flags); + + c=inb(base_io + 0x29); + outb((c | 0x04),base_io + 0x29); + + n=0x1f80; +next_fblk_885: + if (n >= 0x2000) { + goto flash_ok_885; + } + outw(n,base_io + 0x3c); + if (inl(base_io + 0x38) == 0xffffffff) { + goto flash_ok_885; + } + for (m=0; m < 2; m++) { + p->global_map[m]= 0; + for (k=0; k < 4; k++) { + outw(n++,base_io + 0x3c); + ((unsigned long *)&setupdata[m][0])[k]=inl(base_io + 0x38); + } + for (k=0; k < 4; k++) { + outw(n++,base_io + 0x3c); + ((unsigned long *)&p->sp[m][0])[k]=inl(base_io + 0x38); + } + n += 8; + } + goto next_fblk_885; +flash_ok_885: +#ifdef ED_DBGP + printk( "Flash Read OK\n"); +#endif + c=inb(base_io + 0x29); + outb((c & 0xfb),base_io + 0x29); + for (c=0;c < 2;c++) { + p->ultra_map[c]=0; + p->async[c] = 0; + for (k=0; k < 16; k++) { + n=1; + n = n << k; + if (p->sp[c][k] > 1) { + p->ultra_map[c] |= n; + } else { + if (p->sp[c][k] == 0) { + p->async[c] |= n; + } + } + } + p->async[c] = ~(p->async[c]); + + if (p->global_map[c] == 0) { + k=setupdata[c][1]; + if ((k & 0x40) != 0) + p->global_map[c] |= 0x20; + k &= 0x07; + p->global_map[c] |= k; + if ((setupdata[c][2] & 0x04) != 0) + p->global_map[c] |= 0x08; + p->host_id[c] = setupdata[c][0] & 0x07; + } + } + + k = inb(base_io + 0x28) & 0x8f; + k |= 0x10; + outb(k, base_io + 0x28); + outb(0x80, base_io + 0x41); + outb(0x80, base_io + 0x51); + mdelay(100); + outb(0, base_io + 0x41); + outb(0, base_io + 0x51); + mdelay(1000); + inb(base_io + 0x9b); + inb(base_io + 0x97); + inb(base_io + 0xdb); + inb(base_io + 0xd7); + tmport = base_io + 0x80; + k=p->host_id[0]; + if (k > 7) + k = (k & 0x07) | 0x40; + k |= 0x08; + outb(k, tmport); + tmport += 0x18; + outb(0, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0); + tmport -= 0x08; + inb(tmport); + tmport = base_io + 0x81; + outb(8, tmport++); + outb(0x7f, tmport); + tmport = base_io + 0x91; + outb(0x20, tmport); + + tmport = base_io + 0xc0; + k=p->host_id[1]; + if (k > 7) + k = (k & 0x07) | 0x40; + k |= 0x08; + outb(k, tmport); + tmport += 0x18; + outb(0, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0); + tmport -= 0x08; + inb(tmport); + tmport = base_io + 0xc1; + outb(8, tmport++); + outb(0x7f, tmport); + tmport = base_io + 0xd1; + outb(0x20, tmport); + + tscam_885(); + printk(KERN_INFO " Scanning Channel A SCSI Device ...\n"); + is885(p, base_io + 0x80, 0); + printk(KERN_INFO " Scanning Channel B SCSI Device ...\n"); + is885(p, base_io + 0xc0, 1); + + k = inb(base_io + 0x28) & 0xcf; + k |= 0xc0; + outb(k, base_io + 0x28); + k = inb(base_io + 0x1f) | 0x80; + outb(k, base_io + 0x1f); + k = inb(base_io + 0x29) | 0x01; + outb(k, base_io + 0x29); +#ifdef ED_DBGP + //printk("atp885: atp_host[0] 0x%p\n", atp_host[0]); +#endif + shpnt->max_id = 16; + shpnt->max_lun = (p->global_map[0] & 0x07) + 1; + shpnt->max_channel = 1; + shpnt->this_id = p->host_id[0]; + shpnt->unique_id = base_io; + shpnt->io_port = base_io; + shpnt->n_io_port = 0xff; /* Number of bytes of I/O space used */ + shpnt->irq = pdev->irq; + } else { - shpnt->n_io_port = 0x40; /* Number of bytes of I/O space used */ - } - shpnt->irq = dev->irq; - spin_unlock_irqrestore(shpnt->host_lock, flags); - if (ent->device == 0x8081) { - if (!request_region(base_io, 0x60, "atp870u")) - goto request_io_fail; - } else { - if (!request_region(base_io, 0x40, "atp870u")) - goto request_io_fail; - } + error = pci_read_config_byte(pdev, 0x49, &host_id); - count++; - if (scsi_add_host(shpnt, &dev->dev)) - goto scsi_add_fail; - scsi_scan_host(shpnt); - return 0; - -scsi_add_fail: - if (ent->device == 0x8081) - release_region(base_io, 0x60); - else - release_region(base_io, 0x40); -request_io_fail: - free_irq(dev->irq, shpnt); -free_tables: - atp870u_free_tables(shpnt); -unregister: - scsi_host_put(shpnt); - return -1; -} + printk(KERN_INFO " ACARD AEC-671X PCI Ultra/W SCSI-2/3 Host Adapter: %d " + "IO:%x, IRQ:%d.\n", count, base_io, pdev->irq); + + atp_dev.ioport[0] = base_io; + atp_dev.pciport[0] = base_io + 0x20; + atp_dev.dev_id = ent->device; + host_id &= 0x07; + atp_dev.host_id[0] = host_id; + tmport = base_io + 0x22; + atp_dev.scam_on = inb(tmport); + tmport += 0x0b; + atp_dev.global_map[0] = inb(tmport++); + atp_dev.ultra_map[0] = inw(tmport); + + if (atp_dev.ultra_map[0] == 0) { + atp_dev.scam_on = 0x00; + atp_dev.global_map[0] = 0x20; + atp_dev.ultra_map[0] = 0xffff; + } + + shpnt = scsi_host_alloc(&atp870u_template, sizeof(struct atp_unit)); + if (!shpnt) + return -ENOMEM; + + p = (struct atp_unit *)&shpnt->hostdata; + + atp_dev.host = shpnt; + atp_dev.pdev = pdev; + pci_set_drvdata(pdev, p); + memcpy(p, &atp_dev, sizeof atp_dev); + if (atp870u_init_tables(shpnt) < 0) + goto unregister; + + if (request_irq(pdev->irq, atp870u_intr_handle, SA_SHIRQ, "atp870i", shpnt)) { + printk(KERN_ERR "Unable to allocate IRQ%d for Acard controller.\n", pdev->irq); + goto free_tables; + } + + spin_lock_irqsave(shpnt->host_lock, flags); + if (atp_dev.chip_ver > 0x07) { /* check if atp876 chip then enable terminator */ + tmport = base_io + 0x3e; + outb(0x00, tmport); + } + + tmport = base_io + 0x3a; + k = (inb(tmport) & 0xf3) | 0x10; + outb(k, tmport); + outb((k & 0xdf), tmport); + mdelay(32); + outb(k, tmport); + mdelay(32); + tmport = base_io; + outb((host_id | 0x08), tmport); + tmport += 0x18; + outb(0, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0) + mdelay(1); + + tmport -= 0x08; + inb(tmport); + tmport = base_io + 1; + outb(8, tmport++); + outb(0x7f, tmport); + tmport = base_io + 0x11; + outb(0x20, tmport); + + tscam(shpnt); + is870(p, base_io); + tmport = base_io + 0x3a; + outb((inb(tmport) & 0xef), tmport); + tmport++; + outb((inb(tmport) | 0x20), tmport); + if (atp_dev.chip_ver == 4) + shpnt->max_id = 16; + else + shpnt->max_id = 7; + shpnt->this_id = host_id; + shpnt->unique_id = base_io; + shpnt->io_port = base_io; + shpnt->n_io_port = 0x40; /* Number of bytes of I/O space used */ + shpnt->irq = pdev->irq; + } + spin_unlock_irqrestore(shpnt->host_lock, flags); + if(ent->device==ATP885_DEVID) { + if(!request_region(base_io, 0xff, "atp870u")) /* Register the IO ports that we use */ + goto request_io_fail; + } else if((ent->device==ATP880_DEVID1)||(ent->device==ATP880_DEVID2)) { + if(!request_region(base_io, 0x60, "atp870u")) /* Register the IO ports that we use */ + goto request_io_fail; + } else { + if(!request_region(base_io, 0x40, "atp870u")) /* Register the IO ports that we use */ + goto request_io_fail; + } + count++; + if (scsi_add_host(shpnt, &pdev->dev)) + goto scsi_add_fail; + scsi_scan_host(shpnt); +#ifdef ED_DBGP + printk("atp870u_prob : exit\n"); +#endif + return 0; + +scsi_add_fail: + printk("atp870u_prob:scsi_add_fail\n"); + if(ent->device==ATP885_DEVID) { + release_region(base_io, 0xff); + } else if((ent->device==ATP880_DEVID1)||(ent->device==ATP880_DEVID2)) { + release_region(base_io, 0x60); + } else { + release_region(base_io, 0x40); + } +request_io_fail: + printk("atp870u_prob:request_io_fail\n"); + free_irq(pdev->irq, shpnt); +free_tables: + printk("atp870u_prob:free_table\n"); + atp870u_free_tables(shpnt); +unregister: + printk("atp870u_prob:unregister\n"); + scsi_host_put(shpnt); + return -1; +} /* The abort command does not leave the device in a clean state where it is available to be used again. Until this gets worked out, we will leave it commented out. */ -static int atp870u_abort(struct scsi_cmnd * SCpnt) +int atp870u_abort(struct scsi_cmnd * SCpnt) { - unsigned char j, k; + unsigned char j, k, c; struct scsi_cmnd *workrequ; unsigned int tmport; - struct atp_unit *dev = (struct atp_unit *)&SCpnt->device->host->hostdata; + struct atp_unit *dev; + struct Scsi_Host *host; + host = SCpnt->device->host; - printk(KERN_DEBUG "working=%x last_cmd=%x ", dev->working, dev->last_cmd); - printk(" quhdu=%x quendu=%x ", dev->quhdu, dev->quendu); - tmport = dev->ioport; - for (j = 0; j < 0x17; j++) { + dev = (struct atp_unit *)&host->hostdata; + c=SCpnt->device->channel; + printk(" atp870u: abort Channel = %x \n", c); + printk("working=%x last_cmd=%x ", dev->working[c], dev->last_cmd[c]); + printk(" quhdu=%x quendu=%x ", dev->quhd[c], dev->quend[c]); + tmport = dev->ioport[c]; + for (j = 0; j < 0x18; j++) { printk(" r%2x=%2x", j, inb(tmport++)); } - tmport += 0x05; + tmport += 0x04; printk(" r1c=%2x", inb(tmport)); tmport += 0x03; - printk(" r1f=%2x in_snd=%2x ", inb(tmport), dev->in_snd); - tmport = dev->pciport; - printk(" r20=%2x", inb(tmport)); + printk(" r1f=%2x in_snd=%2x ", inb(tmport), dev->in_snd[c]); + tmport= dev->pciport[c]; + printk(" d00=%2x", inb(tmport)); tmport += 0x02; - printk(" r22=%2x", inb(tmport)); - tmport = dev->ioport + 0x3a; - printk(" r3a=%2x \n", inb(tmport)); - tmport = dev->ioport + 0x3b; - printk(" r3b=%2x \n", inb(tmport)); - for (j = 0; j < 16; j++) { - if (dev->id[j].curr_req != NULL) { - workrequ = dev->id[j].curr_req; - printk("\n que cdb= "); - for (k = 0; k < workrequ->cmd_len; k++) { - printk(" %2x ", workrequ->cmnd[k]); - } - printk(" last_lenu= %lx ", dev->id[j].last_lenu); + printk(" d02=%2x", inb(tmport)); + for(j=0;j<16;j++) { + if (dev->id[c][j].curr_req != NULL) { + workrequ = dev->id[c][j].curr_req; + printk("\n que cdb= "); + for (k=0; k < workrequ->cmd_len; k++) { + printk(" %2x ",workrequ->cmnd[k]); } + printk(" last_lenu= %x ",(unsigned int)dev->id[c][j].last_len); + } } - /* Sort of - the thing handles itself */ return SUCCESS; } -static const char *atp870u_info(struct Scsi_Host *notused) +const char *atp870u_info(struct Scsi_Host *notused) { static char buffer[128]; @@ -2611,17 +3057,21 @@ return buffer; } +int atp870u_set_info(char *buffer, int length, struct Scsi_Host *HBAptr) +{ + return -ENOSYS; /* Currently this is a no-op */ +} + #define BLS buffer + len + size -static int atp870u_proc_info(struct Scsi_Host *HBAptr, char *buffer, - char **start, off_t offset, int length, int inout) +int atp870u_proc_info(struct Scsi_Host *HBAptr, char *buffer, char **start, off_t offset, int length, int inout) { static u8 buff[512]; int size = 0; int len = 0; off_t begin = 0; off_t pos = 0; - - if (inout) + + if (inout) return -ENOSYS; if (offset == 0) { memset(buff, 0, sizeof(buff)); @@ -2637,7 +3087,7 @@ size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq); len += size; pos = begin + len; - + *start = buffer + (offset - begin); /* Start of wanted data */ len -= (offset - begin); /* Start slop */ if (len > length) { @@ -2646,15 +3096,15 @@ return (len); } -static int atp870u_biosparam(struct scsi_device *sdev, - struct block_device *dev, sector_t capacity, int *ip) + +static int atp870u_biosparam(struct scsi_device *disk, struct block_device *dev, + sector_t capacity, int *ip) { int heads, sectors, cylinders; heads = 64; sectors = 32; cylinders = (unsigned long)capacity / (heads * sectors); - if (cylinders > 1024) { heads = 255; sectors = 63; @@ -2667,39 +3117,46 @@ return 0; } -static void atp870u_remove(struct pci_dev *pdev) -{ - struct atp_unit *atp_dev = pci_get_drvdata(pdev); - struct Scsi_Host *pshost = atp_dev->host; - +static void atp870u_remove (struct pci_dev *pdev) +{ + struct atp_unit *devext = pci_get_drvdata(pdev); + struct Scsi_Host *pshost = devext->host; + + scsi_remove_host(pshost); + printk(KERN_INFO "free_irq : %d\n",pshost->irq); free_irq(pshost->irq, pshost); release_region(pshost->io_port, pshost->n_io_port); + printk(KERN_INFO "atp870u_free_tables : %p\n",pshost); atp870u_free_tables(pshost); + printk(KERN_INFO "scsi_host_put : %p\n",pshost); scsi_host_put(pshost); - pci_set_drvdata(pdev, NULL); + printk(KERN_INFO "pci_set_drvdata : %p\n",pdev); + pci_set_drvdata(pdev, NULL); } - MODULE_LICENSE("GPL"); static struct scsi_host_template atp870u_template = { - .module = THIS_MODULE, - .name = "atp870u", - .proc_name = "atp870u", - .proc_info = atp870u_proc_info, - .info = atp870u_info, - .queuecommand = atp870u_queuecommand, - .eh_abort_handler = atp870u_abort, - .bios_param = atp870u_biosparam, - .can_queue = qcnt, - .this_id = 7, - .sg_tablesize = ATP870U_SCATTER, - .cmd_per_lun = ATP870U_CMDLUN, - .use_clustering = ENABLE_CLUSTERING, + .module = THIS_MODULE, + .name = "atp870u" /* name */, + .proc_name = "atp870u", + .proc_info = atp870u_proc_info, + .info = atp870u_info /* info */, + .queuecommand = atp870u_queuecommand /* queuecommand */, + .eh_abort_handler = atp870u_abort /* abort */, + .bios_param = atp870u_biosparam /* biosparm */, + .can_queue = qcnt /* can_queue */, + .this_id = 7 /* SCSI ID */, + .sg_tablesize = ATP870U_SCATTER /*SG_ALL*/ /*SG_NONE*/, + .cmd_per_lun = ATP870U_CMDLUN /* commands per lun */, + .use_clustering = ENABLE_CLUSTERING, + .max_sectors = ATP870U_MAX_SECTORS, }; static struct pci_device_id atp870u_id_table[] = { - { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, 0x8081) }, + { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, ATP885_DEVID) }, + { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, ATP880_DEVID1) }, + { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, ATP880_DEVID2) }, { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7610) }, { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7612UW) }, { PCI_DEVICE(PCI_VENDOR_ID_ARTOP, PCI_DEVICE_ID_ARTOP_AEC7612U) }, @@ -2712,7 +3169,7 @@ MODULE_DEVICE_TABLE(pci, atp870u_id_table); -static struct pci_driver atp870u_driver = { +static struct pci_driver atp870u_driver = { .id_table = atp870u_id_table, .name = "atp870u", .probe = atp870u_probe, @@ -2721,14 +3178,688 @@ static int __init atp870u_init(void) { - return pci_module_init(&atp870u_driver); +#ifdef ED_DBGP + printk("atp870u_init: Entry\n"); +#endif + return pci_register_driver(&atp870u_driver); } static void __exit atp870u_exit(void) { +#ifdef ED_DBGP + printk("atp870u_exit: Entry\n"); +#endif pci_unregister_driver(&atp870u_driver); } +void tscam_885(void) +{ + unsigned char i; + + for (i = 0; i < 0x2; i++) { + mdelay(300); + } + return; +} + + + +void is885(struct atp_unit *dev, unsigned int wkport,unsigned char c) +{ + unsigned int tmport; + unsigned char i, j, k, rmb, n, lvdmode; + unsigned short int m; + static unsigned char mbuf[512]; + static unsigned char satn[9] = {0, 0, 0, 0, 0, 0, 0, 6, 6}; + static unsigned char inqd[9] = {0x12, 0, 0, 0, 0x24, 0, 0, 0x24, 6}; + static unsigned char synn[6] = {0x80, 1, 3, 1, 0x19, 0x0e}; + unsigned char synu[6] = {0x80, 1, 3, 1, 0x0a, 0x0e}; + static unsigned char synw[6] = {0x80, 1, 3, 1, 0x19, 0x0e}; + unsigned char synuw[6] = {0x80, 1, 3, 1, 0x0a, 0x0e}; + static unsigned char wide[6] = {0x80, 1, 2, 3, 1, 0}; + static unsigned char u3[9] = { 0x80,1,6,4,0x09,00,0x0e,0x01,0x02 }; + + lvdmode=inb(wkport + 0x1b) >> 7; + + for (i = 0; i < 16; i++) { + m = 1; + m = m << i; + if ((m & dev->active_id[c]) != 0) { + continue; + } + if (i == dev->host_id[c]) { + printk(KERN_INFO " ID: %2d Host Adapter\n", dev->host_id[c]); + continue; + } + tmport = wkport + 0x1b; + outb(0x01, tmport); + tmport = wkport + 0x01; + outb(0x08, tmport++); + outb(0x7f, tmport++); + outb(satn[0], tmport++); + outb(satn[1], tmport++); + outb(satn[2], tmport++); + outb(satn[3], tmport++); + outb(satn[4], tmport++); + outb(satn[5], tmport++); + tmport += 0x06; + outb(0, tmport); + tmport += 0x02; + outb(dev->id[c][i].devsp, tmport++); + + outb(0, tmport++); + outb(satn[6], tmport++); + outb(satn[7], tmport++); + j = i; + if ((j & 0x08) != 0) { + j = (j & 0x07) | 0x40; + } + outb(j, tmport); + tmport += 0x03; + outb(satn[8], tmport); + tmport += 0x07; + + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) { + continue; + } + while (inb(tmport) != 0x8e); + dev->active_id[c] |= m; + + tmport = wkport + 0x10; + outb(0x30, tmport); + tmport = wkport + 0x14; + outb(0x00, tmport); + +phase_cmd: + tmport = wkport + 0x18; + outb(0x08, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + j = inb(tmport); + if (j != 0x16) { + tmport = wkport + 0x10; + outb(0x41, tmport); + goto phase_cmd; + } +sel_ok: + tmport = wkport + 0x03; + outb(inqd[0], tmport++); + outb(inqd[1], tmport++); + outb(inqd[2], tmport++); + outb(inqd[3], tmport++); + outb(inqd[4], tmport++); + outb(inqd[5], tmport); + tmport += 0x07; + outb(0, tmport); + tmport += 0x02; + outb(dev->id[c][i].devsp, tmport++); + outb(0, tmport++); + outb(inqd[6], tmport++); + outb(inqd[7], tmport++); + tmport += 0x03; + outb(inqd[8], tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) { + continue; + } + while (inb(tmport) != 0x8e); + tmport = wkport + 0x1b; + outb(0x00, tmport); + tmport = wkport + 0x18; + outb(0x08, tmport); + tmport += 0x07; + j = 0; +rd_inq_data: + k = inb(tmport); + if ((k & 0x01) != 0) { + tmport -= 0x06; + mbuf[j++] = inb(tmport); + tmport += 0x06; + goto rd_inq_data; + } + if ((k & 0x80) == 0) { + goto rd_inq_data; + } + tmport -= 0x08; + j = inb(tmport); + if (j == 0x16) { + goto inq_ok; + } + tmport = wkport + 0x10; + outb(0x46, tmport); + tmport += 0x02; + outb(0, tmport++); + outb(0, tmport++); + outb(0, tmport++); + tmport += 0x03; + outb(0x08, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + if (inb(tmport) != 0x16) { + goto sel_ok; + } +inq_ok: + mbuf[36] = 0; + printk( KERN_INFO" ID: %2d %s\n", i, &mbuf[8]); + dev->id[c][i].devtype = mbuf[0]; + rmb = mbuf[1]; + n = mbuf[7]; + if ((mbuf[7] & 0x60) == 0) { + goto not_wide; + } + if ((i < 8) && ((dev->global_map[c] & 0x20) == 0)) { + goto not_wide; + } + if (lvdmode == 0) { + goto chg_wide; + } + if (dev->sp[c][i] != 0x04) { // force u2 + goto chg_wide; + } + + tmport = wkport + 0x1b; + outb(0x01, tmport); + tmport = wkport + 0x03; + outb(satn[0], tmport++); + outb(satn[1], tmport++); + outb(satn[2], tmport++); + outb(satn[3], tmport++); + outb(satn[4], tmport++); + outb(satn[5], tmport++); + tmport += 0x06; + outb(0, tmport); + tmport += 0x02; + outb(dev->id[c][i].devsp, tmport++); + outb(0, tmport++); + outb(satn[6], tmport++); + outb(satn[7], tmport++); + tmport += 0x03; + outb(satn[8], tmport); + tmport += 0x07; + + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) { + continue; + } + while (inb(tmport) != 0x8e); +try_u3: + j = 0; + tmport = wkport + 0x14; + outb(0x09, tmport); + tmport += 0x04; + outb(0x20, tmport); + tmport += 0x07; + + while ((inb(tmport) & 0x80) == 0) { + if ((inb(tmport) & 0x01) != 0) { + tmport -= 0x06; + outb(u3[j++], tmport); + tmport += 0x06; + } + } + tmport -= 0x08; + while ((inb(tmport) & 0x80) == 0x00); + j = inb(tmport) & 0x0f; + if (j == 0x0f) { + goto u3p_in; + } + if (j == 0x0a) { + goto u3p_cmd; + } + if (j == 0x0e) { + goto try_u3; + } + continue; +u3p_out: + tmport = wkport + 0x18; + outb(0x20, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0) { + if ((inb(tmport) & 0x01) != 0) { + tmport -= 0x06; + outb(0, tmport); + tmport += 0x06; + } + } + tmport -= 0x08; + j = inb(tmport) & 0x0f; + if (j == 0x0f) { + goto u3p_in; + } + if (j == 0x0a) { + goto u3p_cmd; + } + if (j == 0x0e) { + goto u3p_out; + } + continue; +u3p_in: + tmport = wkport + 0x14; + outb(0x09, tmport); + tmport += 0x04; + outb(0x20, tmport); + tmport += 0x07; + k = 0; +u3p_in1: + j = inb(tmport); + if ((j & 0x01) != 0) { + tmport -= 0x06; + mbuf[k++] = inb(tmport); + tmport += 0x06; + goto u3p_in1; + } + if ((j & 0x80) == 0x00) { + goto u3p_in1; + } + tmport -= 0x08; + j = inb(tmport) & 0x0f; + if (j == 0x0f) { + goto u3p_in; + } + if (j == 0x0a) { + goto u3p_cmd; + } + if (j == 0x0e) { + goto u3p_out; + } + continue; +u3p_cmd: + tmport = wkport + 0x10; + outb(0x30, tmport); + tmport = wkport + 0x14; + outb(0x00, tmport); + tmport += 0x04; + outb(0x08, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + j = inb(tmport); + if (j != 0x16) { + if (j == 0x4e) { + goto u3p_out; + } + continue; + } + if (mbuf[0] != 0x01) { + goto chg_wide; + } + if (mbuf[1] != 0x06) { + goto chg_wide; + } + if (mbuf[2] != 0x04) { + goto chg_wide; + } + if (mbuf[3] == 0x09) { + m = 1; + m = m << i; + dev->wide_id[c] |= m; + dev->id[c][i].devsp = 0xce; +#ifdef ED_DBGP + printk("dev->id[%2d][%2d].devsp = %2x\n",c,i,dev->id[c][i].devsp); +#endif + continue; + } +chg_wide: + tmport = wkport + 0x1b; + outb(0x01, tmport); + tmport = wkport + 0x03; + outb(satn[0], tmport++); + outb(satn[1], tmport++); + outb(satn[2], tmport++); + outb(satn[3], tmport++); + outb(satn[4], tmport++); + outb(satn[5], tmport++); + tmport += 0x06; + outb(0, tmport); + tmport += 0x02; + outb(dev->id[c][i].devsp, tmport++); + outb(0, tmport++); + outb(satn[6], tmport++); + outb(satn[7], tmport++); + tmport += 0x03; + outb(satn[8], tmport); + tmport += 0x07; + + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) { + continue; + } + while (inb(tmport) != 0x8e); +try_wide: + j = 0; + tmport = wkport + 0x14; + outb(0x05, tmport); + tmport += 0x04; + outb(0x20, tmport); + tmport += 0x07; + + while ((inb(tmport) & 0x80) == 0) { + if ((inb(tmport) & 0x01) != 0) { + tmport -= 0x06; + outb(wide[j++], tmport); + tmport += 0x06; + } + } + tmport -= 0x08; + while ((inb(tmport) & 0x80) == 0x00); + j = inb(tmport) & 0x0f; + if (j == 0x0f) { + goto widep_in; + } + if (j == 0x0a) { + goto widep_cmd; + } + if (j == 0x0e) { + goto try_wide; + } + continue; +widep_out: + tmport = wkport + 0x18; + outb(0x20, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0) { + if ((inb(tmport) & 0x01) != 0) { + tmport -= 0x06; + outb(0, tmport); + tmport += 0x06; + } + } + tmport -= 0x08; + j = inb(tmport) & 0x0f; + if (j == 0x0f) { + goto widep_in; + } + if (j == 0x0a) { + goto widep_cmd; + } + if (j == 0x0e) { + goto widep_out; + } + continue; +widep_in: + tmport = wkport + 0x14; + outb(0xff, tmport); + tmport += 0x04; + outb(0x20, tmport); + tmport += 0x07; + k = 0; +widep_in1: + j = inb(tmport); + if ((j & 0x01) != 0) { + tmport -= 0x06; + mbuf[k++] = inb(tmport); + tmport += 0x06; + goto widep_in1; + } + if ((j & 0x80) == 0x00) { + goto widep_in1; + } + tmport -= 0x08; + j = inb(tmport) & 0x0f; + if (j == 0x0f) { + goto widep_in; + } + if (j == 0x0a) { + goto widep_cmd; + } + if (j == 0x0e) { + goto widep_out; + } + continue; +widep_cmd: + tmport = wkport + 0x10; + outb(0x30, tmport); + tmport = wkport + 0x14; + outb(0x00, tmport); + tmport += 0x04; + outb(0x08, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + j = inb(tmport); + if (j != 0x16) { + if (j == 0x4e) { + goto widep_out; + } + continue; + } + if (mbuf[0] != 0x01) { + goto not_wide; + } + if (mbuf[1] != 0x02) { + goto not_wide; + } + if (mbuf[2] != 0x03) { + goto not_wide; + } + if (mbuf[3] != 0x01) { + goto not_wide; + } + m = 1; + m = m << i; + dev->wide_id[c] |= m; +not_wide: + if ((dev->id[c][i].devtype == 0x00) || (dev->id[c][i].devtype == 0x07) || + ((dev->id[c][i].devtype == 0x05) && ((n & 0x10) != 0))) { + m = 1; + m = m << i; + if ((dev->async[c] & m) != 0) { + goto set_sync; + } + } + continue; +set_sync: + if (dev->sp[c][i] == 0x02) { + synu[4]=0x0c; + synuw[4]=0x0c; + } else { + if (dev->sp[c][i] >= 0x03) { + synu[4]=0x0a; + synuw[4]=0x0a; + } + } + tmport = wkport + 0x1b; + j = 0; + if ((m & dev->wide_id[c]) != 0) { + j |= 0x01; + } + outb(j, tmport); + tmport = wkport + 0x03; + outb(satn[0], tmport++); + outb(satn[1], tmport++); + outb(satn[2], tmport++); + outb(satn[3], tmport++); + outb(satn[4], tmport++); + outb(satn[5], tmport++); + tmport += 0x06; + outb(0, tmport); + tmport += 0x02; + outb(dev->id[c][i].devsp, tmport++); + outb(0, tmport++); + outb(satn[6], tmport++); + outb(satn[7], tmport++); + tmport += 0x03; + outb(satn[8], tmport); + tmport += 0x07; + + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + if ((inb(tmport) != 0x11) && (inb(tmport) != 0x8e)) { + continue; + } + while (inb(tmport) != 0x8e); +try_sync: + j = 0; + tmport = wkport + 0x14; + outb(0x06, tmport); + tmport += 0x04; + outb(0x20, tmport); + tmport += 0x07; + + while ((inb(tmport) & 0x80) == 0) { + if ((inb(tmport) & 0x01) != 0) { + tmport -= 0x06; + if ((m & dev->wide_id[c]) != 0) { + if ((m & dev->ultra_map[c]) != 0) { + outb(synuw[j++], tmport); + } else { + outb(synw[j++], tmport); + } + } else { + if ((m & dev->ultra_map[c]) != 0) { + outb(synu[j++], tmport); + } else { + outb(synn[j++], tmport); + } + } + tmport += 0x06; + } + } + tmport -= 0x08; + while ((inb(tmport) & 0x80) == 0x00); + j = inb(tmport) & 0x0f; + if (j == 0x0f) { + goto phase_ins; + } + if (j == 0x0a) { + goto phase_cmds; + } + if (j == 0x0e) { + goto try_sync; + } + continue; +phase_outs: + tmport = wkport + 0x18; + outb(0x20, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0x00) { + if ((inb(tmport) & 0x01) != 0x00) { + tmport -= 0x06; + outb(0x00, tmport); + tmport += 0x06; + } + } + tmport -= 0x08; + j = inb(tmport); + if (j == 0x85) { + goto tar_dcons; + } + j &= 0x0f; + if (j == 0x0f) { + goto phase_ins; + } + if (j == 0x0a) { + goto phase_cmds; + } + if (j == 0x0e) { + goto phase_outs; + } + continue; +phase_ins: + tmport = wkport + 0x14; + outb(0x06, tmport); + tmport += 0x04; + outb(0x20, tmport); + tmport += 0x07; + k = 0; +phase_ins1: + j = inb(tmport); + if ((j & 0x01) != 0x00) { + tmport -= 0x06; + mbuf[k++] = inb(tmport); + tmport += 0x06; + goto phase_ins1; + } + if ((j & 0x80) == 0x00) { + goto phase_ins1; + } + tmport -= 0x08; + while ((inb(tmport) & 0x80) == 0x00); + j = inb(tmport); + if (j == 0x85) { + goto tar_dcons; + } + j &= 0x0f; + if (j == 0x0f) { + goto phase_ins; + } + if (j == 0x0a) { + goto phase_cmds; + } + if (j == 0x0e) { + goto phase_outs; + } + continue; +phase_cmds: + tmport = wkport + 0x10; + outb(0x30, tmport); +tar_dcons: + tmport = wkport + 0x14; + outb(0x00, tmport); + tmport += 0x04; + outb(0x08, tmport); + tmport += 0x07; + while ((inb(tmport) & 0x80) == 0x00); + tmport -= 0x08; + j = inb(tmport); + if (j != 0x16) { + continue; + } + if (mbuf[0] != 0x01) { + continue; + } + if (mbuf[1] != 0x03) { + continue; + } + if (mbuf[4] == 0x00) { + continue; + } + if (mbuf[3] > 0x64) { + continue; + } + if (mbuf[4] > 0x0e) { + mbuf[4] = 0x0e; + } + dev->id[c][i].devsp = mbuf[4]; + if (mbuf[3] < 0x0c){ + j = 0xb0; + goto set_syn_ok; + } + if ((mbuf[3] < 0x0d) && (rmb == 0)) { + j = 0xa0; + goto set_syn_ok; + } + if (mbuf[3] < 0x1a) { + j = 0x20; + goto set_syn_ok; + } + if (mbuf[3] < 0x33) { + j = 0x40; + goto set_syn_ok; + } + if (mbuf[3] < 0x4c) { + j = 0x50; + goto set_syn_ok; + } + j = 0x60; + set_syn_ok: + dev->id[c][i].devsp = (dev->id[c][i].devsp & 0x0f) | j; +#ifdef ED_DBGP + printk("dev->id[%2d][%2d].devsp = %2x\n",c,i,dev->id[c][i].devsp); +#endif + } + tmport = wkport + 0x16; + outb(0x80, tmport); +} + module_init(atp870u_init); module_exit(atp870u_exit); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/scsi/atp870u.h linux-2.6.11/drivers/scsi/atp870u.h --- linux.vanilla-2.6.11/drivers/scsi/atp870u.h 2005-03-05 15:15:13.000000000 +0000 +++ linux-2.6.11/drivers/scsi/atp870u.h 2005-03-05 16:14:06.000000000 +0000 @@ -2,50 +2,64 @@ #define _ATP870U_H #include +#include /* I/O Port */ -#define MAX_CDB 12 -#define MAX_SENSE 14 -#define qcnt 32 -#define ATP870U_SCATTER 128 -#define ATP870U_CMDLUN 1 - -struct atp_unit { - unsigned long ioport; - unsigned long pciport; - unsigned char last_cmd; - unsigned char in_snd; - unsigned char in_int; - unsigned char quhdu; - unsigned char quendu; +#define MAX_CDB 12 +#define MAX_SENSE 14 +#define qcnt 32 +#define ATP870U_SCATTER 128 +#define ATP870U_CMDLUN 1 + +#define MAX_ADAPTER 8 +#define MAX_SCSI_ID 16 +#define ATP870U_MAX_SECTORS 128 + +#define ATP885_DEVID 0x808A +#define ATP880_DEVID1 0x8080 +#define ATP880_DEVID2 0x8081 + +//#define ED_DBGP + +struct atp_unit +{ + unsigned long baseport; + unsigned long ioport[2]; + unsigned long pciport[2]; + unsigned long irq; + unsigned char last_cmd[2]; + unsigned char in_snd[2]; + unsigned char in_int[2]; + unsigned char quhd[2]; + unsigned char quend[2]; + unsigned char global_map[2]; + unsigned char chip_ver; unsigned char scam_on; - unsigned char global_map; - unsigned char chip_veru; - unsigned char host_idu; - volatile int working; - unsigned short wide_idu; - unsigned short active_idu; - unsigned short ultra_map; - unsigned short async; - unsigned short deviceid; - unsigned char ata_cdbu[16]; - unsigned char sp[16]; - struct scsi_cmnd *querequ[qcnt]; - struct atp_id { - unsigned char dirctu; - unsigned char devspu; - unsigned char devtypeu; - unsigned long prdaddru; - unsigned long tran_lenu; - unsigned long last_lenu; - unsigned char *prd_posu; - unsigned char *prd_tableu; - dma_addr_t prd_phys; + unsigned char host_id[2]; + unsigned int working[2]; + unsigned short wide_id[2]; + unsigned short active_id[2]; + unsigned short ultra_map[2]; + unsigned short async[2]; + unsigned short dev_id; + unsigned char sp[2][16]; + unsigned char r1f[2][16]; + struct scsi_cmnd *quereq[2][qcnt]; + struct atp_id + { + unsigned char dirct; + unsigned char devsp; + unsigned char devtype; + unsigned long tran_len; + unsigned long last_len; + unsigned char *prd_pos; + unsigned char *prd_table; + dma_addr_t prdaddr; struct scsi_cmnd *curr_req; - } id[16]; - struct Scsi_Host *host; - struct pci_dev *pdev; + } id[2][16]; + struct Scsi_Host *host; + struct pci_dev *pdev; unsigned int unit; }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/scsi/ide-scsi.c linux-2.6.11/drivers/scsi/ide-scsi.c --- linux.vanilla-2.6.11/drivers/scsi/ide-scsi.c 2005-03-05 15:17:04.000000000 +0000 +++ linux-2.6.11/drivers/scsi/ide-scsi.c 2005-03-06 17:25:05.000000000 +0000 @@ -544,7 +544,7 @@ drive->hwif->atapi_output_bytes(drive, scsi->pc->c, 12); if (test_bit (PC_DMA_OK, &pc->flags)) { set_bit (PC_DMA_IN_PROGRESS, &pc->flags); - hwif->dma_start(drive); + hwif->ide_dma_start(drive); } return ide_started; } @@ -611,7 +611,7 @@ feature.all = 0; if (drive->using_dma && !idescsi_map_sg(drive, pc)) { hwif->sg_mapped = 1; - feature.b.dma = !hwif->dma_setup(drive); + feature.b.dma = !hwif->ide_dma_setup(drive); hwif->sg_mapped = 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/scsi/Kconfig linux-2.6.11/drivers/scsi/Kconfig --- linux.vanilla-2.6.11/drivers/scsi/Kconfig 2005-03-05 15:17:04.000000000 +0000 +++ linux-2.6.11/drivers/scsi/Kconfig 2005-03-05 16:14:25.000000000 +0000 @@ -273,8 +273,8 @@ tristate "ACARD SCSI support" depends on PCI && SCSI help - This driver supports the ACARD 870U/W SCSI host adapter. - + This driver supports the ACARD SCSI host adapter. + Support Chip To compile this driver as a module, choose M here: the module will be called atp870u. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/scsi/nsp32.h linux-2.6.11/drivers/scsi/nsp32.h --- linux.vanilla-2.6.11/drivers/scsi/nsp32.h 2005-03-05 15:15:13.000000000 +0000 +++ linux-2.6.11/drivers/scsi/nsp32.h 2005-03-05 16:14:43.000000000 +0000 @@ -22,7 +22,6 @@ * VENDOR/DEVICE ID */ #define PCI_VENDOR_ID_IODATA 0x10fc -#define PCI_VENDOR_ID_WORKBIT 0x1145 #define PCI_DEVICE_ID_NINJASCSI_32BI_CBSC_II 0x0005 #define PCI_DEVICE_ID_NINJASCSI_32BI_KME 0xf007 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/usb/media/Kconfig linux-2.6.11/drivers/usb/media/Kconfig --- linux.vanilla-2.6.11/drivers/usb/media/Kconfig 2005-03-05 15:15:14.000000000 +0000 +++ linux-2.6.11/drivers/usb/media/Kconfig 2005-03-05 15:26:35.000000000 +0000 @@ -175,3 +175,39 @@ To compile this driver as a module, choose M here: the module will be called w9968cf. + +config USB_PWC + tristate "USB Philips Cameras" + depends on USB && VIDEO_DEV + ---help--- + Say Y or M here if you want to use one of these Philips & OEM + webcams: + * Philips PCA645, PCA646 + * Philips PCVC675, PCVC680, PCVC690 + * Philips PCVC720/40, PCVC730, PCVC740, PCVC750 + * Askey VC010 + * Logitech QuickCam Pro 3000, 4000, 'Zoom', 'Notebook Pro' + and 'Orbit'/'Sphere' + * Samsung MPC-C10, MPC-C30 + * Creative Webcam 5, Pro Ex + * SOTEC Afina Eye + * Visionite VCS-UC300, VCS-UM100 + + The PCA635, PCVC665 and PCVC720/20 are not supported by this driver + and never will be, but the 665 and 720/20 are supported by other + drivers. + + See for more information and + installation instructions. + + The built-in microphone is enabled by selecting USB Audio support. + + This driver uses the Video For Linux API. You must say Y or M to + "Video For Linux" (under Character Devices) to use this driver. + Information on this API and pointers to "v4l" programs may be found + at . + + To compile this driver as a module, choose M here: the + module will be called pwc. + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/usb/media/Makefile linux-2.6.11/drivers/usb/media/Makefile --- linux.vanilla-2.6.11/drivers/usb/media/Makefile 2005-03-05 15:17:05.000000000 +0000 +++ linux-2.6.11/drivers/usb/media/Makefile 2005-03-05 15:26:35.000000000 +0000 @@ -14,3 +14,4 @@ obj-$(CONFIG_USB_STV680) += stv680.o obj-$(CONFIG_USB_VICAM) += vicam.o usbvideo.o obj-$(CONFIG_USB_W9968CF) += w9968cf.o +obj-$(CONFIG_USB_PWC) += pwc/ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/usb/media/pwc/ChangeLog linux-2.6.11/drivers/usb/media/pwc/ChangeLog --- linux.vanilla-2.6.11/drivers/usb/media/pwc/ChangeLog 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.11/drivers/usb/media/pwc/ChangeLog 2005-03-05 15:26:35.000000000 +0000 @@ -0,0 +1,143 @@ +9.0.2 + +* Adding #ifdef to compile PWC before and after 2.6.5 + +9.0.1 + +9.0 + + +8.12 + +* Implement motorized pan/tilt feature for Logitech QuickCam Orbit/Spere. + +8.11.1 + +* Fix for PCVC720/40, would not be able to set videomode +* Fix for Samsung MPC models, appearantly they are based on a newer chipset + +8.11 + +* 20 dev_hints (per request) +* Hot unplugging should be better, no more dangling pointers or memory leaks +* Added reserved Logitech webcam IDs +* Device now remembers size & fps between close()/open() +* Removed palette stuff altogether + +8.10.1 + +* Added IDs for PCVC720K/40 and Creative Labs Webcam Pro + +8.10 + +* Fixed ID for QuickCam Notebook pro +* Added GREALSIZE ioctl() call +* Fixed bug in case PWCX was not loaded and invalid size was set + +8.9 + +* Merging with kernel 2.5.49 +* Adding IDs for QuickCam Zoom & QuickCam Notebook + +8.8 + +* Fixing 'leds' parameter +* Adding IDs for Logitech QuickCam Pro 4000 +* Making URB init/cleanup a little nicer + +8.7 + +* Incorporating changes in ioctl() parameter passing +* Also changes to URB mechanism + +8.6 + +* Added ID's for Visionite VCS UM100 and UC300 +* Removed YUV420-interlaced palette altogether (was confusing) +* Removed MIRROR stuff as it didn't work anyway +* Fixed a problem with the 'leds' parameter (wouldn't blink) +* Added ioctl()s for advanced features: 'extended' whitebalance ioctl()s, + CONTOUR, BACKLIGHT, FLICKER, DYNNOISE. +* VIDIOCGCAP.name now contains real camera model name instead of + 'Philips xxx webcam' +* Added PROBE ioctl (see previous point & API doc) + +8.5 + +* Adding IDs for Creative Labs Webcam 5 +* Adding IDs for SOTEC CMS-001 webcam +* Solving possible hang in VIDIOCSYNC when unplugging the cam +* Forgot to return structure in VIDIOCPWCGAWB, oops +* Time interval for the LEDs are now in milliseconds + +8.4 + +* Fixing power_save option for Vesta range +* Handling new error codes in ISOC callback +* Adding dev_hint module parameter, to specify /dev/videoX device nodes + +8.3 + +* Adding Samsung C10 and C30 cameras +* Removing palette module parameter +* Fixed typo in ID of QuickCam 3000 Pro +* Adding LED settings (blinking while in use) for ToUCam cameras. +* Turns LED off when camera is not in use. + +8.2 + +* Making module more silent when trace = 0 +* Adding QuickCam 3000 Pro IDs +* Chrominance control for the Vesta cameras +* Hopefully fixed problems on machines with BIGMEM and > 1GB of RAM +* Included Oliver Neukem's lock_kernel() patch +* Allocates less memory for image buffers +* Adds ioctl()s for the whitebalancing + +8.1 + +* Adding support for 750 +* Adding V4L GAUDIO/SAUDIO/UNIT ioctl() calls + +8.0 +* 'damage control' after inclusion in 2.4.5. +* Changed wait-queue mechanism in read/mmap/poll according to the book. +* Included YUV420P palette. +* Changed interface to decompressor module. +* Cleaned up pwc structure a bit. + +7.0 + +* Fixed bug in vcvt_420i_yuyv; extra variables on stack were misaligned. +* There is now a clear error message when an image size is selected that + is only supported using the decompressor, and the decompressor isn't + loaded. +* When the decompressor wasn't loaded, selecting large image size + would create skewed or double images. + +6.3 + +* Introduced spinlocks for the buffer pointer manipulation; a number of + reports seem to suggest the down()/up() semaphores were the cause of + lockups, since they are not suitable for interrupt/user locking. +* Separated decompressor and core code into 2 modules. + +6.2 + +* Non-integral image sizes are now padded with gray or black. +* Added SHUTTERSPEED ioctl(). +* Fixed buglet in VIDIOCPWCSAGC; the function would always return an error, + even though the call succeeded. +* Added hotplug support for 2.4.*. +* Memory: the 645/646 uses less memory now. + +6.1 + +* VIDIOCSPICT returns -EINVAL with invalid palettes. +* Added saturation control. +* Split decompressors from rest. +* Fixed bug that would reset the framerate to the default framerate if + the rate field was set to 0 (which is not what I intended, nl. do not + change the framerate!). +* VIDIOCPWCSCQUAL (setting compression quality) now takes effect immediately. +* Workaround for a bug in the 730 sensor. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/usb/media/pwc/Makefile linux-2.6.11/drivers/usb/media/pwc/Makefile --- linux.vanilla-2.6.11/drivers/usb/media/pwc/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.11/drivers/usb/media/pwc/Makefile 2005-03-05 15:26:35.000000000 +0000 @@ -0,0 +1,20 @@ +ifneq ($(KERNELRELEASE),) + +pwc-objs := pwc-if.o pwc-misc.o pwc-ctrl.o pwc-uncompress.o pwc-dec1.o pwc-dec23.o pwc-kiara.o pwc-timon.o + +obj-$(CONFIG_USB_PWC) += pwc.o + +else + +KDIR := /lib/modules/$(shell uname -r)/build +PWD := $(shell pwd) + +default: + $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules + +endif + +clean: + rm -f *.[oas] .*.flags *.ko .*.cmd .*.d .*.tmp *.mod.c + rm -rf .tmp_versions + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-ctrl.c linux-2.6.11/drivers/usb/media/pwc/pwc-ctrl.c --- linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-ctrl.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.11/drivers/usb/media/pwc/pwc-ctrl.c 2005-03-05 15:26:35.000000000 +0000 @@ -0,0 +1,1630 @@ +/* Driver for Philips webcam + Functions that send various control messages to the webcam, including + video modes. + (C) 1999-2003 Nemosoft Unv. + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + Changes + 2001/08/03 Alvarado Added methods for changing white balance and + red/green gains + */ + +/* Control functions for the cam; brightness, contrast, video mode, etc. */ + +#ifdef __KERNEL__ +#include +#endif +#include +#include + +#include "pwc.h" +#include "pwc-ioctl.h" +#include "pwc-uncompress.h" +#include "pwc-kiara.h" +#include "pwc-timon.h" +#include "pwc-dec1.h" +#include "pwc-dec23.h" + +/* Request types: video */ +#define SET_LUM_CTL 0x01 +#define GET_LUM_CTL 0x02 +#define SET_CHROM_CTL 0x03 +#define GET_CHROM_CTL 0x04 +#define SET_STATUS_CTL 0x05 +#define GET_STATUS_CTL 0x06 +#define SET_EP_STREAM_CTL 0x07 +#define GET_EP_STREAM_CTL 0x08 +#define SET_MPT_CTL 0x0D +#define GET_MPT_CTL 0x0E + +/* Selectors for the Luminance controls [GS]ET_LUM_CTL */ +#define AGC_MODE_FORMATTER 0x2000 +#define PRESET_AGC_FORMATTER 0x2100 +#define SHUTTER_MODE_FORMATTER 0x2200 +#define PRESET_SHUTTER_FORMATTER 0x2300 +#define PRESET_CONTOUR_FORMATTER 0x2400 +#define AUTO_CONTOUR_FORMATTER 0x2500 +#define BACK_LIGHT_COMPENSATION_FORMATTER 0x2600 +#define CONTRAST_FORMATTER 0x2700 +#define DYNAMIC_NOISE_CONTROL_FORMATTER 0x2800 +#define FLICKERLESS_MODE_FORMATTER 0x2900 +#define AE_CONTROL_SPEED 0x2A00 +#define BRIGHTNESS_FORMATTER 0x2B00 +#define GAMMA_FORMATTER 0x2C00 + +/* Selectors for the Chrominance controls [GS]ET_CHROM_CTL */ +#define WB_MODE_FORMATTER 0x1000 +#define AWB_CONTROL_SPEED_FORMATTER 0x1100 +#define AWB_CONTROL_DELAY_FORMATTER 0x1200 +#define PRESET_MANUAL_RED_GAIN_FORMATTER 0x1300 +#define PRESET_MANUAL_BLUE_GAIN_FORMATTER 0x1400 +#define COLOUR_MODE_FORMATTER 0x1500 +#define SATURATION_MODE_FORMATTER1 0x1600 +#define SATURATION_MODE_FORMATTER2 0x1700 + +/* Selectors for the Status controls [GS]ET_STATUS_CTL */ +#define SAVE_USER_DEFAULTS_FORMATTER 0x0200 +#define RESTORE_USER_DEFAULTS_FORMATTER 0x0300 +#define RESTORE_FACTORY_DEFAULTS_FORMATTER 0x0400 +#define READ_AGC_FORMATTER 0x0500 +#define READ_SHUTTER_FORMATTER 0x0600 +#define READ_RED_GAIN_FORMATTER 0x0700 +#define READ_BLUE_GAIN_FORMATTER 0x0800 +#define SENSOR_TYPE_FORMATTER1 0x0C00 +#define READ_RAW_Y_MEAN_FORMATTER 0x3100 +#define SET_POWER_SAVE_MODE_FORMATTER 0x3200 +#define MIRROR_IMAGE_FORMATTER 0x3300 +#define LED_FORMATTER 0x3400 +#define SENSOR_TYPE_FORMATTER2 0x3700 + +/* Formatters for the Video Endpoint controls [GS]ET_EP_STREAM_CTL */ +#define VIDEO_OUTPUT_CONTROL_FORMATTER 0x0100 + +/* Formatters for the motorized pan & tilt [GS]ET_MPT_CTL */ +#define PT_RELATIVE_CONTROL_FORMATTER 0x01 +#define PT_RESET_CONTROL_FORMATTER 0x02 +#define PT_STATUS_FORMATTER 0x03 + +static char *size2name[PSZ_MAX] = +{ + "subQCIF", + "QSIF", + "QCIF", + "SIF", + "CIF", + "VGA", +}; + +/********/ + +/* Entries for the Nala (645/646) camera; the Nala doesn't have compression + preferences, so you either get compressed or non-compressed streams. + + An alternate value of 0 means this mode is not available at all. + */ + +struct Nala_table_entry { + char alternate; /* USB alternate setting */ + int compressed; /* Compressed yes/no */ + + unsigned char mode[3]; /* precomputed mode table */ +}; + +static struct Nala_table_entry Nala_table[PSZ_MAX][8] = +{ +#include "pwc-nala.h" +}; + + +/****************************************************************************/ + + +#define SendControlMsg(request, value, buflen) \ + usb_control_msg(pdev->udev, usb_sndctrlpipe(pdev->udev, 0), \ + request, \ + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ + value, \ + pdev->vcinterface, \ + &buf, buflen, HZ / 2) + +#define RecvControlMsg(request, value, buflen) \ + usb_control_msg(pdev->udev, usb_rcvctrlpipe(pdev->udev, 0), \ + request, \ + USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE, \ + value, \ + pdev->vcinterface, \ + &buf, buflen, HZ / 2) + + +#if PWC_DEBUG +void pwc_hexdump(void *p, int len) +{ + int i; + unsigned char *s; + char buf[100], *d; + + s = (unsigned char *)p; + d = buf; + *d = '\0'; + Debug("Doing hexdump @ %p, %d bytes.\n", p, len); + for (i = 0; i < len; i++) { + d += sprintf(d, "%02X ", *s++); + if ((i & 0xF) == 0xF) { + Debug("%s\n", buf); + d = buf; + *d = '\0'; + } + } + if ((i & 0xF) != 0) + Debug("%s\n", buf); +} +#endif + +static inline int send_video_command(struct usb_device *udev, int index, void *buf, int buflen) +{ + return usb_control_msg(udev, + usb_sndctrlpipe(udev, 0), + SET_EP_STREAM_CTL, + USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE, + VIDEO_OUTPUT_CONTROL_FORMATTER, + index, + buf, buflen, HZ); +} + + + +static inline int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames) +{ + unsigned char buf[3]; + int ret, fps; + struct Nala_table_entry *pEntry; + int frames2frames[31] = + { /* closest match of framerate */ + 0, 0, 0, 0, 4, /* 0-4 */ + 5, 5, 7, 7, 10, /* 5-9 */ + 10, 10, 12, 12, 15, /* 10-14 */ + 15, 15, 15, 20, 20, /* 15-19 */ + 20, 20, 20, 24, 24, /* 20-24 */ + 24, 24, 24, 24, 24, /* 25-29 */ + 24 /* 30 */ + }; + int frames2table[31] = + { 0, 0, 0, 0, 0, /* 0-4 */ + 1, 1, 1, 2, 2, /* 5-9 */ + 3, 3, 4, 4, 4, /* 10-14 */ + 5, 5, 5, 5, 5, /* 15-19 */ + 6, 6, 6, 6, 7, /* 20-24 */ + 7, 7, 7, 7, 7, /* 25-29 */ + 7 /* 30 */ + }; + + if (size < 0 || size > PSZ_CIF || frames < 4 || frames > 25) + return -EINVAL; + frames = frames2frames[frames]; + fps = frames2table[frames]; + pEntry = &Nala_table[size][fps]; + if (pEntry->alternate == 0) + return -EINVAL; + + if (pEntry->compressed) + return -ENOENT; /* Not supported. */ + + memcpy(buf, pEntry->mode, 3); + ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 3); + if (ret < 0) { + Debug("Failed to send video command... %d\n", ret); + return ret; + } + if (pEntry->compressed && pdev->vpalette != VIDEO_PALETTE_RAW) + { + switch(pdev->type) { + case 645: + case 646: + pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data); + break; + + case 675: + case 680: + case 690: + case 720: + case 730: + case 740: + case 750: + pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); + break; + } + } + + pdev->cmd_len = 3; + memcpy(pdev->cmd_buf, buf, 3); + + /* Set various parameters */ + pdev->vframes = frames; + pdev->vsize = size; + pdev->valternate = pEntry->alternate; + pdev->image = pwc_image_sizes[size]; + pdev->frame_size = (pdev->image.x * pdev->image.y * 3) / 2; + if (pEntry->compressed) { + if (pdev->release < 5) { /* 4 fold compression */ + pdev->vbandlength = 528; + pdev->frame_size /= 4; + } + else { + pdev->vbandlength = 704; + pdev->frame_size /= 3; + } + } + else + pdev->vbandlength = 0; + return 0; +} + + +static inline int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) +{ + unsigned char buf[13]; + const struct Timon_table_entry *pChoose; + int ret, fps; + + if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) + return -EINVAL; + if (size == PSZ_VGA && frames > 15) + return -EINVAL; + fps = (frames / 5) - 1; + + /* Find a supported framerate with progressively higher compression ratios + if the preferred ratio is not available. + */ + pChoose = NULL; + while (compression <= 3) { + pChoose = &Timon_table[size][fps][compression]; + if (pChoose->alternate != 0) + break; + compression++; + } + if (pChoose == NULL || pChoose->alternate == 0) + return -ENOENT; /* Not supported. */ + + memcpy(buf, pChoose->mode, 13); + if (snapshot) + buf[0] |= 0x80; + ret = send_video_command(pdev->udev, pdev->vendpoint, buf, 13); + if (ret < 0) + return ret; + + if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW) + pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); + + pdev->cmd_len = 13; + memcpy(pdev->cmd_buf, buf, 13); + + /* Set various parameters */ + pdev->vframes = frames; + pdev->vsize = size; + pdev->vsnapshot = snapshot; + pdev->valternate = pChoose->alternate; + pdev->image = pwc_image_sizes[size]; + pdev->vbandlength = pChoose->bandlength; + if (pChoose->bandlength > 0) + pdev->frame_size = (pChoose->bandlength * pdev->image.y) / 4; + else + pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; + return 0; +} + + +static inline int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, int compression, int snapshot) +{ + const struct Kiara_table_entry *pChoose = 0; + int fps, ret; + unsigned char buf[12]; + struct Kiara_table_entry RawEntry = {6, 773, 1272, {0xAD, 0xF4, 0x10, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}; + + if (size >= PSZ_MAX || frames < 5 || frames > 30 || compression < 0 || compression > 3) + return -EINVAL; + if (size == PSZ_VGA && frames > 15) + return -EINVAL; + fps = (frames / 5) - 1; + + /* special case: VGA @ 5 fps and snapshot is raw bayer mode */ + if (size == PSZ_VGA && frames == 5 && snapshot) + { + /* Only available in case the raw palette is selected or + we have the decompressor available. This mode is + only available in compressed form + */ + if (pdev->vpalette == VIDEO_PALETTE_RAW) + { + Info("Choosing VGA/5 BAYER mode (%d).\n", pdev->vpalette); + pChoose = &RawEntry; + } + else + { + Info("VGA/5 BAYER mode _must_ have a decompressor available, or use RAW palette.\n"); + } + } + else + { + /* Find a supported framerate with progressively higher compression ratios + if the preferred ratio is not available. + Skip this step when using RAW modes. + */ + while (compression <= 3) { + pChoose = &Kiara_table[size][fps][compression]; + if (pChoose->alternate != 0) + break; + compression++; + } + } + if (pChoose == NULL || pChoose->alternate == 0) + return -ENOENT; /* Not supported. */ + + Debug("Using alternate setting %d.\n", pChoose->alternate); + + /* usb_control_msg won't take staticly allocated arrays as argument?? */ + memcpy(buf, pChoose->mode, 12); + if (snapshot) + buf[0] |= 0x80; + + /* Firmware bug: video endpoint is 5, but commands are sent to endpoint 4 */ + ret = send_video_command(pdev->udev, 4 /* pdev->vendpoint */, buf, 12); + if (ret < 0) + return ret; + + if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW) + pwc_dec23_init(pdev->type, pdev->release, buf, pdev->decompress_data); + + pdev->cmd_len = 12; + memcpy(pdev->cmd_buf, buf, 12); + /* All set and go */ + pdev->vframes = frames; + pdev->vsize = size; + pdev->vsnapshot = snapshot; + pdev->valternate = pChoose->alternate; + pdev->image = pwc_image_sizes[size]; + pdev->vbandlength = pChoose->bandlength; + if (pdev->vbandlength > 0) + pdev->frame_size = (pdev->vbandlength * pdev->image.y) / 4; + else + pdev->frame_size = (pdev->image.x * pdev->image.y * 12) / 8; + return 0; +} + + + +/** + @pdev: device structure + @width: viewport width + @height: viewport height + @frame: framerate, in fps + @compression: preferred compression ratio + @snapshot: snapshot mode or streaming + */ +int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot) +{ + int ret, size; + + Trace(TRACE_FLOW, "set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette); + size = pwc_decode_size(pdev, width, height); + if (size < 0) { + Debug("Could not find suitable size.\n"); + return -ERANGE; + } + Debug("decode_size = %d.\n", size); + + ret = -EINVAL; + switch(pdev->type) { + case 645: + case 646: + ret = set_video_mode_Nala(pdev, size, frames); + break; + + case 675: + case 680: + case 690: + ret = set_video_mode_Timon(pdev, size, frames, compression, snapshot); + break; + + case 720: + case 730: + case 740: + case 750: + ret = set_video_mode_Kiara(pdev, size, frames, compression, snapshot); + break; + } + if (ret < 0) { + if (ret == -ENOENT) + Info("Video mode %s@%d fps is only supported with the decompressor module (pwcx).\n", size2name[size], frames); + else { + Err("Failed to set video mode %s@%d fps; return code = %d\n", size2name[size], frames, ret); + } + return ret; + } + pdev->view.x = width; + pdev->view.y = height; + pdev->frame_total_size = pdev->frame_size + pdev->frame_header_size + pdev->frame_trailer_size; + pwc_set_image_buffer_size(pdev); + Trace(TRACE_SIZE, "Set viewport to %dx%d, image size is %dx%d.\n", width, height, pwc_image_sizes[size].x, pwc_image_sizes[size].y); + return 0; +} + + +void pwc_set_image_buffer_size(struct pwc_device *pdev) +{ + int i, factor = 0, filler = 0; + + /* for PALETTE_YUV420P */ + switch(pdev->vpalette) + { + case VIDEO_PALETTE_YUV420P: + factor = 6; + filler = 128; + break; + case VIDEO_PALETTE_RAW: + factor = 6; /* can be uncompressed YUV420P */ + filler = 0; + break; + } + + /* Set sizes in bytes */ + pdev->image.size = pdev->image.x * pdev->image.y * factor / 4; + pdev->view.size = pdev->view.x * pdev->view.y * factor / 4; + + /* Align offset, or you'll get some very weird results in + YUV420 mode... x must be multiple of 4 (to get the Y's in + place), and y even (or you'll mixup U & V). This is less of a + problem for YUV420P. + */ + pdev->offset.x = ((pdev->view.x - pdev->image.x) / 2) & 0xFFFC; + pdev->offset.y = ((pdev->view.y - pdev->image.y) / 2) & 0xFFFE; + + /* Fill buffers with gray or black */ + for (i = 0; i < MAX_IMAGES; i++) { + if (pdev->image_ptr[i] != NULL) + memset(pdev->image_ptr[i], filler, pdev->view.size); + } +} + + + +/* BRIGHTNESS */ + +int pwc_get_brightness(struct pwc_device *pdev) +{ + char buf; + int ret; + + ret = RecvControlMsg(GET_LUM_CTL, BRIGHTNESS_FORMATTER, 1); + if (ret < 0) + return ret; + return buf << 9; +} + +int pwc_set_brightness(struct pwc_device *pdev, int value) +{ + char buf; + + if (value < 0) + value = 0; + if (value > 0xffff) + value = 0xffff; + buf = (value >> 9) & 0x7f; + return SendControlMsg(SET_LUM_CTL, BRIGHTNESS_FORMATTER, 1); +} + +/* CONTRAST */ + +int pwc_get_contrast(struct pwc_device *pdev) +{ + char buf; + int ret; + + ret = RecvControlMsg(GET_LUM_CTL, CONTRAST_FORMATTER, 1); + if (ret < 0) + return ret; + return buf << 10; +} + +int pwc_set_contrast(struct pwc_device *pdev, int value) +{ + char buf; + + if (value < 0) + value = 0; + if (value > 0xffff) + value = 0xffff; + buf = (value >> 10) & 0x3f; + return SendControlMsg(SET_LUM_CTL, CONTRAST_FORMATTER, 1); +} + +/* GAMMA */ + +int pwc_get_gamma(struct pwc_device *pdev) +{ + char buf; + int ret; + + ret = RecvControlMsg(GET_LUM_CTL, GAMMA_FORMATTER, 1); + if (ret < 0) + return ret; + return buf << 11; +} + +int pwc_set_gamma(struct pwc_device *pdev, int value) +{ + char buf; + + if (value < 0) + value = 0; + if (value > 0xffff) + value = 0xffff; + buf = (value >> 11) & 0x1f; + return SendControlMsg(SET_LUM_CTL, GAMMA_FORMATTER, 1); +} + + +/* SATURATION */ + +int pwc_get_saturation(struct pwc_device *pdev) +{ + char buf; + int ret; + + if (pdev->type < 675) + return -1; + ret = RecvControlMsg(GET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1); + if (ret < 0) + return ret; + return 32768 + buf * 327; +} + +int pwc_set_saturation(struct pwc_device *pdev, int value) +{ + char buf; + + if (pdev->type < 675) + return -EINVAL; + if (value < 0) + value = 0; + if (value > 0xffff) + value = 0xffff; + /* saturation ranges from -100 to +100 */ + buf = (value - 32768) / 327; + return SendControlMsg(SET_CHROM_CTL, pdev->type < 730 ? SATURATION_MODE_FORMATTER2 : SATURATION_MODE_FORMATTER1, 1); +} + +/* AGC */ + +static inline int pwc_set_agc(struct pwc_device *pdev, int mode, int value) +{ + char buf; + int ret; + + if (mode) + buf = 0x0; /* auto */ + else + buf = 0xff; /* fixed */ + + ret = SendControlMsg(SET_LUM_CTL, AGC_MODE_FORMATTER, 1); + + if (!mode && ret >= 0) { + if (value < 0) + value = 0; + if (value > 0xffff) + value = 0xffff; + buf = (value >> 10) & 0x3F; + ret = SendControlMsg(SET_LUM_CTL, PRESET_AGC_FORMATTER, 1); + } + if (ret < 0) + return ret; + return 0; +} + +static inline int pwc_get_agc(struct pwc_device *pdev, int *value) +{ + unsigned char buf; + int ret; + + ret = RecvControlMsg(GET_LUM_CTL, AGC_MODE_FORMATTER, 1); + if (ret < 0) + return ret; + + if (buf != 0) { /* fixed */ + ret = RecvControlMsg(GET_LUM_CTL, PRESET_AGC_FORMATTER, 1); + if (ret < 0) + return ret; + if (buf > 0x3F) + buf = 0x3F; + *value = (buf << 10); + } + else { /* auto */ + ret = RecvControlMsg(GET_STATUS_CTL, READ_AGC_FORMATTER, 1); + if (ret < 0) + return ret; + /* Gah... this value ranges from 0x00 ... 0x9F */ + if (buf > 0x9F) + buf = 0x9F; + *value = -(48 + buf * 409); + } + + return 0; +} + +static inline int pwc_set_shutter_speed(struct pwc_device *pdev, int mode, int value) +{ + char buf[2]; + int speed, ret; + + + if (mode) + buf[0] = 0x0; /* auto */ + else + buf[0] = 0xff; /* fixed */ + + ret = SendControlMsg(SET_LUM_CTL, SHUTTER_MODE_FORMATTER, 1); + + if (!mode && ret >= 0) { + if (value < 0) + value = 0; + if (value > 0xffff) + value = 0xffff; + switch(pdev->type) { + case 675: + case 680: + case 690: + /* speed ranges from 0x0 to 0x290 (656) */ + speed = (value / 100); + buf[1] = speed >> 8; + buf[0] = speed & 0xff; + break; + case 720: + case 730: + case 740: + case 750: + /* speed seems to range from 0x0 to 0xff */ + buf[1] = 0; + buf[0] = value >> 8; + break; + } + + ret = SendControlMsg(SET_LUM_CTL, PRESET_SHUTTER_FORMATTER, 2); + } + return ret; +} + + +/* POWER */ + +int pwc_camera_power(struct pwc_device *pdev, int power) +{ + char buf; + + if (pdev->type < 675 || (pdev->type < 730 && pdev->release < 6)) + return 0; /* Not supported by Nala or Timon < release 6 */ + + if (power) + buf = 0x00; /* active */ + else + buf = 0xFF; /* power save */ + return SendControlMsg(SET_STATUS_CTL, SET_POWER_SAVE_MODE_FORMATTER, 1); +} + + + +/* private calls */ + +static inline int pwc_restore_user(struct pwc_device *pdev) +{ + char buf; /* dummy */ + return SendControlMsg(SET_STATUS_CTL, RESTORE_USER_DEFAULTS_FORMATTER, 0); +} + +static inline int pwc_save_user(struct pwc_device *pdev) +{ + char buf; /* dummy */ + return SendControlMsg(SET_STATUS_CTL, SAVE_USER_DEFAULTS_FORMATTER, 0); +} + +static inline int pwc_restore_factory(struct pwc_device *pdev) +{ + char buf; /* dummy */ + return SendControlMsg(SET_STATUS_CTL, RESTORE_FACTORY_DEFAULTS_FORMATTER, 0); +} + + /* ************************************************* */ + /* Patch by Alvarado: (not in the original version */ + + /* + * the camera recognizes modes from 0 to 4: + * + * 00: indoor (incandescant lighting) + * 01: outdoor (sunlight) + * 02: fluorescent lighting + * 03: manual + * 04: auto + */ +static inline int pwc_set_awb(struct pwc_device *pdev, int mode) +{ + char buf; + int ret; + + if (mode < 0) + mode = 0; + + if (mode > 4) + mode = 4; + + buf = mode & 0x07; /* just the lowest three bits */ + + ret = SendControlMsg(SET_CHROM_CTL, WB_MODE_FORMATTER, 1); + + if (ret < 0) + return ret; + return 0; +} + +static inline int pwc_get_awb(struct pwc_device *pdev) +{ + unsigned char buf; + int ret; + + ret = RecvControlMsg(GET_CHROM_CTL, WB_MODE_FORMATTER, 1); + + if (ret < 0) + return ret; + return buf; +} + +static inline int pwc_set_red_gain(struct pwc_device *pdev, int value) +{ + unsigned char buf; + + if (value < 0) + value = 0; + if (value > 0xffff) + value = 0xffff; + /* only the msb is considered */ + buf = value >> 8; + return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1); +} + +static inline int pwc_get_red_gain(struct pwc_device *pdev, int *value) +{ + unsigned char buf; + int ret; + + ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_RED_GAIN_FORMATTER, 1); + if (ret < 0) + return ret; + *value = buf << 8; + return 0; +} + + +static inline int pwc_set_blue_gain(struct pwc_device *pdev, int value) +{ + unsigned char buf; + + if (value < 0) + value = 0; + if (value > 0xffff) + value = 0xffff; + /* only the msb is considered */ + buf = value >> 8; + return SendControlMsg(SET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1); +} + +static inline int pwc_get_blue_gain(struct pwc_device *pdev, int *value) +{ + unsigned char buf; + int ret; + + ret = RecvControlMsg(GET_CHROM_CTL, PRESET_MANUAL_BLUE_GAIN_FORMATTER, 1); + if (ret < 0) + return ret; + *value = buf << 8; + return 0; +} + + +/* The following two functions are different, since they only read the + internal red/blue gains, which may be different from the manual + gains set or read above. + */ +static inline int pwc_read_red_gain(struct pwc_device *pdev, int *value) +{ + unsigned char buf; + int ret; + + ret = RecvControlMsg(GET_STATUS_CTL, READ_RED_GAIN_FORMATTER, 1); + if (ret < 0) + return ret; + *value = buf << 8; + return 0; +} + +static inline int pwc_read_blue_gain(struct pwc_device *pdev, int *value) +{ + unsigned char buf; + int ret; + + ret = RecvControlMsg(GET_STATUS_CTL, READ_BLUE_GAIN_FORMATTER, 1); + if (ret < 0) + return ret; + *value = buf << 8; + return 0; +} + + +static inline int pwc_set_wb_speed(struct pwc_device *pdev, int speed) +{ + unsigned char buf; + + /* useful range is 0x01..0x20 */ + buf = speed / 0x7f0; + return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1); +} + +static inline int pwc_get_wb_speed(struct pwc_device *pdev, int *value) +{ + unsigned char buf; + int ret; + + ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_SPEED_FORMATTER, 1); + if (ret < 0) + return ret; + *value = buf * 0x7f0; + return 0; +} + + +static inline int pwc_set_wb_delay(struct pwc_device *pdev, int delay) +{ + unsigned char buf; + + /* useful range is 0x01..0x3F */ + buf = (delay >> 10); + return SendControlMsg(SET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1); +} + +static inline int pwc_get_wb_delay(struct pwc_device *pdev, int *value) +{ + unsigned char buf; + int ret; + + ret = RecvControlMsg(GET_CHROM_CTL, AWB_CONTROL_DELAY_FORMATTER, 1); + if (ret < 0) + return ret; + *value = buf << 10; + return 0; +} + + +int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value) +{ + unsigned char buf[2]; + + if (pdev->type < 730) + return 0; + on_value /= 100; + off_value /= 100; + if (on_value < 0) + on_value = 0; + if (on_value > 0xff) + on_value = 0xff; + if (off_value < 0) + off_value = 0; + if (off_value > 0xff) + off_value = 0xff; + + buf[0] = on_value; + buf[1] = off_value; + + return SendControlMsg(SET_STATUS_CTL, LED_FORMATTER, 2); +} + +int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value) +{ + unsigned char buf[2]; + int ret; + + if (pdev->type < 730) { + *on_value = -1; + *off_value = -1; + return 0; + } + + ret = RecvControlMsg(GET_STATUS_CTL, LED_FORMATTER, 2); + if (ret < 0) + return ret; + *on_value = buf[0] * 100; + *off_value = buf[1] * 100; + return 0; +} + +static inline int pwc_set_contour(struct pwc_device *pdev, int contour) +{ + unsigned char buf; + int ret; + + if (contour < 0) + buf = 0xff; /* auto contour on */ + else + buf = 0x0; /* auto contour off */ + ret = SendControlMsg(SET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1); + if (ret < 0) + return ret; + + if (contour < 0) + return 0; + if (contour > 0xffff) + contour = 0xffff; + + buf = (contour >> 10); /* contour preset is [0..3f] */ + ret = SendControlMsg(SET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1); + if (ret < 0) + return ret; + return 0; +} + +static inline int pwc_get_contour(struct pwc_device *pdev, int *contour) +{ + unsigned char buf; + int ret; + + ret = RecvControlMsg(GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, 1); + if (ret < 0) + return ret; + + if (buf == 0) { + /* auto mode off, query current preset value */ + ret = RecvControlMsg(GET_LUM_CTL, PRESET_CONTOUR_FORMATTER, 1); + if (ret < 0) + return ret; + *contour = buf << 10; + } + else + *contour = -1; + return 0; +} + + +static inline int pwc_set_backlight(struct pwc_device *pdev, int backlight) +{ + unsigned char buf; + + if (backlight) + buf = 0xff; + else + buf = 0x0; + return SendControlMsg(SET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1); +} + +static inline int pwc_get_backlight(struct pwc_device *pdev, int *backlight) +{ + int ret; + unsigned char buf; + + ret = RecvControlMsg(GET_LUM_CTL, BACK_LIGHT_COMPENSATION_FORMATTER, 1); + if (ret < 0) + return ret; + *backlight = buf; + return 0; +} + + +static inline int pwc_set_flicker(struct pwc_device *pdev, int flicker) +{ + unsigned char buf; + + if (flicker) + buf = 0xff; + else + buf = 0x0; + return SendControlMsg(SET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1); +} + +static inline int pwc_get_flicker(struct pwc_device *pdev, int *flicker) +{ + int ret; + unsigned char buf; + + ret = RecvControlMsg(GET_LUM_CTL, FLICKERLESS_MODE_FORMATTER, 1); + if (ret < 0) + return ret; + *flicker = buf; + return 0; +} + + +static inline int pwc_set_dynamic_noise(struct pwc_device *pdev, int noise) +{ + unsigned char buf; + + if (noise < 0) + noise = 0; + if (noise > 3) + noise = 3; + buf = noise; + return SendControlMsg(SET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); +} + +static inline int pwc_get_dynamic_noise(struct pwc_device *pdev, int *noise) +{ + int ret; + unsigned char buf; + + ret = RecvControlMsg(GET_LUM_CTL, DYNAMIC_NOISE_CONTROL_FORMATTER, 1); + if (ret < 0) + return ret; + *noise = buf; + return 0; +} + +int pwc_mpt_reset(struct pwc_device *pdev, int flags) +{ + unsigned char buf; + + buf = flags & 0x03; // only lower two bits are currently used + return SendControlMsg(SET_MPT_CTL, PT_RESET_CONTROL_FORMATTER, 1); +} + +static inline int pwc_mpt_set_angle(struct pwc_device *pdev, int pan, int tilt) +{ + unsigned char buf[4]; + + /* set new relative angle; angles are expressed in degrees * 100, + but cam as .5 degree resolution, hence devide by 200. Also + the angle must be multiplied by 64 before it's send to + the cam (??) + */ + pan = 64 * pan / 100; + tilt = -64 * tilt / 100; /* positive tilt is down, which is not what the user would expect */ + buf[0] = pan & 0xFF; + buf[1] = (pan >> 8) & 0xFF; + buf[2] = tilt & 0xFF; + buf[3] = (tilt >> 8) & 0xFF; + return SendControlMsg(SET_MPT_CTL, PT_RELATIVE_CONTROL_FORMATTER, 4); +} + +static inline int pwc_mpt_get_status(struct pwc_device *pdev, struct pwc_mpt_status *status) +{ + int ret; + unsigned char buf[5]; + + ret = RecvControlMsg(GET_MPT_CTL, PT_STATUS_FORMATTER, 5); + if (ret < 0) + return ret; + status->status = buf[0] & 0x7; // 3 bits are used for reporting + status->time_pan = (buf[1] << 8) + buf[2]; + status->time_tilt = (buf[3] << 8) + buf[4]; + return 0; +} + + +int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor) +{ + unsigned char buf; + int ret = -1, request; + + if (pdev->type < 675) + request = SENSOR_TYPE_FORMATTER1; + else if (pdev->type < 730) + return -1; /* The Vesta series doesn't have this call */ + else + request = SENSOR_TYPE_FORMATTER2; + + ret = RecvControlMsg(GET_STATUS_CTL, request, 1); + if (ret < 0) + return ret; + if (pdev->type < 675) + *sensor = buf | 0x100; + else + *sensor = buf; + return 0; +} + + + /* End of Add-Ons */ + /* ************************************************* */ + +/* Linux 2.5.something and 2.6 pass direct pointers to arguments of + ioctl() calls. With 2.4, you have to do tedious copy_from_user() + and copy_to_user() calls. With these macros we circumvent this, + and let me maintain only one source file. The functionality is + exactly the same otherwise. + */ + +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) + +/* define local variable for arg */ +#define ARG_DEF(ARG_type, ARG_name)\ + ARG_type *ARG_name = arg; +/* copy arg to local variable */ +#define ARG_IN(ARG_name) /* nothing */ +/* argument itself (referenced) */ +#define ARGR(ARG_name) (*ARG_name) +/* argument address */ +#define ARGA(ARG_name) ARG_name +/* copy local variable to arg */ +#define ARG_OUT(ARG_name) /* nothing */ + +#else + +#define ARG_DEF(ARG_type, ARG_name)\ + ARG_type ARG_name; +#define ARG_IN(ARG_name)\ + if (copy_from_user(&ARG_name, arg, sizeof(ARG_name))) {\ + ret = -EFAULT;\ + break;\ + } +#define ARGR(ARG_name) ARG_name +#define ARGA(ARG_name) &ARG_name +#define ARG_OUT(ARG_name)\ + if (copy_to_user(arg, &ARG_name, sizeof(ARG_name))) {\ + ret = -EFAULT;\ + break;\ + } + +#endif + +int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg) +{ + int ret = 0; + + switch(cmd) { + case VIDIOCPWCRUSER: + { + if (pwc_restore_user(pdev)) + ret = -EINVAL; + break; + } + + case VIDIOCPWCSUSER: + { + if (pwc_save_user(pdev)) + ret = -EINVAL; + break; + } + + case VIDIOCPWCFACTORY: + { + if (pwc_restore_factory(pdev)) + ret = -EINVAL; + break; + } + + case VIDIOCPWCSCQUAL: + { + ARG_DEF(int, qual) + + ARG_IN(qual) + if (ARGR(qual) < 0 || ARGR(qual) > 3) + ret = -EINVAL; + else + ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot); + if (ret >= 0) + pdev->vcompression = ARGR(qual); + break; + } + + case VIDIOCPWCGCQUAL: + { + ARG_DEF(int, qual) + + ARGR(qual) = pdev->vcompression; + ARG_OUT(qual) + break; + } + + case VIDIOCPWCPROBE: + { + ARG_DEF(struct pwc_probe, probe) + + strcpy(ARGR(probe).name, pdev->vdev->name); + ARGR(probe).type = pdev->type; + ARG_OUT(probe) + break; + } + + case VIDIOCPWCGSERIAL: + { + ARG_DEF(struct pwc_serial, serial) + + strcpy(ARGR(serial).serial, pdev->serial); + ARG_OUT(serial) + break; + } + + case VIDIOCPWCSAGC: + { + ARG_DEF(int, agc) + + ARG_IN(agc) + if (pwc_set_agc(pdev, ARGR(agc) < 0 ? 1 : 0, ARGR(agc))) + ret = -EINVAL; + break; + } + + case VIDIOCPWCGAGC: + { + ARG_DEF(int, agc) + + if (pwc_get_agc(pdev, ARGA(agc))) + ret = -EINVAL; + ARG_OUT(agc) + break; + } + + case VIDIOCPWCSSHUTTER: + { + ARG_DEF(int, shutter_speed) + + ARG_IN(shutter_speed) + ret = pwc_set_shutter_speed(pdev, ARGR(shutter_speed) < 0 ? 1 : 0, ARGR(shutter_speed)); + break; + } + + case VIDIOCPWCSAWB: + { + ARG_DEF(struct pwc_whitebalance, wb) + + ARG_IN(wb) + ret = pwc_set_awb(pdev, ARGR(wb).mode); + if (ret >= 0 && ARGR(wb).mode == PWC_WB_MANUAL) { + pwc_set_red_gain(pdev, ARGR(wb).manual_red); + pwc_set_blue_gain(pdev, ARGR(wb).manual_blue); + } + break; + } + + case VIDIOCPWCGAWB: + { + ARG_DEF(struct pwc_whitebalance, wb) + + memset(ARGA(wb), 0, sizeof(struct pwc_whitebalance)); + ARGR(wb).mode = pwc_get_awb(pdev); + if (ARGR(wb).mode < 0) + ret = -EINVAL; + else { + if (ARGR(wb).mode == PWC_WB_MANUAL) { + ret = pwc_get_red_gain(pdev, &ARGR(wb).manual_red); + if (ret < 0) + break; + ret = pwc_get_blue_gain(pdev, &ARGR(wb).manual_blue); + if (ret < 0) + break; + } + if (ARGR(wb).mode == PWC_WB_AUTO) { + ret = pwc_read_red_gain(pdev, &ARGR(wb).read_red); + if (ret < 0) + break; + ret =pwc_read_blue_gain(pdev, &ARGR(wb).read_blue); + if (ret < 0) + break; + } + } + ARG_OUT(wb) + break; + } + + case VIDIOCPWCSAWBSPEED: + { + ARG_DEF(struct pwc_wb_speed, wbs) + + if (ARGR(wbs).control_speed > 0) { + ret = pwc_set_wb_speed(pdev, ARGR(wbs).control_speed); + } + if (ARGR(wbs).control_delay > 0) { + ret = pwc_set_wb_delay(pdev, ARGR(wbs).control_delay); + } + break; + } + + case VIDIOCPWCGAWBSPEED: + { + ARG_DEF(struct pwc_wb_speed, wbs) + + ret = pwc_get_wb_speed(pdev, &ARGR(wbs).control_speed); + if (ret < 0) + break; + ret = pwc_get_wb_delay(pdev, &ARGR(wbs).control_delay); + if (ret < 0) + break; + ARG_OUT(wbs) + break; + } + + case VIDIOCPWCSLED: + { + ARG_DEF(struct pwc_leds, leds) + + ARG_IN(leds) + ret = pwc_set_leds(pdev, ARGR(leds).led_on, ARGR(leds).led_off); + break; + } + + + case VIDIOCPWCGLED: + { + ARG_DEF(struct pwc_leds, leds) + + ret = pwc_get_leds(pdev, &ARGR(leds).led_on, &ARGR(leds).led_off); + ARG_OUT(leds) + break; + } + + case VIDIOCPWCSCONTOUR: + { + ARG_DEF(int, contour) + + ARG_IN(contour) + ret = pwc_set_contour(pdev, ARGR(contour)); + break; + } + + case VIDIOCPWCGCONTOUR: + { + ARG_DEF(int, contour) + + ret = pwc_get_contour(pdev, ARGA(contour)); + ARG_OUT(contour) + break; + } + + case VIDIOCPWCSBACKLIGHT: + { + ARG_DEF(int, backlight) + + ARG_IN(backlight) + ret = pwc_set_backlight(pdev, ARGR(backlight)); + break; + } + + case VIDIOCPWCGBACKLIGHT: + { + ARG_DEF(int, backlight) + + ret = pwc_get_backlight(pdev, ARGA(backlight)); + ARG_OUT(backlight) + break; + } + + case VIDIOCPWCSFLICKER: + { + ARG_DEF(int, flicker) + + ARG_IN(flicker) + ret = pwc_set_flicker(pdev, ARGR(flicker)); + break; + } + + case VIDIOCPWCGFLICKER: + { + ARG_DEF(int, flicker) + + ret = pwc_get_flicker(pdev, ARGA(flicker)); + ARG_OUT(flicker) + break; + } + + case VIDIOCPWCSDYNNOISE: + { + ARG_DEF(int, dynnoise) + + ARG_IN(dynnoise) + ret = pwc_set_dynamic_noise(pdev, ARGR(dynnoise)); + break; + } + + case VIDIOCPWCGDYNNOISE: + { + ARG_DEF(int, dynnoise) + + ret = pwc_get_dynamic_noise(pdev, ARGA(dynnoise)); + ARG_OUT(dynnoise); + break; + } + + case VIDIOCPWCGREALSIZE: + { + ARG_DEF(struct pwc_imagesize, size) + + ARGR(size).width = pdev->image.x; + ARGR(size).height = pdev->image.y; + ARG_OUT(size) + break; + } + + case VIDIOCPWCMPTRESET: + { + if (pdev->features & FEATURE_MOTOR_PANTILT) + { + ARG_DEF(int, flags) + + ARG_IN(flags) + ret = pwc_mpt_reset(pdev, ARGR(flags)); + if (ret >= 0) + { + pdev->pan_angle = 0; + pdev->tilt_angle = 0; + } + } + else + { + ret = -ENXIO; + } + break; + } + + case VIDIOCPWCMPTGRANGE: + { + if (pdev->features & FEATURE_MOTOR_PANTILT) + { + ARG_DEF(struct pwc_mpt_range, range) + + ARGR(range) = pdev->angle_range; + ARG_OUT(range) + } + else + { + ret = -ENXIO; + } + break; + } + + case VIDIOCPWCMPTSANGLE: + { + int new_pan, new_tilt; + + if (pdev->features & FEATURE_MOTOR_PANTILT) + { + ARG_DEF(struct pwc_mpt_angles, angles) + + ARG_IN(angles) + /* The camera can only set relative angles, so + do some calculations when getting an absolute angle . + */ + if (ARGR(angles).absolute) + { + new_pan = ARGR(angles).pan; + new_tilt = ARGR(angles).tilt; + } + else + { + new_pan = pdev->pan_angle + ARGR(angles).pan; + new_tilt = pdev->tilt_angle + ARGR(angles).tilt; + } + /* check absolute ranges */ + if (new_pan < pdev->angle_range.pan_min || + new_pan > pdev->angle_range.pan_max || + new_tilt < pdev->angle_range.tilt_min || + new_tilt > pdev->angle_range.tilt_max) + { + ret = -ERANGE; + } + else + { + /* go to relative range, check again */ + new_pan -= pdev->pan_angle; + new_tilt -= pdev->tilt_angle; + /* angles are specified in degrees * 100, thus the limit = 36000 */ + if (new_pan < -36000 || new_pan > 36000 || new_tilt < -36000 || new_tilt > 36000) + ret = -ERANGE; + } + if (ret == 0) /* no errors so far */ + { + ret = pwc_mpt_set_angle(pdev, new_pan, new_tilt); + if (ret >= 0) + { + pdev->pan_angle += new_pan; + pdev->tilt_angle += new_tilt; + } + if (ret == -EPIPE) /* stall -> out of range */ + ret = -ERANGE; + } + } + else + { + ret = -ENXIO; + } + break; + } + + case VIDIOCPWCMPTGANGLE: + { + + if (pdev->features & FEATURE_MOTOR_PANTILT) + { + ARG_DEF(struct pwc_mpt_angles, angles) + + ARGR(angles).absolute = 1; + ARGR(angles).pan = pdev->pan_angle; + ARGR(angles).tilt = pdev->tilt_angle; + ARG_OUT(angles) + } + else + { + ret = -ENXIO; + } + break; + } + + case VIDIOCPWCMPTSTATUS: + { + if (pdev->features & FEATURE_MOTOR_PANTILT) + { + ARG_DEF(struct pwc_mpt_status, status) + + ret = pwc_mpt_get_status(pdev, ARGA(status)); + ARG_OUT(status) + } + else + { + ret = -ENXIO; + } + break; + } + + case VIDIOCPWCGVIDCMD: + { + ARG_DEF(struct pwc_video_command, cmd); + + ARGR(cmd).type = pdev->type; + ARGR(cmd).release = pdev->release; + ARGR(cmd).command_len = pdev->cmd_len; + memcpy(&ARGR(cmd).command_buf, pdev->cmd_buf, pdev->cmd_len); + ARGR(cmd).bandlength = pdev->vbandlength; + ARGR(cmd).frame_size = pdev->frame_size; + ARG_OUT(cmd) + break; + } + /* + case VIDIOCPWCGVIDTABLE: + { + ARG_DEF(struct pwc_table_init_buffer, table); + ARGR(table).len = pdev->cmd_len; + memcpy(&ARGR(table).buffer, pdev->decompress_data, pdev->decompressor->table_size); + ARG_OUT(table) + break; + } + */ + + default: + ret = -ENOIOCTLCMD; + break; + } + + if (ret > 0) + return 0; + return ret; +} + + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-dec1.c linux-2.6.11/drivers/usb/media/pwc/pwc-dec1.c --- linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-dec1.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.11/drivers/usb/media/pwc/pwc-dec1.c 2005-03-05 15:26:35.000000000 +0000 @@ -0,0 +1,42 @@ +/* Linux driver for Philips webcam + Decompression for chipset version 1 + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + + +#include "pwc-dec1.h" + + +void pwc_dec1_init(int type, int release, void *buffer, void *table) +{ + +} + +void pwc_dec1_exit(void) +{ + + + +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-dec1.h linux-2.6.11/drivers/usb/media/pwc/pwc-dec1.h --- linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-dec1.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.11/drivers/usb/media/pwc/pwc-dec1.h 2005-03-05 15:26:35.000000000 +0000 @@ -0,0 +1,36 @@ +/* Linux driver for Philips webcam + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + + +#ifndef PWC_DEC1_H +#define PWC_DEC1_H + +void pwc_dec1_init(int type, int release, void *buffer, void *private_data); +void pwc_dec1_exit(void); + +#endif + + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-dec23.c linux-2.6.11/drivers/usb/media/pwc/pwc-dec23.c --- linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-dec23.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.11/drivers/usb/media/pwc/pwc-dec23.c 2005-03-05 15:26:35.000000000 +0000 @@ -0,0 +1,623 @@ +/* Linux driver for Philips webcam + Decompression for chipset version 2 et 3 + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "pwc-timon.h" +#include "pwc-kiara.h" +#include "pwc-dec23.h" +#include "pwc-ioctl.h" + +#include + +/**** + * + * + * + */ + + +static void fill_table_a000(unsigned int *p) +{ + static unsigned int initial_values[12] = { + 0xFFAD9B00, 0xFFDDEE00, 0x00221200, 0x00526500, + 0xFFC21E00, 0x003DE200, 0xFF924B80, 0xFFD2A300, + 0x002D5D00, 0x006DB480, 0xFFED3E00, 0x0012C200 + }; + static unsigned int values_derivated[12] = { + 0x0000A4CA, 0x00004424, 0xFFFFBBDC, 0xFFFF5B36, + 0x00007BC4, 0xFFFF843C, 0x0000DB69, 0x00005ABA, + 0xFFFFA546, 0xFFFF2497, 0x00002584, 0xFFFFDA7C + }; + unsigned int temp_values[12]; + int i,j; + + memcpy(temp_values,initial_values,sizeof(initial_values)); + for (i=0;i<256;i++) + { + for (j=0;j<12;j++) + { + *p++ = temp_values[j]; + temp_values[j] += values_derivated[j]; + } + } +} + +static void fill_table_d000(unsigned char *p) +{ + int bit,byte; + + for (bit=0; bit<8; bit++) + { + unsigned char bitpower = 1<=1 && k<3) + bit=(table[0]>>15)&7; + else if (k>=3 && k<6) + bit=(table[0]>>12)&7; + else if (k>=6 && k<10) + bit=(table[0]>>9)&7; + else if (k>=10 && k<13) + bit=(table[0]>>6)&7; + else if (k>=13 && k<15) + bit=(table[0]>>3)&7; + else + bit=(table[0])&7; + if (k == 0) + *(unsigned char *)p8++ = 8; + else + *(unsigned char *)p8++ = j - bit; + *(unsigned char *)p8++ = bit; + + pw = 1<xx + pdev->yy) + * + */ +void fill_table_dc00_d800(unsigned int precision, unsigned int *pdc00, unsigned int *pd800) +{ + int i; + unsigned int offset1, offset2; + + for(i=0,offset1=0x4000, offset2=0; i<256 ; i++,offset1+=0x7BC4, offset2+=0x7BC4) + { + unsigned int msb = offset1 >> 15; + + if ( msb > 255) + { + if (msb) + msb=0; + else + msb=255; + } + + *pdc00++ = msb << precision; + *pd800++ = offset2; + } + +} + +/* + * struct { + * unsigned char op; // operation to execute + * unsigned char bits; // bits use to perform operation + * unsigned char offset1; // offset to add to access in the table_0004 % 16 + * unsigned char offset2; // offset to add to access in the table_0004 + * } + * + */ +static unsigned int table_ops[] = { +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x01,0x30, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x20, 0x01,0x00,0x00,0x00, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x00, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x00, 0x01,0x00,0x00,0x00, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x02,0x10, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x60, 0x01,0x00,0x00,0x00, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x40, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x40, 0x01,0x00,0x00,0x00, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x01,0x70, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x20, 0x01,0x00,0x00,0x00, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x00, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x00, 0x01,0x00,0x00,0x00, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x10, 0x00,0x06,0x02,0x50, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x01,0x60, 0x01,0x00,0x00,0x00, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x00, 0x00,0x04,0x01,0x50, 0x00,0x05,0x02,0x40, +0x02,0x00,0x00,0x00, 0x00,0x03,0x01,0x40, 0x00,0x05,0x03,0x40, 0x01,0x00,0x00,0x00 +}; + +/* + * TODO: multiply by 4 all values + * + */ +static unsigned int MulIdx[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3, + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, + 6, 7, 8, 9, 7,10,11, 8, 8,11,10, 7, 9, 8, 7, 6, + 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, 4, 5, 5, 4, + 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2, 1, 3, 0, 2, + 0, 3, 3, 0, 1, 2, 2, 1, 2, 1, 1, 2, 3, 0, 0, 3, + 0, 1, 2, 3, 3, 2, 1, 0, 3, 2, 1, 0, 0, 1, 2, 3, + 1, 1, 1, 1, 3, 3, 3, 3, 0, 0, 0, 0, 2, 2, 2, 2, + 7,10,11, 8, 9, 8, 7, 6, 6, 7, 8, 9, 8,11,10, 7, + 4, 5, 5, 4, 5, 4, 4, 5, 5, 4, 4, 5, 4, 5, 5, 4, + 7, 9, 6, 8,10, 8, 7,11,11, 7, 8,10, 8, 6, 9, 7, + 1, 3, 0, 2, 2, 0, 3, 1, 2, 0, 3, 1, 1, 3, 0, 2, + 1, 2, 2, 1, 3, 0, 0, 3, 0, 3, 3, 0, 2, 1, 1, 2, +10, 8, 7,11, 8, 6, 9, 7, 7, 9, 6, 8,11, 7, 8,10 +}; + + + +void pwc_dec23_init(int type, int release, unsigned char *mode, void *data) +{ + int flags; + struct pwc_dec23_private *pdev = data; + release = release; + + switch (type) + { + case 720: + case 730: + case 740: + case 750: + flags = mode[2]&0x18; /* our: flags = 8, mode[2]==e8 */ + if (flags==8) + pdev->zz = 7; + else if (flags==0x10) + pdev->zz = 8; + else + pdev->zz = 6; + flags = mode[2]>>5; /* our: 7 */ + + fill_table_color(flags, (unsigned int *)KiaraRomTable, pdev->table_0004, pdev->table_8004); + break; + + + case 675: + case 680: + case 690: + flags = mode[2]&6; + if (flags==2) + pdev->zz = 7; + else if (flags==4) + pdev->zz = 8; + else + pdev->zz = 6; + flags = mode[2]>>3; + + fill_table_color(flags, (unsigned int *)TimonRomTable, pdev->table_0004, pdev->table_8004); + break; + + default: + /* Not supported */ + return; + } + + /* * * * ** */ + pdev->xx = 8 - pdev->zz; + pdev->yy = 15 - pdev->xx; + pdev->zzmask = 0xFF>>pdev->xx; + //pdev->zzmask = (1U<zz)-1; + + + fill_table_dc00_d800(pdev->xx + pdev->yy, pdev->table_dc00, pdev->table_d800); + fill_table_a000(pdev->table_a004); + fill_table_d000(pdev->table_d004); +} + + +/* + * To manage the stream, we keep in a 32 bits variables, + * the next bits in the stream. fill_reservoir() add to + * the reservoir at least wanted nbits. + * + * + */ +#define fill_nbits(reservoir,nbits_in_reservoir,stream,nbits_wanted) do { \ + while (nbits_in_reservoir>= nbits_wanted; \ + nbits_in_reservoir -= nbits_wanted; \ +} while(0); + + + +static void DecompressBand23(const struct pwc_dec23_private *pdev, + const unsigned char *rawyuv, + unsigned char *planar_y, + unsigned char *planar_u, + unsigned char *planar_v, + unsigned int image_x, /* aka number of pixels wanted ??? */ + unsigned int pixels_per_line, /* aka number of pixels per line */ + int flags) +{ + + + unsigned int reservoir, nbits_in_reservoir; + int first_4_bits; + unsigned int bytes_per_channel; + int line_size; /* size of the line (4Y+U+V) */ + int passes; + const unsigned char *ptable0004, *ptable8004; + + int even_line; + unsigned int temp_colors[16]; + int nblocks; + + const unsigned char *stream; + unsigned char *dest_y, *dest_u=NULL, *dest_v=NULL; + unsigned int offset_to_plane_u, offset_to_plane_v; + + int i; + + + reservoir = 0; + nbits_in_reservoir = 0; + stream = rawyuv+1; /* The first byte of the stream is skipped */ + even_line = 1; + + get_nbits(reservoir,nbits_in_reservoir,stream,4,first_4_bits); + + line_size = pixels_per_line*3; + + for (passes=0;passes<2;passes++) + { + if (passes==0) + { + bytes_per_channel = pixels_per_line; + dest_y = planar_y; + nblocks = image_x/4; + } + else + { + /* Format planar: All Y, then all U, then all V */ + bytes_per_channel = pixels_per_line/2; + dest_u = planar_u; + dest_v = planar_v; + dest_y = dest_u; + nblocks = image_x/8; + } + + offset_to_plane_u = bytes_per_channel*2; + offset_to_plane_v = bytes_per_channel*3; + /* + printf("bytes_per_channel = %d\n",bytes_per_channel); + printf("offset_to_plane_u = %d\n",offset_to_plane_u); + printf("offset_to_plane_v = %d\n",offset_to_plane_v); + */ + + while (nblocks-->0) + { + unsigned int gray_index; + + fill_nbits(reservoir,nbits_in_reservoir,stream,16); + gray_index = reservoir & pdev->zzmask; + reservoir >>= pdev->zz; + nbits_in_reservoir -= pdev->zz; + + fill_nbits(reservoir,nbits_in_reservoir,stream,2); + + if ( (reservoir & 3) == 0) + { + reservoir>>=2; + nbits_in_reservoir-=2; + for (i=0;i<16;i++) + temp_colors[i] = pdev->table_dc00[gray_index]; + + } + else + { + unsigned int channel_v, offset1; + + /* swap bit 0 and 2 of offset_OR */ + channel_v = ((reservoir & 1) << 2) | (reservoir & 2) | ((reservoir & 4)>>2); + reservoir>>=3; + nbits_in_reservoir-=3; + + for (i=0;i<16;i++) + temp_colors[i] = pdev->table_d800[gray_index]; + + ptable0004 = pdev->table_0004 + (passes*16384) + (first_4_bits*1024) + (channel_v*128); + ptable8004 = pdev->table_8004 + (passes*4096) + (first_4_bits*256) + (channel_v*32); + + offset1 = 0; + while(1) + { + unsigned int index_in_table_ops, op, rows=0; + fill_nbits(reservoir,nbits_in_reservoir,stream,16); + + /* mode is 0,1 or 2 */ + index_in_table_ops = (reservoir&0x3F); + op = table_ops[ index_in_table_ops*4 ]; + if (op == 2) + { + reservoir >>= 2; + nbits_in_reservoir -= 2; + break; /* exit the while(1) */ + } + if (op == 0) + { + unsigned int shift; + + offset1 = (offset1 + table_ops[index_in_table_ops*4+2]) & 0x0F; + shift = table_ops[ index_in_table_ops*4+1 ]; + reservoir >>= shift; + nbits_in_reservoir -= shift; + rows = ptable0004[ offset1 + table_ops[index_in_table_ops*4+3] ]; + } + if (op == 1) + { + /* 10bits [ xxxx xxxx yyyy 000 ] + * yyy => offset in the table8004 + * xxx => offset in the tabled004 + */ + unsigned int mask, shift; + unsigned int col1, row1, total_bits; + + offset1 = (offset1 + ((reservoir>>3)&0x0F)+1) & 0x0F; + + col1 = (reservoir>>7) & 0xFF; + row1 = ptable8004 [ offset1*2 ]; + + /* Bit mask table */ + mask = pdev->table_d004[ (row1<<8) + col1 ]; + shift = ptable8004 [ offset1*2 + 1]; + rows = ((mask << shift) + 0x80) & 0xFF; + + total_bits = row1 + 8; + reservoir >>= total_bits; + nbits_in_reservoir -= total_bits; + } + { + const unsigned int *table_a004 = pdev->table_a004 + rows*12; + unsigned int *poffset = MulIdx + offset1*16; /* 64/4 (int) */ + for (i=0;i<16;i++) + { + temp_colors[i] += table_a004[ *poffset ]; + poffset++; + } + } + } + } +#define USE_SIGNED_INT_FOR_COLOR +#ifdef USE_SIGNED_INT_FOR_COLOR +# define CLAMP(x) ((x)>255?255:((x)<0?0:x)) +#else +# define CLAMP(x) ((x)>255?255:x) +#endif + + if (passes == 0) + { +#ifdef USE_SIGNED_INT_FOR_COLOR + const int *c = temp_colors; +#else + const unsigned int *c = temp_colors; +#endif + unsigned char *d; + + d = dest_y; + for (i=0;i<4;i++,c++) + *d++ = CLAMP((*c) >> pdev->yy); + + d = dest_y + bytes_per_channel; + for (i=0;i<4;i++,c++) + *d++ = CLAMP((*c) >> pdev->yy); + + d = dest_y + offset_to_plane_u; + for (i=0;i<4;i++,c++) + *d++ = CLAMP((*c) >> pdev->yy); + + d = dest_y + offset_to_plane_v; + for (i=0;i<4;i++,c++) + *d++ = CLAMP((*c) >> pdev->yy); + + dest_y += 4; + } + else if (passes == 1) + { +#ifdef USE_SIGNED_INT_FOR_COLOR + int *c1 = temp_colors; + int *c2 = temp_colors+4; +#else + unsigned int *c1 = temp_colors; + unsigned int *c2 = temp_colors+4; +#endif + unsigned char *d; + + d = dest_y; + for (i=0;i<4;i++,c1++,c2++) + { + *d++ = CLAMP((*c1) >> pdev->yy); + *d++ = CLAMP((*c2) >> pdev->yy); + } + c1 = temp_colors+12; + //c2 = temp_colors+8; + d = dest_y + bytes_per_channel; + for (i=0;i<4;i++,c1++,c2++) + { + *d++ = CLAMP((*c1) >> pdev->yy); + *d++ = CLAMP((*c2) >> pdev->yy); + } + + if (even_line) /* Each line, swap u/v */ + { + even_line=0; + dest_y = dest_v; + dest_u += 8; + } + else + { + even_line=1; + dest_y = dest_u; + dest_v += 8; + } + } + + } /* end of while (nblocks-->0) */ + + } /* end of for (passes=0;passes<2;passes++) */ + +} + + +/** + * + * image: size of the image wanted + * view : size of the image returned by the camera + * offset: (x,y) to displayer image in the view + * + * src: raw data + * dst: image output + * flags: PWCX_FLAG_PLANAR + * pdev: private buffer + * bandlength: + * + */ +void pwc_dec23_decompress(const struct pwc_coord *image, + const struct pwc_coord *view, + const struct pwc_coord *offset, + const void *src, + void *dst, + int flags, + const void *data, + int bandlength) +{ + const struct pwc_dec23_private *pdev = data; + unsigned char *pout, *pout_planar_y=NULL, *pout_planar_u=NULL, *pout_planar_v=NULL; + int i,n,stride,pixel_size; + + + if (flags & PWCX_FLAG_BAYER) + { + pout = dst + (view->x * offset->y) + offset->x; + pixel_size = view->x * 4; + } + else + { + n = view->x * view->y; + + /* offset in Y plane */ + stride = view->x * offset->y; + pout_planar_y = dst + stride + offset->x; + + /* offsets in U/V planes */ + stride = (view->x * offset->y)/4 + offset->x/2; + pout_planar_u = dst + n + + stride; + pout_planar_v = dst + n + n/4 + stride; + + pixel_size = view->x * 4; + } + + + for (i=0;iy;i+=4) + { + if (flags & PWCX_FLAG_BAYER) + { + //TODO: + //DecompressBandBayer(pdev,src,pout,image.x,view->x,flags); + src += bandlength; + pout += pixel_size; + } + else + { + DecompressBand23(pdev,src,pout_planar_y,pout_planar_u,pout_planar_v,image->x,view->x,flags); + src += bandlength; + pout_planar_y += pixel_size; + pout_planar_u += view->x; + pout_planar_v += view->x; + } + } +} + +void pwc_dec23_exit(void) +{ + /* Do nothing */ + +} + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-dec23.h linux-2.6.11/drivers/usb/media/pwc/pwc-dec23.h --- linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-dec23.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.11/drivers/usb/media/pwc/pwc-dec23.h 2005-03-05 15:26:35.000000000 +0000 @@ -0,0 +1,58 @@ +/* Linux driver for Philips webcam + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef PWC_DEC23_H +#define PWC_DEC23_H + +struct pwc_dec23_private +{ + unsigned char xx,yy,zz,zzmask; + + unsigned char table_0004[2*0x4000]; + unsigned char table_8004[2*0x1000]; + unsigned int table_a004[256*12]; + + unsigned char table_d004[8*256]; + unsigned int table_d800[256]; + unsigned int table_dc00[256]; +}; + + +void pwc_dec23_init(int type, int release, unsigned char *buffer, void *private_data); +void pwc_dec23_exit(void); +void pwc_dec23_decompress(const struct pwc_coord *image, + const struct pwc_coord *view, + const struct pwc_coord *offset, + const void *src, + void *dst, + int flags, + const void *data, + int bandlength); + + + +#endif + + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc.h linux-2.6.11/drivers/usb/media/pwc/pwc.h --- linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.11/drivers/usb/media/pwc/pwc.h 2005-03-05 15:26:35.000000000 +0000 @@ -0,0 +1,278 @@ +/* (C) 1999-2003 Nemosoft Unv. + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef PWC_H +#define PWC_H + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pwc-uncompress.h" +#include "pwc-ioctl.h" + +/* Defines and structures for the Philips webcam */ +/* Used for checking memory corruption/pointer validation */ +#define PWC_MAGIC 0x89DC10ABUL +#undef PWC_MAGIC + +/* Turn some debugging options on/off */ +#define PWC_DEBUG 0 + +/* Trace certain actions in the driver */ +#define TRACE_MODULE 0x0001 +#define TRACE_PROBE 0x0002 +#define TRACE_OPEN 0x0004 +#define TRACE_READ 0x0008 +#define TRACE_MEMORY 0x0010 +#define TRACE_FLOW 0x0020 +#define TRACE_SIZE 0x0040 +#define TRACE_PWCX 0x0080 +#define TRACE_SEQUENCE 0x1000 + +#define Trace(R, A...) if (pwc_trace & R) printk(KERN_DEBUG PWC_NAME " " A) +#define Debug(A...) printk(KERN_DEBUG PWC_NAME " " A) +#define Info(A...) printk(KERN_INFO PWC_NAME " " A) +#define Err(A...) printk(KERN_ERR PWC_NAME " " A) + + +/* Defines for ToUCam cameras */ +#define TOUCAM_HEADER_SIZE 8 +#define TOUCAM_TRAILER_SIZE 4 + +#define FEATURE_MOTOR_PANTILT 0x0001 + +/* Version block */ +#define PWC_MAJOR 9 +#define PWC_MINOR 0 +#define PWC_VERSION "9.0.2-unofficial" +#define PWC_NAME "pwc" + +/* Turn certain features on/off */ +#define PWC_INT_PIPE 0 + +/* Ignore errors in the first N frames, to allow for startup delays */ +#define FRAME_LOWMARK 5 + +/* Size and number of buffers for the ISO pipe. */ +#define MAX_ISO_BUFS 2 +#define ISO_FRAMES_PER_DESC 10 +#define ISO_MAX_FRAME_SIZE 960 +#define ISO_BUFFER_SIZE (ISO_FRAMES_PER_DESC * ISO_MAX_FRAME_SIZE) + +/* Frame buffers: contains compressed or uncompressed video data. */ +#define MAX_FRAMES 5 +/* Maximum size after decompression is 640x480 YUV data, 1.5 * 640 * 480 */ +#define PWC_FRAME_SIZE (460800 + TOUCAM_HEADER_SIZE + TOUCAM_TRAILER_SIZE) + +/* Absolute maximum number of buffers available for mmap() */ +#define MAX_IMAGES 10 + +/* The following structures were based on cpia.h. Why reinvent the wheel? :-) */ +struct pwc_iso_buf +{ + void *data; + int length; + int read; + struct urb *urb; +}; + +/* intermediate buffers with raw data from the USB cam */ +struct pwc_frame_buf +{ + void *data; + volatile int filled; /* number of bytes filled */ + struct pwc_frame_buf *next; /* list */ +#if PWC_DEBUG + int sequence; /* Sequence number */ +#endif +}; + +struct pwc_device +{ + struct video_device *vdev; +#ifdef PWC_MAGIC + int magic; +#endif + /* Pointer to our usb_device */ + struct usb_device *udev; + + int type; /* type of cam (645, 646, 675, 680, 690, 720, 730, 740, 750) */ + int release; /* release number */ + int features; /* feature bits */ + char serial[30]; /* serial number (string) */ + int error_status; /* set when something goes wrong with the cam (unplugged, USB errors) */ + int usb_init; /* set when the cam has been initialized over USB */ + + /*** Video data ***/ + int vopen; /* flag */ + int vendpoint; /* video isoc endpoint */ + int vcinterface; /* video control interface */ + int valternate; /* alternate interface needed */ + int vframes, vsize; /* frames-per-second & size (see PSZ_*) */ + int vpalette; /* palette: 420P, RAW or RGBBAYER */ + int vframe_count; /* received frames */ + int vframes_dumped; /* counter for dumped frames */ + int vframes_error; /* frames received in error */ + int vmax_packet_size; /* USB maxpacket size */ + int vlast_packet_size; /* for frame synchronisation */ + int visoc_errors; /* number of contiguous ISOC errors */ + int vcompression; /* desired compression factor */ + int vbandlength; /* compressed band length; 0 is uncompressed */ + char vsnapshot; /* snapshot mode */ + char vsync; /* used by isoc handler */ + char vmirror; /* for ToUCaM series */ + + int cmd_len; + unsigned char cmd_buf[13]; + + /* The image acquisition requires 3 to 4 steps: + 1. data is gathered in short packets from the USB controller + 2. data is synchronized and packed into a frame buffer + 3a. in case data is compressed, decompress it directly into image buffer + 3b. in case data is uncompressed, copy into image buffer with viewport + 4. data is transferred to the user process + + Note that MAX_ISO_BUFS != MAX_FRAMES != MAX_IMAGES.... + We have in effect a back-to-back-double-buffer system. + */ + /* 1: isoc */ + struct pwc_iso_buf sbuf[MAX_ISO_BUFS]; + char iso_init; + + /* 2: frame */ + struct pwc_frame_buf *fbuf; /* all frames */ + struct pwc_frame_buf *empty_frames, *empty_frames_tail; /* all empty frames */ + struct pwc_frame_buf *full_frames, *full_frames_tail; /* all filled frames */ + struct pwc_frame_buf *fill_frame; /* frame currently being filled */ + struct pwc_frame_buf *read_frame; /* frame currently read by user process */ + int frame_header_size, frame_trailer_size; + int frame_size; + int frame_total_size; /* including header & trailer */ + int drop_frames; +#if PWC_DEBUG + int sequence; /* Debugging aid */ +#endif + + /* 3: decompression */ + struct pwc_decompressor *decompressor; /* function block with decompression routines */ + void *decompress_data; /* private data for decompression engine */ + + /* 4: image */ + /* We have an 'image' and a 'view', where 'image' is the fixed-size image + as delivered by the camera, and 'view' is the size requested by the + program. The camera image is centered in this viewport, laced with + a gray or black border. view_min <= image <= view <= view_max; + */ + int image_mask; /* bitmask of supported sizes */ + struct pwc_coord view_min, view_max; /* minimum and maximum viewable sizes */ + struct pwc_coord abs_max; /* maximum supported size with compression */ + struct pwc_coord image, view; /* image and viewport size */ + struct pwc_coord offset; /* offset within the viewport */ + + void *image_data; /* total buffer, which is subdivided into ... */ + void *image_ptr[MAX_IMAGES]; /* ...several images... */ + int fill_image; /* ...which are rotated. */ + int len_per_image; /* length per image */ + int image_read_pos; /* In case we read data in pieces, keep track of were we are in the imagebuffer */ + int image_used[MAX_IMAGES]; /* For MCAPTURE and SYNC */ + + struct semaphore modlock; /* to prevent races in video_open(), etc */ + spinlock_t ptrlock; /* for manipulating the buffer pointers */ + + /*** motorized pan/tilt feature */ + struct pwc_mpt_range angle_range; + int pan_angle; /* in degrees * 100 */ + int tilt_angle; /* absolute angle; 0,0 is home position */ + + /*** Misc. data ***/ + wait_queue_head_t frameq; /* When waiting for a frame to finish... */ +#if PWC_INT_PIPE + void *usb_int_handler; /* for the interrupt endpoint */ +#endif +}; + + +#ifdef __cplusplus +extern "C" { +#endif + +/* Global variables */ +extern int pwc_trace; +extern int pwc_preferred_compression; + +/** functions in pwc-if.c */ +int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot); + +/** Functions in pwc-misc.c */ +/* sizes in pixels */ +extern struct pwc_coord pwc_image_sizes[PSZ_MAX]; + +int pwc_decode_size(struct pwc_device *pdev, int width, int height); +void pwc_construct(struct pwc_device *pdev); + +/** Functions in pwc-ctrl.c */ +/* Request a certain video mode. Returns < 0 if not possible */ +extern int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frames, int compression, int snapshot); +/* Calculate the number of bytes per image (not frame) */ +extern void pwc_set_image_buffer_size(struct pwc_device *pdev); + +/* Various controls; should be obvious. Value 0..65535, or < 0 on error */ +extern int pwc_get_brightness(struct pwc_device *pdev); +extern int pwc_set_brightness(struct pwc_device *pdev, int value); +extern int pwc_get_contrast(struct pwc_device *pdev); +extern int pwc_set_contrast(struct pwc_device *pdev, int value); +extern int pwc_get_gamma(struct pwc_device *pdev); +extern int pwc_set_gamma(struct pwc_device *pdev, int value); +extern int pwc_get_saturation(struct pwc_device *pdev); +extern int pwc_set_saturation(struct pwc_device *pdev, int value); +extern int pwc_set_leds(struct pwc_device *pdev, int on_value, int off_value); +extern int pwc_get_leds(struct pwc_device *pdev, int *on_value, int *off_value); +extern int pwc_get_cmos_sensor(struct pwc_device *pdev, int *sensor); + +/* Power down or up the camera; not supported by all models */ +extern int pwc_camera_power(struct pwc_device *pdev, int power); + +/* Private ioctl()s; see pwc-ioctl.h */ +extern int pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg); + + +/** pwc-uncompress.c */ +/* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */ +extern int pwc_decompress(struct pwc_device *pdev); + +#ifdef __cplusplus +} +#endif + + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-if.c linux-2.6.11/drivers/usb/media/pwc/pwc-if.c --- linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-if.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.11/drivers/usb/media/pwc/pwc-if.c 2005-03-09 17:22:08.000000000 +0000 @@ -0,0 +1,2211 @@ +/* Linux driver for Philips webcam + USB and Video4Linux interface part. + (C) 1999-2004 Nemosoft Unv. + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +/* + This code forms the interface between the USB layers and the Philips + specific stuff. Some adanved stuff of the driver falls under an + NDA, signed between me and Philips B.V., Eindhoven, the Netherlands, and + is thus not distributed in source form. The binary pwcx.o module + contains the code that falls under the NDA. + + In case you're wondering: 'pwc' stands for "Philips WebCam", but + I really didn't want to type 'philips_web_cam' every time (I'm lazy as + any Linux kernel hacker, but I don't like uncomprehensible abbreviations + without explanation). + + Oh yes, convention: to disctinguish between all the various pointers to + device-structures, I use these names for the pointer variables: + udev: struct usb_device * + vdev: struct video_device * + pdev: struct pwc_devive * +*/ + +/* Contributors: + - Alvarado: adding whitebalance code + - Alistar Moire: QuickCam 3000 Pro device/product ID + - Tony Hoyle: Creative Labs Webcam 5 device/product ID + - Mark Burazin: solving hang in VIDIOCSYNC when camera gets unplugged + - Jk Fang: Sotec Afina Eye ID + - Xavier Roche: QuickCam Pro 4000 ID + - Jens Knudsen: QuickCam Zoom ID + - J. Debert: QuickCam for Notebooks ID +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pwc.h" +#include "pwc-ioctl.h" +#include "pwc-kiara.h" +#include "pwc-timon.h" +#include "pwc-dec23.h" +#include "pwc-dec1.h" +#include "pwc-uncompress.h" + +/* Function prototypes and driver templates */ + +/* hotplug device table support */ +static struct usb_device_id pwc_device_table [] = { + { USB_DEVICE(0x0471, 0x0302) }, /* Philips models */ + { USB_DEVICE(0x0471, 0x0303) }, + { USB_DEVICE(0x0471, 0x0304) }, + { USB_DEVICE(0x0471, 0x0307) }, + { USB_DEVICE(0x0471, 0x0308) }, + { USB_DEVICE(0x0471, 0x030C) }, + { USB_DEVICE(0x0471, 0x0310) }, + { USB_DEVICE(0x0471, 0x0311) }, + { USB_DEVICE(0x0471, 0x0312) }, + { USB_DEVICE(0x0471, 0x0313) }, /* the 'new' 720K */ + { USB_DEVICE(0x069A, 0x0001) }, /* Askey */ + { USB_DEVICE(0x046D, 0x08B0) }, /* Logitech QuickCam Pro 3000 */ + { USB_DEVICE(0x046D, 0x08B1) }, /* Logitech QuickCam Notebook Pro */ + { USB_DEVICE(0x046D, 0x08B2) }, /* Logitech QuickCam Pro 4000 */ + { USB_DEVICE(0x046D, 0x08B3) }, /* Logitech QuickCam Zoom (old model) */ + { USB_DEVICE(0x046D, 0x08B4) }, /* Logitech QuickCam Zoom (new model) */ + { USB_DEVICE(0x046D, 0x08B5) }, /* Logitech QuickCam Orbit/Sphere */ + { USB_DEVICE(0x046D, 0x08B6) }, /* Logitech (reserved) */ + { USB_DEVICE(0x046D, 0x08B7) }, /* Logitech (reserved) */ + { USB_DEVICE(0x046D, 0x08B8) }, /* Logitech (reserved) */ + { USB_DEVICE(0x055D, 0x9000) }, /* Samsung */ + { USB_DEVICE(0x055D, 0x9001) }, + { USB_DEVICE(0x041E, 0x400C) }, /* Creative Webcam 5 */ + { USB_DEVICE(0x041E, 0x4011) }, /* Creative Webcam Pro Ex */ + { USB_DEVICE(0x04CC, 0x8116) }, /* Afina Eye */ + { USB_DEVICE(0x06BE, 0x8116) }, /* new Afina Eye */ + { USB_DEVICE(0x0d81, 0x1910) }, /* Visionite */ + { USB_DEVICE(0x0d81, 0x1900) }, + { } +}; +MODULE_DEVICE_TABLE(usb, pwc_device_table); + +static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id); +static void usb_pwc_disconnect(struct usb_interface *intf); + +static struct usb_driver pwc_driver = { + .owner = THIS_MODULE, + .name = "Philips webcam", /* name */ + .id_table = pwc_device_table, + .probe = usb_pwc_probe, /* probe() */ + .disconnect = usb_pwc_disconnect, /* disconnect() */ +}; + +#define MAX_DEV_HINTS 20 +#define MAX_ISOC_ERRORS 20 + +static int default_size = PSZ_QCIF; +static int default_fps = 10; +static int default_fbufs = 3; /* Default number of frame buffers */ +static int default_mbufs = 2; /* Default number of mmap() buffers */ + int pwc_trace = TRACE_MODULE | TRACE_FLOW | TRACE_PWCX; +static int power_save = 0; +static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */ + int pwc_preferred_compression = 2; /* 0..3 = uncompressed..high */ +static struct { + int type; + char serial_number[30]; + int device_node; + struct pwc_device *pdev; +} device_hint[MAX_DEV_HINTS]; + +/***/ + +static int pwc_video_open(struct inode *inode, struct file *file); +static int pwc_video_close(struct inode *inode, struct file *file); +static ssize_t pwc_video_read(struct file *file, char *buf, + size_t count, loff_t *ppos); +static unsigned int pwc_video_poll(struct file *file, poll_table *wait); +static int pwc_video_ioctl(struct inode *inode, struct file *file, + unsigned int ioctlnr, unsigned long arg); +static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma); + +static struct file_operations pwc_fops = { + .owner = THIS_MODULE, + .open = pwc_video_open, + .release = pwc_video_close, + .read = pwc_video_read, + .poll = pwc_video_poll, + .mmap = pwc_video_mmap, + .ioctl = pwc_video_ioctl, + .llseek = no_llseek, +}; +static struct video_device pwc_template = { + .owner = THIS_MODULE, + .name = "Philips Webcam", /* Filled in later */ + .type = VID_TYPE_CAPTURE, + .hardware = VID_HARDWARE_PWC, + .release = video_device_release, + .fops = &pwc_fops, + .minor = -1, +}; + +/***************************************************************************/ + +/* Okay, this is some magic that I worked out and the reasoning behind it... + + The biggest problem with any USB device is of course: "what to do + when the user unplugs the device while it is in use by an application?" + We have several options: + 1) Curse them with the 7 plagues when they do (requires divine intervention) + 2) Tell them not to (won't work: they'll do it anyway) + 3) Oops the kernel (this will have a negative effect on a user's uptime) + 4) Do something sensible. + + Of course, we go for option 4. + + It happens that this device will be linked to two times, once from + usb_device and once from the video_device in their respective 'private' + pointers. This is done when the device is probed() and all initialization + succeeded. The pwc_device struct links back to both structures. + + When a device is unplugged while in use it will be removed from the + list of known USB devices; I also de-register it as a V4L device, but + unfortunately I can't free the memory since the struct is still in use + by the file descriptor. This free-ing is then deferend until the first + opportunity. Crude, but it works. + + A small 'advantage' is that if a user unplugs the cam and plugs it back + in, it should get assigned the same video device minor, but unfortunately + it's non-trivial to re-link the cam back to the video device... (that + would surely be magic! :)) +*/ + +/***************************************************************************/ +/* Private functions */ + +/* Here we want the physical address of the memory. + * This is used when initializing the contents of the area. + */ +static inline unsigned long kvirt_to_pa(unsigned long adr) +{ + unsigned long kva, ret; + + kva = (unsigned long) page_address(vmalloc_to_page((void *)adr)); + kva |= adr & (PAGE_SIZE-1); /* restore the offset */ + ret = __pa(kva); + return ret; +} + +static void * rvmalloc(unsigned long size) +{ + void * mem; + unsigned long adr; + + size=PAGE_ALIGN(size); + mem=vmalloc_32(size); + if (mem) + { + memset(mem, 0, size); /* Clear the ram out, no junk to the user */ + adr=(unsigned long) mem; + while (size > 0) + { + SetPageReserved(vmalloc_to_page((void *)adr)); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + } + return mem; +} + +static void rvfree(void * mem, unsigned long size) +{ + unsigned long adr; + + if (mem) + { + adr=(unsigned long) mem; + while ((long) size > 0) + { + ClearPageReserved(vmalloc_to_page((void *)adr)); + adr+=PAGE_SIZE; + size-=PAGE_SIZE; + } + vfree(mem); + } +} + + + + +static int pwc_allocate_buffers(struct pwc_device *pdev) +{ + int i; + void *kbuf; + + Trace(TRACE_MEMORY, ">> pwc_allocate_buffers(pdev = 0x%p)\n", pdev); + + if (pdev == NULL) + return -ENXIO; + +#ifdef PWC_MAGIC + if (pdev->magic != PWC_MAGIC) { + Err("allocate_buffers(): magic failed.\n"); + return -ENXIO; + } +#endif + /* Allocate Isochronuous pipe buffers */ + for (i = 0; i < MAX_ISO_BUFS; i++) { + if (pdev->sbuf[i].data == NULL) { + kbuf = kmalloc(ISO_BUFFER_SIZE, GFP_KERNEL); + if (kbuf == NULL) { + Err("Failed to allocate iso buffer %d.\n", i); + return -ENOMEM; + } + Trace(TRACE_MEMORY, "Allocated iso buffer at %p.\n", kbuf); + pdev->sbuf[i].data = kbuf; + memset(kbuf, 0, ISO_BUFFER_SIZE); + } + } + + /* Allocate frame buffer structure */ + if (pdev->fbuf == NULL) { + kbuf = kmalloc(default_fbufs * sizeof(struct pwc_frame_buf), GFP_KERNEL); + if (kbuf == NULL) { + Err("Failed to allocate frame buffer structure.\n"); + return -ENOMEM; + } + Trace(TRACE_MEMORY, "Allocated frame buffer structure at %p.\n", kbuf); + pdev->fbuf = kbuf; + memset(kbuf, 0, default_fbufs * sizeof(struct pwc_frame_buf)); + } + /* create frame buffers, and make circular ring */ + for (i = 0; i < default_fbufs; i++) { + if (pdev->fbuf[i].data == NULL) { + kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */ + if (kbuf == NULL) { + Err("Failed to allocate frame buffer %d.\n", i); + return -ENOMEM; + } + Trace(TRACE_MEMORY, "Allocated frame buffer %d at %p.\n", i, kbuf); + pdev->fbuf[i].data = kbuf; + memset(kbuf, 128, PWC_FRAME_SIZE); + } + } + + /* Allocate decompressor table space */ + kbuf = NULL; + switch (pdev->type) + { + case 675: + case 680: + case 690: + case 720: + case 730: + case 740: + case 750: + Trace(TRACE_MEMORY,"private_data(%zd)\n",sizeof(struct pwc_dec23_private)); + kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); /* Timon & Kiara */ + break; + case 645: + case 646: + /* TODO & FIXME */ + kbuf = kmalloc(sizeof(struct pwc_dec23_private), GFP_KERNEL); + break; + } + if (kbuf == NULL) { + Err("Failed to allocate decompress table.\n"); + return -ENOMEM; + } + pdev->decompress_data = kbuf; + + /* Allocate image buffer; double buffer for mmap() */ + kbuf = rvmalloc(default_mbufs * pdev->len_per_image); + if (kbuf == NULL) { + Err("Failed to allocate image buffer(s). needed (%d)\n",default_mbufs * pdev->len_per_image); + return -ENOMEM; + } + Trace(TRACE_MEMORY, "Allocated image buffer at %p.\n", kbuf); + pdev->image_data = kbuf; + for (i = 0; i < default_mbufs; i++) + pdev->image_ptr[i] = kbuf + i * pdev->len_per_image; + for (; i < MAX_IMAGES; i++) + pdev->image_ptr[i] = NULL; + + kbuf = NULL; + + Trace(TRACE_MEMORY, "<< pwc_allocate_buffers()\n"); + return 0; +} + +static void pwc_free_buffers(struct pwc_device *pdev) +{ + int i; + + Trace(TRACE_MEMORY, "Entering free_buffers(%p).\n", pdev); + + if (pdev == NULL) + return; +#ifdef PWC_MAGIC + if (pdev->magic != PWC_MAGIC) { + Err("free_buffers(): magic failed.\n"); + return; + } +#endif + + /* Release Iso-pipe buffers */ + for (i = 0; i < MAX_ISO_BUFS; i++) + if (pdev->sbuf[i].data != NULL) { + Trace(TRACE_MEMORY, "Freeing ISO buffer at %p.\n", pdev->sbuf[i].data); + kfree(pdev->sbuf[i].data); + pdev->sbuf[i].data = NULL; + } + + /* The same for frame buffers */ + if (pdev->fbuf != NULL) { + for (i = 0; i < default_fbufs; i++) { + if (pdev->fbuf[i].data != NULL) { + Trace(TRACE_MEMORY, "Freeing frame buffer %d at %p.\n", i, pdev->fbuf[i].data); + vfree(pdev->fbuf[i].data); + pdev->fbuf[i].data = NULL; + } + } + kfree(pdev->fbuf); + pdev->fbuf = NULL; + } + + /* Intermediate decompression buffer & tables */ + if (pdev->decompress_data != NULL) { + Trace(TRACE_MEMORY, "Freeing decompression buffer at %p.\n", pdev->decompress_data); + kfree(pdev->decompress_data); + pdev->decompress_data = NULL; + } + pdev->decompressor = NULL; + + /* Release image buffers */ + if (pdev->image_data != NULL) { + Trace(TRACE_MEMORY, "Freeing image buffer at %p.\n", pdev->image_data); + rvfree(pdev->image_data, default_mbufs * pdev->len_per_image); + } + pdev->image_data = NULL; + + Trace(TRACE_MEMORY, "Leaving free_buffers().\n"); +} + +/* The frame & image buffer mess. + + Yes, this is a mess. Well, it used to be simple, but alas... In this + module, 3 buffers schemes are used to get the data from the USB bus to + the user program. The first scheme involves the ISO buffers (called thus + since they transport ISO data from the USB controller), and not really + interesting. Suffices to say the data from this buffer is quickly + gathered in an interrupt handler (pwc_isoc_handler) and placed into the + frame buffer. + + The frame buffer is the second scheme, and is the central element here. + It collects the data from a single frame from the camera (hence, the + name). Frames are delimited by the USB camera with a short USB packet, + so that's easy to detect. The frame buffers form a list that is filled + by the camera+USB controller and drained by the user process through + either read() or mmap(). + + The image buffer is the third scheme, in which frames are decompressed + and converted into planar format. For mmap() there is more than + one image buffer available. + + The frame buffers provide the image buffering. In case the user process + is a bit slow, this introduces lag and some undesired side-effects. + The problem arises when the frame buffer is full. I used to drop the last + frame, which makes the data in the queue stale very quickly. But dropping + the frame at the head of the queue proved to be a litte bit more difficult. + I tried a circular linked scheme, but this introduced more problems than + it solved. + + Because filling and draining are completely asynchronous processes, this + requires some fiddling with pointers and mutexes. + + Eventually, I came up with a system with 2 lists: an 'empty' frame list + and a 'full' frame list: + * Initially, all frame buffers but one are on the 'empty' list; the one + remaining buffer is our initial fill frame. + * If a frame is needed for filling, we try to take it from the 'empty' + list, unless that list is empty, in which case we take the buffer at + the head of the 'full' list. + * When our fill buffer has been filled, it is appended to the 'full' + list. + * If a frame is needed by read() or mmap(), it is taken from the head of + the 'full' list, handled, and then appended to the 'empty' list. If no + buffer is present on the 'full' list, we wait. + The advantage is that the buffer that is currently being decompressed/ + converted, is on neither list, and thus not in our way (any other scheme + I tried had the problem of old data lingering in the queue). + + Whatever strategy you choose, it always remains a tradeoff: with more + frame buffers the chances of a missed frame are reduced. On the other + hand, on slower machines it introduces lag because the queue will + always be full. + */ + +/** + \brief Find next frame buffer to fill. Take from empty or full list, whichever comes first. + */ +static inline int pwc_next_fill_frame(struct pwc_device *pdev) +{ + int ret; + unsigned long flags; + + ret = 0; + spin_lock_irqsave(&pdev->ptrlock, flags); + if (pdev->fill_frame != NULL) { + /* append to 'full' list */ + if (pdev->full_frames == NULL) { + pdev->full_frames = pdev->fill_frame; + pdev->full_frames_tail = pdev->full_frames; + } + else { + pdev->full_frames_tail->next = pdev->fill_frame; + pdev->full_frames_tail = pdev->fill_frame; + } + } + if (pdev->empty_frames != NULL) { + /* We have empty frames available. That's easy */ + pdev->fill_frame = pdev->empty_frames; + pdev->empty_frames = pdev->empty_frames->next; + } + else { + /* Hmm. Take it from the full list */ +#if PWC_DEBUG + /* sanity check */ + if (pdev->full_frames == NULL) { + Err("Neither empty or full frames available!\n"); + spin_unlock_irqrestore(&pdev->ptrlock, flags); + return -EINVAL; + } +#endif + pdev->fill_frame = pdev->full_frames; + pdev->full_frames = pdev->full_frames->next; + ret = 1; + } + pdev->fill_frame->next = NULL; +#if PWC_DEBUG + Trace(TRACE_SEQUENCE, "Assigning sequence number %d.\n", pdev->sequence); + pdev->fill_frame->sequence = pdev->sequence++; +#endif + spin_unlock_irqrestore(&pdev->ptrlock, flags); + return ret; +} + + +/** + \brief Reset all buffers, pointers and lists, except for the image_used[] buffer. + + If the image_used[] buffer is cleared too, mmap()/VIDIOCSYNC will run into trouble. + */ +static void pwc_reset_buffers(struct pwc_device *pdev) +{ + int i; + unsigned long flags; + + spin_lock_irqsave(&pdev->ptrlock, flags); + pdev->full_frames = NULL; + pdev->full_frames_tail = NULL; + for (i = 0; i < default_fbufs; i++) { + pdev->fbuf[i].filled = 0; + if (i > 0) + pdev->fbuf[i].next = &pdev->fbuf[i - 1]; + else + pdev->fbuf->next = NULL; + } + pdev->empty_frames = &pdev->fbuf[default_fbufs - 1]; + pdev->empty_frames_tail = pdev->fbuf; + pdev->read_frame = NULL; + pdev->fill_frame = pdev->empty_frames; + pdev->empty_frames = pdev->empty_frames->next; + + pdev->image_read_pos = 0; + pdev->fill_image = 0; + spin_unlock_irqrestore(&pdev->ptrlock, flags); +} + + +/** + \brief Do all the handling for getting one frame: get pointer, decompress, advance pointers. + */ +static int pwc_handle_frame(struct pwc_device *pdev) +{ + int ret = 0; + unsigned long flags; + + spin_lock_irqsave(&pdev->ptrlock, flags); + /* First grab our read_frame; this is removed from all lists, so + we can release the lock after this without problems */ + if (pdev->read_frame != NULL) { + /* This can't theoretically happen */ + Err("Huh? Read frame still in use?\n"); + } + else { + if (pdev->full_frames == NULL) { + Err("Woops. No frames ready.\n"); + } + else { + pdev->read_frame = pdev->full_frames; + pdev->full_frames = pdev->full_frames->next; + pdev->read_frame->next = NULL; + } + + if (pdev->read_frame != NULL) { +#if PWC_DEBUG + Trace(TRACE_SEQUENCE, "Decompressing frame %d\n", pdev->read_frame->sequence); +#endif + /* Decompression is a lenghty process, so it's outside of the lock. + This gives the isoc_handler the opportunity to fill more frames + in the mean time. + */ + spin_unlock_irqrestore(&pdev->ptrlock, flags); + ret = pwc_decompress(pdev); + spin_lock_irqsave(&pdev->ptrlock, flags); + + /* We're done with read_buffer, tack it to the end of the empty buffer list */ + if (pdev->empty_frames == NULL) { + pdev->empty_frames = pdev->read_frame; + pdev->empty_frames_tail = pdev->empty_frames; + } + else { + pdev->empty_frames_tail->next = pdev->read_frame; + pdev->empty_frames_tail = pdev->read_frame; + } + pdev->read_frame = NULL; + } + } + spin_unlock_irqrestore(&pdev->ptrlock, flags); + return ret; +} + +/** + \brief Advance pointers of image buffer (after each user request) +*/ +static inline void pwc_next_image(struct pwc_device *pdev) +{ + pdev->image_used[pdev->fill_image] = 0; + pdev->fill_image = (pdev->fill_image + 1) % default_mbufs; +} + + +/* This gets called for the Isochronous pipe (video). This is done in + * interrupt time, so it has to be fast, not crash, and not stall. Neat. + */ +static void pwc_isoc_handler(struct urb *urb, struct pt_regs *regs) +{ + struct pwc_device *pdev; + int i, fst, flen; + int awake; + struct pwc_frame_buf *fbuf; + unsigned char *fillptr = 0, *iso_buf = 0; + + awake = 0; + pdev = (struct pwc_device *)urb->context; + if (pdev == NULL) { + Err("isoc_handler() called with NULL device?!\n"); + return; + } +#ifdef PWC_MAGIC + if (pdev->magic != PWC_MAGIC) { + Err("isoc_handler() called with bad magic!\n"); + return; + } +#endif + if (urb->status == -ENOENT || urb->status == -ECONNRESET) { + Trace(TRACE_OPEN, "pwc_isoc_handler(): URB (%p) unlinked %ssynchronuously.\n", urb, urb->status == -ENOENT ? "" : "a"); + return; + } + if (urb->status != -EINPROGRESS && urb->status != 0) { + const char *errmsg; + + errmsg = "Unknown"; + switch(urb->status) { + case -ENOSR: errmsg = "Buffer error (overrun)"; break; + case -EPIPE: errmsg = "Stalled (device not responding)"; break; + case -EOVERFLOW: errmsg = "Babble (bad cable?)"; break; + case -EPROTO: errmsg = "Bit-stuff error (bad cable?)"; break; + case -EILSEQ: errmsg = "CRC/Timeout (could be anything)"; break; + case -ETIMEDOUT: errmsg = "NAK (device does not respond)"; break; + } + Trace(TRACE_FLOW, "pwc_isoc_handler() called with status %d [%s].\n", urb->status, errmsg); + /* Give up after a number of contiguous errors on the USB bus. + Appearantly something is wrong so we simulate an unplug event. + */ + if (++pdev->visoc_errors > MAX_ISOC_ERRORS) + { + Info("Too many ISOC errors, bailing out.\n"); + pdev->error_status = EIO; + awake = 1; + wake_up_interruptible(&pdev->frameq); + } + goto handler_end; // ugly, but practical + } + + fbuf = pdev->fill_frame; + if (fbuf == NULL) { + Err("pwc_isoc_handler without valid fill frame.\n"); + awake = 1; + goto handler_end; + } + else { + fillptr = fbuf->data + fbuf->filled; + } + + /* Reset ISOC error counter. We did get here, after all. */ + pdev->visoc_errors = 0; + + /* vsync: 0 = don't copy data + 1 = sync-hunt + 2 = synched + */ + /* Compact data */ + for (i = 0; i < urb->number_of_packets; i++) { + fst = urb->iso_frame_desc[i].status; + flen = urb->iso_frame_desc[i].actual_length; + iso_buf = urb->transfer_buffer + urb->iso_frame_desc[i].offset; + if (fst == 0) { + if (flen > 0) { /* if valid data... */ + if (pdev->vsync > 0) { /* ...and we are not sync-hunting... */ + pdev->vsync = 2; + + /* ...copy data to frame buffer, if possible */ + if (flen + fbuf->filled > pdev->frame_total_size) { + Trace(TRACE_FLOW, "Frame buffer overflow (flen = %d, frame_total_size = %d).\n", flen, pdev->frame_total_size); + pdev->vsync = 0; /* Hmm, let's wait for an EOF (end-of-frame) */ + pdev->vframes_error++; + } + else { + memmove(fillptr, iso_buf, flen); + fillptr += flen; + } + } + fbuf->filled += flen; + } /* ..flen > 0 */ + + if (flen < pdev->vlast_packet_size) { + /* Shorter packet... We probably have the end of an image-frame; + wake up read() process and let select()/poll() do something. + Decompression is done in user time over there. + */ + if (pdev->vsync == 2) { + /* The ToUCam Fun CMOS sensor causes the firmware to send 2 or 3 bogus + frames on the USB wire after an exposure change. This conditition is + however detected in the cam and a bit is set in the header. + */ + if (pdev->type == 730) { + unsigned char *ptr = (unsigned char *)fbuf->data; + + if (ptr[1] == 1 && ptr[0] & 0x10) { +#if PWC_DEBUG + Debug("Hyundai CMOS sensor bug. Dropping frame %d.\n", fbuf->sequence); +#endif + pdev->drop_frames += 2; + pdev->vframes_error++; + } + if ((ptr[0] ^ pdev->vmirror) & 0x01) { + if (ptr[0] & 0x01) + Info("Snapshot button pressed.\n"); + else + Info("Snapshot button released.\n"); + } + if ((ptr[0] ^ pdev->vmirror) & 0x02) { + if (ptr[0] & 0x02) + Info("Image is mirrored.\n"); + else + Info("Image is normal.\n"); + } + pdev->vmirror = ptr[0] & 0x03; + /* Sometimes the trailer of the 730 is still sent as a 4 byte packet + after a short frame; this condition is filtered out specifically. A 4 byte + frame doesn't make sense anyway. + So we get either this sequence: + drop_bit set -> 4 byte frame -> short frame -> good frame + Or this one: + drop_bit set -> short frame -> good frame + So we drop either 3 or 2 frames in all! + */ + if (fbuf->filled == 4) + pdev->drop_frames++; + } + + /* In case we were instructed to drop the frame, do so silently. + The buffer pointers are not updated either (but the counters are reset below). + */ + if (pdev->drop_frames > 0) + pdev->drop_frames--; + else { + /* Check for underflow first */ + if (fbuf->filled < pdev->frame_total_size) { + Trace(TRACE_FLOW, "Frame buffer underflow (%d bytes); discarded.\n", fbuf->filled); + pdev->vframes_error++; + } + else { + /* Send only once per EOF */ + awake = 1; /* delay wake_ups */ + + /* Find our next frame to fill. This will always succeed, since we + * nick a frame from either empty or full list, but if we had to + * take it from the full list, it means a frame got dropped. + */ + if (pwc_next_fill_frame(pdev)) { + pdev->vframes_dumped++; + if ((pdev->vframe_count > FRAME_LOWMARK) && (pwc_trace & TRACE_FLOW)) { + if (pdev->vframes_dumped < 20) + Trace(TRACE_FLOW, "Dumping frame %d.\n", pdev->vframe_count); + if (pdev->vframes_dumped == 20) + Trace(TRACE_FLOW, "Dumping frame %d (last message).\n", pdev->vframe_count); + } + } + fbuf = pdev->fill_frame; + } + } /* !drop_frames */ + pdev->vframe_count++; + } + fbuf->filled = 0; + fillptr = fbuf->data; + pdev->vsync = 1; + } /* .. flen < last_packet_size */ + pdev->vlast_packet_size = flen; + } /* ..status == 0 */ +#if PWC_DEBUG + /* This is normally not interesting to the user, unless you are really debugging something */ + else { + static int iso_error = 0; + iso_error++; + if (iso_error < 20) + Trace(TRACE_FLOW, "Iso frame %d of USB has error %d\n", i, fst); + } +#endif + } + +handler_end: + if (awake) + wake_up_interruptible(&pdev->frameq); + + urb->dev = pdev->udev; + i = usb_submit_urb(urb, GFP_ATOMIC); + if (i != 0) + Err("Error (%d) re-submitting urb in pwc_isoc_handler.\n", i); +} + + +static int pwc_isoc_init(struct pwc_device *pdev) +{ + struct usb_device *udev; + struct urb *urb; + int i, j, ret; + + struct usb_interface *intf; + struct usb_host_interface *idesc = NULL; + + if (pdev == NULL) + return -EFAULT; + if (pdev->iso_init) + return 0; + pdev->vsync = 0; + udev = pdev->udev; + + /* Get the current alternate interface, adjust packet size */ + if (!udev->actconfig) + return -EFAULT; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5) + idesc = &udev->actconfig->interface[0]->altsetting[pdev->valternate]; +#else + intf = usb_ifnum_to_if(udev, 0); + if (intf) + idesc = usb_altnum_to_altsetting(intf, pdev->valternate); +#endif + + if (!idesc) + return -EFAULT; + + /* Search video endpoint */ + pdev->vmax_packet_size = -1; + for (i = 0; i < idesc->desc.bNumEndpoints; i++) + if ((idesc->endpoint[i].desc.bEndpointAddress & 0xF) == pdev->vendpoint) { + pdev->vmax_packet_size = idesc->endpoint[i].desc.wMaxPacketSize; + break; + } + + if (pdev->vmax_packet_size < 0 || pdev->vmax_packet_size > ISO_MAX_FRAME_SIZE) { + Err("Failed to find packet size for video endpoint in current alternate setting.\n"); + return -ENFILE; /* Odd error, that should be noticable */ + } + + /* Set alternate interface */ + ret = 0; + Trace(TRACE_OPEN, "Setting alternate interface %d\n", pdev->valternate); + ret = usb_set_interface(pdev->udev, 0, pdev->valternate); + if (ret < 0) + return ret; + + for (i = 0; i < MAX_ISO_BUFS; i++) { + urb = usb_alloc_urb(ISO_FRAMES_PER_DESC, GFP_KERNEL); + if (urb == NULL) { + Err("Failed to allocate urb %d\n", i); + ret = -ENOMEM; + break; + } + pdev->sbuf[i].urb = urb; + Trace(TRACE_MEMORY, "Allocated URB at 0x%p\n", urb); + } + if (ret) { + /* De-allocate in reverse order */ + while (i >= 0) { + if (pdev->sbuf[i].urb != NULL) + usb_free_urb(pdev->sbuf[i].urb); + pdev->sbuf[i].urb = NULL; + i--; + } + return ret; + } + + /* init URB structure */ + for (i = 0; i < MAX_ISO_BUFS; i++) { + urb = pdev->sbuf[i].urb; + + urb->interval = 1; // devik + urb->dev = udev; + urb->pipe = usb_rcvisocpipe(udev, pdev->vendpoint); + urb->transfer_flags = URB_ISO_ASAP; + urb->transfer_buffer = pdev->sbuf[i].data; + urb->transfer_buffer_length = ISO_BUFFER_SIZE; + urb->complete = pwc_isoc_handler; + urb->context = pdev; + urb->start_frame = 0; + urb->number_of_packets = ISO_FRAMES_PER_DESC; + for (j = 0; j < ISO_FRAMES_PER_DESC; j++) { + urb->iso_frame_desc[j].offset = j * ISO_MAX_FRAME_SIZE; + urb->iso_frame_desc[j].length = pdev->vmax_packet_size; + } + } + + /* link */ + for (i = 0; i < MAX_ISO_BUFS; i++) { + ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL); + if (ret) + Err("isoc_init() submit_urb %d failed with error %d\n", i, ret); + else + Trace(TRACE_MEMORY, "URB 0x%p submitted.\n", pdev->sbuf[i].urb); + } + + /* All is done... */ + pdev->iso_init = 1; + Trace(TRACE_OPEN, "<< pwc_isoc_init()\n"); + return 0; +} + +static void pwc_isoc_cleanup(struct pwc_device *pdev) +{ + int i; + + Trace(TRACE_OPEN, ">> pwc_isoc_cleanup()\n"); + if (pdev == NULL) + return; + + /* Unlinking ISOC buffers one by one */ + for (i = 0; i < MAX_ISO_BUFS; i++) { + struct urb *urb; + + urb = pdev->sbuf[i].urb; + if (urb != 0) { + if (pdev->iso_init) { + Trace(TRACE_MEMORY, "Unlinking URB %p\n", urb); + usb_kill_urb(urb); + } + Trace(TRACE_MEMORY, "Freeing URB\n"); + usb_free_urb(urb); + pdev->sbuf[i].urb = NULL; + } + } + + /* Stop camera, but only if we are sure the camera is still there (unplug + is signalled by EPIPE) + */ + if (pdev->error_status && pdev->error_status != EPIPE) { + Trace(TRACE_OPEN, "Setting alternate interface 0.\n"); + usb_set_interface(pdev->udev, 0, 0); + } + + pdev->iso_init = 0; + Trace(TRACE_OPEN, "<< pwc_isoc_cleanup()\n"); +} + +int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot) +{ + int ret, start; + + /* Stop isoc stuff */ + pwc_isoc_cleanup(pdev); + /* Reset parameters */ + pwc_reset_buffers(pdev); + /* Try to set video mode... */ + start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot); + if (ret) { + Trace(TRACE_FLOW, "pwc_set_video_mode attempt 1 failed.\n"); + /* That failed... restore old mode (we know that worked) */ + start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); + if (start) { + Trace(TRACE_FLOW, "pwc_set_video_mode attempt 2 failed.\n"); + } + } + if (start == 0) + { + if (pwc_isoc_init(pdev) < 0) + { + Info("Failed to restart ISOC transfers in pwc_try_video_mode.\n"); + ret = -EAGAIN; /* let's try again, who knows if it works a second time */ + } + } + pdev->drop_frames++; /* try to avoid garbage during switch */ + return ret; /* Return original error code */ +} + + +/***************************************************************************/ +/* Video4Linux functions */ + +static int pwc_video_open(struct inode *inode, struct file *file) +{ + int i; + struct video_device *vdev = video_devdata(file); + struct pwc_device *pdev; + + Trace(TRACE_OPEN, ">> video_open called(vdev = 0x%p).\n", vdev); + + pdev = (struct pwc_device *)vdev->priv; + if (pdev == NULL) + BUG(); + if (pdev->vopen) + return -EBUSY; + + down(&pdev->modlock); + if (!pdev->usb_init) { + Trace(TRACE_OPEN, "Doing first time initialization.\n"); + pdev->usb_init = 1; + + if (pwc_trace & TRACE_OPEN) + { + /* Query sensor type */ + const char *sensor_type = NULL; + int ret; + + ret = pwc_get_cmos_sensor(pdev, &i); + if (ret >= 0) + { + switch(i) { + case 0x00: sensor_type = "Hyundai CMOS sensor"; break; + case 0x20: sensor_type = "Sony CCD sensor + TDA8787"; break; + case 0x2E: sensor_type = "Sony CCD sensor + Exas 98L59"; break; + case 0x2F: sensor_type = "Sony CCD sensor + ADI 9804"; break; + case 0x30: sensor_type = "Sharp CCD sensor + TDA8787"; break; + case 0x3E: sensor_type = "Sharp CCD sensor + Exas 98L59"; break; + case 0x3F: sensor_type = "Sharp CCD sensor + ADI 9804"; break; + case 0x40: sensor_type = "UPA 1021 sensor"; break; + case 0x100: sensor_type = "VGA sensor"; break; + case 0x101: sensor_type = "PAL MR sensor"; break; + default: sensor_type = "unknown type of sensor"; break; + } + } + if (sensor_type != NULL) + Info("This %s camera is equipped with a %s (%d).\n", pdev->vdev->name, sensor_type, i); + } + } + + /* Turn on camera */ + if (power_save) { + i = pwc_camera_power(pdev, 1); + if (i < 0) + Info("Failed to restore power to the camera! (%d)\n", i); + } + /* Set LED on/off time */ + if (pwc_set_leds(pdev, led_on, led_off) < 0) + Info("Failed to set LED on/off time.\n"); + + pwc_construct(pdev); /* set min/max sizes correct */ + + /* So far, so good. Allocate memory. */ + i = pwc_allocate_buffers(pdev); + if (i < 0) { + Trace(TRACE_OPEN, "Failed to allocate buffer memory.\n"); + up(&pdev->modlock); + return i; + } + + /* Reset buffers & parameters */ + pwc_reset_buffers(pdev); + for (i = 0; i < default_mbufs; i++) + pdev->image_used[i] = 0; + pdev->vframe_count = 0; + pdev->vframes_dumped = 0; + pdev->vframes_error = 0; + pdev->visoc_errors = 0; + pdev->error_status = 0; +#if PWC_DEBUG + pdev->sequence = 0; +#endif + pwc_construct(pdev); /* set min/max sizes correct */ + + /* Set some defaults */ + pdev->vsnapshot = 0; + + /* Start iso pipe for video; first try the last used video size + (or the default one); if that fails try QCIF/10 or QSIF/10; + it that fails too, give up. + */ + i = pwc_set_video_mode(pdev, pwc_image_sizes[pdev->vsize].x, pwc_image_sizes[pdev->vsize].y, pdev->vframes, pdev->vcompression, 0); + if (i) { + Trace(TRACE_OPEN, "First attempt at set_video_mode failed.\n"); + if (pdev->type == 730 || pdev->type == 740 || pdev->type == 750) + i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QSIF].x, pwc_image_sizes[PSZ_QSIF].y, 10, pdev->vcompression, 0); + else + i = pwc_set_video_mode(pdev, pwc_image_sizes[PSZ_QCIF].x, pwc_image_sizes[PSZ_QCIF].y, 10, pdev->vcompression, 0); + } + if (i) { + Trace(TRACE_OPEN, "Second attempt at set_video_mode failed.\n"); + up(&pdev->modlock); + return i; + } + + i = pwc_isoc_init(pdev); + if (i) { + Trace(TRACE_OPEN, "Failed to init ISOC stuff = %d.\n", i); + up(&pdev->modlock); + return i; + } + + pdev->vopen++; + file->private_data = vdev; + up(&pdev->modlock); + Trace(TRACE_OPEN, "<< video_open() returns 0.\n"); + return 0; +} + +/* Note that all cleanup is done in the reverse order as in _open */ +static int pwc_video_close(struct inode *inode, struct file *file) +{ + struct video_device *vdev = file->private_data; + struct pwc_device *pdev; + int i; + + Trace(TRACE_OPEN, ">> video_close called(vdev = 0x%p).\n", vdev); + + pdev = (struct pwc_device *)vdev->priv; + if (pdev->vopen == 0) + Info("video_close() called on closed device?\n"); + + /* Dump statistics, but only if a reasonable amount of frames were + processed (to prevent endless log-entries in case of snap-shot + programs) + */ + if (pdev->vframe_count > 20) + Info("Closing video device: %d frames received, dumped %d frames, %d frames with errors.\n", pdev->vframe_count, pdev->vframes_dumped, pdev->vframes_error); + + switch (pdev->type) + { + case 675: + case 680: + case 690: + case 720: + case 730: + case 740: + case 750: + pwc_dec23_exit(); /* Timon & Kiara */ + break; + case 645: + case 646: + pwc_dec1_exit(); + break; + } + + pwc_isoc_cleanup(pdev); + pwc_free_buffers(pdev); + + /* Turn off LEDS and power down camera, but only when not unplugged */ + if (pdev->error_status != EPIPE) { + /* Turn LEDs off */ + if (pwc_set_leds(pdev, 0, 0) < 0) + Info("Failed to set LED on/off time.\n"); + if (power_save) { + i = pwc_camera_power(pdev, 0); + if (i < 0) + Err("Failed to power down camera (%d)\n", i); + } + } + pdev->vopen = 0; + Trace(TRACE_OPEN, "<< video_close()\n"); + return 0; +} + +/* + * FIXME: what about two parallel reads ???? + * ANSWER: Not supported. You can't open the device more than once, + despite what the V4L1 interface says. First, I don't see + the need, second there's no mechanism of alerting the + 2nd/3rd/... process of events like changing image size. + And I don't see the point of blocking that for the + 2nd/3rd/... process. + In multi-threaded environments reading parallel from any + device is tricky anyhow. + */ + +static ssize_t pwc_video_read(struct file *file, char *buf, + size_t count, loff_t *ppos) +{ + struct video_device *vdev = file->private_data; + struct pwc_device *pdev; + int noblock = file->f_flags & O_NONBLOCK; + DECLARE_WAITQUEUE(wait, current); + int bytes_to_read; + + Trace(TRACE_READ, "video_read(0x%p, %p, %zd) called.\n", vdev, buf, count); + if (vdev == NULL) + return -EFAULT; + pdev = vdev->priv; + if (pdev == NULL) + return -EFAULT; + if (pdev->error_status) + return -pdev->error_status; /* Something happened, report what. */ + + /* In case we're doing partial reads, we don't have to wait for a frame */ + if (pdev->image_read_pos == 0) { + /* Do wait queueing according to the (doc)book */ + add_wait_queue(&pdev->frameq, &wait); + while (pdev->full_frames == NULL) { + /* Check for unplugged/etc. here */ + if (pdev->error_status) { + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + return -pdev->error_status ; + } + if (noblock) { + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + return -EWOULDBLOCK; + } + if (signal_pending(current)) { + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + return -ERESTARTSYS; + } + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + } + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + + /* Decompress and release frame */ + if (pwc_handle_frame(pdev)) + return -EFAULT; + } + + Trace(TRACE_READ, "Copying data to user space.\n"); + if (pdev->vpalette == VIDEO_PALETTE_RAW) + bytes_to_read = pdev->frame_size; + else + bytes_to_read = pdev->view.size; + + /* copy bytes to user space; we allow for partial reads */ + if (count + pdev->image_read_pos > bytes_to_read) + count = bytes_to_read - pdev->image_read_pos; + if (copy_to_user(buf, pdev->image_ptr[pdev->fill_image] + pdev->image_read_pos, count)) + return -EFAULT; + pdev->image_read_pos += count; + if (pdev->image_read_pos >= bytes_to_read) { /* All data has been read */ + pdev->image_read_pos = 0; + pwc_next_image(pdev); + } + return count; +} + +static unsigned int pwc_video_poll(struct file *file, poll_table *wait) +{ + struct video_device *vdev = file->private_data; + struct pwc_device *pdev; + + if (vdev == NULL) + return -EFAULT; + pdev = vdev->priv; + if (pdev == NULL) + return -EFAULT; + + poll_wait(file, &pdev->frameq, wait); + if (pdev->error_status) + return POLLERR; + if (pdev->full_frames != NULL) /* we have frames waiting */ + return (POLLIN | POLLRDNORM); + + return 0; +} + +static int pwc_video_do_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, void *arg) +{ + struct video_device *vdev = file->private_data; + struct pwc_device *pdev; + DECLARE_WAITQUEUE(wait, current); + + if (vdev == NULL) + return -EFAULT; + pdev = vdev->priv; + if (pdev == NULL) + return -EFAULT; + + switch (cmd) { + /* Query cabapilities */ + case VIDIOCGCAP: + { + struct video_capability *caps = arg; + + strcpy(caps->name, vdev->name); + caps->type = VID_TYPE_CAPTURE; + caps->channels = 1; + caps->audios = 1; + caps->minwidth = pdev->view_min.x; + caps->minheight = pdev->view_min.y; + caps->maxwidth = pdev->view_max.x; + caps->maxheight = pdev->view_max.y; + break; + } + + /* Channel functions (simulate 1 channel) */ + case VIDIOCGCHAN: + { + struct video_channel *v = arg; + + if (v->channel != 0) + return -EINVAL; + v->flags = 0; + v->tuners = 0; + v->type = VIDEO_TYPE_CAMERA; + strcpy(v->name, "Webcam"); + return 0; + } + + case VIDIOCSCHAN: + { + /* The spec says the argument is an integer, but + the bttv driver uses a video_channel arg, which + makes sense becasue it also has the norm flag. + */ + struct video_channel *v = arg; + if (v->channel != 0) + return -EINVAL; + return 0; + } + + + /* Picture functions; contrast etc. */ + case VIDIOCGPICT: + { + struct video_picture *p = arg; + int val; + + val = pwc_get_brightness(pdev); + if (val >= 0) + p->brightness = val; + else + p->brightness = 0xffff; + val = pwc_get_contrast(pdev); + if (val >= 0) + p->contrast = val; + else + p->contrast = 0xffff; + /* Gamma, Whiteness, what's the difference? :) */ + val = pwc_get_gamma(pdev); + if (val >= 0) + p->whiteness = val; + else + p->whiteness = 0xffff; + val = pwc_get_saturation(pdev); + if (val >= 0) + p->colour = val; + else + p->colour = 0xffff; + p->depth = 24; + p->palette = pdev->vpalette; + p->hue = 0xFFFF; /* N/A */ + break; + } + + case VIDIOCSPICT: + { + struct video_picture *p = arg; + /* + * FIXME: Suppose we are mid read + ANSWER: No problem: the firmware of the camera + can handle brightness/contrast/etc + changes at _any_ time, and the palette + is used exactly once in the uncompress + routine. + */ + pwc_set_brightness(pdev, p->brightness); + pwc_set_contrast(pdev, p->contrast); + pwc_set_gamma(pdev, p->whiteness); + pwc_set_saturation(pdev, p->colour); + if (p->palette && p->palette != pdev->vpalette) { + switch (p->palette) { + case VIDEO_PALETTE_YUV420P: + case VIDEO_PALETTE_RAW: + pdev->vpalette = p->palette; + return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot); + break; + default: + return -EINVAL; + break; + } + } + break; + } + + /* Window/size parameters */ + case VIDIOCGWIN: + { + struct video_window *vw = arg; + + vw->x = 0; + vw->y = 0; + vw->width = pdev->view.x; + vw->height = pdev->view.y; + vw->chromakey = 0; + vw->flags = (pdev->vframes << PWC_FPS_SHIFT) | + (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0); + break; + } + + case VIDIOCSWIN: + { + struct video_window *vw = arg; + int fps, snapshot, ret; + + fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT; + snapshot = vw->flags & PWC_FPS_SNAPSHOT; + if (fps == 0) + fps = pdev->vframes; + if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot) + return 0; + ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot); + if (ret) + return ret; + break; + } + + /* We don't have overlay support (yet) */ + case VIDIOCGFBUF: + { + struct video_buffer *vb = arg; + + memset(vb,0,sizeof(*vb)); + break; + } + + /* mmap() functions */ + case VIDIOCGMBUF: + { + /* Tell the user program how much memory is needed for a mmap() */ + struct video_mbuf *vm = arg; + int i; + + memset(vm, 0, sizeof(*vm)); + vm->size = default_mbufs * pdev->len_per_image; + vm->frames = default_mbufs; /* double buffering should be enough for most applications */ + for (i = 0; i < default_mbufs; i++) + vm->offsets[i] = i * pdev->len_per_image; + break; + } + + case VIDIOCMCAPTURE: + { + /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */ + struct video_mmap *vm = arg; + + Trace(TRACE_READ, "VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format); + if (vm->frame < 0 || vm->frame >= default_mbufs) + return -EINVAL; + + /* xawtv is nasty. It probes the available palettes + by setting a very small image size and trying + various palettes... The driver doesn't support + such small images, so I'm working around it. + */ + if (vm->format) + { + switch (vm->format) + { + case VIDEO_PALETTE_YUV420P: + case VIDEO_PALETTE_RAW: + break; + default: + return -EINVAL; + break; + } + } + + if ((vm->width != pdev->view.x || vm->height != pdev->view.y) && + (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) { + int ret; + + Trace(TRACE_OPEN, "VIDIOCMCAPTURE: changing size to please xawtv :-(.\n"); + ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot); + if (ret) + return ret; + } /* ... size mismatch */ + + /* FIXME: should we lock here? */ + if (pdev->image_used[vm->frame]) + return -EBUSY; /* buffer wasn't available. Bummer */ + pdev->image_used[vm->frame] = 1; + + /* Okay, we're done here. In the SYNC call we wait until a + frame comes available, then expand image into the given + buffer. + In contrast to the CPiA cam the Philips cams deliver a + constant stream, almost like a grabber card. Also, + we have separate buffers for the rawdata and the image, + meaning we can nearly always expand into the requested buffer. + */ + Trace(TRACE_READ, "VIDIOCMCAPTURE done.\n"); + break; + } + + case VIDIOCSYNC: + { + /* The doc says: "Whenever a buffer is used it should + call VIDIOCSYNC to free this frame up and continue." + + The only odd thing about this whole procedure is + that MCAPTURE flags the buffer as "in use", and + SYNC immediately unmarks it, while it isn't + after SYNC that you know that the buffer actually + got filled! So you better not start a CAPTURE in + the same frame immediately (use double buffering). + This is not a problem for this cam, since it has + extra intermediate buffers, but a hardware + grabber card will then overwrite the buffer + you're working on. + */ + int *mbuf = arg; + int ret; + + Trace(TRACE_READ, "VIDIOCSYNC called (%d).\n", *mbuf); + + /* bounds check */ + if (*mbuf < 0 || *mbuf >= default_mbufs) + return -EINVAL; + /* check if this buffer was requested anyway */ + if (pdev->image_used[*mbuf] == 0) + return -EINVAL; + + /* Add ourselves to the frame wait-queue. + + FIXME: needs auditing for safety. + QUESTION: In what respect? I think that using the + frameq is safe now. + */ + add_wait_queue(&pdev->frameq, &wait); + while (pdev->full_frames == NULL) { + if (pdev->error_status) { + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + return -pdev->error_status; + } + + if (signal_pending(current)) { + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + return -ERESTARTSYS; + } + schedule(); + set_current_state(TASK_INTERRUPTIBLE); + } + remove_wait_queue(&pdev->frameq, &wait); + set_current_state(TASK_RUNNING); + + /* The frame is ready. Expand in the image buffer + requested by the user. I don't care if you + mmap() 5 buffers and request data in this order: + buffer 4 2 3 0 1 2 3 0 4 3 1 . . . + Grabber hardware may not be so forgiving. + */ + Trace(TRACE_READ, "VIDIOCSYNC: frame ready.\n"); + pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */ + /* Decompress, etc */ + ret = pwc_handle_frame(pdev); + pdev->image_used[*mbuf] = 0; + if (ret) + return -EFAULT; + break; + } + + case VIDIOCGAUDIO: + { + struct video_audio *v = arg; + + strcpy(v->name, "Microphone"); + v->audio = -1; /* unknown audio minor */ + v->flags = 0; + v->mode = VIDEO_SOUND_MONO; + v->volume = 0; + v->bass = 0; + v->treble = 0; + v->balance = 0x8000; + v->step = 1; + break; + } + + case VIDIOCSAUDIO: + { + /* Dummy: nothing can be set */ + break; + } + + case VIDIOCGUNIT: + { + struct video_unit *vu = arg; + + vu->video = pdev->vdev->minor & 0x3F; + vu->audio = -1; /* not known yet */ + vu->vbi = -1; + vu->radio = -1; + vu->teletext = -1; + break; + } + default: + return pwc_ioctl(pdev, cmd, arg); + } /* ..switch */ + return 0; +} + +static int pwc_video_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + return video_usercopy(inode, file, cmd, arg, pwc_video_do_ioctl); +} + + +static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct video_device *vdev = file->private_data; + struct pwc_device *pdev; + unsigned long start = vma->vm_start; + unsigned long size = vma->vm_end-vma->vm_start; + unsigned long page, pos; + + Trace(TRACE_MEMORY, "mmap(0x%p, 0x%lx, %lu) called.\n", vdev, start, size); + pdev = vdev->priv; + + vma->vm_flags |= VM_IO; + + pos = (unsigned long)pdev->image_data; + while (size > 0) { + page = vmalloc_to_pfn((void *)pos); + if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + + start += PAGE_SIZE; + pos += PAGE_SIZE; + if (size > PAGE_SIZE) + size -= PAGE_SIZE; + else + size = 0; + } + + return 0; +} + +/***************************************************************************/ +/* USB functions */ + +/* This function gets called when a new device is plugged in or the usb core + * is loaded. + */ + +static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id *id) +{ + struct usb_device *udev = interface_to_usbdev(intf); + struct pwc_device *pdev = NULL; + int vendor_id, product_id, type_id; + int i, hint; + int features = 0; + int video_nr = -1; /* default: use next available device */ + char serial_number[30], *name; + + /* Check if we can handle this device */ + Trace(TRACE_PROBE, "probe() called [%04X %04X], if %d\n", + udev->descriptor.idVendor, udev->descriptor.idProduct, + intf->altsetting->desc.bInterfaceNumber); + + /* the interfaces are probed one by one. We are only interested in the + video interface (0) now. + Interface 1 is the Audio Control, and interface 2 Audio itself. + */ + if (intf->altsetting->desc.bInterfaceNumber > 0) + return -ENODEV; + + vendor_id = udev->descriptor.idVendor; + product_id = udev->descriptor.idProduct; + + if (vendor_id == 0x0471) { + switch (product_id) { + case 0x0302: + Info("Philips PCA645VC USB webcam detected.\n"); + name = "Philips 645 webcam"; + type_id = 645; + break; + case 0x0303: + Info("Philips PCA646VC USB webcam detected.\n"); + name = "Philips 646 webcam"; + type_id = 646; + break; + case 0x0304: + Info("Askey VC010 type 2 USB webcam detected.\n"); + name = "Askey VC010 webcam"; + type_id = 646; + break; + case 0x0307: + Info("Philips PCVC675K (Vesta) USB webcam detected.\n"); + name = "Philips 675 webcam"; + type_id = 675; + break; + case 0x0308: + Info("Philips PCVC680K (Vesta Pro) USB webcam detected.\n"); + name = "Philips 680 webcam"; + type_id = 680; + break; + case 0x030C: + Info("Philips PCVC690K (Vesta Pro Scan) USB webcam detected.\n"); + name = "Philips 690 webcam"; + type_id = 690; + break; + case 0x0310: + Info("Philips PCVC730K (ToUCam Fun)/PCVC830 (ToUCam II) USB webcam detected.\n"); + name = "Philips 730 webcam"; + type_id = 730; + break; + case 0x0311: + Info("Philips PCVC740K (ToUCam Pro)/PCVC840 (ToUCam II) USB webcam detected.\n"); + name = "Philips 740 webcam"; + type_id = 740; + break; + case 0x0312: + Info("Philips PCVC750K (ToUCam Pro Scan) USB webcam detected.\n"); + name = "Philips 750 webcam"; + type_id = 750; + break; + case 0x0313: + Info("Philips PCVC720K/40 (ToUCam XS) USB webcam detected.\n"); + name = "Philips 720K/40 webcam"; + type_id = 720; + break; + default: + return -ENODEV; + break; + } + } + else if (vendor_id == 0x069A) { + switch(product_id) { + case 0x0001: + Info("Askey VC010 type 1 USB webcam detected.\n"); + name = "Askey VC010 webcam"; + type_id = 645; + break; + default: + return -ENODEV; + break; + } + } + else if (vendor_id == 0x046d) { + switch(product_id) { + case 0x08b0: + Info("Logitech QuickCam Pro 3000 USB webcam detected.\n"); + name = "Logitech QuickCam Pro 3000"; + type_id = 740; /* CCD sensor */ + break; + case 0x08b1: + Info("Logitech QuickCam Notebook Pro USB webcam detected.\n"); + name = "Logitech QuickCam Notebook Pro"; + type_id = 740; /* CCD sensor */ + break; + case 0x08b2: + Info("Logitech QuickCam 4000 Pro USB webcam detected.\n"); + name = "Logitech QuickCam Pro 4000"; + type_id = 740; /* CCD sensor */ + break; + case 0x08b3: + Info("Logitech QuickCam Zoom USB webcam detected.\n"); + name = "Logitech QuickCam Zoom"; + type_id = 740; /* CCD sensor */ + break; + case 0x08B4: + Info("Logitech QuickCam Zoom (new model) USB webcam detected.\n"); + name = "Logitech QuickCam Zoom"; + type_id = 740; /* CCD sensor */ + break; + case 0x08b5: + Info("Logitech QuickCam Orbit/Sphere USB webcam detected.\n"); + name = "Logitech QuickCam Orbit"; + type_id = 740; /* CCD sensor */ + features |= FEATURE_MOTOR_PANTILT; + break; + case 0x08b6: + case 0x08b7: + case 0x08b8: + Info("Logitech QuickCam detected (reserved ID).\n"); + name = "Logitech QuickCam (res.)"; + type_id = 730; /* Assuming CMOS */ + break; + default: + return -ENODEV; + break; + } + } + else if (vendor_id == 0x055d) { + /* I don't know the difference between the C10 and the C30; + I suppose the difference is the sensor, but both cameras + work equally well with a type_id of 675 + */ + switch(product_id) { + case 0x9000: + Info("Samsung MPC-C10 USB webcam detected.\n"); + name = "Samsung MPC-C10"; + type_id = 675; + break; + case 0x9001: + Info("Samsung MPC-C30 USB webcam detected.\n"); + name = "Samsung MPC-C30"; + type_id = 675; + break; + default: + return -ENODEV; + break; + } + } + else if (vendor_id == 0x041e) { + switch(product_id) { + case 0x400c: + Info("Creative Labs Webcam 5 detected.\n"); + name = "Creative Labs Webcam 5"; + type_id = 730; + break; + case 0x4011: + Info("Creative Labs Webcam Pro Ex detected.\n"); + name = "Creative Labs Webcam Pro Ex"; + type_id = 740; + break; + default: + return -ENODEV; + break; + } + } + else if (vendor_id == 0x04cc) { + switch(product_id) { + case 0x8116: + Info("Sotec Afina Eye USB webcam detected.\n"); + name = "Sotec Afina Eye"; + type_id = 730; + break; + default: + return -ENODEV; + break; + } + } + else if (vendor_id == 0x06be) { + switch(product_id) { + case 0x8116: + /* This is essentially the same cam as the Sotec Afina Eye */ + Info("AME Co. Afina Eye USB webcam detected.\n"); + name = "AME Co. Afina Eye"; + type_id = 750; + break; + default: + return -ENODEV; + break; + } + + } + else if (vendor_id == 0x0d81) { + switch(product_id) { + case 0x1900: + Info("Visionite VCS-UC300 USB webcam detected.\n"); + name = "Visionite VCS-UC300"; + type_id = 740; /* CCD sensor */ + break; + case 0x1910: + Info("Visionite VCS-UM100 USB webcam detected.\n"); + name = "Visionite VCS-UM100"; + type_id = 730; /* CMOS sensor */ + break; + default: + return -ENODEV; + break; + } + } + else + return -ENODEV; /* Not any of the know types; but the list keeps growing. */ + + memset(serial_number, 0, 30); + usb_string(udev, udev->descriptor.iSerialNumber, serial_number, 29); + Trace(TRACE_PROBE, "Device serial number is %s\n", serial_number); + + if (udev->descriptor.bNumConfigurations > 1) + Info("Warning: more than 1 configuration available.\n"); + + /* Allocate structure, initialize pointers, mutexes, etc. and link it to the usb_device */ + pdev = kmalloc(sizeof(struct pwc_device), GFP_KERNEL); + if (pdev == NULL) { + Err("Oops, could not allocate memory for pwc_device.\n"); + return -ENOMEM; + } + memset(pdev, 0, sizeof(struct pwc_device)); + pdev->type = type_id; + pdev->vsize = default_size; + pdev->vframes = default_fps; + strcpy(pdev->serial, serial_number); + pdev->features = features; + if (vendor_id == 0x046D && product_id == 0x08B5) + { + /* Logitech QuickCam Orbit + The ranges have been determined experimentally; they may differ from cam to cam. + Also, the exact ranges left-right and up-down are different for my cam + */ + pdev->angle_range.pan_min = -7000; + pdev->angle_range.pan_max = 7000; + pdev->angle_range.tilt_min = -3000; + pdev->angle_range.tilt_max = 2500; + } + + init_MUTEX(&pdev->modlock); + pdev->ptrlock = SPIN_LOCK_UNLOCKED; + + pdev->udev = udev; + init_waitqueue_head(&pdev->frameq); + pdev->vcompression = pwc_preferred_compression; + + /* Allocate video_device structure */ + pdev->vdev = video_device_alloc(); + if (pdev->vdev == 0) + { + Err("Err, cannot allocate video_device struture. Failing probe."); + kfree(pdev); + return -ENOMEM; + } + memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); + strcpy(pdev->vdev->name, name); + pdev->vdev->owner = THIS_MODULE; + video_set_drvdata(pdev->vdev, pdev); + + pdev->release = udev->descriptor.bcdDevice; + Trace(TRACE_PROBE, "Release: %04x\n", pdev->release); + + /* Now search device_hint[] table for a match, so we can hint a node number. */ + for (hint = 0; hint < MAX_DEV_HINTS; hint++) { + if (((device_hint[hint].type == -1) || (device_hint[hint].type == pdev->type)) && + (device_hint[hint].pdev == NULL)) { + /* so far, so good... try serial number */ + if ((device_hint[hint].serial_number[0] == '*') || !strcmp(device_hint[hint].serial_number, serial_number)) { + /* match! */ + video_nr = device_hint[hint].device_node; + Trace(TRACE_PROBE, "Found hint, will try to register as /dev/video%d\n", video_nr); + break; + } + } + } + + pdev->vdev->release = video_device_release; + i = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr); + if (i < 0) { + Err("Failed to register as video device (%d).\n", i); + video_device_release(pdev->vdev); /* Drip... drip... drip... */ + kfree(pdev); /* Oops, no memory leaks please */ + return -EIO; + } + else { + Info("Registered as /dev/video%d.\n", pdev->vdev->minor & 0x3F); + } + + /* occupy slot */ + if (hint < MAX_DEV_HINTS) + device_hint[hint].pdev = pdev; + + Trace(TRACE_PROBE, "probe() function returning struct at 0x%p.\n", pdev); + usb_set_intfdata (intf, pdev); + return 0; +} + +/* The user janked out the cable... */ +static void usb_pwc_disconnect(struct usb_interface *intf) +{ + struct pwc_device *pdev; + int hint; + + lock_kernel(); + pdev = usb_get_intfdata (intf); + usb_set_intfdata (intf, NULL); + if (pdev == NULL) { + Err("pwc_disconnect() Called without private pointer.\n"); + goto disconnect_out; + } + if (pdev->udev == NULL) { + Err("pwc_disconnect() already called for %p\n", pdev); + goto disconnect_out; + } + if (pdev->udev != interface_to_usbdev(intf)) { + Err("pwc_disconnect() Woops: pointer mismatch udev/pdev.\n"); + goto disconnect_out; + } +#ifdef PWC_MAGIC + if (pdev->magic != PWC_MAGIC) { + Err("pwc_disconnect() Magic number failed. Consult your scrolls and try again.\n"); + goto disconnect_out; + } +#endif + + /* We got unplugged; this is signalled by an EPIPE error code */ + if (pdev->vopen) { + Info("Disconnected while webcam is in use!\n"); + pdev->error_status = EPIPE; + } + + /* Alert waiting processes */ + wake_up_interruptible(&pdev->frameq); + /* Wait until device is closed */ + while (pdev->vopen) + schedule(); + /* Device is now closed, so we can safely unregister it */ + Trace(TRACE_PROBE, "Unregistering video device in disconnect().\n"); + video_unregister_device(pdev->vdev); + + /* Free memory (don't set pdev to 0 just yet) */ + kfree(pdev); + +disconnect_out: + /* search device_hint[] table if we occupy a slot, by any chance */ + for (hint = 0; hint < MAX_DEV_HINTS; hint++) + if (device_hint[hint].pdev == pdev) + device_hint[hint].pdev = NULL; + + unlock_kernel(); +} + + +/* *grunt* We have to do atoi ourselves :-( */ +static int pwc_atoi(const char *s) +{ + int k = 0; + + k = 0; + while (*s != '\0' && *s >= '0' && *s <= '9') { + k = 10 * k + (*s - '0'); + s++; + } + return k; +} + + +/* + * Initialization code & module stuff + */ + +static char *size = NULL; +static int fps = 0; +static int fbufs = 0; +static int mbufs = 0; +static int trace = -1; +static int compression = -1; +static int leds[2] = { -1, -1 }; +static char *dev_hint[MAX_DEV_HINTS] = { }; + +MODULE_PARM(size, "s"); +MODULE_PARM_DESC(size, "Initial image size. One of sqcif, qsif, qcif, sif, cif, vga"); +MODULE_PARM(fps, "i"); +MODULE_PARM_DESC(fps, "Initial frames per second. Varies with model, useful range 5-30"); +MODULE_PARM(fbufs, "i"); +MODULE_PARM_DESC(fbufs, "Number of internal frame buffers to reserve"); +MODULE_PARM(mbufs, "i"); +MODULE_PARM_DESC(mbufs, "Number of external (mmap()ed) image buffers"); +MODULE_PARM(trace, "i"); +MODULE_PARM_DESC(trace, "For debugging purposes"); +MODULE_PARM(power_save, "i"); +MODULE_PARM_DESC(power_save, "Turn power save feature in camera on or off"); +MODULE_PARM(compression, "i"); +MODULE_PARM_DESC(compression, "Preferred compression quality. Range 0 (uncompressed) to 3 (high compression)"); +MODULE_PARM(leds, "2i"); +MODULE_PARM_DESC(leds, "LED on,off time in milliseconds"); +MODULE_PARM(dev_hint, "0-20s"); +MODULE_PARM_DESC(dev_hint, "Device node hints"); + +MODULE_DESCRIPTION("Philips & OEM USB webcam driver"); +MODULE_AUTHOR("Luc Saillard "); +MODULE_LICENSE("GPL"); + +static int __init usb_pwc_init(void) +{ + int i, sz; + char *sizenames[PSZ_MAX] = { "sqcif", "qsif", "qcif", "sif", "cif", "vga" }; + + Info("Philips webcam module version " PWC_VERSION " loaded.\n"); + Info("Supports Philips PCA645/646, PCVC675/680/690, PCVC720[40]/730/740/750 & PCVC830/840.\n"); + Info("Also supports the Askey VC010, various Logitech Quickcams, Samsung MPC-C10 and MPC-C30,\n"); + Info("the Creative WebCam 5 & Pro Ex, SOTEC Afina Eye and Visionite VCS-UC300 and VCS-UM100.\n"); + + if (fps) { + if (fps < 4 || fps > 30) { + Err("Framerate out of bounds (4-30).\n"); + return -EINVAL; + } + default_fps = fps; + Info("Default framerate set to %d.\n", default_fps); + } + + if (size) { + /* string; try matching with array */ + for (sz = 0; sz < PSZ_MAX; sz++) { + if (!strcmp(sizenames[sz], size)) { /* Found! */ + default_size = sz; + break; + } + } + if (sz == PSZ_MAX) { + Err("Size not recognized; try size=[sqcif | qsif | qcif | sif | cif | vga].\n"); + return -EINVAL; + } + Info("Default image size set to %s [%dx%d].\n", sizenames[default_size], pwc_image_sizes[default_size].x, pwc_image_sizes[default_size].y); + } + if (mbufs) { + if (mbufs < 1 || mbufs > MAX_IMAGES) { + Err("Illegal number of mmap() buffers; use a number between 1 and %d.\n", MAX_IMAGES); + return -EINVAL; + } + default_mbufs = mbufs; + Info("Number of image buffers set to %d.\n", default_mbufs); + } + if (fbufs) { + if (fbufs < 2 || fbufs > MAX_FRAMES) { + Err("Illegal number of frame buffers; use a number between 2 and %d.\n", MAX_FRAMES); + return -EINVAL; + } + default_fbufs = fbufs; + Info("Number of frame buffers set to %d.\n", default_fbufs); + } + if (trace >= 0) { + Info("Trace options: 0x%04x\n", trace); + pwc_trace = trace; + } + if (compression >= 0) { + if (compression > 3) { + Err("Invalid compression setting; use a number between 0 (uncompressed) and 3 (high).\n"); + return -EINVAL; + } + pwc_preferred_compression = compression; + Info("Preferred compression set to %d.\n", pwc_preferred_compression); + } + if (power_save) + Info("Enabling power save on open/close.\n"); + if (leds[0] >= 0) + led_on = leds[0]; + if (leds[1] >= 0) + led_off = leds[1]; + + /* Big device node whoopla. Basicly, it allows you to assign a + device node (/dev/videoX) to a camera, based on its type + & serial number. The format is [type[.serialnumber]:]node. + + Any camera that isn't matched by these rules gets the next + available free device node. + */ + for (i = 0; i < MAX_DEV_HINTS; i++) { + char *s, *colon, *dot; + + /* This loop also initializes the array */ + device_hint[i].pdev = NULL; + s = dev_hint[i]; + if (s != NULL && *s != '\0') { + device_hint[i].type = -1; /* wildcard */ + strcpy(device_hint[i].serial_number, "*"); + + /* parse string: chop at ':' & '/' */ + colon = dot = s; + while (*colon != '\0' && *colon != ':') + colon++; + while (*dot != '\0' && *dot != '.') + dot++; + /* Few sanity checks */ + if (*dot != '\0' && dot > colon) { + Err("Malformed camera hint: the colon must be after the dot.\n"); + return -EINVAL; + } + + if (*colon == '\0') { + /* No colon */ + if (*dot != '\0') { + Err("Malformed camera hint: no colon + device node given.\n"); + return -EINVAL; + } + else { + /* No type or serial number specified, just a number. */ + device_hint[i].device_node = pwc_atoi(s); + } + } + else { + /* There's a colon, so we have at least a type and a device node */ + device_hint[i].type = pwc_atoi(s); + device_hint[i].device_node = pwc_atoi(colon + 1); + if (*dot != '\0') { + /* There's a serial number as well */ + int k; + + dot++; + k = 0; + while (*dot != ':' && k < 29) { + device_hint[i].serial_number[k++] = *dot; + dot++; + } + device_hint[i].serial_number[k] = '\0'; + } + } +#if PWC_DEBUG + Debug("device_hint[%d]:\n", i); + Debug(" type : %d\n", device_hint[i].type); + Debug(" serial# : %s\n", device_hint[i].serial_number); + Debug(" node : %d\n", device_hint[i].device_node); +#endif + } + else + device_hint[i].type = 0; /* not filled */ + } /* ..for MAX_DEV_HINTS */ + + Trace(TRACE_PROBE, "Registering driver at address 0x%p.\n", &pwc_driver); + return usb_register(&pwc_driver); +} + +static void __exit usb_pwc_exit(void) +{ + Trace(TRACE_MODULE, "Deregistering driver.\n"); + usb_deregister(&pwc_driver); + Info("Philips webcam module removed.\n"); +} + +module_init(usb_pwc_init); +module_exit(usb_pwc_exit); + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-ioctl.h linux-2.6.11/drivers/usb/media/pwc/pwc-ioctl.h --- linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-ioctl.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.11/drivers/usb/media/pwc/pwc-ioctl.h 2005-03-05 15:26:35.000000000 +0000 @@ -0,0 +1,292 @@ +#ifndef PWC_IOCTL_H +#define PWC_IOCTL_H + +/* (C) 2001-2004 Nemosoft Unv. + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* This is pwc-ioctl.h belonging to PWC 8.12.1 + It contains structures and defines to communicate from user space + directly to the driver. + */ + +/* + Changes + 2001/08/03 Alvarado Added ioctl constants to access methods for + changing white balance and red/blue gains + 2002/12/15 G. H. Fernandez-Toribio VIDIOCGREALSIZE + 2003/12/13 Nemosft Unv. Some modifications to make interfacing to + PWCX easier + */ + +/* These are private ioctl() commands, specific for the Philips webcams. + They contain functions not found in other webcams, and settings not + specified in the Video4Linux API. + + The #define names are built up like follows: + VIDIOC VIDeo IOCtl prefix + PWC Philps WebCam + G optional: Get + S optional: Set + ... the function + */ + + + /* Enumeration of image sizes */ +#define PSZ_SQCIF 0x00 +#define PSZ_QSIF 0x01 +#define PSZ_QCIF 0x02 +#define PSZ_SIF 0x03 +#define PSZ_CIF 0x04 +#define PSZ_VGA 0x05 +#define PSZ_MAX 6 + + +/* The frame rate is encoded in the video_window.flags parameter using + the upper 16 bits, since some flags are defined nowadays. The following + defines provide a mask and shift to filter out this value. + + In 'Snapshot' mode the camera freezes its automatic exposure and colour + balance controls. + */ +#define PWC_FPS_SHIFT 16 +#define PWC_FPS_MASK 0x00FF0000 +#define PWC_FPS_FRMASK 0x003F0000 +#define PWC_FPS_SNAPSHOT 0x00400000 + + +/* structure for transfering x & y coordinates */ +struct pwc_coord +{ + int x, y; /* guess what */ + int size; /* size, or offset */ +}; + + +/* Used with VIDIOCPWCPROBE */ +struct pwc_probe +{ + char name[32]; + int type; +}; + +struct pwc_serial +{ + char serial[30]; /* String with serial number. Contains terminating 0 */ +}; + +/* pwc_whitebalance.mode values */ +#define PWC_WB_INDOOR 0 +#define PWC_WB_OUTDOOR 1 +#define PWC_WB_FL 2 +#define PWC_WB_MANUAL 3 +#define PWC_WB_AUTO 4 + +/* Used with VIDIOCPWC[SG]AWB (Auto White Balance). + Set mode to one of the PWC_WB_* values above. + *red and *blue are the respective gains of these colour components inside + the camera; range 0..65535 + When 'mode' == PWC_WB_MANUAL, 'manual_red' and 'manual_blue' are set or read; + otherwise undefined. + 'read_red' and 'read_blue' are read-only. +*/ +struct pwc_whitebalance +{ + int mode; + int manual_red, manual_blue; /* R/W */ + int read_red, read_blue; /* R/O */ +}; + +/* + 'control_speed' and 'control_delay' are used in automatic whitebalance mode, + and tell the camera how fast it should react to changes in lighting, and + with how much delay. Valid values are 0..65535. +*/ +struct pwc_wb_speed +{ + int control_speed; + int control_delay; + +}; + +/* Used with VIDIOCPWC[SG]LED */ +struct pwc_leds +{ + int led_on; /* Led on-time; range = 0..25000 */ + int led_off; /* Led off-time; range = 0..25000 */ +}; + +/* Image size (used with GREALSIZE) */ +struct pwc_imagesize +{ + int width; + int height; +}; + +/* Defines and structures for Motorized Pan & Tilt */ +#define PWC_MPT_PAN 0x01 +#define PWC_MPT_TILT 0x02 +#define PWC_MPT_TIMEOUT 0x04 /* for status */ + +/* Set angles; when absolute != 0, the angle is absolute and the + driver calculates the relative offset for you. This can only + be used with VIDIOCPWCSANGLE; VIDIOCPWCGANGLE always returns + absolute angles. + */ +struct pwc_mpt_angles +{ + int absolute; /* write-only */ + int pan; /* degrees * 100 */ + int tilt; /* degress * 100 */ +}; + +/* Range of angles of the camera, both horizontally and vertically. + */ +struct pwc_mpt_range +{ + int pan_min, pan_max; /* degrees * 100 */ + int tilt_min, tilt_max; +}; + +struct pwc_mpt_status +{ + int status; + int time_pan; + int time_tilt; +}; + + +/* This is used for out-of-kernel decompression. With it, you can get + all the necessary information to initialize and use the decompressor + routines in standalone applications. + */ +struct pwc_video_command +{ + int type; /* camera type (645, 675, 730, etc.) */ + int release; /* release number */ + + int size; /* one of PSZ_* */ + int alternate; + int command_len; /* length of USB video command */ + unsigned char command_buf[13]; /* Actual USB video command */ + int bandlength; /* >0 = compressed */ + int frame_size; /* Size of one (un)compressed frame */ +}; + +/* Flags for PWCX subroutines. Not all modules honour all flags. */ +#define PWCX_FLAG_PLANAR 0x0001 +#define PWCX_FLAG_BAYER 0x0008 + + +/* IOCTL definitions */ + + /* Restore user settings */ +#define VIDIOCPWCRUSER _IO('v', 192) + /* Save user settings */ +#define VIDIOCPWCSUSER _IO('v', 193) + /* Restore factory settings */ +#define VIDIOCPWCFACTORY _IO('v', 194) + + /* You can manipulate the compression factor. A compression preference of 0 + means use uncompressed modes when available; 1 is low compression, 2 is + medium and 3 is high compression preferred. Of course, the higher the + compression, the lower the bandwidth used but more chance of artefacts + in the image. The driver automatically chooses a higher compression when + the preferred mode is not available. + */ + /* Set preferred compression quality (0 = uncompressed, 3 = highest compression) */ +#define VIDIOCPWCSCQUAL _IOW('v', 195, int) + /* Get preferred compression quality */ +#define VIDIOCPWCGCQUAL _IOR('v', 195, int) + + +/* Retrieve serial number of camera */ +#define VIDIOCPWCGSERIAL _IOR('v', 198, struct pwc_serial) + + /* This is a probe function; since so many devices are supported, it + becomes difficult to include all the names in programs that want to + check for the enhanced Philips stuff. So in stead, try this PROBE; + it returns a structure with the original name, and the corresponding + Philips type. + To use, fill the structure with zeroes, call PROBE and if that succeeds, + compare the name with that returned from VIDIOCGCAP; they should be the + same. If so, you can be assured it is a Philips (OEM) cam and the type + is valid. + */ +#define VIDIOCPWCPROBE _IOR('v', 199, struct pwc_probe) + + /* Set AGC (Automatic Gain Control); int < 0 = auto, 0..65535 = fixed */ +#define VIDIOCPWCSAGC _IOW('v', 200, int) + /* Get AGC; int < 0 = auto; >= 0 = fixed, range 0..65535 */ +#define VIDIOCPWCGAGC _IOR('v', 200, int) + /* Set shutter speed; int < 0 = auto; >= 0 = fixed, range 0..65535 */ +#define VIDIOCPWCSSHUTTER _IOW('v', 201, int) + + /* Color compensation (Auto White Balance) */ +#define VIDIOCPWCSAWB _IOW('v', 202, struct pwc_whitebalance) +#define VIDIOCPWCGAWB _IOR('v', 202, struct pwc_whitebalance) + + /* Auto WB speed */ +#define VIDIOCPWCSAWBSPEED _IOW('v', 203, struct pwc_wb_speed) +#define VIDIOCPWCGAWBSPEED _IOR('v', 203, struct pwc_wb_speed) + + /* LEDs on/off/blink; int range 0..65535 */ +#define VIDIOCPWCSLED _IOW('v', 205, struct pwc_leds) +#define VIDIOCPWCGLED _IOR('v', 205, struct pwc_leds) + + /* Contour (sharpness); int < 0 = auto, 0..65536 = fixed */ +#define VIDIOCPWCSCONTOUR _IOW('v', 206, int) +#define VIDIOCPWCGCONTOUR _IOR('v', 206, int) + + /* Backlight compensation; 0 = off, otherwise on */ +#define VIDIOCPWCSBACKLIGHT _IOW('v', 207, int) +#define VIDIOCPWCGBACKLIGHT _IOR('v', 207, int) + + /* Flickerless mode; = 0 off, otherwise on */ +#define VIDIOCPWCSFLICKER _IOW('v', 208, int) +#define VIDIOCPWCGFLICKER _IOR('v', 208, int) + + /* Dynamic noise reduction; 0 off, 3 = high noise reduction */ +#define VIDIOCPWCSDYNNOISE _IOW('v', 209, int) +#define VIDIOCPWCGDYNNOISE _IOR('v', 209, int) + + /* Real image size as used by the camera; tells you whether or not there's a gray border around the image */ +#define VIDIOCPWCGREALSIZE _IOR('v', 210, struct pwc_imagesize) + + /* Motorized pan & tilt functions */ +#define VIDIOCPWCMPTRESET _IOW('v', 211, int) +#define VIDIOCPWCMPTGRANGE _IOR('v', 211, struct pwc_mpt_range) +#define VIDIOCPWCMPTSANGLE _IOW('v', 212, struct pwc_mpt_angles) +#define VIDIOCPWCMPTGANGLE _IOR('v', 212, struct pwc_mpt_angles) +#define VIDIOCPWCMPTSTATUS _IOR('v', 213, struct pwc_mpt_status) + + /* Get the USB set-video command; needed for initializing libpwcx */ +#define VIDIOCPWCGVIDCMD _IOR('v', 215, struct pwc_video_command) +struct pwc_table_init_buffer { + int len; + char *buffer; + +}; +#define VIDIOCPWCGVIDTABLE _IOR('v', 216, struct pwc_table_init_buffer) + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-kiara.c linux-2.6.11/drivers/usb/media/pwc/pwc-kiara.c --- linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-kiara.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.11/drivers/usb/media/pwc/pwc-kiara.c 2005-03-05 15:26:35.000000000 +0000 @@ -0,0 +1,891 @@ +/* Linux driver for Philips webcam + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +/* This tables contains entries for the 730/740/750 (Kiara) camera, with + 4 different qualities (no compression, low, medium, high). + It lists the bandwidth requirements for said mode by its alternate interface + number. An alternate of 0 means that the mode is unavailable. + + There are 6 * 4 * 4 entries: + 6 different resolutions subqcif, qsif, qcif, sif, cif, vga + 6 framerates: 5, 10, 15, 20, 25, 30 + 4 compression modi: none, low, medium, high + + When an uncompressed mode is not available, the next available compressed mode + will be chosen (unless the decompressor is absent). Sometimes there are only + 1 or 2 compressed modes available; in that case entries are duplicated. +*/ + + +#include "pwc-kiara.h" +#include "pwc-uncompress.h" + +const struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4] = +{ + /* SQCIF */ + { + /* 5 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 10 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 15 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 20 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 25 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 30 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + }, + /* QSIF */ + { + /* 5 fps */ + { + {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, + {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, + {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, + {1, 146, 0, {0x1D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0x00, 0x80}}, + }, + /* 10 fps */ + { + {2, 291, 0, {0x1C, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0x01, 0x80}}, + {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, + {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, + {1, 192, 630, {0x14, 0xF4, 0x30, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xC0, 0x00, 0x80}}, + }, + /* 15 fps */ + { + {3, 437, 0, {0x1B, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x01, 0x80}}, + {2, 292, 640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}}, + {2, 292, 640, {0x13, 0xF4, 0x30, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x20, 0x24, 0x01, 0x80}}, + {1, 192, 420, {0x13, 0xF4, 0x30, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x18, 0xC0, 0x00, 0x80}}, + }, + /* 20 fps */ + { + {4, 589, 0, {0x1A, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4D, 0x02, 0x80}}, + {3, 448, 730, {0x12, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xC0, 0x01, 0x80}}, + {2, 292, 476, {0x12, 0xF4, 0x30, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0x01, 0x80}}, + {1, 192, 312, {0x12, 0xF4, 0x50, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0x00, 0x80}}, + }, + /* 25 fps */ + { + {5, 703, 0, {0x19, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x02, 0x80}}, + {3, 447, 610, {0x11, 0xF4, 0x30, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x28, 0xBF, 0x01, 0x80}}, + {2, 292, 398, {0x11, 0xF4, 0x50, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x28, 0x24, 0x01, 0x80}}, + {1, 193, 262, {0x11, 0xF4, 0x50, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x28, 0xC1, 0x00, 0x80}}, + }, + /* 30 fps */ + { + {8, 874, 0, {0x18, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x6A, 0x03, 0x80}}, + {5, 704, 730, {0x10, 0xF4, 0x30, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x28, 0xC0, 0x02, 0x80}}, + {3, 448, 492, {0x10, 0xF4, 0x30, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x28, 0xC0, 0x01, 0x80}}, + {2, 292, 320, {0x10, 0xF4, 0x50, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x28, 0x24, 0x01, 0x80}}, + }, + }, + /* QCIF */ + { + /* 5 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 10 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 15 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 20 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 25 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 30 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + }, + /* SIF */ + { + /* 5 fps */ + { + {4, 582, 0, {0x0D, 0xF4, 0x30, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x02, 0x80}}, + {3, 387, 1276, {0x05, 0xF4, 0x30, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x01, 0x80}}, + {2, 291, 960, {0x05, 0xF4, 0x30, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0x01, 0x80}}, + {1, 191, 630, {0x05, 0xF4, 0x50, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x18, 0xBF, 0x00, 0x80}}, + }, + /* 10 fps */ + { + {0, }, + {6, 775, 1278, {0x04, 0xF4, 0x30, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x03, 0x80}}, + {3, 447, 736, {0x04, 0xF4, 0x30, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x28, 0xBF, 0x01, 0x80}}, + {2, 292, 480, {0x04, 0xF4, 0x70, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x28, 0x24, 0x01, 0x80}}, + }, + /* 15 fps */ + { + {0, }, + {9, 955, 1050, {0x03, 0xF4, 0x30, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x03, 0x80}}, + {4, 592, 650, {0x03, 0xF4, 0x30, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x50, 0x02, 0x80}}, + {3, 448, 492, {0x03, 0xF4, 0x50, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x38, 0xC0, 0x01, 0x80}}, + }, + /* 20 fps */ + { + {0, }, + {9, 958, 782, {0x02, 0xF4, 0x30, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x03, 0x80}}, + {5, 703, 574, {0x02, 0xF4, 0x50, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x02, 0x80}}, + {3, 446, 364, {0x02, 0xF4, 0x90, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x38, 0xBE, 0x01, 0x80}}, + }, + /* 25 fps */ + { + {0, }, + {9, 958, 654, {0x01, 0xF4, 0x30, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x03, 0x80}}, + {6, 776, 530, {0x01, 0xF4, 0x50, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x03, 0x80}}, + {4, 592, 404, {0x01, 0xF4, 0x70, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x48, 0x50, 0x02, 0x80}}, + }, + /* 30 fps */ + { + {0, }, + {9, 957, 526, {0x00, 0xF4, 0x50, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x03, 0x80}}, + {6, 775, 426, {0x00, 0xF4, 0x70, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x03, 0x80}}, + {4, 590, 324, {0x00, 0x7A, 0x88, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x50, 0x4E, 0x02, 0x80}}, + }, + }, + /* CIF */ + { + /* 5 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 10 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 15 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 20 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 25 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 30 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + }, + /* VGA */ + { + /* 5 fps */ + { + {0, }, + {6, 773, 1272, {0x25, 0xF4, 0x30, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x03, 0x80}}, + {4, 592, 976, {0x25, 0xF4, 0x50, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x02, 0x80}}, + {3, 448, 738, {0x25, 0xF4, 0x90, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x01, 0x80}}, + }, + /* 10 fps */ + { + {0, }, + {9, 956, 788, {0x24, 0xF4, 0x70, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x03, 0x80}}, + {6, 776, 640, {0x24, 0xF4, 0xB0, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x03, 0x80}}, + {4, 592, 488, {0x24, 0x7A, 0xE8, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x02, 0x80}}, + }, + /* 15 fps */ + { + {0, }, + {9, 957, 526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}}, + {9, 957, 526, {0x23, 0x7A, 0xE8, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x03, 0x80}}, + {8, 895, 492, {0x23, 0x7A, 0xE8, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x03, 0x80}}, + }, + /* 20 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 25 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 30 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + }, +}; + + +/* + * Rom table for kiara chips + * + * 32 roms tables (one for each resolution ?) + * 2 tables per roms (one for each passes) (Y, and U&V) + * 128 bytes per passes + */ + +const unsigned int KiaraRomTable [8][2][16][8] = +{ + { /* version 0 */ + { /* version 0, passes 0 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000001,0x00000001}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000009,0x00000009,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00000009,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000249,0x0000024a,0x00000049}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000249,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000249, + 0x00000249,0x0000124a,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000249, + 0x0000124a,0x00009252,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00009252,0x00009292,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009292,0x00009292,0x00009493,0x000124db}, + {0x00000000,0x00000000,0x00000249,0x0000924a, + 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x0000a493,0x000124db,0x000124db,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x000124db,0x000126dc,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000124db,0x000136e4,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b925,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 0, passes 1 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000}, + {0x00000000,0x00000000,0x00000001,0x00000009, + 0x00000009,0x00000009,0x00000009,0x00000001}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000249,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00001252}, + {0x00000000,0x00000000,0x00000049,0x00001249, + 0x0000124a,0x0000124a,0x00001252,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009252,0x00009252,0x00009292,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x0000924a, + 0x00009292,0x00009292,0x00009292,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x00009292, + 0x00009492,0x00009493,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x0000a493,0x000124db,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00009252,0x00009493, + 0x000126dc,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000136e4,0x000136e4,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 1 */ + { /* version 1, passes 0 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000001}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000009,0x00000009,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00001252}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x0000124a,0x00009252,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009252,0x00009292,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009252,0x00009292,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x0000924a, + 0x00009252,0x00009493,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x0000924a, + 0x00009292,0x00009493,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x00009252, + 0x00009492,0x00009493,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x000124db,0x000124db,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000126dc,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 1, passes 1 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000}, + {0x00000000,0x00000000,0x00000049,0x00000009, + 0x00000049,0x00000009,0x00000001,0x00000000}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000000}, + {0x00000000,0x00000000,0x00000249,0x00000049, + 0x00000249,0x00000049,0x0000024a,0x00000001}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00000001}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00000001}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x0000024a,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x0000024a,0x00000009}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x00009252,0x00001252,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x00009292,0x00001252,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x00009292,0x00001252,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009292,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x0000924a,0x0000924a, + 0x00009492,0x00009493,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 2 */ + { /* version 2, passes 0 */ + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x0000124a,0x00001252,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x00009252,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x0000124a,0x00009292,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009252,0x00009493,0x00009493,0x0000a49b}, + {0x00000000,0x00000000,0x00000249,0x0000924a, + 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009292,0x00009493,0x0000a49b,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x000124db,0x000124db,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x0000a493,0x000124db,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x000136e4}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0001249b,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000136e4,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x00009252,0x000124db, + 0x000126dc,0x0001b724,0x0001b725,0x0001b925}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 2, passes 1 */ + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00000249, + 0x0000124a,0x0000124a,0x00001252,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x00009292,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009292,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x0000a49b,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009493,0x0000a49b,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009493,0x0000a49b,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x0000a49b,0x0000a49b,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x00009252,0x0000a49b, + 0x0001249b,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 3 */ + { /* version 3, passes 0 */ + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x000124db,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000126dc,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000136e4,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000136e4,0x0001b725,0x0001b925}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x000136e4,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x000136e4,0x0001b925,0x00025bb6,0x00024b77}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 3, passes 1 */ + {0x00000000,0x00000000,0x00001249,0x00000249, + 0x0000124a,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x00009493,0x0000a49b,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x0000a49b,0x000126dc,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x000126dc,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x000126dc,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00009492,0x0000a49b, + 0x000136e4,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x0001b724,0x0001b724,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 4 */ + { /* version 4, passes 0 */ + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000249,0x00000049, + 0x00000249,0x00000249,0x0000024a,0x00000049}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x00009252,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009493,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009292,0x00009493,0x00009493,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000124db,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0001249b,0x000126dc,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00009252,0x00009493, + 0x000124db,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009252,0x0000a49b, + 0x000124db,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00009492,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x000136e4,0x0001b925,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 4, passes 1 */ + {0x00000000,0x00000000,0x00000249,0x00000049, + 0x00000009,0x00000009,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000049,0x00000049,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x00000249,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x0000124a,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009252,0x0000124a,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x00009252,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x00009292,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x00009292,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x00009493,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000124db,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009252,0x000124db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 5 */ + { /* version 5, passes 0 */ + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x0000a49b,0x000124db,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000126dc,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b725,0x000136e4}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, + {0x00000000,0x00000000,0x00009492,0x0000a49b, + 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b925,0x0001c96e,0x0001b925}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001c924,0x0002496d,0x00025bb6,0x00024b77}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 5, passes 1 */ + {0x00000000,0x00000000,0x00001249,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009252,0x00009252,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x0000a49b,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000124db,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000124db,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x000126dc,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009292,0x000124db, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 6 */ + { /* version 6, passes 0 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000126dc,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b725,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000136e4,0x0001b724,0x0001b92d,0x000136e4}, + {0x00000000,0x00000000,0x00009492,0x0000a49b, + 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b925,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x0001b724,0x0001c92d,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x0001b724,0x0001c92d,0x00024b76,0x0002496e}, + {0x00000000,0x00000000,0x00012492,0x000126db, + 0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 6, passes 1 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x00009252,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x00009292,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x0000a49b,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000124db,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x000126dc,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001c924,0x0001b724,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 7 */ + { /* version 7, passes 0 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x0000a49b, + 0x0001249b,0x000126dc,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000136e4,0x0001b725,0x000124db}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000136e4,0x0001b724,0x0001b725,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x000124db, + 0x000136e4,0x0001b724,0x0001b725,0x000126dc}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b724,0x0001c96e,0x000136e4}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x0001b724,0x0001c92d,0x0001c96e,0x0001b925}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001b924,0x0001c92d,0x00024b76,0x0002496e}, + {0x00000000,0x00000000,0x00012492,0x000136db, + 0x00024924,0x00024b6d,0x0002ddb6,0x00025bbf}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 7, passes 1 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x00009492,0x00009292,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x0000a49b,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x000124db,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000136db, + 0x0001b724,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000136db, + 0x0001b724,0x000126dc,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00009292,0x000136db, + 0x0001b724,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009492,0x000136db, + 0x0001b724,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00012492,0x0001b6db, + 0x0001c924,0x0001b724,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + } +}; + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-kiara.h linux-2.6.11/drivers/usb/media/pwc/pwc-kiara.h --- linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-kiara.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.11/drivers/usb/media/pwc/pwc-kiara.h 2005-03-05 15:26:35.000000000 +0000 @@ -0,0 +1,45 @@ +/* Linux driver for Philips webcam + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* Entries for the Kiara (730/740/750) camera */ + +#ifndef PWC_KIARA_H +#define PWC_KIARA_H + +#include "pwc-ioctl.h" + +struct Kiara_table_entry +{ + char alternate; /* USB alternate interface */ + unsigned short packetsize; /* Normal packet size */ + unsigned short bandlength; /* Bandlength when decompressing */ + unsigned char mode[12]; /* precomputed mode settings for cam */ +}; + +const extern struct Kiara_table_entry Kiara_table[PSZ_MAX][6][4]; +const extern unsigned int KiaraRomTable[8][2][16][8]; + +#endif + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-misc.c linux-2.6.11/drivers/usb/media/pwc/pwc-misc.c --- linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-misc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.11/drivers/usb/media/pwc/pwc-misc.c 2005-03-05 15:26:35.000000000 +0000 @@ -0,0 +1,140 @@ +/* Linux driver for Philips webcam + Various miscellaneous functions and tables. + (C) 1999-2003 Nemosoft Unv. + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include + +#include "pwc.h" + +struct pwc_coord pwc_image_sizes[PSZ_MAX] = +{ + { 128, 96, 0 }, + { 160, 120, 0 }, + { 176, 144, 0 }, + { 320, 240, 0 }, + { 352, 288, 0 }, + { 640, 480, 0 }, +}; + +/* x,y -> PSZ_ */ +int pwc_decode_size(struct pwc_device *pdev, int width, int height) +{ + int i, find; + + /* Make sure we don't go beyond our max size. + NB: we have different limits for RAW and normal modes. In case + you don't have the decompressor loaded or use RAW mode, + the maximum viewable size is smaller. + */ + if (pdev->vpalette == VIDEO_PALETTE_RAW) + { + if (width > pdev->abs_max.x || height > pdev->abs_max.y) + { + Debug("VIDEO_PALETTE_RAW: going beyond abs_max.\n"); + return -1; + } + } + else + { + if (width > pdev->view_max.x || height > pdev->view_max.y) + { + Debug("VIDEO_PALETTE_ not RAW: going beyond view_max.\n"); + return -1; + } + } + + /* Find the largest size supported by the camera that fits into the + requested size. + */ + find = -1; + for (i = 0; i < PSZ_MAX; i++) { + if (pdev->image_mask & (1 << i)) { + if (pwc_image_sizes[i].x <= width && pwc_image_sizes[i].y <= height) + find = i; + } + } + return find; +} + +/* initialize variables depending on type and decompressor*/ +void pwc_construct(struct pwc_device *pdev) +{ + switch(pdev->type) { + case 645: + case 646: + pdev->view_min.x = 128; + pdev->view_min.y = 96; + pdev->view_max.x = 352; + pdev->view_max.y = 288; + pdev->abs_max.x = 352; + pdev->abs_max.y = 288; + pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QCIF | 1 << PSZ_CIF; + pdev->vcinterface = 2; + pdev->vendpoint = 4; + pdev->frame_header_size = 0; + pdev->frame_trailer_size = 0; + break; + case 675: + case 680: + case 690: + pdev->view_min.x = 128; + pdev->view_min.y = 96; + /* Anthill bug #38: PWC always reports max size, even without PWCX */ + pdev->view_max.x = 640; + pdev->view_max.y = 480; + pdev->image_mask = 1 << PSZ_SQCIF | 1 << PSZ_QSIF | 1 << PSZ_QCIF | 1 << PSZ_SIF | 1 << PSZ_CIF | 1 << PSZ_VGA; + pdev->abs_max.x = 640; + pdev->abs_max.y = 480; + pdev->vcinterface = 3; + pdev->vendpoint = 4; + pdev->frame_header_size = 0; + pdev->frame_trailer_size = 0; + break; + case 720: + case 730: + case 740: + case 750: + pdev->view_min.x = 160; + pdev->view_min.y = 120; + pdev->view_max.x = 640; + pdev->view_max.y = 480; + pdev->image_mask = 1 << PSZ_QSIF | 1 << PSZ_SIF | 1 << PSZ_VGA; + pdev->abs_max.x = 640; + pdev->abs_max.y = 480; + pdev->vcinterface = 3; + pdev->vendpoint = 5; + pdev->frame_header_size = TOUCAM_HEADER_SIZE; + pdev->frame_trailer_size = TOUCAM_TRAILER_SIZE; + break; + } + Debug("type = %d\n",pdev->type); + pdev->vpalette = VIDEO_PALETTE_YUV420P; /* default */ + pdev->view_min.size = pdev->view_min.x * pdev->view_min.y; + pdev->view_max.size = pdev->view_max.x * pdev->view_max.y; + /* length of image, in YUV format; always allocate enough memory. */ + pdev->len_per_image = (pdev->abs_max.x * pdev->abs_max.y * 3) / 2; +} + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-nala.h linux-2.6.11/drivers/usb/media/pwc/pwc-nala.h --- linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-nala.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.11/drivers/usb/media/pwc/pwc-nala.h 2005-03-05 15:26:35.000000000 +0000 @@ -0,0 +1,66 @@ + /* SQCIF */ + { + {0, 0, {0x04, 0x01, 0x03}}, + {8, 0, {0x05, 0x01, 0x03}}, + {7, 0, {0x08, 0x01, 0x03}}, + {7, 0, {0x0A, 0x01, 0x03}}, + {6, 0, {0x0C, 0x01, 0x03}}, + {5, 0, {0x0F, 0x01, 0x03}}, + {4, 0, {0x14, 0x01, 0x03}}, + {3, 0, {0x18, 0x01, 0x03}}, + }, + /* QSIF */ + { + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + }, + /* QCIF */ + { + {0, 0, {0x04, 0x01, 0x02}}, + {8, 0, {0x05, 0x01, 0x02}}, + {7, 0, {0x08, 0x01, 0x02}}, + {6, 0, {0x0A, 0x01, 0x02}}, + {5, 0, {0x0C, 0x01, 0x02}}, + {4, 0, {0x0F, 0x01, 0x02}}, + {1, 0, {0x14, 0x01, 0x02}}, + {1, 0, {0x18, 0x01, 0x02}}, + }, + /* SIF */ + { + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + }, + /* CIF */ + { + {4, 0, {0x04, 0x01, 0x01}}, + {7, 1, {0x05, 0x03, 0x01}}, + {6, 1, {0x08, 0x03, 0x01}}, + {4, 1, {0x0A, 0x03, 0x01}}, + {3, 1, {0x0C, 0x03, 0x01}}, + {2, 1, {0x0F, 0x03, 0x01}}, + {0}, + {0}, + }, + /* VGA */ + { + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + {0}, + }, diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-timon.c linux-2.6.11/drivers/usb/media/pwc/pwc-timon.c --- linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-timon.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.11/drivers/usb/media/pwc/pwc-timon.c 2005-03-05 15:26:35.000000000 +0000 @@ -0,0 +1,1446 @@ +/* Linux driver for Philips webcam + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +/* This tables contains entries for the 675/680/690 (Timon) camera, with + 4 different qualities (no compression, low, medium, high). + It lists the bandwidth requirements for said mode by its alternate interface + number. An alternate of 0 means that the mode is unavailable. + + There are 6 * 4 * 4 entries: + 6 different resolutions subqcif, qsif, qcif, sif, cif, vga + 6 framerates: 5, 10, 15, 20, 25, 30 + 4 compression modi: none, low, medium, high + + When an uncompressed mode is not available, the next available compressed mode + will be chosen (unless the decompressor is absent). Sometimes there are only + 1 or 2 compressed modes available; in that case entries are duplicated. +*/ + +#include "pwc-timon.h" + +const struct Timon_table_entry Timon_table[PSZ_MAX][6][4] = +{ + /* SQCIF */ + { + /* 5 fps */ + { + {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, + {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, + {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, + {1, 140, 0, {0x05, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x8C, 0xFC, 0x80, 0x02}}, + }, + /* 10 fps */ + { + {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, + {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, + {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, + {2, 280, 0, {0x04, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x18, 0xA9, 0x80, 0x02}}, + }, + /* 15 fps */ + { + {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, + {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, + {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, + {3, 410, 0, {0x03, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x9A, 0x71, 0x80, 0x02}}, + }, + /* 20 fps */ + { + {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, + {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, + {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, + {4, 559, 0, {0x02, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x2F, 0x56, 0x80, 0x02}}, + }, + /* 25 fps */ + { + {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, + {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, + {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, + {5, 659, 0, {0x01, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x93, 0x46, 0x80, 0x02}}, + }, + /* 30 fps */ + { + {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, + {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, + {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, + {7, 838, 0, {0x00, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x46, 0x3B, 0x80, 0x02}}, + }, + }, + /* QSIF */ + { + /* 5 fps */ + { + {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, + {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, + {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, + {1, 146, 0, {0x2D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x92, 0xFC, 0xC0, 0x02}}, + }, + /* 10 fps */ + { + {2, 291, 0, {0x2C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x23, 0xA1, 0xC0, 0x02}}, + {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, + {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, + {1, 191, 630, {0x2C, 0xF4, 0x05, 0x13, 0xA9, 0x12, 0xE1, 0x17, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, + }, + /* 15 fps */ + { + {3, 437, 0, {0x2B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xB5, 0x6D, 0xC0, 0x02}}, + {2, 291, 640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, + {2, 291, 640, {0x2B, 0xF4, 0x05, 0x13, 0xF7, 0x13, 0x2F, 0x13, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, + {1, 191, 420, {0x2B, 0xF4, 0x0D, 0x0D, 0x1B, 0x0C, 0x53, 0x1E, 0x08, 0xBF, 0xF4, 0xC0, 0x02}}, + }, + /* 20 fps */ + { + {4, 588, 0, {0x2A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x4C, 0x52, 0xC0, 0x02}}, + {3, 447, 730, {0x2A, 0xF4, 0x05, 0x16, 0xC9, 0x16, 0x01, 0x0E, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, + {2, 292, 476, {0x2A, 0xF4, 0x0D, 0x0E, 0xD8, 0x0E, 0x10, 0x19, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, + {1, 192, 312, {0x2A, 0xF4, 0x1D, 0x09, 0xB3, 0x08, 0xEB, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}}, + }, + /* 25 fps */ + { + {5, 703, 0, {0x29, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0xBF, 0x42, 0xC0, 0x02}}, + {3, 447, 610, {0x29, 0xF4, 0x05, 0x13, 0x0B, 0x12, 0x43, 0x14, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, + {2, 292, 398, {0x29, 0xF4, 0x0D, 0x0C, 0x6C, 0x0B, 0xA4, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, + {1, 192, 262, {0x29, 0xF4, 0x25, 0x08, 0x23, 0x07, 0x5B, 0x1E, 0x18, 0xC0, 0xF4, 0xC0, 0x02}}, + }, + /* 30 fps */ + { + {8, 873, 0, {0x28, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x69, 0x37, 0xC0, 0x02}}, + {5, 704, 774, {0x28, 0xF4, 0x05, 0x18, 0x21, 0x17, 0x59, 0x0F, 0x18, 0xC0, 0x42, 0xC0, 0x02}}, + {3, 448, 492, {0x28, 0xF4, 0x05, 0x0F, 0x5D, 0x0E, 0x95, 0x15, 0x18, 0xC0, 0x69, 0xC0, 0x02}}, + {2, 291, 320, {0x28, 0xF4, 0x1D, 0x09, 0xFB, 0x09, 0x33, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}}, + }, + }, + /* QCIF */ + { + /* 5 fps */ + { + {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, + {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, + {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, + {1, 193, 0, {0x0D, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xC1, 0xF4, 0xC0, 0x02}}, + }, + /* 10 fps */ + { + {3, 385, 0, {0x0C, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x81, 0x79, 0xC0, 0x02}}, + {2, 291, 800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, + {2, 291, 800, {0x0C, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x11, 0x08, 0x23, 0xA1, 0xC0, 0x02}}, + {1, 194, 532, {0x0C, 0xF4, 0x05, 0x10, 0x9A, 0x0F, 0xBE, 0x1B, 0x08, 0xC2, 0xF0, 0xC0, 0x02}}, + }, + /* 15 fps */ + { + {4, 577, 0, {0x0B, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x41, 0x52, 0xC0, 0x02}}, + {3, 447, 818, {0x0B, 0xF4, 0x05, 0x19, 0x89, 0x18, 0xAD, 0x0F, 0x10, 0xBF, 0x69, 0xC0, 0x02}}, + {2, 292, 534, {0x0B, 0xF4, 0x05, 0x10, 0xA3, 0x0F, 0xC7, 0x19, 0x10, 0x24, 0xA1, 0xC0, 0x02}}, + {1, 195, 356, {0x0B, 0xF4, 0x15, 0x0B, 0x11, 0x0A, 0x35, 0x1E, 0x10, 0xC3, 0xF0, 0xC0, 0x02}}, + }, + /* 20 fps */ + { + {6, 776, 0, {0x0A, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x08, 0x3F, 0xC0, 0x02}}, + {4, 591, 804, {0x0A, 0xF4, 0x05, 0x19, 0x1E, 0x18, 0x42, 0x0F, 0x18, 0x4F, 0x4E, 0xC0, 0x02}}, + {3, 447, 608, {0x0A, 0xF4, 0x05, 0x12, 0xFD, 0x12, 0x21, 0x15, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, + {2, 291, 396, {0x0A, 0xF4, 0x15, 0x0C, 0x5E, 0x0B, 0x82, 0x1E, 0x18, 0x23, 0xA1, 0xC0, 0x02}}, + }, + /* 25 fps */ + { + {9, 928, 0, {0x09, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0xA0, 0x33, 0xC0, 0x02}}, + {5, 703, 800, {0x09, 0xF4, 0x05, 0x18, 0xF4, 0x18, 0x18, 0x10, 0x18, 0xBF, 0x42, 0xC0, 0x02}}, + {3, 447, 508, {0x09, 0xF4, 0x0D, 0x0F, 0xD2, 0x0E, 0xF6, 0x1B, 0x18, 0xBF, 0x69, 0xC0, 0x02}}, + {2, 292, 332, {0x09, 0xF4, 0x1D, 0x0A, 0x5A, 0x09, 0x7E, 0x1E, 0x18, 0x24, 0xA1, 0xC0, 0x02}}, + }, + /* 30 fps */ + { + {0, }, + {9, 956, 876, {0x08, 0xF4, 0x05, 0x1B, 0x58, 0x1A, 0x7C, 0x0E, 0x20, 0xBC, 0x33, 0x10, 0x02}}, + {4, 592, 542, {0x08, 0xF4, 0x05, 0x10, 0xE4, 0x10, 0x08, 0x17, 0x20, 0x50, 0x4E, 0x10, 0x02}}, + {2, 291, 266, {0x08, 0xF4, 0x25, 0x08, 0x48, 0x07, 0x6C, 0x1E, 0x20, 0x23, 0xA1, 0x10, 0x02}}, + }, + }, + /* SIF */ + { + /* 5 fps */ + { + {4, 582, 0, {0x35, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x46, 0x52, 0x60, 0x02}}, + {3, 387, 1276, {0x35, 0xF4, 0x05, 0x27, 0xD8, 0x26, 0x48, 0x03, 0x10, 0x83, 0x79, 0x60, 0x02}}, + {2, 291, 960, {0x35, 0xF4, 0x0D, 0x1D, 0xF2, 0x1C, 0x62, 0x04, 0x10, 0x23, 0xA1, 0x60, 0x02}}, + {1, 191, 630, {0x35, 0xF4, 0x1D, 0x13, 0xA9, 0x12, 0x19, 0x05, 0x08, 0xBF, 0xF4, 0x60, 0x02}}, + }, + /* 10 fps */ + { + {0, }, + {6, 775, 1278, {0x34, 0xF4, 0x05, 0x27, 0xE8, 0x26, 0x58, 0x05, 0x30, 0x07, 0x3F, 0x10, 0x02}}, + {3, 447, 736, {0x34, 0xF4, 0x15, 0x16, 0xFB, 0x15, 0x6B, 0x05, 0x18, 0xBF, 0x69, 0x10, 0x02}}, + {2, 291, 480, {0x34, 0xF4, 0x2D, 0x0E, 0xF9, 0x0D, 0x69, 0x09, 0x18, 0x23, 0xA1, 0x10, 0x02}}, + }, + /* 15 fps */ + { + {0, }, + {9, 955, 1050, {0x33, 0xF4, 0x05, 0x20, 0xCF, 0x1F, 0x3F, 0x06, 0x48, 0xBB, 0x33, 0x10, 0x02}}, + {4, 591, 650, {0x33, 0xF4, 0x15, 0x14, 0x44, 0x12, 0xB4, 0x08, 0x30, 0x4F, 0x4E, 0x10, 0x02}}, + {3, 448, 492, {0x33, 0xF4, 0x25, 0x0F, 0x52, 0x0D, 0xC2, 0x09, 0x28, 0xC0, 0x69, 0x10, 0x02}}, + }, + /* 20 fps */ + { + {0, }, + {9, 958, 782, {0x32, 0xF4, 0x0D, 0x18, 0x6A, 0x16, 0xDA, 0x0B, 0x58, 0xBE, 0x33, 0xD0, 0x02}}, + {5, 703, 574, {0x32, 0xF4, 0x1D, 0x11, 0xE7, 0x10, 0x57, 0x0B, 0x40, 0xBF, 0x42, 0xD0, 0x02}}, + {3, 446, 364, {0x32, 0xF4, 0x3D, 0x0B, 0x5C, 0x09, 0xCC, 0x0E, 0x30, 0xBE, 0x69, 0xD0, 0x02}}, + }, + /* 25 fps */ + { + {0, }, + {9, 958, 654, {0x31, 0xF4, 0x15, 0x14, 0x66, 0x12, 0xD6, 0x0B, 0x50, 0xBE, 0x33, 0x90, 0x02}}, + {6, 776, 530, {0x31, 0xF4, 0x25, 0x10, 0x8C, 0x0E, 0xFC, 0x0C, 0x48, 0x08, 0x3F, 0x90, 0x02}}, + {4, 592, 404, {0x31, 0xF4, 0x35, 0x0C, 0x96, 0x0B, 0x06, 0x0B, 0x38, 0x50, 0x4E, 0x90, 0x02}}, + }, + /* 30 fps */ + { + {0, }, + {9, 957, 526, {0x30, 0xF4, 0x25, 0x10, 0x68, 0x0E, 0xD8, 0x0D, 0x58, 0xBD, 0x33, 0x60, 0x02}}, + {6, 775, 426, {0x30, 0xF4, 0x35, 0x0D, 0x48, 0x0B, 0xB8, 0x0F, 0x50, 0x07, 0x3F, 0x60, 0x02}}, + {4, 590, 324, {0x30, 0x7A, 0x4B, 0x0A, 0x1C, 0x08, 0xB4, 0x0E, 0x40, 0x4E, 0x52, 0x60, 0x02}}, + }, + }, + /* CIF */ + { + /* 5 fps */ + { + {6, 771, 0, {0x15, 0xF4, 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x03, 0x3F, 0x80, 0x02}}, + {4, 465, 1278, {0x15, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x03, 0x18, 0xD1, 0x65, 0x80, 0x02}}, + {2, 291, 800, {0x15, 0xF4, 0x15, 0x18, 0xF4, 0x17, 0x3C, 0x05, 0x18, 0x23, 0xA1, 0x80, 0x02}}, + {1, 193, 528, {0x15, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x18, 0xC1, 0xF4, 0x80, 0x02}}, + }, + /* 10 fps */ + { + {0, }, + {9, 932, 1278, {0x14, 0xF4, 0x05, 0x27, 0xEE, 0x26, 0x36, 0x04, 0x30, 0xA4, 0x33, 0x10, 0x02}}, + {4, 591, 812, {0x14, 0xF4, 0x15, 0x19, 0x56, 0x17, 0x9E, 0x06, 0x28, 0x4F, 0x4E, 0x10, 0x02}}, + {2, 291, 400, {0x14, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x28, 0x23, 0xA1, 0x10, 0x02}}, + }, + /* 15 fps */ + { + {0, }, + {9, 956, 876, {0x13, 0xF4, 0x0D, 0x1B, 0x58, 0x19, 0xA0, 0x05, 0x38, 0xBC, 0x33, 0x60, 0x02}}, + {5, 703, 644, {0x13, 0xF4, 0x1D, 0x14, 0x1C, 0x12, 0x64, 0x08, 0x38, 0xBF, 0x42, 0x60, 0x02}}, + {3, 448, 410, {0x13, 0xF4, 0x3D, 0x0C, 0xC4, 0x0B, 0x0C, 0x0E, 0x38, 0xC0, 0x69, 0x60, 0x02}}, + }, + /* 20 fps */ + { + {0, }, + {9, 956, 650, {0x12, 0xF4, 0x1D, 0x14, 0x4A, 0x12, 0x92, 0x09, 0x48, 0xBC, 0x33, 0x10, 0x03}}, + {6, 776, 528, {0x12, 0xF4, 0x2D, 0x10, 0x7E, 0x0E, 0xC6, 0x0A, 0x40, 0x08, 0x3F, 0x10, 0x03}}, + {4, 591, 402, {0x12, 0xF4, 0x3D, 0x0C, 0x8F, 0x0A, 0xD7, 0x0E, 0x40, 0x4F, 0x4E, 0x10, 0x03}}, + }, + /* 25 fps */ + { + {0, }, + {9, 956, 544, {0x11, 0xF4, 0x25, 0x10, 0xF4, 0x0F, 0x3C, 0x0A, 0x48, 0xBC, 0x33, 0xC0, 0x02}}, + {7, 840, 478, {0x11, 0xF4, 0x2D, 0x0E, 0xEB, 0x0D, 0x33, 0x0B, 0x48, 0x48, 0x3B, 0xC0, 0x02}}, + {5, 703, 400, {0x11, 0xF4, 0x3D, 0x0C, 0x7A, 0x0A, 0xC2, 0x0E, 0x48, 0xBF, 0x42, 0xC0, 0x02}}, + }, + /* 30 fps */ + { + {0, }, + {9, 956, 438, {0x10, 0xF4, 0x35, 0x0D, 0xAC, 0x0B, 0xF4, 0x0D, 0x50, 0xBC, 0x33, 0x10, 0x02}}, + {7, 838, 384, {0x10, 0xF4, 0x45, 0x0B, 0xFD, 0x0A, 0x45, 0x0F, 0x50, 0x46, 0x3B, 0x10, 0x02}}, + {6, 773, 354, {0x10, 0x7A, 0x4B, 0x0B, 0x0C, 0x09, 0x80, 0x10, 0x50, 0x05, 0x3F, 0x10, 0x02}}, + }, + }, + /* VGA */ + { + /* 5 fps */ + { + {0, }, + {6, 773, 1272, {0x1D, 0xF4, 0x15, 0x27, 0xB6, 0x24, 0x96, 0x02, 0x30, 0x05, 0x3F, 0x10, 0x02}}, + {4, 592, 976, {0x1D, 0xF4, 0x25, 0x1E, 0x78, 0x1B, 0x58, 0x03, 0x30, 0x50, 0x4E, 0x10, 0x02}}, + {3, 448, 738, {0x1D, 0xF4, 0x3D, 0x17, 0x0C, 0x13, 0xEC, 0x04, 0x30, 0xC0, 0x69, 0x10, 0x02}}, + }, + /* 10 fps */ + { + {0, }, + {9, 956, 788, {0x1C, 0xF4, 0x35, 0x18, 0x9C, 0x15, 0x7C, 0x03, 0x48, 0xBC, 0x33, 0x10, 0x02}}, + {6, 776, 640, {0x1C, 0x7A, 0x53, 0x13, 0xFC, 0x11, 0x2C, 0x04, 0x48, 0x08, 0x3F, 0x10, 0x02}}, + {4, 592, 488, {0x1C, 0x7A, 0x6B, 0x0F, 0x3C, 0x0C, 0x6C, 0x06, 0x48, 0x50, 0x4E, 0x10, 0x02}}, + }, + /* 15 fps */ + { + {0, }, + {9, 957, 526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}}, + {9, 957, 526, {0x1B, 0x7A, 0x63, 0x10, 0x68, 0x0D, 0x98, 0x06, 0x58, 0xBD, 0x33, 0x80, 0x02}}, + {8, 895, 492, {0x1B, 0x7A, 0x6B, 0x0F, 0x5D, 0x0C, 0x8D, 0x06, 0x58, 0x7F, 0x37, 0x80, 0x02}}, + }, + /* 20 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 25 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + /* 30 fps */ + { + {0, }, + {0, }, + {0, }, + {0, }, + }, + }, +}; + +/* + * 16 versions: + * 2 tables (one for Y, and one for U&V) + * 16 levels of details per tables + * 8 blocs + */ + +const unsigned int TimonRomTable [16][2][16][8] = +{ + { /* version 0 */ + { /* version 0, passes 0 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000001}, + {0x00000000,0x00000000,0x00000001,0x00000001, + 0x00000001,0x00000001,0x00000001,0x00000001}, + {0x00000000,0x00000000,0x00000001,0x00000001, + 0x00000001,0x00000009,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00000009,0x00000001, + 0x00000009,0x00000009,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000009,0x00000009,0x00000049,0x00000009}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000009,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000009,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000249,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000249,0x00000249,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000249,0x0000124a,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000249, + 0x00000249,0x0000124a,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x0000124a,0x00009252,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 0, passes 1 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000}, + {0x00000000,0x00000000,0x00000001,0x00000001, + 0x00000001,0x00000001,0x00000000,0x00000000}, + {0x00000000,0x00000000,0x00000009,0x00000001, + 0x00000001,0x00000009,0x00000000,0x00000000}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000009,0x00000009,0x00000000,0x00000000}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000009,0x00000009,0x00000001,0x00000000}, + {0x00000000,0x00000000,0x00000049,0x00000009, + 0x00000009,0x00000049,0x00000001,0x00000001}, + {0x00000000,0x00000000,0x00000049,0x00000009, + 0x00000009,0x00000049,0x00000001,0x00000001}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000009,0x00000001}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000009,0x00000001}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000009,0x00000001}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000249,0x00000049,0x00000009}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000249,0x00000049,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00000049, + 0x00000249,0x00000249,0x00000049,0x00000009}, + {0x00000000,0x00000000,0x00001249,0x00000249, + 0x0000124a,0x0000124a,0x0000024a,0x00000049}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 1 */ + { /* version 1, passes 0 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000001}, + {0x00000000,0x00000000,0x00000001,0x00000001, + 0x00000001,0x00000009,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000009,0x00000009,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000009,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000009,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000249,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00001252}, + {0x00000000,0x00000000,0x00000049,0x00000249, + 0x00000249,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00000049,0x00000249, + 0x0000124a,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x0000124a,0x00009252,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009252,0x00009252,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x0000924a, + 0x00009292,0x00009493,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x00009492,0x0000a49b,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 1, passes 1 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000009,0x00000001,0x00000001,0x00000000}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000009,0x00000009,0x00000001,0x00000000}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000009,0x00000001,0x00000000}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000001,0x00000001}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000009,0x00000001}, + {0x00000000,0x00000000,0x00000249,0x00000049, + 0x00000049,0x00000249,0x00000009,0x00000001}, + {0x00000000,0x00000000,0x00000249,0x00000049, + 0x00000249,0x00000249,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x00000049,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x0000124a,0x00000049,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x0000124a,0x00000049,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x0000124a,0x0000024a,0x00000049}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x0000024a,0x00000049}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x0000024a,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009252,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 2 */ + { /* version 2, passes 0 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000001}, + {0x00000000,0x00000000,0x00000009,0x00000009, + 0x00000009,0x00000009,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000049,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00001252}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x0000124a,0x00009252,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009252,0x00009292,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009252,0x00009292,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x0000924a, + 0x00009252,0x00009493,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x0000924a, + 0x00009292,0x00009493,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x00009252, + 0x00009492,0x00009493,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x000124db,0x000124db,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000126dc,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 2, passes 1 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000}, + {0x00000000,0x00000000,0x00000049,0x00000009, + 0x00000049,0x00000009,0x00000001,0x00000000}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000000}, + {0x00000000,0x00000000,0x00000249,0x00000049, + 0x00000249,0x00000049,0x0000024a,0x00000001}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00000001}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00000001}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x0000024a,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x0000024a,0x00000009}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x00009252,0x00001252,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x00009292,0x00001252,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x00009292,0x00001252,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009292,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x0000924a,0x0000924a, + 0x00009492,0x00009493,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 3 */ + { /* version 3, passes 0 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000001}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000049,0x00000249, + 0x00000249,0x00000249,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x00009252,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x0000124a,0x00009292,0x00009292,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009252,0x00009292,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009292,0x00009493,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x00009252, + 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x00009292,0x0000a49b,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x00009492,0x0000a49b,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x0000a49b,0x000124db,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x0000a493,0x0000a49b,0x000124db,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0001249b,0x000126dc,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000136e4,0x0001b725,0x000136e4}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 3, passes 1 */ + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000}, + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000001,0x00000000}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x00000049,0x00000001}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x0000124a,0x00001252,0x00000001}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x00001252,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x0000124a,0x00009252,0x00009292,0x00000009}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x00009252,0x00009292,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009252,0x00009292,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009493,0x00009292,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009493,0x00009292,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009493,0x00009493,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009292,0x00009493,0x00009493,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x00009493,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x00009492,0x0000a49b,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x00009292, + 0x0000a493,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 4 */ + { /* version 4, passes 0 */ + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x0000124a,0x00001252,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x00009252,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x0000124a,0x00009292,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009252,0x00009493,0x00009493,0x0000a49b}, + {0x00000000,0x00000000,0x00000249,0x0000924a, + 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009292,0x00009493,0x0000a49b,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x000124db,0x000124db,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x0000a493,0x000124db,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x000136e4}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0001249b,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000136e4,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x00009252,0x000124db, + 0x000126dc,0x0001b724,0x0001b725,0x0001b925}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 4, passes 1 */ + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00000249, + 0x0000124a,0x0000124a,0x00001252,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x00009292,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009292,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x0000a49b,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009493,0x0000a49b,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009493,0x0000a49b,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x0000a49b,0x0000a49b,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x00009252,0x0000a49b, + 0x0001249b,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 5 */ + { /* version 5, passes 0 */ + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x0000124a,0x00001252,0x00009292}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x0000124a,0x00009292,0x00009292,0x00009493}, + {0x00000000,0x00000000,0x00000249,0x0000924a, + 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x0000a49b,0x000124db,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x0000a493,0x000124db,0x000124db,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0001249b,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0001249b,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0001249b,0x000126dc,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000126dc,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x000136e4,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b724,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 5, passes 1 */ + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009493,0x00009493,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009493,0x00009493,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009493,0x0000a49b,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x00009493,0x000124db,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x00009493,0x000124db,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x0000a49b,0x000124db,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x0000a49b,0x000124db,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000124db,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000124db,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000124db,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009252,0x000124db, + 0x000126dc,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 6 */ + { /* version 6, passes 0 */ + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x0000124a,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009493,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x0000a49b,0x0000a49b,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x000124db,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000126dc,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000136e4,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000136e4,0x0001b725,0x0001b925}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x000136e4,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x000136e4,0x0001b925,0x00025bb6,0x00024b77}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 6, passes 1 */ + {0x00000000,0x00000000,0x00001249,0x00000249, + 0x0000124a,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x00009493,0x0000a49b,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x0000a49b,0x000126dc,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x000126dc,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x000126dc,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00009492,0x0000a49b, + 0x000136e4,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x0001b724,0x0001b724,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 7 */ + { /* version 7, passes 0 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009493,0x0000a49b,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x0000a493,0x0000a49b,0x000124db,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x000136e4}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0001249b,0x000126dc,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00001249,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000136e4,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000136e4,0x0001b725,0x0001b925}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x00009292,0x000124db, + 0x000126dc,0x0001b724,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b724,0x0001c96e,0x0002496e}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x000136e4,0x0001b925,0x0001c96e,0x0002496e}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b724,0x0002496d,0x00025bb6,0x00025bbf}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 7, passes 1 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x00009493,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x000124db,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000124db,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x000124db,0x000136e4,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x000124db,0x000136e4,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000124db,0x000136e4,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x000136e4,0x0001b724,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00012492,0x000126db, + 0x0001b724,0x0001b925,0x0001b725,0x000136e4}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 8 */ + { /* version 8, passes 0 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009292,0x00009493,0x0000a49b,0x000124db}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x0000a493,0x000124db,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x000136e4}, + {0x00000000,0x00000000,0x00001249,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000136e4,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000136e4,0x0001b725,0x0001b925}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d}, + {0x00000000,0x00000000,0x00009252,0x000124db, + 0x000126dc,0x0001b724,0x0001b92d,0x0001c92d}, + {0x00000000,0x00000000,0x00009292,0x000124db, + 0x000126dc,0x0001b925,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b925,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b925,0x00024b76,0x00024b77}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x000136e4,0x0001b925,0x00024b76,0x00025bbf}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x000136e4,0x0001c92d,0x00024b76,0x00025bbf}, + {0x00000000,0x00000000,0x00012492,0x000136db, + 0x0001b724,0x00024b6d,0x0002ddb6,0x0002efff}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 8, passes 1 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009493,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x000124db,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x000124db,0x000136e4,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000126dc,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x000136e4,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00009292,0x000124db, + 0x000136e4,0x0001b724,0x0001b725,0x000136e4}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x000136e4,0x0001b925,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x000136e4,0x0001b925,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b724,0x0002496d,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 9 */ + { /* version 9, passes 0 */ + {0x00000000,0x00000000,0x00000049,0x00000049, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00000249,0x00000049, + 0x00000249,0x00000249,0x0000024a,0x00000049}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x0000124a,0x00009252,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009493,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009292,0x00009493,0x00009493,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000124db,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0001249b,0x000126dc,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00009252,0x00009493, + 0x000124db,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009252,0x0000a49b, + 0x000124db,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00009492,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x000136e4,0x0001b925,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 9, passes 1 */ + {0x00000000,0x00000000,0x00000249,0x00000049, + 0x00000009,0x00000009,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000049,0x00000049,0x00000009,0x00000009}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x00000249,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x0000124a,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009252,0x0000124a,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x00009252,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x00009292,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x00009292,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x00009493,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000124db,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009252,0x000124db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 10 */ + { /* version 10, passes 0 */ + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00000249,0x00001249, + 0x00009252,0x00009292,0x00009292,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x00009493,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x000124db,0x000124db,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000124db,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0001249b,0x000126dc,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000126dc,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009252,0x0000a49b, + 0x000124db,0x000136e4,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x00009492,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b92d,0x0001b724}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000126dc,0x0001b925,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x000136e4,0x0002496d,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 10, passes 1 */ + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000049,0x00000049,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x00000249,0x00000049,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x00009252,0x0000024a,0x00000049}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009493,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00009252, + 0x00009492,0x00009493,0x00001252,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x00009493,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x00009492,0x00009493,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x00009493,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009252,0x000126db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 11 */ + { /* version 11, passes 0 */ + {0x00000000,0x00000000,0x00000249,0x00000249, + 0x00000249,0x00000249,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009492,0x0000a49b,0x0000a49b,0x00009292}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x0000a49b,0x000124db,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000126dc,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b725,0x000136e4}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, + {0x00000000,0x00000000,0x00009492,0x0000a49b, + 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b925,0x0001c96e,0x0001b925}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001c924,0x0002496d,0x00025bb6,0x00024b77}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 11, passes 1 */ + {0x00000000,0x00000000,0x00001249,0x00000249, + 0x00000249,0x00000249,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009252,0x00009252,0x0000024a,0x0000024a}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x0000a49b,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x0000a49b,0x00009292,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000124db,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000124db,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x000126dc,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009292,0x000124db, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 12 */ + { /* version 12, passes 0 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x0000a493,0x0000a49b,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x000126dc,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000136e4,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b725,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000136e4,0x0001b724,0x0001b92d,0x000136e4}, + {0x00000000,0x00000000,0x00009492,0x0000a49b, + 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b724,0x0001b92d,0x0001b724}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b925,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x0001b724,0x0001b925,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x0001b724,0x0001c92d,0x0001c96e,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x0001b724,0x0001c92d,0x00024b76,0x0002496e}, + {0x00000000,0x00000000,0x00012492,0x000126db, + 0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 12, passes 1 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x00001249,0x00009292, + 0x00009492,0x00009252,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x00009292,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x0000a49b,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000124db,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000124db,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x000126dc,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x000136e4,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00009492,0x000126db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001c924,0x0001b724,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 13 */ + { /* version 13, passes 0 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x00009252,0x00009292,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x000124db,0x000126dc,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x0000a49b, + 0x0001249b,0x000126dc,0x000126dc,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x000136e4,0x0001b725,0x000124db}, + {0x00000000,0x00000000,0x00009292,0x0000a49b, + 0x000136e4,0x0001b724,0x0001b725,0x000126dc}, + {0x00000000,0x00000000,0x00009292,0x000124db, + 0x000136e4,0x0001b724,0x0001b725,0x000126dc}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b724,0x0001c96e,0x000136e4}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x000136e4,0x0001c92d,0x0001c96e,0x0001b724}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x0001b724,0x0001c92d,0x0001c96e,0x0001b925}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001b924,0x0001c92d,0x00024b76,0x0002496e}, + {0x00000000,0x00000000,0x00012492,0x000136db, + 0x00024924,0x00024b6d,0x0002ddb6,0x00025bbf}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 13, passes 1 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x00009492,0x00009292,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x0000a49b,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x000124db,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000136db, + 0x0001b724,0x000124db,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000136db, + 0x0001b724,0x000126dc,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00009292,0x000136db, + 0x0001b724,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x00009492,0x000136db, + 0x0001b724,0x000126dc,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00012492,0x0001b6db, + 0x0001c924,0x0001b724,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 14 */ + { /* version 14, passes 0 */ + {0x00000000,0x00000000,0x00001249,0x0000924a, + 0x00009292,0x00009493,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00001249,0x0000a49b, + 0x0000a493,0x000124db,0x000126dc,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x0000a49b}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x000136e4,0x0001b725,0x000124db}, + {0x00000000,0x00000000,0x00009292,0x000124db, + 0x000126dc,0x0001b724,0x0001b92d,0x000126dc}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b724,0x0001b92d,0x000126dc}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001c92d,0x0001c96e,0x000136e4}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x0001b724,0x0001c92d,0x0001c96e,0x0001b724}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x0001b724,0x0001c92d,0x00024b76,0x0001b925}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001b724,0x0001c92d,0x00024b76,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b724,0x0001c92d,0x00024b76,0x0002496e}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b924,0x0002496d,0x00024b76,0x00024b77}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b924,0x00024b6d,0x0002ddb6,0x00025bbf}, + {0x00000000,0x00000000,0x00012492,0x0001b6db, + 0x00024924,0x0002db6d,0x00036db6,0x0002efff}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 14, passes 1 */ + {0x00000000,0x00000000,0x00001249,0x00001249, + 0x0000124a,0x0000124a,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x00009493, + 0x0000a493,0x00009292,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x0000a49b,0x00001252,0x00001252}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000136e4,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000136e4,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x000136e4,0x00009493,0x00009292}, + {0x00000000,0x00000000,0x00009492,0x000136db, + 0x0001b724,0x000136e4,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x00009492,0x000136db, + 0x0001b724,0x000136e4,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x00009492,0x000136db, + 0x0001b724,0x000136e4,0x0000a49b,0x00009493}, + {0x00000000,0x00000000,0x00009492,0x000136db, + 0x0001b724,0x000136e4,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b724,0x000136e4,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b724,0x000136e4,0x000124db,0x0000a49b}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b724,0x000136e4,0x000126dc,0x000124db}, + {0x00000000,0x00000000,0x00012492,0x0001b6db, + 0x0001c924,0x0001b724,0x000136e4,0x000126dc}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + }, + { /* version 15 */ + { /* version 15, passes 0 */ + {0x00000000,0x00000000,0x00001249,0x00009493, + 0x0000a493,0x0000a49b,0x000124db,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0001249b,0x000126dc,0x000136e4,0x000124db}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x000126dc,0x0001b724,0x0001b725,0x000126dc}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x0001b724,0x0001b92d,0x000126dc}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x000136e4,0x0001b925,0x0001c96e,0x000136e4}, + {0x00000000,0x00000000,0x00009492,0x000124db, + 0x0001b724,0x0001c92d,0x0001c96e,0x0001b724}, + {0x00000000,0x00000000,0x0000a492,0x000124db, + 0x0001b724,0x0001c92d,0x0001c96e,0x0001b724}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001b724,0x0001c92d,0x0001c96e,0x0001b925}, + {0x00000000,0x00000000,0x0000a492,0x000126db, + 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b924,0x0001c92d,0x00024b76,0x0001c92d}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001b924,0x0002496d,0x00024b76,0x0002496e}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001c924,0x0002496d,0x00025bb6,0x00024b77}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001c924,0x00024b6d,0x00025bb6,0x00024b77}, + {0x00000000,0x00000000,0x00012492,0x000136db, + 0x0001c924,0x00024b6d,0x0002ddb6,0x00025bbf}, + {0x00000000,0x00000000,0x00012492,0x0001b6db, + 0x00024924,0x0002db6d,0x00036db6,0x0002efff}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + }, + { /* version 15, passes 1 */ + {0x00000000,0x00000000,0x0000924a,0x0000924a, + 0x00009292,0x00009292,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x0000a49b, + 0x0000a493,0x000124db,0x00009292,0x00009292}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000124db,0x0001b724,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000126dc,0x0001b724,0x00009493,0x00009493}, + {0x00000000,0x00000000,0x0000924a,0x000124db, + 0x000136e4,0x0001b724,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00009292,0x000136db, + 0x0001b724,0x0001b724,0x0000a49b,0x0000a49b}, + {0x00000000,0x00000000,0x00009492,0x000136db, + 0x0001c924,0x0001b724,0x000124db,0x000124db}, + {0x00000000,0x00000000,0x00009492,0x000136db, + 0x0001c924,0x0001b724,0x000124db,0x000124db}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001c924,0x0001b724,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001c924,0x0001b925,0x000126dc,0x000126dc}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001c924,0x0001b925,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001c924,0x0001b925,0x000136e4,0x000136e4}, + {0x00000000,0x00000000,0x0000a492,0x000136db, + 0x0001c924,0x0001b925,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x00012492,0x000136db, + 0x0001c924,0x0001b925,0x0001b725,0x0001b724}, + {0x00000000,0x00000000,0x00012492,0x0001b6db, + 0x00024924,0x0002496d,0x0001b92d,0x0001b925}, + {0x00000000,0x00000000,0x00000000,0x00000000, + 0x00000000,0x00000000,0x00000000,0x00000000} + } + } +}; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-timon.h linux-2.6.11/drivers/usb/media/pwc/pwc-timon.h --- linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-timon.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.11/drivers/usb/media/pwc/pwc-timon.h 2005-03-05 15:26:35.000000000 +0000 @@ -0,0 +1,61 @@ +/* Linux driver for Philips webcam + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + + +/* This tables contains entries for the 675/680/690 (Timon) camera, with + 4 different qualities (no compression, low, medium, high). + It lists the bandwidth requirements for said mode by its alternate interface + number. An alternate of 0 means that the mode is unavailable. + + There are 6 * 4 * 4 entries: + 6 different resolutions subqcif, qsif, qcif, sif, cif, vga + 6 framerates: 5, 10, 15, 20, 25, 30 + 4 compression modi: none, low, medium, high + + When an uncompressed mode is not available, the next available compressed mode + will be chosen (unless the decompressor is absent). Sometimes there are only + 1 or 2 compressed modes available; in that case entries are duplicated. +*/ + +#ifndef PWC_TIMON_H +#define PWC_TIMON_H + +#include "pwc-ioctl.h" + +struct Timon_table_entry +{ + char alternate; /* USB alternate interface */ + unsigned short packetsize; /* Normal packet size */ + unsigned short bandlength; /* Bandlength when decompressing */ + unsigned char mode[13]; /* precomputed mode settings for cam */ +}; + +const extern struct Timon_table_entry Timon_table[PSZ_MAX][6][4]; +const extern unsigned int TimonRomTable [16][2][16][8]; + + +#endif + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-uncompress.c linux-2.6.11/drivers/usb/media/pwc/pwc-uncompress.c --- linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-uncompress.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.11/drivers/usb/media/pwc/pwc-uncompress.c 2005-03-05 15:26:35.000000000 +0000 @@ -0,0 +1,147 @@ +/* Linux driver for Philips webcam + Decompression frontend. + (C) 1999-2003 Nemosoft Unv. + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include + +#include "pwc.h" +#include "pwc-uncompress.h" +#include "pwc-dec1.h" +#include "pwc-dec23.h" + +int pwc_decompress(struct pwc_device *pdev) +{ + struct pwc_frame_buf *fbuf; + int n, line, col, stride; + void *yuv, *image; + u16 *src; + u16 *dsty, *dstu, *dstv; + + if (pdev == NULL) + return -EFAULT; +#if defined(__KERNEL__) && defined(PWC_MAGIC) + if (pdev->magic != PWC_MAGIC) { + Err("pwc_decompress(): magic failed.\n"); + return -EFAULT; + } +#endif + + fbuf = pdev->read_frame; + if (fbuf == NULL) + return -EFAULT; + image = pdev->image_ptr[pdev->fill_image]; + if (!image) + return -EFAULT; + + yuv = fbuf->data + pdev->frame_header_size; /* Skip header */ + + /* Raw format; that's easy... */ + if (pdev->vpalette == VIDEO_PALETTE_RAW) + { + memcpy(image, yuv, pdev->frame_size); + return 0; + } + + if (pdev->vbandlength == 0) { + /* Uncompressed mode. We copy the data into the output buffer, + using the viewport size (which may be larger than the image + size). Unfortunately we have to do a bit of byte stuffing + to get the desired output format/size. + */ + /* + * We do some byte shuffling here to go from the + * native format to YUV420P. + */ + src = (u16 *)yuv; + n = pdev->view.x * pdev->view.y; + + /* offset in Y plane */ + stride = pdev->view.x * pdev->offset.y + pdev->offset.x; + dsty = (u16 *)(image + stride); + + /* offsets in U/V planes */ + stride = pdev->view.x * pdev->offset.y / 4 + pdev->offset.x / 2; + dstu = (u16 *)(image + n + stride); + dstv = (u16 *)(image + n + n / 4 + stride); + + /* increment after each line */ + stride = (pdev->view.x - pdev->image.x) / 2; /* u16 is 2 bytes */ + + for (line = 0; line < pdev->image.y; line++) { + for (col = 0; col < pdev->image.x; col += 4) { + *dsty++ = *src++; + *dsty++ = *src++; + if (line & 1) + *dstv++ = *src++; + else + *dstu++ = *src++; + } + dsty += stride; + if (line & 1) + dstv += (stride >> 1); + else + dstu += (stride >> 1); + } + } + else { + /* Compressed; the decompressor routines will write the data + in planar format immediately. + */ + int flags; + + flags = PWCX_FLAG_PLANAR; + if (pdev->vsize == PSZ_VGA && pdev->vframes == 5 && pdev->vsnapshot) + { + printk(KERN_ERR "pwc: Mode Bayer is not supported for now\n"); + flags |= PWCX_FLAG_BAYER; + return -ENXIO; /* No such device or address: missing decompressor */ + } + + switch (pdev->type) + { + case 675: + case 680: + case 690: + case 720: + case 730: + case 740: + case 750: + pwc_dec23_decompress(&pdev->image, &pdev->view, &pdev->offset, + yuv, image, + flags, + pdev->decompress_data, pdev->vbandlength); + break; + case 645: + case 646: + /* TODO & FIXME */ + return -ENXIO; /* No such device or address: missing decompressor */ + break; + } + } + return 0; +} + + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-uncompress.h linux-2.6.11/drivers/usb/media/pwc/pwc-uncompress.h --- linux.vanilla-2.6.11/drivers/usb/media/pwc/pwc-uncompress.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.11/drivers/usb/media/pwc/pwc-uncompress.h 2005-03-05 15:26:35.000000000 +0000 @@ -0,0 +1,41 @@ +/* (C) 1999-2003 Nemosoft Unv. + (C) 2004 Luc Saillard (luc@saillard.org) + + NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx + driver and thus may have bugs that are not present in the original version. + Please send bug reports and support requests to . + The decompression routines have been implemented by reverse-engineering the + Nemosoft binary pwcx module. Caveat emptor. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* This file is the bridge between the kernel module and the plugin; it + describes the structures and datatypes used in both modules. Any + significant change should be reflected by increasing the + pwc_decompressor_version major number. + */ +#ifndef PWC_UNCOMPRESS_H +#define PWC_UNCOMPRESS_H + +#include + +#include "pwc-ioctl.h" + +/* from pwc-dec.h */ +#define PWCX_FLAG_PLANAR 0x0001 +/* */ + +#endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/drivers/usb/media/pwc/philips.txt linux-2.6.11/drivers/usb/media/pwc/philips.txt --- linux.vanilla-2.6.11/drivers/usb/media/pwc/philips.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.11/drivers/usb/media/pwc/philips.txt 2005-03-05 15:26:35.000000000 +0000 @@ -0,0 +1,236 @@ +This file contains some additional information for the Philips and OEM webcams. +E-mail: webcam@smcc.demon.nl Last updated: 2004-01-19 +Site: http://www.smcc.demon.nl/webcam/ + +As of this moment, the following cameras are supported: + * Philips PCA645 + * Philips PCA646 + * Philips PCVC675 + * Philips PCVC680 + * Philips PCVC690 + * Philips PCVC720/40 + * Philips PCVC730 + * Philips PCVC740 + * Philips PCVC750 + * Askey VC010 + * Creative Labs Webcam 5 + * Creative Labs Webcam Pro Ex + * Logitech QuickCam 3000 Pro + * Logitech QuickCam 4000 Pro + * Logitech QuickCam Notebook Pro + * Logitech QuickCam Zoom + * Logitech QuickCam Orbit + * Logitech QuickCam Sphere + * Samsung MPC-C10 + * Samsung MPC-C30 + * Sotec Afina Eye + * AME CU-001 + * Visionite VCS-UM100 + * Visionite VCS-UC300 + +The main webpage for the Philips driver is at the address above. It contains +a lot of extra information, a FAQ, and the binary plugin 'PWCX'. This plugin +contains decompression routines that allow you to use higher image sizes and +framerates; in addition the webcam uses less bandwidth on the USB bus (handy +if you want to run more than 1 camera simultaneously). These routines fall +under a NDA, and may therefor not be distributed as source; however, its use +is completely optional. + +You can build this code either into your kernel, or as a module. I recommend +the latter, since it makes troubleshooting a lot easier. The built-in +microphone is supported through the USB Audio class. + +When you load the module you can set some default settings for the +camera; some programs depend on a particular image-size or -format and +don't know how to set it properly in the driver. The options are: + +size + Can be one of 'sqcif', 'qsif', 'qcif', 'sif', 'cif' or + 'vga', for an image size of resp. 128x96, 160x120, 176x144, + 320x240, 352x288 and 640x480 (of course, only for those cameras that + support these resolutions). + +fps + Specifies the desired framerate. Is an integer in the range of 4-30. + +fbufs + This paramter specifies the number of internal buffers to use for storing + frames from the cam. This will help if the process that reads images from + the cam is a bit slow or momentarely busy. However, on slow machines it + only introduces lag, so choose carefully. The default is 3, which is + reasonable. You can set it between 2 and 5. + +mbufs + This is an integer between 1 and 10. It will tell the module the number of + buffers to reserve for mmap(), VIDIOCCGMBUF, VIDIOCMCAPTURE and friends. + The default is 2, which is adequate for most applications (double + buffering). + + Should you experience a lot of 'Dumping frame...' messages during + grabbing with a tool that uses mmap(), you might want to increase if. + However, it doesn't really buffer images, it just gives you a bit more + slack when your program is behind. But you need a multi-threaded or + forked program to really take advantage of these buffers. + + The absolute maximum is 10, but don't set it too high! Every buffer takes + up 460 KB of RAM, so unless you have a lot of memory setting this to + something more than 4 is an absolute waste. This memory is only + allocated during open(), so nothing is wasted when the camera is not in + use. + +power_save + When power_save is enabled (set to 1), the module will try to shut down + the cam on close() and re-activate on open(). This will save power and + turn off the LED. Not all cameras support this though (the 645 and 646 + don't have power saving at all), and some models don't work either (they + will shut down, but never wake up). Consider this experimental. By + default this option is disabled. + +compression (only useful with the plugin) + With this option you can control the compression factor that the camera + uses to squeeze the image through the USB bus. You can set the + parameter between 0 and 3: + 0 = prefer uncompressed images; if the requested mode is not available + in an uncompressed format, the driver will silently switch to low + compression. + 1 = low compression. + 2 = medium compression. + 3 = high compression. + + High compression takes less bandwidth of course, but it could also + introduce some unwanted artefacts. The default is 2, medium compression. + See the FAQ on the website for an overview of which modes require + compression. + + The compression parameter does not apply to the 645 and 646 cameras + and OEM models derived from those (only a few). Most cams honour this + parameter. + +leds + This settings takes 2 integers, that define the on/off time for the LED + (in milliseconds). One of the interesting things that you can do with + this is let the LED blink while the camera is in use. This: + + leds=500,500 + + will blink the LED once every second. But with: + + leds=0,0 + + the LED never goes on, making it suitable for silent surveillance. + + By default the camera's LED is on solid while in use, and turned off + when the camera is not used anymore. + + This parameter works only with the ToUCam range of cameras (720, 730, 740, + 750) and OEMs. For other cameras this command is silently ignored, and + the LED cannot be controlled. + + Finally: this parameters does not take effect UNTIL the first time you + open the camera device. Until then, the LED remains on. + +dev_hint + A long standing problem with USB devices is their dynamic nature: you + never know what device a camera gets assigned; it depends on module load + order, the hub configuration, the order in which devices are plugged in, + and the phase of the moon (i.e. it can be random). With this option you + can give the driver a hint as to what video device node (/dev/videoX) it + should use with a specific camera. This is also handy if you have two + cameras of the same model. + + A camera is specified by its type (the number from the camera model, + like PCA645, PCVC750VC, etc) and optionally the serial number (visible + in /proc/bus/usb/devices). A hint consists of a string with the following + format: + + [type[.serialnumber]:]node + + The square brackets mean that both the type and the serialnumber are + optional, but a serialnumber cannot be specified without a type (which + would be rather pointless). The serialnumber is separated from the type + by a '.'; the node number by a ':'. + + This somewhat cryptic syntax is best explained by a few examples: + + dev_hint=3,5 The first detected cam gets assigned + /dev/video3, the second /dev/video5. Any + other cameras will get the first free + available slot (see below). + + dev_hint=645:1,680:2 The PCA645 camera will get /dev/video1, + and a PCVC680 /dev/video2. + + dev_hint=645.0123:3,645.4567:0 The PCA645 camera with serialnumber + 0123 goes to /dev/video3, the same + camera model with the 4567 serial + gets /dev/video0. + + dev_hint=750:1,4,5,6 The PCVC750 camera will get /dev/video1, the + next 3 Philips cams will use /dev/video4 + through /dev/video6. + + Some points worth knowing: + - Serialnumbers are case sensitive and must be written full, including + leading zeroes (it's treated as a string). + - If a device node is already occupied, registration will fail and + the webcam is not available. + - You can have up to 64 video devices; be sure to make enough device + nodes in /dev if you want to spread the numbers (this does not apply + to devfs). After /dev/video9 comes /dev/video10 (not /dev/videoA). + - If a camera does not match any dev_hint, it will simply get assigned + the first available device node, just as it used to be. + +trace + In order to better detect problems, it is now possible to turn on a + 'trace' of some of the calls the module makes; it logs all items in your + kernel log at debug level. + + The trace variable is a bitmask; each bit represents a certain feature. + If you want to trace something, look up the bit value(s) in the table + below, add the values together and supply that to the trace variable. + + Value Value Description Default + (dec) (hex) + 1 0x1 Module initialization; this will log messages On + while loading and unloading the module + + 2 0x2 probe() and disconnect() traces On + + 4 0x4 Trace open() and close() calls Off + + 8 0x8 read(), mmap() and associated ioctl() calls Off + + 16 0x10 Memory allocation of buffers, etc. Off + + 32 0x20 Showing underflow, overflow and Dumping frame On + messages + + 64 0x40 Show viewport and image sizes Off + + 128 0x80 PWCX debugging Off + + For example, to trace the open() & read() fuctions, sum 8 + 4 = 12, + so you would supply trace=12 during insmod or modprobe. If + you want to turn the initialization and probing tracing off, set trace=0. + The default value for trace is 35 (0x23). + + + +Example: + + # modprobe pwc size=cif fps=15 power_save=1 + +The fbufs, mbufs and trace parameters are global and apply to all connected +cameras. Each camera has its own set of buffers. + +size and fps only specify defaults when you open() the device; this is to +accommodate some tools that don't set the size. You can change these +settings after open() with the Video4Linux ioctl() calls. The default of +defaults is QCIF size at 10 fps. + +The compression parameter is semiglobal; it sets the initial compression +preference for all camera's, but this parameter can be set per camera with +the VIDIOCPWCSCQUAL ioctl() call. + +All parameters are optional. + diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/fs/exec.c linux-2.6.11/fs/exec.c --- linux.vanilla-2.6.11/fs/exec.c 2005-03-05 15:17:05.000000000 +0000 +++ linux-2.6.11/fs/exec.c 2005-03-05 16:16:51.000000000 +0000 @@ -58,6 +58,9 @@ int core_uses_pid; char core_pattern[65] = "core"; +int suid_dumpable = 0; + +EXPORT_SYMBOL(suid_dumpable); /* The maximal length of core_pattern is also specified in sysctl.c */ static struct linux_binfmt *formats; @@ -866,6 +869,9 @@ if (current->euid == current->uid && current->egid == current->gid) current->mm->dumpable = 1; + else + current->mm->dumpable = suid_dumpable; + name = bprm->filename; for (i=0; (ch = *(name++)) != '\0';) { if (ch == '/') @@ -883,7 +889,7 @@ permission(bprm->file->f_dentry->d_inode,MAY_READ, NULL) || (bprm->interp_flags & BINPRM_FLAGS_ENFORCE_NONDUMP)) { suid_keys(current); - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; } /* An exec changes our domain. We are no longer part of the thread @@ -1431,6 +1437,8 @@ struct inode * inode; struct file * file; int retval = 0; + int fsuid = current->fsuid; + int flag = 0; binfmt = current->binfmt; if (!binfmt || !binfmt->core_dump) @@ -1440,6 +1448,16 @@ up_write(&mm->mmap_sem); goto fail; } + + /* + * We cannot trust fsuid as being the "true" uid of the + * process nor do we know its entire history. We only know it + * was tainted so we dump it as root in mode 2. + */ + if (mm->dumpable == 2) { /* Setuid core dump mode */ + flag = O_EXCL; /* Stop rewrite attacks */ + current->fsuid = 0; /* Dump root private */ + } mm->dumpable = 0; init_completion(&mm->core_done); spin_lock_irq(¤t->sighand->siglock); @@ -1465,7 +1483,7 @@ lock_kernel(); format_corename(corename, core_pattern, signr); unlock_kernel(); - file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE, 0600); + file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, 0600); if (IS_ERR(file)) goto fail_unlock; inode = file->f_dentry->d_inode; @@ -1490,6 +1508,7 @@ close_fail: filp_close(file, NULL); fail_unlock: + current->fsuid = fsuid; complete_all(&mm->core_done); fail: return retval; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/fs/jbd/transaction.c linux-2.6.11/fs/jbd/transaction.c --- linux.vanilla-2.6.11/fs/jbd/transaction.c 2005-03-05 15:17:05.000000000 +0000 +++ linux-2.6.11/fs/jbd/transaction.c 2005-03-07 17:57:15.000000000 +0000 @@ -1775,10 +1775,10 @@ JBUFFER_TRACE(jh, "checkpointed: add to BJ_Forget"); ret = __dispose_buffer(jh, journal->j_running_transaction); + journal_put_journal_head(jh); spin_unlock(&journal->j_list_lock); jbd_unlock_bh_state(bh); spin_unlock(&journal->j_state_lock); - journal_put_journal_head(jh); return ret; } else { /* There is no currently-running transaction. So the @@ -1789,10 +1789,10 @@ JBUFFER_TRACE(jh, "give to committing trans"); ret = __dispose_buffer(jh, journal->j_committing_transaction); + journal_put_journal_head(jh); spin_unlock(&journal->j_list_lock); jbd_unlock_bh_state(bh); spin_unlock(&journal->j_state_lock); - journal_put_journal_head(jh); return ret; } else { /* The orphan record's transaction has @@ -1813,10 +1813,10 @@ journal->j_running_transaction); jh->b_next_transaction = NULL; } + journal_put_journal_head(jh); spin_unlock(&journal->j_list_lock); jbd_unlock_bh_state(bh); spin_unlock(&journal->j_state_lock); - journal_put_journal_head(jh); return 0; } else { /* Good, the buffer belongs to the running transaction. diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/fs/proc/base.c linux-2.6.11/fs/proc/base.c --- linux.vanilla-2.6.11/fs/proc/base.c 2005-03-05 15:17:05.000000000 +0000 +++ linux-2.6.11/fs/proc/base.c 2005-03-05 15:44:47.000000000 +0000 @@ -287,7 +287,7 @@ (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE)) goto out; rmb(); - if (!task->mm->dumpable && !capable(CAP_SYS_PTRACE)) + if (task->mm->dumpable != 1 && !capable(CAP_SYS_PTRACE)) goto out; if (security_ptrace(current, task)) goto out; @@ -1031,7 +1031,9 @@ if (mm) dumpable = mm->dumpable; task_unlock(task); - return dumpable; + if(dumpable == 1) + return 1; + return 0; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/include/asm-i386/ide.h linux-2.6.11/include/asm-i386/ide.h --- linux.vanilla-2.6.11/include/asm-i386/ide.h 2005-03-05 15:15:19.000000000 +0000 +++ linux-2.6.11/include/asm-i386/ide.h 2005-03-05 15:43:01.000000000 +0000 @@ -41,16 +41,20 @@ static __inline__ unsigned long ide_default_io_base(int index) { + if(pci_find_device(PCI_ANY_ID, PCI_ANY_ID, NULL) == NULL) { + switch(index) { + case 2: return 0x1e8; + case 3: return 0x168; + case 4: return 0x1e0; + case 5: return 0x160; + } + } switch (index) { case 0: return 0x1f0; case 1: return 0x170; - case 2: return 0x1e8; - case 3: return 0x168; - case 4: return 0x1e0; - case 5: return 0x160; default: return 0; - } + } } #define IDE_ARCH_OBSOLETE_INIT diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/include/asm-i386/param.h linux-2.6.11/include/asm-i386/param.h --- linux.vanilla-2.6.11/include/asm-i386/param.h 2005-03-05 15:15:19.000000000 +0000 +++ linux-2.6.11/include/asm-i386/param.h 2005-03-05 15:42:54.000000000 +0000 @@ -1,8 +1,10 @@ #ifndef _ASMi386_PARAM_H #define _ASMi386_PARAM_H +#include + #ifdef __KERNEL__ -# define HZ 1000 /* Internal kernel timer frequency */ +# define HZ (CONFIG_X86_HZ) # define USER_HZ 100 /* .. some user interfaces are in "ticks" */ # define CLOCKS_PER_SEC (USER_HZ) /* like times() */ #endif diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/include/linux/binfmts.h linux-2.6.11/include/linux/binfmts.h --- linux.vanilla-2.6.11/include/linux/binfmts.h 2005-03-05 15:17:06.000000000 +0000 +++ linux-2.6.11/include/linux/binfmts.h 2005-03-05 15:42:27.000000000 +0000 @@ -69,6 +69,11 @@ extern int search_binary_handler(struct linux_binprm *,struct pt_regs *); extern int flush_old_exec(struct linux_binprm * bprm); +extern int suid_dumpable; +#define SUID_DUMP_DISABLE 0 /* No setuid dumping */ +#define SUID_DUMP_USER 1 /* Dump as user of process */ +#define SUID_DUMP_ROOT 2 /* Dump as root */ + /* Stack area protections */ #define EXSTACK_DEFAULT 0 /* Whatever the arch defaults to */ #define EXSTACK_DISABLE_X 1 /* Disable executable stacks */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/include/linux/hayesesp.h linux-2.6.11/include/linux/hayesesp.h --- linux.vanilla-2.6.11/include/linux/hayesesp.h 2005-03-05 15:15:24.000000000 +0000 +++ linux-2.6.11/include/linux/hayesesp.h 2005-03-08 12:58:42.000000000 +0000 @@ -109,6 +109,7 @@ struct async_icount icount; /* kernel counters for the 4 input interrupts */ struct hayes_esp_config config; /* port configuration */ struct esp_struct *next_port; /* For the linked list */ + spinlock_t lock; }; struct esp_pio_buffer { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/include/linux/ide.h linux-2.6.11/include/linux/ide.h --- linux.vanilla-2.6.11/include/linux/ide.h 2005-03-05 15:17:06.000000000 +0000 +++ linux-2.6.11/include/linux/ide.h 2005-03-06 17:30:15.000000000 +0000 @@ -190,7 +190,10 @@ #define WAIT_READY (5*HZ) /* 5sec - some laptops are very slow */ #define WAIT_PIDENTIFY (10*HZ) /* 10sec - should be less than 3ms (?), if all ATAPI CD is closed at boot */ #define WAIT_WORSTCASE (30*HZ) /* 30sec - worst case when spinning up */ -#define WAIT_CMD (10*HZ) /* 10sec - maximum wait for an IRQ to happen */ +/* We should make this more tunable and smart: Windows apparently uses 7 secs + but we've seen drives take long. Equally some drives can now do fast fails + for RAID. Can probably be 10 but lets see if 15 helps */ +#define WAIT_CMD (15*HZ) /* 10sec - maximum wait for an IRQ to happen */ #define WAIT_MIN_SLEEP (2*HZ/100) /* 20msec - minimum sleep time */ #define HOST(hwif,chipset) \ @@ -748,6 +751,7 @@ unsigned int usage; /* current "open()" count for drive */ unsigned int failures; /* current failure count */ unsigned int max_failures; /* maximum allowed failure count */ + u64 probed_capacity;/* initial reported media capacity (ide-cd only currently) */ u64 capacity64; /* total number of sectors */ @@ -764,6 +768,7 @@ #define IDE_CHIPSET_IS_PCI(c) ((IDE_CHIPSET_PCI_MASK >> (c)) & 1) struct ide_pci_device_s; +struct ide_task_s; typedef struct hwif_s { struct hwif_s *next; /* for linked-list in ide_hwgroup_t */ @@ -771,6 +776,7 @@ struct hwgroup_s *hwgroup; /* actually (ide_hwgroup_t *) */ struct proc_dir_entry *proc; /* /proc/ide/ directory entry */ + u16 key; /* /proc persistent keying */ char name[6]; /* name of interface, eg. "ide0" */ /* task file registers for pata and sata */ @@ -826,6 +832,9 @@ // u8 (*ratemask)(ide_drive_t *); // /* device rate limiter */ // u8 (*ratefilter)(ide_drive_t *, u8); + /* hwif remove hook, called on unload/pci remove paths*/ + void (*remove)(struct hwif_s *); + /* allow command filter/control */ #endif void (*ata_input_data)(ide_drive_t *, void *, u32); @@ -834,9 +843,9 @@ void (*atapi_input_bytes)(ide_drive_t *, void *, u32); void (*atapi_output_bytes)(ide_drive_t *, void *, u32); - int (*dma_setup)(ide_drive_t *); - void (*dma_exec_cmd)(ide_drive_t *, u8); - void (*dma_start)(ide_drive_t *); + int (*ide_dma_setup)(ide_drive_t *); + void (*ide_dma_exec_cmd)(ide_drive_t *, u8); + void (*ide_dma_start)(ide_drive_t *); int (*ide_dma_end)(ide_drive_t *drive); int (*ide_dma_check)(ide_drive_t *drive); int (*ide_dma_on)(ide_drive_t *drive); @@ -897,7 +906,9 @@ unsigned noprobe : 1; /* don't probe for this interface */ unsigned present : 1; /* this interface exists */ + unsigned configured : 1; /* this hwif exists and is set up (may not be "present") */ unsigned hold : 1; /* this interface is always present */ + unsigned user_dev : 1; /* user ioctl created device */ unsigned serialized : 1; /* serialized all channel operation */ unsigned sharing_irq: 1; /* 1 = sharing irq with another hwif */ unsigned reset : 1; /* reset after probe */ @@ -908,6 +919,7 @@ unsigned no_dsc : 1; /* 0 default, 1 dsc_overlap disabled */ unsigned auto_poll : 1; /* supports nop auto-poll */ unsigned sg_mapped : 1; /* sg_table and sg_nents are ready */ + unsigned polling : 1; /* doing a polled command ignore irqs */ struct device gendev; struct semaphore gendev_rel_sem; /* To deal with device release() */ @@ -1002,6 +1014,11 @@ extern int ide_write_setting(ide_drive_t *drive, ide_settings_t *setting, int val); extern void ide_add_generic_settings(ide_drive_t *drive); +extern void *ide_drive_to_key(ide_drive_t *drive); +extern ide_drive_t *ide_drive_from_key(void *); +extern void *ide_hwif_to_key(ide_hwif_t *hwif); +extern ide_hwif_t *ide_hwif_from_key(void *); + /* * /proc/ide interface */ @@ -1018,7 +1035,7 @@ extern void proc_ide_create(void); extern void proc_ide_destroy(void); extern void create_proc_ide_interfaces(void); -void destroy_proc_ide_interface(ide_hwif_t *); +extern void destroy_proc_ide_interface(ide_hwif_t *); extern void ide_add_proc_entries(struct proc_dir_entry *, ide_proc_entry_t *, void *); extern void ide_remove_proc_entries(struct proc_dir_entry *, ide_proc_entry_t *); read_proc_t proc_ide_read_capacity; @@ -1130,6 +1147,7 @@ extern int noautodma; extern int ide_end_request (ide_drive_t *drive, int uptodate, int nrsecs); +extern int ide_end_dequeued_request (ide_drive_t *drive, struct request *rq, int uptodate, int nrsecs); /* * This is used on exit from the driver to designate the next irq handler @@ -1342,16 +1360,18 @@ extern void ide_pci_unregister_driver(struct pci_driver *driver); void ide_pci_setup_ports(struct pci_dev *, struct ide_pci_device_s *, int, ata_index_t *); extern void ide_setup_pci_noise (struct pci_dev *dev, struct ide_pci_device_s *d); +extern void ide_pci_remove_hwifs(struct pci_dev *dev); extern void default_hwif_iops(ide_hwif_t *); extern void default_hwif_mmiops(ide_hwif_t *); +extern void removed_hwif_iops(ide_hwif_t *); extern void default_hwif_transport(ide_hwif_t *); -int ide_register_driver(ide_driver_t *driver); -void ide_unregister_driver(ide_driver_t *driver); -int ide_register_subdriver(ide_drive_t *, ide_driver_t *); -int ide_unregister_subdriver (ide_drive_t *drive); -int ide_replace_subdriver(ide_drive_t *drive, const char *driver); +extern int ide_register_driver(ide_driver_t *driver); +extern void ide_unregister_driver(ide_driver_t *driver); +extern int ide_register_subdriver(ide_drive_t *, ide_driver_t *); +extern int ide_unregister_subdriver (ide_drive_t *drive); +extern int ide_replace_subdriver(ide_drive_t *drive, const char *driver); #define ON_BOARD 1 #define NEVER_BOARD 0 @@ -1444,11 +1464,12 @@ extern int ide_hwif_request_regions(ide_hwif_t *hwif); extern void ide_hwif_release_regions(ide_hwif_t* hwif); -extern void ide_unregister (unsigned int index); +extern int ide_unregister_hwif(ide_hwif_t *hwif); +extern int __ide_unregister_hwif(ide_hwif_t *hwif); -void ide_undecoded_slave(ide_hwif_t *); +extern void ide_undecoded_slave(ide_hwif_t *); -int probe_hwif_init_with_fixup(ide_hwif_t *, void (*)(ide_hwif_t *)); +extern int probe_hwif_init_with_fixup(ide_hwif_t *, void (*)(ide_hwif_t *)); extern int probe_hwif_init(ide_hwif_t *); static inline void *ide_get_hwifdata (ide_hwif_t * hwif) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/include/linux/irq.h linux-2.6.11/include/linux/irq.h --- linux.vanilla-2.6.11/include/linux/irq.h 2005-03-05 15:17:06.000000000 +0000 +++ linux-2.6.11/include/linux/irq.h 2005-03-05 15:41:54.000000000 +0000 @@ -83,7 +83,7 @@ extern fastcall int handle_IRQ_event(unsigned int irq, struct pt_regs *regs, struct irqaction *action); extern fastcall unsigned int __do_IRQ(unsigned int irq, struct pt_regs *regs); -extern void note_interrupt(unsigned int irq, irq_desc_t *desc, int action_ret); +extern void note_interrupt(unsigned int irq, irq_desc_t *desc, int action_ret, struct pt_regs *regs); extern void report_bad_irq(unsigned int irq, irq_desc_t *desc, int action_ret); extern int can_request_irq(unsigned int irq, unsigned long irqflags); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/include/linux/pci_ids.h linux-2.6.11/include/linux/pci_ids.h --- linux.vanilla-2.6.11/include/linux/pci_ids.h 2005-03-05 15:17:06.000000000 +0000 +++ linux-2.6.11/include/linux/pci_ids.h 2005-03-08 10:15:31.000000000 +0000 @@ -352,10 +352,21 @@ #define PCI_DEVICE_ID_ATI_RS300_133 0x5831 #define PCI_DEVICE_ID_ATI_RS300_166 0x5832 #define PCI_DEVICE_ID_ATI_RS300_200 0x5833 +#define PCI_DEVICE_ID_ATI_RS350_100 0x7830 +#define PCI_DEVICE_ID_ATI_RS350_133 0x7831 +#define PCI_DEVICE_ID_ATI_RS350_166 0x7832 +#define PCI_DEVICE_ID_ATI_RS350_200 0x7833 +#define PCI_DEVICE_ID_ATI_RS400_100 0x5a30 +#define PCI_DEVICE_ID_ATI_RS400_133 0x5a31 +#define PCI_DEVICE_ID_ATI_RS400_166 0x5a32 +#define PCI_DEVICE_ID_ATI_RS400_200 0x5a33 +#define PCI_DEVICE_ID_ATI_RS480 0x5950 /* ATI IXP Chipset */ #define PCI_DEVICE_ID_ATI_IXP200_IDE 0x4349 #define PCI_DEVICE_ID_ATI_IXP300_IDE 0x4369 +#define PCI_DEVICE_ID_ATI_IXP300_SATA 0x436e #define PCI_DEVICE_ID_ATI_IXP400_IDE 0x4376 +#define PCI_DEVICE_ID_ATI_IXP400_SATA 0x4379 #define PCI_VENDOR_ID_VLSI 0x1004 #define PCI_DEVICE_ID_VLSI_82C592 0x0005 @@ -1497,6 +1508,9 @@ #define PCI_DEVICE_ID_ARTOP_AEC7612D 0x8040 #define PCI_DEVICE_ID_ARTOP_AEC7612SUW 0x8050 #define PCI_DEVICE_ID_ARTOP_8060 0x8060 +#define PCI_DEVICE_ID_ARTOP_AEC67160 0x8080 +#define PCI_DEVICE_ID_ARTOP_AEC67160_2 0x8081 +#define PCI_DEVICE_ID_ARTOP_AEC67162 0x808a #define PCI_VENDOR_ID_ZEITNET 0x1193 #define PCI_DEVICE_ID_ZEITNET_1221 0x0001 @@ -1609,6 +1623,10 @@ #define PCI_DEVICE_ID_PC300_TE_M_2 0x0320 #define PCI_DEVICE_ID_PC300_TE_M_1 0x0321 +/* Allied Telesyn */ +#define PCI_VENDOR_ID_AT 0x1259 +#define PCI_SUBDEVICE_ID_AT_2701FX 0x2703 + #define PCI_VENDOR_ID_ESSENTIAL 0x120f #define PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER 0x0001 @@ -1678,6 +1696,8 @@ #define PCI_VENDOR_ID_ITE 0x1283 #define PCI_DEVICE_ID_ITE_IT8172G 0x8172 #define PCI_DEVICE_ID_ITE_IT8172G_AUDIO 0x0801 +#define PCI_DEVICE_ID_ITE_8211 0x8211 +#define PCI_DEVICE_ID_ITE_8212 0x8212 #define PCI_DEVICE_ID_ITE_8872 0x8872 #define PCI_DEVICE_ID_ITE_IT8330G_0 0xe886 @@ -2427,3 +2447,6 @@ #define PCI_DEVICE_ID_ARK_STING 0xa091 #define PCI_DEVICE_ID_ARK_STINGARK 0xa099 #define PCI_DEVICE_ID_ARK_2000MT 0xa0a1 + +#define PCI_VENDOR_ID_WORKBIT 0x1145 +#define PCI_DEVICE_ID_WORKBIT_CB 0xf021 diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/include/linux/sched.h linux-2.6.11/include/linux/sched.h --- linux.vanilla-2.6.11/include/linux/sched.h 2005-03-05 15:17:06.000000000 +0000 +++ linux-2.6.11/include/linux/sched.h 2005-03-05 15:41:25.000000000 +0000 @@ -234,7 +234,7 @@ unsigned long saved_auxv[42]; /* for /proc/PID/auxv */ - unsigned dumpable:1; + unsigned dumpable:2; cpumask_t cpu_vm_mask; /* Architecture-specific MM context */ diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/include/linux/stallion.h linux-2.6.11/include/linux/stallion.h --- linux.vanilla-2.6.11/include/linux/stallion.h 2005-03-05 15:15:24.000000000 +0000 +++ linux-2.6.11/include/linux/stallion.h 2005-03-05 15:41:16.000000000 +0000 @@ -126,7 +126,7 @@ int nrbnks; int irq; int irqtype; - void (*isr)(struct stlbrd *brdp); + int (*isr)(struct stlbrd *brdp); unsigned int ioaddr1; unsigned int ioaddr2; unsigned int iosize1; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/include/linux/sysctl.h linux-2.6.11/include/linux/sysctl.h --- linux.vanilla-2.6.11/include/linux/sysctl.h 2005-03-05 15:17:06.000000000 +0000 +++ linux-2.6.11/include/linux/sysctl.h 2005-03-05 16:19:57.000000000 +0000 @@ -135,6 +135,7 @@ KERN_HZ_TIMER=65, /* int: hz timer on or off */ KERN_UNKNOWN_NMI_PANIC=66, /* int: unknown nmi panic flag */ KERN_BOOTLOADER_TYPE=67, /* int: boot loader type */ + KERN_SETUID_DUMPABLE=68, /* int: behaviour of dumps for setuid core */ }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/kernel/irq/handle.c linux-2.6.11/kernel/irq/handle.c --- linux.vanilla-2.6.11/kernel/irq/handle.c 2005-03-05 15:17:06.000000000 +0000 +++ linux-2.6.11/kernel/irq/handle.c 2005-03-05 15:40:28.000000000 +0000 @@ -119,7 +119,7 @@ desc->handler->ack(irq); action_ret = handle_IRQ_event(irq, regs, desc->action); if (!noirqdebug) - note_interrupt(irq, desc, action_ret); + note_interrupt(irq, desc, action_ret, regs); desc->handler->end(irq); return 1; } @@ -173,7 +173,7 @@ spin_lock(&desc->lock); if (!noirqdebug) - note_interrupt(irq, desc, action_ret); + note_interrupt(irq, desc, action_ret, regs); if (likely(!(desc->status & IRQ_PENDING))) break; desc->status &= ~IRQ_PENDING; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/kernel/irq/spurious.c linux-2.6.11/kernel/irq/spurious.c --- linux.vanilla-2.6.11/kernel/irq/spurious.c 2005-03-05 15:15:25.000000000 +0000 +++ linux-2.6.11/kernel/irq/spurious.c 2005-03-05 15:39:57.000000000 +0000 @@ -11,6 +11,77 @@ #include #include +static int irqfixup; + +/* + * Recovery handler for misrouted interrupts. + */ + +static int misrouted_irq(int irq, struct pt_regs *regs) +{ + int i; + irq_desc_t *desc; + int ok = 0; + int work = 0; /* Did we do work for a real IRQ */ + for(i = 1; i < NR_IRQS; i++) + { + struct irqaction *action; + if(i == irq) /* Already tried */ + continue; + desc = &irq_desc[i]; + spin_lock(&desc->lock); + action = desc->action; + /* Already running on another processor */ + if(desc->status & IRQ_INPROGRESS) + { + /* Already running: If it is shared get the other + CPU to go looking for our mystery interrupt too */ + if(desc->action && (desc->action->flags & SA_SHIRQ)) + desc->status |= IRQ_PENDING; + spin_unlock(&desc->lock); + continue; + } + /* Honour the normal IRQ locking */ + desc->status |= IRQ_INPROGRESS; + spin_unlock(&desc->lock); + while(action) + { + /* Only shared IRQ handlers are safe to call */ + if(action->flags & SA_SHIRQ) + { + if(action->handler(i, action->dev_id, regs) == IRQ_HANDLED) + ok = 1; + } + action = action->next; + } + local_irq_disable(); + /* Now clean up the flags */ + spin_lock(&desc->lock); + action = desc->action; + + /* While we were looking for a fixup someone queued a real + IRQ clashing with our walk */ + + while((desc->status & IRQ_PENDING) && action) + { + /* Perform real IRQ processing for the IRQ we deferred */ + work = 1; + spin_unlock(&desc->lock); + handle_IRQ_event(i, regs, action); + spin_lock(&desc->lock); + desc->status &= ~IRQ_PENDING; + } + desc->status &= ~IRQ_INPROGRESS; + /* If we did actual work for the real IRQ line we must + let the IRQ controller clean up too */ + if(work) + desc->handler->end(i); + spin_unlock(&desc->lock); + } + /* So the caller can adjust the irq error counts */ + return ok; +} + /* * If 99,900 of the previous 100,000 interrupts have not been handled * then assume that the IRQ is stuck in some manner. Drop a diagnostic @@ -31,7 +102,7 @@ printk(KERN_ERR "irq event %d: bogus return value %x\n", irq, action_ret); } else { - printk(KERN_ERR "irq %d: nobody cared!\n", irq); + printk(KERN_ERR "irq %d: nobody cared (try booting with the \"irqpoll\" option.\n", irq); } dump_stack(); printk(KERN_ERR "handlers:\n"); @@ -55,7 +126,7 @@ } } -void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret) +void note_interrupt(unsigned int irq, irq_desc_t *desc, irqreturn_t action_ret, struct pt_regs *regs) { if (action_ret != IRQ_HANDLED) { desc->irqs_unhandled++; @@ -63,6 +134,15 @@ report_bad_irq(irq, desc, action_ret); } + if(unlikely(irqfixup)) { /* Don't punish working computers */ + if((irqfixup == 2 && irq == 0) || action_ret == IRQ_NONE) { + int ok; + ok = misrouted_irq(irq, regs); + if(action_ret == IRQ_NONE) + desc->irqs_unhandled -= ok; + } + } + desc->irq_count++; if (desc->irq_count < 100000) return; @@ -94,3 +174,22 @@ __setup("noirqdebug", noirqdebug_setup); +static int __init irqfixup_setup(char *str) +{ + irqfixup = 1; + printk(KERN_WARNING "Misrouted IRQ fixup support enabled.\n"); + printk(KERN_WARNING "This may impact system performance.\n"); + return 1; +} + +__setup("irqfixup", irqfixup_setup); + +static int __init irqpoll_setup(char *str) +{ + irqfixup = 2; + printk(KERN_WARNING "Misrouted IRQ fixup and polling support enabled.\n"); + printk(KERN_WARNING "This may significantly impact system performance.\n"); + return 1; +} + +__setup("irqpoll", irqpoll_setup); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/kernel/sys.c linux-2.6.11/kernel/sys.c --- linux.vanilla-2.6.11/kernel/sys.c 2005-03-05 15:17:06.000000000 +0000 +++ linux-2.6.11/kernel/sys.c 2005-03-05 15:39:25.000000000 +0000 @@ -522,7 +522,7 @@ } if (new_egid != old_egid) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; wmb(); } if (rgid != (gid_t) -1 || @@ -553,7 +553,7 @@ { if(old_egid != gid) { - current->mm->dumpable=0; + current->mm->dumpable = suid_dumpable; wmb(); } current->gid = current->egid = current->sgid = current->fsgid = gid; @@ -562,7 +562,7 @@ { if(old_egid != gid) { - current->mm->dumpable=0; + current->mm->dumpable = suid_dumpable; wmb(); } current->egid = current->fsgid = gid; @@ -593,7 +593,7 @@ if(dumpclear) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; wmb(); } current->uid = new_ruid; @@ -650,7 +650,7 @@ if (new_euid != old_euid) { - current->mm->dumpable=0; + current->mm->dumpable = suid_dumpable; wmb(); } current->fsuid = current->euid = new_euid; @@ -700,7 +700,7 @@ if (old_euid != uid) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; wmb(); } current->fsuid = current->euid = uid; @@ -745,7 +745,7 @@ if (euid != (uid_t) -1) { if (euid != current->euid) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; wmb(); } current->euid = euid; @@ -795,7 +795,7 @@ if (egid != (gid_t) -1) { if (egid != current->egid) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; wmb(); } current->egid = egid; @@ -842,7 +842,7 @@ { if (uid != old_fsuid) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; wmb(); } current->fsuid = uid; @@ -872,7 +872,7 @@ { if (gid != old_fsgid) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; wmb(); } current->fsgid = gid; @@ -1635,7 +1635,7 @@ error = 1; break; case PR_SET_DUMPABLE: - if (arg2 != 0 && arg2 != 1) { + if (arg2 < 0 || arg2 > 2) { error = -EINVAL; break; } diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/kernel/sysctl.c linux-2.6.11/kernel/sysctl.c --- linux.vanilla-2.6.11/kernel/sysctl.c 2005-03-05 15:17:06.000000000 +0000 +++ linux-2.6.11/kernel/sysctl.c 2005-03-05 15:38:11.000000000 +0000 @@ -58,6 +58,7 @@ extern int max_threads; extern int sysrq_enabled; extern int core_uses_pid; +extern int suid_dumpable; extern char core_pattern[]; extern int cad_pid; extern int pid_max; @@ -632,6 +633,14 @@ .proc_handler = &proc_dointvec, }, #endif + { + .ctl_name = KERN_SETUID_DUMPABLE, + .procname = "suid_dumpable", + .data = &suid_dumpable, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec, + }, { .ctl_name = 0 } }; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/Makefile linux-2.6.11/Makefile --- linux.vanilla-2.6.11/Makefile 2005-03-05 15:16:59.000000000 +0000 +++ linux-2.6.11/Makefile 2005-03-09 17:09:10.422291152 +0000 @@ -1,8 +1,8 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 11 -EXTRAVERSION = -NAME=Woozy Numbat +EXTRAVERSION = ac2 +NAME=AC # *DOCUMENTATION* # To see a list of typical targets execute "make help" diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/net/802/tr.c linux-2.6.11/net/802/tr.c --- linux.vanilla-2.6.11/net/802/tr.c 2005-03-05 15:17:06.000000000 +0000 +++ linux-2.6.11/net/802/tr.c 2005-03-05 15:37:00.000000000 +0000 @@ -251,10 +251,11 @@ unsigned int hash; struct rif_cache_s *entry; unsigned char *olddata; + unsigned long flags; static const unsigned char mcast_func_addr[] = {0xC0,0x00,0x00,0x04,0x00,0x00}; - spin_lock_bh(&rif_lock); + spin_lock_irqsave(&rif_lock, flags); /* * Broadcasts are single route as stated in RFC 1042 @@ -323,7 +324,7 @@ else slack = 18 - ((ntohs(trh->rcf) & TR_RCF_LEN_MASK)>>8); olddata = skb->data; - spin_unlock_bh(&rif_lock); + spin_unlock_irqrestore(&rif_lock, flags); skb_pull(skb, slack); memmove(skb->data, olddata, sizeof(struct trh_hdr) - slack); @@ -337,10 +338,11 @@ static void tr_add_rif_info(struct trh_hdr *trh, struct net_device *dev) { unsigned int hash, rii_p = 0; + unsigned long flags; struct rif_cache_s *entry; - spin_lock_bh(&rif_lock); + spin_lock_irqsave(&rif_lock, flags); /* * Firstly see if the entry exists @@ -378,7 +380,7 @@ if(!entry) { printk(KERN_DEBUG "tr.c: Couldn't malloc rif cache entry !\n"); - spin_unlock_bh(&rif_lock); + spin_unlock_irqrestore(&rif_lock, flags); return; } @@ -420,7 +422,7 @@ } entry->last_used=jiffies; } - spin_unlock_bh(&rif_lock); + spin_unlock_irqrestore(&rif_lock, flags); } /* @@ -430,9 +432,9 @@ static void rif_check_expire(unsigned long dummy) { int i; - unsigned long next_interval = jiffies + sysctl_tr_rif_timeout/2; + unsigned long flags, next_interval = jiffies + sysctl_tr_rif_timeout/2; - spin_lock_bh(&rif_lock); + spin_lock_irqsave(&rif_lock, flags); for(i =0; i < RIF_TABLE_SIZE; i++) { struct rif_cache_s *entry, **pentry; @@ -454,7 +456,7 @@ } } - spin_unlock_bh(&rif_lock); + spin_unlock_irqrestore(&rif_lock, flags); mod_timer(&rif_timer, next_interval); @@ -485,7 +487,7 @@ static void *rif_seq_start(struct seq_file *seq, loff_t *pos) { - spin_lock_bh(&rif_lock); + spin_lock_irq(&rif_lock); return *pos ? rif_get_idx(*pos - 1) : SEQ_START_TOKEN; } @@ -516,7 +518,7 @@ static void rif_seq_stop(struct seq_file *seq, void *v) { - spin_unlock_bh(&rif_lock); + spin_unlock_irq(&rif_lock); } static int rif_seq_show(struct seq_file *seq, void *v) diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/net/bridge/br_ioctl.c linux-2.6.11/net/bridge/br_ioctl.c --- linux.vanilla-2.6.11/net/bridge/br_ioctl.c 2005-03-05 15:15:25.000000000 +0000 +++ linux-2.6.11/net/bridge/br_ioctl.c 2005-03-05 15:36:16.000000000 +0000 @@ -324,6 +324,8 @@ int *indices; int ret = 0; + if (args[2] >= 16384) + return -ENOMEM; indices = kmalloc(args[2]*sizeof(int), GFP_KERNEL); if (indices == NULL) return -ENOMEM; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/net/netrom/nr_in.c linux-2.6.11/net/netrom/nr_in.c --- linux.vanilla-2.6.11/net/netrom/nr_in.c 2005-03-05 15:15:26.000000000 +0000 +++ linux-2.6.11/net/netrom/nr_in.c 2005-03-05 15:35:16.000000000 +0000 @@ -74,7 +74,6 @@ static int nr_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype) { - bh_lock_sock(sk); switch (frametype) { case NR_CONNACK: { nr_cb *nr = nr_sk(sk); @@ -103,8 +102,6 @@ default: break; } - bh_unlock_sock(sk); - return 0; } @@ -116,7 +113,6 @@ static int nr_state2_machine(struct sock *sk, struct sk_buff *skb, int frametype) { - bh_lock_sock(sk); switch (frametype) { case NR_CONNACK | NR_CHOKE_FLAG: nr_disconnect(sk, ECONNRESET); @@ -132,8 +128,6 @@ default: break; } - bh_unlock_sock(sk); - return 0; } @@ -154,7 +148,6 @@ nr = skb->data[18]; ns = skb->data[17]; - bh_lock_sock(sk); switch (frametype) { case NR_CONNREQ: nr_write_internal(sk, NR_CONNACK); @@ -265,12 +258,10 @@ default: break; } - bh_unlock_sock(sk); - return queued; } -/* Higher level upcall for a LAPB frame */ +/* Higher level upcall for a LAPB frame - called with sk locked */ int nr_process_rx_frame(struct sock *sk, struct sk_buff *skb) { nr_cb *nr = nr_sk(sk); diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/net/rose/rose_route.c linux-2.6.11/net/rose/rose_route.c --- linux.vanilla-2.6.11/net/rose/rose_route.c 2005-03-05 15:17:06.000000000 +0000 +++ linux-2.6.11/net/rose/rose_route.c 2005-03-05 15:34:38.000000000 +0000 @@ -727,7 +727,8 @@ } if (rose_route.mask > 10) /* Mask can't be more than 10 digits */ return -EINVAL; - + if(rose_route.ndigis > 8) /* No more than 8 digipeats */ + return -EINVAL; err = rose_add_node(&rose_route, dev); dev_put(dev); return err; diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/security/commoncap.c linux-2.6.11/security/commoncap.c --- linux.vanilla-2.6.11/security/commoncap.c 2005-03-05 15:17:08.000000000 +0000 +++ linux-2.6.11/security/commoncap.c 2005-03-05 15:34:31.000000000 +0000 @@ -149,7 +149,7 @@ if (bprm->e_uid != current->uid || bprm->e_gid != current->gid || !cap_issubset (new_permitted, current->cap_permitted)) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; if (unsafe & ~LSM_UNSAFE_PTRACE_CAP) { if (!capable(CAP_SETUID)) { diff -u --new-file --recursive --exclude-from /usr/src/exclude linux.vanilla-2.6.11/security/dummy.c linux-2.6.11/security/dummy.c --- linux.vanilla-2.6.11/security/dummy.c 2005-03-05 15:17:08.000000000 +0000 +++ linux-2.6.11/security/dummy.c 2005-03-05 15:34:31.000000000 +0000 @@ -130,7 +130,7 @@ static void dummy_bprm_apply_creds (struct linux_binprm *bprm, int unsafe) { if (bprm->e_uid != current->uid || bprm->e_gid != current->gid) { - current->mm->dumpable = 0; + current->mm->dumpable = suid_dumpable; if ((unsafe & ~LSM_UNSAFE_PTRACE_CAP) && !capable(CAP_SETUID)) { bprm->e_uid = current->uid;