- USAR Systems provided us with one of their excellent USB
Evaluation Kits. It allows us to test the Linux-USB driver
- for compilance with the latest USB specification. USAR
+ for compliance with the latest USB specification. USAR
Systems recognized the importance of an up-to-date open
Operating System and supports this project with
Hardware. Thanks!.
Linux users.
- Many thanks to ing büro h doran [http://www.ibhdoran.com]!
- It was almost imposible to get a PC backplate USB connector
+ It was almost impossible to get a PC backplate USB connector
for the motherboard here at Europe (mine, home-made, was
- quite lowsy :). Now I know where to adquire nice USB stuff!
+ quite lousy :). Now I know where to acquire nice USB stuff!
- Genius Germany donated a USB mouse to test the mouse boot
protocol. They've also donated a F-23 digital joystick and a
documentation for the UUSBD. Go for it!
- Ric Klaren <ia_ric@cs.utwente.nl> for doing nice
- introductory documents (compiting with Alberto's :).
+ introductory documents (competing with Alberto's :).
- Christian Groessler <cpg@aladdin.de>, for it's help on those
itchy bits ... :)
- Rasca Gmelch <thron@gmx.de> has revived the raw driver and
pointed bugs, as well as started the uusbd-utils package.
- - Peter Dettori <dettori@ozy.dec.com> is unconvering bugs like
+ - Peter Dettori <dettori@ozy.dec.com> is uncovering bugs like
crazy, as well as making cool suggestions, great :)
- All the Free Software and Linux community, the FSF & the GNU
- Big thanks to Richard Stallman for creating Emacs!
- The people at the linux-usb mailing list, for reading so
- many messages :) Ok, no more kidding; for all your advices!
+ many messages :) Ok, no more kidding; for all your advises!
- All the people at the USB Implementors Forum for their
help and assistance.
- URBs can be linked. After completing one URB, the next one can be
automatically submitted. This is especially useful for ISO transfers:
You only have read/write the data from/to the buffers in the completion
-handler, the continous streaming itself is transparently done by the
+handler, the continuous streaming itself is transparently done by the
URB-machinery.
1.2. The URB structure
Usually, (to reduce restart time) the completion handler is called
AFTER the URB re-submission. You can get the other way by setting
-USB_URB_EARLY_COMPLETE in transfer_flags. This is implicite for
+USB_URB_EARLY_COMPLETE in transfer_flags. This is implicit for
INT transfers.
1.5. How to submit an URB?
with the ASAP flag result in a seamless ISO streaming. Exception: The
execution cannot be scheduled later than 900 frames from the 'now'-time.
The same applies to INT transfers, but here the seamless continuation is
-independent of the transfer flags (implicitely ASAP).
+independent of the transfer flags (implicitly ASAP).
1.6. How to cancel an already running URB?
audio synchronisation/adaptive transfer rates). You can also use the length
0 to omit one or more frames (striping).
-As can be concluded from above, the UHCI-driver does not care for continous
+As can be concluded from above, the UHCI-driver does not care for continuous
data in case of short packet ISO reads! There's no fixup_isoc() like in the
old driver. There may be a common routine to do this in the future, but this
has nothing to do with the UHCI-driver!
For scheduling you can choose your own start frame or ASAP. As written above,
queuing more than one ISO frame with ASAP to the same device&endpoint result
-in seamless ISO streaming. For continous streaming you have to use URB
+in seamless ISO streaming. For continuous streaming you have to use URB
linking.
1.9. How to start interrupt (INT) transfers?
3.1.3 usbkbd.c
~~~~~~~~~~~~~~
- Much like usbmouse.c, this module talks to keyboards with a simpplified
+ Much like usbmouse.c, this module talks to keyboards with a simplified
HIDBP protocol. It's smaller, but doesn't support any extra special keys.
Use hid.c instead if there isn't any special reason to use this.
3.2 Event handlers
~~~~~~~~~~~~~~~~~~
- Event handlers distrubite the events from the devices to userland and
+ Event handlers distribute the events from the devices to userland and
kernel, as needed.
3.2.1 keybdev.c
~~~~~~~~~~~~~
Evdev is the generic input event interface. It passes the events generated
in the kernel straight to the program, with timestamps. The API is still
-evolving, but should be useable now. It's described in section 5.
+evolving, but should be usable now. It's described in section 5.
This should be the way for GPM and X to get keyboard and mouse mouse
events. It allows for multihead in X without any specific multihead kernel
You can test the joystick emulation with the 'jstest' utility, available
in the joystick package (see Documentation/joystick.txt).
- You can test the event devics with the 'evtest' utitily available on the
+ You can test the event devics with the 'evtest' utility available on the
input driver homepage (see the URL above).
5. Event interface
};
'time' is the timestamp, it returns the time at which the event happened.
-Type is for example EV_REL for relative momement, REL_KEY for a keypress or
+Type is for example EV_REL for relative movement, REL_KEY for a keypress or
release. More types are defined in include/linux/input.h.
'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete
The OHCI HCD layer is a simple but nearly complete implementation of what the
USB people would call a HCD for the OHCI.
- (ISO comming soon, Bulk, INT u. CTRL transfers enabled)
+ (ISO coming soon, Bulk, INT u. CTRL transfers enabled)
It is based on Linus Torvalds UHCI code and Gregory Smith OHCI fragments (0.03 source tree).
The layer (functions) on top of it, is for interfacing to the alternate-usb device-drivers.
- Endpoint Descriptor (ED) handling more static approach
(EDs should be allocated in parallel to the SET CONFIGURATION command and they live
- as long as the function (device) is alive or another configuration is choosen.
+ as long as the function (device) is alive or another configuration is chosen.
In the HCD layer the EDs has to be allocated manually either by calling a subroutine
or by sending a USB root hub vendor specific command to the virtual root hub.
At the alternate linux usb stack EDs will be added (allocated) at their first use.
- ED will be unlinked from the HC chains if they are not bussy.
+ ED will be unlinked from the HC chains if they are not busy.
files: ohci-hcd.c ohci-hcd.h
routines: (do not use for drivers, use the top layer alternate usb commands instead)
/proc/bus/usb filesystem output
===============================
-(version 2000.03.24)
+(version 2000.08.15)
The /proc filesystem for USB devices generates
one per line, with each driver's USB minor dev node
number range if applicable.
+**NOTE**: If /proc/bus/usb appears empty, you need
+ to mount the filesystem, issue the command (as root):
+
+ mount -t usbdevfs none /proc/bus/usb
+
+ An alternative and more permanent method would be to add
+
+ none /proc/bus/usb usbdevfs defaults 0 0
+
+ to /etc/fstab. This will mount usbdevfs at each reboot.
+ You can then issue `cat /proc/bus/usb/devices` to extract
+ USB device information.
+
+For more information on mounting the usbdevfs file system, see the
+"USB Device Filesystem" section of the USB Guide. The latest copy
+of the USB Guide can be found at http://www.linux-usb.org/
+
In /proc/bus/usb/devices, each device's output has multiple
lines of ASCII output.
I made it ASCII instead of binary on purpose, so that someone
S: SerialNumber=ssss
| |__Serial Number of this device as read from the device,
| except that it is a generated string for USB host controllers
-| (virtual root hubs), and represent's the host controller's
+| (virtual root hubs), and represents the host controller's
| unique identification in the system (currently I/O or
| memory-mapped base address).
|__String info tag
MESSAGES
-On occassion the message 'usb_control/bulk_msg: timeout' or something
+On occasions the message 'usb_control/bulk_msg: timeout' or something
similar will appear in '/var/adm/messages' or on the console or both,
depending on how your system is configured. This is a side effect
that scanners are sometimes very slow at warming up and/or
-initialiazing. In most cases, however, only several of these messages
+initializing. In most cases, however, only several of these messages
should appear and is generally considered to be normal. If you see
a message of the type 'excessive NAK's received' then this should
be considered abnormal and generally indicates that the USB system is
days (and nights) on the 16th and 17th of October 1999, now known as the
great USB-October-Revolution started by GA, DF, and TS ;-)
-Since the concept is in no way UHCI dependant, we hope that it will also be
+Since the concept is in no way UHCI dependent, we hope that it will also be
transfered to the OHCI-driver, so both drivers share a common API.
1.2. Advantages and disadvantages
1.4. What's really working?
-As said above, CTRL und BULK already work fine even with the wrappers,
+As said above, CTRL and BULK already work fine even with the wrappers,
so legacy code wouldn't notice the change.
Regarding to Thomas, ISO transfers now run stable with USB audio.
INT transfers (e.g. mouse driver) work fine, too.
affected, no atomic memory operation is required. The three QHs in the
common chain are never equipped with TDs!
-For ISO or INT, the TD for each frame is simply inserted into the apropriate
+For ISO or INT, the TD for each frame is simply inserted into the appropriate
ISO/INT-TD-chain for the desired frame. The 7 skeleton INT-TDs are scattered
among the 1024 frames similar to the old UHCI driver.
usb-help.txt
-2000-March-24
+2000-July-12
For USB help other than the readme files that are located in
linux/Documentation/usb/*, see the following:
Linux-USB project: http://www.linux-usb.org
mirrors at http://www.suse.cz/development/linux-usb/
and http://usb.in.tum.de/linux-usb/
-Linux USB Guide: http://linuxusbguide.sourceforge.net
+Linux USB Guide: http://linux-usb.sourceforge.net
Linux-USB device overview (working devices and drivers):
http://www.qbik.ch/usb/devices/
-The Linux-USB mailing list is linux-usb@suse.com .
+The Linux-USB mailing lists are:
+ linux-usb-users@lists.sourceforge.net for general user help
+ linux-usb-devel@lists.sourceforge.net for developer discussions
###
Current status:
The device's firmware is downloaded on connection, the new firmware
- runs properly and all four ports are successfuly recognized and connected.
- Now data flow needs to be implemented properly.
- This driver is not fully operational.
+ runs properly and all four ports are successfully recognized and connected.
+ Data can be sent and received through the device on all ports.
+ Hardware flow control needs to be implemented.
HandSpring Visor USB docking station
O_NONBLOCK, select()
+Keyspan USA-series Serial Adapters
+
+ Single and Dual port adapters - driver uses Keyspan supplied
+ firmware and is being developed with their support.
+
+ Driver isn't as far advanced as Keyspan PDA driver mentioned above.
+
+Current status:
+ Things that work:
+ Firmware upload for USA-18X, USA-28, USA-28X, USA-19 and USA-19W
+ Simple character I/O fixed at 9600 baud on USA-19 only
+
+ Things that don't:
+ Everything else. (for now...)
+
+ Big Things on the todo list:
+ Driver is in infancy, much functionality remains to be added
+
+
FTDI Single Port Serial Driver
This is a single port DB-25 serial adapter. More information about this
Digi AccelePort Driver
- This driver supports the Digi AccelePort USB 4 device, a 4 port
- USB serial converter. The driver does NOT yet support the Digi
- AccelePort USB 2 or 8.
+ This driver supports the Digi AccelePort USB 2 and 4 devices, 2 port
+ (plus a parallel port) and 4 port USB serial converters. The driver
+ does NOT yet support the Digi AccelePort USB 8.
- The driver supports open, close, read, write, termios settings (baud
- rate, word size, parity, stop bits, hardware/software flow control,
- CREAD), DTR/RTS, and TIOCMGET/SET/BIS/BIC ioctls. It has not been
- thoroughly tested, but it seems to be working reasonable well. There
- is more work to do, including flow control, ioctls, and support for
- the Digi AccelePort USB 2 and 8.
+ The driver is generally working, though we still have a few more ioctls
+ to implement and final testing and debugging to do. The paralled port
+ on the USB 2 is supported as a serial to parallel converter; in other
+ words, it appears as another USB serial port on Linux, even though
+ physically it is really a parallel port. The Digi Acceleport USB 8
+ is not yet supported.
Please contact Peter Berger (pberger@brimson.com) or Al Borchers
(alborchers@steinerpoint.com) for questions or problems with this
VERSION = 2
PATCHLEVEL = 2
SUBLEVEL = 18
-EXTRAVERSION = pre6
+EXTRAVERSION = pre7
ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
if (boot_cpu_data.x86 >= 6) break; /* Athlon and post-Athlon CPUs */
/* else fall through */
case X86_VENDOR_CENTAUR:
- return;
+ if(boot_cpu_data.x86 != 6)
+ return;
/*break;*/
}
/* Save value of CR4 and clear Page Global Enable (bit 7) */
{
case X86_VENDOR_AMD:
case X86_VENDOR_INTEL:
+ case X86_VENDOR_CENTAUR:
/* Disable MTRRs, and set the default type to uncached */
rdmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
wrmsr (MTRRdefType_MSR, ctxt->deftype_lo & 0xf300UL, ctxt->deftype_hi);
if (boot_cpu_data.x86 >= 6) break; /* Athlon and post-Athlon CPUs */
/* else fall through */
case X86_VENDOR_CENTAUR:
- __restore_flags (ctxt->flags);
- return;
+ if(boot_cpu_data.x86 != 6)
+ {
+ __restore_flags (ctxt->flags);
+ return;
+ }
/*break;*/
}
/* Flush caches and TLBs */
{
case X86_VENDOR_AMD:
case X86_VENDOR_INTEL:
+ case X86_VENDOR_CENTAUR:
wrmsr (MTRRdefType_MSR, ctxt->deftype_lo, ctxt->deftype_hi);
break;
case X86_VENDOR_CYRIX:
/* Cyrix have 8 ARRs */
case X86_VENDOR_CENTAUR:
/* and Centaur has 8 MCR's */
- return 8;
+ if(boot_cpu.x86==5)
+ return 8;
+ /* the cyrix III has intel compatible MTRR */
+ if(boot_cpu.x86==6)
+ {
+ rdmsr (MTRRcap_MSR, config, dummy);
+ return (config & 0xff);
+ }
/*break;*/
}
return 0;
case X86_VENDOR_AMD:
if (boot_cpu_data.x86 < 6) return 1; /* pre-Athlon CPUs */
/* else fall through */
+ case X86_VENDOR_CENTAUR:
+ if (boot_cpu_data.x86 == 5)
+ return 1; /* C6 */
+ /* CyrixIII is Intel like */
case X86_VENDOR_INTEL:
rdmsr (MTRRcap_MSR, config, dummy);
return (config & (1<<10));
printk ("mtrr: size: %lx base: %lx\n", size, base);
return -EINVAL;
}
- if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR)
+ if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR && boot_cpu_data.x86 == 5)
{
if (centaur_ctx->type_bits[type]==0) {
printk ("mtrr: type not supported\n");
get_free_region = cyrix_get_free_region;
break;
case X86_VENDOR_CENTAUR:
- get_mtrr = centaur_get_mcr;
- set_mtrr_up = centaur_set_mcr_up;
+ if(boot_cpu_data.x86 == 5)
+ {
+ get_mtrr = centaur_get_mcr;
+ set_mtrr_up = centaur_set_mcr_up;
+ }
+ if(boot_cpu_data.x86 == 6)
+ {
+ get_mtrr = intel_get_mtrr;
+ set_mtrr_up = intel_set_mtrr_up;
+ }
break;
}
} /* End Function mtrr_setup */
case X86_VENDOR_CYRIX:
cyrix_arr_init ();
break;
- case X86_VENDOR_CENTAUR:
- centaur_mcr_init ();
+ case X86_VENDOR_CENTAUR: /* C6 and Cyrix III have different ones */
+ if(boot_cpu_data.x86 == 5)
+ centaur_mcr_init ();
+ if(boot_cpu_data.x86 == 6)
+ get_mtrr_state(&smp_mtrr_state);
break;
}
} /* End Function mtrr_init_boot_cpu */
cyrix_arr_init ();
break;
case X86_VENDOR_CENTAUR:
- centaur_mcr_init ();
+ if(boot_cpu_data.x86 == 5)
+ centaur_mcr_init ();
break;
}
# endif /* !__SMP__ */
*
* Transmeta CPU detection. H. Peter Anvin <hpa@zytor.com>, May 2000
*
- * Cleaned up get_model_name(), AMD_model(), added display_cacheinfo().
- * Dave Jones <davej@suse.de>, September 2000
+ * Cleaned up get_model_name(), AMD_model(), added display_cacheinfo().
+ * Dave Jones <davej@suse.de>, September 2000
+ *
+ * Added Cyrix III initial detection code
+ * Alan Cox <alan@redhat.com>, Septembr 2000
*/
/*
/*
* Actually we must have cpuid or we could never have
- * figured out that this was AMD/Cyrix/Transmeta
+ * figured out that this was AMD/Centaur/Cyrix/Transmeta
* from the vendor info :-).
*/
c->x86_cache_size=(ecx>>24)+(edx>>24);
}
+ /* Yes this can occur - the CyrixIII just has a large L1 */
if (n < 0x80000006)
return; /* No function to get L2 info */
transmeta_model(c);
return;
}
+
+ if(c->x86_vendor == X86_VENDOR_CENTAUR && c->x86==6)
+ {
+ /* The Cyrix III supports model naming and cache queries */
+ get_model_name(c);
+ display_cacheinfo(c);
+ return;
+ }
if (c->cpuid_level > 1) {
/* supports eax=2 call */
"Intel", "Cyrix", "AMD", "UMC", "NexGen", "Centaur", "Rise", "Transmeta" };
+__initfunc(void setup_centaur(struct cpuinfo_x86 *c))
+{
+ u32 hv,lv;
+
+ /* Centaur C6 Series */
+ if(c->x86==5)
+ {
+ rdmsr(0x107, lv, hv);
+ printk("Centaur FSR was 0x%X ",lv);
+ lv|=(1<<1 | 1<<2 | 1<<7);
+ /* lv|=(1<<6); - may help too if the board can cope */
+ printk("now 0x%X\n", lv);
+ wrmsr(0x107, lv, hv);
+ /* Emulate MTRRs using Centaur's MCR. */
+ c->x86_capability |= X86_FEATURE_MTRR;
+
+ /* Disable TSC on C6 as per errata. */
+ if (c->x86_model ==4) {
+ printk ("Disabling bugged TSC.\n");
+ c->x86_capability &= ~X86_FEATURE_TSC;
+ }
+
+ /* Set 3DNow! on Winchip 2 and above. */
+ if (c->x86_model >=8)
+ c->x86_capability |= X86_FEATURE_AMD3D;
+
+ c->x86_capability |=X86_FEATURE_CX8;
+ }
+ /* Cyrix III 'Samuel' CPU */
+ if(c->x86 == 6 && c->x86_model == 6)
+ {
+ rdmsr(0x1107, lv, hv);
+ lv|=(1<<1); /* Report CX8 */
+ lv|=(1<<7); /* PGE enable */
+ wrmsr(0x1107, lv, hv);
+ /* Cyrix III */
+ c->x86_capability |= X86_FEATURE_CX8;
+ rdmsr(0x80000001, lv, hv);
+ if(hv&(1<<31))
+ c->x86_capability |= X86_FEATURE_AMD3D;
+ }
+}
+
__initfunc(void print_cpu_info(struct cpuinfo_x86 *c))
{
char *vendor = NULL;
printk("\n");
if(c->x86_vendor == X86_VENDOR_CENTAUR) {
- u32 hv,lv;
- rdmsr(0x107, lv, hv);
- printk("Centaur FSR was 0x%X ",lv);
- lv|=(1<<1 | 1<<2 | 1<<7);
- /* lv|=(1<<6); - may help too if the board can cope */
- printk("now 0x%X\n", lv);
- wrmsr(0x107, lv, hv);
- /* Emulate MTRRs using Centaur's MCR. */
- c->x86_capability |= X86_FEATURE_MTRR;
-
- /* Disable TSC on C6 as per errata. */
- if (c->x86_model ==4) {
- printk ("Disabling bugged TSC.\n");
- c->x86_capability &= ~X86_FEATURE_TSC;
- }
-
- /* Set 3DNow! on Winchip 2 and above. */
- if (c->x86_model >=8)
- c->x86_capability |= X86_FEATURE_AMD3D;
-
- c->x86_capability |=X86_FEATURE_CX8;
+ setup_centaur(c);
}
}
-/* $Id: srmmu.c,v 1.187.2.9 2000/03/05 17:39:18 davem Exp $
+/* $Id: srmmu.c,v 1.187.2.10 2000/09/07 04:44:48 davem Exp $
* srmmu.c: SRMMU specific routines for memory management.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
goto done;
inode = file->f_dentry->d_inode;
offset = (address & PAGE_MASK) - vma->vm_start;
- vmaring = inode->i_mmap;
- do {
+ vmaring = inode->i_mmap_shared;
+ if (vmaring) do {
/* Do not mistake ourselves as another mapping. */
if(vmaring == vma)
continue;
-/* $Id: sun4c.c,v 1.173.2.5 1999/10/11 08:24:44 davem Exp $
+/* $Id: sun4c.c,v 1.173.2.6 2000/09/07 04:44:48 davem Exp $
* sun4c.c: Doing in software what should be done in hardware.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
inode = dentry->d_inode;
if (inode) {
unsigned long offset = (address & PAGE_MASK) - vma->vm_start;
- struct vm_area_struct *vmaring = inode->i_mmap;
+ struct vm_area_struct *vmaring = inode->i_mmap_shared;
int alias_found = 0;
- do {
+ if (vmaring) do {
unsigned long vaddr = vmaring->vm_start + offset;
unsigned long start;
-/* $Id: entry.S,v 1.103.2.5 2000/03/06 22:30:22 davem Exp $
+/* $Id: entry.S,v 1.103.2.6 2000/09/08 14:00:04 jj Exp $
* arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points.
*
* Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
1: b,pt %xcc, ret_sys_call
ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
-sparc_exit: rdpr %otherwin, %g1
- rdpr %pstate, %g2
+sparc_exit: rdpr %pstate, %g2
wrpr %g2, PSTATE_IE, %pstate
+ rdpr %otherwin, %g1
rdpr %cansave, %g3
add %g3, %g1, %g3
wrpr %g3, 0x0, %cansave
#define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "Compaq SMART2 Driver (v 1.0.9)"
-#define DRIVER_VERSION SMART2_DRIVER_VERSION(1,0,9)
+#define DRIVER_NAME "Compaq SMART2 Driver (v 1.0.10)"
+#define DRIVER_VERSION SMART2_DRIVER_VERSION(1,0,10)
+
+/* Embedded module documentation macros - see modules.h */
+/* Original author Chris Frantz - Compaq Computer Corporation */
+MODULE_AUTHOR("Compaq Computer Corporation");
+MODULE_DESCRIPTION("Driver for Compaq Smart2 Array Controllers");
+
#define MAJOR_NR COMPAQ_SMART2_MAJOR
#include <linux/blk.h>
#include <linux/blkdev.h>
int i;
+ c->pci_bus = bus;
+ c->pci_dev_fn = device_fn;
pdev = pci_find_slot(bus, device_fn);
vendor_id = pdev->vendor;
device_id = pdev->device;
c->vaddr = remap_pci_mem(c->paddr, 128);
c->board_id = board_id;
+
for(i=0; i<NR_PRODUCTS; i++) {
if (board_id == products[i].board_id) {
c->product_name = products[i].product_name;
hba[nr_ctlr]->access = *(products[j].access);
hba[nr_ctlr]->ctlr = nr_ctlr;
hba[nr_ctlr]->board_id = board_id;
+ hba[nr_ctlr]->pci_bus = 0; /* not PCI */
+ hba[nr_ctlr]->pci_dev_fn = 0; /* not PCI */
DBGINFO(
printk("i = %d, j = %d\n", i, j);
if (!arg) return -EINVAL;
put_user(DRIVER_VERSION, (unsigned long*)arg);
return 0;
+ case IDAGETPCIINFO:
+ {
+
+ ida_pci_info_struct pciinfo;
+ if (!arg) return -EINVAL;
+ pciinfo.bus = hba[ctlr]->pci_bus;
+ pciinfo.dev_fn = hba[ctlr]->pci_dev_fn;
+ pciinfo.board_id = hba[ctlr]->board_id;
+ copy_to_user_ret((void *) arg, &pciinfo,
+ sizeof( ida_pci_info_struct), -EFAULT);
+ return(0);
+ }
+
RO_IOCTLS(inode->i_rdev, arg);
default:
int log_drives;
int phys_drives;
+ unsigned char pci_bus; /* 0 if EISA */
+ unsigned char pci_dev_fn; /* 0 if EISA */
__u32 board_id;
char *product_name;
#define IDAGETCTLRSIG 0x29293030
#define IDAREVALIDATEVOLS 0x30303131
#define IDADRIVERVERSION 0x31313232
+#define IDAGETPCIINFO 0x32323333
+typedef struct _ida_pci_info_struct
+{
+ unsigned char bus;
+ unsigned char dev_fn;
+ __u32 board_id;
+} ida_pci_info_struct;
/*
* Normally, the ioctl determines the logical unit for this command by
* the major,minor number of the fd passed to ioctl. If you need to send
union ctlr_cmds {
drv_info_t drv;
- unsigned char buf[512];
+ unsigned char buf[1024];
id_ctlr_t id_ctlr;
drv_param_t drv_param;
hex ' Aztech/Packard Bell I/O port (0x350 or 0x358)' CONFIG_RADIO_AZTECH_PORT 350
fi
dep_tristate 'ADS Cadet AM/FM Tuner' CONFIG_RADIO_CADET $CONFIG_VIDEO_DEV
- dep_tristate 'Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV
dep_tristate 'GemTek Radio Card support' CONFIG_RADIO_GEMTEK $CONFIG_VIDEO_DEV
if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then
hex ' GemTek i/o port (0x20c, 0x24c, 0x248, 0x30c, or 0x34c)' CONFIG_RADIO_GEMTEK_PORT 34c
fi
+ dep_tristate 'Maestro on board radio' CONFIG_RADIO_MAESTRO $CONFIG_VIDEO_DEV
+ dep_tristate 'Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV
dep_tristate 'Trust FM Radio' CONFIG_RADIO_TRUST $CONFIG_VIDEO_DEV
if [ "$CONFIG_RADIO_TRUST" = "y" ]; then
hex ' Trust FM Radio I/O port (0x350 or 0x358)' CONFIG_RADIO_TRUST_PORT 350
endif
ifeq ($(CONFIG_INTEL_RNG),y)
-L_OBJS += i810_rng.o
+O_OBJS += i810_rng.o
else
ifeq ($(CONFIG_INTEL_RNG),m)
M_OBJS += i810_rng.o
endif
endif
+ifeq ($(CONFIG_RADIO_MAESTRO),y)
+O_OBJS += radio-maestro.o
+else
+ ifeq ($(CONFIG_RADIO_MAESTRO),m)
+ M_OBJS += radio-maestro.o
+ endif
+endif
+
ifeq ($(CONFIG_RADIO_GEMTEK),y)
O_OBJS += radio-gemtek.o
else
--- /dev/null
+/* Maestro PCI sound card radio driver for Linux support
+ * (c) 2000 A. Tlalka, atlka@pg.gda.pl
+ * Notes on the hardware
+ *
+ * + Frequency control is done digitally
+ * + No volume control - only mute/unmute - you have to use Aux line volume
+ * control on Maestro card to set the volume
+ * + Radio status (tuned/not_tuned and stereo/mono) is valid some time after
+ * frequency setting (>100ms) and only when the radio is unmuted.
+ * version 0.02
+ * + io port is automatically detected - only the first radio is used
+ * version 0.03
+ * + thread access locking additions
+ * version 0.04
+ * + code improvements
+ * + VIDEO_TUNER_LOW is permanent
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+#include <linux/pci.h>
+#include <linux/videodev.h>
+
+#define DRIVER_VERSION "0.04"
+
+#define PCI_VENDOR_ESS 0x125D
+#define PCI_DEVICE_ID_ESS_ESS1968 0x1968 /* Maestro 2 */
+#define PCI_DEVICE_ID_ESS_ESS1978 0x1978 /* Maestro 2E */
+
+#define GPIO_DATA 0x60 /* port offset from ESS_IO_BASE */
+
+#define IO_MASK 4 /* mask register offset from GPIO_DATA
+ bits 1=unmask write to given bit */
+#define IO_DIR 8 /* direction register offset from GPIO_DATA
+ bits 0/1=read/write direction */
+
+#define GPIO6 0x0040 /* mask bits for GPIO lines */
+#define GPIO7 0x0080
+#define GPIO8 0x0100
+#define GPIO9 0x0200
+
+#define STR_DATA GPIO6 /* radio TEA5757 pins and GPIO bits */
+#define STR_CLK GPIO7
+#define STR_WREN GPIO8
+#define STR_MOST GPIO9
+
+#define FREQ_LO 50*16000
+#define FREQ_HI 150*16000
+
+#define FREQ_IF 171200 /* 10.7*16000 */
+#define FREQ_STEP 200 /* 12.5*16 */
+
+#define FREQ2BITS(x) ((((unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1))\
+ /(FREQ_STEP<<2))<<2) /* (x==fmhz*16*1000) -> bits */
+
+#define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF)
+
+
+
+static int radio_open(struct video_device *, int);
+static int radio_ioctl(struct video_device *, unsigned int, void *);
+static void radio_close(struct video_device *);
+
+static struct video_device maestro_radio=
+{
+ "Maestro radio",
+ VID_TYPE_TUNER,
+ VID_HARDWARE_SF16MI,
+ radio_open,
+ radio_close,
+ NULL,
+ NULL,
+ NULL,
+ radio_ioctl,
+ NULL,
+ NULL
+};
+
+static struct radio_device
+{
+ __u16 io, /* base of Maestro card radio io (GPIO_DATA)*/
+ muted, /* VIDEO_AUDIO_MUTE */
+ stereo, /* VIDEO_TUNER_STEREO_ON */
+ tuned; /* signal strength (0 or 0xffff) */
+ struct semaphore lock;
+} radio_unit = {0, 0, 0, 0, MUTEX};
+
+static int users = 0;
+
+static void sleep_125ms(void)
+{
+ current->state = TASK_INTERRUPTIBLE;
+ schedule_timeout(HZ >> 3);
+}
+
+static void udelay2(void)
+{
+ udelay(2);
+}
+
+static void udelay4(void)
+{
+ udelay(4);
+}
+
+static void udelay16(void)
+{
+ udelay(16);
+}
+
+static __u32 radio_bits_get(struct radio_device *dev)
+{
+ register __u16 io=dev->io, l, rdata;
+ register __u32 data=0;
+ __u16 omask;
+ omask = inw(io + IO_MASK);
+ outw(~(STR_CLK | STR_WREN), io + IO_MASK);
+ outw(0, io);
+ udelay16();
+ for (l=24;l--;) {
+ outw(STR_CLK, io); /* HI state */
+ udelay2();
+ if(!l)
+ dev->tuned = inw(io) & STR_MOST ? 0 : 0xffff;
+ outw(0, io); /* LO state */
+ udelay2();
+ data <<= 1; /* shift data */
+ rdata = inw(io);
+ if(!l)
+ dev->stereo = rdata & STR_MOST ?
+ 0 : VIDEO_TUNER_STEREO_ON;
+ else
+ if(rdata & STR_DATA)
+ data++;
+ udelay2();
+ }
+ if(dev->muted)
+ outw(STR_WREN, io);
+ udelay4();
+ outw(omask, io + IO_MASK);
+ return data & 0x3ffe;
+}
+
+static void radio_bits_set(struct radio_device *dev, __u32 data)
+{
+ register __u16 io=dev->io, l, bits;
+ __u16 omask, odir;
+ omask = inw(io + IO_MASK);
+ odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN);
+ outw(odir | STR_DATA, io + IO_DIR);
+ outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK);
+ udelay16();
+ for (l=25;l;l--) {
+ bits = ((data >> 18) & STR_DATA) | STR_WREN ;
+ data <<= 1; /* shift data */
+ outw(bits, io); /* start strobe */
+ udelay2();
+ outw(bits | STR_CLK, io); /* HI level */
+ udelay2();
+ outw(bits, io); /* LO level */
+ udelay4();
+ }
+ if(!dev->muted)
+ outw(0, io);
+ udelay4();
+ outw(omask, io + IO_MASK);
+ outw(odir, io + IO_DIR);
+ sleep_125ms();
+}
+
+inline static int radio_function(struct video_device *dev,
+ unsigned int cmd, void *arg)
+{
+ struct radio_device *card=dev->priv;
+ switch(cmd) {
+ case VIDIOCGCAP: {
+ struct video_capability v;
+ strcpy(v.name, "Maestro radio");
+ v.type=VID_TYPE_TUNER;
+ v.channels=v.audios=1;
+ v.maxwidth=v.maxheight=v.minwidth=v.minheight=0;
+ if(copy_to_user(arg,&v,sizeof(v)))
+ return -EFAULT;
+ return 0;
+ }
+ case VIDIOCGTUNER: {
+ struct video_tuner v;
+ if(copy_from_user(&v, arg,sizeof(v))!=0)
+ return -EFAULT;
+ if(v.tuner)
+ return -EINVAL;
+ (void)radio_bits_get(card);
+ v.flags = VIDEO_TUNER_LOW | card->stereo;
+ v.signal = card->tuned;
+ strcpy(v.name, "FM");
+ v.rangelow = FREQ_LO;
+ v.rangehigh = FREQ_HI;
+ v.mode = VIDEO_MODE_AUTO;
+ if(copy_to_user(arg,&v, sizeof(v)))
+ return -EFAULT;
+ return 0;
+ }
+ case VIDIOCSTUNER: {
+ struct video_tuner v;
+ if(copy_from_user(&v, arg, sizeof(v)))
+ return -EFAULT;
+ if(v.tuner!=0)
+ return -EINVAL;
+ return 0;
+ }
+ case VIDIOCGFREQ: {
+ unsigned long tmp=BITS2FREQ(radio_bits_get(card));
+ if(copy_to_user(arg, &tmp, sizeof(tmp)))
+ return -EFAULT;
+ return 0;
+ }
+ case VIDIOCSFREQ: {
+ unsigned long tmp;
+ if(copy_from_user(&tmp, arg, sizeof(tmp)))
+ return -EFAULT;
+ if ( tmp<FREQ_LO || tmp>FREQ_HI )
+ return -EINVAL;
+ radio_bits_set(card, FREQ2BITS(tmp));
+ return 0;
+ }
+ case VIDIOCGAUDIO: {
+ struct video_audio v;
+ strcpy(v.name, "Radio");
+ v.audio=v.volume=v.bass=v.treble=v.balance=v.step=0;
+ v.flags=VIDEO_AUDIO_MUTABLE | card->muted;
+ v.mode=VIDEO_SOUND_STEREO;
+ if(copy_to_user(arg,&v, sizeof(v)))
+ return -EFAULT;
+ return 0;
+ }
+ case VIDIOCSAUDIO: {
+ struct video_audio v;
+ if(copy_from_user(&v, arg, sizeof(v)))
+ return -EFAULT;
+ if(v.audio)
+ return -EINVAL;
+ {
+ register __u16 io=card->io;
+ register __u16 omask = inw(io + IO_MASK);
+ outw(~STR_WREN, io + IO_MASK);
+ outw((card->muted = v.flags & VIDEO_AUDIO_MUTE)
+ ? STR_WREN : 0, io);
+ udelay4();
+ outw(omask, io + IO_MASK);
+ sleep_125ms();
+ return 0;
+ }
+ }
+ case VIDIOCGUNIT: {
+ struct video_unit v;
+ v.video=VIDEO_NO_UNIT;
+ v.vbi=VIDEO_NO_UNIT;
+ v.radio=dev->minor;
+ v.audio=0;
+ v.teletext=VIDEO_NO_UNIT;
+ if(copy_to_user(arg, &v, sizeof(v)))
+ return -EFAULT;
+ return 0;
+ }
+ default: return -ENOIOCTLCMD;
+ }
+}
+
+static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+ struct radio_device *card=dev->priv;
+ int ret;
+ down(&card->lock);
+ ret = radio_function(dev, cmd, arg);
+ up(&card->lock);
+ return ret;
+}
+
+static int radio_open(struct video_device *dev, int flags)
+{
+ if(users)
+ return -EBUSY;
+ users++;
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+static void radio_close(struct video_device *dev)
+{
+ users--;
+ MOD_DEC_USE_COUNT;
+}
+
+
+inline static __u16 radio_install(struct pci_dev *pcidev);
+
+#ifdef MODULE
+MODULE_AUTHOR("Adam Tlalka, atlka@pg.gda.pl");
+MODULE_DESCRIPTION("Radio driver for the Maestro PCI sound card radio.");
+
+EXPORT_NO_SYMBOLS;
+
+void cleanup_module(void)
+{
+ video_unregister_device(&maestro_radio);
+}
+
+int init_module(void)
+#else
+__initfunc(int maestro_radio_init(struct video_init *v))
+#endif
+{
+ register __u16 found=0;
+ struct pci_dev *pcidev = NULL;
+ if(!pci_present())
+ return -ENODEV;
+ while(!found && (pcidev = pci_find_device(PCI_VENDOR_ESS,
+ PCI_DEVICE_ID_ESS_ESS1968,
+ pcidev)))
+ found |= radio_install(pcidev);
+ while(!found && (pcidev = pci_find_device(PCI_VENDOR_ESS,
+ PCI_DEVICE_ID_ESS_ESS1978,
+ pcidev)))
+ found |= radio_install(pcidev);
+ if(!found) {
+ printk(KERN_INFO "radio-maestro: no devices found.\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+inline static __u16 radio_power_on(struct radio_device *dev)
+{
+ register __u16 io=dev->io;
+ register __u32 ofreq;
+ __u16 omask, odir;
+ omask = inw(io + IO_MASK);
+ odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN);
+ outw(odir & ~STR_WREN, io + IO_DIR);
+ dev->muted = inw(io) & STR_WREN ? 0 : VIDEO_AUDIO_MUTE;
+ outw(odir, io + IO_DIR);
+ outw(~(STR_WREN | STR_CLK), io + IO_MASK);
+ outw(dev->muted ? 0 : STR_WREN, io);
+ udelay16();
+ outw(omask, io + IO_MASK);
+ ofreq = radio_bits_get(dev);
+ if((ofreq<FREQ2BITS(FREQ_LO)) || (ofreq>FREQ2BITS(FREQ_HI)))
+ ofreq = FREQ2BITS(FREQ_LO);
+ radio_bits_set(dev, ofreq);
+ return (ofreq == radio_bits_get(dev));
+}
+
+inline static __u16 radio_install(struct pci_dev *pcidev)
+{
+ if(((pcidev->class >> 8) & 0xffff) != PCI_CLASS_MULTIMEDIA_AUDIO)
+ return 0;
+
+ radio_unit.io = (pcidev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK)
+ + GPIO_DATA;
+ maestro_radio.priv = &radio_unit;
+ if(radio_power_on(&radio_unit)) {
+ if(video_register_device(&maestro_radio, VFL_TYPE_RADIO)==-1) {
+ printk("radio-maestro: can't register device!");
+ return 0;
+ }
+ printk(KERN_INFO "radio-maestro: version "
+ DRIVER_VERSION
+ " time "
+ __TIME__ " "
+ __DATE__
+ "\n");
+ printk(KERN_INFO "radio-maestro: radio chip initialized\n");
+ return 1;
+ } else
+ return 0;
+}
+
#define WD_TIMO (100*60) /* 1 minute */
-#ifndef MODULE
-
-/**
- * wdtpci_setup:
- * @str: command line string
- *
- * Setup options. The board isn't really probe-able so we have to
- * get the user to tell us the configuration. Sane people build it
- * modular but the others come here.
- */
-
-static int __init wdtpci_setup(char *str)
-{
- int ints[4];
-
- str = get_options (str, ARRAY_SIZE(ints), ints);
-
- if (ints[0] > 0)
- {
- io = ints[1];
- if(ints[0] > 1)
- irq = ints[2];
- }
-
- return 1;
-}
-
-__setup("wdt=", wdtpci_setup);
-
-#endif /* !MODULE */
-
/*
* Programming support
*/
static int kiss_esc_crc(unsigned char *s, unsigned char *d, unsigned short crc, int len)
{
unsigned char *ptr = d;
- unsigned char c;
+ unsigned char c=0;
*ptr++ = END;
while (len > 0) {
sppp_ipcp_open (sp);
break;
case LCP_STATE_OPENED:
-#if 0
/* Remote magic changed -- close session. */
sp->lcp.state = LCP_STATE_CLOSED;
sp->ipcp.state = IPCP_STATE_CLOSED;
sppp_lcp_open (sp);
/* An ACK has already been sent. */
sp->lcp.state = LCP_STATE_ACK_SENT;
-#endif
break;
}
break;
sp->lcp.magic += newmagic;
} else
sp->lcp.magic = rmagic;
- }
+ }
if (sp->lcp.state != LCP_STATE_ACK_SENT) {
/* Go to closed state. */
sp->lcp.state = LCP_STATE_CLOSED;
remove_proc_entry("config", megaCfg->controller_proc_dir_entry);
remove_proc_entry("mailbox", megaCfg->controller_proc_dir_entry);
for (i = 0; i < numCtlrs; i++) {
- char buf[12] ={0};
+ char buf[12];
+ memset(buf,0,12);
sprintf(buf,"%d",i);
remove_proc_entry(buf,mega_proc_dir_entry);
}
dep_tristate 'Crystal CS4281' CONFIG_SOUND_CS4281 $CONFIG_SOUND
dep_tristate 'Crystal SoundFusion (CS4280/461x)' CONFIG_SOUND_FUSION $CONFIG_SOUND
-dep_tristate 'Creative SBLive! (EMU10K1)' CONFIG_SOUND_EMU10K1 $CONFIG_SOUND
+if [ "$CONFIG_PCI" = "y" ]; then
+ dep_tristate 'Creative SBLive! (EMU10K1)' CONFIG_SOUND_EMU10K1 $CONFIG_SOUND
+fi
dep_tristate 'Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND
if [ "$CONFIG_SOUND_ES1370" = "y" ]; then
bool 'Joystick support at boot time' CONFIG_SOUND_ES1370_JOYPORT_BOOT
dep_tristate ' Microtek X6USB scanner support (EXPERIMENTAL)' CONFIG_USB_MICROTEK $CONFIG_SCSI
dep_tristate ' USB Bluetooth support (EXPERIMENTAL)' CONFIG_USB_BLUETOOTH $CONFIG_USB
fi
- dep_tristate ' Kawasaki USB-ethernet controller' CONFIG_USB_KAWETH $CONFIG_USB
+ if [ "$CONFIG_NET" = "y" ]; then
+ dep_tristate ' Kawasaki USB-ethernet controller' CONFIG_USB_KAWETH $CONFIG_USB
+ fi
comment 'USB HID'
dep_tristate ' USB Human Interface Device (HID) support' CONFIG_USB_HID $CONFIG_USB
extern struct list_head usb_driver_list;
+#if 0
static int finddriver(struct usb_driver **driver, char *name)
{
struct list_head *tmp;
return -EINVAL;
}
+#endif
/*
* file operations
unsigned char *tbuf;
int i, ret;
- copy_from_user_ret(&ctrl, (void *)arg, sizeof(ctrl), -EFAULT);
+ if (copy_from_user(&ctrl, (void *)arg, sizeof(ctrl)))
+ return -EFAULT;
switch (ctrl.requesttype & 0x1f) {
case USB_RECIP_ENDPOINT:
if ((ret = findintfep(ps->dev, ctrl.index & 0xff)) < 0)
i = my_usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
ctrl.value, ctrl.index, tbuf, ctrl.length, tmo);
if ((i > 0) && ctrl.length) {
- copy_to_user_ret(ctrl.data, tbuf, ctrl.length, -EFAULT);
+ if (copy_to_user(ctrl.data, tbuf, ctrl.length))
+ return -EFAULT;
}
} else {
if (ctrl.length) {
- copy_from_user_ret(tbuf, ctrl.data, ctrl.length, -EFAULT);
+ if (copy_from_user(tbuf, ctrl.data, ctrl.length))
+ return -EFAULT;
}
i = my_usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.request, ctrl.requesttype,
ctrl.value, ctrl.index, tbuf, ctrl.length, tmo);
unsigned char *tbuf;
int i, ret;
- copy_from_user_ret(&bulk, (void *)arg, sizeof(bulk), -EFAULT);
+ if (copy_from_user(&bulk, (void *)arg, sizeof(bulk)))
+ return -EFAULT;
if ((ret = findintfep(ps->dev, bulk.ep)) < 0)
return ret;
if ((ret = checkintf(ps, ret)))
}
i = my_usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
if (!i && len2) {
- copy_to_user_ret(bulk.data, tbuf, len2, -EFAULT);
+ if (copy_to_user(bulk.data, tbuf, len2))
+ return -EFAULT;
}
} else {
if (len1) {
- copy_from_user_ret(tbuf, bulk.data, len1, -EFAULT);
+ if (copy_from_user(tbuf, bulk.data, len1))
+ return -EFAULT;
}
i = my_usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
}
unsigned int ep;
int ret;
- get_user_ret(ep, (unsigned int *)arg, -EFAULT);
+ if (get_user(ep, (unsigned int *)arg))
+ return -EFAULT;
if ((ret = findintfep(ps->dev, ep)) < 0)
return ret;
if ((ret = checkintf(ps, ret)))
return 0;
}
+static int proc_clearhalt(struct dev_state *ps, void *arg)
+{
+ unsigned int ep;
+ int pipe;
+ int ret;
+
+ if (get_user(ep, (unsigned int *)arg))
+ return -EFAULT;
+ if ((ret = findintfep(ps->dev, ep)) < 0)
+ return ret;
+ if ((ret = checkintf(ps, ret)))
+ return ret;
+ if (ep & USB_DIR_IN)
+ pipe = usb_rcvbulkpipe(ps->dev, ep & 0x7f);
+ else
+ pipe = usb_sndbulkpipe(ps->dev, ep & 0x7f);
+
+ return usb_clear_halt(ps->dev, pipe);
+}
+
static int proc_getdriver(struct dev_state *ps, void *arg)
{
struct usbdevfs_getdriver gd;
struct usb_interface *interface;
int ret;
- copy_from_user_ret(&gd, arg, sizeof(gd), -EFAULT);
+ if (copy_from_user(&gd, arg, sizeof(gd)))
+ return -EFAULT;
if ((ret = findintfif(ps->dev, gd.interface)) < 0)
return ret;
interface = usb_ifnum_to_if(ps->dev, gd.interface);
if (!interface->driver)
return -ENODATA;
strcpy(gd.driver, interface->driver->name);
- copy_to_user_ret(arg, &gd, sizeof(gd), -EFAULT);
+ if (copy_to_user(arg, &gd, sizeof(gd)))
+ return -EFAULT;
return 0;
}
ci.devnum = ps->dev->devnum;
ci.slow = ps->dev->slow;
- copy_to_user_ret(arg, &ci, sizeof(ci), -EFAULT);
+ if (copy_to_user(arg, &ci, sizeof(ci)))
+ return -EFAULT;
return 0;
}
struct usb_interface *interface;
int ret;
- copy_from_user_ret(&setintf, arg, sizeof(setintf), -EFAULT);
+ if (copy_from_user(&setintf, arg, sizeof(setintf)))
+ return -EFAULT;
if ((ret = findintfif(ps->dev, setintf.interface)) < 0)
return ret;
interface = usb_ifnum_to_if(ps->dev, setintf.interface);
{
unsigned int u;
- get_user_ret(u, (unsigned int *)arg, -EFAULT);
+ if (get_user(u, (unsigned int *)arg))
+ return -EFAULT;
if (usb_set_configuration(ps->dev, u) < 0)
return -EINVAL;
return 0;
unsigned int u, totlen, isofrmlen;
int ret;
- copy_from_user_ret(&uurb, arg, sizeof(uurb), -EFAULT);
+ if (copy_from_user(&uurb, arg, sizeof(uurb)))
+ return -EFAULT;
if (uurb.flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_DISABLE_SPD))
return -EINVAL;
if (!uurb.buffer)
if (as->userbuffer)
if (copy_to_user(as->userbuffer, as->urb.transfer_buffer, as->urb.transfer_buffer_length))
return -EFAULT;
- put_user_ret(as->urb.status, &((struct usbdevfs_urb *)as->userurb)->status, -EFAULT);
- put_user_ret(as->urb.actual_length, &((struct usbdevfs_urb *)as->userurb)->actual_length, -EFAULT);
- put_user_ret(as->urb.error_count, &((struct usbdevfs_urb *)as->userurb)->error_count, -EFAULT);
+ if (put_user(as->urb.status,
+ &((struct usbdevfs_urb *)as->userurb)->status) ||
+ __put_user(as->urb.actual_length,
+ &((struct usbdevfs_urb *)as->userurb)->actual_length) ||
+ __put_user(as->urb.error_count,
+ &((struct usbdevfs_urb *)as->userurb)->error_count))
+ return -EFAULT;
if (!(usb_pipeisoc(as->urb.pipe)))
return 0;
for (i = 0; i < as->urb.number_of_packets; i++) {
- put_user_ret(as->urb.iso_frame_desc[i].actual_length,
- &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].actual_length,
- -EFAULT);
- put_user_ret(as->urb.iso_frame_desc[i].status,
- &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].status,
- -EFAULT);
+ if (put_user(as->urb.iso_frame_desc[i].actual_length,
+ &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].actual_length) ||
+ __put_user(as->urb.iso_frame_desc[i].status,
+ &((struct usbdevfs_urb *)as->userurb)->iso_frame_desc[i].status))
+ return -EFAULT;
}
return 0;
}
free_async(as);
if (ret)
return ret;
- put_user_ret(addr, (void **)arg, -EFAULT);
+ if (put_user(addr, (void **)arg))
+ return -EFAULT;
return 0;
}
if (signal_pending(current))
free_async(as);
if (ret)
return ret;
- put_user_ret(addr, (void **)arg, -EFAULT);
+ if (put_user(addr, (void **)arg))
+ return -EFAULT;
return 0;
}
{
struct usbdevfs_disconnectsignal ds;
- copy_from_user_ret(&ds, arg, sizeof(ds), -EFAULT);
+ if (copy_from_user(&ds, arg, sizeof(ds)))
+ return -EFAULT;
if (ds.signr != 0 && (ds.signr < SIGRTMIN || ds.signr > SIGRTMAX))
return -EINVAL;
ps->discsignr = ds.signr;
unsigned int intf;
int ret;
- get_user_ret(intf, (unsigned int *)arg, -EFAULT);
+ if (get_user(intf, (unsigned int *)arg))
+ return -EFAULT;
if ((ret = findintfif(ps->dev, intf)) < 0)
return ret;
return claimintf(ps, ret);
unsigned int intf;
int ret;
- get_user_ret(intf, (unsigned int *)arg, -EFAULT);
+ if (get_user(intf, (unsigned int *)arg))
+ return -EFAULT;
if ((ret = findintfif(ps->dev, intf)) < 0)
return ret;
return releaseintf(ps, intf);
int retval = 0;
/* get input parameters and alloc buffer */
- copy_from_user_ret (&ctrl, (void *) arg, sizeof (ctrl), -EFAULT);
+ if (copy_from_user (&ctrl, (void *) arg, sizeof (ctrl)))
+ return -EFAULT;
if ((size = _IOC_SIZE (ctrl.ioctl_code)) > 0) {
if ((buf = kmalloc (size, GFP_KERNEL)) == 0)
return -ENOMEM;
kfree (buf);
return -EFAULT;
} else
- memset (arg, size, 0);
+ memset (arg, 0, size);
}
/* ioctl to device */
ret = proc_resetdevice(ps);
break;
+ case USBDEVFS_CLEAR_HALT:
+ ret = proc_clearhalt(ps, (void *)arg);
+ if (ret >= 0)
+ inode->i_mtime = CURRENT_TIME;
+ break;
+
case USBDEVFS_GETDRIVER:
ret = proc_getdriver(ps, (void *)arg);
break;
struct special {
const char *name;
struct inode_operations *iops;
+ struct inode *inode;
struct list_head inodes;
};
inode->i_uid = listuid;
inode->i_gid = listgid;
inode->i_mode = listmode | S_IFREG;
+ special[i].inode = inode;
list_add_tail(&inode->u.usbdev_i.slist, &s->u.usbdevfs_sb.ilist);
list_add_tail(&inode->u.usbdev_i.dlist, &special[i].inodes);
}
/* --------------------------------------------------------------------- */
+static void update_special_inodes (void)
+{
+ int i;
+ for (i = 0; i < NRSPECIAL; i++) {
+ struct inode *inode = special[i].inode;
+ if (inode)
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ }
+}
+
+
void usbdevfs_add_bus(struct usb_bus *bus)
{
struct list_head *slist;
lock_kernel();
for (slist = superlist.next; slist != &superlist; slist = slist->next)
new_bus_inode(bus, list_entry(slist, struct super_block, u.usbdevfs_sb.slist));
+ update_special_inodes();
unlock_kernel();
usbdevfs_conn_disc_event();
}
lock_kernel();
while (!list_empty(&bus->inodes))
free_inode(list_entry(bus->inodes.next, struct inode, u.usbdev_i.dlist));
+ update_special_inodes();
unlock_kernel();
usbdevfs_conn_disc_event();
}
lock_kernel();
for (slist = superlist.next; slist != &superlist; slist = slist->next)
new_dev_inode(dev, list_entry(slist, struct super_block, u.usbdevfs_sb.slist));
+ update_special_inodes();
unlock_kernel();
usbdevfs_conn_disc_event();
}
send_sig_info(ds->discsignr, &sinfo, ds->disctask);
}
}
+
+ update_special_inodes();
unlock_kernel();
usbdevfs_conn_disc_event();
}
if(!urb_priv_kmem) {
err("kmem_cache_create for urb_priv_t failed (out of memory)");
+ kmem_cache_destroy(urb_priv_kmem);
return -ENOMEM;
}
#endif
i++;
}
+#ifdef DEBUG_SLAB
+ if (retval < 0 ) {
+ if(kmem_cache_destroy(uhci_desc_kmem))
+ err("uhci_desc_kmem remained");
+ if(kmem_cache_destroy(urb_priv_kmem))
+ err("urb_priv_kmem remained");
+ }
+#endif
+
return retval;
}
ssize_t block, blocks;
loff_t offset;
ssize_t chars;
- ssize_t written = 0;
+ ssize_t written = 0, retval = 0;
struct buffer_head * bhlist[NBUF];
size_t size;
kdev_t dev;
else
size = INT_MAX;
while (count>0) {
- if (block >= size)
- return written ? written : -ENOSPC;
+ if (block >= size) {
+ retval = -ENOSPC;
+ goto cleanup;
+ }
chars = blocksize - offset;
if (chars > count)
chars=count;
if (chars != blocksize)
fn = bread;
bh = fn(dev, block, blocksize);
- if (!bh)
- return written ? written : -EIO;
+ if (!bh) {
+ retval = -EIO;
+ goto cleanup;
+ }
if (!buffer_uptodate(bh))
wait_on_buffer(bh);
}
#else
bh = getblk(dev, block, blocksize);
- if (!bh)
- return written ? written : -EIO;
+ if (!bh) {
+ retval = -EIO;
+ goto cleanup;
+ }
if (!buffer_uptodate(bh))
{
if (!bhlist[i])
{
while(i >= 0) brelse(bhlist[i--]);
- return written ? written : -EIO;
+ retval = -EIO;
+ goto cleanup;
}
}
}
wait_on_buffer(bh);
if (!buffer_uptodate(bh)) {
brelse(bh);
- return written ? written : -EIO;
+ retval = -EIO;
+ goto cleanup;
}
};
};
if(write_error)
break;
}
+ cleanup:
if ( buffercount ){
ll_rw_block(WRITE, buffercount, bufferlist);
for(i=0; i<buffercount; i++){
brelse(bufferlist[i]);
}
}
- filp->f_reada = 1;
+ if(!retval)
+ filp->f_reada = 1;
if(write_error)
return -EIO;
- return written;
+ return written ? written : retval;
}
ssize_t block_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
*/
if (IS_MANDLOCK(inode) &&
(inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
- inode->i_mmap) {
- struct vm_area_struct *vma = inode->i_mmap;
+ inode->i_mmap_shared) {
error = -EAGAIN;
- do {
- if (vma->vm_flags & VM_MAYSHARE)
- goto out_putf;
- } while ((vma = vma->vm_next_share) != NULL);
+ goto out_putf;
}
error = -EINVAL;
return 0;
}
-#ifdef CONFIG_MODULES
int unregister_filesystem(struct file_system_type * fs)
{
+#ifdef CONFIG_MODULES
struct file_system_type ** tmp;
tmp = &file_systems;
}
tmp = &(*tmp)->next;
}
+#endif
return -EINVAL;
}
-#endif
static int fs_index(const char * __name)
{
struct wait_queue *i_wait;
struct file_lock *i_flock;
struct vm_area_struct *i_mmap;
+ struct vm_area_struct *i_mmap_shared;
struct page *i_pages;
struct dquot *i_dquot[MAXQUOTAS];
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
#define __exit
#define BASE_ADDRESS(x,i) ((x)->base_address[i])
-#define SETUP_PARAM char *str, int *ints
-#define SETUP_PARSE(x) do {} while (0)
+#define SETUP_PARAM char *str
+#define SETUP_PARSE(x) int ints[x]; get_options(str, x, ints)
#else
#define BASE_ADDRESS(x,i) ((x)->resource[i].start)
#define SETUP_PARAM char *str
struct vm_area_struct * vm_avl_left;
struct vm_area_struct * vm_avl_right;
- /* For areas with inode, the list inode->i_mmap, for shm areas,
+ /* For areas with inode, the list inode->i_mmap{,_shared}, for shm areas,
* the list of attaches, otherwise unused.
*/
struct vm_area_struct *vm_next_share;
extern inline void pci_set_master(struct pci_dev *dev)
{ return; }
+extern inline unsigned long pci_resource_len (struct pci_dev *dev, int n_base)
+{ return 0; }
+
#endif /* !CONFIG_PCI */
#endif /* __KERNEL__ */
#define USB_CLASS_AUDIO 1
#define USB_CLASS_COMM 2
#define USB_CLASS_HID 3
+#define USB_CLASS_PHYSICAL 5
#define USB_CLASS_PRINTER 7
#define USB_CLASS_MASS_STORAGE 8
#define USB_CLASS_HUB 9
#define USB_CLASS_DATA 10
+#define USB_CLASS_APP_SPEC 0xfe
#define USB_CLASS_VENDOR_SPEC 0xff
/*
#define USBDEVFS_IOCTL _IOWR('U', 18, struct usbdevfs_ioctl)
#define USBDEVFS_HUB_PORTINFO _IOR('U', 19, struct usbdevfs_hub_portinfo)
#define USBDEVFS_RESET _IO('U', 20)
+#define USBDEVFS_CLEAR_HALT _IOR('U', 21, unsigned int)
/* --------------------------------------------------------------------- */
#endif
#ifdef CONFIG_AGP
-extern int agp_initialize (void);
-extern void agp_setup(char *str, int *ints);
+extern int agp_init (void);
#endif
/*
#endif
#ifdef CONFIG_BLK_CPQ_DA
{ "smart2=", cpqarray_setup },
-#endif
-#ifdef CONFIG_AGP
- { "agp_try_unsupported=", agp_setup},
#endif
{ 0, 0 }
};
nubus_init();
#endif
#ifdef CONFIG_AGP
- agp_initialize ();
+ agp_init();
#endif
/* Networking initialization needs a process context */
{
unsigned long offset, nr;
+ /* If users can be writing to this page using arbitrary
+ * virtual addresses, take care about potential aliasing
+ * before reading the page on the kernel side.
+ */
+ if (inode->i_mmap_shared != NULL)
+ flush_dcache_page(page_address(page));
+
offset = pos & ~PAGE_CACHE_MASK;
nr = PAGE_CACHE_SIZE - offset;
if (nr > inode->i_size - pos)
flush_page_to_ram(pte_page(pte));
}
-/*
- * Handle all mappings that got truncated by a "truncate()"
- * system call.
- *
- * NOTE! We have to be ready to update the memory sharing
- * between the file and the memory map for a potential last
- * incomplete page. Ugly, but necessary.
- */
-void vmtruncate(struct inode * inode, unsigned long offset)
+static void vmtruncate_list(struct vm_area_struct *mpnt, unsigned long offset)
{
- struct vm_area_struct * mpnt;
-
- truncate_inode_pages(inode, offset);
- if (!inode->i_mmap)
- return;
- mpnt = inode->i_mmap;
do {
struct mm_struct *mm = mpnt->vm_mm;
unsigned long start = mpnt->vm_start;
} while ((mpnt = mpnt->vm_next_share) != NULL);
}
+/*
+ * Handle all mappings that got truncated by a "truncate()"
+ * system call.
+ *
+ * NOTE! We have to be ready to update the memory sharing
+ * between the file and the memory map for a potential last
+ * incomplete page. Ugly, but necessary.
+ */
+void vmtruncate(struct inode * inode, unsigned long offset)
+{
+ truncate_inode_pages(inode, offset);
+ if (inode->i_mmap)
+ vmtruncate_list(inode->i_mmap, offset);
+ if (inode->i_mmap_shared)
+ vmtruncate_list(inode->i_mmap_shared, offset);
+}
+
/*
* This is called with the kernel lock held, we need
return free > pages;
}
-/* Remove one vm structure from the inode's i_mmap ring. */
+/* Remove one vm structure from the inode's i_mmap{,_shared} ring. */
static inline void remove_shared_vm_struct(struct vm_area_struct *vma)
{
struct file * file = vma->vm_file;
}
/* Insert vm structure into process list sorted by address
- * and into the inode's i_mmap ring.
+ * and into the inode's i_mmap{,_shared} ring.
*/
void insert_vm_struct(struct mm_struct *mm, struct vm_area_struct *vmp)
{
file = vmp->vm_file;
if (file) {
struct inode * inode = file->f_dentry->d_inode;
+ struct vm_area_struct **head;
+
if (vmp->vm_flags & VM_DENYWRITE)
inode->i_writecount--;
+ head = &inode->i_mmap;
+ if (vmp->vm_flags & VM_SHARED)
+ head = &inode->i_mmap_shared;
+
/* insert vmp into inode's share list */
- if((vmp->vm_next_share = inode->i_mmap) != NULL)
- inode->i_mmap->vm_pprev_share = &vmp->vm_next_share;
- inode->i_mmap = vmp;
- vmp->vm_pprev_share = &inode->i_mmap;
+ if((vmp->vm_next_share = *head) != NULL)
+ (*head)->vm_pprev_share = &vmp->vm_next_share;
+ *head = vmp;
+ vmp->vm_pprev_share = head;
}
}
*
* PF_INET protocol family socket handler.
*
- * Version: $Id: af_inet.c,v 1.87.2.8 2000/07/05 01:33:52 davem Exp $
+ * Version: $Id: af_inet.c,v 1.87.2.9 2000/09/14 10:44:31 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
snum = ntohs(addr->sin_port);
#ifdef CONFIG_IP_MASQUERADE
/* The kernel masquerader needs some ports. */
- if((snum >= PORT_MASQ_BEGIN) && (snum <= PORT_MASQ_END))
+ if((snum >= PORT_MASQ_BEGIN) && (snum <= PORT_MASQ_END) &&
+ chk_addr_ret != RTN_MULTICAST)
return -EADDRINUSE;
#endif
if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))