From: Linus Torvalds Date: Fri, 23 Nov 2007 20:18:43 +0000 (-0500) Subject: Import 2.2.7pre4 X-Git-Tag: 2.2.7pre4 X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=830c685b136f230db6c4a847da3e998a1c10638c;p=history.git Import 2.2.7pre4 --- diff --git a/Documentation/scsi-generic.txt b/Documentation/scsi-generic.txt new file mode 100644 index 000000000000..17822c4ad70f --- /dev/null +++ b/Documentation/scsi-generic.txt @@ -0,0 +1,636 @@ + Notes on Linux's SG driver version 2.1.30 + ----------------------------------------- + 990328 + +Introduction +============ +These are notes on the Linux SCSI generic packet device driver (sg) +describing version 2.1.30 . The original driver was written by Lawrence +Foard and has remained in place with minimal changes since circa 1992. +Version 2 of this driver remains backward compatible (binary and +source **) with the original. It adds scatter gather, command queuing, +per file descriptor sequencing, asynchronous notification and better +error reporting. + +Sg is one of the four "high level" SCSI device drivers along with +sd, st and sr (disk, tape and CDROM respectively). Sg is more generalized +(but lower level) than its sibling and tends to be used on SCSI devices +that don't fit into the already serviced categories. Thus sg is used for +scanners, cd writers and reading audio cds amongst other things. + +The interface and usage of the original sg driver has been documented +by Heiko Eissfeldt in a HOWTO called SCSI-Programming-HOWTO. My copy +of the document is version 1.5 dated 7th May 1996. It can found at +ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/SCSI-Programming-HOWTO . +Amongst other things it has a lot of tables from the SCSI-2 standard +that are very useful for programming this interface. + +** It is possible to write applications that perform differently +depending on whether they are using the original or this version of +the sg device driver. The author is not aware of any useful applications +that have problems with version 2 (yet). + + +Architecture +============ +The SCSI generic packet device driver (sg) is a character based device. +It is one of the four high level device driver in the SCSI sub-system; +the others are sd (for direct-access devices - disks), st (for tapes) +and sr (for data cdroms). The other three devices are block devices. + +The unifying layer of the SCSI sub-system in the so-called mid-level. +Below that are all the drivers for the various adapters supported by +Linux. + +Since sg is a character device it supports the traditional Unix +system calls of open(), close(), read(), write() and ioctl(). Two other +related system calls: poll() and fcntl() are added to this list and +how they interact with the sg device driver is documented later. + +An SG device is accessed by write()ing SCSI commands plus any associated +outgoing data to it; the resulting status codes and any incoming data are +then obtained by a read() call. The device can be opened O_NONBLOCK +(non-blocking) and poll() used to monitor its progress. The device may be +opened O_EXCL which excludes other "sg" users from this device (but not +"sd", "st" or "sr" users). The buffer given to the write() call is made +up as follows: + - struct sg_header image (see below) + - scsi command (6, 10 or 12 bytes long) + - data to be written to the device (if any) + +The buffer received from the corresponding read() call contains: + - struct sg_header image (check status/errors + sense_buffer) + - data read back from device (if any) + +The given SCSI command has its LUN field overwritten by the LUN value of +the associated sg device that has been open()ed. + + +sg_header +========= +This is the name of the control structure that conveys information +about the length of data to be read/written by the associated SCSI +command. It also conveys error and status information from the +read() call. An instance of this structure is the first thing that +is placed in the data buffers of both write() and read(). + +In its original form it looked like this: +struct sg_header { + int pack_len; + int reply_len; + int pack_id; + int result; + unsigned int twelve_byte:1; + unsigned int other_flags:31; + unsigned char sense_buffer[16]; +}; /* this structure is 36 bytes long */ + +The 'pack_len' is bizzare and ends up having the 'reply_len' put in it +(perhaps it had a use at some stage). + +The 'reply_len' is the length of the data the corresponding read() +will/should request (including the sg_header). + +The 'pack_id' is not acted upon by the sg device driver but is conveyed +back to the corresponding read() so it can be used for sequencing by an +application. + +The 'result' is also bizzare, turning certain types of host codes it 0 (no +error), EBUSY or EIO. With better error reporting now available, the +'result' is best ignored. + +The 'twelve_byte' field overrides the internal SCSI command length "guessing" +algorithm for group 6 and 7 commands (ie when 1st byte >= 0xc0) and forces +a command lenth of 12 bytes. +The command length "guessing" algorithm is as follows: +Group: 0 1 2 3 4 5 6 7 +Length: 6 10 10 12 12 12 10 10 + +'other_flags' was originally documented as "not used" but some current +applications assume it has 0 placed in it. + +The 'sense_buffer' is the first 16 bytes of SCSI sense buffer that is +returned when the target returns a SCSI status code of CHECK_CONDITION +or COMMAND_TERMINATED [or (driver_status & DRIVER_SENSE) is true]. This +buffer should be at least 18 bytes long and arguably 32 bytes; unfortunately +this is unlikely to happen in the 2.2.x series of kernels. + +The new sg_header offered in this driver is: +#define SG_MAX_SENSE 16 +struct sg_header +{ + int pack_len; /* [o] reply_len (ie useless) ignored as input */ + int reply_len; /* [i] max length of expected reply (inc. sg_header) */ + int pack_id; /* [io] id number of packet (use ints >= 0) */ + int result; /* [o] 0==ok, else (+ve) Unix errno code (e.g. EIO) */ + unsigned int twelve_byte:1; + /* [i] Force 12 byte command length for group 6 & 7 commands */ + unsigned int target_status:5; /* [o] scsi status from target */ + unsigned int host_status:8; /* [o] host status (see "DID" codes) */ + unsigned int driver_status:8; /* [o] driver status+suggestion */ + unsigned int other_flags:10; /* unused */ + unsigned char sense_buffer[SG_MAX_SENSE]; /* [o] when target_status is + CHECK_CONDITION or COMMAND_TERMINATED this is output. */ +}; /* This structure is 36 bytes long on i386 */ + +Firstly the new header is binary compatible with the original. This is +important for keeping existing apps working without recompilation. + +Only those elements (or fields) that are new or in some way different +from the original are documented below. + +'pack_id' becomes input to a read() when ioctl(sg_fd, SG_SET_FORCE_PACK_ID, +&one) is active. A 'pack_id' of -1 is interpreted as fetch the oldest +waiting packet; any other value will cause the read() to wait (or yield +EAGAIN) until a packet with that 'pack_id' becomes available. In all cases +the value of 'pack_id' available after a read() is the value given to that +variable in the prior, corresponding write(). + +The 'target_status' field is always output and is the (masked and shifted +1 bit right) SCSI status code from the target device. The allowable +values are (found in ): +/* N.B. 1 bit offset from usual SCSI status values */ +#define GOOD 0x00 +#define CHECK_CONDITION 0x01 +#define CONDITION_GOOD 0x02 +#define BUSY 0x04 +#define INTERMEDIATE_GOOD 0x08 +#define INTERMEDIATE_C_GOOD 0x0a +#define RESERVATION_CONFLICT 0x0c +#define COMMAND_TERMINATED 0x11 +#define QUEUE_FULL 0x14 +When the 'target_status' is CHECK_CONDITION or COMMAND_TERMINATED the +'sense_buffer' is output. Note that when (driver_status & DRIVER_SENSE) +is true then the 'sense_buffer' is also output (this seems to occur when +the scsi ide emulation is used). When the 'sense_buffer' is output the +SCSI Sense Key can be found at (sense_buffer[2] & 0x0f) . + +The 'host_status' field is always output and has the following values +whose "defines" are not visible outside the kernel (unfortunately): +#define DID_OK 0x00 /* NO error */ +#define DID_NO_CONNECT 0x01 /* Couldn't connect before timeout period */ +#define DID_BUS_BUSY 0x02 /* BUS stayed busy through time out period */ +#define DID_TIME_OUT 0x03 /* TIMED OUT for other reason */ +#define DID_BAD_TARGET 0x04 /* BAD target. */ +#define DID_ABORT 0x05 /* Told to abort for some other reason */ +#define DID_PARITY 0x06 /* Parity error */ +#define DID_ERROR 0x07 /* Internal error */ +#define DID_RESET 0x08 /* Reset by somebody. */ +#define DID_BAD_INTR 0x09 /* Got an interrupt we weren't expecting. */ +#define DID_PASSTHROUGH 0x0a /* Force command past mid-layer */ +#define DID_SOFT_ERROR 0x0b /* The low level driver just wish a retry */ + +The 'driver_status' field is always output. When ('driver_status' & +DRIVER_SENSE) is true the 'sense_buffer' is also output. The following +values whose "defines" are not visible outside the kernel (unfortunately) +can occur: +#define DRIVER_OK 0x00 /* Typically no suggestion */ +#define DRIVER_BUSY 0x01 +#define DRIVER_SOFT 0x02 +#define DRIVER_MEDIA 0x03 +#define DRIVER_ERROR 0x04 +#define DRIVER_INVALID 0x05 +#define DRIVER_TIMEOUT 0x06 +#define DRIVER_HARD 0x07 +#define DRIVER_SENSE 0x08 +/* above status 'or'ed with one of the following suggestions */ +#define SUGGEST_RETRY 0x10 +#define SUGGEST_ABORT 0x20 +#define SUGGEST_REMAP 0x30 +#define SUGGEST_DIE 0x40 +#define SUGGEST_SENSE 0x80 + +'other_flags' still remains as a 10 bit field, so code that places 0 in it +will still be happy. It is not used. + + +memory +====== +Memory is a scarce resource in any computer. Sg needs to reserve memory +suitable for DMA roughly equal in size to the maximum of the write and +read data buffers for each packet. This DMA memory is obtained at the time +of a write() and released when the corresponding read() is called (although +if memory is tight it may be using the buffer reserved by the open() ). + +Linux obtaining memory a challenge for several reasons. The memory pool +that sg uses is in common with all other device drivers and all user +processes. In this environment the only way to 99.9% guarantee a driver +will have memory in Linux is to build it into the kernel (ie not as a +module) and then reserve it on initialization before user processes get +a chance. [Of course, another driver initialized before sg could take +all available memory ...] Another problem is the biggest contiguous +chunk of memory that can be obtained from the kernel is 32 * PAGE_SIZE +(which is 128KBytes on i386). As memory gets "splintered" there is a good +chance that buffers won't be available (my machine has 64 MBytes of RAM +and has 3 available at the moment). + +The original sg driver used the following technique: grab a SG_BIG_BUFF +sized buffer at driver initialization and use it for all requests greater +than PAGE_SIZE (4096 bytes on i386). By default SG_BIG_BUFF is set to +32 KBytes in the origianl driver but many applications suggest that the +user increases this number. Linux limits the biggest single buffer of +this type to 32 * PAGE_SIZE (128KBytes on i386). Unfortunately if the +sg driver is a module then there is a high chance a contiguous block of +that large size will not be available at module initialization. + +The author has found no "silver bullet" solution but uses multiple +techniques hoping that at least one is able provide memory at the critical +time. Listed below are some of these techniques: + - use scatter gather: then instead of one large buffer needing to + be found, multiple smaller buffer can be used + - use memory above the 16MByte level: the original driver limited + itself to obtaining memory below the 16MByte level (on the i386) + due to the shortcomings of DMA on ISA adapters. Yet more and more + people use PCI adapters that don't have this problem. So make + the decision based on the capabilities of the host adpater + associated with the current SCSI device + - reserve some memory at open() for emergencies but otherwise + fetch and release it on a per packet basis + - if the kernel is short of memory then dip into the SCSI DMA + pool (maintained by the mid-level driver) to a limited amount + + + +System Calls +============ +What follows are descriptions of the characteristics of the standard +Unix operating system calls when applied to a SCSI generic device +using this version of the device driver. + +open +---- +The filename should be an 'sg' device such as +/dev/sg[a-z] +/dev/sg[0,1,2,...] +or a symbolic link to one of these. [Devfs has its own sub-directory for +sg devices.] It seems as though SCSI devices are allocated to sg minor +numbers in the same order as they appear in 'cat /proc/scsi/scsi'. +Sg is a "character" based Linux device driver. This means it has an +open/close/read/write/ioctl type interface. + +Flags can be either O_RDONLY or O_RDWR or-ed with either +O_EXCL waits for other opens on sg device to be closed before + proceeding. If O_NONBLOCK is set then yields EBUSY when + someone else has the sg device open. The combination of + O_RDONLY and O_EXCL is disallowed. +O_NONBLOCK Sets non-blocking mode. Calls that would otherwise block + yield EAGAIN (eg read() ) or EBUSY (eg open() ). + +The original version of sg did not allow the O_RDONLY (yielding a EACCES +error). This version allows it for accessing ioctls (e.g. doing an sg +device scan with the SG_GET_SCSI_ID ioctl) but write()s will not be +allowed. + +By default, sequencing is per file descriptor in this version of sg. This +means, for example that 2 processes can independently manipulate the same +sg device at the same time. This may or may not make sense depending on +the application: 2 processes (logically) reading from the same direct access +device (ie a disk) is ok while running 2 instances of cd writing software +on the same device at the same time probably wouldn't be a good idea. The +previous version of sg supported only per device sequencing and this can +still be selected with the SG_SET_MERGE_FD,1 ioctl(). + +The driver will attempt to reserve SG_SCATTER_SZ bytes (32KBytes in the +current sg.h) on open() for "emergency" situations. If this is unavailable +it will halve its request and try again. It gives up if PAGE_SIZE bytes +(4096 bytes on i386) cannot be obtained so no memory is reserved. In this +case open() will still return successfully. The actual amount of memory +reserved can be found with the SG_GET_RESERVED_SIZE ioctl(). + +Returns a file descriptor if >= 0 , otherwise -1 implies an error. + +Error codes (value in 'errno' after -1 returned): +ENODEV sg not compiled into kernel or the kernel cannot find the + sg module (or it can't initialize itself (low memory??)) +ENXIO either scsi sub-system is currently processing some error + (eg doing a device reset) or the sg driver/module removed + or corrupted +EBUSY O_NONBLOCK set and some user of this sg device has O_EXCL + set while someone is already using this device +EINTR while waiting for an "exclusive" lock to clear, a signal + is received, just try again ... +ENOMEM An attempt to get memory to store this open's context + failed (this was _not_ a request to reserve DMA memory) +EACCES An attempt to use both O_RDONLY and O_EXCL + + +write +----- +Even though sg is a character-based device driver it sends and receives +packets to/from the associated scsi device. Write() is used to send a +packet containing 2 mandatory parts and 1 optional part. The mandatory +parts are: + - a control block (an instance of struct sg_header) + - a SCSI command (6, 10 or 12 bytes long) +The optional part is: + - outgoing data (eg if a SCSI write command is being sent) +These should appear as one contiguous string in the buffer given to +write() in the above order with no pad characters. + +If a write() accepts this packet then at some later time the user should +call a read() to get the result of the SCSI command. The previous sg +driver enforced a strict write()/read()/write()/read() regime so that a +second write() would block until first read() was finished. This sg +driver relaxes that condition and thereby allows command queuing +(limit is SG_MAX_QUEUE (16) outstanding packets per file descriptor). +However, for backward compatibility, command queuing is turned off +by default (#define SG_DEF_COMMAND_Q 0 in sg.h). This can be changed +via the the SG_SET_COMMAND_Q ioctl() [or by recompiling after changing +the above define to 1]. + +In this sg driver a write() should return more or less immediately. + +Returns number of bytes written if > 0 , otherwise -1 implies an error. + +Error codes (value in 'errno' after -1 returned): +ENXIO either scsi sub-system is currently processing some error + (eg doing a device reset) or the sg driver/module removed + or corrupted +EACCES opened with RD_ONLY flag +EIO incoming buffer too short. It should be at least (6 + + sizeof(struct sg_header))==42 bytes long +EDOM a) command queuing off: a packet is already queued + b) command queuing on: too many packets queued + (SG_MAX_QUEUE exceeded) +EAGAIN SCSI mid-level out of command blocks (rare), try again. + This is more likely to happen when queuing commands, + so wait a bit (eg usleep(10000) ) before trying again +ENOMEM can't get memory for DMA. Take evasive action ... + (see section on memory) + + +read +---- +Read() is used to receive a packet containing 1 mandatory part and 1 +optional part. The mandatory part is: + - a control block (an instance of struct sg_header) +The optional part is: + - incoming data (eg if a SCSI read command was sent by earlier write() ) +The buffer given to a read() and its corresponding count should be +sufficient to accommodate this packet to avoid truncation. Truncation has +occurred if count < sg_header::replylen . + +By default, read() will return the oldest packet queued up. If the +SG_SET_FORCE_PACK_ID,1 ioctl() is active then read() will attempt to +fetch the packet whose pack_id (given earlier to write()) matches the +sg_header::pack_id given to this read(). If not available it will either +wait or yield EAGAIN. As a special case, -1 in sg_header::pack_id given +to read() will match the oldest packet. + + +Returns number of bytes read if > 0 , otherwise -1 implies an error. +Unfortunately the return value in the non-error case is simply the +same as the count argument. It is not the actual number of bytes +DMA-ed by the SCSI device. This driver is currently unable to provide +such an underrun indication. + +Error codes (value in 'errno' after -1 returned): +ENXIO either scsi sub-system is currently processing some error + (eg doing a device reset) or the sg driver/module removed + or corrupted +EAGAIN either no waiting packet or requested packet is not + available while O_NONBLOCK flag was set +EINTR while waiting for a packet, a signal is received, just + try again ... +EIO if the 'count' given to read() is < sizeof(struct sg_header) + and the 'result' element in sg_header is non-zero. Not a + recommended error reporting technique + + +close +----- +Preferably a close() should be done after all issued write()s have had +their corresponding read() calls completed. Unfortunately this is not +always possible. The semantics of close() in Unix are to return more +or less immediately (ie not wait on any event) so the driver needs to +arrange to an orderly cleanup of those packets that are still "in +flight". + +A process that has an open file descriptor to an sg device may be aborted +(eg by a kill signal). In this case, the kernel automatically calls close +(which is called 'sg_release()' in the version 2 driver) to facilitate +the cleanup mentioned above. + +A problem persists in version 2.1.8 if the sg driver is a module and is +removed while packets are still "in flight". Hopefully this will be soon +fixed. + +Returns 0 if successful, otherwise -1 implies an error. + +Error codes (value in 'errno' after -1 returned): +ENXIO sg driver/module removed or corrupted + +ioctl (sg specific) +------------------- +Ken Thompson (or perhaps some other Unix luminary) described ioctl() as +the "garbage bin of Unix". This driver compounds the situation by adding +around 18 more commands. These commands either yield state information (10 +of them), change the driver's characteristics (8 of them) or allow direct +communication with the common SCSI mid-level driver. + +Those commands with an appended "+" are new in version 2. + +Those commands with an appended "W" are only accessible from file +descriptors opened with O_RDWR. They will yield EACCES otherwise. + +SG_GET_TIMEOUT: +Ignores its 3rd argument and _returns_ the timeout value (which will be +>= 0 ). The unit of this timeout is "jiffies" which are currently 10 +millisecond intervals on i386 (less on an alpha). Linux supplies +a manifest constant HZ which is the number of "jiffies" in 1 second. + +SG_SET_TIMEOUT: +Assumes 3rd argument points to an int containing the new timeout value +for this file descriptor. The unit is a "jiffy". Packets that are +already "in flight" will not be effected. The default value is set +on open() and is SG_DEFAULT_TIMEOUT (defined in sg.h). + +SG_EMULATED_HOST: +Assumes 3rd argument points to an int and outputs a flag indicating +whether the host (adapter) is connected to a real SCSI bus or is +emulated one (eg ide-scsi device driver). A value of 1 means emulated +while 0 is not. + +SG_SET_FORCE_LOW_DMA +: +Assumes 3rd argument points to an int containing 0 or 1. 0 (default) +means sg decides whether to use memory above 16 Mbyte level (on i386) +based on the host adapter being used by this SCSI device. Typically +PCI SCSI adapters will indicate they can DMA to the whole 32 bit address +space. +If 1 is given then the host adapter is overridden and only memory below +the 16MB level is used for DMA. A requirement for this should be +extremely rare. If the "reserve" buffer allocated on open() is not in +use then it will be de-allocated and re-allocated under the 16MB level +(and the latter operation could fail yielding ENOMEM). +Only the current file descriptor is effected. + +SG_GET_LOW_DMA +: +Assumes 3rd argument points to an int and places 0 or 1 in it. 0 +indicates the whole 32 bit address space is being used for DMA transfers +on this file descriptor. 1 indicates the memory below the 16MB level +(on i386) is being used (and this may be the case because the host +adapters setting has been overridden by SG_SET_FORCE_LOW_DMA,1 . + +SG_GET_SCSI_ID +: +Assumes 3rd argument is pointing to an object of type Sg_scsi_id and +populates it. That structure contains ints for host_no, channel, +scsi_id, lun and scsi_type. Most of this information is available from +other sources (eg SCSI_IOCTL_GET_IDLUN and SCSI_IOCTL_GET_BUS_NUMBER) +but tends to be awkward to collect. + +SG_SET_FORCE_PACK_ID +: +Assumes 3rd argument is pointing to an int. 0 (default) instructs read() +to return the oldest (written) packet if multiple packets are +waiting to be read (when command queuing is being used). +1 instructs read() to view the sg_header::pack_id as input and return the +oldest packet matching that pack_id or wait until it arrives (or yield +EAGAIN if O_NONBLOCK is in force). As a special case the pack_id of -1 +given to read() in the mode will match the oldest packet. +Only the current file descriptor is effected by this command. + +SG_GET_LOW_DMA +: +Assumes 3rd argument points to an int and places the pack_id of the +oldest (written) packet in it. If no packet is waiting to be read then +yields -1. + +SG_GET_NUM_WAITING +: +Assumes 3rd argument points to an int and places the number of packets +waiting to be read in it. + +SG_GET_SG_TABLESIZE +: +Assumes 3rd argument points to an int and places the maximum number of +scatter gather elements supported by the host adapter. 0 indicates that +the adapter does support scatter gather. + +SG_SET_RESERVED_SIZE +W: +This is not currently implemented. It is intended for reserving either a +large buffer or scatter gather list that will be available until the +current file descriptor is closed. The requested amount of memory may +not be available so SG_GET_RESERVED_SIZE should be used after this call +to see how much was reserved. (EBUSY error possible) + +SG_GET_RESERVED_SIZE +: +Assumes 3rd argument points to an int and places the size in bytes of +the DMA buffer reserved on open() for emergencies. If this is 0 then it +is probably not wise to attempt on operation like burning a CD on this +file descriptor. + +SG_SET_MERGE_FD +W: +Assumes 3rd argument is pointing to an int. 0 (the default) causes all +subsequent sequencing to be per file descriptor. 1 causes all subsequent +sequencing to be per device. If this command tries to change the current +state and the is one or more _other_ file descriptors using this sg +device then an EBUSY error occurs. Also if this file descriptor was not +open()ed with the O_RDWR flag then an EACCES error occurs. +Per device sequencing was the original semantics and allowed, for example +different processes to "share" the device, one perhaps write()ing with +the other one read()ing. This command is supplied if anyone needs those +semantics. Per file descriptor sequencing, perhaps with the usage of +the O_EXCL flag, seems more sensible. + +SG_GET_MERGE_FD +: +Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies +sequencing is per file descriptor. 1 implies sequencing is per device +(original sg driver's semantics). + +SG_SET_COMMAND_Q +: +Assumes 3rd argument is pointing to an int. 0 (current default, set by +SG_DEF_COMMAND_Q in sg.h) disables command queuing. Attempts to write() +a packet while one is already queued will result in a EDOM error. +1 turns command queuing on. +Changing the queuing state only effects write()s done after the change. +Only the current file descriptor is effected by this command. + +SG_GET_COMMAND_Q +: +Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies +that command queuing is off on this file descriptor. 1 implies command +queuing is on. + +SG_SET_DEBUG +: +Assumes 3rd argument is pointing to an int. 0 (default) turns debugging +off. Values > 0 cause the SCSI sense buffer to be decoded and output +to the console/log when a SCSI device error occurs. Values > 8 cause +the current sg device driver's state to be output to the console/log +(this is a "one off" effect). +If you need a _lot_ of the SCSI sub-system debug information (mainly from +the mid-level) then try 'echo "scsi dump 0" > /proc/scsi/scsi' and lots of +debug will appear in your console/log. + +ioctl (in common with sd, st + sr) +---------------------------------- +The following ioctl()s can be called from any high-level scsi device +driver (ie sd, st, sr + sg). Access permissions may differ a bit from +one device to another, the access information given below is specific to +the sg device driver. + +SCSI_IOCTL_GET_IDLUN: +SCSI_IOCTL_GET_BUS_NUMBER: + +SCSI_IOCTL_SEND_COMMAND: W +If open()ed O_RDONLY yields an EACCESS error. Otherwise is forwarded onto +the SCSI mid-level driver for processing. +Don't know much about this one but it looks pretty powerful and +dangerous. Some comments says it is also deprecated. + +: W +If open()ed O_RDONLY yields an EACCESS error. Otherwise is forwarded onto +the SCSI mid-level driver for processing. + + +poll +---- +This is a native call in Linux 2.2 but most of its capabilities are available +through the older select() call. Given a choice poll() should probably be +used. Typically poll() is used when a sg scsi device is open()ed O_NONBLOCK +for polling; or alternatively with asynchronous notification using the +fcntl() system call (below) and the SIGPOLL (aka SIGIO) signal. +Only if something drastically is wrong (eg file handle gone stale) will +POLLERR ever be set. POLLPRI, POLLHUP and POLLNVAL are never set. +POLLIN is set when there is one or more packets waiting to be read. +When POLLIN is set it implies that a read() will not block (or yield +EAGAIN in non-blocking mode) but return a packet immediately. +POLLOUT (aka POLLWRNORM) is set when write() is able to accept a packet +(ie will _not_ yield an EDOM error). The setting of POLLOUT is effected +by the SG_SET_COMMAND_Q state: if the state is on then POLLOUT will remain +set until the number of queued packets reaches SG_MAX_QUEUE, if the +state is off then POLLOUT is only set when no packets are queued. +Note that a packet can be queued after write()ing but not available to be +read(); this typically happens when a SCSI read command is issued while +the data is being retreaved. +Poll() is per file descriptor unless SG_SET_MERGE_FD is set in which case +it is per device. + + +fcntl +----- +There are several uses for this system call in association with a sg +file descriptor. The first pseudo code shows code that is useful for +scanning the sg devices, taking care not to be caught in a wait for +an O_EXCL lock by another process, and when the appropriate device is +found switching to normal blocked io. A working example of this logic +is in the sg_scan.c utility program. + +open("/dev/sga", O_RDONLY | O_NONBLOCK) +/* check device, EBUSY means some other process has O_EXCL lock on it */ +/* one the device you want is found then ... */ +flags = fcntl(sg_fd, F_GETFL) +fcntl(sg_fd, F_SETFL, flags & (~ O_NONBLOCK)) +/* for simple apps is is easier to use normal blocked io */ + + +Some work has to be done in Linux to set up for asynchronous notification. +This is a non-blocking mode of operation in which when the driver receives +data back from a device so that a read() can be done, it sends a SIGPOLL +(aka SIGIO) signal to the owning process. A working example of this logic +is in the sg_poll.c test program. + +sigemptyset(&sig_set) +sigaddset(&sig_set, SIGPOLL) +sigaction(SIGPOLL, &s_action, 0) +fcntl(sg_fd, F_SETOWN, getpid()) +flags = fcntl(sg_fd, F_GETFL); +fcntl(sg_fd, F_SETFL, flags | O_ASYNC) + + +Utility and Test Programs +========================= diff --git a/MAINTAINERS b/MAINTAINERS index bc38c72ff906..f852c910535c 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -650,6 +650,11 @@ L: linux-scsi@vger.rutgers.edu W: http://www.torque.net/sg S: Maintained +SCSI GENERIC +L: linux-scsi@vger.rutgers.edu +M: douglas.gilbert@rbcds.com +S: Maintained + SCSI SUBSYSTEM L: linux-scsi@vger.rutgers.edu S: Unmaintained @@ -771,7 +776,7 @@ M: axboe@image.dk L: linux-kernel@vger.rutgers.edu S: Maintained -USB HUB DRIVER +USB HUB AND UHCI DRIVERS P: Johannes Erdfelt M: jerdfelt@sventech.com L: linux-usb@peloncho.fis.ucm.es @@ -798,9 +803,9 @@ M: Alan.Cox@linux.org W: http://roadrunner.swansea.linux.org.uk/v4l.shtml S: Maintained -WAN ROUTER AND SANGOMA WANPIPE DRIVERS (X.25, FRAME RELAY, PPP) -P: Gene Kozin -M: genek@compuserve.com +WAN ROUTER & SANGOMA WANPIPE DRIVERS & API (X.25, FRAME RELAY, PPP, CISCO HDLC) +P: Jaspreet Singh +M: jaspreet@sangoma.com M: dm@sangoma.com W: http://www.sangoma.com S: Supported diff --git a/Makefile b/Makefile index 1a123ca5f2ed..47b243fffee1 100644 --- a/Makefile +++ b/Makefile @@ -175,7 +175,7 @@ DRIVERS := $(DRIVERS) drivers/net/hamradio/hamradio.a endif ifeq ($(CONFIG_USB),y) -DRIVERS := $(DRIVERS) drivers/uusbd/usb.a +DRIVERS := $(DRIVERS) drivers/usb/usb.a endif ifeq ($(CONFIG_I2O),y) diff --git a/arch/alpha/kernel/setup.c b/arch/alpha/kernel/setup.c index 42821d903ded..80b4454e1820 100644 --- a/arch/alpha/kernel/setup.c +++ b/arch/alpha/kernel/setup.c @@ -183,6 +183,11 @@ setup_arch(char **cmdline_p, unsigned long * memory_start_p, vec = get_sysvec_byname(p+9); continue; } + + if (strncmp(p, "cycle=", 6) == 0) { + est_cycle_freq = simple_strtol(p+6, NULL, 0); + continue; + } } /* Replace the command line, not that we've killed it with strtok. */ @@ -721,8 +726,8 @@ int get_cpuinfo(char *buffer) (char*)cpu->serial_no, systype_name, sysvariation_name, hwrpb->sys_revision, (char*)hwrpb->ssn, - hwrpb->cycle_freq ? : est_cycle_freq, - hwrpb->cycle_freq ? "" : "est.", + est_cycle_freq ? : hwrpb->cycle_freq, + est_cycle_freq ? "est." : "", hwrpb->intr_freq / 4096, (100 * hwrpb->intr_freq / 4096) % 100, hwrpb->pagesize, diff --git a/arch/alpha/kernel/time.c b/arch/alpha/kernel/time.c index 222b8f26fadd..a84378926472 100644 --- a/arch/alpha/kernel/time.c +++ b/arch/alpha/kernel/time.c @@ -226,7 +226,7 @@ time_init(void) { void (*irq_handler)(int, void *, struct pt_regs *); unsigned int year, mon, day, hour, min, sec, cc1, cc2; - unsigned long cycle_freq; + unsigned long cycle_freq, diff, one_percent; /* * The Linux interpretation of the CMOS clock register contents: @@ -240,19 +240,30 @@ time_init(void) /* Read cycle counter exactly on falling edge of update flag */ cc1 = rpcc(); - /* If our cycle frequency isn't valid, go another round and give - a guess at what it should be. */ - cycle_freq = hwrpb->cycle_freq; - if (cycle_freq == 0) { - printk("HWRPB cycle frequency bogus. Estimating... "); - + if (!est_cycle_freq) { + /* Sometimes the hwrpb->cycle_freq value is bogus. + Go another round to check up on it and see. */ do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)); do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP); cc2 = rpcc(); - est_cycle_freq = cycle_freq = cc2 - cc1; + est_cycle_freq = cc2 - cc1; cc1 = cc2; + } - printk("%lu Hz\n", cycle_freq); + /* If the given value is within 1% of what we calculated, + accept it. Otherwise, use what we found. */ + cycle_freq = hwrpb->cycle_freq; + one_percent = cycle_freq / 100; + diff = cycle_freq - est_cycle_freq; + if (diff < 0) + diff = -diff; + if (diff > one_percent) { + cycle_freq = est_cycle_freq; + printk("HWRPB cycle frequency bogus. Estimated %lu Hz\n", + cycle_freq); + } + else { + est_cycle_freq = 0; } /* From John Bowman : allow the values diff --git a/arch/alpha/lib/clear_user.S b/arch/alpha/lib/clear_user.S index 65d7e2f282aa..21d86eb78a11 100644 --- a/arch/alpha/lib/clear_user.S +++ b/arch/alpha/lib/clear_user.S @@ -80,6 +80,7 @@ $tail: ret $31, ($28), 1 # .. e1 : __do_clear_user: + ldgp $29,0($27) # we do exceptions -- we need the gp. and $6, 7, $4 # e0 : find dest misalignment beq $0, $zerolength # .. e1 : addq $0, $4, $1 # e0 : bias counter diff --git a/arch/alpha/lib/copy_user.S b/arch/alpha/lib/copy_user.S index aa309b9f5245..da5d2795ad83 100644 --- a/arch/alpha/lib/copy_user.S +++ b/arch/alpha/lib/copy_user.S @@ -46,6 +46,8 @@ .globl __copy_user .ent __copy_user __copy_user: + ldgp $29,0($27) # we do exceptions -- we need the gp. + .prologue 1 and $6,7,$3 beq $0,$35 beq $3,$36 diff --git a/arch/alpha/lib/strlen_user.S b/arch/alpha/lib/strlen_user.S index cdf71158f833..1f4fb07f589a 100644 --- a/arch/alpha/lib/strlen_user.S +++ b/arch/alpha/lib/strlen_user.S @@ -27,7 +27,8 @@ .align 3 __strlen_user: - .prologue 0 + ldgp $29,0($27) # we do exceptions -- we need the gp. + .prologue 1 EX( ldq_u t0, 0(a0) ) # load first quadword (a0 may be misaligned) lda t1, -1(zero) diff --git a/arch/alpha/lib/strncpy_from_user.S b/arch/alpha/lib/strncpy_from_user.S index aff7c1d2bf91..998450196356 100644 --- a/arch/alpha/lib/strncpy_from_user.S +++ b/arch/alpha/lib/strncpy_from_user.S @@ -31,6 +31,7 @@ .globl __strncpy_from_user .ent __strncpy_from_user .frame $30, 0, $26 + .prologue 1 .align 3 $aligned: @@ -99,6 +100,7 @@ $a_eoc: /*** The Function Entry Point ***/ .align 3 __strncpy_from_user: + ldgp $29, 0($27) # we do exceptions -- we need the gp. mov a0, v0 # save the string start beq a2, $zerolength diff --git a/arch/i386/config.in b/arch/i386/config.in index 23a38e419efe..65a3aee0a71c 100644 --- a/arch/i386/config.in +++ b/arch/i386/config.in @@ -168,6 +168,8 @@ endmenu source drivers/char/Config.in +# source drivers/usb/Config.in + source fs/Config.in if [ "$CONFIG_VT" = "y" ]; then diff --git a/arch/i386/kernel/bios32.c b/arch/i386/kernel/bios32.c index a7018a7e5335..91d338b2c2f4 100644 --- a/arch/i386/kernel/bios32.c +++ b/arch/i386/kernel/bios32.c @@ -1095,6 +1095,8 @@ static void __init pcibios_scan_buglist(struct pci_bus *b) * for buggy PCI BIOS'es :-[). */ +extern int skip_ioapic_setup; + static void __init pcibios_fixup_devices(void) { struct pci_dev *dev; @@ -1147,6 +1149,7 @@ static void __init pcibios_fixup_devices(void) /* * Recalculate IRQ numbers if we use the I/O APIC */ + if(!skip_ioapic_setup) { int irq; unsigned char pin; diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c index 79ef5f9fd4bf..6de1fd686622 100644 --- a/arch/m68k/atari/atakeyb.c +++ b/arch/m68k/atari/atakeyb.c @@ -291,7 +291,7 @@ static void atakeyb_rep( unsigned long ignore ) atakeyb_rep_timer.prev = atakeyb_rep_timer.next = NULL; add_timer( &atakeyb_rep_timer ); - handle_scancode(rep_scancode); + handle_scancode(rep_scancode, 1); } atari_enable_irq( IRQ_MFP_ACIA ); @@ -448,7 +448,7 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp) add_timer( &atakeyb_rep_timer ); } - handle_scancode(break_flag | scancode); + handle_scancode(scancode, !break_flag); break; } break; diff --git a/arch/m68k/hp300/hil.c b/arch/m68k/hp300/hil.c index 3be0d488a68b..d7fe1867c04b 100644 --- a/arch/m68k/hp300/hil.c +++ b/arch/m68k/hp300/hil.c @@ -223,12 +223,13 @@ static void poll_finished(void) { case 0x40: { - unsigned char scode = (poll.data[1] >> 1) | ((poll.data[1] & 1)?0x80:0); + int down = (poll.data[1] & 1) == 0; + unsigned char scode = poll.data[1] >> 1; #if 0 - if (scode & 0x80) - printk("[%02x]", scode & 0x7f); + if (down) + printk("[%02x]", scode); #endif - handle_scancode(scode); + handle_scancode(scode, down); } break; } diff --git a/arch/m68k/mac/mackeyb.c b/arch/m68k/mac/mackeyb.c index 5a6ae7c75af0..a128a6314a99 100644 --- a/arch/m68k/mac/mackeyb.c +++ b/arch/m68k/mac/mackeyb.c @@ -60,7 +60,7 @@ static void input_keycode(int, int); extern struct kbd_struct kbd_table[]; extern void adb_bus_init(void); -extern void handle_scancode(unsigned char); +extern void handle_scancode(unsigned char, int); extern void put_queue(int); /* keyb */ @@ -387,7 +387,7 @@ input_keycode(int keycode, int repeat) */ switch (keycode) { case 0x39: - handle_scancode(keycode); /* down */ + handle_scancode(keycode, 1); /* down */ up_flag = 0x80; /* see below ... */ mark_bh(KEYBOARD_BH); break; @@ -397,7 +397,7 @@ input_keycode(int keycode, int repeat) } } - handle_scancode(keycode + up_flag); + handle_scancode(keycode, !up_flag); } static void diff --git a/drivers/Makefile b/drivers/Makefile index d83456c61aaa..eef043f28559 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -10,7 +10,7 @@ SUB_DIRS := block char net misc sound MOD_SUB_DIRS := $(SUB_DIRS) ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sbus cdrom isdn pnp \ - macintosh video dio zorro fc4 + macintosh video dio zorro fc4 usb ifdef CONFIG_DIO SUB_DIRS += dio @@ -44,6 +44,11 @@ SUB_DIRS += macintosh MOD_SUB_DIRS += macintosh endif +ifeq ($(CONFIG_USB),y) +SUB_DIRS += usb +MOD_SUB_DIRS += usb +endif + # If CONFIG_SCSI is set, the core of SCSI support will be added to the kernel, # but some of the low-level things may also be modules. ifeq ($(CONFIG_SCSI),y) diff --git a/drivers/acorn/char/keyb_ps2.c b/drivers/acorn/char/keyb_ps2.c index c3ef33363a6b..4af051f444e5 100644 --- a/drivers/acorn/char/keyb_ps2.c +++ b/drivers/acorn/char/keyb_ps2.c @@ -221,11 +221,6 @@ unsigned char ps2kbd_sysrq_xlate[] = }; #endif -int ps2kbd_pretranslate(unsigned char scancode) -{ - return 1; -} - int ps2kbd_translate(unsigned char scancode, unsigned char *keycode_p, char *uf_p) { *uf_p = scancode & 0200; @@ -235,7 +230,7 @@ int ps2kbd_translate(unsigned char scancode, unsigned char *keycode_p, char *uf_ static void ps2kbd_key(unsigned int keycode, unsigned int up_flag) { - handle_scancode(keycode + (up_flag ? 0x80 : 0)); + handle_scancode(keycode, !up_flag); } static inline void ps2kbd_sendbyte(unsigned char val) diff --git a/drivers/block/ide-cd.h b/drivers/block/ide-cd.h index 89fa51a83a6f..28f4b9c74ba1 100644 --- a/drivers/block/ide-cd.h +++ b/drivers/block/ide-cd.h @@ -334,13 +334,13 @@ struct atapi_capabilities_page { #if defined(__BIG_ENDIAN_BITFIELD) __u8 reserved3 : 2; - /* Drive can fake writes */ - __u8 test_write : 1; - __u8 reserved3a : 1; - /* Drive can write DVD-R discs */ - __u8 dvd_r_write : 1; /* Drive can write DVD-RAM discs */ __u8 dvd_ram_write : 1; + /* Drive can write DVD-R discs */ + __u8 dvd_r_write : 1; + __u8 reserved3a : 1; + /* Drive can fake writes */ + __u8 test_write : 1; /* Drive can write to CD-R/W (CD-E) discs (orange book, part III) */ __u8 cd_rw_write : 1; /* reserved in 1.2 */ /* Drive supports write to CD-R discs (orange book, part II) */ @@ -350,13 +350,13 @@ struct atapi_capabilities_page { __u8 cd_r_write : 1; /* reserved in 1.2 */ /* Drive can write to CD-R/W (CD-E) discs (orange book, part III) */ __u8 cd_rw_write : 1; /* reserved in 1.2 */ - /* Drive can write DVD-RAM discs */ - __u8 dvd_ram_write : 1; - /* Drive can write DVD-R discs */ - __u8 dvd_r_write : 1; - __u8 reserved3a : 1; /* Drive can fake writes */ __u8 test_write : 1; + __u8 reserved3a : 1; + /* Drive can write DVD-R discs */ + __u8 dvd_r_write : 1; + /* Drive can write DVD-RAM discs */ + __u8 dvd_ram_write : 1; __u8 reserved3 : 2; #else #error "Please fix " diff --git a/drivers/cdrom/optcd.c b/drivers/cdrom/optcd.c index 76103945be2e..4406e1733276 100644 --- a/drivers/cdrom/optcd.c +++ b/drivers/cdrom/optcd.c @@ -100,6 +100,10 @@ static void debug(int debug_this, const char* fmt, ...) #else #define DEBUG(x) #endif + +static int blksize = 2048; +static int hsecsize = 2048; + /* Drive hardware/firmware characteristics Identifiers in accordance with Optics Storage documentation */ @@ -2061,6 +2065,8 @@ __initfunc(int optcd_init(void)) return -EIO; } + hardsect_size[MAJOR_NR] = &hsecsize; + blksize_size[MAJOR_NR] = &blksize; blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; read_ahead[MAJOR_NR] = 4; request_region(optcd_port, 4, "optcd"); diff --git a/drivers/char/Makefile b/drivers/char/Makefile index d623c4ec8c30..dfe297b6592a 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -42,14 +42,15 @@ endif ifndef CONFIG_SUN_KEYBOARD ifdef CONFIG_VT -L_OBJS += keyboard.o +LX_OBJS += keyboard.o endif ifneq ($(ARCH),m68k) L_OBJS += pc_keyb.o defkeymap.o endif else ifdef CONFIG_PCI -L_OBJS += defkeymap.o keyboard.o +L_OBJS += defkeymap.o +LX_OBJS += keyboard.o endif endif diff --git a/drivers/char/amikeyb.c b/drivers/char/amikeyb.c index 164fc5df5017..8c8c58388d32 100644 --- a/drivers/char/amikeyb.c +++ b/drivers/char/amikeyb.c @@ -188,7 +188,7 @@ static void amikeyb_rep(unsigned long ignore) amikeyb_rep_timer.expires = jiffies + key_repeat_rate; amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL; add_timer(&amikeyb_rep_timer); - handle_scancode(rep_scancode); + handle_scancode(rep_scancode, 1); restore_flags(flags); } @@ -243,8 +243,8 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp) if (keycode == AMIKEY_CAPS) { /* if the key is CAPS, fake a press/release. */ - handle_scancode(AMIKEY_CAPS); - handle_scancode(BREAK_MASK | AMIKEY_CAPS); + handle_scancode(AMIKEY_CAPS, 1); + handle_scancode(AMIKEY_CAPS, 0); } else if (keycode < 0x78) { /* handle repeat */ if (break_flag) { @@ -257,7 +257,7 @@ static void keyboard_interrupt(int irq, void *dummy, struct pt_regs *fp) amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL; add_timer(&amikeyb_rep_timer); } - handle_scancode(scancode); + handle_scancode(scancode, !break_flag); } else switch (keycode) { case 0x78: diff --git a/drivers/char/bttv.c b/drivers/char/bttv.c index 5ce2fa70fb13..12ac86673fce 100644 --- a/drivers/char/bttv.c +++ b/drivers/char/bttv.c @@ -2853,6 +2853,16 @@ static void handle_chipset(void) } #endif +static void init_tea6300(struct i2c_bus *bus) +{ + I2CWrite(bus, I2C_TEA6300, TEA6300_VL, 0x35, 1); /* volume left 0dB */ + I2CWrite(bus, I2C_TEA6300, TEA6300_VR, 0x35, 1); /* volume right 0dB */ + I2CWrite(bus, I2C_TEA6300, TEA6300_BA, 0x07, 1); /* bass 0dB */ + I2CWrite(bus, I2C_TEA6300, TEA6300_TR, 0x07, 1); /* treble 0dB */ + I2CWrite(bus, I2C_TEA6300, TEA6300_FA, 0x0f, 1); /* fader off */ + I2CWrite(bus, I2C_TEA6300, TEA6300_SW, 0x01, 1); /* mute off input A */ +} + static void init_tda8425(struct i2c_bus *bus) { I2CWrite(bus, I2C_TDA8425, TDA8425_VL, 0xFC, 1); /* volume left 0dB */ @@ -2978,6 +2988,14 @@ static void idcard(int i) break; } + if (I2CRead(&(btv->i2c), I2C_TEA6300) >=0) + { + printk(KERN_INFO "bttv%d: fader chip: TEA6300\n",btv->nr); + btv->audio_chip = TEA6300; + init_tea6300(&(btv->i2c)); + } else + printk(KERN_INFO "bttv%d: NO fader chip: TEA6300\n",btv->nr); + printk(KERN_INFO "bttv%d: model: ",btv->nr); sprintf(btv->video_dev.name,"BT%d",btv->id); diff --git a/drivers/char/bttv.h b/drivers/char/bttv.h index 59776cc20a80..479384783b48 100644 --- a/drivers/char/bttv.h +++ b/drivers/char/bttv.h @@ -114,6 +114,7 @@ struct bttv int type; /* card type */ int audio; /* audio mode */ int audio_chip; + int fader_chip; int radio; u32 *risc_jmp; @@ -222,6 +223,7 @@ struct bttv #define TDA9850 0x01 #define TDA8425 0x02 #define TDA9840 0x03 +#define TEA6300 0x04 #define I2C_TSA5522 0xc2 #define I2C_TDA9840 0x84 @@ -230,6 +232,7 @@ struct bttv #define I2C_HAUPEE 0xa0 #define I2C_STBEE 0xae #define I2C_VHX 0xc0 +#define I2C_TEA6300 0x80 #define TDA9840_SW 0x00 #define TDA9840_LVADJ 0x02 @@ -249,6 +252,12 @@ struct bttv #define TDA8425_BA 0x02 #define TDA8425_TR 0x03 #define TDA8425_S1 0x08 - + +#define TEA6300_VL 0x00 /* volume control left */ +#define TEA6300_VR 0x01 /* volume control right */ +#define TEA6300_BA 0x02 /* bass control */ +#define TEA6300_TR 0x03 /* treble control */ +#define TEA6300_FA 0x04 /* fader control */ +#define TEA6300_SW 0x05 /* mute and source switch */ #endif diff --git a/drivers/char/dn_keyb.c b/drivers/char/dn_keyb.c index 02436b8f2c5b..304feb0e8cf7 100644 --- a/drivers/char/dn_keyb.c +++ b/drivers/char/dn_keyb.c @@ -414,9 +414,9 @@ static void dn_keyb_process_key_event(unsigned char scancode) { } else if((scancode & (~BREAK_FLAG)) == DNKEY_CAPS) { /* printk("handle_scancode: %02x\n",DNKEY_CAPS); */ - handle_scancode(DNKEY_CAPS); + handle_scancode(DNKEY_CAPS, 1); /* printk("handle_scancode: %02x\n",BREAK_FLAG | DNKEY_CAPS); */ - handle_scancode(BREAK_FLAG | DNKEY_CAPS); + handle_scancode(DNKEY_CAPS, 0); } else if( (scancode == DNKEY_REPEAT) && (prev_scancode < 0x7e) && !(prev_scancode==DNKEY_CTRL || prev_scancode==DNKEY_LSHIFT || @@ -424,13 +424,13 @@ static void dn_keyb_process_key_event(unsigned char scancode) { prev_scancode==DNKEY_LALT || prev_scancode==DNKEY_RALT)) { if(jiffies-lastkeypress > DNKEY_REPEAT_DELAY) { /* printk("handle_scancode: %02x\n",prev_scancode); */ - handle_scancode(prev_scancode); + handle_scancode(prev_scancode, 1); } lastscancode=prev_scancode; } else { /* printk("handle_scancode: %02x\n",scancode); */ - handle_scancode(scancode); + handle_scancode(scancode & ~BREAK_FLAG, !(scancode & BREAK_FLAG)); lastkeypress=jiffies; } } diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c index fa7040e36b2d..607f4b664f51 100644 --- a/drivers/char/keyboard.c +++ b/drivers/char/keyboard.c @@ -24,6 +24,7 @@ */ #include +#include #include #include #include @@ -59,6 +60,8 @@ #define KBD_DEFLOCK 0 #endif +EXPORT_SYMBOL(handle_scancode); + extern void ctrl_alt_del(void); struct wait_queue * keypress_wait = NULL; @@ -190,15 +193,15 @@ int getkeycode(unsigned int scancode) return kbd_getkeycode(scancode); } -void handle_scancode(unsigned char scancode) +void handle_scancode(unsigned char scancode, int down) { unsigned char keycode; - char up_flag; /* 0 or 0200 */ + char up_flag = down ? 0 : 0200; char raw_mode; do_poke_blanked_console = 1; mark_bh(CONSOLE_BH); - add_keyboard_randomness(scancode); + add_keyboard_randomness(scancode | up_flag); tty = ttytab? ttytab[fg_console]: NULL; if (tty && (!tty->driver_data)) { @@ -213,20 +216,15 @@ void handle_scancode(unsigned char scancode) } kbd = kbd_table + fg_console; if ((raw_mode = (kbd->kbdmode == VC_RAW))) { - put_queue(scancode); + put_queue(scancode | up_flag); /* we do not return yet, because we want to maintain the key_down array, so that we have the correct values when finishing RAW mode or when changing VT's */ - } + } - if (!kbd_pretranslate(scancode, raw_mode)) - return; - /* + /* * Convert scancode to keycode - */ - up_flag = (scancode & 0200); - scancode &= 0x7f; - + */ if (!kbd_translate(scancode, &keycode, raw_mode)) return; @@ -239,10 +237,10 @@ void handle_scancode(unsigned char scancode) if (up_flag) { rep = 0; - if(!test_and_clear_bit(keycode, key_down)) + if(!test_and_clear_bit(keycode, key_down)) up_flag = kbd_unexpected_up(keycode); } else - rep = test_and_set_bit(keycode, key_down); + rep = test_and_set_bit(keycode, key_down); #ifdef CONFIG_MAGIC_SYSRQ /* Handle the SysRq Hack */ if (keycode == SYSRQ_KEY) { @@ -257,11 +255,11 @@ void handle_scancode(unsigned char scancode) if (kbd->kbdmode == VC_MEDIUMRAW) { /* soon keycodes will require more than one byte */ - put_queue(keycode + up_flag); + put_queue(keycode + up_flag); raw_mode = 1; /* Most key classes will be ignored */ - } + } - /* + /* * Small change in philosophy: earlier we defined repetition by * rep = keycode == prev_keycode; * prev_keycode = keycode; @@ -270,9 +268,9 @@ void handle_scancode(unsigned char scancode) */ /* - * Repeat a key only if the input buffers are empty or the - * characters get echoed locally. This makes key repeat usable - * with slow applications and under heavy loads. + * Repeat a key only if the input buffers are empty or the + * characters get echoed locally. This makes key repeat usable + * with slow applications and under heavy loads. */ if (!rep || (vc_kbd_mode(kbd,VC_REPEAT) && tty && diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 5f14bde50dd7..51ab86d8f00a 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -51,6 +51,12 @@ extern void mda_console_init(void); #if defined(CONFIG_PPC) || defined(CONFIG_MAC) extern void adbdev_init(void); #endif +#ifdef CONFIG_USB_UHCI +int uhci_init(void); +#endif +#ifdef CONFIG_USB_OHCI +int ohci_init(void); +#endif static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp, const char * buf, size_t count, loff_t *ppos) @@ -599,6 +605,12 @@ __initfunc(int chr_dev_init(void)) if (register_chrdev(MEM_MAJOR,"mem",&memory_fops)) printk("unable to get major %d for memory devs\n", MEM_MAJOR); rand_initialize(); +#ifdef CONFIG_USB_UHCI + uhci_init(); +#endif +#ifdef CONFIG_USB_OHCI + ohci_init(); +#endif #if defined (CONFIG_FB) fbmem_init(); #endif diff --git a/drivers/char/n_tty.c b/drivers/char/n_tty.c index 4bf35716bf26..1c6f93f44817 100644 --- a/drivers/char/n_tty.c +++ b/drivers/char/n_tty.c @@ -922,8 +922,14 @@ do_it_again: } } - if (down_interruptible(&tty->atomic_read)) - return -ERESTARTSYS; + if (file->f_flags & O_NONBLOCK) { + if (down_trylock(&tty->atomic_read)) + return -EAGAIN; + } + else { + if (down_interruptible(&tty->atomic_read)) + return -ERESTARTSYS; + } add_wait_queue(&tty->read_wait, &wait); set_bit(TTY_DONT_FLIP, &tty->flags); diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c index b1793daf0890..62f0c57bb99e 100644 --- a/drivers/char/pc_keyb.c +++ b/drivers/char/pc_keyb.c @@ -240,8 +240,6 @@ static unsigned char e0_keys[128] = { 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */ }; -static unsigned int prev_scancode = 0; /* remember E0, E1 */ - int pckbd_setkeycode(unsigned int scancode, unsigned int keycode) { if (scancode < SC_LIM || scancode > 255 || keycode > 127) @@ -284,41 +282,28 @@ static int do_acknowledge(unsigned char scancode) scancode); #endif } - if (scancode == 0) { -#ifdef KBD_REPORT_ERR - printk(KERN_INFO "Keyboard buffer overflow\n"); -#endif - prev_scancode = 0; - return 0; - } return 1; } -int pckbd_pretranslate(unsigned char scancode, char raw_mode) +int pckbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode) { - if (scancode == 0xff) { - /* in scancode mode 1, my ESC key generates 0xff */ - /* the calculator keys on a FOCUS 9000 generate 0xff */ -#ifndef KBD_IS_FOCUS_9000 -#ifdef KBD_REPORT_ERR - if (!raw_mode) - printk(KERN_DEBUG "Keyboard error\n"); -#endif -#endif - prev_scancode = 0; - return 0; - } + static int prev_scancode = 0; + /* special prefix scancodes.. */ if (scancode == 0xe0 || scancode == 0xe1) { prev_scancode = scancode; return 0; - } - return 1; -} + } + + /* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */ + if (scancode == 0x00 || scancode == 0xff) { + prev_scancode = 0; + return 0; + } + + scancode &= 0x7f; -int pckbd_translate(unsigned char scancode, unsigned char *keycode, - char raw_mode) -{ if (prev_scancode) { /* * usually it will be 0xe0, but a Pause key generates @@ -452,7 +437,7 @@ static unsigned char handle_kbd_event(void) handle_mouse_event(scancode); } else { if (do_acknowledge(scancode)) - handle_scancode(scancode); + handle_scancode(scancode, !(scancode & 0x80)); mark_bh(KEYBOARD_BH); } diff --git a/drivers/char/radio-sf16fmi.c b/drivers/char/radio-sf16fmi.c index 58f9918d1c0a..53333f082de8 100644 --- a/drivers/char/radio-sf16fmi.c +++ b/drivers/char/radio-sf16fmi.c @@ -4,6 +4,7 @@ * (c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz * * Fitted to new interface by Alan Cox + * Made working and cleaned up functions * * Notes on the hardware * @@ -74,9 +75,10 @@ static inline void fmi_unmute(int port) outb(0x08, port); } -static inline int fmi_setfreq(struct fmi_device *dev, unsigned long freq) +static inline int fmi_setfreq(struct fmi_device *dev) { int myport = dev->port; + unsigned long freq = dev->curfreq; int i; outbits(16, RSF16_ENCODE(freq), myport); @@ -158,7 +160,6 @@ static int fmi_ioctl(struct video_device *dev, unsigned int cmd, void *arg) v.flags=fmi->flags; v.mode=VIDEO_MODE_AUTO; v.signal = fmi_getsigstr(fmi); - strcpy(v.name, "FM"); if(copy_to_user(arg,&v, sizeof(v))) return -EFAULT; return 0; @@ -192,8 +193,10 @@ static int fmi_ioctl(struct video_device *dev, unsigned int cmd, void *arg) tmp *= 1000; if ( tmpRSF16_MAXFREQ ) return -EINVAL; - fmi->curfreq = tmp; - fmi_setfreq(fmi, fmi->curfreq); + /*rounding in steps of 800 to match th freq + that will be used */ + fmi->curfreq = (tmp/800)*800; + fmi_setfreq(fmi); return 0; } case VIDIOCGAUDIO: @@ -205,7 +208,7 @@ static int fmi_ioctl(struct video_device *dev, unsigned int cmd, void *arg) v.treble=0; v.flags=( (!fmi->curvol)*VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE); strcpy(v.name, "Radio"); - v.mode=VIDEO_SOUND_MONO; + v.mode=VIDEO_SOUND_STEREO; v.balance=0; v.step=0; /* No volume, just (un)mute */ if(copy_to_user(arg,&v, sizeof(v))) diff --git a/drivers/char/radio-typhoon.c b/drivers/char/radio-typhoon.c index 3282ea67a8ba..60e357a9b294 100644 --- a/drivers/char/radio-typhoon.c +++ b/drivers/char/radio-typhoon.c @@ -196,7 +196,7 @@ static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg) v.flags = VIDEO_TUNER_LOW; v.mode = VIDEO_MODE_AUTO; v.signal = 0xFFFF; /* We can't get the signal strength */ - strcpy(v.tuner, "FM"); + strcpy(v.name, "FM"); if (copy_to_user(arg, &v, sizeof(v))) return -EFAULT; return 0; diff --git a/drivers/char/softdog.c b/drivers/char/softdog.c index dc14c0e17a07..9dc9cbfe4d60 100644 --- a/drivers/char/softdog.c +++ b/drivers/char/softdog.c @@ -132,7 +132,6 @@ static ssize_t softdog_write(struct file *file, const char *data, size_t len, lo static int softdog_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - int i; static struct watchdog_info ident= { 0, diff --git a/drivers/macintosh/mac_keyb.c b/drivers/macintosh/mac_keyb.c index dbe7e4eb0fdf..5d6ee7bbe8d7 100644 --- a/drivers/macintosh/mac_keyb.c +++ b/drivers/macintosh/mac_keyb.c @@ -194,7 +194,7 @@ extern int console_loglevel; extern struct kbd_struct kbd_table[]; extern struct wait_queue * keypress_wait; -extern void handle_scancode(unsigned char); +extern void handle_scancode(unsigned char, int); static struct adb_ids keyboard_ids; static struct adb_ids mouse_ids; @@ -234,11 +234,6 @@ int mackbd_getkeycode(unsigned int scancode) return -EINVAL; } -int mackbd_pretranslate(unsigned char scancode, char raw_mode) -{ - return 1; -} - int mackbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode) { @@ -338,8 +333,8 @@ input_keycode(int keycode, int repeat) switch (keycode) { /*case 0xb9:*/ case 0x39: - handle_scancode(0x39); - handle_scancode(0xb9); + handle_scancode(0x39, 1); + handle_scancode(0x39, 0); mark_bh(KEYBOARD_BH); return; case 0x47: @@ -349,7 +344,7 @@ input_keycode(int keycode, int repeat) } } - handle_scancode(keycode + up_flag); + handle_scancode(keycode, !up_flag); } static void diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index d907fe7f3720..25daedb2dcbe 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -62,8 +62,8 @@ search the MCA slots until it finds a 3c523 with the specified parameters. - This driver should support multiple ethernet cards, but I can't test - that. If someone would I'd greatly appreciate it. + This driver does support multiple ethernet cards when used as a module + (up to MAX_3C523_CARDS, the default being 4) This has been tested with both BNC and TP versions, internal and external transceivers. Haven't tested with the 64K version (that I @@ -76,7 +76,12 @@ update to 1.3.59, incorporated multicast diffs from ni52.c Feb 15th, 1996 added shared irq support - + Apr 1999 + added support for multiple cards when used as a module + added option to disable multicast as is causes problems + Ganesh Sittampalam + Stuart Adamson + $Header: /fsys2/home/chrisb/linux-1.3.59-MCA/drivers/net/RCS/3c523.c,v 1.1 1996/02/05 01:53:46 chrisb Exp chrisb $ */ @@ -107,6 +112,7 @@ /*************************************************************************/ #define DEBUG /* debug on */ #define SYSBUSVAL 0 /* 1 = 8 Bit, 0 = 16 bit - 3c523 only does 16 bit */ +#undef ELMC_MULTICAST /* Disable multicast support as it is somewhat seriously broken at the moment */ #define make32(ptr16) (p->memtop + (short) (ptr16) ) #define make24(ptr32) ((char *) (ptr32) - p->base) @@ -180,7 +186,9 @@ static int elmc_open(struct device *dev); static int elmc_close(struct device *dev); static int elmc_send_packet(struct sk_buff *, struct device *); static struct net_device_stats *elmc_get_stats(struct device *dev); +#ifdef ELMC_MULTICAST static void set_multicast_list(struct device *dev); +#endif /* helper-functions */ static int init586(struct device *dev); @@ -432,21 +440,19 @@ __initfunc(int elmc_probe(struct device *dev)) while (slot != -1) { status = mca_read_stored_pos(slot, 2); + dev->irq=irq_table[(status & ELMC_STATUS_IRQ_SELECT) >> 6]; + dev->base_addr=csr_table[(status & ELMC_STATUS_CSR_SELECT) >> 1]; + /* If we're trying to match a specified irq or IO address, we'll reject a match unless it's what we're looking for. + Also reject it if the card is already in use. */ - if (base_addr || irq) { - /* we're looking for a card at a particular place */ - if (irq && irq != irq_table[(status & ELMC_STATUS_IRQ_SELECT) >> 6]) { - slot = mca_find_adapter(ELMC_MCA_ID, slot + 1); - continue; - } - if (base_addr && base_addr != csr_table[(status & ELMC_STATUS_CSR_SELECT) >> 1]) { - slot = mca_find_adapter(ELMC_MCA_ID, slot + 1); - continue; - } + if((irq && irq != dev->irq) || (base_addr && base_addr != dev->base_addr) + || check_region(dev->base_addr,ELMC_IO_EXTENT)) { + slot = mca_find_adapter(ELMC_MCA_ID, slot + 1); + continue; } /* found what we're looking for... */ break; @@ -476,9 +482,6 @@ __initfunc(int elmc_probe(struct device *dev)) /* revision is stored in the first 4 bits of the revision register */ revision = inb(dev->base_addr + ELMC_REVISION) & 0xf; - /* figure out our irq */ - dev->irq = irq_table[(status & ELMC_STATUS_IRQ_SELECT) >> 6]; - /* according to docs, we read the interrupt and write it back to the IRQ select register, since the POST might not configure the IRQ properly. */ @@ -497,9 +500,6 @@ __initfunc(int elmc_probe(struct device *dev)) break; } - /* Our IO address? */ - dev->base_addr = csr_table[(status & ELMC_STATUS_CSR_SELECT) >> 1]; - request_region(dev->base_addr, ELMC_IO_EXTENT, "3c523"); dev->priv = (void *) kmalloc(sizeof(struct priv), GFP_KERNEL); @@ -565,7 +565,11 @@ __initfunc(int elmc_probe(struct device *dev)) dev->stop = &elmc_close; dev->get_stats = &elmc_get_stats; dev->hard_start_xmit = &elmc_send_packet; +#ifdef ELMC_MULTICAST dev->set_multicast_list = &set_multicast_list; +#else + dev->set_multicast_list = NULL; +#endif ether_setup(dev); @@ -577,6 +581,10 @@ __initfunc(int elmc_probe(struct device *dev)) That gets done in elmc_open(). I'm not sure that's such a good idea, but it works, so I'll go with it. */ +#ifndef ELMC_MULTICAST + dev->flags&=~IFF_MULTICAST; /* Multicast doesn't work */ +#endif + return 0; } @@ -1210,6 +1218,7 @@ static struct net_device_stats *elmc_get_stats(struct device *dev) * Set MC list .. */ +#ifdef ELMC_MULTICAST static void set_multicast_list(struct device *dev) { if (!dev->start) { @@ -1222,60 +1231,85 @@ static void set_multicast_list(struct device *dev) startrecv586(dev); dev->start = 1; } +#endif /*************************************************************************/ #ifdef MODULE -static char devicename[9] = {0,}; +/* Increase if needed ;) */ +#define MAX_3C523_CARDS 4 +/* I'm not sure where this magic 9 comes from */ +#define NAMELEN 9 -static struct device dev_elmc = -{ - devicename /*"3c523" */ , 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, elmc_probe +static char devicenames[NAMELEN * MAX_3C523_CARDS] = {0,}; + +static struct device dev_elmc[MAX_3C523_CARDS] = +{ + { + NULL /*"3c523" */ , 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL + }, }; -static int irq = 0; -static int io = 0; -MODULE_PARM(irq, "i"); -MODULE_PARM(io, "i"); +static int irq[MAX_3C523_CARDS] = {0,}; +static int io[MAX_3C523_CARDS] = {0,}; +MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_3C523_CARDS) "i"); +MODULE_PARM(io, "1-" __MODULE_STRING(MAX_3C523_CARDS) "i"); int init_module(void) { - struct device *dev = &dev_elmc; - - dev->base_addr = io; - dev->irq = irq; - if (register_netdev(dev) != 0) { - return -EIO; + int this_dev,found = 0; + + /* Loop until we either can't find any more cards, or we have MAX_3C523_CARDS */ + for(this_dev=0; this_devname=devicenames+(NAMELEN*this_dev); + dev->irq=irq[this_dev]; + dev->base_addr=io[this_dev]; + dev->init=elmc_probe; + if(register_netdev(dev)!=0) { + if(io[this_dev]==0) break; + printk(KERN_WARNING "3c523.c: No 3c523 card found at io=%#x\n",io[this_dev]); + } else found++; } - return 0; + + if(found==0) { + if(io[0]==0) printk(KERN_NOTICE "3c523.c: No 3c523 cards found\n"); + return -ENXIO; + } else return 0; } void cleanup_module(void) { - struct device *dev = &dev_elmc; - - /* shutdown interrupts on the card */ - elmc_id_reset586(); - if (dev->irq != 0) { - /* this should be done by close, but if we failed to - initialize properly something may have gotten hosed. */ - free_irq(dev->irq, dev); - dev->irq = 0; - } - if (dev->base_addr != 0) { - release_region(dev->base_addr, ELMC_IO_EXTENT); - dev->base_addr = 0; - } - irq = 0; - io = 0; - unregister_netdev(dev); + int this_dev; + for(this_dev=0; this_devpriv) { + /* shutdown interrupts on the card */ + elmc_id_reset586(); + if (dev->irq != 0) { + /* this should be done by close, but if we failed to + initialize properly something may have gotten hosed. */ + free_irq(dev->irq, dev); + dev->irq = 0; + } + if (dev->base_addr != 0) { + release_region(dev->base_addr, ELMC_IO_EXTENT); + dev->base_addr = 0; + } + irq[this_dev] = 0; + io[this_dev] = 0; + unregister_netdev(dev); - mca_set_adapter_procfn(((struct priv *) (dev->priv))->slot, + mca_set_adapter_procfn(((struct priv *) (dev->priv))->slot, NULL, NULL); - kfree_s(dev->priv, sizeof(struct priv)); - dev->priv = NULL; + kfree_s(dev->priv, sizeof(struct priv)); + dev->priv = NULL; + } + } } #endif /* MODULE */ diff --git a/drivers/net/ibmtr.c b/drivers/net/ibmtr.c index 6df5b821aa33..9d63a442d2d8 100644 --- a/drivers/net/ibmtr.c +++ b/drivers/net/ibmtr.c @@ -70,6 +70,12 @@ * Changes by Joel Sloan (jjs@c-me.com) : * + disable verbose debug messages by default - to enable verbose * debugging, edit the IBMTR_DEBUG_MESSAGES define below + * + * Changes by Mike Phillips : + * + Added extra #ifdef's to work with new PCMCIA Token Ring Code. + * The PCMCIA code now just sets up the card so it can be recognized + * by ibmtr_probe. Also checks allocated memory vs. on-board memory + * for correct figure to use. * * Changes by Tim Hockin (thockin@isunix.it.ilstu.edu) : * + added spinlocks for SMP sanity (10 March 1999) @@ -94,6 +100,7 @@ in the event that chatty debug messages are desired - jjs 12/30/98 */ #undef NO_AUTODETECT #undef ENABLE_PAGING + #define FALSE 0 #define TRUE (!FALSE) @@ -191,6 +198,9 @@ unsigned char ibmtr_debug_trace=0; int ibmtr_probe(struct device *dev); static int ibmtr_probe1(struct device *dev, int ioaddr); static unsigned char get_sram_size(struct tok_info *adapt_info); +#ifdef PCMCIA +extern unsigned char pcmcia_reality_check(unsigned char gss); +#endif static int tok_init_card(struct device *dev); void tok_interrupt(int irq, void *dev_id, struct pt_regs *regs); static int trdev_init(struct device *dev); @@ -256,7 +266,9 @@ __initfunc(int ibmtr_probe(struct device *dev)) if (ibmtr_probe1(dev, base_addr)) { #ifndef MODULE +#ifndef PCMCIA tr_freedev(dev); +#endif #endif return -ENODEV; } else @@ -272,7 +284,9 @@ __initfunc(int ibmtr_probe(struct device *dev)) continue; if (ibmtr_probe1(dev, ioaddr)) { #ifndef MODULE +#ifndef PCMCIA tr_freedev(dev); +#endif #endif } else return 0; @@ -291,7 +305,9 @@ __initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr)) unsigned long timeout; #ifndef MODULE +#ifndef PCMCIA dev = init_trdev(dev,0); +#endif #endif /* Query the adapter PIO base port which will return @@ -300,7 +316,7 @@ __initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr)) */ segment = inb(PIOaddr); - + /* * Out of range values so we'll assume non-existent IO device */ @@ -373,12 +389,19 @@ __initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr)) } /* Now, allocate some of the pl0 buffers for this driver.. */ + + /* If called from PCMCIA, ti is already set up, so no need to + waste the memory, just use the existing structure */ + +#ifndef PCMCIA ti = (struct tok_info *)kmalloc(sizeof(struct tok_info), GFP_KERNEL); if (ti == NULL) return -ENOMEM; memset(ti, 0, sizeof(struct tok_info)); - +#else + ti = dev->priv ; +#endif ti->mmio= t_mmio; ti->readlog_pending = 0; @@ -388,6 +411,10 @@ __initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr)) should fit with out future hope of multiple adapter support as well /dwm */ + /* if PCMCIA, then the card is recognized as TR_ISAPNP + * and there is no need to set up the interrupt, it is already done. */ + +#ifndef PCMCIA switch (cardpresent) { case TR_ISA: @@ -428,7 +455,6 @@ __initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr)) irq=10; if (intr==3) irq=11; - timeout = jiffies + TR_SPIN_INTERVAL; while(!readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)) if (time_after(jiffies, timeout)) { @@ -436,11 +462,13 @@ __initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr)) kfree_s(ti, sizeof(struct tok_info)); return -ENODEV; } + ti->sram=((__u32)readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)<<12); ti->global_int_enable=PIOaddr+ADAPTINTREL; ti->adapter_int_enable=PIOaddr+ADAPTINTREL; break; } +#endif if (ibmtr_debug_trace & TRC_INIT) { /* just report int */ DPRINTK("irq=%d",irq); @@ -483,8 +511,11 @@ __initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr)) ti->token_release = readb(ti->mmio + AIPEARLYTOKEN); /* How much shared RAM is on adapter ? */ +#ifdef PCMCIA + ti->avail_shared_ram = pcmcia_reality_check(get_sram_size(ti)); +#else ti->avail_shared_ram = get_sram_size(ti); - +#endif /* We need to set or do a bunch of work here based on previous results.. */ /* Support paging? What sizes?: F=no, E=16k, D=32k, C=16 & 32k */ ti->shared_ram_paging = readb(ti->mmio + AIPSHRAMPAGE); @@ -593,7 +624,6 @@ __initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr)) } #endif } - /* finish figuring the shared RAM address */ if (cardpresent==TR_ISA) { static __u32 ram_bndry_mask[]={0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000}; @@ -619,15 +649,20 @@ __initfunc(static int ibmtr_probe1(struct device *dev, int PIOaddr)) DPRINTK("Using %dK shared RAM\n",ti->mapped_ram_size/2); #endif + /* The PCMCIA has already got the interrupt line and the io port, + so no chance of anybody else getting it - MLP */ + +#ifndef PCMCIA if (request_irq (dev->irq = irq, &tok_interrupt,0,"ibmtr", dev) != 0) { DPRINTK("Could not grab irq %d. Halting Token Ring driver.\n",irq); kfree_s(ti, sizeof(struct tok_info)); return -ENODEV; } + + /*?? Now, allocate some of the PIO PORTs for this driver.. */ + request_region(PIOaddr,IBMTR_IO_EXTENT,"ibmtr"); /* record PIOaddr range as busy */ +#endif - /*?? Now, allocate some of the PIO PORTs for this driver.. */ - request_region(PIOaddr,IBMTR_IO_EXTENT,"ibmtr"); /* record PIOaddr range - as busy */ #if !TR_NEWFORMAT DPRINTK("%s",version); /* As we have passed card identification, let the world know we're here! */ @@ -717,7 +752,6 @@ __initfunc(static unsigned char get_sram_size(struct tok_info *adapt_info)) unsigned char avail_sram_code; static unsigned char size_code[]={ 0,16,32,64,127,128 }; - /* Adapter gives 'F' -- use RRR bits 3,2 'E' -- 8kb 'D' -- 16kb @@ -747,7 +781,9 @@ __initfunc(static int trdev_init(struct device *dev)) dev->change_mtu = ibmtr_change_mtu; #ifndef MODULE +#ifndef PCMCIA tr_setup(dev); +#endif #endif return 0; } @@ -842,7 +878,7 @@ void tok_interrupt (int irq, void *dev_id, struct pt_regs *regs) DPRINTK("PCMCIA card removed.\n"); spin_unlock(&(ti->lock)); dev->interrupt = 0; - return; + return; } /* Check ISRP EVEN too. */ @@ -1186,7 +1222,6 @@ static void initial_tok_int(struct device *dev) __u32 encoded_addr; __u32 hw_encoded_addr; struct tok_info *ti; - ti=(struct tok_info *) dev->priv; ti->do_tok_int=NOT_FIRST; diff --git a/drivers/net/irda/actisys.c b/drivers/net/irda/actisys.c index 513b9ba30bd6..46ce2badfb85 100644 --- a/drivers/net/irda/actisys.c +++ b/drivers/net/irda/actisys.c @@ -7,7 +7,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Wed Oct 21 20:02:35 1998 - * Modified at: Tue Feb 9 15:38:16 1999 + * Modified at: Mon Apr 12 11:56:35 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli, All Rights Reserved. @@ -234,8 +234,8 @@ static void actisys_init_qos( struct irda_device *idev, struct qos_info *qos) /* Remove support for 38400 if this is not a 220L+ dongle */ if ( idev->io.dongle_id == ACTISYS_DONGLE) qos->baud_rate.bits &= ~IR_38400; - - qos->min_turn_time.bits &= 0xfe; /* All except 0 ms */ + + qos->min_turn_time.bits &= 0x40; /* Needs 0.01 ms */ } #ifdef MODULE diff --git a/drivers/net/irda/esi.c b/drivers/net/irda/esi.c index 8bdf796ef730..5395d2829688 100644 --- a/drivers/net/irda/esi.c +++ b/drivers/net/irda/esi.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Thomas Davis, * Created at: Sat Feb 21 18:54:38 1998 - * Modified at: Tue Feb 9 15:36:47 1999 + * Modified at: Mon Apr 12 11:55:30 1999 * Modified by: Dag Brattli * Sources: esi.c * @@ -56,9 +56,9 @@ static struct dongle dongle = { esi_qos_init, }; -__initfunc(void esi_init(void)) +__initfunc(int esi_init(void)) { - irtty_register_dongle( &dongle); + return irtty_register_dongle(&dongle); } void esi_cleanup(void) @@ -132,7 +132,7 @@ static void esi_change_speed( struct irda_device *idev, int baud) } /* Change speed of serial driver */ tty->termios->c_cflag = cflag; - tty->driver.set_termios( tty, &old_termios); + tty->driver.set_termios(tty, &old_termios); irtty_set_dtr_rts(tty, dtr, rts); } @@ -151,6 +151,7 @@ static void esi_reset( struct irda_device *idev, int unused) static void esi_qos_init( struct irda_device *idev, struct qos_info *qos) { qos->baud_rate.bits &= IR_9600|IR_19200|IR_115200; + qos->min_turn_time.bits &= 0x01; /* Needs at least 10 ms */ } #ifdef MODULE @@ -163,8 +164,7 @@ static void esi_qos_init( struct irda_device *idev, struct qos_info *qos) */ int init_module(void) { - esi_init(); - return(0); + return esi_init(); } /* diff --git a/drivers/net/irda/girbil.c b/drivers/net/irda/girbil.c index f74186b6ae4c..128b32a23e22 100644 --- a/drivers/net/irda/girbil.c +++ b/drivers/net/irda/girbil.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sat Feb 6 21:02:33 1999 - * Modified at: Tue Feb 9 15:36:36 1999 + * Modified at: Sat Apr 10 19:53:12 1999 * Modified by: Dag Brattli * * Copyright (c) 1999 Dag Brattli, All Rights Reserved. @@ -195,7 +195,7 @@ void girbil_reset(struct irda_device *idev, int unused) { struct irtty_cb *self; struct tty_struct *tty; - __u8 control = GIRBIL_TXEN | GIRBIL_RXEN /* | GIRBIL_ECAN */; + __u8 control = GIRBIL_TXEN | GIRBIL_RXEN; ASSERT(idev != NULL, return;); ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); diff --git a/drivers/net/irda/irport.c b/drivers/net/irda/irport.c index 6f23506528e5..5ea6dba738a0 100644 --- a/drivers/net/irda/irport.c +++ b/drivers/net/irda/irport.c @@ -1,7 +1,7 @@ /********************************************************************* * * Filename: irport.c - * Version: 0.8 + * Version: 0.9 * Description: Serial driver for IrDA. * Status: Experimental. * Author: Dag Brattli @@ -9,7 +9,6 @@ * Modified at: Sat May 23 23:15:20 1998 * Modified by: Dag Brattli * Sources: serial.c by Linus Torvalds - * serial_serial.c by Aage Kvalnes * * Copyright (c) 1997,1998 Dag Brattli * All Rights Reserved. @@ -25,10 +24,10 @@ * * NOTICE: * - * This driver is ment to be a small serial driver to be used for - * IR-chipsets that has a UART (16550) compatibility mode. If your - * chipset is is UART only, you should probably use IrTTY instead since - * the Linux serial driver is probably more robust and optimized. + * This driver is ment to be a small half duplex serial driver to be + * used for IR-chipsets that has a UART (16550) compatibility mode. If + * your chipset is is UART only, you should probably use IrTTY instead + * since the Linux serial driver is probably more robust and optimized. * * The functions in this file may be used by FIR drivers, but this * driver knows nothing about FIR drivers so don't ever insert such @@ -64,7 +63,6 @@ #include #define IO_EXTENT 8 -#define CONFIG_HALF_DUPLEX /* static unsigned int io[] = { 0x3e8, ~0, ~0, ~0 }; */ /* static unsigned int irq[] = { 11, 0, 0, 0 }; */ @@ -114,7 +112,7 @@ static void irport_cleanup(void) * Start IO port * */ -int irport_open( int iobase) +int irport_open(int iobase) { DEBUG(4, __FUNCTION__ "(), iobase=%#x\n", iobase); @@ -134,7 +132,7 @@ int irport_open( int iobase) * Stop IO port * */ -void irport_close( int iobase) +void irport_close(int iobase) { DEBUG(4, __FUNCTION__ "()\n"); @@ -142,7 +140,7 @@ void irport_close( int iobase) outb(0, iobase+UART_MCR); /* Turn off interrupts */ - outb(0, iobase+UART_IER); + outb(0, iobase+UART_IER); } /* @@ -186,16 +184,22 @@ void irport_change_speed( int iobase, int speed) * more packets to send, we send them here. * */ -static void irport_write_wakeup( struct irda_device *idev) +static void irport_write_wakeup(struct irda_device *idev) { - int actual = 0, count; + int actual = 0; int iobase; ASSERT(idev != NULL, return;); ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); /* Finished with frame? */ - if (idev->tx_buff.offset == idev->tx_buff.len) { + if (idev->tx_buff.len > 0) { + /* Write data left in transmit buffer */ + actual = irport_write(idev->io.iobase2, idev->io.fifo_size, + idev->tx_buff.data, idev->tx_buff.len); + idev->tx_buff.data += actual; + idev->tx_buff.len -= actual; + } else { iobase = idev->io.iobase2; /* * Now serial buffer is almost free & we can start @@ -206,23 +210,14 @@ static void irport_write_wakeup( struct irda_device *idev) /* Schedule network layer, so we can get some more frames */ mark_bh(NET_BH); -#ifdef CONFIG_HALF_DUPLEX + outb(UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_14 | UART_FCR_CLEAR_RCVR, iobase+UART_FCR); /* Enable FIFO's */ /* Turn on receive interrupts */ outb(UART_IER_RLSI|UART_IER_RDI, iobase+UART_IER); -#endif - return; } - - /* Write data left in transmit buffer */ - count = idev->tx_buff.len - idev->tx_buff.offset; - actual = irport_write(idev->io.iobase2, idev->io.fifo_size, - idev->tx_buff.head, count); - idev->tx_buff.offset += actual; - idev->tx_buff.head += actual; } /* @@ -283,22 +278,19 @@ int irport_hard_xmit(struct sk_buff *skb, struct device *dev) if (irda_lock((void *) &dev->tbusy) == FALSE) return -EBUSY; - /* - * Transfer skb to tx_buff while wrapping, stuffing and making CRC - */ + /* Init tx buffer */ + idev->tx_buff.data = idev->tx_buff.head; + + /* Copy skb to tx_buff while wrapping, stuffing and making CRC */ idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data, idev->tx_buff.truesize); -/* actual = irport_write(idev->io.iobase2, idev->io.fifo_size, */ -/* idev->tx_buff.data, idev->tx_buff.len); */ - - idev->tx_buff.offset = actual; - idev->tx_buff.head = idev->tx_buff.data + actual; + idev->tx_buff.data += actual; + idev->tx_buff.len -= actual; -#ifdef CONFIG_HALF_DUPLEX /* Turn on transmit finished interrupt. Will fire immediately! */ outb(UART_IER_THRI, iobase+UART_IER); -#endif + dev_kfree_skb(skb); return 0; @@ -318,44 +310,37 @@ static void irport_receive(struct irda_device *idev) if (!idev) return; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); iobase = idev->io.iobase2; - if (idev->rx_buff.len == 0) - idev->rx_buff.head = idev->rx_buff.data; - /* * Receive all characters in Rx FIFO, unwrap and unstuff them. * async_unwrap_char will deliver all found frames */ do { - async_unwrap_char(idev, inb( iobase+UART_RX)); + async_unwrap_char(idev, inb(iobase+UART_RX)); /* Make sure we don't stay here to long */ if (boguscount++ > 32) { DEBUG(0,__FUNCTION__ "(), breaking!\n"); break; } - } while (inb(iobase+UART_LSR) & UART_LSR_DR); } /* * Function irport_interrupt (irq, dev_id, regs) * - * + * Interrupt handler */ void irport_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct irda_device *idev = (struct irda_device *) dev_id; - int iobase; int iir, lsr; int boguscount = 0; - DEBUG(5, __FUNCTION__ "(), irq %d\n", irq); - if (!idev) { printk(KERN_WARNING __FUNCTION__ "() irq %d for unknown device.\n", irq); @@ -368,19 +353,13 @@ void irport_interrupt(int irq, void *dev_id, struct pt_regs *regs) iir = inb(iobase + UART_IIR) & UART_IIR_ID; while (iir) { - DEBUG(4,__FUNCTION__ "(), iir=%#x\n", iir); - /* Clear interrupt */ lsr = inb(iobase+UART_LSR); if ((iir & UART_IIR_THRI) && (lsr & UART_LSR_THRE)) { /* Transmitter ready for data */ irport_write_wakeup(idev); - } -#ifdef CONFIG_HALF_DUPLEX - else -#endif - if ((iir & UART_IIR_RDI) && (lsr & UART_LSR_DR)) { + } else if ((iir & UART_IIR_RDI) && (lsr & UART_LSR_DR)) { /* Receive interrupt */ irport_receive(idev); } @@ -394,7 +373,6 @@ void irport_interrupt(int irq, void *dev_id, struct pt_regs *regs) idev->netdev.interrupt = 0; } - #ifdef MODULE /* diff --git a/drivers/net/irda/irtty.c b/drivers/net/irda/irtty.c index 8ea10d9a8f21..cc7ab91a4c49 100644 --- a/drivers/net/irda/irtty.c +++ b/drivers/net/irda/irtty.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Tue Dec 9 21:18:38 1997 - * Modified at: Tue Apr 6 21:35:25 1999 + * Modified at: Thu Apr 22 09:20:24 1999 * Modified by: Dag Brattli * Sources: slip.c by Laurence Culhane, * Fred N. van Kempen, @@ -45,22 +45,22 @@ static hashbin_t *dongles = NULL; static struct tty_ldisc irda_ldisc; -static int irtty_hard_xmit( struct sk_buff *skb, struct device *dev); -static void irtty_wait_until_sent( struct irda_device *driver); -static int irtty_is_receiving( struct irda_device *idev); -static int irtty_net_init( struct device *dev); +static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev); +static void irtty_wait_until_sent(struct irda_device *driver); +static int irtty_is_receiving(struct irda_device *idev); +static int irtty_net_init(struct device *dev); static int irtty_net_open(struct device *dev); static int irtty_net_close(struct device *dev); -static int irtty_open( struct tty_struct *tty); -static void irtty_close( struct tty_struct *tty); -static int irtty_ioctl( struct tty_struct *, void *, int, void *); -static int irtty_receive_room( struct tty_struct *tty); -static void irtty_change_speed( struct irda_device *dev, int baud); -static void irtty_write_wakeup( struct tty_struct *tty); +static int irtty_open(struct tty_struct *tty); +static void irtty_close(struct tty_struct *tty); +static int irtty_ioctl(struct tty_struct *, void *, int, void *); +static int irtty_receive_room(struct tty_struct *tty); +static void irtty_change_speed(struct irda_device *dev, int baud); +static void irtty_write_wakeup(struct tty_struct *tty); -static void irtty_receive_buf( struct tty_struct *, const unsigned char *, - char *, int); +static void irtty_receive_buf(struct tty_struct *, const unsigned char *, + char *, int); char *driver_name = "irtty"; __initfunc(int irtty_init(void)) @@ -73,15 +73,15 @@ __initfunc(int irtty_init(void)) return -ENOMEM; } - dongles = hashbin_new( HB_LOCAL); - if ( dongles == NULL) { - printk( KERN_WARNING - "IrDA: Can't allocate dongles hashbin!\n"); + dongles = hashbin_new(HB_LOCAL); + if (dongles == NULL) { + printk(KERN_WARNING + "IrDA: Can't allocate dongles hashbin!\n"); return -ENOMEM; } /* Fill in our line protocol discipline, and register it */ - memset( &irda_ldisc, 0, sizeof( irda_ldisc)); + memset(&irda_ldisc, 0, sizeof( irda_ldisc)); irda_ldisc.magic = TTY_LDISC_MAGIC; irda_ldisc.name = "irda"; @@ -97,10 +97,10 @@ __initfunc(int irtty_init(void)) irda_ldisc.receive_room = irtty_receive_room; irda_ldisc.write_wakeup = irtty_write_wakeup; - if (( status = tty_register_ldisc( N_IRDA, &irda_ldisc)) != 0) { - printk( KERN_ERR - "IrDA: can't register line discipline (err = %d)\n", - status); + if (( status = tty_register_ldisc(N_IRDA, &irda_ldisc)) != 0) { + printk(KERN_ERR + "IrDA: can't register line discipline (err = %d)\n", + status); } return status; @@ -120,10 +120,10 @@ static void irtty_cleanup(void) /* * Unregister tty line-discipline */ - if (( ret = tty_register_ldisc( N_IRDA, NULL))) { - printk( KERN_ERR - "IrTTY: can't unregister line discipline (err = %d)\n", - ret); + if ((ret = tty_register_ldisc(N_IRDA, NULL))) { + ERROR(__FUNCTION__ + "(), can't unregister line discipline (err = %d)\n", + ret); } /* @@ -131,8 +131,8 @@ static void irtty_cleanup(void) * callback to irtty_close(), therefore we do give any deallocation * function to hashbin_destroy(). */ - hashbin_delete( irtty, NULL); - hashbin_delete( dongles, NULL); + hashbin_delete(irtty, NULL); + hashbin_delete(dongles, NULL); } #endif /* MODULE */ @@ -143,47 +143,45 @@ static void irtty_cleanup(void) * discipline is called for. Because we are sure the tty line exists, * we only have to link it to a free IrDA channel. */ -static int irtty_open( struct tty_struct *tty) +static int irtty_open(struct tty_struct *tty) { struct irtty_cb *self; char name[16]; - ASSERT( tty != NULL, return -EEXIST;); + ASSERT(tty != NULL, return -EEXIST;); /* First make sure we're not already connected. */ self = (struct irtty_cb *) tty->disc_data; - if ( self != NULL && self->magic == IRTTY_MAGIC) + if (self != NULL && self->magic == IRTTY_MAGIC) return -EEXIST; /* * Allocate new instance of the driver */ - self = kmalloc( sizeof(struct irtty_cb), GFP_KERNEL); - if ( self == NULL) { - printk( KERN_ERR "IrDA: Can't allocate memory for " - "IrDA control block!\n"); + self = kmalloc(sizeof(struct irtty_cb), GFP_KERNEL); + if (self == NULL) { + printk(KERN_ERR "IrDA: Can't allocate memory for " + "IrDA control block!\n"); return -ENOMEM; } - memset( self, 0, sizeof(struct irtty_cb)); + memset(self, 0, sizeof(struct irtty_cb)); self->tty = tty; tty->disc_data = self; /* Give self a name */ - sprintf( name, "%s%d", tty->driver.name, - MINOR(tty->device) - tty->driver.minor_start + - tty->driver.name_base); - + sprintf(name, "%s%d", tty->driver.name, + MINOR(tty->device) - tty->driver.minor_start + + tty->driver.name_base); + /* hashbin_insert( irtty, (QUEUE*) self, 0, self->name); */ - hashbin_insert( irtty, (QUEUE*) self, (int) self, NULL); + hashbin_insert(irtty, (QUEUE*) self, (int) self, NULL); - if (tty->driver.flush_buffer) { + if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); - } - - if (tty->ldisc.flush_buffer) { + + if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); - } self->magic = IRTTY_MAGIC; @@ -198,12 +196,12 @@ static int irtty_open( struct tty_struct *tty) * that are not device dependent (such as link disconnect time) so * this parameter can be set by IrLAP (or the user) instead. DB */ - irda_init_max_qos_capabilies( &self->idev.qos); + irda_init_max_qos_capabilies(&self->idev.qos); /* The only value we must override it the baudrate */ self->idev.qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| IR_115200; - self->idev.qos.min_turn_time.bits = 0x03; + self->idev.qos.min_turn_time.bits = 0x0f; self->idev.flags = IFF_SIR | IFF_PIO; irda_qos_bits_to_value(&self->idev.qos); @@ -236,7 +234,7 @@ static int irtty_open( struct tty_struct *tty) } /* - * Function irtty_close ( tty) + * Function irtty_close (tty) * * Close down a IrDA channel. This means flushing out any pending queues, * and then restoring the TTY line discipline to what it was before it got @@ -272,14 +270,40 @@ static void irtty_close(struct tty_struct *tty) MOD_DEC_USE_COUNT; } +/* + * Function irtty_stop_receiver (irda_device, stop) + * + * + * + */ +static void irtty_stop_receiver(struct irda_device *idev, int stop) +{ + struct termios old_termios; + struct irtty_cb *self; + int cflag; + + self = (struct irtty_cb *) idev->priv; + + old_termios = *(self->tty->termios); + cflag = self->tty->termios->c_cflag; + + if (stop) + cflag &= ~CREAD; + else + cflag |= CREAD; + + self->tty->termios->c_cflag = cflag; + self->tty->driver.set_termios(self->tty, &old_termios); +} + /* - * Function irtty_change_speed ( self, baud) + * Function irtty_change_speed (self, baud) * * Change the speed of the serial port. The driver layer must check that * all transmission has finished using the irtty_wait_until_sent() * function. */ -static void irtty_change_speed( struct irda_device *idev, int baud) +static void irtty_change_speed(struct irda_device *idev, int baud) { struct termios old_termios; struct irtty_cb *self; @@ -287,22 +311,22 @@ static void irtty_change_speed( struct irda_device *idev, int baud) DEBUG(4,__FUNCTION__ "(), <%ld>\n", jiffies); - ASSERT( idev != NULL, return;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); self = (struct irtty_cb *) idev->priv; - ASSERT( self != NULL, return;); - ASSERT( self->magic == IRTTY_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == IRTTY_MAGIC, return;); old_termios = *(self->tty->termios); cflag = self->tty->termios->c_cflag; cflag &= ~CBAUD; - DEBUG( 4, __FUNCTION__ "(), Setting speed to %d\n", baud); + DEBUG(4, __FUNCTION__ "(), Setting speed to %d\n", baud); - switch( baud) { + switch (baud) { case 1200: cflag |= B1200; break; @@ -331,7 +355,7 @@ static void irtty_change_speed( struct irda_device *idev, int baud) } self->tty->termios->c_cflag = cflag; - self->tty->driver.set_termios( self->tty, &old_termios); + self->tty->driver.set_termios(self->tty, &old_termios); } /* @@ -340,43 +364,42 @@ static void irtty_change_speed( struct irda_device *idev, int baud) * Initialize attached dongle. Warning, must be called with a process * context! */ -static void irtty_init_dongle( struct irtty_cb *self, int type) +static void irtty_init_dongle(struct irtty_cb *self, int type) { struct dongle_q *node; - ASSERT( self != NULL, return;); - ASSERT( self->magic == IRTTY_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == IRTTY_MAGIC, return;); #ifdef CONFIG_KMOD /* Try to load the module needed */ switch( type) { case ESI_DONGLE: - DEBUG( 0, __FUNCTION__ "(), ESI dongle!\n"); - request_module( "esi"); + MESSAGE("IrDA: Trying to initialize ESI dongle!\n"); + request_module("esi"); break; case TEKRAM_DONGLE: - DEBUG( 0, __FUNCTION__ "(), Tekram dongle!\n"); - request_module( "tekram"); + MESSAGE("IrDA: Trying to initialize Tekram dongle!\n"); + request_module("tekram"); break; case ACTISYS_DONGLE: /* FALLTHROUGH */ case ACTISYS_PLUS_DONGLE: - DEBUG( 0, __FUNCTION__ "(), ACTiSYS dongle!\n"); - request_module( "actisys"); + MESSAGE("IrDA: Trying to initialize ACTiSYS dongle!\n"); + request_module("actisys"); break; case GIRBIL_DONGLE: - DEBUG( 0, __FUNCTION__ "(), GIrBIL dongle!\n"); - request_module( "girbil"); + MESSAGE("IrDA: Trying to initialize GIrBIL dongle!\n"); + request_module("girbil"); break; default: - DEBUG( 0, __FUNCTION__ "(), Unknown dongle type!\n"); + ERROR("Unknown dongle type!\n"); return; - break; } #endif /* CONFIG_KMOD */ - node = hashbin_find( dongles, type, NULL); + node = hashbin_find(dongles, type, NULL); if ( !node) { - DEBUG(0, __FUNCTION__ "(), Unable to find requested dongle\n"); + ERROR("Unable to find requested dongle\n"); return; } self->dongle_q = node; @@ -387,14 +410,14 @@ static void irtty_init_dongle( struct irtty_cb *self, int type) /* * Now initialize the dongle! */ - node->dongle->open( &self->idev, type); - node->dongle->qos_init( &self->idev, &self->idev.qos); + node->dongle->open(&self->idev, type); + node->dongle->qos_init(&self->idev, &self->idev.qos); /* Reset dongle */ - node->dongle->reset( &self->idev, 0); + node->dongle->reset(&self->idev, 0); /* Set to default baudrate */ - node->dongle->change_speed( &self->idev, 9600); + node->dongle->change_speed(&self->idev, 9600); } /* @@ -411,25 +434,25 @@ static int irtty_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg) self = (struct irtty_cb *) tty->disc_data; - ASSERT( self != NULL, return -ENODEV;); - ASSERT( self->magic == IRTTY_MAGIC, return -EBADR;); + ASSERT(self != NULL, return -ENODEV;); + ASSERT(self->magic == IRTTY_MAGIC, return -EBADR;); - if ( _IOC_DIR(cmd) & _IOC_READ) + if (_IOC_DIR(cmd) & _IOC_READ) err = verify_area( VERIFY_WRITE, (void *) arg, size); - else if ( _IOC_DIR(cmd) & _IOC_WRITE) + else if (_IOC_DIR(cmd) & _IOC_WRITE) err = verify_area( VERIFY_READ, (void *) arg, size); - if ( err) + if (err) return err; switch(cmd) { case TCGETS: case TCGETA: - return n_tty_ioctl( tty, (struct file *) file, cmd, - (unsigned long) arg); + return n_tty_ioctl(tty, (struct file *) file, cmd, + (unsigned long) arg); break; case IRTTY_IOCTDONGLE: /* Initialize dongle */ - irtty_init_dongle( self, (int) arg); + irtty_init_dongle(self, (int) arg); break; default: return -ENOIOCTLCMD; @@ -450,8 +473,8 @@ static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp, { struct irtty_cb *self = (struct irtty_cb *) tty->disc_data; - ASSERT( self != NULL, return;); - ASSERT( self->magic == IRTTY_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == IRTTY_MAGIC, return;); /* Read the characters out of the buffer */ while (count--) { @@ -461,19 +484,19 @@ static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp, if (fp && *fp++) { DEBUG( 0, "Framing or parity error!\n"); irda_device_set_media_busy( &self->idev, TRUE); - /* sl->rx_errors++; */ + cp++; continue; } /* Unwrap and destuff one byte */ - async_unwrap_char( &self->idev, *cp++); + async_unwrap_char(&self->idev, *cp++); } } /* * Function irtty_hard_xmit (skb, dev) * - * Transmit skb + * Transmit frame * */ static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev) @@ -482,9 +505,6 @@ static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev) struct irda_device *idev; int actual = 0; - ASSERT( dev != NULL, return 0;); - ASSERT( skb != NULL, return 0;); - idev = (struct irda_device *) dev->priv; ASSERT(idev != NULL, return 0;); @@ -498,10 +518,11 @@ static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev) /* Lock transmit buffer */ if (irda_lock((void *) &dev->tbusy) == FALSE) return -EBUSY; - - /* - * Transfer skb to tx_buff while wrapping, stuffing and making CRC - */ + + /* Init tx buffer*/ + idev->tx_buff.data = idev->tx_buff.head; + + /* Copy skb to tx_buff while wrapping, stuffing and making CRC */ idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data, idev->tx_buff.truesize); @@ -509,13 +530,14 @@ static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev) dev->trans_start = jiffies; - if ( self->tty->driver.write) + if (self->tty->driver.write) actual = self->tty->driver.write(self->tty, 0, idev->tx_buff.data, idev->tx_buff.len); - idev->tx_buff.offset = actual; - idev->tx_buff.head = idev->tx_buff.data + actual; + /* Hide the part we just transmitted */ + idev->tx_buff.data += actual; + idev->tx_buff.len -= actual; idev->stats.tx_packets++; idev->stats.tx_bytes += idev->tx_buff.len; @@ -524,7 +546,7 @@ static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev) * Did we transmit the whole frame? Commented out for now since * I must check if this optimalization really works. DB. */ - if (( idev->tx.count - idev->tx.ptr) <= 0) { + if ((idev->tx_buff.len) == 0) { DEBUG( 4, "irtty_xmit_buf: finished with frame!\n"); self->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); irda_unlock( &self->tbusy); @@ -541,8 +563,9 @@ static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev) * Used by the TTY to find out how much data we can receive at a time * */ -static int irtty_receive_room( struct tty_struct *tty) +static int irtty_receive_room(struct tty_struct *tty) { + DEBUG(0, __FUNCTION__ "()\n"); return 65536; /* We can handle an infinite amount of data. :-) */ } @@ -553,47 +576,42 @@ static int irtty_receive_room( struct tty_struct *tty) * more packets to send, we send them here. * */ -static void irtty_write_wakeup( struct tty_struct *tty) +static void irtty_write_wakeup(struct tty_struct *tty) { - int actual = 0, count; struct irtty_cb *self = (struct irtty_cb *) tty->disc_data; struct irda_device *idev; + int actual = 0; /* * First make sure we're connected. */ - ASSERT( self != NULL, return;); - ASSERT( self->magic == IRTTY_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == IRTTY_MAGIC, return;); idev = &self->idev; - /* - * Finished with frame? - */ - if ( idev->tx_buff.offset == idev->tx_buff.len) { + /* Finished with frame? */ + if (idev->tx_buff.len > 0) { + /* Write data left in transmit buffer */ + actual = tty->driver.write(tty, 0, idev->tx_buff.data, + idev->tx_buff.len); + idev->tx_buff.data += actual; + idev->tx_buff.len -= actual; + } else { /* * Now serial buffer is almost free & we can start * transmission of another packet */ DEBUG(5, __FUNCTION__ "(), finished with frame!\n"); - + tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); idev->netdev.tbusy = 0; /* Unlock */ - + /* Tell network layer that we want more frames */ - mark_bh( NET_BH); - - return; + mark_bh(NET_BH); } - /* - * Write data left in transmit buffer - */ - count = idev->tx_buff.len - idev->tx_buff.offset; - actual = tty->driver.write( tty, 0, idev->tx_buff.head, count); - idev->tx_buff.offset += actual; - idev->tx_buff.head += actual; } /* @@ -602,9 +620,9 @@ static void irtty_write_wakeup( struct tty_struct *tty) * Return TRUE is we are currently receiving a frame * */ -static int irtty_is_receiving( struct irda_device *idev) +static int irtty_is_receiving(struct irda_device *idev) { - return ( idev->rx_buff.state != OUTSIDE_FRAME); + return (idev->rx_buff.state != OUTSIDE_FRAME); } /* @@ -614,20 +632,20 @@ static int irtty_is_receiving( struct irda_device *idev) * to change the speed of the serial port. Warning this function must * be called with a process context! */ -static void irtty_wait_until_sent( struct irda_device *idev) +static void irtty_wait_until_sent(struct irda_device *idev) { struct irtty_cb *self = (struct irtty_cb *) idev->priv; - ASSERT( self != NULL, return;); - ASSERT( self->magic == IRTTY_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == IRTTY_MAGIC, return;); - DEBUG( 4, "Chars in buffer %d\n", - self->tty->driver.chars_in_buffer( self->tty)); + DEBUG(4, "Chars in buffer %d\n", + self->tty->driver.chars_in_buffer(self->tty)); - tty_wait_until_sent( self->tty, 0); + tty_wait_until_sent(self->tty, 0); } -int irtty_register_dongle( struct dongle *dongle) +int irtty_register_dongle(struct dongle *dongle) { struct dongle_q *new; @@ -638,12 +656,11 @@ int irtty_register_dongle( struct dongle *dongle) } /* Make new IrDA dongle */ - new = (struct dongle_q *)kmalloc(sizeof(struct dongle_q), GFP_KERNEL); - if (new == NULL) { - return 1; + new = (struct dongle_q *) kmalloc(sizeof(struct dongle_q), GFP_KERNEL); + if (new == NULL) + return -1; - } - memset( new, 0, sizeof( struct dongle_q)); + memset(new, 0, sizeof( struct dongle_q)); new->dongle = dongle; /* Insert IrDA dongle into hashbin */ @@ -652,16 +669,16 @@ int irtty_register_dongle( struct dongle *dongle) return 0; } -void irtty_unregister_dongle( struct dongle *dongle) +void irtty_unregister_dongle(struct dongle *dongle) { struct dongle_q *node; - node = hashbin_remove( dongles, dongle->type, NULL); - if ( !node) { - DEBUG( 0, __FUNCTION__ "(), dongle not found!\n"); + node = hashbin_remove(dongles, dongle->type, NULL); + if (!node) { + ERROR(__FUNCTION__ "(), dongle not found!\n"); return; } - kfree( node); + kfree(node); } @@ -696,26 +713,24 @@ void irtty_set_dtr_rts(struct tty_struct *tty, int dtr, int rts) set_fs(get_ds()); if (tty->driver.ioctl(tty, NULL, TIOCMSET, (unsigned long) &arg)) { - DEBUG(0, __FUNCTION__ "(), error!\n"); + ERROR(__FUNCTION__ "(), error doing ioctl!\n"); } set_fs(fs); } - -static int irtty_net_init( struct device *dev) +static int irtty_net_init(struct device *dev) { /* Set up to be a normal IrDA network device driver */ - irda_device_setup( dev); + irda_device_setup(dev); /* Insert overrides below this line! */ return 0; } - -static int irtty_net_open( struct device *dev) +static int irtty_net_open(struct device *dev) { - ASSERT( dev != NULL, return -1;); + ASSERT(dev != NULL, return -1;); /* Ready to play! */ dev->tbusy = 0; @@ -729,7 +744,7 @@ static int irtty_net_open( struct device *dev) static int irtty_net_close(struct device *dev) { - ASSERT( dev != NULL, return -1;); + ASSERT(dev != NULL, return -1;); /* Stop device */ dev->tbusy = 1; diff --git a/drivers/net/irda/pc87108.c b/drivers/net/irda/pc87108.c index 385a1eb5f2a2..878b2e33a846 100644 --- a/drivers/net/irda/pc87108.c +++ b/drivers/net/irda/pc87108.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sat Nov 7 21:43:15 1998 - * Modified at: Sat Apr 3 15:54:47 1999 + * Modified at: Tue Apr 20 11:11:39 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli @@ -734,10 +734,9 @@ static int pc87108_hard_xmit( struct sk_buff *skb, struct device *dev) /* Decide if we should use PIO or DMA transfer */ if ( idev->io.baudrate > 115200) { - memcpy( idev->tx_buff.data, skb->data, skb->len); + idev->tx_buff.data = idev->tx_buff.head; + memcpy(idev->tx_buff.data, skb->data, skb->len); idev->tx_buff.len = skb->len; - idev->tx_buff.head = idev->tx_buff.data; - idev->tx_buff.offset = 0; mtt = irda_get_mtt( skb); if ( mtt > 50) { @@ -767,11 +766,10 @@ static int pc87108_hard_xmit( struct sk_buff *skb, struct device *dev) pc87108_dma_write( idev, iobase); } } else { - idev->tx_buff.len = async_wrap_skb( skb, idev->tx_buff.data, - idev->tx_buff.truesize); + idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data, + idev->tx_buff.truesize); - idev->tx_buff.offset = 0; - idev->tx_buff.head = idev->tx_buff.data; + idev->tx_buff.data = idev->tx_buff.head; /* Add interrupt on tx low level (will fire immediately) */ switch_bank( iobase, BANK0); @@ -945,8 +943,7 @@ static int pc87108_dma_receive(struct irda_device *idev) /* driver->media_busy = FALSE; */ idev->io.direction = IO_RECV; - idev->rx_buff.head = idev->rx_buff.data; - idev->rx_buff.offset = 0; + idev->rx_buff.data = idev->rx_buff.head; /* Reset Rx FIFO. This will also flush the ST_FIFO */ outb(FCR_RXTH|FCR_TXTH|FCR_RXSR|FCR_FIFO_EN, iobase+FCR); @@ -1024,42 +1021,41 @@ static int pc87108_dma_receive_complete( struct irda_device *idev, int iobase) /* Skip frame */ idev->stats.rx_errors++; - idev->rx_buff.offset += len; - idev->rx_buff.head += len; + idev->rx_buff.data += len; - if ( status & FRM_ST_MAX_LEN) + if (status & FRM_ST_MAX_LEN) idev->stats.rx_length_errors++; - if ( status & FRM_ST_PHY_ERR) + if (status & FRM_ST_PHY_ERR) idev->stats.rx_frame_errors++; - if ( status & FRM_ST_BAD_CRC) + if (status & FRM_ST_BAD_CRC) idev->stats.rx_crc_errors++; } /* The errors below can be reported in both cases */ - if ( status & FRM_ST_OVR1) + if (status & FRM_ST_OVR1) idev->stats.rx_fifo_errors++; - if ( status & FRM_ST_OVR2) + if (status & FRM_ST_OVR2) idev->stats.rx_fifo_errors++; } else { /* Check if we have transfered all data to memory */ - if ( inb( iobase+LSR) & LSR_RXDA) { + if (inb(iobase+LSR) & LSR_RXDA) { /* Put this entry back in fifo */ st_fifo->head--; st_fifo->len++; st_fifo->entries[st_fifo->head].status = status; - st_fifo->entries[ st_fifo->head].len = len; + st_fifo->entries[st_fifo->head].len = len; /* Restore bank register */ - outb( bank, iobase+BSR); + outb(bank, iobase+BSR); return FALSE; /* I'll be back! */ } /* Should be OK then */ - skb = dev_alloc_skb( len+1); + skb = dev_alloc_skb(len+1); if (skb == NULL) { printk( KERN_INFO __FUNCTION__ "(), memory squeeze, dropping frame.\n"); @@ -1070,20 +1066,19 @@ static int pc87108_dma_receive_complete( struct irda_device *idev, int iobase) } /* Make sure IP header gets aligned */ - skb_reserve( skb, 1); + skb_reserve(skb, 1); /* Copy frame without CRC */ - if ( idev->io.baudrate < 4000000) { - skb_put( skb, len-2); - memcpy( skb->data, idev->rx_buff.head, len-2); + if (idev->io.baudrate < 4000000) { + skb_put(skb, len-2); + memcpy(skb->data, idev->rx_buff.data, len-2); } else { - skb_put( skb, len-4); - memcpy( skb->data, idev->rx_buff.head, len-4); + skb_put(skb, len-4); + memcpy(skb->data, idev->rx_buff.data, len-4); } /* Move to next frame */ - idev->rx_buff.offset += len; - idev->rx_buff.head += len; + idev->rx_buff.data += len; idev->stats.rx_packets++; skb->dev = &idev->netdev; @@ -1093,7 +1088,7 @@ static int pc87108_dma_receive_complete( struct irda_device *idev, int iobase) } } /* Restore bank register */ - outb( bank, iobase+BSR); + outb(bank, iobase+BSR); return TRUE; } @@ -1109,23 +1104,19 @@ static void pc87108_pio_receive( struct irda_device *idev) __u8 byte = 0x00; int iobase; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - ASSERT( idev != NULL, return;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); iobase = idev->io.iobase; - if ( idev->rx_buff.len == 0) { - idev->rx_buff.head = idev->rx_buff.data; - } - /* Receive all characters in Rx FIFO */ do { - byte = inb( iobase+RXD); - async_unwrap_char( idev, byte); + byte = inb(iobase+RXD); + async_unwrap_char(idev, byte); - } while ( inb( iobase+LSR) & LSR_RXDA); /* Data available */ + } while (inb(iobase+LSR) & LSR_RXDA); /* Data available */ } /* @@ -1134,38 +1125,35 @@ static void pc87108_pio_receive( struct irda_device *idev) * Handle SIR interrupt * */ -static __u8 pc87108_sir_interrupt( struct irda_device *idev, int eir) +static __u8 pc87108_sir_interrupt(struct irda_device *idev, int eir) { - int len; int actual; __u8 new_ier = 0; /* Transmit FIFO low on data */ if ( eir & EIR_TXLDL_EV) { /* Write data left in transmit buffer */ - len = idev->tx_buff.len - idev->tx_buff.offset; - - ASSERT( len > 0, return 0;); - actual = pc87108_pio_write( idev->io.iobase, - idev->tx_buff.head, - len, idev->io.fifo_size); - idev->tx_buff.offset += actual; - idev->tx_buff.head += actual; + actual = pc87108_pio_write(idev->io.iobase, + idev->tx_buff.data, + idev->tx_buff.len, + idev->io.fifo_size); + idev->tx_buff.data += actual; + idev->tx_buff.len -= actual; idev->io.direction = IO_XMIT; - ASSERT( actual <= len, return 0;); /* Check if finished */ - if ( actual == len) { - DEBUG( 4, __FUNCTION__ "(), finished with frame!\n"); + if (idev->tx_buff.len > 0) + new_ier |= IER_TXLDL_IE; + else { idev->netdev.tbusy = 0; /* Unlock */ idev->stats.tx_packets++; - + mark_bh(NET_BH); new_ier |= IER_TXEMP_IE; - } else - new_ier |= IER_TXLDL_IE; + } + } /* Check if transmission has completed */ if ( eir & EIR_TXEMP_EV) { diff --git a/drivers/net/irda/tekram.c b/drivers/net/irda/tekram.c index eb8e2a0c41ce..de1a553a4aaf 100644 --- a/drivers/net/irda/tekram.c +++ b/drivers/net/irda/tekram.c @@ -1,12 +1,12 @@ /********************************************************************* * * Filename: tekram.c - * Version: 0.5 + * Version: 1.0 * Description: Implementation of the Tekram IrMate IR-210B dongle * Status: Experimental. * Author: Dag Brattli * Created at: Wed Oct 21 20:02:35 1998 - * Modified at: Mon Feb 15 14:13:17 1999 + * Modified at: Tue Apr 13 16:33:54 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli, All Rights Reserved. @@ -33,16 +33,23 @@ #include #include -#include #include #include #include -static void tekram_reset( struct irda_device *dev, int unused); -static void tekram_open( struct irda_device *dev, int type); -static void tekram_close( struct irda_device *dev); -static void tekram_change_speed( struct irda_device *dev, int baud); -static void tekram_init_qos( struct irda_device *idev, struct qos_info *qos); +static void tekram_reset(struct irda_device *dev, int unused); +static void tekram_open(struct irda_device *dev, int type); +static void tekram_close(struct irda_device *dev); +static void tekram_change_speed(struct irda_device *dev, int baud); +static void tekram_init_qos(struct irda_device *idev, struct qos_info *qos); + +#define TEKRAM_115200 0x00 +#define TEKRAM_57600 0x01 +#define TEKRAM_38400 0x02 +#define TEKRAM_19200 0x03 +#define TEKRAM_9600 0x04 + +#define TEKRAM_PW 0x10 /* Pulse select bit */ static struct dongle dongle = { TEKRAM_DONGLE, @@ -53,9 +60,9 @@ static struct dongle dongle = { tekram_init_qos, }; -__initfunc(void tekram_init(void)) +__initfunc(int tekram_init(void)) { - irtty_register_dongle( &dongle); + return irtty_register_dongle(&dongle); } void tekram_cleanup(void) @@ -102,17 +109,17 @@ static void tekram_change_speed( struct irda_device *dev, int baud) int cflag; __u8 byte; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - ASSERT( dev != NULL, return;); - ASSERT( dev->magic == IRDA_DEVICE_MAGIC, return;); + ASSERT(dev != NULL, return;); + ASSERT(dev->magic == IRDA_DEVICE_MAGIC, return;); self = (struct irtty_cb *) dev->priv; - ASSERT( self != NULL, return;); - ASSERT( self->magic == IRTTY_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == IRTTY_MAGIC, return;); - if ( !self->tty) + if (!self->tty) return; tty = self->tty; @@ -123,26 +130,27 @@ static void tekram_change_speed( struct irda_device *dev, int baud) cflag &= ~CBAUD; switch (baud) { - case 9600: default: + /* FALLTHROUGH */ + case 9600: cflag |= B9600; - byte = 4; + byte = TEKRAM_PW|TEKRAM_9600; break; case 19200: cflag |= B19200; - byte = 3; + byte = TEKRAM_PW|TEKRAM_19200; break; case 34800: cflag |= B38400; - byte = 2; + byte = TEKRAM_PW|TEKRAM_38400; break; case 57600: cflag |= B57600; - byte = 1; + byte = TEKRAM_PW|TEKRAM_57600; break; case 115200: cflag |= B115200; - byte = 0; + byte = TEKRAM_PW|TEKRAM_115200; break; } @@ -150,22 +158,22 @@ static void tekram_change_speed( struct irda_device *dev, int baud) irtty_set_dtr_rts(tty, TRUE, FALSE); /* Wait at least 7us */ - udelay( 7); + udelay(7); /* Write control byte */ - if ( tty->driver.write) - tty->driver.write( self->tty, 0, &byte, 1); + if (tty->driver.write) + tty->driver.write(self->tty, 0, &byte, 1); /* Wait at least 100 ms */ current->state = TASK_INTERRUPTIBLE; - schedule_timeout( 10); + schedule_timeout(MSECS_TO_JIFFIES(100)); /* Set DTR, Set RTS */ irtty_set_dtr_rts(tty, TRUE, TRUE); /* Now change the speed of the serial port */ tty->termios->c_cflag = cflag; - tty->driver.set_termios( tty, &old_termios); + tty->driver.set_termios(tty, &old_termios); } /* @@ -175,30 +183,29 @@ static void tekram_change_speed( struct irda_device *dev, int baud) * must be called with a process context!! * * Algorithm: - * 0. set RTS and DTR, and wait 50 ms - * ( power off the IR-210 ) + * 0. Clear RTS and DTR, and wait 50 ms (power off the IR-210 ) * 1. clear RTS * 2. set DTR, and wait at least 1 ms * 3. clear DTR to SPACE state, wait at least 50 us for further * operation */ -void tekram_reset( struct irda_device *dev, int unused) +void tekram_reset(struct irda_device *dev, int unused) { struct irtty_cb *self; struct tty_struct *tty; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - ASSERT( dev != NULL, return;); - ASSERT( dev->magic == IRDA_DEVICE_MAGIC, return;); + ASSERT(dev != NULL, return;); + ASSERT(dev->magic == IRDA_DEVICE_MAGIC, return;); self = (struct irtty_cb *) dev->priv; - ASSERT( self != NULL, return;); - ASSERT( self->magic == IRTTY_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == IRTTY_MAGIC, return;); tty = self->tty; - if ( !tty) + if (!tty) return; /* Power off dongle */ @@ -206,18 +213,20 @@ void tekram_reset( struct irda_device *dev, int unused) /* Sleep 50 ms */ current->state = TASK_INTERRUPTIBLE; - schedule_timeout(5); + schedule_timeout(MSECS_TO_JIFFIES(50)); /* Clear DTR, Set RTS */ irtty_set_dtr_rts(tty, FALSE, TRUE); /* Should sleep 1 ms, but 10-20 should not do any harm */ current->state = TASK_INTERRUPTIBLE; - schedule_timeout(2); + schedule_timeout(MSECS_TO_JIFFIES(20)); /* Set DTR, Set RTS */ irtty_set_dtr_rts(tty, TRUE, TRUE); + udelay(50); + /* Finished! */ } @@ -227,10 +236,11 @@ void tekram_reset( struct irda_device *dev, int unused) * Initialize QoS capabilities * */ -static void tekram_init_qos( struct irda_device *idev, struct qos_info *qos) +static void tekram_init_qos(struct irda_device *idev, struct qos_info *qos) { qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; - qos->min_turn_time.bits &= 0xfe; /* All except 0 ms */ + qos->min_turn_time.bits &= 0x01; /* Needs at least 10 ms */ + irda_qos_bits_to_value(qos); } #ifdef MODULE @@ -246,8 +256,7 @@ MODULE_DESCRIPTION("Tekram IrMate IR-210B dongle driver"); */ int init_module(void) { - tekram_init(); - return(0); + return tekram_init(); } /* diff --git a/drivers/net/irda/uircc.c b/drivers/net/irda/uircc.c index c4915c7556b7..60c8e024a0d1 100644 --- a/drivers/net/irda/uircc.c +++ b/drivers/net/irda/uircc.c @@ -7,7 +7,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sat Dec 26 10:59:03 1998 - * Modified at: Sat Apr 3 15:54:41 1999 + * Modified at: Tue Apr 20 11:15:52 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli, All Rights Reserved. @@ -190,7 +190,7 @@ static int uircc_open(int i, unsigned int iobase, unsigned int iobase2, /* The only value we must override it the baudrate */ idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600| - IR_115200|/*IR_576000|IR_1152000| */(IR_4000000 << 8); + IR_115200/*IR_576000|IR_1152000 |(IR_4000000 << 8)*/; idev->qos.min_turn_time.bits = 0x0f; irda_qos_bits_to_value(&idev->qos); @@ -372,7 +372,7 @@ static void uircc_change_speed(struct irda_device *idev, int speed) DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n"); /* Set self pole address */ - outb(0x10, iobase+UIRCC_CR8); + //outb(0xfe, iobase+UIRCC_CR8); /* outb(0x10, iobase+UIRCC_CR11); */ break; @@ -443,8 +443,7 @@ static int uircc_hard_xmit(struct sk_buff *skb, struct device *dev) skb->len++; idev->tx_buff.len = skb->len; - idev->tx_buff.head = idev->tx_buff.data; - idev->tx_buff.offset = 0; + idev->tx_buff.data = idev->tx_buff.head; mtt = irda_get_mtt(skb); @@ -586,11 +585,15 @@ static int uircc_dma_receive(struct irda_device *idev) outb(self->cr3, iobase+UIRCC_CR3); /* Transmit reset (just in case) */ - outb(UIRCC_CR0_XMIT_RST, iobase+UIRCC_CR0); + outb(UIRCC_CR0_XMIT_RST|0x17, iobase+UIRCC_CR0); /* Set modem */ outb(0x08, iobase+UIRCC_CR10); + /* Enable receiving with CRC */ + self->cr3 = (UIRCC_CR3_RECV_EN|UIRCC_CR3_RX_CRC_EN); + outb(self->cr3, iobase+UIRCC_CR3); + /* Make sure Rx DMA is set */ outb(UIRCC_CR1_RX_DMA|UIRCC_CR1_MUST_SET, iobase+UIRCC_CR1); @@ -602,13 +605,13 @@ static int uircc_dma_receive(struct irda_device *idev) /* driver->media_busy = FALSE; */ idev->io.direction = IO_RECV; - idev->rx_buff.head = idev->rx_buff.data; - idev->rx_buff.offset = 0; + idev->rx_buff.data = idev->rx_buff.head; +#if 0 /* Enable receiving with CRC */ self->cr3 = (UIRCC_CR3_RECV_EN|UIRCC_CR3_RX_CRC_EN); outb(self->cr3, iobase+UIRCC_CR3); - +#endif DEBUG(4, __FUNCTION__ "(), cr3=%#x\n", self->cr3); /* Address check? */ @@ -673,7 +676,7 @@ static int uircc_dma_receive_complete(struct irda_device *idev, int iobase) /* } */ skb_put(skb, len); - memcpy(skb->data, idev->rx_buff.head, len); + memcpy(skb->data, idev->rx_buff.data, len); idev->stats.rx_packets++; skb->dev = &idev->netdev; @@ -737,7 +740,7 @@ static void uircc_interrupt(int irq, void *dev_id, struct pt_regs *regs) uircc_dma_xmit_complete(idev, FALSE); uircc_dma_receive(idev); - /* outb(0, iobase+UIRCC_CR2); */ + outb(0x0d, iobase+UIRCC_CR2); break; case UIRCC_SR3_TMR_OUT: /* Disable timer */ diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index 5d92f5a19820..9234c4a82022 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Paul VanderSpek * Created at: Wed Nov 4 11:46:16 1998 - * Modified at: Wed Apr 7 17:35:59 1999 + * Modified at: Tue Apr 20 11:15:00 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Corel Computer Corp. @@ -482,8 +482,7 @@ int w83977af_hard_xmit( struct sk_buff *skb, struct device *dev) if (idev->io.baudrate > 115200) { memcpy(idev->tx_buff.data, skb->data, skb->len); idev->tx_buff.len = skb->len; - idev->tx_buff.head = idev->tx_buff.data; - idev->tx_buff.offset = 0; + idev->tx_buff.data = idev->tx_buff.head; mtt = irda_get_mtt(skb); if (mtt > 50) { @@ -512,20 +511,18 @@ int w83977af_hard_xmit( struct sk_buff *skb, struct device *dev) w83977af_dma_write(idev, iobase); } } else { + idev->tx_buff.data = idev->tx_buff.head; idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data, idev->tx_buff.truesize); - idev->tx_buff.offset = 0; - idev->tx_buff.head = idev->tx_buff.data; - /* Add interrupt on tx low level (will fire immediately) */ - switch_bank( iobase, SET0); + switch_bank(iobase, SET0); outb(ICR_ETXTHI, iobase+ICR); } dev_kfree_skb(skb); /* Restore set register */ - outb( set, iobase+SSR); + outb(set, iobase+SSR); return 0; } @@ -594,9 +591,9 @@ static int w83977af_pio_write(int iobase, __u8 *buf, int len, int fifo_size) } /* Fill FIFO with current frame */ - while (( fifo_size-- > 0) && (actual < len)) { + while ((fifo_size-- > 0) && (actual < len)) { /* Transmit next byte */ - outb( buf[actual++], iobase+TBR); + outb(buf[actual++], iobase+TBR); } DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", @@ -702,8 +699,7 @@ int w83977af_dma_receive(struct irda_device *idev) #endif /* driver->media_busy = FALSE; */ idev->io.direction = IO_RECV; - idev->rx_buff.head = idev->rx_buff.data; - idev->rx_buff.offset = 0; + idev->rx_buff.data = idev->rx_buff.head; /* * Reset Rx FIFO. This will also flush the ST_FIFO, it's very @@ -751,30 +747,30 @@ int w83977af_dma_receive_complete(struct irda_device *idev) __u8 set; __u8 status; - DEBUG( 0, __FUNCTION__ "\n"); + DEBUG(0, __FUNCTION__ "\n"); iobase = idev->io.iobase; /* Save current set */ - set = inb( iobase+SSR); + set = inb(iobase+SSR); iobase = idev->io.iobase; switch_bank(iobase, SET5); - if ( prev.status & FS_FO_FSFDR) { + if (prev.status & FS_FO_FSFDR) { status = prev.status; len = prev.len; - + prev.status = 0; } else { - status = inb( iobase+FS_FO); - len = inb( iobase+RFLFL); - len |= inb( iobase+RFLFH) << 8; + status = inb(iobase+FS_FO); + len = inb(iobase+RFLFL); + len |= inb(iobase+RFLFH) << 8; } - while ( status & FS_FO_FSFDR) { + while (status & FS_FO_FSFDR) { /* Check for errors */ - if ( status & FS_FO_ERR_MSK) { + if (status & FS_FO_ERR_MSK) { if ( status & FS_FO_LST_FR) { /* Add number of lost frames to stats */ idev->stats.rx_errors += len; @@ -782,29 +778,28 @@ int w83977af_dma_receive_complete(struct irda_device *idev) /* Skip frame */ idev->stats.rx_errors++; - idev->rx_buff.offset += len; - idev->rx_buff.head += len; + idev->rx_buff.data += len; - if ( status & FS_FO_MX_LEX) + if (status & FS_FO_MX_LEX) idev->stats.rx_length_errors++; - if ( status & FS_FO_PHY_ERR) + if (status & FS_FO_PHY_ERR) idev->stats.rx_frame_errors++; - if ( status & FS_FO_CRC_ERR) + if (status & FS_FO_CRC_ERR) idev->stats.rx_crc_errors++; } /* The errors below can be reported in both cases */ - if ( status & FS_FO_RX_OV) + if (status & FS_FO_RX_OV) idev->stats.rx_fifo_errors++; - if ( status & FS_FO_FSF_OV) + if (status & FS_FO_FSF_OV) idev->stats.rx_fifo_errors++; } else { /* Check if we have transfered all data to memory */ switch_bank(iobase, SET0); - if ( inb( iobase+USR) & USR_RDR) { + if (inb(iobase+USR) & USR_RDR) { /* Put this entry back in fifo */ prev.status = status; prev.len = len; @@ -815,31 +810,30 @@ int w83977af_dma_receive_complete(struct irda_device *idev) return FALSE; /* I'll be back! */ } - skb = dev_alloc_skb( len+1); + skb = dev_alloc_skb(len+1); if (skb == NULL) { - printk( KERN_INFO __FUNCTION__ - "(), memory squeeze, dropping frame.\n"); + printk(KERN_INFO __FUNCTION__ + "(), memory squeeze, dropping frame.\n"); /* Restore set register */ - outb( set, iobase+SSR); + outb(set, iobase+SSR); return FALSE; } /* Align to 20 bytes */ - skb_reserve( skb, 1); + skb_reserve(skb, 1); /* Copy frame without CRC */ if ( idev->io.baudrate < 4000000) { skb_put( skb, len-2); - memcpy( skb->data, idev->rx_buff.head, len-2); + memcpy( skb->data, idev->rx_buff.data, len-2); } else { skb_put( skb, len-4); - memcpy( skb->data, idev->rx_buff.head, len-4); + memcpy( skb->data, idev->rx_buff.data, len-4); } /* Move to next frame */ - idev->rx_buff.offset += len; - idev->rx_buff.head += len; + idev->rx_buff.data += len; skb->dev = &idev->netdev; skb->mac.raw = skb->data; @@ -854,7 +848,7 @@ int w83977af_dma_receive_complete(struct irda_device *idev) len |= inb( iobase+RFLFH) << 8; } /* Restore set register */ - outb( set, iobase+SSR); + outb(set, iobase+SSR); return TRUE; } @@ -865,28 +859,24 @@ int w83977af_dma_receive_complete(struct irda_device *idev) * Receive all data in receiver FIFO * */ -static void w83977af_pio_receive( struct irda_device *idev) +static void w83977af_pio_receive(struct irda_device *idev) { __u8 byte = 0x00; int iobase; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - ASSERT( idev != NULL, return;); - ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;); + ASSERT(idev != NULL, return;); + ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;); iobase = idev->io.iobase; - if ( idev->rx_buff.len == 0) { - idev->rx_buff.head = idev->rx_buff.data; - } - /* Receive all characters in Rx FIFO */ do { - byte = inb( iobase+RBR); - async_unwrap_char( idev, byte); + byte = inb(iobase+RBR); + async_unwrap_char(idev, byte); - } while ( inb( iobase+USR) & USR_RDR); /* Data available */ + } while (inb(iobase+USR) & USR_RDR); /* Data available */ } /* @@ -897,7 +887,6 @@ static void w83977af_pio_receive( struct irda_device *idev) */ static __u8 w83977af_sir_interrupt(struct irda_device *idev, int isr) { - int len; int actual; __u8 new_icr = 0; @@ -906,19 +895,19 @@ static __u8 w83977af_sir_interrupt(struct irda_device *idev, int isr) /* Transmit FIFO low on data */ if (isr & ISR_TXTH_I) { /* Write data left in transmit buffer */ - len = idev->tx_buff.len - idev->tx_buff.offset; - - ASSERT(len > 0, return 0;); actual = w83977af_pio_write(idev->io.iobase, - idev->tx_buff.head, - len, idev->io.fifo_size); - idev->tx_buff.offset += actual; - idev->tx_buff.head += actual; + idev->tx_buff.data, + idev->tx_buff.len, + idev->io.fifo_size); + idev->tx_buff.data += actual; + idev->tx_buff.len -= actual; idev->io.direction = IO_XMIT; - ASSERT( actual <= len, return 0;); + /* Check if finished */ - if ( actual == len) { + if (idev->tx_buff.len > 0) + new_icr |= ICR_ETXTHI; + else { DEBUG( 4, __FUNCTION__ "(), finished with frame!\n"); idev->netdev.tbusy = 0; /* Unlock */ idev->stats.tx_packets++; @@ -927,8 +916,8 @@ static __u8 w83977af_sir_interrupt(struct irda_device *idev, int isr) mark_bh(NET_BH); new_icr |= ICR_ETBREI; - } else - new_icr |= ICR_ETXTHI; + } + } /* Check if transmission has completed */ if (isr & ISR_TXEMP_I) { diff --git a/drivers/net/net_init.c b/drivers/net/net_init.c index edb41febb4d4..4391bb68fe3a 100644 --- a/drivers/net/net_init.c +++ b/drivers/net/net_init.c @@ -252,6 +252,22 @@ hipfound: /* From the double loop above. */ return dev; } + +void unregister_hipdev(struct device *dev) +{ + int i; + rtnl_lock(); + unregister_netdevice(dev); + for (i = 0; i < MAX_HIP_CARDS; ++i) { + if (hipdev_index[i] == dev) { + hipdev_index[i] = NULL; + break; + } + } + rtnl_unlock(); +} + + static int hippi_neigh_setup_dev(struct device *dev, struct neigh_parms *p) { /* Never send broadcast/multicast ARP messages */ diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index d56f772061cb..f2ce89efa73e 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -13,7 +13,7 @@ * This driver is for PCnet32 and PCnetPCI based ethercards */ -static const char *version = "pcnet32.c:v1.11 17.1.99 tsbogend@alpha.franken.de\n"; +static const char *version = "pcnet32.c:v1.21 31.3.99 tsbogend@alpha.franken.de\n"; #include #include @@ -58,9 +58,36 @@ static const int rx_copybreak = 200; #define PORT_PORTSEL 0x03 #define PORT_ASEL 0x04 +#define PORT_100 0x40 #define PORT_FD 0x80 -static int options = PORT_ASEL; /* port selection */ + +/* + * table to translate option values from tulip + * to internal options + */ +static unsigned char options_mapping[] = { + PORT_ASEL, /* 0 Auto-select */ + PORT_AUI, /* 1 BNC/AUI */ + PORT_AUI, /* 2 AUI/BNC */ + PORT_ASEL, /* 3 not supported */ + PORT_10BT | PORT_FD, /* 4 10baseT-FD */ + PORT_ASEL, /* 5 not supported */ + PORT_ASEL, /* 6 not supported */ + PORT_ASEL, /* 7 not supported */ + PORT_ASEL, /* 8 not supported */ + PORT_MII, /* 9 MII 10baseT */ + PORT_MII | PORT_FD, /* 10 MII 10baseT-FD */ + PORT_MII, /* 11 MII (autosel) */ + PORT_10BT, /* 12 10BaseT */ + PORT_MII | PORT_100, /* 13 MII 100BaseTx */ + PORT_MII | PORT_100 | PORT_FD, /* 14 MII 100BaseTx-FD */ + PORT_ASEL /* 15 not supported */ +}; + +#define MAX_UNITS 8 +static int options[MAX_UNITS] = {0, }; +static int full_duplex[MAX_UNITS] = {0, }; /* * Theory of Operation @@ -116,6 +143,12 @@ static int options = PORT_ASEL; /* port selection */ * added port selection for modules * detect special T1/E1 WAN card and setup port selection * v1.11: fixed wrong checking of Tx errors + * v1.20: added check of return value kmalloc (cpeterso@cs.washington.edu) + * added save original kmalloc addr for freeing (mcr@solidum.com) + * added support for PCnetHome chip (joe@MIT.EDU) + * rewritten PCI card detection + * added dwio mode to get driver working on some PPC machines + * v1.21: added mii selection and mii ioctl */ @@ -140,202 +173,402 @@ static int options = PORT_ASEL; /* port selection */ #define PKT_BUF_SZ 1544 /* Offsets from base I/O address. */ -#define PCNET32_DATA 0x10 -#define PCNET32_ADDR 0x12 -#define PCNET32_RESET 0x14 -#define PCNET32_BUS_IF 0x16 -#define PCNET32_TOTAL_SIZE 0x18 +#define PCNET32_WIO_RDP 0x10 +#define PCNET32_WIO_RAP 0x12 +#define PCNET32_WIO_RESET 0x14 +#define PCNET32_WIO_BDP 0x16 + +#define PCNET32_DWIO_RDP 0x10 +#define PCNET32_DWIO_RAP 0x14 +#define PCNET32_DWIO_RESET 0x18 +#define PCNET32_DWIO_BDP 0x1C + +#define PCNET32_TOTAL_SIZE 0x20 #define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */ /* The PCNET32 Rx and Tx ring descriptors. */ struct pcnet32_rx_head { - u32 base; - s16 buf_length; - s16 status; - u32 msg_length; - u32 reserved; + u32 base; + s16 buf_length; + s16 status; + u32 msg_length; + u32 reserved; }; struct pcnet32_tx_head { - u32 base; - s16 length; - s16 status; - u32 misc; - u32 reserved; + u32 base; + s16 length; + s16 status; + u32 misc; + u32 reserved; }; - /* The PCNET32 32-Bit initialization block, described in databook. */ struct pcnet32_init_block { - u16 mode; - u16 tlen_rlen; - u8 phys_addr[6]; - u16 reserved; - u32 filter[2]; - /* Receive and transmit ring base, along with extra bits. */ - u32 rx_ring; - u32 tx_ring; + u16 mode; + u16 tlen_rlen; + u8 phys_addr[6]; + u16 reserved; + u32 filter[2]; + /* Receive and transmit ring base, along with extra bits. */ + u32 rx_ring; + u32 tx_ring; +}; + +/* PCnet32 access functions */ +struct pcnet32_access { + u16 (*read_csr)(unsigned long, int); + void (*write_csr)(unsigned long, int, u16); + u16 (*read_bcr)(unsigned long, int); + void (*write_bcr)(unsigned long, int, u16); + u16 (*read_rap)(unsigned long); + void (*write_rap)(unsigned long, u16); + void (*reset)(unsigned long); }; struct pcnet32_private { - /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */ - struct pcnet32_rx_head rx_ring[RX_RING_SIZE]; - struct pcnet32_tx_head tx_ring[TX_RING_SIZE]; - struct pcnet32_init_block init_block; - const char *name; - /* The saved address of a sent-in-place packet/buffer, for skfree(). */ - struct sk_buff *tx_skbuff[TX_RING_SIZE]; - struct sk_buff *rx_skbuff[RX_RING_SIZE]; - int cur_rx, cur_tx; /* The next free ring entry */ - int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ - struct net_device_stats stats; - char tx_full; - int options; - int shared_irq:1, /* shared irq possible */ - full_duplex:1; /* full duplex possible */ + /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */ + struct pcnet32_rx_head rx_ring[RX_RING_SIZE]; + struct pcnet32_tx_head tx_ring[TX_RING_SIZE]; + struct pcnet32_init_block init_block; + const char *name; + /* The saved address of a sent-in-place packet/buffer, for skfree(). */ + struct sk_buff *tx_skbuff[TX_RING_SIZE]; + struct sk_buff *rx_skbuff[RX_RING_SIZE]; + struct pcnet32_access a; + void *origmem; + int cur_rx, cur_tx; /* The next free ring entry */ + int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */ + struct net_device_stats stats; + char tx_full; + int options; + int shared_irq:1, /* shared irq possible */ + full_duplex:1, /* full duplex possible */ + mii:1; /* mii port available */ #ifdef MODULE - struct device *next; + struct device *next; #endif }; -int pcnet32_probe(struct device *dev); -static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, unsigned char irq_line, int shared); -static int pcnet32_open(struct device *dev); -static int pcnet32_init_ring(struct device *dev); -static int pcnet32_start_xmit(struct sk_buff *skb, struct device *dev); -static int pcnet32_rx(struct device *dev); -static void pcnet32_interrupt(int irq, void *dev_id, struct pt_regs *regs); -static int pcnet32_close(struct device *dev); -static struct net_device_stats *pcnet32_get_stats(struct device *dev); -static void pcnet32_set_multicast_list(struct device *dev); +int pcnet32_probe(struct device *); +static int pcnet32_probe1(struct device *, unsigned long, unsigned char, int, int); +static int pcnet32_open(struct device *); +static int pcnet32_init_ring(struct device *); +static int pcnet32_start_xmit(struct sk_buff *, struct device *); +static int pcnet32_rx(struct device *); +static void pcnet32_interrupt(int, void *, struct pt_regs *); +static int pcnet32_close(struct device *); +static struct net_device_stats *pcnet32_get_stats(struct device *); +static void pcnet32_set_multicast_list(struct device *); +#ifdef HAVE_PRIVATE_IOCTL +static int pcnet32_mii_ioctl(struct device *, struct ifreq *, int); +#endif + +enum pci_flags_bit { + PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4, + PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3, +}; + +struct pcnet32_pci_id_info { + const char *name; + u16 vendor_id, device_id, device_id_mask, flags; + int io_size; + int (*probe1) (struct device *, unsigned long, unsigned char, int, int); +}; + +static struct pcnet32_pci_id_info pcnet32_tbl[] = { + { "AMD PCnetPCI series", + 0x1022, 0x2000, 0xfffe, PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE, + pcnet32_probe1}, + {0,} +}; + +static u16 pcnet32_wio_read_csr (unsigned long addr, int index) +{ + outw (index, addr+PCNET32_WIO_RAP); + return inw (addr+PCNET32_WIO_RDP); +} + +static void pcnet32_wio_write_csr (unsigned long addr, int index, u16 val) +{ + outw (index, addr+PCNET32_WIO_RAP); + outw (val, addr+PCNET32_WIO_RDP); +} + +static u16 pcnet32_wio_read_bcr (unsigned long addr, int index) +{ + outw (index, addr+PCNET32_WIO_RAP); + return inw (addr+PCNET32_WIO_BDP); +} + +static void pcnet32_wio_write_bcr (unsigned long addr, int index, u16 val) +{ + outw (index, addr+PCNET32_WIO_RAP); + outw (val, addr+PCNET32_WIO_BDP); +} + +static u16 pcnet32_wio_read_rap (unsigned long addr) +{ + return inw (addr+PCNET32_WIO_RAP); +} + +static void pcnet32_wio_write_rap (unsigned long addr, u16 val) +{ + outw (val, addr+PCNET32_WIO_RAP); +} + +static void pcnet32_wio_reset (unsigned long addr) +{ + inw (addr+PCNET32_WIO_RESET); +} + +static int pcnet32_wio_check (unsigned long addr) +{ + outw (88, addr+PCNET32_WIO_RAP); + return (inw (addr+PCNET32_WIO_RAP) == 88); +} + +static struct pcnet32_access pcnet32_wio = { + pcnet32_wio_read_csr, + pcnet32_wio_write_csr, + pcnet32_wio_read_bcr, + pcnet32_wio_write_bcr, + pcnet32_wio_read_rap, + pcnet32_wio_write_rap, + pcnet32_wio_reset +}; + +static u16 pcnet32_dwio_read_csr (unsigned long addr, int index) +{ + outl (index, addr+PCNET32_DWIO_RAP); + return (inl (addr+PCNET32_DWIO_RDP) & 0xffff); +} + +static void pcnet32_dwio_write_csr (unsigned long addr, int index, u16 val) +{ + outl (index, addr+PCNET32_DWIO_RAP); + outl (val, addr+PCNET32_DWIO_RDP); +} + +static u16 pcnet32_dwio_read_bcr (unsigned long addr, int index) +{ + outl (index, addr+PCNET32_DWIO_RAP); + return (inl (addr+PCNET32_DWIO_BDP) & 0xffff); +} + +static void pcnet32_dwio_write_bcr (unsigned long addr, int index, u16 val) +{ + outl (index, addr+PCNET32_DWIO_RAP); + outl (val, addr+PCNET32_DWIO_BDP); +} + +static u16 pcnet32_dwio_read_rap (unsigned long addr) +{ + return (inl (addr+PCNET32_DWIO_RAP) & 0xffff); +} + +static void pcnet32_dwio_write_rap (unsigned long addr, u16 val) +{ + outl (val, addr+PCNET32_DWIO_RAP); +} + +static void pcnet32_dwio_reset (unsigned long addr) +{ + inl (addr+PCNET32_DWIO_RESET); +} + +static int pcnet32_dwio_check (unsigned long addr) +{ + outl (88, addr+PCNET32_DWIO_RAP); + return (inl (addr+PCNET32_DWIO_RAP) == 88); +} + +static struct pcnet32_access pcnet32_dwio = { + pcnet32_dwio_read_csr, + pcnet32_dwio_write_csr, + pcnet32_dwio_read_bcr, + pcnet32_dwio_write_bcr, + pcnet32_dwio_read_rap, + pcnet32_dwio_write_rap, + pcnet32_dwio_reset + +}; -__initfunc(int pcnet32_probe (struct device *dev)) +int __init pcnet32_probe (struct device *dev) { - unsigned int ioaddr = dev ? dev->base_addr: 0; + unsigned long ioaddr = dev ? dev->base_addr: 0; unsigned int irq_line = dev ? dev->irq : 0; int *port; + int cards_found = 0; - if (ioaddr > 0x1ff) - return pcnet32_probe1(dev, ioaddr, irq_line, 0); - else if(ioaddr != 0) - return ENXIO; + +#ifndef __powerpc__ + if (ioaddr > 0x1ff) { + if (check_region(ioaddr, PCNET32_TOTAL_SIZE) == 0) + return pcnet32_probe1(dev, ioaddr, irq_line, 0, 0); + else + return ENODEV; + } else +#endif + if(ioaddr != 0) + return ENXIO; #if defined(CONFIG_PCI) if (pci_present()) { - struct pci_dev *pdev = NULL; + struct pci_dev *pdev; + unsigned char pci_bus, pci_device_fn; + int pci_index; printk("pcnet32.c: PCI bios is present, checking for devices...\n"); - while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, pdev))) { - unsigned short pci_command; + for (pci_index = 0; pci_index < 0xff; pci_index++) { + u16 vendor, device, pci_command; + int chip_idx; - irq_line = pdev->irq; + if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, + pci_index, &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) + break; + + pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID, &vendor); + pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID, &device); + + for (chip_idx = 0; pcnet32_tbl[chip_idx].vendor_id; chip_idx++) + if (vendor == pcnet32_tbl[chip_idx].vendor_id && + (device & pcnet32_tbl[chip_idx].device_id_mask) == pcnet32_tbl[chip_idx].device_id) + break; + if (pcnet32_tbl[chip_idx].vendor_id == 0) + continue; + + pdev = pci_find_slot(pci_bus, pci_device_fn); ioaddr = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; +#if defined(ADDR_64BITS) && defined(__alpha__) + ioaddr |= ((long)pdev->base_address[1]) << 32; +#endif + irq_line = pdev->irq; + + /* Avoid already found cards from previous pcnet32_probe() calls */ + if ((pcnet32_tbl[chip_idx].flags & PCI_USES_IO) && + check_region(ioaddr, pcnet32_tbl[chip_idx].io_size)) + continue; + /* PCI Spec 2.1 states that it is either the driver or PCI card's * responsibility to set the PCI Master Enable Bit if needed. * (From Mark Stockton ) */ pci_read_config_word(pdev, PCI_COMMAND, &pci_command); - - /* Avoid already found cards from previous pcnet32_probe() calls */ - if (check_region(ioaddr, PCNET32_TOTAL_SIZE)) - continue; - if ( ! (pci_command & PCI_COMMAND_MASTER)) { printk("PCI Master Bit has not been set. Setting...\n"); pci_command |= PCI_COMMAND_MASTER|PCI_COMMAND_IO; pci_write_config_word(pdev, PCI_COMMAND, pci_command); } + printk("Found PCnet/PCI at %#lx, irq %d.\n", ioaddr, irq_line); - printk("Found PCnet/PCI at %#x, irq %d.\n", - ioaddr, irq_line); - - if (pcnet32_probe1(dev, ioaddr, irq_line, 1) != 0) { /* Shouldn't happen. */ - printk(KERN_ERR "pcnet32.c: Probe of PCI card at %#x failed.\n", ioaddr); - break; + if (pcnet32_tbl[chip_idx].probe1(dev, ioaddr, irq_line, 1, cards_found) == 0) { + cards_found++; + dev = NULL; } - return 0; } } else #endif /* defined(CONFIG_PCI) */ /* now look for PCnet32 VLB cards */ for (port = pcnet32_portlist; *port; port++) { - unsigned int ioaddr = *port; + unsigned long ioaddr = *port; if ( check_region(ioaddr, PCNET32_TOTAL_SIZE) == 0) { /* check if there is really a pcnet chip on that ioaddr */ if ((inb(ioaddr + 14) == 0x57) && (inb(ioaddr + 15) == 0x57) && - (pcnet32_probe1(dev, ioaddr, 0, 0) == 0)) - return 0; + (pcnet32_probe1(dev, ioaddr, 0, 0, 0) == 0)) + cards_found++; } } - return ENODEV; + return cards_found ? 0: ENODEV; } /* pcnet32_probe1 */ -__initfunc(static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, unsigned char irq_line, int shared)) +static int __init +pcnet32_probe1(struct device *dev, unsigned long ioaddr, unsigned char irq_line, int shared, int card_idx) { struct pcnet32_private *lp; - int i,full_duplex = 0; + int i,media,fdx = 0, mii = 0; + int chip_version; char *chipname; + char *priv; + struct pcnet32_access *a; + + /* reset the chip */ + pcnet32_dwio_reset(ioaddr); + pcnet32_wio_reset(ioaddr); + + if (pcnet32_wio_read_csr (ioaddr, 0) == 4 && pcnet32_wio_check (ioaddr)) { + a = &pcnet32_wio; + } else { + if (pcnet32_dwio_read_csr (ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) { + a = &pcnet32_dwio; + } else + return ENODEV; + } - inw(ioaddr+PCNET32_RESET); /* Reset the PCNET32 */ - - outw(0x0000, ioaddr+PCNET32_ADDR); /* Switch to window 0 */ - if (inw(ioaddr+PCNET32_DATA) != 0x0004) - return ENODEV; - - /* Get the version of the chip. */ - outw(88, ioaddr+PCNET32_ADDR); - if (inw(ioaddr+PCNET32_ADDR) != 88) { - /* should never happen */ + chip_version = a->read_csr (ioaddr, 88) | (a->read_csr (ioaddr,89) << 16); + if (pcnet32_debug > 2) + printk(" PCnet chip version is %#x.\n", chip_version); + if ((chip_version & 0xfff) != 0x003) return ENODEV; - } else { /* Good, it's a newer chip. */ - int chip_version = inw(ioaddr+PCNET32_DATA); - outw(89, ioaddr+PCNET32_ADDR); - chip_version |= inw(ioaddr+PCNET32_DATA) << 16; + chip_version = (chip_version >> 12) & 0xffff; + switch (chip_version) { + case 0x2420: + chipname = "PCnet/PCI 79C970"; + break; + case 0x2430: + if (shared) + chipname = "PCnet/PCI 79C970"; /* 970 gives the wrong chip id back */ + else + chipname = "PCnet/32 79C965"; + break; + case 0x2621: + chipname = "PCnet/PCI II 79C970A"; + fdx = 1; + break; + case 0x2623: + chipname = "PCnet/FAST 79C971"; + fdx = 1; mii = 1; + break; + case 0x2624: + chipname = "PCnet/FAST+ 79C972"; + fdx = 1; mii = 1; + break; + case 0x2626: + chipname = "PCnet/Home 79C978"; + fdx = 1; + /* + * This is based on specs published at www.amd.com. This section + * assumes that a card with a 79C978 wants to go into 1Mb HomePNA + * mode. The 79C978 can also go into standard ethernet, and there + * probably should be some sort of module option to select the + * mode by which the card should operate + */ + /* switch to home wiring mode */ + media = a->read_bcr (ioaddr, 49); if (pcnet32_debug > 2) - printk(" PCnet chip version is %#x.\n", chip_version); - if ((chip_version & 0xfff) != 0x003) - return ENODEV; - chip_version = (chip_version >> 12) & 0xffff; - switch (chip_version) { - case 0x2420: - chipname = "PCnet/PCI 79C970"; - break; - case 0x2430: - if (shared) - chipname = "PCnet/PCI 79C970"; /* 970 gives the wrong chip id back */ - else - chipname = "PCnet/32 79C965"; - break; - case 0x2621: - chipname = "PCnet/PCI II 79C970A"; - full_duplex = 1; - break; - case 0x2623: - chipname = "PCnet/FAST 79C971"; - full_duplex = 1; - break; - case 0x2624: - chipname = "PCnet/FAST+ 79C972"; - full_duplex = 1; - break; - default: - printk("pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version); - return ENODEV; - } + printk("pcnet32: pcnet32 media value %#x.\n", media); + media &= ~3; + media |= 1; + if (pcnet32_debug > 2) + printk("pcnet32: pcnet32 media reset to %#x.\n", media); + a->write_bcr (ioaddr, 49, media); + break; + default: + printk("pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version); + return ENODEV; } - if (dev == NULL) - dev = init_etherdev(0, 0); + dev = init_etherdev(dev, 0); - printk("%s: %s at %#3x,", dev->name, chipname, ioaddr); + printk(KERN_INFO "%s: %s at %#3lx,", dev->name, chipname, ioaddr); /* There is a 16 byte station address PROM at the base address. The first six bytes are the station address. */ @@ -345,15 +578,31 @@ __initfunc(static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, un dev->base_addr = ioaddr; request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname); - /* Make certain the data structures used by the PCnet32 are 16byte aligned and DMAble. */ - lp = (struct pcnet32_private *) (((unsigned long)kmalloc(sizeof(*lp)+15, GFP_DMA | GFP_KERNEL)+15) & ~15); + if ((priv = kmalloc(sizeof(*lp)+15,GFP_KERNEL)) == NULL) + return ENOMEM; + + /* + * Make certain the data structures used by + * the PCnet32 are 16byte aligned + */ + lp = (struct pcnet32_private *)(((unsigned long)priv+15) & ~15); memset(lp, 0, sizeof(*lp)); dev->priv = lp; lp->name = chipname; lp->shared_irq = shared; - lp->full_duplex = full_duplex; - lp->options = options; + lp->full_duplex = fdx; + lp->mii = mii; + if (options[card_idx] > sizeof (options_mapping)) + lp->options = PORT_ASEL; + else + lp->options = options_mapping[options[card_idx]]; + + if (fdx && !(lp->options & PORT_ASEL) && full_duplex[card_idx]) + lp->options |= PORT_FD; + + lp->origmem = priv; + lp->a = *a; /* detect special T1/E1 WAN card by checking for MAC address */ if (dev->dev_addr[0] == 0x00 && dev->dev_addr[1] == 0xe0 && dev->dev_addr[2] == 0x75) @@ -369,24 +618,17 @@ __initfunc(static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, un lp->init_block.tx_ring = (u32)le32_to_cpu(virt_to_bus(lp->tx_ring)); /* switch pcnet32 to 32bit mode */ - outw(0x0014, ioaddr+PCNET32_ADDR); - outw(0x0002, ioaddr+PCNET32_BUS_IF); - - outw(0x0001, ioaddr+PCNET32_ADDR); - inw(ioaddr+PCNET32_ADDR); - outw(virt_to_bus(&lp->init_block) & 0xffff, ioaddr+PCNET32_DATA); - outw(0x0002, ioaddr+PCNET32_ADDR); - inw(ioaddr+PCNET32_ADDR); - outw(virt_to_bus(&lp->init_block) >> 16, ioaddr+PCNET32_DATA); - outw(0x0000, ioaddr+PCNET32_ADDR); - inw(ioaddr+PCNET32_ADDR); + a->write_bcr (ioaddr, 20, 2); + + a->write_csr (ioaddr, 1, virt_to_bus(&lp->init_block) & 0xffff); + a->write_csr (ioaddr, 2, virt_to_bus(&lp->init_block) >> 16); if (irq_line) { dev->irq = irq_line; } if (dev->irq >= 2) - printk(" assigned IRQ %d.\n", dev->irq); + printk(" assigned IRQ %d.\n", dev->irq); else { unsigned long irq_mask = probe_irq_on(); @@ -396,7 +638,7 @@ __initfunc(static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, un * boards will work. */ /* Trigger an initialization just for the interrupt. */ - outw(0x0041, ioaddr+PCNET32_DATA); + a->write_csr (ioaddr, 0, 0x41); mdelay (1); dev->irq = probe_irq_off (irq_mask); @@ -409,7 +651,7 @@ __initfunc(static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, un } if (pcnet32_debug > 0) - printk(version); + printk(version); /* The PCNET32-specific entries in the device structure. */ dev->open = &pcnet32_open; @@ -417,6 +659,10 @@ __initfunc(static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, un dev->stop = &pcnet32_close; dev->get_stats = &pcnet32_get_stats; dev->set_multicast_list = &pcnet32_set_multicast_list; +#ifdef HAVE_PRIVATE_IOCTL + dev->do_ioctl = &pcnet32_mii_ioctl; +#endif + #ifdef MODULE lp->next = pcnet32_dev; @@ -432,95 +678,96 @@ __initfunc(static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, un static int pcnet32_open(struct device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; - unsigned int ioaddr = dev->base_addr; - unsigned short val; - int i; - - if (dev->irq == 0 || - request_irq(dev->irq, &pcnet32_interrupt, - lp->shared_irq ? SA_SHIRQ : 0, lp->name, (void *)dev)) { - return -EAGAIN; - } - - /* Reset the PCNET32 */ - inw(ioaddr+PCNET32_RESET); + struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + unsigned long ioaddr = dev->base_addr; + u16 val; + int i; + + if (dev->irq == 0 || + request_irq(dev->irq, &pcnet32_interrupt, + lp->shared_irq ? SA_SHIRQ : 0, lp->name, (void *)dev)) { + return -EAGAIN; + } - /* switch pcnet32 to 32bit mode */ - outw(0x0014, ioaddr+PCNET32_ADDR); - outw(0x0002, ioaddr+PCNET32_BUS_IF); + /* Reset the PCNET32 */ + lp->a.reset (ioaddr); - if (pcnet32_debug > 1) - printk("%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n", - dev->name, dev->irq, - (u32) virt_to_bus(lp->tx_ring), - (u32) virt_to_bus(lp->rx_ring), - (u32) virt_to_bus(&lp->init_block)); + /* switch pcnet32 to 32bit mode */ + lp->a.write_csr (ioaddr, 20, 2); + + if (pcnet32_debug > 1) + printk("%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n", + dev->name, dev->irq, + (u32) virt_to_bus(lp->tx_ring), + (u32) virt_to_bus(lp->rx_ring), + (u32) virt_to_bus(&lp->init_block)); - /* set/reset autoselect bit */ - outw(0x0002, ioaddr+PCNET32_ADDR); - val = inw(ioaddr+PCNET32_BUS_IF) & ~2; - if (lp->options & PORT_ASEL) - val |= 2; - outw(val, ioaddr+PCNET32_BUS_IF); - - /* handle full duplex setting */ - if (lp->full_duplex) { - outw (0x0009, ioaddr+PCNET32_ADDR); - val = inw(ioaddr+PCNET32_BUS_IF) & ~3; - if (lp->options & PORT_FD) { - val |= 1; - if (lp->options == (PORT_FD | PORT_AUI)) - val |= 2; - } - outw(val, ioaddr+PCNET32_BUS_IF); + /* set/reset autoselect bit */ + val = lp->a.read_bcr (ioaddr, 2) & ~2; + if (lp->options & PORT_ASEL) + val |= 2; + lp->a.write_bcr (ioaddr, 2, val); + + /* handle full duplex setting */ + if (lp->full_duplex) { + val = lp->a.read_bcr (ioaddr, 9) & ~3; + if (lp->options & PORT_FD) { + val |= 1; + if (lp->options == (PORT_FD | PORT_AUI)) + val |= 2; } + lp->a.write_bcr (ioaddr, 9, val); + } - /* set/reset GPSI bit in test register */ - outw (0x007c, ioaddr+PCNET32_ADDR); - val = inw(ioaddr+PCNET32_DATA) & ~0x10; - if ((lp->options & PORT_PORTSEL) == PORT_GPSI) - val |= 0x10; - outw(val, ioaddr+PCNET32_DATA); - - lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7); - lp->init_block.filter[0] = 0x00000000; - lp->init_block.filter[1] = 0x00000000; - if (pcnet32_init_ring(dev)) - return -ENOMEM; + /* set/reset GPSI bit in test register */ + val = lp->a.read_csr (ioaddr, 124) & ~0x10; + if ((lp->options & PORT_PORTSEL) == PORT_GPSI) + val |= 0x10; + lp->a.write_csr (ioaddr, 124, val); - /* Re-initialize the PCNET32, and start it when done. */ - outw(0x0001, ioaddr+PCNET32_ADDR); - outw(virt_to_bus(&lp->init_block) &0xffff, ioaddr+PCNET32_DATA); - outw(0x0002, ioaddr+PCNET32_ADDR); - outw(virt_to_bus(&lp->init_block) >> 16, ioaddr+PCNET32_DATA); - - outw(0x0004, ioaddr+PCNET32_ADDR); - outw(0x0915, ioaddr+PCNET32_DATA); - - outw(0x0000, ioaddr+PCNET32_ADDR); - outw(0x0001, ioaddr+PCNET32_DATA); - - dev->tbusy = 0; - dev->interrupt = 0; - dev->start = 1; - i = 0; - while (i++ < 100) - if (inw(ioaddr+PCNET32_DATA) & 0x0100) - break; - /* - * We used to clear the InitDone bit, 0x0100, here but Mark Stockton - * reports that doing so triggers a bug in the '974. - */ - outw(0x0042, ioaddr+PCNET32_DATA); - - if (pcnet32_debug > 2) - printk("%s: PCNET32 open after %d ticks, init block %#x csr0 %4.4x.\n", - dev->name, i, (u32) virt_to_bus(&lp->init_block), inw(ioaddr+PCNET32_DATA)); - - MOD_INC_USE_COUNT; + if (lp->mii & (lp->options & PORT_ASEL)) { + val = lp->a.read_bcr (ioaddr, 32) & ~0x38; /* disable Auto Negotiation, set 10Mpbs, HD */ + if (lp->options & PORT_FD) + val |= 0x10; + if (lp->options & PORT_100) + val |= 0x08; + lp->a.write_bcr (ioaddr, 32, val); + } + + lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7); + lp->init_block.filter[0] = 0x00000000; + lp->init_block.filter[1] = 0x00000000; + if (pcnet32_init_ring(dev)) + return -ENOMEM; + + /* Re-initialize the PCNET32, and start it when done. */ + lp->a.write_csr (ioaddr, 1, virt_to_bus(&lp->init_block) &0xffff); + lp->a.write_csr (ioaddr, 2, virt_to_bus(&lp->init_block) >> 16); + + lp->a.write_csr (ioaddr, 4, 0x0915); + lp->a.write_csr (ioaddr, 0, 0x0001); + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + i = 0; + while (i++ < 100) + if (lp->a.read_csr (ioaddr, 0) & 0x0100) + break; + /* + * We used to clear the InitDone bit, 0x0100, here but Mark Stockton + * reports that doing so triggers a bug in the '974. + */ + lp->a.write_csr (ioaddr, 0, 0x0042); + + if (pcnet32_debug > 2) + printk("%s: PCNET32 open after %d ticks, init block %#x csr0 %4.4x.\n", + dev->name, i, (u32) virt_to_bus(&lp->init_block), + lp->a.read_csr (ioaddr, 0)); + + MOD_INC_USE_COUNT; - return 0; /* Always succeed */ + return 0; /* Always succeed */ } /* @@ -539,15 +786,15 @@ pcnet32_open(struct device *dev) static void pcnet32_purge_tx_ring(struct device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; - int i; + struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + int i; - for (i = 0; i < TX_RING_SIZE; i++) { - if (lp->tx_skbuff[i]) { - dev_kfree_skb(lp->tx_skbuff[i]); - lp->tx_skbuff[i] = NULL; - } + for (i = 0; i < TX_RING_SIZE; i++) { + if (lp->tx_skbuff[i]) { + dev_kfree_skb(lp->tx_skbuff[i]); + lp->tx_skbuff[i] = NULL; } + } } @@ -555,445 +802,437 @@ pcnet32_purge_tx_ring(struct device *dev) static int pcnet32_init_ring(struct device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; - int i; - - lp->tx_full = 0; - lp->cur_rx = lp->cur_tx = 0; - lp->dirty_rx = lp->dirty_tx = 0; - - for (i = 0; i < RX_RING_SIZE; i++) { - if (lp->rx_skbuff[i] == NULL) { - if (!(lp->rx_skbuff[i] = dev_alloc_skb (PKT_BUF_SZ))) { - /* there is not much, we can do at this point */ - printk ("%s: pcnet32_init_ring dev_alloc_skb failed.\n",dev->name); - return -1; - } - skb_reserve (lp->rx_skbuff[i], 2); + struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + int i; + + lp->tx_full = 0; + lp->cur_rx = lp->cur_tx = 0; + lp->dirty_rx = lp->dirty_tx = 0; + + for (i = 0; i < RX_RING_SIZE; i++) { + if (lp->rx_skbuff[i] == NULL) { + if (!(lp->rx_skbuff[i] = dev_alloc_skb (PKT_BUF_SZ))) { + /* there is not much, we can do at this point */ + printk ("%s: pcnet32_init_ring dev_alloc_skb failed.\n",dev->name); + return -1; } - lp->rx_ring[i].base = (u32)le32_to_cpu(virt_to_bus(lp->rx_skbuff[i]->tail)); - lp->rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ); - lp->rx_ring[i].status = le16_to_cpu(0x8000); - } - /* The Tx buffer address is filled in as needed, but we do need to clear - the upper ownership bit. */ - for (i = 0; i < TX_RING_SIZE; i++) { - lp->tx_ring[i].base = 0; - lp->tx_ring[i].status = 0; + skb_reserve (lp->rx_skbuff[i], 2); } + lp->rx_ring[i].base = (u32)le32_to_cpu(virt_to_bus(lp->rx_skbuff[i]->tail)); + lp->rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ); + lp->rx_ring[i].status = le16_to_cpu(0x8000); + } + /* The Tx buffer address is filled in as needed, but we do need to clear + the upper ownership bit. */ + for (i = 0; i < TX_RING_SIZE; i++) { + lp->tx_ring[i].base = 0; + lp->tx_ring[i].status = 0; + } - lp->init_block.tlen_rlen = TX_RING_LEN_BITS | RX_RING_LEN_BITS; - for (i = 0; i < 6; i++) - lp->init_block.phys_addr[i] = dev->dev_addr[i]; - lp->init_block.rx_ring = (u32)le32_to_cpu(virt_to_bus(lp->rx_ring)); - lp->init_block.tx_ring = (u32)le32_to_cpu(virt_to_bus(lp->tx_ring)); - return 0; + lp->init_block.tlen_rlen = TX_RING_LEN_BITS | RX_RING_LEN_BITS; + for (i = 0; i < 6; i++) + lp->init_block.phys_addr[i] = dev->dev_addr[i]; + lp->init_block.rx_ring = (u32)le32_to_cpu(virt_to_bus(lp->rx_ring)); + lp->init_block.tx_ring = (u32)le32_to_cpu(virt_to_bus(lp->tx_ring)); + return 0; } static void pcnet32_restart(struct device *dev, unsigned int csr0_bits) { - int i; - unsigned int ioaddr = dev->base_addr; + struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + unsigned long ioaddr = dev->base_addr; + int i; - pcnet32_purge_tx_ring(dev); - if (pcnet32_init_ring(dev)) - return; + pcnet32_purge_tx_ring(dev); + if (pcnet32_init_ring(dev)) + return; - outw(0x0000, ioaddr + PCNET32_ADDR); - /* ReInit Ring */ - outw(0x0001, ioaddr + PCNET32_DATA); - i = 0; - while (i++ < 100) - if (inw(ioaddr+PCNET32_DATA) & 0x0100) - break; - - outw(csr0_bits, ioaddr + PCNET32_DATA); + /* ReInit Ring */ + lp->a.write_csr (ioaddr, 0, 1); + i = 0; + while (i++ < 100) + if (lp->a.read_csr (ioaddr, 0) & 0x0100) + break; + + lp->a.write_csr (ioaddr, 0, csr0_bits); } static int pcnet32_start_xmit(struct sk_buff *skb, struct device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; - unsigned int ioaddr = dev->base_addr; - int entry; - unsigned long flags; - - /* Transmitter timeout, serious problems. */ - if (dev->tbusy) { - int tickssofar = jiffies - dev->trans_start; - if (tickssofar < HZ/2) - return 1; - outw(0, ioaddr+PCNET32_ADDR); - printk("%s: transmit timed out, status %4.4x, resetting.\n", - dev->name, inw(ioaddr+PCNET32_DATA)); - outw(0x0004, ioaddr+PCNET32_DATA); - lp->stats.tx_errors++; - if (pcnet32_debug > 2) { - int i; - printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.", - lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "", - lp->cur_rx); - for (i = 0 ; i < RX_RING_SIZE; i++) - printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ", - lp->rx_ring[i].base, -lp->rx_ring[i].buf_length, - lp->rx_ring[i].msg_length, (unsigned)lp->rx_ring[i].status); - for (i = 0 ; i < TX_RING_SIZE; i++) - printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ", - lp->tx_ring[i].base, -lp->tx_ring[i].length, - lp->tx_ring[i].misc, (unsigned)lp->tx_ring[i].status); - printk("\n"); - } - pcnet32_restart(dev, 0x0042); - - dev->tbusy = 0; - dev->trans_start = jiffies; - dev_kfree_skb(skb); - return 0; + struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + unsigned int ioaddr = dev->base_addr; + int entry; + unsigned long flags; + + /* Transmitter timeout, serious problems. */ + if (dev->tbusy) { + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < HZ/2) + return 1; + printk("%s: transmit timed out, status %4.4x, resetting.\n", + dev->name, lp->a.read_csr (ioaddr, 0)); + lp->a.write_csr (ioaddr, 0, 0x0004); + lp->stats.tx_errors++; + if (pcnet32_debug > 2) { + int i; + printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.", + lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "", + lp->cur_rx); + for (i = 0 ; i < RX_RING_SIZE; i++) + printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ", + lp->rx_ring[i].base, -lp->rx_ring[i].buf_length, + lp->rx_ring[i].msg_length, (unsigned)lp->rx_ring[i].status); + for (i = 0 ; i < TX_RING_SIZE; i++) + printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ", + lp->tx_ring[i].base, -lp->tx_ring[i].length, + lp->tx_ring[i].misc, (unsigned)lp->tx_ring[i].status); + printk("\n"); } + pcnet32_restart(dev, 0x0042); - if (pcnet32_debug > 3) { - outw(0x0000, ioaddr+PCNET32_ADDR); - printk("%s: pcnet32_start_xmit() called, csr0 %4.4x.\n", dev->name, - inw(ioaddr+PCNET32_DATA)); - } + dev->tbusy = 0; + dev->trans_start = jiffies; + dev_kfree_skb(skb); + return 0; + } - /* Block a timer-based transmit from overlapping. This could better be - done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ - if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { - printk("%s: Transmitter access conflict.\n", dev->name); - return 1; - } + if (pcnet32_debug > 3) { + printk("%s: pcnet32_start_xmit() called, csr0 %4.4x.\n", + dev->name, lp->a.read_csr (ioaddr, 0)); + } - save_flags (flags); - cli (); + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) { + printk("%s: Transmitter access conflict.\n", dev->name); + return 1; + } - /* Fill in a Tx ring entry */ + save_flags (flags); + cli (); - /* Mask to ring buffer boundary. */ - entry = lp->cur_tx & TX_RING_MOD_MASK; + /* Fill in a Tx ring entry */ - /* Caution: the write order is important here, set the base address - with the "ownership" bits last. */ + /* Mask to ring buffer boundary. */ + entry = lp->cur_tx & TX_RING_MOD_MASK; - lp->tx_ring[entry].length = le16_to_cpu(-skb->len); + /* Caution: the write order is important here, set the base address + with the "ownership" bits last. */ - lp->tx_ring[entry].misc = 0x00000000; + lp->tx_ring[entry].length = le16_to_cpu(-skb->len); - lp->tx_skbuff[entry] = skb; - lp->tx_ring[entry].base = (u32)le32_to_cpu(virt_to_bus(skb->data)); - lp->tx_ring[entry].status = le16_to_cpu(0x8300); + lp->tx_ring[entry].misc = 0x00000000; - lp->cur_tx++; - lp->stats.tx_bytes += skb->len; + lp->tx_skbuff[entry] = skb; + lp->tx_ring[entry].base = (u32)le32_to_cpu(virt_to_bus(skb->data)); + lp->tx_ring[entry].status = le16_to_cpu(0x8300); - /* Trigger an immediate send poll. */ - outw(0x0000, ioaddr+PCNET32_ADDR); - outw(0x0048, ioaddr+PCNET32_DATA); + lp->cur_tx++; + lp->stats.tx_bytes += skb->len; - dev->trans_start = jiffies; + /* Trigger an immediate send poll. */ + lp->a.write_csr (ioaddr, 0, 0x0048); - if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0) - clear_bit (0, (void *)&dev->tbusy); - else - lp->tx_full = 1; - restore_flags(flags); - return 0; + dev->trans_start = jiffies; + + if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0) + clear_bit (0, (void *)&dev->tbusy); + else + lp->tx_full = 1; + restore_flags(flags); + return 0; } /* The PCNET32 interrupt handler. */ static void pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs) { - struct device *dev = (struct device *)dev_id; - struct pcnet32_private *lp; - unsigned int csr0, ioaddr; - int boguscnt = max_interrupt_work; - int must_restart; - - if (dev == NULL) { - printk ("pcnet32_interrupt(): irq %d for unknown device.\n", irq); - return; - } + struct device *dev = (struct device *)dev_id; + struct pcnet32_private *lp; + unsigned long ioaddr; + u16 csr0; + int boguscnt = max_interrupt_work; + int must_restart; - ioaddr = dev->base_addr; - lp = (struct pcnet32_private *)dev->priv; - if (dev->interrupt) - printk("%s: Re-entering the interrupt handler.\n", dev->name); + if (dev == NULL) { + printk ("pcnet32_interrupt(): irq %d for unknown device.\n", irq); + return; + } - dev->interrupt = 1; + ioaddr = dev->base_addr; + lp = (struct pcnet32_private *)dev->priv; + if (dev->interrupt) + printk("%s: Re-entering the interrupt handler.\n", dev->name); - outw(0x00, dev->base_addr + PCNET32_ADDR); - while ((csr0 = inw(dev->base_addr + PCNET32_DATA)) & 0x8600 && --boguscnt >= 0) { - /* Acknowledge all of the current interrupt sources ASAP. */ - outw(csr0 & ~0x004f, dev->base_addr + PCNET32_DATA); + dev->interrupt = 1; - must_restart = 0; + while ((csr0 = lp->a.read_csr (ioaddr, 0)) & 0x8600 && --boguscnt >= 0) { + /* Acknowledge all of the current interrupt sources ASAP. */ + lp->a.write_csr (ioaddr, 0, csr0 & ~0x004f); - if (pcnet32_debug > 5) - printk("%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n", - dev->name, csr0, inw(dev->base_addr + PCNET32_DATA)); + must_restart = 0; - if (csr0 & 0x0400) /* Rx interrupt */ - pcnet32_rx(dev); + if (pcnet32_debug > 5) + printk("%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n", + dev->name, csr0, lp->a.read_csr (ioaddr, 0)); - if (csr0 & 0x0200) { /* Tx-done interrupt */ - int dirty_tx = lp->dirty_tx; + if (csr0 & 0x0400) /* Rx interrupt */ + pcnet32_rx(dev); - while (dirty_tx < lp->cur_tx) { - int entry = dirty_tx & TX_RING_MOD_MASK; - int status = (short)le16_to_cpu(lp->tx_ring[entry].status); + if (csr0 & 0x0200) { /* Tx-done interrupt */ + int dirty_tx = lp->dirty_tx; + + while (dirty_tx < lp->cur_tx) { + int entry = dirty_tx & TX_RING_MOD_MASK; + int status = (short)le16_to_cpu(lp->tx_ring[entry].status); - if (status < 0) - break; /* It still hasn't been Txed */ - - lp->tx_ring[entry].base = 0; - - if (status & 0x4000) { - /* There was an major error, log it. */ - int err_status = le32_to_cpu(lp->tx_ring[entry].misc); - lp->stats.tx_errors++; - if (err_status & 0x04000000) lp->stats.tx_aborted_errors++; - if (err_status & 0x08000000) lp->stats.tx_carrier_errors++; - if (err_status & 0x10000000) lp->stats.tx_window_errors++; - if (err_status & 0x40000000) { - /* Ackk! On FIFO errors the Tx unit is turned off! */ - lp->stats.tx_fifo_errors++; - /* Remove this verbosity later! */ - printk("%s: Tx FIFO error! Status %4.4x.\n", - dev->name, csr0); - must_restart = 1; + if (status < 0) + break; /* It still hasn't been Txed */ + + lp->tx_ring[entry].base = 0; + + if (status & 0x4000) { + /* There was an major error, log it. */ + int err_status = le32_to_cpu(lp->tx_ring[entry].misc); + lp->stats.tx_errors++; + if (err_status & 0x04000000) lp->stats.tx_aborted_errors++; + if (err_status & 0x08000000) lp->stats.tx_carrier_errors++; + if (err_status & 0x10000000) lp->stats.tx_window_errors++; + if (err_status & 0x40000000) { + /* Ackk! On FIFO errors the Tx unit is turned off! */ + lp->stats.tx_fifo_errors++; + /* Remove this verbosity later! */ + printk("%s: Tx FIFO error! Status %4.4x.\n", + dev->name, csr0); + must_restart = 1; } - } else { - if (status & 0x1800) - lp->stats.collisions++; - lp->stats.tx_packets++; - } - - /* We must free the original skb */ - if (lp->tx_skbuff[entry]) { - dev_kfree_skb(lp->tx_skbuff[entry]); - lp->tx_skbuff[entry] = 0; - } - dirty_tx++; - } + } else { + if (status & 0x1800) + lp->stats.collisions++; + lp->stats.tx_packets++; + } + + /* We must free the original skb */ + if (lp->tx_skbuff[entry]) { + dev_kfree_skb(lp->tx_skbuff[entry]); + lp->tx_skbuff[entry] = 0; + } + dirty_tx++; + } #ifndef final_version - if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) { - printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n", - dirty_tx, lp->cur_tx, lp->tx_full); - dirty_tx += TX_RING_SIZE; - } + if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) { + printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n", + dirty_tx, lp->cur_tx, lp->tx_full); + dirty_tx += TX_RING_SIZE; + } #endif + if (lp->tx_full && dev->tbusy + && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) { + /* The ring is no longer full, clear tbusy. */ + lp->tx_full = 0; + clear_bit(0, (void *)&dev->tbusy); + mark_bh(NET_BH); + } + lp->dirty_tx = dirty_tx; + } - if (lp->tx_full && dev->tbusy - && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) { - /* The ring is no longer full, clear tbusy. */ - lp->tx_full = 0; - clear_bit(0, (void *)&dev->tbusy); - mark_bh(NET_BH); - } - lp->dirty_tx = dirty_tx; - } - - /* Log misc errors. */ - if (csr0 & 0x4000) lp->stats.tx_errors++; /* Tx babble. */ - if (csr0 & 0x1000) { - /* - * this happens when our receive ring is full. This shouldn't - * be a problem as we will see normal rx interrupts for the frames - * in the receive ring. But there are some PCI chipsets (I can reproduce - * this on SP3G with Intel saturn chipset) which have sometimes problems - * and will fill up the receive ring with error descriptors. In this - * situation we don't get a rx interrupt, but a missed frame interrupt sooner - * or later. So we try to clean up our receive ring here. - */ - pcnet32_rx(dev); - lp->stats.rx_errors++; /* Missed a Rx frame. */ - } - if (csr0 & 0x0800) { - printk("%s: Bus master arbitration failure, status %4.4x.\n", - dev->name, csr0); - /* unlike for the lance, there is no restart needed */ - } + /* Log misc errors. */ + if (csr0 & 0x4000) lp->stats.tx_errors++; /* Tx babble. */ + if (csr0 & 0x1000) { + /* + * this happens when our receive ring is full. This shouldn't + * be a problem as we will see normal rx interrupts for the frames + * in the receive ring. But there are some PCI chipsets (I can reproduce + * this on SP3G with Intel saturn chipset) which have sometimes problems + * and will fill up the receive ring with error descriptors. In this + * situation we don't get a rx interrupt, but a missed frame interrupt sooner + * or later. So we try to clean up our receive ring here. + */ + pcnet32_rx(dev); + lp->stats.rx_errors++; /* Missed a Rx frame. */ + } + if (csr0 & 0x0800) { + printk("%s: Bus master arbitration failure, status %4.4x.\n", + dev->name, csr0); + /* unlike for the lance, there is no restart needed */ + } - if (must_restart) { - /* stop the chip to clear the error condition, then restart */ - outw(0x0000, dev->base_addr + PCNET32_ADDR); - outw(0x0004, dev->base_addr + PCNET32_DATA); - pcnet32_restart(dev, 0x0002); - } + if (must_restart) { + /* stop the chip to clear the error condition, then restart */ + lp->a.write_csr (ioaddr, 0, 0x0004); + pcnet32_restart(dev, 0x0002); } + } /* Clear any other interrupt, and set interrupt enable. */ - outw(0x0000, dev->base_addr + PCNET32_ADDR); - outw(0x7940, dev->base_addr + PCNET32_DATA); + lp->a.write_csr (ioaddr, 0, 0x7940); - if (pcnet32_debug > 4) - printk("%s: exiting interrupt, csr%d=%#4.4x.\n", - dev->name, inw(ioaddr + PCNET32_ADDR), - inw(dev->base_addr + PCNET32_DATA)); + if (pcnet32_debug > 4) + printk("%s: exiting interrupt, csr0=%#4.4x.\n", + dev->name, lp->a.read_csr (ioaddr, 0)); - dev->interrupt = 0; - return; + dev->interrupt = 0; + return; } static int pcnet32_rx(struct device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; - int entry = lp->cur_rx & RX_RING_MOD_MASK; - int i; - - /* If we own the next entry, it's a new packet. Send it up. */ - while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) { - int status = (short)le16_to_cpu(lp->rx_ring[entry].status) >> 8; - - if (status != 0x03) { /* There was an error. */ - /* There is a tricky error noted by John Murphy, - to Russ Nelson: Even with full-sized - buffers it's possible for a jabber packet to use two - buffers, with only the last correctly noting the error. */ - if (status & 0x01) /* Only count a general error at the */ - lp->stats.rx_errors++; /* end of a packet.*/ - if (status & 0x20) lp->stats.rx_frame_errors++; - if (status & 0x10) lp->stats.rx_over_errors++; - if (status & 0x08) lp->stats.rx_crc_errors++; - if (status & 0x04) lp->stats.rx_fifo_errors++; - lp->rx_ring[entry].status &= le16_to_cpu(0x03ff); - } - else - { - /* Malloc up new buffer, compatible with net-2e. */ - short pkt_len = (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff)-4; - struct sk_buff *skb; + struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + int entry = lp->cur_rx & RX_RING_MOD_MASK; + int i; + + /* If we own the next entry, it's a new packet. Send it up. */ + while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) { + int status = (short)le16_to_cpu(lp->rx_ring[entry].status) >> 8; + + if (status != 0x03) { /* There was an error. */ + /* + * There is a tricky error noted by John Murphy, + * to Russ Nelson: Even with full-sized + * buffers it's possible for a jabber packet to use two + * buffers, with only the last correctly noting the error. + */ + if (status & 0x01) /* Only count a general error at the */ + lp->stats.rx_errors++; /* end of a packet.*/ + if (status & 0x20) lp->stats.rx_frame_errors++; + if (status & 0x10) lp->stats.rx_over_errors++; + if (status & 0x08) lp->stats.rx_crc_errors++; + if (status & 0x04) lp->stats.rx_fifo_errors++; + lp->rx_ring[entry].status &= le16_to_cpu(0x03ff); + } else { + /* Malloc up new buffer, compatible with net-2e. */ + short pkt_len = (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff)-4; + struct sk_buff *skb; - if(pkt_len < 60) { - printk("%s: Runt packet!\n",dev->name); - lp->stats.rx_errors++; - } else { - int rx_in_place = 0; + if(pkt_len < 60) { + printk("%s: Runt packet!\n",dev->name); + lp->stats.rx_errors++; + } else { + int rx_in_place = 0; - if (pkt_len > rx_copybreak) { - struct sk_buff *newskb; + if (pkt_len > rx_copybreak) { + struct sk_buff *newskb; - if ((newskb = dev_alloc_skb (PKT_BUF_SZ))) { - skb_reserve (newskb, 2); - skb = lp->rx_skbuff[entry]; - skb_put (skb, pkt_len); - lp->rx_skbuff[entry] = newskb; - newskb->dev = dev; - lp->rx_ring[entry].base = le32_to_cpu(virt_to_bus(newskb->tail)); - rx_in_place = 1; - } else - skb = NULL; - } else - skb = dev_alloc_skb(pkt_len+2); + if ((newskb = dev_alloc_skb (PKT_BUF_SZ))) { + skb_reserve (newskb, 2); + skb = lp->rx_skbuff[entry]; + skb_put (skb, pkt_len); + lp->rx_skbuff[entry] = newskb; + newskb->dev = dev; + lp->rx_ring[entry].base = le32_to_cpu(virt_to_bus(newskb->tail)); + rx_in_place = 1; + } else + skb = NULL; + } else + skb = dev_alloc_skb(pkt_len+2); - if (skb == NULL) { - printk("%s: Memory squeeze, deferring packet.\n", dev->name); - for (i=0; i < RX_RING_SIZE; i++) - if ((short)le16_to_cpu(lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].status) < 0) - break; - - if (i > RX_RING_SIZE -2) { - lp->stats.rx_dropped++; - lp->rx_ring[entry].status |= le16_to_cpu(0x8000); - lp->cur_rx++; - } - break; - } - skb->dev = dev; - if (!rx_in_place) { - skb_reserve(skb,2); /* 16 byte align */ - skb_put(skb,pkt_len); /* Make room */ - eth_copy_and_sum(skb, - (unsigned char *)bus_to_virt(le32_to_cpu(lp->rx_ring[entry].base)), - pkt_len,0); - } - lp->stats.rx_bytes += skb->len; - skb->protocol=eth_type_trans(skb,dev); - netif_rx(skb); - lp->stats.rx_packets++; - } + if (skb == NULL) { + printk("%s: Memory squeeze, deferring packet.\n", dev->name); + for (i=0; i < RX_RING_SIZE; i++) + if ((short)le16_to_cpu(lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].status) < 0) + break; + + if (i > RX_RING_SIZE -2) { + lp->stats.rx_dropped++; + lp->rx_ring[entry].status |= le16_to_cpu(0x8000); + lp->cur_rx++; + } + break; + } + skb->dev = dev; + if (!rx_in_place) { + skb_reserve(skb,2); /* 16 byte align */ + skb_put(skb,pkt_len); /* Make room */ + eth_copy_and_sum(skb, + (unsigned char *)bus_to_virt(le32_to_cpu(lp->rx_ring[entry].base)), + pkt_len,0); } - /* The docs say that the buffer length isn't touched, but Andrew Boyd - of QNX reports that some revs of the 79C965 clear it. */ - lp->rx_ring[entry].buf_length = le16_to_cpu(-PKT_BUF_SZ); - lp->rx_ring[entry].status |= le16_to_cpu(0x8000); - entry = (++lp->cur_rx) & RX_RING_MOD_MASK; + lp->stats.rx_bytes += skb->len; + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + lp->stats.rx_packets++; + } } + /* + * The docs say that the buffer length isn't touched, but Andrew Boyd + * of QNX reports that some revs of the 79C965 clear it. + */ + lp->rx_ring[entry].buf_length = le16_to_cpu(-PKT_BUF_SZ); + lp->rx_ring[entry].status |= le16_to_cpu(0x8000); + entry = (++lp->cur_rx) & RX_RING_MOD_MASK; + } - /* We should check that at least two ring entries are free. If not, - we should free one and mark stats->rx_dropped++. */ - - return 0; + return 0; } static int pcnet32_close(struct device *dev) { - unsigned int ioaddr = dev->base_addr; - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; - int i; + unsigned long ioaddr = dev->base_addr; + struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + int i; - dev->start = 0; - set_bit (0, (void *)&dev->tbusy); + dev->start = 0; + set_bit (0, (void *)&dev->tbusy); - outw(112, ioaddr+PCNET32_ADDR); - lp->stats.rx_missed_errors = inw(ioaddr+PCNET32_DATA); + lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112); - outw(0, ioaddr+PCNET32_ADDR); + if (pcnet32_debug > 1) + printk("%s: Shutting down ethercard, status was %2.2x.\n", + dev->name, lp->a.read_csr (ioaddr, 0)); - if (pcnet32_debug > 1) - printk("%s: Shutting down ethercard, status was %2.2x.\n", - dev->name, inw(ioaddr+PCNET32_DATA)); + /* We stop the PCNET32 here -- it occasionally polls memory if we don't. */ + lp->a.write_csr (ioaddr, 0, 0x0004); - /* We stop the PCNET32 here -- it occasionally polls - memory if we don't. */ - outw(0x0004, ioaddr+PCNET32_DATA); + /* + * Switch back to 16bit mode to avoid problems with dumb + * DOS packet driver after a warm reboot + */ + lp->a.write_bcr (ioaddr, 20, 4); - free_irq(dev->irq, dev); + free_irq(dev->irq, dev); - /* free all allocated skbuffs */ - for (i = 0; i < RX_RING_SIZE; i++) { - lp->rx_ring[i].status = 0; - if (lp->rx_skbuff[i]) - dev_kfree_skb(lp->rx_skbuff[i]); - lp->rx_skbuff[i] = NULL; - } + /* free all allocated skbuffs */ + for (i = 0; i < RX_RING_SIZE; i++) { + lp->rx_ring[i].status = 0; + if (lp->rx_skbuff[i]) + dev_kfree_skb(lp->rx_skbuff[i]); + lp->rx_skbuff[i] = NULL; + } - for (i = 0; i < TX_RING_SIZE; i++) { - if (lp->tx_skbuff[i]) - dev_kfree_skb(lp->tx_skbuff[i]); - lp->rx_skbuff[i] = NULL; - } + for (i = 0; i < TX_RING_SIZE; i++) { + if (lp->tx_skbuff[i]) + dev_kfree_skb(lp->tx_skbuff[i]); + lp->rx_skbuff[i] = NULL; + } - MOD_DEC_USE_COUNT; + MOD_DEC_USE_COUNT; - return 0; + return 0; } static struct net_device_stats * pcnet32_get_stats(struct device *dev) { - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; - unsigned int ioaddr = dev->base_addr; - unsigned short saved_addr; - unsigned long flags; - - save_flags(flags); - cli(); - saved_addr = inw(ioaddr+PCNET32_ADDR); - outw(112, ioaddr+PCNET32_ADDR); - lp->stats.rx_missed_errors = inw(ioaddr+PCNET32_DATA); - outw(saved_addr, ioaddr+PCNET32_ADDR); - restore_flags(flags); - - return &lp->stats; + struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + unsigned long ioaddr = dev->base_addr; + u16 saved_addr; + unsigned long flags; + + save_flags(flags); + cli(); + saved_addr = lp->a.read_rap(ioaddr); + lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112); + lp->a.write_rap(ioaddr, saved_addr); + restore_flags(flags); + + return &lp->stats; } - /* taken from the sunlance driver, which it took from the depca driver */ static void pcnet32_load_multicast (struct device *dev) { @@ -1044,34 +1283,68 @@ static void pcnet32_load_multicast (struct device *dev) } -/* Set or clear the multicast filter for this adaptor. +/* + * Set or clear the multicast filter for this adaptor. */ - static void pcnet32_set_multicast_list(struct device *dev) { - unsigned int ioaddr = dev->base_addr; - struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; - - if (dev->flags&IFF_PROMISC) { - /* Log any net taps. */ - printk("%s: Promiscuous mode enabled.\n", dev->name); - lp->init_block.mode = le16_to_cpu(0x8000 | (lp->options & PORT_PORTSEL) << 7); - } else { - lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7); - pcnet32_load_multicast (dev); - } + unsigned long ioaddr = dev->base_addr; + struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + + if (dev->flags&IFF_PROMISC) { + /* Log any net taps. */ + printk("%s: Promiscuous mode enabled.\n", dev->name); + lp->init_block.mode = le16_to_cpu(0x8000 | (lp->options & PORT_PORTSEL) << 7); + } else { + lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7); + pcnet32_load_multicast (dev); + } - outw(0, ioaddr+PCNET32_ADDR); - outw(0x0004, ioaddr+PCNET32_DATA); /* Temporarily stop the lance. */ + lp->a.write_csr (ioaddr, 0, 0x0004); /* Temporarily stop the lance. */ - pcnet32_restart(dev, 0x0042); /* Resume normal operation */ + pcnet32_restart(dev, 0x0042); /* Resume normal operation */ } +#ifdef HAVE_PRIVATE_IOCTL +static int pcnet32_mii_ioctl(struct device *dev, struct ifreq *rq, int cmd) +{ + unsigned long ioaddr = dev->base_addr; + struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv; + u16 *data = (u16 *)&rq->ifr_data; + int phyaddr = lp->a.read_bcr (ioaddr, 33); + + if (lp->mii) { + switch(cmd) { + case SIOCDEVPRIVATE: /* Get the address of the PHY in use. */ + data[0] = (phyaddr >> 5) & 0x1f; + /* Fall Through */ + case SIOCDEVPRIVATE+1: /* Read the specified MII register. */ + lp->a.write_bcr (ioaddr, 33, ((data[0] & 0x1f) << 5) | (data[1] & 0x1f)); + data[3] = lp->a.read_bcr (ioaddr, 34); + lp->a.write_bcr (ioaddr, 33, phyaddr); + return 0; + case SIOCDEVPRIVATE+2: /* Write the specified MII register */ + if (!suser()) + return -EPERM; + lp->a.write_bcr (ioaddr, 33, ((data[0] & 0x1f) << 5) | (data[1] & 0x1f)); + lp->a.write_bcr (ioaddr, 34, data[2]); + lp->a.write_bcr (ioaddr, 33, phyaddr); + return 0; + default: + return -EOPNOTSUPP; + } + } + return -EOPNOTSUPP; +} +#endif /* HAVE_PRIVATE_IOCTL */ + #ifdef MODULE MODULE_PARM(debug, "i"); -MODULE_PARM(options, "i"); MODULE_PARM(max_interrupt_work, "i"); MODULE_PARM(rx_copybreak, "i"); +MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i"); +MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i"); + /* An additional parameter that may be passed in... */ static int debug = -1; @@ -1079,27 +1352,27 @@ static int debug = -1; int init_module(void) { - if (debug > 0) - pcnet32_debug = debug; + if (debug > 0) + pcnet32_debug = debug; - pcnet32_dev = NULL; - return pcnet32_probe(NULL); + pcnet32_dev = NULL; + return pcnet32_probe(NULL); } void cleanup_module(void) { - struct device *next_dev; - - /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ - while (pcnet32_dev) { - next_dev = ((struct pcnet32_private *) pcnet32_dev->priv)->next; - unregister_netdev(pcnet32_dev); - release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE); - kfree(pcnet32_dev->priv); - kfree(pcnet32_dev); - pcnet32_dev = next_dev; - } + struct device *next_dev; + + /* No need to check MOD_IN_USE, as sys_delete_module() checks. */ + while (pcnet32_dev) { + next_dev = ((struct pcnet32_private *) pcnet32_dev->priv)->next; + unregister_netdev(pcnet32_dev); + release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE); + kfree(((struct pcnet32_private *)pcnet32_dev->priv)->origmem); + kfree(pcnet32_dev); + pcnet32_dev = next_dev; + } } #endif /* MODULE */ diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index 9b175bffaa06..4016cf60fdd5 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -59,15 +59,7 @@ * stack will need to know about I/O vectors or something similar. */ -static const char *version = "rrunner.c: v0.09 12/14/98 Jes Sorensen (Jes.Sorensen@cern.ch)\n"; - -static unsigned int read_eeprom(struct rr_private *rrpriv, - unsigned long offset, - unsigned char *buf, - unsigned long length); -static u32 read_eeprom_word(struct rr_private *rrpriv, - void * offset); -static int rr_load_firmware(struct device *dev); +static const char __initdata *version = "rrunner.c: v0.17 03/09/99 Jes Sorensen (Jes.Sorensen@cern.ch)\n"; /* @@ -78,44 +70,32 @@ static int rr_load_firmware(struct device *dev); extern __u32 sysctl_wmem_max; extern __u32 sysctl_rmem_max; +static int probed __initdata = 0; + __initfunc(int rr_hippi_probe (struct device *dev)) { - static int i = 0; int boards_found = 0; int version_disp; /* was version info already displayed? */ - u8 pci_bus; /* PCI bus number (0-255) */ - u8 pci_dev_fun; /* PCI device and function numbers (0-255) */ + struct pci_dev *pdev = NULL; + struct pci_dev *opdev = NULL; u8 pci_latency; - u16 command; /* PCI Configuration space Command register */ - unsigned int tmp; - u8 irq; struct rr_private *rrpriv; + if (probed) + return -ENODEV; + probed++; + if (!pci_present()) /* is PCI BIOS even present? */ return -ENODEV; version_disp = 0; - for (; i < 255; i++) + while((pdev = pci_find_device(PCI_VENDOR_ID_ESSENTIAL, + PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER, + pdev))) { - if (pcibios_find_device(PCI_VENDOR_ID_ESSENTIAL, - PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER, - i, &pci_bus, &pci_dev_fun) != 0) - break; - - pcibios_read_config_word(pci_bus, pci_dev_fun, - PCI_COMMAND, &command); - - /* Enable mastering */ - - command |= PCI_COMMAND_MASTER; - pcibios_write_config_word(pci_bus, pci_dev_fun, - PCI_COMMAND, command); - - if (!(command & PCI_COMMAND_MEMORY)){ - printk("shared mem not enabled - unable to configure RoadRunner\n"); - break; - } + if (pdev == opdev) + return 0; /* * So we found our HIPPI ... time to tell the system. @@ -123,31 +103,24 @@ __initfunc(int rr_hippi_probe (struct device *dev)) dev = init_hippi_dev(dev, sizeof(struct rr_private)); - if (dev == NULL) + if (!dev) break; if (!dev->priv) dev->priv = kmalloc(sizeof(*rrpriv), GFP_KERNEL); - rrpriv = (struct rr_private *)dev->priv; - - /* Read register base address from - PCI Configuration Space */ - - pcibios_read_config_dword(pci_bus, pci_dev_fun, - PCI_BASE_ADDRESS_0, &tmp); + if (!dev->priv) + return -ENOMEM; - pcibios_read_config_byte(pci_bus, pci_dev_fun, - PCI_INTERRUPT_LINE, &irq); + rrpriv = (struct rr_private *)dev->priv; + memset(rrpriv, 0, sizeof(*rrpriv)); - dev->irq = irq; - rrpriv->pci_bus = pci_bus; - rrpriv->pci_dev_fun = pci_dev_fun; - sprintf(rrpriv->name, "RoadRunner serial HIPPI"); #ifdef __SMP__ spin_lock_init(&rrpriv->lock); #endif + sprintf(rrpriv->name, "RoadRunner serial HIPPI"); + dev->irq = pdev->irq; dev->open = &rr_open; dev->hard_start_xmit = &rr_start_xmit; dev->stop = &rr_close; @@ -168,29 +141,30 @@ __initfunc(int rr_hippi_probe (struct device *dev)) printk(version); } - printk(KERN_INFO "%s: Essential RoadRunner serial HIPPI at 0x%08x, irq %i\n", - dev->name, tmp, dev->irq); - - pcibios_read_config_byte(pci_bus, pci_dev_fun, - PCI_LATENCY_TIMER, &pci_latency); -#if 0 - if (pci_latency <= 48){ - printk(" PCI latency counter too low (%i), setting to 48 clocks\n", pci_latency); - pcibios_write_config_byte(pci_bus, pci_dev_fun, - PCI_LATENCY_TIMER, 48); + pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency); + if (pci_latency <= 0x58){ + pci_latency = 0x58; + pci_write_config_byte(pdev, PCI_LATENCY_TIMER, + pci_latency); } -#else - if (pci_latency <= 0x58) - pcibios_write_config_byte(pci_bus, pci_dev_fun, - PCI_LATENCY_TIMER, 0x58); -#endif + + pci_set_master(pdev); + + printk(KERN_INFO "%s: Essential RoadRunner serial HIPPI " + "at 0x%08lx, irq %i, PCI latency %i\n", dev->name, + pdev->base_address[0], dev->irq, pci_latency); + /* * Remap the regs into kernel space. */ - rrpriv->regs = (struct rr_regs *)ioremap(tmp, 0x1000); + rrpriv->regs = (struct rr_regs *) + ioremap(pdev->base_address[0], 0x1000); + if (!rrpriv->regs){ - printk(KERN_ERR "%s: Unable to map I/O register, RoadRunner %i will be disabled.\n", dev->name, i); + printk(KERN_ERR "%s: Unable to map I/O register, " + "RoadRunner %i will be disabled.\n", + dev->name, boards_found); break; } @@ -198,7 +172,7 @@ __initfunc(int rr_hippi_probe (struct device *dev)) * Don't access any registes before this point! */ #ifdef __BIG_ENDIAN - regs->HostCtrl |= NO_SWAP; + writel(readl(®s->HostCtrl) | NO_SWAP, ®s->HostCtrl); #endif /* * Need to add a case for little-endian 64-bit hosts here. @@ -209,6 +183,7 @@ __initfunc(int rr_hippi_probe (struct device *dev)) boards_found++; dev->base_addr = 0; dev = NULL; + opdev = pdev; } /* @@ -217,12 +192,59 @@ __initfunc(int rr_hippi_probe (struct device *dev)) * 1 or more boards. Otherwise, return failure (-ENODEV). */ +#ifdef MODULE + return boards_found; +#else if (boards_found > 0) return 0; else return -ENODEV; +#endif } +static struct device *root_dev = NULL; + +#ifdef MODULE +#if LINUX_VERSION_CODE > 0x20118 +MODULE_AUTHOR("Jes Sorensen "); +MODULE_DESCRIPTION("Essential RoadRunner HIPPI driver"); +#endif + + +int init_module(void) +{ + int cards; + + root_dev = NULL; + + cards = rr_hippi_probe(NULL); + return cards ? 0 : -ENODEV; +} + +void cleanup_module(void) +{ + struct rr_private *rr; + struct device *next; + + while (root_dev) { + next = ((struct rr_private *)root_dev->priv)->next; + rr = (struct rr_private *)root_dev->priv; + + if (!(readl(&rr->regs->HostCtrl) & NIC_HALTED)){ + printk(KERN_ERR "%s: trying to unload running NIC\n", + root_dev->name); + writel(HALT_NIC, &rr->regs->HostCtrl); + } + + iounmap(rr->regs); + unregister_hipdev(root_dev); + kfree(root_dev); + + root_dev = next; + } +} +#endif + /* * Commands are considered to be slow, thus there is no reason to @@ -238,21 +260,25 @@ static void rr_issue_cmd(struct rr_private *rrpriv, struct cmd *cmd) * This is temporary - it will go away in the final version. * We probably also want to make this function inline. */ - if (regs->HostCtrl & NIC_HALTED){ - printk("issuing command for halted NIC, code 0x%x, HostCtrl %08x\n", cmd->code, regs->HostCtrl); - if (regs->Mode & FATAL_ERR) - printk("error code %02x\n", regs->Fail1); + if (readl(®s->HostCtrl) & NIC_HALTED){ + printk("issuing command for halted NIC, code 0x%x, " + "HostCtrl %08x\n", cmd->code, readl(®s->HostCtrl)); + if (readl(®s->Mode) & FATAL_ERR) + printk("error codes Fail1 %02x, Fail2 %02x\n", + readl(®s->Fail1), readl(®s->Fail2)); } idx = rrpriv->info->cmd_ctrl.pi; - regs->CmdRing[idx] = *(u32*)(cmd); + writel(*(u32*)(cmd), ®s->CmdRing[idx]); + mb(); idx = (idx - 1) % CMD_RING_ENTRIES; rrpriv->info->cmd_ctrl.pi = idx; + mb(); - if (regs->Mode & FATAL_ERR) - printk("error code %02x\n", regs->Fail1); + if (readl(®s->Mode) & FATAL_ERR) + printk("error code %02x\n", readl(®s->Fail1)); } @@ -273,85 +299,97 @@ static int rr_reset(struct device *dev) rr_load_firmware(dev); - regs->TX_state = 0x01000000; - regs->RX_state = 0xff800000; - regs->AssistState = 0; - regs->LocalCtrl = CLEAR_INTA; - regs->BrkPt = 0x01; - regs->Timer = 0; - regs->TimerRef = 0; - regs->DmaReadState = RESET_DMA; - regs->DmaWriteState = RESET_DMA; - regs->DmaWriteHostHi = 0; - regs->DmaWriteHostLo = 0; - regs->DmaReadHostHi = 0; - regs->DmaReadHostLo = 0; - regs->DmaReadLen = 0; - regs->DmaWriteLen = 0; - regs->DmaWriteLcl = 0; - regs->DmaWriteIPchecksum = 0; - regs->DmaReadLcl = 0; - regs->DmaReadIPchecksum = 0; - regs->PciState = 0; /* 0x90 for GE? */ - regs->Mode = SWAP_DATA; + writel(0x01000000, ®s->TX_state); + writel(0xff800000, ®s->RX_state); + writel(0, ®s->AssistState); + writel(CLEAR_INTA, ®s->LocalCtrl); + writel(0x01, ®s->BrkPt); + writel(0, ®s->Timer); + writel(0, ®s->TimerRef); + writel(RESET_DMA, ®s->DmaReadState); + writel(RESET_DMA, ®s->DmaWriteState); + writel(0, ®s->DmaWriteHostHi); + writel(0, ®s->DmaWriteHostLo); + writel(0, ®s->DmaReadHostHi); + writel(0, ®s->DmaReadHostLo); + writel(0, ®s->DmaReadLen); + writel(0, ®s->DmaWriteLen); + writel(0, ®s->DmaWriteLcl); + writel(0, ®s->DmaWriteIPchecksum); + writel(0, ®s->DmaReadLcl); + writel(0, ®s->DmaReadIPchecksum); + writel(0, ®s->PciState); +#if (BITS_PER_LONG == 64) && defined __LITTLE_ENDIAN + writel(SWAP_DATA | PTR64BIT | PTR_WD_SWAP, ®s->Mode); +#elif (BITS_PER_LONG == 64) + writel(SWAP_DATA | PTR64BIT | PTR_WD_NOSWAP, ®s->Mode); +#else + writel(SWAP_DATA | PTR32BIT | PTR_WD_NOSWAP, ®s->Mode); +#endif #if 0 /* * Don't worry, this is just black magic. */ - regs->RxBase = 0xdf000; - regs->RxPrd = 0xdf000; - regs->RxCon = 0xdf000; - regs->TxBase = 0xce000; - regs->TxPrd = 0xce000; - regs->TxCon = 0xce000; - regs->RxIndPro = 0; - regs->RxIndCon = 0; - regs->RxIndRef = 0; - regs->TxIndPro = 0; - regs->TxIndCon = 0; - regs->TxIndRef = 0; - regs->pad10[0] = 0xcc000; - regs->DrCmndPro = 0; - regs->DrCmndCon = 0; - regs->DwCmndPro = 0; - regs->DwCmndCon = 0; - regs->DwCmndRef = 0; - regs->DrDataPro = 0; - regs->DrDataCon = 0; - regs->DrDataRef = 0; - regs->DwDataPro = 0; - regs->DwDataCon = 0; - regs->DwDataRef = 0; + writel(0xdf000, ®s->RxBase); + writel(0xdf000, ®s->RxPrd); + writel(0xdf000, ®s->RxCon); + writel(0xce000, ®s->TxBase); + writel(0xce000, ®s->TxPrd); + writel(0xce000, ®s->TxCon); + writel(0, ®s->RxIndPro); + writel(0, ®s->RxIndCon); + writel(0, ®s->RxIndRef); + writel(0, ®s->TxIndPro); + writel(0, ®s->TxIndCon); + writel(0, ®s->TxIndRef); + writel(0xcc000, ®s->pad10[0]); + writel(0, ®s->DrCmndPro); + writel(0, ®s->DrCmndCon); + writel(0, ®s->DwCmndPro); + writel(0, ®s->DwCmndCon); + writel(0, ®s->DwCmndRef); + writel(0, ®s->DrDataPro); + writel(0, ®s->DrDataCon); + writel(0, ®s->DrDataRef); + writel(0, ®s->DwDataPro); + writel(0, ®s->DwDataCon); + writel(0, ®s->DwDataRef); #endif - regs->MbEvent = 0xffffffff; - regs->Event = 0; + writel(0xffffffff, ®s->MbEvent); + writel(0, ®s->Event); - regs->TxPi = 0; - regs->IpRxPi = 0; + writel(0, ®s->TxPi); + writel(0, ®s->IpRxPi); - regs->EvtCon = 0; - regs->EvtPrd = 0; + writel(0, ®s->EvtCon); + writel(0, ®s->EvtPrd); rrpriv->info->evt_ctrl.pi = 0; for (i = 0; i < CMD_RING_ENTRIES; i++) - regs->CmdRing[i] = 0; + writel(0, ®s->CmdRing[i]); - regs->PciState = 0; +/* + * Why 32 ? is this not cache line size dependant? + */ + writel(WBURST_32, ®s->PciState); + mb(); - start_pc = read_eeprom_word(rrpriv, &hw->rncd_info.FwStart); + start_pc = rr_read_eeprom_word(rrpriv, &hw->rncd_info.FwStart); #if (DEBUG > 1) printk("%s: Executing firmware at address 0x%06x\n", dev->name, start_pc); #endif - regs->Pc = start_pc + 0x800; + writel(start_pc + 0x800, ®s->Pc); + mb(); udelay(5); - regs->Pc = start_pc; + writel(start_pc, ®s->Pc); + mb(); return 0; } @@ -360,7 +398,7 @@ static int rr_reset(struct device *dev) /* * Read a string from the EEPROM. */ -static unsigned int read_eeprom(struct rr_private *rrpriv, +static unsigned int rr_read_eeprom(struct rr_private *rrpriv, unsigned long offset, unsigned char *buf, unsigned long length) @@ -368,22 +406,25 @@ static unsigned int read_eeprom(struct rr_private *rrpriv, struct rr_regs *regs = rrpriv->regs; u32 misc, io, host, i; - io = regs->ExtIo; - regs->ExtIo = 0; - misc = regs->LocalCtrl; - regs->LocalCtrl = 0; - host = regs->HostCtrl; - regs->HostCtrl |= HALT_NIC; + io = readl(®s->ExtIo); + writel(0, ®s->ExtIo); + misc = readl(®s->LocalCtrl); + writel(0, ®s->LocalCtrl); + host = readl(®s->HostCtrl); + writel(host | HALT_NIC, ®s->HostCtrl); + mb(); for (i = 0; i < length; i++){ - regs->WinBase = (EEPROM_BASE + ((offset+i) << 3)); - buf[i] = (regs->WinData >> 24) & 0xff; + writel((EEPROM_BASE + ((offset+i) << 3)), ®s->WinBase); + mb(); + buf[i] = (readl(®s->WinData) >> 24) & 0xff; + mb(); } - regs->HostCtrl = host; - regs->LocalCtrl = misc; - regs->ExtIo = io; - + writel(host, ®s->HostCtrl); + writel(misc, ®s->LocalCtrl); + writel(io, ®s->ExtIo); + mb(); return i; } @@ -392,13 +433,13 @@ static unsigned int read_eeprom(struct rr_private *rrpriv, * Shortcut to read one word (4 bytes) out of the EEPROM and convert * it to our CPU byte-order. */ -static u32 read_eeprom_word(struct rr_private *rrpriv, +static u32 rr_read_eeprom_word(struct rr_private *rrpriv, void * offset) { u32 word; - if ((read_eeprom(rrpriv, (unsigned long)offset, - (char *)&word, 4) == 4)) + if ((rr_read_eeprom(rrpriv, (unsigned long)offset, + (char *)&word, 4) == 4)) return be32_to_cpu(word); return 0; } @@ -410,38 +451,42 @@ static u32 read_eeprom_word(struct rr_private *rrpriv, * This is only called when the firmware is not running. */ static unsigned int write_eeprom(struct rr_private *rrpriv, - unsigned long offset, - unsigned char *buf, - unsigned long length) + unsigned long offset, + unsigned char *buf, + unsigned long length) { struct rr_regs *regs = rrpriv->regs; u32 misc, io, data, i, j, ready, error = 0; - io = regs->ExtIo; - regs->ExtIo = 0; - misc = regs->LocalCtrl; - regs->LocalCtrl = ENABLE_EEPROM_WRITE; + io = readl(®s->ExtIo); + writel(0, ®s->ExtIo); + misc = readl(®s->LocalCtrl); + writel(ENABLE_EEPROM_WRITE, ®s->LocalCtrl); + mb(); for (i = 0; i < length; i++){ - regs->WinBase = (EEPROM_BASE + ((offset+i) << 3)); + writel((EEPROM_BASE + ((offset+i) << 3)), ®s->WinBase); + mb(); data = buf[i] << 24; /* * Only try to write the data if it is not the same * value already. */ - if ((regs->WinData & 0xff000000) != data){ - regs->WinData = data; + if ((readl(®s->WinData) & 0xff000000) != data){ + writel(data, ®s->WinData); ready = 0; j = 0; mb(); while(!ready){ - udelay(1000); - if ((regs->WinData & 0xff000000) == data) + udelay(20); + if ((readl(®s->WinData) & 0xff000000) == + data) ready = 1; + mb(); if (j++ > 5000){ printk("data mismatch: %08x, " "WinData %08x\n", data, - regs->WinData); + readl(®s->WinData)); ready = 1; error = 1; } @@ -449,8 +494,9 @@ static unsigned int write_eeprom(struct rr_private *rrpriv, } } - regs->LocalCtrl = misc; - regs->ExtIo = io; + writel(misc, ®s->LocalCtrl); + writel(io, ®s->ExtIo); + mb(); return error; } @@ -465,7 +511,8 @@ __initfunc(static int rr_init(struct device *dev)) rrpriv = (struct rr_private *)dev->priv; regs = rrpriv->regs; - rev = regs->FwRev; + rev = readl(®s->FwRev); + rrpriv->fw_rev = rev; if (rev > 0x00020024) printk(" Firmware revision: %i.%i.%i\n", (rev >> 16), ((rev >> 8) & 0xff), (rev & 0xff)); @@ -477,13 +524,13 @@ __initfunc(static int rr_init(struct device *dev)) printk(" Firmware revision too old: %i.%i.%i, please " "upgrade to 2.0.37 or later.\n", (rev >> 16), ((rev >> 8) & 0xff), (rev & 0xff)); - return -EFAULT; - } - printk(" Maximum receive rings %i\n", regs->MaxRxRng); +#if (DEBUG > 2) + printk(" Maximum receive rings %i\n", readl(®s->MaxRxRng)); +#endif - sram_size = read_eeprom_word(rrpriv, (void *)8); + sram_size = rr_read_eeprom_word(rrpriv, (void *)8); printk(" SRAM size 0x%06x\n", sram_size); if (sysctl_rmem_max < 262144){ @@ -498,6 +545,9 @@ __initfunc(static int rr_init(struct device *dev)) sysctl_wmem_max = 262144; } + rrpriv->next = root_dev; + root_dev = dev; + return 0; } @@ -507,7 +557,7 @@ static int rr_init1(struct device *dev) struct rr_private *rrpriv; struct rr_regs *regs; u32 hostctrl; - unsigned long myjif, flags, tmp_ptr; + unsigned long myjif, flags; struct cmd cmd; short i; @@ -516,8 +566,9 @@ static int rr_init1(struct device *dev) spin_lock_irqsave(&rrpriv->lock, flags); - hostctrl = regs->HostCtrl; - regs->HostCtrl |= HALT_NIC; + hostctrl = readl(®s->HostCtrl); + writel(hostctrl | HALT_NIC | RR_CLEAR_INT, ®s->HostCtrl); + mb(); if (hostctrl & PARITY_ERR){ printk("%s: Parity error halting NIC - this is serious!\n", @@ -526,31 +577,14 @@ static int rr_init1(struct device *dev) return -EFAULT; } - - memset(rrpriv->rx_ctrl, 0, 256 * sizeof(struct ring_ctrl)); - memset(rrpriv->info, 0, sizeof(struct rr_info)); - - tmp_ptr = virt_to_bus((void *)rrpriv->rx_ctrl); -#if (BITS_PER_LONG == 64) - regs->RxRingHi = (tmp_ptr >> 32); -#else - regs->RxRingHi = 0; -#endif - regs->RxRingLo = ((tmp_ptr) & 0xffffffff); - - tmp_ptr = virt_to_bus((void *)rrpriv->info); -#if (BITS_PER_LONG == 64) - regs->InfoPtrHi = (tmp_ptr >> 32); -#else - regs->InfoPtrHi = 0; -#endif - regs->InfoPtrLo = ((tmp_ptr) & 0xffffffff); + set_rxaddr(regs, rrpriv->rx_ctrl); + set_infoaddr(regs, rrpriv->info); rrpriv->info->evt_ctrl.entry_size = sizeof(struct event); rrpriv->info->evt_ctrl.entries = EVT_RING_ENTRIES; rrpriv->info->evt_ctrl.mode = 0; rrpriv->info->evt_ctrl.pi = 0; - rrpriv->info->evt_ctrl.rngptr = virt_to_bus(rrpriv->evt_ring); + set_rraddr(&rrpriv->info->evt_ctrl.rngptr, rrpriv->evt_ring); rrpriv->info->cmd_ctrl.entry_size = sizeof(struct cmd); rrpriv->info->cmd_ctrl.entries = CMD_RING_ENTRIES; @@ -558,20 +592,19 @@ static int rr_init1(struct device *dev) rrpriv->info->cmd_ctrl.pi = 15; for (i = 0; i < CMD_RING_ENTRIES; i++) { - regs->CmdRing[i] = 0; + writel(0, ®s->CmdRing[i]); } for (i = 0; i < TX_RING_ENTRIES; i++) { rrpriv->tx_ring[i].size = 0; - rrpriv->tx_ring[i].addr = 0; + set_rraddr(&rrpriv->tx_ring[i].addr, 0); rrpriv->tx_skbuff[i] = 0; } - rrpriv->info->tx_ctrl.entry_size = sizeof(struct tx_desc); rrpriv->info->tx_ctrl.entries = TX_RING_ENTRIES; rrpriv->info->tx_ctrl.mode = 0; rrpriv->info->tx_ctrl.pi = 0; - rrpriv->info->tx_ctrl.rngptr = virt_to_bus(rrpriv->tx_ring); + set_rraddr(&rrpriv->info->tx_ctrl.rngptr, rrpriv->tx_ring); /* * Set dirty_tx before we start receiving interrupts, otherwise @@ -585,14 +618,20 @@ static int rr_init1(struct device *dev) rr_reset(dev); - regs->IntrTmr = 0x60; - regs->WriteDmaThresh = 0x80 | 0x1f; - regs->ReadDmaThresh = 0x80 | 0x1f; + writel(0x60, ®s->IntrTmr); + /* + * These seem to have no real effect as the Firmware sets + * it's own default values + */ + writel(0x10, ®s->WriteDmaThresh); + writel(0x20, ®s->ReadDmaThresh); rrpriv->fw_running = 0; + mb(); hostctrl &= ~(HALT_NIC | INVALID_INST_B | PARITY_ERR); - regs->HostCtrl = hostctrl; + writel(hostctrl, ®s->HostCtrl); + mb(); spin_unlock_irqrestore(&rrpriv->lock, flags); @@ -626,10 +665,7 @@ static int rr_init1(struct device *dev) if ((((unsigned long)skb->data) & 0xfff) > ~65320) printk("skb alloc error\n"); -#if (BITS_PER_LONG == 32) - rrpriv->rx_ring[i].zero = 0; -#endif - rrpriv->rx_ring[i].addr = virt_to_bus(skb->data); + set_rraddr(&rrpriv->rx_ring[i].addr, skb->data); rrpriv->rx_ring[i].size = dev->mtu + HIPPI_HLEN; } @@ -637,7 +673,8 @@ static int rr_init1(struct device *dev) rrpriv->rx_ctrl[4].entries = RX_RING_ENTRIES; rrpriv->rx_ctrl[4].mode = 8; rrpriv->rx_ctrl[4].pi = 0; - rrpriv->rx_ctrl[4].rngptr = virt_to_bus(rrpriv->rx_ring); + mb(); + set_rraddr(&rrpriv->rx_ctrl[4].rngptr, rrpriv->rx_ring); cmd.code = C_NEW_RNG; cmd.ring = 4; @@ -647,18 +684,15 @@ static int rr_init1(struct device *dev) #if 0 { u32 tmp; - tmp = regs->ExtIo; - regs->ExtIo = 0x80; + tmp = readl(®s->ExtIo); + writel(0x80, ®s->ExtIo); i = jiffies + 1 * HZ; while (jiffies < i); - regs->ExtIo = tmp; + writel(tmp, ®s->ExtIo); } #endif dev->tbusy = 0; -#if 0 - dev->interrupt = 0; -#endif dev->start = 1; return 0; } @@ -669,24 +703,24 @@ static int rr_init1(struct device *dev) * events) and are handled here, outside the main interrupt handler, * to reduce the size of the handler. */ -static u32 rr_handle_event(struct device *dev, u32 prodidx) +static u32 rr_handle_event(struct device *dev, u32 prodidx, u32 eidx) { struct rr_private *rrpriv; struct rr_regs *regs; - u32 tmp, eidx; + u32 tmp; rrpriv = (struct rr_private *)dev->priv; regs = rrpriv->regs; - eidx = rrpriv->info->evt_ctrl.pi; while (prodidx != eidx){ switch (rrpriv->evt_ring[eidx].code){ case E_NIC_UP: - tmp = regs->FwRev; + tmp = readl(®s->FwRev); printk("%s: Firmware revision %i.%i.%i up and running\n", dev->name, (tmp >> 16), ((tmp >> 8) & 0xff), (tmp & 0xff)); rrpriv->fw_running = 1; + mb(); break; case E_LINK_ON: printk("%s: Optical link ON\n", dev->name); @@ -729,7 +763,7 @@ static u32 rr_handle_event(struct device *dev, u32 prodidx) #if (DEBUG > 2) printk("%s: RX ring valid event\n", dev->name); #endif - regs->IpRxPi = RX_RING_ENTRIES - 1; + writel(RX_RING_ENTRIES - 1, ®s->IpRxPi); break; case E_INV_RNG: printk("%s: RX ring invalid event\n", dev->name); @@ -756,35 +790,24 @@ static u32 rr_handle_event(struct device *dev, u32 prodidx) } rrpriv->info->evt_ctrl.pi = eidx; + mb(); return eidx; } -static int rx_int(struct device *dev, u32 rxlimit) +static void rx_int(struct device *dev, u32 rxlimit, u32 index) { struct rr_private *rrpriv = (struct rr_private *)dev->priv; - u32 index, pkt_len; + u32 pkt_len; struct rr_regs *regs = rrpriv->regs; - index = rrpriv->cur_rx; - - while(index != rxlimit){ + do { pkt_len = rrpriv->rx_ring[index].size; #if (DEBUG > 2) printk("index %i, rxlimit %i\n", index, rxlimit); printk("len %x, mode %x\n", pkt_len, rrpriv->rx_ring[index].mode); #endif -#if 0 -/* - * I have never seen this occur - */ - if(!(rrpriv->rx_skbuff[index])){ - printk("Trying to receive in empty skbuff\n"); - goto out; - } -#endif - if (pkt_len > 0){ struct sk_buff *skb; @@ -808,7 +831,7 @@ static int rx_int(struct device *dev, u32 rxlimit) skb = rrpriv->rx_skbuff[index]; skb_put(skb, pkt_len); rrpriv->rx_skbuff[index] = newskb; - rrpriv->rx_ring[index].addr = virt_to_bus(newskb->data); + set_rraddr(&rrpriv->rx_ring[index].addr, newskb->data); }else{ printk("%s: Out of memory, deferring " "packet\n", dev->name); @@ -829,13 +852,13 @@ static int rx_int(struct device *dev, u32 rxlimit) rrpriv->rx_ring[index].size = dev->mtu + HIPPI_HLEN; if ((index & 7) == 7) - regs->IpRxPi = index; + writel(index, ®s->IpRxPi); index = (index + 1) % RX_RING_ENTRIES; - } + } while(index != rxlimit); rrpriv->cur_rx = index; - return index; + mb(); } @@ -844,25 +867,18 @@ static void rr_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) struct rr_private *rrpriv; struct rr_regs *regs; struct device *dev = (struct device *)dev_id; - u32 prodidx, eidx, txcsmr, rxlimit, txcon; + u32 prodidx, rxindex, eidx, txcsmr, rxlimit, txcon; unsigned long flags; rrpriv = (struct rr_private *)dev->priv; regs = rrpriv->regs; - if (!(regs->HostCtrl & RR_INT)) + if (!(readl(®s->HostCtrl) & RR_INT)) return; -#if 0 - if (test_and_set_bit(0, (void*)&dev->interrupt) != 0) { - printk("%s: Re-entering the interrupt handler.\n", dev->name); - return; - } -#endif - spin_lock_irqsave(&rrpriv->lock, flags); - prodidx = regs->EvtPrd; + prodidx = readl(®s->EvtPrd); txcsmr = (prodidx >> 8) & 0xff; rxlimit = (prodidx >> 16) & 0xff; prodidx &= 0xff; @@ -872,6 +888,10 @@ static void rr_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) prodidx, rrpriv->info->evt_ctrl.pi); #endif + rxindex = rrpriv->cur_rx; + if (rxindex != rxlimit) + rx_int(dev, rxlimit, rxindex); + txcon = rrpriv->dirty_tx; if (txcsmr != txcon) { do { @@ -881,11 +901,12 @@ static void rr_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) rrpriv->tx_skbuff[txcon] = NULL; rrpriv->tx_ring[txcon].size = 0; - rrpriv->tx_ring[txcon].addr = 0; + set_rraddr(&rrpriv->tx_ring[txcon].addr, 0); rrpriv->tx_ring[txcon].mode = 0; txcon = (txcon + 1) % TX_RING_ENTRIES; } while (txcsmr != txcon); + mb(); rrpriv->dirty_tx = txcon; if (rrpriv->tx_full && dev->tbusy && @@ -897,21 +918,15 @@ static void rr_interrupt(int irq, void *dev_id, struct pt_regs *ptregs) } } - rx_int(dev, rxlimit); - eidx = rrpriv->info->evt_ctrl.pi; - if (prodidx != eidx) - eidx = rr_handle_event(dev, prodidx); + eidx = rr_handle_event(dev, prodidx, eidx); eidx |= ((txcsmr << 8) | (rxlimit << 16)); - regs->EvtCon = eidx; + writel(eidx, ®s->EvtCon); + mb(); spin_unlock_irqrestore(&rrpriv->lock, flags); - -#if 0 - dev->interrupt = 0; -#endif } @@ -919,35 +934,64 @@ static int rr_open(struct device *dev) { struct rr_private *rrpriv; struct rr_regs *regs; + int ecode = 0; + unsigned long flags; rrpriv = (struct rr_private *)dev->priv; regs = rrpriv->regs; -#if 0 - regs->HostCtrl |= (HALT_NIC | RR_CLEAR_INT); -#endif + if (rrpriv->fw_rev < 0x00020000) { + printk(KERN_WARNING "%s: trying to configure device with " + "obsolete firmware\n", dev->name); + ecode = -EBUSY; + goto error; + } + + rrpriv->rx_ctrl = kmalloc(256*sizeof(struct ring_ctrl), + GFP_KERNEL | GFP_DMA); + if (!rrpriv->rx_ctrl) { + ecode = -ENOMEM; + goto error; + } + + rrpriv->info = kmalloc(sizeof(struct rr_info), GFP_KERNEL | GFP_DMA); + if (!rrpriv->info){ + kfree(rrpriv->rx_ctrl); + ecode = -ENOMEM; + goto error; + } + memset(rrpriv->rx_ctrl, 0, 256 * sizeof(struct ring_ctrl)); + memset(rrpriv->info, 0, sizeof(struct rr_info)); + mb(); + + spin_lock_irqsave(&rrpriv->lock, flags); + writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, ®s->HostCtrl); + spin_unlock_irqrestore(&rrpriv->lock, flags); if (request_irq(dev->irq, rr_interrupt, SA_SHIRQ, rrpriv->name, dev)) { printk(KERN_WARNING "%s: Requested IRQ %d is busy\n", dev->name, dev->irq); - return -EAGAIN; + ecode = -EAGAIN; + goto error; } - rrpriv->rx_ctrl = kmalloc(256*sizeof(struct ring_ctrl), - GFP_KERNEL | GFP_DMA); - rrpriv->info = kmalloc(sizeof(struct rr_info), GFP_KERNEL | GFP_DMA); - rr_init1(dev); dev->tbusy = 0; -#if 0 - dev->interrupt = 0; -#endif dev->start = 1; MOD_INC_USE_COUNT; return 0; + + error: + spin_lock_irqsave(&rrpriv->lock, flags); + writel(readl(®s->HostCtrl)|HALT_NIC|RR_CLEAR_INT, ®s->HostCtrl); + spin_unlock_irqrestore(&rrpriv->lock, flags); + + dev->tbusy = 1; + dev->start = 0; + return -ENOMEM; } @@ -965,12 +1009,13 @@ static void rr_dump(struct device *dev) printk("%s: dumping NIC TX rings\n", dev->name); printk("RxPrd %08x, TxPrd %02x, EvtPrd %08x, TxPi %02x, TxCtrlPi %02x\n", - regs->RxPrd, regs->TxPrd, regs->EvtPrd, regs->TxPi, + readl(®s->RxPrd), readl(®s->TxPrd), + readl(®s->EvtPrd), readl(®s->TxPi), rrpriv->info->tx_ctrl.pi); - printk("Error code 0x%x\n", regs->Fail1); + printk("Error code 0x%x\n", readl(®s->Fail1)); - index = (((regs->EvtPrd >> 8) & 0xff ) - 1) % EVT_RING_ENTRIES; + index = (((readl(®s->EvtPrd) >> 8) & 0xff ) - 1) % EVT_RING_ENTRIES; cons = rrpriv->dirty_tx; printk("TX ring index %i, TX consumer %i\n", index, cons); @@ -989,12 +1034,12 @@ static void rr_dump(struct device *dev) if (rrpriv->tx_skbuff[cons]){ len = min(0x80, rrpriv->tx_skbuff[cons]->len); printk("skbuff for cons %i is valid - dumping data (0x%x bytes - skbuff len 0x%x)\n", cons, len, rrpriv->tx_skbuff[cons]->len); - printk("mode 0x%x, size 0x%x,\n phys %08x (virt %08x), skbuff-addr %08x, truesize 0x%x\n", + printk("mode 0x%x, size 0x%x,\n phys %08x (virt %08lx), skbuff-addr %08lx, truesize 0x%x\n", rrpriv->tx_ring[cons].mode, rrpriv->tx_ring[cons].size, - rrpriv->tx_ring[cons].addr, - (unsigned int)bus_to_virt(rrpriv->tx_ring[cons].addr), - (unsigned int)rrpriv->tx_skbuff[cons]->data, + rrpriv->tx_ring[cons].addr.addrlo, + (unsigned long)bus_to_virt(rrpriv->tx_ring[cons].addr.addrlo), + (unsigned long)rrpriv->tx_skbuff[cons]->data, (unsigned int)rrpriv->tx_skbuff[cons]->truesize); for (i = 0; i < len; i++){ if (!(i & 7)) @@ -1009,7 +1054,7 @@ static void rr_dump(struct device *dev) printk("mode 0x%x, size 0x%x, phys-addr %08x\n", rrpriv->tx_ring[i].mode, rrpriv->tx_ring[i].size, - rrpriv->tx_ring[i].addr); + rrpriv->tx_ring[i].addr.addrlo); } @@ -1033,24 +1078,26 @@ static int rr_close(struct device *dev) */ spin_lock(&rrpriv->lock); - tmp = regs->HostCtrl; + tmp = readl(®s->HostCtrl); if (tmp & NIC_HALTED){ printk("%s: NIC already halted\n", dev->name); rr_dump(dev); - }else - tmp |= HALT_NIC; - regs->HostCtrl = tmp; + }else{ + tmp |= HALT_NIC | RR_CLEAR_INT; + writel(tmp, ®s->HostCtrl); + mb(); + } rrpriv->fw_running = 0; - regs->TxPi = 0; - regs->IpRxPi = 0; + writel(0, ®s->TxPi); + writel(0, ®s->IpRxPi); - regs->EvtCon = 0; - regs->EvtPrd = 0; + writel(0, ®s->EvtCon); + writel(0, ®s->EvtPrd); for (i = 0; i < CMD_RING_ENTRIES; i++) - regs->CmdRing[i] = 0; + writel(0, ®s->CmdRing[i]); rrpriv->info->tx_ctrl.entries = 0; rrpriv->info->cmd_ctrl.pi = 0; @@ -1060,7 +1107,7 @@ static int rr_close(struct device *dev) for (i = 0; i < TX_RING_ENTRIES; i++) { if (rrpriv->tx_skbuff[i]) { rrpriv->tx_ring[i].size = 0; - rrpriv->tx_ring[i].addr = 0; + set_rraddr(&rrpriv->tx_ring[i].addr, 0); dev_kfree_skb(rrpriv->tx_skbuff[i]); } } @@ -1068,7 +1115,7 @@ static int rr_close(struct device *dev) for (i = 0; i < RX_RING_ENTRIES; i++) { if (rrpriv->rx_skbuff[i]) { rrpriv->rx_ring[i].size = 0; - rrpriv->rx_ring[i].addr = 0; + set_rraddr(&rrpriv->rx_ring[i].addr, 0); dev_kfree_skb(rrpriv->rx_skbuff[i]); } } @@ -1094,6 +1141,10 @@ static int rr_start_xmit(struct sk_buff *skb, struct device *dev) u32 *ifield; struct sk_buff *new_skb; + if (readl(®s->Mode) & FATAL_ERR) + printk("error codes Fail1 %02x, Fail2 %02x\n", + readl(®s->Fail1), readl(®s->Fail2)); + /* * We probably need to deal with tbusy here to prevent overruns. */ @@ -1128,11 +1179,11 @@ static int rr_start_xmit(struct sk_buff *skb, struct device *dev) index = txctrl->pi; rrpriv->tx_skbuff[index] = skb; - rrpriv->tx_ring[index].addr = virt_to_bus(skb->data); + set_rraddr(&rrpriv->tx_ring[index].addr, skb->data); rrpriv->tx_ring[index].size = len + 8; /* include IFIELD */ rrpriv->tx_ring[index].mode = PACKET_START | PACKET_END; txctrl->pi = (index + 1) % TX_RING_ENTRIES; - regs->TxPi = txctrl->pi; + writel(txctrl->pi, ®s->TxPi); if (txctrl->pi == rrpriv->dirty_tx){ rrpriv->tx_full = 1; @@ -1167,8 +1218,9 @@ static int rr_load_firmware(struct device *dev) { struct rr_private *rrpriv; struct rr_regs *regs; + unsigned long eptr, segptr; int i, j; - u32 localctrl, eptr, sptr, segptr, len, tmp; + u32 localctrl, sptr, len, tmp; u32 p2len, p2size, nr_seg, revision, io, sram_size; struct eeprom *hw = NULL; @@ -1178,40 +1230,44 @@ static int rr_load_firmware(struct device *dev) if (dev->flags & IFF_UP) return -EBUSY; - if (!(regs->HostCtrl & NIC_HALTED)){ + if (!(readl(®s->HostCtrl) & NIC_HALTED)){ printk("%s: Trying to load firmware to a running NIC.\n", dev->name); return -EBUSY; } - localctrl = regs->LocalCtrl; - regs->LocalCtrl = 0; + localctrl = readl(®s->LocalCtrl); + writel(0, ®s->LocalCtrl); - regs->EvtPrd = 0; - regs->RxPrd = 0; - regs->TxPrd = 0; + writel(0, ®s->EvtPrd); + writel(0, ®s->RxPrd); + writel(0, ®s->TxPrd); /* * First wipe the entire SRAM, otherwise we might run into all * kinds of trouble ... sigh, this took almost all afternoon * to track down ;-( */ - io = regs->ExtIo; - regs->ExtIo = 0; - sram_size = read_eeprom_word(rrpriv, (void *)8); + io = readl(®s->ExtIo); + writel(0, ®s->ExtIo); + sram_size = rr_read_eeprom_word(rrpriv, (void *)8); for (i = 200; i < sram_size / 4; i++){ - regs->WinBase = i * 4; - regs->WinData = 0; + writel(i * 4, ®s->WinBase); + mb(); + writel(0, ®s->WinData); + mb(); } - regs->ExtIo = io; + writel(io, ®s->ExtIo); + mb(); - eptr = read_eeprom_word(rrpriv, &hw->rncd_info.AddrRunCodeSegs); + eptr = (unsigned long)rr_read_eeprom_word(rrpriv, + &hw->rncd_info.AddrRunCodeSegs); eptr = ((eptr & 0x1fffff) >> 3); - p2len = read_eeprom_word(rrpriv, (void *)(0x83*4)); + p2len = rr_read_eeprom_word(rrpriv, (void *)(0x83*4)); p2len = (p2len << 2); - p2size = read_eeprom_word(rrpriv, (void *)(0x84*4)); + p2size = rr_read_eeprom_word(rrpriv, (void *)(0x84*4)); p2size = ((p2size & 0x1fffff) >> 3); if ((eptr < p2size) || (eptr > (p2size + p2len))){ @@ -1219,7 +1275,7 @@ static int rr_load_firmware(struct device *dev) goto out; } - revision = read_eeprom_word(rrpriv, &hw->manf.HeaderFmt); + revision = rr_read_eeprom_word(rrpriv, &hw->manf.HeaderFmt); if (revision != 1){ printk("%s: invalid firmware format (%i)\n", @@ -1227,18 +1283,18 @@ static int rr_load_firmware(struct device *dev) goto out; } - nr_seg = read_eeprom_word(rrpriv, (void *)eptr); + nr_seg = rr_read_eeprom_word(rrpriv, (void *)eptr); eptr +=4; #if (DEBUG > 1) printk("%s: nr_seg %i\n", dev->name, nr_seg); #endif for (i = 0; i < nr_seg; i++){ - sptr = read_eeprom_word(rrpriv, (void *)eptr); + sptr = rr_read_eeprom_word(rrpriv, (void *)eptr); eptr += 4; - len = read_eeprom_word(rrpriv, (void *)eptr); + len = rr_read_eeprom_word(rrpriv, (void *)eptr); eptr += 4; - segptr = read_eeprom_word(rrpriv, (void *)eptr); + segptr = (unsigned long)rr_read_eeprom_word(rrpriv, (void *)eptr); segptr = ((segptr & 0x1fffff) >> 3); eptr += 4; #if (DEBUG > 1) @@ -1246,16 +1302,19 @@ static int rr_load_firmware(struct device *dev) dev->name, i, sptr, len, segptr); #endif for (j = 0; j < len; j++){ - tmp = read_eeprom_word(rrpriv, (void *)segptr); - regs->WinBase = sptr; - regs->WinData = tmp; + tmp = rr_read_eeprom_word(rrpriv, (void *)segptr); + writel(sptr, ®s->WinBase); + mb(); + writel(tmp, ®s->WinData); + mb(); segptr += 4; sptr += 4; } } out: - regs->LocalCtrl = localctrl; + writel(localctrl, ®s->LocalCtrl); + mb(); return 0; } @@ -1291,7 +1350,7 @@ static int rr_ioctl(struct device *dev, struct ifreq *rq, int cmd) error = -ENOMEM; goto out; } - i = read_eeprom(rrpriv, 0, image, EEPROM_BYTES); + i = rr_read_eeprom(rrpriv, 0, image, EEPROM_BYTES); if (i != EEPROM_BYTES){ kfree(image); printk(KERN_ERR "%s: Error reading EEPROM\n", @@ -1325,7 +1384,7 @@ static int rr_ioctl(struct device *dev, struct ifreq *rq, int cmd) } oldimage = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL); - if (!image){ + if (!oldimage){ printk(KERN_ERR "%s: Unable to allocate memory " "for old EEPROM image\n", dev->name); error = -ENOMEM; @@ -1343,7 +1402,7 @@ static int rr_ioctl(struct device *dev, struct ifreq *rq, int cmd) printk(KERN_ERR "%s: Error writing EEPROM\n", dev->name); - i = read_eeprom(rrpriv, 0, oldimage, EEPROM_BYTES); + i = rr_read_eeprom(rrpriv, 0, oldimage, EEPROM_BYTES); if (i != EEPROM_BYTES) printk(KERN_ERR "%s: Error reading back EEPROM " "image\n", dev->name); @@ -1354,7 +1413,6 @@ static int rr_ioctl(struct device *dev, struct ifreq *rq, int cmd) dev->name); error = -EFAULT; } - kfree(image); kfree(oldimage); break; @@ -1374,6 +1432,6 @@ static int rr_ioctl(struct device *dev, struct ifreq *rq, int cmd) /* * Local variables: - * compile-command: "gcc -D__SMP__ -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686 -c rrunner.c" + * compile-command: "gcc -D__SMP__ -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c" * End: */ diff --git a/drivers/net/rrunner.h b/drivers/net/rrunner.h index d475137007c9..e274efa3919e 100644 --- a/drivers/net/rrunner.h +++ b/drivers/net/rrunner.h @@ -278,7 +278,6 @@ struct rr_regs { #define TRACE_ON_WHAT_BIT 0x00020000 /* Traces on */ #define ONEM_BUF_WHAT_BIT 0x00040000 /* 1Meg vs 256K */ #define CHAR_API_WHAT_BIT 0x00080000 /* Char API vs network only */ -#define MS_DOS_WHAT_BIT 0x00100000 /* MS_DOS */ #define CMD_EVT_WHAT_BIT 0x00200000 /* Command event */ #define LONG_TX_WHAT_BIT 0x00400000 #define LONG_RX_WHAT_BIT 0x00800000 @@ -486,6 +485,63 @@ struct cmd { #define SAME_IFIELD 0x80 +typedef struct { +#if (BITS_PER_LONG == 64) + u64 addrlo; +#else + u32 addrhi; + u32 addrlo; +#endif +} rraddr; + + +static inline void set_rraddr(rraddr *ra, volatile void *addr) +{ + unsigned long baddr = virt_to_bus((void *)addr); +#if (BITS_PER_LONG == 64) + ra->addrlo = baddr; +#else + /* Don't bother setting zero every time */ + ra->addrlo = baddr; +#endif + mb(); +} + + +static inline void set_rxaddr(struct rr_regs *regs, volatile void *addr) +{ + unsigned long baddr = virt_to_bus((void *)addr); +#if (BITS_PER_LONG == 64) && defined(__LITTLE_ENDIAN) + writel(baddr & 0xffffffff, ®s->RxRingHi); + writel(baddr >> 32, ®s->RxRingLo); +#elif (BITS_PER_LONG == 64) + writel(baddr >> 32, ®s->RxRingHi); + writel(baddr & 0xffffffff, ®s->RxRingLo); +#else + writel(0, ®s->RxRingHi); + writel(baddr, ®s->RxRingLo); +#endif + mb(); +} + + +static inline void set_infoaddr(struct rr_regs *regs, volatile void *addr) +{ + unsigned long baddr = virt_to_bus((void *)addr); +#if (BITS_PER_LONG == 64) && defined(__LITTLE_ENDIAN) + writel(baddr & 0xffffffff, ®s->InfoPtrHi); + writel(baddr >> 32, ®s->InfoPtrLo); +#elif (BITS_PER_LONG == 64) + writel(baddr >> 32, ®s->InfoPtrHi); + writel(baddr & 0xffffffff, ®s->InfoPtrLo); +#else + writel(0, ®s->InfoPtrHi); + writel(baddr, ®s->InfoPtrLo); +#endif + mb(); +} + + /* * TX ring */ @@ -498,12 +554,7 @@ struct cmd { #define TX_RING_SIZE (TX_RING_ENTRIES * sizeof(struct tx_desc)) struct tx_desc{ -#if (BITS_PER_LONG == 64) - u64 addr; -#else - u32 zero; - u32 addr; -#endif + rraddr addr; u32 res; #ifdef __LITTLE_ENDIAN u16 size; @@ -525,12 +576,7 @@ struct tx_desc{ #define RX_RING_SIZE (RX_RING_ENTRIES * sizeof(struct rx_desc)) struct rx_desc{ -#if (BITS_PER_LONG == 64) - u64 addr; -#else - u32 zero; - u32 addr; -#endif + rraddr addr; u32 res; #ifdef __LITTLE_ENDIAN u16 size; @@ -714,12 +760,7 @@ struct rr_stats { * This struct is shared with the NIC firmware. */ struct ring_ctrl { -#if (BITS_PER_LONG == 64) - u64 rngptr; -#else - u32 zero; - u32 rngptr; -#endif + rraddr rngptr; #ifdef __LITTLE_ENDIAN u16 entries; u8 pad; @@ -759,19 +800,19 @@ struct rr_private struct rx_desc rx_ring[RX_RING_ENTRIES]; struct tx_desc tx_ring[TX_RING_ENTRIES]; struct event evt_ring[EVT_RING_ENTRIES]; - struct sk_buff *tx_skbuff[TX_RING_ENTRIES]; struct sk_buff *rx_skbuff[RX_RING_ENTRIES]; + struct sk_buff *tx_skbuff[TX_RING_ENTRIES]; struct rr_regs *regs; /* Register base */ struct ring_ctrl *rx_ctrl; /* Receive ring control */ struct rr_info *info; /* Shared info page */ + struct device *next; spinlock_t lock; struct timer_list timer; u32 cur_rx, cur_cmd, cur_evt; u32 dirty_rx, dirty_tx; u32 tx_full; + u32 fw_rev; short fw_running; - u8 pci_bus; /* PCI bus number */ - u8 pci_dev_fun; /* PCI device numbers */ char name[24]; /* The assigned name */ struct net_device_stats stats; }; @@ -789,5 +830,11 @@ static int rr_start_xmit(struct sk_buff *skb, struct device *dev); static int rr_close(struct device *dev); static struct net_device_stats *rr_get_stats(struct device *dev); static int rr_ioctl(struct device *dev, struct ifreq *rq, int cmd); +static unsigned int rr_read_eeprom(struct rr_private *rrpriv, + unsigned long offset, + unsigned char *buf, + unsigned long length); +static u32 rr_read_eeprom_word(struct rr_private *rrpriv, void * offset); +static int rr_load_firmware(struct device *dev); #endif /* _RRUNNER_H_ */ diff --git a/drivers/net/z85230.c b/drivers/net/z85230.c index 18cf1709f117..889a82d90e75 100644 --- a/drivers/net/z85230.c +++ b/drivers/net/z85230.c @@ -48,6 +48,7 @@ #include #include "z85230.h" +#include "syncppp.h" static spinlock_t z8530_buffer_lock = SPIN_LOCK_UNLOCKED; diff --git a/drivers/sbus/char/pcikbd.c b/drivers/sbus/char/pcikbd.c index 7c75b570cf5e..6e14d6d7c7d2 100644 --- a/drivers/sbus/char/pcikbd.c +++ b/drivers/sbus/char/pcikbd.c @@ -262,29 +262,22 @@ int do_acknowledge(unsigned char scancode) return 0; } } - if(scancode == 0) { - prev_scancode = 0; - return 0; - } return 1; } -int pcikbd_pretranslate(unsigned char scancode, char raw_mode) +int pcikbd_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode) { - if(scancode == 0xff) { - prev_scancode = 0; + static int prev_scancode = 0; + + if (scancode == 0xe0 || scancode == 0xe1) { + prev_scancode = scancode; return 0; } - if(scancode == 0xe0 || scancode == 0xe1) { - prev_scancode = scancode; + if (scancode == 0x00 || scancode == 0xff) { + prev_scancode = 0; return 0; } - return 1; -} - -int pcikbd_translate(unsigned char scancode, unsigned char *keycode, - char raw_mode) -{ if(prev_scancode) { if(prev_scancode != 0xe0) { if(prev_scancode == 0xe1 && scancode == 0x1d) { @@ -338,7 +331,7 @@ pcikbd_interrupt(int irq, void *dev_id, struct pt_regs *regs) break; scancode = pcikbd_inb(pcikbd_iobase + KBD_DATA_REG); if((status & KBD_STAT_OBF) && do_acknowledge(scancode)) - handle_scancode(scancode); + handle_scancode(scancode, !(scancode & 0x80)); status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG); } while(status & KBD_STAT_OBF); mark_bh(KEYBOARD_BH); diff --git a/drivers/usb/CREDITS b/drivers/usb/CREDITS new file mode 100644 index 000000000000..ea9e55018040 --- /dev/null +++ b/drivers/usb/CREDITS @@ -0,0 +1,23 @@ +Credits for the Simple Linux USB Driver: + +The following people have contributed to this code (in alphabetical +order by last name). I'm sure this list should be longer, its +difficult to maintain. + + Johannes Erdfelt + ham + Bradley M Keryan + Vojtech Pavlik + Gregory P. Smith + Linus Torvalds + + +Special thanks to: + + Inaky Perez Gonzalez for starting the + Linux USB driver effort and writing much of the larger uusbd driver. + Much has been learned from that effort. + + The NetBSD & FreeBSD USB developers. For being on the Linux USB list + and offering suggestions and sharing implementation experiences. + diff --git a/drivers/usb/Config.in b/drivers/usb/Config.in new file mode 100644 index 000000000000..b7955ad3041d --- /dev/null +++ b/drivers/usb/Config.in @@ -0,0 +1,25 @@ +# +# USB device configuration +# +# NOTE NOTE NOTE! This is still considered extremely experimental. +# Right now hubs, mice and keyboards work - at least with UHCI. +# But that may be more a lucky coincidence than anything else.. +# +# This was all developed modularly, but I've been lazy in cleaning +# it up, so right now they are all bools. +# +mainmenu_option next_comment +comment 'USB drivers - not for the faint of heart' + +if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'Support for USB (EXPERIMENTAL!)' CONFIG_USB + if [ "$CONFIG_USB" = "y" ]; then + bool 'UHCI (intel PIIX4 and others) support?' CONFIG_USB_UHCI + bool 'OHCI (compaq and some others) support?' CONFIG_USB_OHCI + + bool 'USB mouse support' CONFIG_USB_MOUSE + bool 'USB keyboard support' CONFIG_USB_KBD + fi +fi + +endmenu diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile new file mode 100644 index 000000000000..867560883c06 --- /dev/null +++ b/drivers/usb/Makefile @@ -0,0 +1,59 @@ +# +# Makefile for the kernel usb device drivers. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now inherited from the +# parent makes.. +# +# This isn't actually supported yet. Don't try to use it. + +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) + +L_TARGET := usb.a +M_OBJS := +L_OBJS := usb.o hub.o usb-debug.o +LX_OBJS := + +ifeq ($(CONFIG_USB_UHCI),y) + L_OBJS += uhci.o uhci-debug.o +else + ifeq ($(CONFIG_USB_UHCI),m) + MX_OBJS += usb-uhci.o uhci-debug.o + endif +endif + +ifeq ($(CONFIG_USB_OHCI),y) + L_OBJS += ohci.o ohci-debug.o +else + ifeq ($(CONFIG_USB_UHCI),m) + MX_OBJS += ohci.o ohci-debug.o + endif +endif + +ifeq ($(CONFIG_USB_MOUSE),y) + L_OBJS += mouse.o +else + ifeq ($(CONFIG_USB_UHCI),m) + MX_OBJS += mouse.o + endif +endif + +ifeq ($(CONFIG_USB_KBD),y) + L_OBJS += keyboard.o keymap.o +else + ifeq ($(CONFIG_USB_UHCI),m) + MX_OBJS += keyboard.o + endif +endif + +include $(TOPDIR)/Rules.make + +keymap.o: keymap.c + +keymap.c: maps/serial.map maps/usb.map maps/fixup.map + ./mkmap > $@ diff --git a/drivers/usb/README.kbd b/drivers/usb/README.kbd new file mode 100644 index 000000000000..84a77d90f044 --- /dev/null +++ b/drivers/usb/README.kbd @@ -0,0 +1,65 @@ +This is a simple USB keyboard driver written from Linus' +USB driver (started with Greg's usb-0.03b.tar.gz source +tree) + +It works fine with my BTC keyboard but I'm still investigating +trouble with my MS keyboard (trouble starts with an inability +to set into boot protocol mode, though, this very well could +be all due to crappy hardware). + +Anyway, I would appreciate you taking a look if you have +any USB keyboards lying around. Oh also, I'm doing this on +UHCI so sorry if it breaks with OHCI. + +-ham + + + +Keyboard patch +-------------- + +Instead of using the multiple keyboard patch and then running into all +of the kernel version problems that the current Linux-USB project has +had, I'm just mapping the USB keycodes to the standard AT-101 keycodes +and sending them directly to "handle_scancode". + +This may or may not be considered a hack. Anyway it is effective, and +I think safe, and allows USB keyboards to coexist with a serial +keyboard (oh yeah, one side effect is that you can for example hold +down the control key on the serial keyboard and press "a" on the USB +keyboard and you get Control-a like with Windows USB) and works +fine for console and X. + +You do need to make a *tiny* patch the kernel source tree so that the +function "handle_scancode" is exported from keyboard.c though. + + $ cd /usr/src/linux + $ patch -p0 < kbd.patch + +And, of course, then, you need to rebuild and install the kernel. + +** [Vojtech]: Alternately, just 'insmod kbd-stub', if you don't want +to use the keyboard and are too lazy to patch the kernel. + +Keyboard map +------------ + +I'm including a stupid utility "mkmap" which generates the USB->serial +keymap. It takes in maps/serial.map (the current serial keymap, +generated by "dumpkeys"), maps/usb.map (the USB keymap), and +maps/fixup.map (fixes for e0 keys and misc.) and spits out keymap.c +Anyway, it is not beautiful but should serve its purpose for the +moment. + +Other changes +------------- +uhci.c: + * added a context value to the irq callback function + (this is exactly like the "dev_id" field to request_irq) + * played with uhci_reset_port to get better hot-plug results + (eg. do a wait_ms(200) before calling uhci_reset_port) +usb.c: + * disconnect all devices after uhci-control thread is killed + * skip over the HID descriptor + * disconnect the high-level driver in usb_disconnect + diff --git a/drivers/usb/README.ohci b/drivers/usb/README.ohci new file mode 100644 index 000000000000..6a3744847669 --- /dev/null +++ b/drivers/usb/README.ohci @@ -0,0 +1,8 @@ +April 24, 1999 04:37:42 PST + +Okay, I've written a lot more of the OHCI code and actually got it back to +a compiling state now with all of the recent improvements to the way stuff +is structured. It is completely untested. + +- greg@electricrain.com + diff --git a/drivers/usb/hub.c b/drivers/usb/hub.c new file mode 100644 index 000000000000..6f0af0884ef3 --- /dev/null +++ b/drivers/usb/hub.c @@ -0,0 +1,409 @@ +/* + * USB hub driver. + * + * This is horrible, it knows about the UHCI driver + * internals, but it's just meant as a rough example, + * let's do the virtualization later when this works. + * + * (C) Copyright 1999 Linus Torvalds + * (C) Copyright 1999 Johannes Erdfelt + */ + +#include +#include +#include +#include +#include + +#include + +#include "usb.h" +#include "uhci.h" +#include "hub.h" + +extern struct usb_operations uhci_device_operations; + +/* Wakes up khubd */ +static struct wait_queue *usb_hub_wait = NULL; +static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED; + +/* List of hubs needing servicing */ +static struct list_head hub_event_list; + +/* + * A irq handler returns non-zero to indicate to + * the low-level driver that it wants to be re-activated, + * or zero to say "I'm done". + */ +static int hub_irq(int status, void *__buffer, void *dev_id) +{ + struct usb_hub *hub = dev_id; + unsigned long flags; + + if (waitqueue_active(&usb_hub_wait)) { + /* Add the hub to the event queue */ + spin_lock_irqsave(&hub_event_lock, flags); + if (hub->event_list.next == &hub->event_list) { + list_add(&hub->event_list, &hub_event_list); + /* Wake up khubd */ + wake_up(&usb_hub_wait); + } + spin_unlock_irqrestore(&hub_event_lock, flags); + } + + return 1; +} + +static void usb_hub_configure(struct usb_hub *hub) +{ + struct usb_device *dev = hub->dev; + unsigned char hubdescriptor[8], buf[4]; + int charac, i; + + usb_set_configuration(dev, dev->config[0].bConfigurationValue); + + if (usb_get_hub_descriptor(dev, hubdescriptor, 8)) + return; + + hub->nports = dev->maxchild = hubdescriptor[2]; + printk("hub: %d-port%s detected\n", hub->nports, + (hub->nports == 1) ? "" : "s"); + + charac = (hubdescriptor[4] << 8) + hubdescriptor[3]; + switch (charac & HUB_CHAR_LPSM) { + case 0x00: + printk("hub: ganged power switching\n"); + break; + case 0x01: + printk("hub: individual port power switching\n"); + break; + case 0x02: + case 0x03: + printk("hub: unknown reserved power switching mode\n"); + break; + } + + if (charac & HUB_CHAR_COMPOUND) + printk("hub: part of a compound device\n"); + else + printk("hub: standalone hub\n"); + + switch (charac & HUB_CHAR_OCPM) { + case 0x00: + printk("hub: global over current protection\n"); + break; + case 0x08: + printk("hub: individual port over current protection\n"); + break; + case 0x10: + case 0x18: + printk("hub: no over current protection\n"); + break; + } + + printk("hub: power on to power good time: %dms\n", + hubdescriptor[5] * 2); + + printk("hub: hub controller current requirement: %dmA\n", + hubdescriptor[6]); + + for (i = 0; i < dev->maxchild; i++) + printk("hub: port %d is%s removable\n", i + 1, + hubdescriptor[7 + ((i + 1)/8)] & (1 << ((i + 1) % 8)) + ? " not" : ""); + + if (usb_get_hub_status(dev, buf)) + return; + + printk("hub: local power source is %s\n", + (buf[0] & 1) ? "lost (inactive)" : "good"); + + printk("hub: %sover current condition exists\n", + (buf[0] & 2) ? "" : "no "); + +#if 0 + for (i = 0; i < hub->nports; i++) { + int portstat, portchange; + unsigned char portstatus[4]; + + if (usb_get_port_status(dev, i + 1, portstatus)) + return; + portstat = (portstatus[1] << 8) + portstatus[0]; + portchange = (portstatus[3] << 8) + portstatus[2]; + + printk("hub: port %d status\n", i + 1); + printk("hub: %sdevice present\n", (portstat & 1) ? "" : "no "); + printk("hub: %s\n", (portstat & 2) ? "enabled" : "disabled"); + printk("hub: %ssuspended\n", (portstat & 4) ? "" : "not "); + printk("hub: %sover current\n", (portstat & 8) ? "" : "not "); + printk("hub: has %spower\n", (portstat & 0x100) ? "" : "no "); + printk("hub: %s speed\n", (portstat & 0x200) ? "low" : "full"); + } +#endif + + /* Enable power to the ports */ + printk("enabling power on all ports\n"); + for (i = 0; i < hub->nports; i++) + usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER); +} + +static int hub_probe(struct usb_device *dev) +{ + struct usb_interface_descriptor *interface; + struct usb_endpoint_descriptor *endpoint; + struct usb_hub *hub; + + /* We don't handle multi-config hubs */ + if (dev->descriptor.bNumConfigurations != 1) + return -1; + + /* We don't handle multi-interface hubs */ + if (dev->config[0].bNumInterfaces != 1) + return -1; + + interface = &dev->config[0].interface[0]; + + /* Is it a hub? */ + if (interface->bInterfaceClass != 9) + return -1; + if (interface->bInterfaceSubClass != 0) + return -1; + + /* Multiple endpoints? What kind of mutant ninja-hub is this? */ + if (interface->bNumEndpoints != 1) + return -1; + + endpoint = &interface->endpoint[0]; + + /* Output endpoint? Curiousier and curiousier.. */ + if (!(endpoint->bEndpointAddress & 0x80)) + return -1; + + /* If it's not an interrupt endpoint, we'd better punt! */ + if ((endpoint->bmAttributes & 3) != 3) + return -1; + + /* We found a hub */ + printk("USB hub found\n"); + + if ((hub = kmalloc(sizeof(*hub), GFP_KERNEL)) == NULL) { + printk("couldn't kmalloc hub struct\n"); + return -1; + } + + memset(hub, 0, sizeof(*hub)); + + dev->private = hub; + + INIT_LIST_HEAD(&hub->event_list); + hub->dev = dev; + + usb_hub_configure(hub); + + usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), hub_irq, endpoint->bInterval, hub); + + /* Wake up khubd */ + wake_up(&usb_hub_wait); + + return 0; +} + +static void hub_disconnect(struct usb_device *dev) +{ + struct usb_hub *hub = dev->private; + unsigned long flags; + + spin_lock_irqsave(&hub_event_lock, flags); + + /* Delete it and then reset it */ + list_del(&hub->event_list); + INIT_LIST_HEAD(&hub->event_list); + + spin_unlock_irqrestore(&hub_event_lock, flags); + + /* Free the memory */ + kfree(hub); +} + +static void usb_hub_port_connect_change(struct usb_device *hub, int port) +{ + struct usb_device *usb; + unsigned char buf[4]; + unsigned short portstatus, portchange; + + usb_disconnect(&hub->children[port]); + + usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET); + + wait_ms(50); /* FIXME: This is from the *BSD stack, thanks! :) */ + + if (usb_get_port_status(hub, port + 1, buf)) { + printk("get_port_status failed\n"); + return; + } + + portstatus = *((unsigned short *)buf + 0); + portchange = *((unsigned short *)buf + 1); + + if ((!(portstatus & USB_PORT_STAT_CONNECTION)) && + (!(portstatus & USB_PORT_STAT_ENABLE))) { + /* We're done now, we already disconnected the device */ + /* printk("not connected/enabled\n"); */ + return; + } + + usb = hub->bus->op->allocate(hub); + if (!usb) { + printk("couldn't allocate usb_device\n"); + return; + } + + usb_connect(usb); + + usb->slow = (portstatus & USB_PORT_STAT_LOW_SPEED) ? 1 : 0; + + hub->children[port] = usb; + + usb_new_device(usb); +} + +static void usb_hub_events(void) +{ + unsigned long flags; + unsigned char buf[4]; + unsigned short portstatus, portchange; + int i; + struct list_head *next, *tmp, *head = &hub_event_list; + struct usb_device *dev; + struct usb_hub *hub; + + spin_lock_irqsave(&hub_event_lock, flags); + + tmp = head->next; + while (tmp != head) { + hub = list_entry(tmp, struct usb_hub, event_list); + dev = hub->dev; + + next = tmp->next; + + list_del(tmp); + INIT_LIST_HEAD(tmp); + + for (i = 0; i < hub->nports; i++) { + if (usb_get_port_status(dev, i + 1, buf)) { + printk("get_port_status failed\n"); + continue; + } + + portstatus = *((unsigned short *)buf + 0); + portchange = *((unsigned short *)buf + 1); + + if (portchange & USB_PORT_STAT_C_CONNECTION) { + printk("hub: port %d connection change\n", i + 1); + + usb_clear_port_feature(dev, i + 1, + USB_PORT_FEAT_C_CONNECTION); + + usb_hub_port_connect_change(dev, i); + } + + if (portchange & USB_PORT_STAT_C_ENABLE) { + printk("hub: port %d enable change\n", i + 1); + usb_clear_port_feature(dev, i + 1, + USB_PORT_FEAT_C_ENABLE); + } + + if (portchange & USB_PORT_STAT_C_SUSPEND) + printk("hub: port %d suspend change\n", i + 1); + + if (portchange & USB_PORT_STAT_C_OVERCURRENT) + printk("hub: port %d over-current change\n", i + 1); + + if (portchange & USB_PORT_STAT_C_RESET) { + printk("hub: port %d reset change\n", i + 1); + usb_clear_port_feature(dev, i + 1, + USB_PORT_FEAT_C_RESET); + } + +#if 0 + if (!portchange) + continue; + + if (usb_get_port_status(dev, i + 1, buf)) + return; + + portstatus = (buf[1] << 8) + buf[0]; + portchange = (buf[3] << 8) + buf[2]; + + printk("hub: port %d status\n", i + 1); + printk("hub: %sdevice present\n", (portstatus & 1) ? "" : "no "); + printk("hub: %s\n", (portstatus & 2) ? "enabled" : "disabled"); + printk("hub: %ssuspended\n", (portstatus & 4) ? "" : "not "); + printk("hub: %sover current\n", (portstatus & 8) ? "" : "not "); + printk("hub: has %spower\n", (portstatus & 0x100) ? "" : "no "); + printk("hub: %s speed\n", (portstatus & 0x200) ? "low" : "full"); +#endif + } + tmp = next; +#if 0 + wait_ms(1000); +#endif + } + + spin_unlock_irqrestore(&hub_event_lock, flags); +} + +static int usb_hub_thread(void *__hub) +{ + lock_kernel(); + + /* + * This thread doesn't need any user-level access, + * so get rid of all our resources + */ + printk("usb_hub_thread at %p\n", &usb_hub_thread); + exit_mm(current); + exit_files(current); + exit_fs(current); + + /* Setup a nice name */ + strcpy(current->comm, "khubd"); + + /* Send me a signal to get me die (for debugging) */ + do { + interruptible_sleep_on(&usb_hub_wait); + usb_hub_events(); + } while (!signal_pending(current)); + + printk("usb_hub_thread exiting\n"); + + return 0; +} + +static struct usb_driver hub_driver = { + "hub", + hub_probe, + hub_disconnect, + { NULL, NULL } +}; + +/* + * This should be a separate module. + */ +int hub_init(void) +{ + int pid; + + INIT_LIST_HEAD(&hub_event_list); + + usb_register(&hub_driver); + pid = kernel_thread(usb_hub_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + if (pid >= 0) + return 0; + + /* Fall through if kernel_thread failed */ + usb_deregister(&hub_driver); + + return 0; +} + diff --git a/drivers/usb/hub.h b/drivers/usb/hub.h new file mode 100644 index 000000000000..d015c5a33063 --- /dev/null +++ b/drivers/usb/hub.h @@ -0,0 +1,80 @@ +#ifndef __LINUX_HUB_H +#define __LINUX_HUB_H + +#include + +/* + * Hub feature numbers + */ +#define C_HUB_LOCAL_POWER 0 +#define C_HUB_OVER_CURRENT 1 + +/* + * Port feature numbers + */ +#define USB_PORT_FEAT_ENABLE 1 +#define USB_PORT_FEAT_SUSPEND 2 +#define USB_PORT_FEAT_OVER_CURRENT 3 +#define USB_PORT_FEAT_RESET 4 +#define USB_PORT_FEAT_POWER 8 +#define USB_PORT_FEAT_LOWSPEED 9 +#define USB_PORT_FEAT_C_CONNECTION 16 +#define USB_PORT_FEAT_C_ENABLE 17 +#define USB_PORT_FEAT_C_SUSPEND 18 +#define USB_PORT_FEAT_C_OVER_CURRENT 19 +#define USB_PORT_FEAT_C_RESET 20 + +/* wPortStatus */ +#define USB_PORT_STAT_CONNECTION 0x0001 +#define USB_PORT_STAT_ENABLE 0x0002 +#define USB_PORT_STAT_SUSPEND 0x0004 +#define USB_PORT_STAT_OVERCURRENT 0x0008 +#define USB_PORT_STAT_RESET 0x0010 +#define USB_PORT_STAT_POWER 0x0100 +#define USB_PORT_STAT_LOW_SPEED 0x0200 + +/* wPortChange */ +#define USB_PORT_STAT_C_CONNECTION 0x0001 +#define USB_PORT_STAT_C_ENABLE 0x0002 +#define USB_PORT_STAT_C_SUSPEND 0x0004 +#define USB_PORT_STAT_C_OVERCURRENT 0x0008 +#define USB_PORT_STAT_C_RESET 0x0010 + +/* Characteristics */ +#define HUB_CHAR_LPSM 0x0003 +#define HUB_CHAR_COMPOUND 0x0004 +#define HUB_CHAR_OCPM 0x0018 + +struct usb_device; + +typedef enum { + USB_PORT_UNPOWERED = 0, /* Default state */ + USB_PORT_POWERED, /* When we've put power to it */ + USB_PORT_ENABLED, /* When it's been enabled */ + USB_PORT_DISABLED, /* If it's been disabled */ + USB_PORT_ADMINDISABLED, /* Forced down */ +} usb_hub_port_state; + +struct usb_hub_port { + usb_hub_port_state cstate; /* Configuration state */ + + struct usb_device *child; /* Device attached to this port */ + + struct usb_hub *parent; /* Parent hub */ +}; + +struct usb_hub { + /* Device structure */ + struct usb_device *dev; + + /* Temporary event list */ + struct list_head event_list; + + /* Number of ports on the hub */ + int nports; + + struct usb_hub_port ports[0]; /* Dynamically allocated */ +}; + +#endif + diff --git a/drivers/usb/inits.h b/drivers/usb/inits.h new file mode 100644 index 000000000000..d59848615b36 --- /dev/null +++ b/drivers/usb/inits.h @@ -0,0 +1,3 @@ +int bp_mouse_init(void); +int usb_kbd_init(void); +int hub_init(void); diff --git a/drivers/usb/keyboard.c b/drivers/usb/keyboard.c new file mode 100644 index 000000000000..c60c812a587e --- /dev/null +++ b/drivers/usb/keyboard.c @@ -0,0 +1,226 @@ +#include +#include +#include +#include +#include +#include +#include "usb.h" + +#define PCKBD_PRESSED 0x00 +#define PCKBD_RELEASED 0x80 +#define PCKBD_NEEDS_E0 0x80 + +#define USBKBD_MODIFIER_BASE 120 +#define USBKBD_KEYCODE_OFFSET 2 +#define USBKBD_KEYCODE_COUNT 6 + +#define USBKBD_VALID_KEYCODE(key) ((unsigned char)(key) > 3) +#define USBKBD_FIND_KEYCODE(down, key, count) \ + ((unsigned char*) memscan((down), (key), (count)) < ((down) + (count))) + +#define USBKBD_REPEAT_DELAY (HZ / 4) +#define USBKBD_REPEAT_RATE (HZ / 20) + +struct usb_keyboard +{ + struct usb_device *dev; + unsigned long down[2]; + unsigned char repeat_key; + struct timer_list repeat_timer; + struct list_head list; +}; + +extern unsigned char usb_kbd_map[]; + +static int usb_kbd_probe(struct usb_device *dev); +static void usb_kbd_disconnect(struct usb_device *dev); +static void usb_kbd_repeat(unsigned long dummy); + +static LIST_HEAD(usb_kbd_list); + +static struct usb_driver usb_kbd_driver = +{ + "keyboard", + usb_kbd_probe, + usb_kbd_disconnect, + {NULL, NULL} +}; + + +static void +usb_kbd_handle_key(unsigned char key, int down) +{ + int scancode = (int) usb_kbd_map[key]; + if(scancode) + { + if(scancode & PCKBD_NEEDS_E0) + { + handle_scancode(0xe0, 1); + } + handle_scancode((scancode & ~PCKBD_NEEDS_E0), down); + } +} + +static void +usb_kbd_repeat(unsigned long dev_id) +{ + struct usb_keyboard *kbd = (struct usb_keyboard*) dev_id; + + unsigned long flags; + save_flags(flags); + cli(); + + if(kbd->repeat_key) + { + usb_kbd_handle_key(kbd->repeat_key, 1); + + /* reset repeat timer */ + kbd->repeat_timer.function = usb_kbd_repeat; + kbd->repeat_timer.expires = jiffies + USBKBD_REPEAT_RATE; + kbd->repeat_timer.data = (unsigned long) kbd; + kbd->repeat_timer.prev = NULL; + kbd->repeat_timer.next = NULL; + add_timer(&kbd->repeat_timer); + } + + restore_flags(flags); +} + +static int +usb_kbd_irq(int state, void *buffer, void *dev_id) +{ + struct usb_keyboard *kbd = (struct usb_keyboard*) dev_id; + unsigned long *down = (unsigned long*) buffer; + + if(kbd->down[0] != down[0] || kbd->down[1] != down[1]) + { + unsigned char *olddown, *newdown; + unsigned char modsdelta, key; + int i; + + /* handle modifier change */ + modsdelta = (*(unsigned char*) down ^ *(unsigned char*) kbd->down); + if(modsdelta) + { + for(i = 0; i < 8; i++) + { + if(modsdelta & 0x01) + { + int pressed = (*(unsigned char*) down >> i) & 0x01; + usb_kbd_handle_key( + i + USBKBD_MODIFIER_BASE, + pressed); + } + modsdelta >>= 1; + } + } + + olddown = (unsigned char*) kbd->down + USBKBD_KEYCODE_OFFSET; + newdown = (unsigned char*) down + USBKBD_KEYCODE_OFFSET; + + /* handle released keys */ + for(i = 0; i < USBKBD_KEYCODE_COUNT; i++) + { + key = olddown[i]; + if(USBKBD_VALID_KEYCODE(key) + && !USBKBD_FIND_KEYCODE(newdown, key, USBKBD_KEYCODE_COUNT)) + { + usb_kbd_handle_key(key, 0); + } + } + + /* handle pressed keys */ + kbd->repeat_key = 0; + for(i = 0; i < USBKBD_KEYCODE_COUNT; i++) + { + key = newdown[i]; + if(USBKBD_VALID_KEYCODE(key) + && !USBKBD_FIND_KEYCODE(olddown, key, USBKBD_KEYCODE_COUNT)) + { + usb_kbd_handle_key(key, 1); + kbd->repeat_key = key; + } + } + + /* set repeat timer if any keys were pressed */ + if(kbd->repeat_key) + { + del_timer(&kbd->repeat_timer); + kbd->repeat_timer.function = usb_kbd_repeat; + kbd->repeat_timer.expires = jiffies + USBKBD_REPEAT_DELAY; + kbd->repeat_timer.data = (unsigned long) kbd; + kbd->repeat_timer.prev = NULL; + kbd->repeat_timer.next = NULL; + add_timer(&kbd->repeat_timer); + } + + kbd->down[0] = down[0]; + kbd->down[1] = down[1]; + } + + return 1; +} + +static int +usb_kbd_probe(struct usb_device *dev) +{ + struct usb_interface_descriptor *interface; + struct usb_endpoint_descriptor *endpoint; + struct usb_keyboard *kbd; + + interface = &dev->config[0].interface[0]; + endpoint = &interface->endpoint[0]; + + if(interface->bInterfaceClass != 3 + || interface->bInterfaceSubClass != 1 + || interface->bInterfaceProtocol != 1) + { + return -1; + } + + printk(KERN_INFO "USB HID boot protocol keyboard detected.\n"); + + kbd = kmalloc(sizeof(struct usb_keyboard), GFP_KERNEL); + if(kbd) + { + memset(kbd, 0, sizeof(*kbd)); + kbd->dev = dev; + dev->private = kbd; + + usb_set_configuration(dev, dev->config[0].bConfigurationValue); + usb_set_protocol(dev, 0); + usb_set_idle(dev, 0, 0); + + usb_request_irq(dev, + usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), + usb_kbd_irq, + endpoint->bInterval, + kbd); + + list_add(&kbd->list, &usb_kbd_list); + } + + return 0; +} + +static void +usb_kbd_disconnect(struct usb_device *dev) +{ + struct usb_keyboard *kbd = (struct usb_keyboard*) dev->private; + if(kbd) + { + dev->private = NULL; + list_del(&kbd->list); + del_timer(&kbd->repeat_timer); + kfree(kbd); + } + + printk(KERN_INFO "USB HID boot protocol keyboard removed.\n"); +} + +int +usb_kbd_init(void) +{ + usb_register(&usb_kbd_driver); + return 0; +} diff --git a/drivers/usb/keymap.c b/drivers/usb/keymap.c new file mode 100644 index 000000000000..16c7b28f3b5e --- /dev/null +++ b/drivers/usb/keymap.c @@ -0,0 +1,50 @@ +unsigned char usb_kbd_map[256] = +{ + 0x00, 0x00, 0x00, 0x00, 0x1e, 0x30, 0x2e, 0x20, + 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, + + 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, + 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x02, 0x03, + + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x1c, 0x01, 0xd3, 0x0f, 0x39, 0x0c, 0x0d, 0x1a, + + 0x1b, 0x2b, 0x00, 0x27, 0x28, 0x29, 0x33, 0x34, + 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, + + 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0xb7, 0x46, + 0x00, 0xd2, 0xc7, 0xc9, 0x63, 0xcf, 0xd1, 0xcd, + + 0xcb, 0xd0, 0xc8, 0x45, 0xb5, 0x37, 0x4a, 0x4e, + 0x9c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, + + 0x48, 0x49, 0x52, 0x53, 0x00, 0x6d, 0x00, 0x00, + 0xbd, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1d, 0x2a, 0x38, 0xdb, 0x9d, 0x36, 0xb8, 0xdc, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; diff --git a/drivers/usb/maps/fixup.map b/drivers/usb/maps/fixup.map new file mode 100644 index 000000000000..fc5d1ed7f227 --- /dev/null +++ b/drivers/usb/maps/fixup.map @@ -0,0 +1,31 @@ +# misc fixes +keycode 0 = Pause +keycode 29 = Control +keycode 99 = Remove +keycode 42 = Shift +keycode 54 = Shift_R +keycode 109 = Application + +# E0 keys (or'ed with 0x80) +keycode 156 = KP_Enter +keycode 157 = Control_R +keycode 181 = KP_Divide +keycode 183 = Print_Screen +keycode 184 = Alt_R +keycode 189 = F13 +keycode 190 = F14 +keycode 193 = F17 +keycode 198 = Break +keycode 199 = Home +keycode 200 = Up +keycode 201 = Prior +keycode 203 = Left +keycode 205 = Right +keycode 207 = End +keycode 208 = Down +keycode 209 = Next +keycode 210 = Insert +keycode 211 = Delete +keycode 219 = Window +keycode 220 = Window_R +keycode 221 = Menu diff --git a/drivers/usb/maps/serial.map b/drivers/usb/maps/serial.map new file mode 100644 index 000000000000..e421a0d23814 --- /dev/null +++ b/drivers/usb/maps/serial.map @@ -0,0 +1,370 @@ +keymaps 0-2,4-6,8-9,12 +keycode 1 = Escape + alt keycode 1 = Meta_Escape + shift alt keycode 1 = Meta_Escape + control alt keycode 1 = Meta_Escape +keycode 2 = one exclam + alt keycode 2 = Meta_one + shift alt keycode 2 = Meta_exclam +keycode 3 = two at at nul nul + alt keycode 3 = Meta_two + shift alt keycode 3 = Meta_at + control alt keycode 3 = Meta_nul +keycode 4 = three numbersign + control keycode 4 = Escape + alt keycode 4 = Meta_three + shift alt keycode 4 = Meta_numbersign +keycode 5 = four dollar dollar Control_backslash + alt keycode 5 = Meta_four + shift alt keycode 5 = Meta_dollar + control alt keycode 5 = Meta_Control_backslash +keycode 6 = five percent + control keycode 6 = Control_bracketright + alt keycode 6 = Meta_five + shift alt keycode 6 = Meta_percent +keycode 7 = six asciicircum + control keycode 7 = Control_asciicircum + alt keycode 7 = Meta_six + shift alt keycode 7 = Meta_asciicircum +keycode 8 = seven ampersand braceleft Control_underscore + alt keycode 8 = Meta_seven + shift alt keycode 8 = Meta_ampersand + control alt keycode 8 = Meta_Control_underscore +keycode 9 = eight asterisk bracketleft Delete + alt keycode 9 = Meta_eight + shift alt keycode 9 = Meta_asterisk + control alt keycode 9 = Meta_Delete +keycode 10 = nine parenleft bracketright + alt keycode 10 = Meta_nine + shift alt keycode 10 = Meta_parenleft +keycode 11 = zero parenright braceright + alt keycode 11 = Meta_zero + shift alt keycode 11 = Meta_parenright +keycode 12 = minus underscore backslash Control_underscore Control_underscore + alt keycode 12 = Meta_minus + shift alt keycode 12 = Meta_underscore + control alt keycode 12 = Meta_Control_underscore +keycode 13 = equal plus + alt keycode 13 = Meta_equal + shift alt keycode 13 = Meta_plus +keycode 14 = Delete + alt keycode 14 = Meta_Delete + shift alt keycode 14 = Meta_Delete + control alt keycode 14 = Meta_Delete +keycode 15 = Tab + alt keycode 15 = Meta_Tab + shift alt keycode 15 = Meta_Tab + control alt keycode 15 = Meta_Tab +keycode 16 = q +keycode 17 = w +keycode 18 = e +keycode 19 = r +keycode 20 = t +keycode 21 = y +keycode 22 = u +keycode 23 = i +keycode 24 = o +keycode 25 = p +keycode 26 = bracketleft braceleft + control keycode 26 = Escape + alt keycode 26 = Meta_bracketleft + shift alt keycode 26 = Meta_braceleft +keycode 27 = bracketright braceright asciitilde Control_bracketright + alt keycode 27 = Meta_bracketright + shift alt keycode 27 = Meta_braceright + control alt keycode 27 = Meta_Control_bracketright +keycode 28 = Return + alt keycode 28 = Meta_Control_m +keycode 29 = Control +keycode 30 = a +keycode 31 = s +keycode 32 = d +keycode 33 = f +keycode 34 = g +keycode 35 = h +keycode 36 = j +keycode 37 = k +keycode 38 = l +keycode 39 = semicolon colon + alt keycode 39 = Meta_semicolon + shift alt keycode 39 = Meta_colon +keycode 40 = apostrophe quotedbl + control keycode 40 = Control_g + alt keycode 40 = Meta_apostrophe + shift alt keycode 40 = Meta_quotedbl +keycode 41 = grave asciitilde + control keycode 41 = nul + alt keycode 41 = Meta_grave + shift alt keycode 41 = Meta_asciitilde +keycode 42 = Shift +keycode 43 = backslash bar + control keycode 43 = Control_backslash + alt keycode 43 = Meta_backslash + shift alt keycode 43 = Meta_bar +keycode 44 = z +keycode 45 = x +keycode 46 = c +keycode 47 = v +keycode 48 = b +keycode 49 = n +keycode 50 = m +keycode 51 = comma less + alt keycode 51 = Meta_comma + shift alt keycode 51 = Meta_less +keycode 52 = period greater + alt keycode 52 = Meta_period + shift alt keycode 52 = Meta_greater +keycode 53 = slash question + control keycode 53 = Delete + alt keycode 53 = Meta_slash + shift alt keycode 53 = Meta_question +keycode 54 = Shift +keycode 55 = KP_Multiply + altgr keycode 55 = Hex_C +keycode 56 = Alt +keycode 57 = space + control keycode 57 = nul + alt keycode 57 = Meta_space + shift alt keycode 57 = Meta_space + control alt keycode 57 = Meta_nul +keycode 58 = Caps_Lock +keycode 59 = F1 F13 Console_13 F25 + alt keycode 59 = Console_1 + control alt keycode 59 = Console_1 +keycode 60 = F2 F14 Console_14 F26 + alt keycode 60 = Console_2 + control alt keycode 60 = Console_2 +keycode 61 = F3 F15 Console_15 F27 + alt keycode 61 = Console_3 + control alt keycode 61 = Console_3 +keycode 62 = F4 F16 Console_16 F28 + alt keycode 62 = Console_4 + control alt keycode 62 = Console_4 +keycode 63 = F5 F17 Console_17 F29 + alt keycode 63 = Console_5 + control alt keycode 63 = Console_5 +keycode 64 = F6 F18 Console_18 F30 + alt keycode 64 = Console_6 + control alt keycode 64 = Console_6 +keycode 65 = F7 F19 Console_19 F31 + alt keycode 65 = Console_7 + control alt keycode 65 = Console_7 +keycode 66 = F8 F20 Console_20 F32 + alt keycode 66 = Console_8 + control alt keycode 66 = Console_8 +keycode 67 = F9 F21 Console_21 F33 + alt keycode 67 = Console_9 + control alt keycode 67 = Console_9 +keycode 68 = F10 F22 Console_22 F34 + alt keycode 68 = Console_10 + control alt keycode 68 = Console_10 +keycode 69 = Num_Lock + altgr keycode 69 = Hex_E +keycode 70 = Scroll_Lock Show_Memory Show_Registers Show_State + alt keycode 70 = Scroll_Lock +keycode 71 = KP_7 + altgr keycode 71 = Hex_7 + alt keycode 71 = Ascii_7 +keycode 72 = KP_8 + altgr keycode 72 = Hex_8 + alt keycode 72 = Ascii_8 +keycode 73 = KP_9 + altgr keycode 73 = Hex_9 + alt keycode 73 = Ascii_9 +keycode 74 = KP_Subtract +keycode 75 = KP_4 + altgr keycode 75 = Hex_4 + alt keycode 75 = Ascii_4 +keycode 76 = KP_5 + altgr keycode 76 = Hex_5 + alt keycode 76 = Ascii_5 +keycode 77 = KP_6 + altgr keycode 77 = Hex_6 + alt keycode 77 = Ascii_6 +keycode 78 = KP_Add +keycode 79 = KP_1 + altgr keycode 79 = Hex_1 + alt keycode 79 = Ascii_1 +keycode 80 = KP_2 + altgr keycode 80 = Hex_2 + alt keycode 80 = Ascii_2 +keycode 81 = KP_3 + altgr keycode 81 = Hex_3 + alt keycode 81 = Ascii_3 +keycode 82 = KP_0 + altgr keycode 82 = Hex_0 + alt keycode 82 = Ascii_0 +keycode 83 = KP_Period + altgr control keycode 83 = Boot + control alt keycode 83 = Boot +keycode 84 = Last_Console +keycode 85 = +keycode 86 = less greater bar + alt keycode 86 = Meta_less + shift alt keycode 86 = Meta_greater +keycode 87 = F11 F23 Console_23 F35 + alt keycode 87 = Console_11 + control alt keycode 87 = Console_11 +keycode 88 = F12 F24 Console_24 F36 + alt keycode 88 = Console_12 + control alt keycode 88 = Console_12 +keycode 89 = +keycode 90 = +keycode 91 = +keycode 92 = +keycode 93 = +keycode 94 = +keycode 95 = +keycode 96 = KP_Enter +keycode 97 = Control +keycode 98 = KP_Divide + altgr keycode 98 = Hex_B +keycode 99 = Control_backslash + alt keycode 99 = Meta_Control_backslash + shift alt keycode 99 = Meta_Control_backslash + control alt keycode 99 = Meta_Control_backslash +keycode 100 = AltGr +keycode 101 = Break +keycode 102 = Find +keycode 103 = Up + alt keycode 103 = KeyboardSignal +keycode 104 = Prior + shift keycode 104 = Scroll_Backward +keycode 105 = Left + alt keycode 105 = Decr_Console +keycode 106 = Right + alt keycode 106 = Incr_Console +keycode 107 = Select +keycode 108 = Down +keycode 109 = Next + shift keycode 109 = Scroll_Forward +keycode 110 = Insert +keycode 111 = Remove + altgr control keycode 111 = Boot + control alt keycode 111 = Boot +keycode 112 = Macro + altgr control keycode 112 = VoidSymbol + shift alt keycode 112 = VoidSymbol +keycode 113 = F13 + altgr control keycode 113 = VoidSymbol + shift alt keycode 113 = VoidSymbol +keycode 114 = F14 + altgr control keycode 114 = VoidSymbol + shift alt keycode 114 = VoidSymbol +keycode 115 = Help + altgr control keycode 115 = VoidSymbol + shift alt keycode 115 = VoidSymbol +keycode 116 = Do + altgr control keycode 116 = VoidSymbol + shift alt keycode 116 = VoidSymbol +keycode 117 = F17 + altgr control keycode 117 = VoidSymbol + shift alt keycode 117 = VoidSymbol +keycode 118 = KP_MinPlus + altgr control keycode 118 = VoidSymbol + shift alt keycode 118 = VoidSymbol +keycode 119 = Pause +keycode 120 = +keycode 121 = +keycode 122 = +keycode 123 = +keycode 124 = +keycode 125 = +keycode 126 = +keycode 127 = +string F1 = "\033[[A" +string F2 = "\033[[B" +string F3 = "\033[[C" +string F4 = "\033[[D" +string F5 = "\033[[E" +string F6 = "\033[17~" +string F7 = "\033[18~" +string F8 = "\033[19~" +string F9 = "\033[20~" +string F10 = "\033[21~" +string F11 = "\033[23~" +string F12 = "\033[24~" +string F13 = "\033[25~" +string F14 = "\033[26~" +string F15 = "\033[28~" +string F16 = "\033[29~" +string F17 = "\033[31~" +string F18 = "\033[32~" +string F19 = "\033[33~" +string F20 = "\033[34~" +string Find = "\033[1~" +string Insert = "\033[2~" +string Remove = "\033[3~" +string Select = "\033[4~" +string Prior = "\033[5~" +string Next = "\033[6~" +string Macro = "\033[M" +string Pause = "\033[P" +compose '`' 'A' to 'À' +compose '`' 'a' to 'à' +compose '\'' 'A' to 'Á' +compose '\'' 'a' to 'á' +compose '^' 'A' to 'Â' +compose '^' 'a' to 'â' +compose '~' 'A' to 'Ã' +compose '~' 'a' to 'ã' +compose '"' 'A' to 'Ä' +compose '"' 'a' to 'ä' +compose 'O' 'A' to 'Å' +compose 'o' 'a' to 'å' +compose '0' 'A' to 'Å' +compose '0' 'a' to 'å' +compose 'A' 'A' to 'Å' +compose 'a' 'a' to 'å' +compose 'A' 'E' to 'Æ' +compose 'a' 'e' to 'æ' +compose ',' 'C' to 'Ç' +compose ',' 'c' to 'ç' +compose '`' 'E' to 'È' +compose '`' 'e' to 'è' +compose '\'' 'E' to 'É' +compose '\'' 'e' to 'é' +compose '^' 'E' to 'Ê' +compose '^' 'e' to 'ê' +compose '"' 'E' to 'Ë' +compose '"' 'e' to 'ë' +compose '`' 'I' to 'Ì' +compose '`' 'i' to 'ì' +compose '\'' 'I' to 'Í' +compose '\'' 'i' to 'í' +compose '^' 'I' to 'Î' +compose '^' 'i' to 'î' +compose '"' 'I' to 'Ï' +compose '"' 'i' to 'ï' +compose '-' 'D' to 'Ð' +compose '-' 'd' to 'ð' +compose '~' 'N' to 'Ñ' +compose '~' 'n' to 'ñ' +compose '`' 'O' to 'Ò' +compose '`' 'o' to 'ò' +compose '\'' 'O' to 'Ó' +compose '\'' 'o' to 'ó' +compose '^' 'O' to 'Ô' +compose '^' 'o' to 'ô' +compose '~' 'O' to 'Õ' +compose '~' 'o' to 'õ' +compose '"' 'O' to 'Ö' +compose '"' 'o' to 'ö' +compose '/' 'O' to 'Ø' +compose '/' 'o' to 'ø' +compose '`' 'U' to 'Ù' +compose '`' 'u' to 'ù' +compose '\'' 'U' to 'Ú' +compose '\'' 'u' to 'ú' +compose '^' 'U' to 'Û' +compose '^' 'u' to 'û' +compose '"' 'U' to 'Ü' +compose '"' 'u' to 'ü' +compose '\'' 'Y' to 'Ý' +compose '\'' 'y' to 'ý' +compose 'T' 'H' to 'Þ' +compose 't' 'h' to 'þ' +compose 's' 's' to 'ß' +compose '"' 'y' to 'ÿ' +compose 's' 'z' to 'ß' +compose 'i' 'j' to 'ÿ' diff --git a/drivers/usb/maps/usb.map b/drivers/usb/maps/usb.map new file mode 100644 index 000000000000..e05c71cd81a4 --- /dev/null +++ b/drivers/usb/maps/usb.map @@ -0,0 +1,233 @@ +# USB kernel keymap. +keymaps 0-2,4-5,8,12 + +keycode 4 = a + altgr keycode 30 = Hex_A +keycode 5 = b + altgr keycode 48 = Hex_B +keycode 6 = c + altgr keycode 46 = Hex_C +keycode 7 = d + altgr keycode 32 = Hex_D +keycode 8 = e + altgr keycode 18 = Hex_E +keycode 9 = f + altgr keycode 33 = Hex_F +keycode 10 = g +keycode 11 = h +keycode 12 = i +keycode 13 = j +keycode 14 = k +keycode 15 = l +keycode 16 = m +keycode 17 = n +keycode 18 = o +keycode 19 = p +keycode 20 = q +keycode 21 = r +keycode 22 = s +keycode 23 = t +keycode 24 = u +keycode 25 = v +keycode 26 = w +keycode 27 = x +keycode 28 = y +keycode 29 = z +keycode 30 = one exclam + alt keycode 2 = Meta_one +keycode 31 = two at + control keycode 3 = nul + shift control keycode 3 = nul + alt keycode 3 = Meta_two +keycode 32 = three numbersign + control keycode 4 = Escape + alt keycode 4 = Meta_three +keycode 33 = four dollar + control keycode 5 = Control_backslash + alt keycode 5 = Meta_four +keycode 34 = five percent + control keycode 6 = Control_bracketright + alt keycode 6 = Meta_five +keycode 35 = six asciicircum + control keycode 7 = Control_asciicircum + alt keycode 7 = Meta_six +keycode 36 = seven ampersand + control keycode 8 = Control_underscore + alt keycode 8 = Meta_seven +keycode 37 = eight asterisk + control keycode 9 = Delete + alt keycode 9 = Meta_eight +keycode 38 = nine parenleft + alt keycode 10 = Meta_nine +keycode 39 = zero parenright + alt keycode 11 = Meta_zero +keycode 40 = Return + alt keycode 28 = Meta_Control_m +keycode 41 = Escape Escape + alt keycode 1 = Meta_Escape +keycode 42 = Delete Delete + control keycode 14 = BackSpace + alt keycode 14 = Meta_Delete +keycode 43 = Tab Tab + alt keycode 15 = Meta_Tab +keycode 44 = space space + control keycode 57 = nul + alt keycode 57 = Meta_space +keycode 45 = minus underscore backslash + control keycode 12 = Control_underscore + shift control keycode 12 = Control_underscore + alt keycode 12 = Meta_minus +keycode 46 = equal plus + alt keycode 13 = Meta_equal +keycode 47 = bracketleft braceleft + control keycode 26 = Escape + alt keycode 26 = Meta_bracketleft +keycode 48 = bracketright braceright asciitilde + control keycode 27 = Control_bracketright + alt keycode 27 = Meta_bracketright +keycode 49 = backslash bar + control keycode 43 = Control_backslash + alt keycode 43 = Meta_backslash +keycode 50 = +keycode 51 = semicolon colon + alt keycode 39 = Meta_semicolon +keycode 52 = apostrophe quotedbl + control keycode 40 = Control_g + alt keycode 40 = Meta_apostrophe +keycode 53 = grave asciitilde + control keycode 41 = nul + alt keycode 41 = Meta_grave +keycode 54 = comma less + alt keycode 51 = Meta_comma +keycode 55 = period greater + control keycode 52 = Compose + alt keycode 52 = Meta_period +keycode 56 = slash question + control keycode 53 = Delete + alt keycode 53 = Meta_slash +keycode 57 = Caps_Lock +keycode 58 = F1 F11 Console_13 + control keycode 59 = F1 + alt keycode 59 = Console_1 + control alt keycode 59 = Console_1 +keycode 59 = F2 F12 Console_14 + control keycode 60 = F2 + alt keycode 60 = Console_2 + control alt keycode 60 = Console_2 +keycode 60 = F3 F13 Console_15 + control keycode 61 = F3 + alt keycode 61 = Console_3 + control alt keycode 61 = Console_3 +keycode 61 = F4 F14 Console_16 + control keycode 62 = F4 + alt keycode 62 = Console_4 + control alt keycode 62 = Console_4 +keycode 62 = F5 F15 Console_17 + control keycode 63 = F5 + alt keycode 63 = Console_5 + control alt keycode 63 = Console_5 +keycode 63 = F6 F16 Console_18 + control keycode 64 = F6 + alt keycode 64 = Console_6 + control alt keycode 64 = Console_6 +keycode 64 = F7 F17 Console_19 + control keycode 65 = F7 + alt keycode 65 = Console_7 + control alt keycode 65 = Console_7 +keycode 65 = F8 F18 Console_20 + control keycode 66 = F8 + alt keycode 66 = Console_8 + control alt keycode 66 = Console_8 +keycode 66 = F9 F19 Console_21 + control keycode 67 = F9 + alt keycode 67 = Console_9 + control alt keycode 67 = Console_9 +keycode 67 = F10 F20 Console_22 + control keycode 68 = F10 + alt keycode 68 = Console_10 + control alt keycode 68 = Console_10 +keycode 68 = F11 F11 Console_23 + control keycode 87 = F11 + alt keycode 87 = Console_11 + control alt keycode 87 = Console_11 +keycode 69 = F12 F12 Console_24 + control keycode 88 = F12 + alt keycode 88 = Console_12 + control alt keycode 88 = Console_12 +keycode 70 = Print_Screen +keycode 71 = Scroll_Lock Show_Memory Show_Registers + control keycode 70 = Show_State + alt keycode 70 = Scroll_Lock +keycode 72 = Pause +keycode 73 = Insert +keycode 74 = Home +keycode 75 = Prior + shift keycode 104 = Scroll_Backward +keycode 76 = Remove +# altgr control keycode 111 = Boot + control alt keycode 111 = Boot +keycode 77 = End +keycode 78 = Next + shift keycode 109 = Scroll_Forward +keycode 79 = Right + alt keycode 106 = Incr_Console +keycode 80 = Left + alt keycode 105 = Decr_Console +keycode 81 = Down +keycode 82 = Up +keycode 83 = Num_Lock + shift keycode 69 = Bare_Num_Lock +keycode 84 = KP_Divide +keycode 85 = KP_Multiply +keycode 86 = KP_Subtract +keycode 87 = KP_Add +keycode 88 = KP_Enter +keycode 89 = KP_1 + alt keycode 79 = Ascii_1 + altgr keycode 79 = Hex_1 +keycode 90 = KP_2 + alt keycode 80 = Ascii_2 + altgr keycode 80 = Hex_2 +keycode 91 = KP_3 + alt keycode 81 = Ascii_3 + altgr keycode 81 = Hex_3 +keycode 92 = KP_4 + alt keycode 75 = Ascii_4 + altgr keycode 75 = Hex_4 +keycode 93 = KP_5 + alt keycode 76 = Ascii_5 + altgr keycode 76 = Hex_5 +keycode 94 = KP_6 + alt keycode 77 = Ascii_6 + altgr keycode 77 = Hex_6 +keycode 95 = KP_7 + alt keycode 71 = Ascii_7 + altgr keycode 71 = Hex_7 +keycode 96 = KP_8 + alt keycode 72 = Ascii_8 + altgr keycode 72 = Hex_8 +keycode 97 = KP_9 + alt keycode 73 = Ascii_9 + altgr keycode 73 = Hex_9 +keycode 98 = KP_0 + alt keycode 82 = Ascii_0 + altgr keycode 82 = Hex_0 +keycode 99 = KP_Period +# altgr control keycode 83 = Boot + control alt keycode 83 = Boot +keycode 100 = +keycode 101 = Application +keycode 102 = +keycode 103 = +keycode 104 = F13 +keycode 105 = F14 + +# modifiers +keycode 120 = Control +keycode 121 = Shift +keycode 122 = Alt +keycode 123 = Window +keycode 124 = Control_R +keycode 125 = Shift_R +keycode 126 = Alt_R +keycode 127 = Window_R diff --git a/drivers/usb/mkmap b/drivers/usb/mkmap new file mode 100644 index 000000000000..35808f227cca --- /dev/null +++ b/drivers/usb/mkmap @@ -0,0 +1,83 @@ +#!/usr/bin/perl + +($ME = $0) =~ s|.*/||; + +$file = "maps/serial.map"; +$line = 1; +open(PC, $file) || die("$!"); +while() +{ + if(/^\s*keycode\s+(\d+)\s*=\s*(\S+)/) + { + my($idx) = int($1); + my($sym) = $2; + if(defined($map{uc($sym)})) + { + # print STDERR "$file:$line: warning: `$sym' redefined\n"; + } + $map{uc($sym)} = $idx; + } + $line++; +} +close(PC); + +$file = "maps/fixup.map"; +$line = 1; +open(FIXUP, $file) || die("$!"); +while() +{ + if(/^\s*keycode\s+(\d+)\s*=\s*/) + { + my($idx) = int($1); + for $sym (split(/\s+/, $')) + { + $map{uc($sym)} = $idx; + } + } + $line++; +} +close(FIXUP); + +$file = "maps/usb.map"; +$line = 1; +open(USB, $file) || die("$!"); +while() +{ + if(/^\s*keycode\s+(\d+)\s*=\s*/) + { + my($idx) = int($1); + for $sym (split(/\s+/, $')) + { + my($val) = $map{uc($sym)}; + $map[$idx] = $val; + if(!defined($val)) + { + print STDERR "$file:$line: warning: `$sym' undefined\n"; + } + else + { + last; + } + } + } + $line++; +} +close(USB); + +print "unsigned char usb_kbd_map[256] = \n{\n"; +for($x = 0; $x < 32; $x++) +{ + if($x && !($x % 2)) + { + print "\n"; + } + print " "; + for($y = 0; $y < 8; $y++) + { + my($idx) = $x * 8 + $y; + print sprintf(" 0x%02x,", + int(defined($map[$idx]) ? $map[$idx]:0)); + } + print "\n"; +} +print "};\n"; diff --git a/drivers/usb/mouse.c b/drivers/usb/mouse.c new file mode 100644 index 000000000000..a724a40b9f97 --- /dev/null +++ b/drivers/usb/mouse.c @@ -0,0 +1,299 @@ +/* + * USB HID boot protocol mouse support based on MS BusMouse driver, psaux + * driver, and Linus's skeleton USB mouse driver + * + * Brad Keryan 4/3/1999 + * + * version 0.02: Hmm, the mouse seems drunk because I'm queueing the events. + * This is wrong: when an application (like X or gpm) reads the mouse device, + * it wants to find out the mouse's current position, not its recent history. + * The button thing turned out to be UHCI not flipping data toggle, so half the + * packets were thrown out. + * + * version 0.01: Switched over to busmouse protocol, and changed the minor + * number to 32 (same as uusbd's hidbp driver). Buttons work more sanely now, + * but it still doesn't generate button events unless you move the mouse. + * + * version 0.0: Driver emulates a PS/2 mouse, stealing /dev/psaux (sorry, I + * know that's not very nice). Moving in the X and Y axes works. Buttons don't + * work right yet: X sees a lot of MotionNotify/ButtonPress/ButtonRelease + * combos when you hold down a button and drag the mouse around. Probably has + * some additional bugs on an SMP machine. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "usb.h" + +#define USB_MOUSE_MINOR 32 + +struct mouse_state { + unsigned char buttons; /* current button state */ + long dx; /* dx, dy, dz are change since last read */ + long dy; + long dz; + int present; /* this mouse is plugged in */ + int active; /* someone is has this mouse's device open */ + int ready; /* the mouse has changed state since the last read */ + struct wait_queue *wait; /* for polling */ + struct fasync_struct *fasync; + /* later, add a list here to support multiple mice */ + /* but we will also need a list of file pointers to identify it */ +}; + +static struct mouse_state static_mouse_state; + +spinlock_t usb_mouse_lock = SPIN_LOCK_UNLOCKED; + +static int mouse_irq(int state, void *__buffer, void *dev_id) +{ + signed char *data = __buffer; + /* finding the mouse is easy when there's only one */ + struct mouse_state *mouse = &static_mouse_state; + + /* if a mouse moves with no one listening, do we care? no */ + if(!mouse->active) + return 1; + + /* if the USB mouse sends an interrupt, then something noteworthy + must have happened */ + mouse->buttons = data[0] & 0x07; + mouse->dx += data[1]; /* data[] is signed, so this works */ + mouse->dy -= data[2]; /* y-axis is reversed */ + mouse->dz += data[3]; + mouse->ready = 1; + + add_mouse_randomness((mouse->buttons << 24) + (mouse->dz << 16 ) + + (mouse->dy << 8) + mouse->dx); + + wake_up_interruptible(&mouse->wait); + if (mouse->fasync) + kill_fasync(mouse->fasync, SIGIO); + + return 1; +} + +static int fasync_mouse(int fd, struct file *filp, int on) +{ + int retval; + struct mouse_state *mouse = &static_mouse_state; + + retval = fasync_helper(fd, filp, on, &mouse->fasync); + if (retval < 0) + return retval; + return 0; +} + +static int release_mouse(struct inode * inode, struct file * file) +{ + struct mouse_state *mouse = &static_mouse_state; + + fasync_mouse(-1, file, 0); + if (--mouse->active) + return 0; + return 0; +} + +static int open_mouse(struct inode * inode, struct file * file) +{ + struct mouse_state *mouse = &static_mouse_state; + + if (!mouse->present) + return -EINVAL; + if (mouse->active++) + return 0; + /* flush state */ + mouse->buttons = mouse->dx = mouse->dy = mouse->dz = 0; + return 0; +} + +static ssize_t write_mouse(struct file * file, + const char * buffer, size_t count, loff_t *ppos) +{ + return -EINVAL; +} + +/* + * Look like a PS/2 mouse, please.. + * + * The PS/2 protocol is fairly strange, but + * oh, well, it's at least common.. + */ +static ssize_t read_mouse(struct file * file, char * buffer, size_t count, loff_t *ppos) +{ + int retval = 0; + static int state = 0; + struct mouse_state *mouse = &static_mouse_state; + + if (count) { + mouse->ready = 0; + switch (state) { + case 0: { /* buttons and sign */ + int buttons = mouse->buttons; + mouse->buttons = 0; + if (mouse->dx < 0) + buttons |= 0x10; + if (mouse->dy < 0) + buttons |= 0x20; + put_user(buttons, buffer); + buffer++; + retval++; + state = 1; + if (!--count) + break; + } + case 1: { /* dx */ + int dx = mouse->dx; + mouse->dx = 0; + put_user(dx, buffer); + buffer++; + retval++; + state = 2; + if (!--count) + break; + } + case 2: { /* dy */ + int dy = mouse->dy; + mouse->dy = 0; + put_user(dy, buffer); + buffer++; + retval++; + state = 0; + } + break; + } + } + return retval; +} + +static unsigned int mouse_poll(struct file *file, poll_table * wait) +{ + struct mouse_state *mouse = &static_mouse_state; + + poll_wait(file, &mouse->wait, wait); + if (mouse->ready) + return POLLIN | POLLRDNORM; + return 0; +} + +struct file_operations usb_mouse_fops = { + NULL, /* mouse_seek */ + read_mouse, + write_mouse, + NULL, /* mouse_readdir */ + mouse_poll, /* mouse_poll */ + NULL, /* mouse_ioctl */ + NULL, /* mouse_mmap */ + open_mouse, + NULL, /* flush */ + release_mouse, + NULL, + fasync_mouse, +}; + +static struct miscdevice usb_mouse = { + USB_MOUSE_MINOR, "USB mouse", &usb_mouse_fops +}; + +static int mouse_probe(struct usb_device *dev) +{ + struct usb_interface_descriptor *interface; + struct usb_endpoint_descriptor *endpoint; + struct mouse_state *mouse = &static_mouse_state; + + /* We don't handle multi-config mice */ + if (dev->descriptor.bNumConfigurations != 1) + return -1; + + /* We don't handle multi-interface mice */ + if (dev->config[0].bNumInterfaces != 1) + return -1; + + /* Is it a mouse interface? */ + interface = &dev->config[0].interface[0]; + if (interface->bInterfaceClass != 3) + return -1; + if (interface->bInterfaceSubClass != 1) + return -1; + if (interface->bInterfaceProtocol != 2) + return -1; + + /* Multiple endpoints? What kind of mutant ninja-mouse is this? */ + if (interface->bNumEndpoints != 1) + return -1; + + endpoint = &interface->endpoint[0]; + + /* Output endpoint? Curiousier and curiousier.. */ + if (!(endpoint->bEndpointAddress & 0x80)) + return -1; + + /* If it's not an interrupt endpoint, we'd better punt! */ + if ((endpoint->bmAttributes & 3) != 3) + return -1; + + printk("USB mouse found\n"); + + usb_set_configuration(dev, dev->config[0].bConfigurationValue); + + usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), mouse_irq, endpoint->bInterval, NULL); + + mouse->present = 1; + return 0; +} + +static void mouse_disconnect(struct usb_device *dev) +{ + struct mouse_state *mouse = &static_mouse_state; + + /* this might need work */ + mouse->present = 0; +} + +static struct usb_driver mouse_driver = { + "mouse", + mouse_probe, + mouse_disconnect, + { NULL, NULL } +}; + +int usb_mouse_init(void) +{ + struct mouse_state *mouse = &static_mouse_state; + + misc_register(&usb_mouse); + + mouse->present = mouse->active = 0; + mouse->wait = NULL; + mouse->fasync = NULL; + + usb_register(&mouse_driver); + printk(KERN_INFO "USB HID boot protocol mouse registered.\n"); + return 0; +} + +#if 0 + +int init_module(void) +{ + return usb_mouse_init(); +} + +void cleanup_module(void) +{ + /* this, too, probably needs work */ + usb_deregister(&mouse_driver); + misc_deregister(&usb_mouse); +} + +#endif diff --git a/drivers/usb/ohci-debug.c b/drivers/usb/ohci-debug.c new file mode 100644 index 000000000000..5f90bbe7260e --- /dev/null +++ b/drivers/usb/ohci-debug.c @@ -0,0 +1,139 @@ +/* + * OHCI debugging code. It's gross. + * + * (C) Copyright 1999 Gregory P. Smith + */ + +#include +#include + +#include "ohci.h" + +void show_ohci_status(struct ohci *ohci) +{ + struct ohci_regs regs; + int i; + + regs.revision = readl(ohci->regs->revision); + regs.control = readl(ohci->regs->control); + regs.cmdstatus = readl(ohci->regs->cmdstatus); + regs.intrstatus = readl(ohci->regs->intrstatus); + regs.intrenable = readl(ohci->regs->intrenable); + regs.intrdisable = readl(ohci->regs->intrdisable); + regs.hcca = readl(ohci->regs->hcca); + regs.ed_periodcurrent = readl(ohci->regs->ed_periodcurrent); + regs.ed_controlhead = readl(ohci->regs->ed_controlhead); + regs.ed_bulkhead = readl(ohci->regs->ed_bulkhead); + regs.ed_bulkcurrent = readl(ohci->regs->ed_bulkcurrent); + regs.current_donehead = readl(ohci->regs->current_donehead); + regs.fminterval = readl(ohci->regs->fminterval); + regs.fmremaining = readl(ohci->regs->fmremaining); + regs.fmnumber = readl(ohci->regs->fmnumber); + regs.periodicstart = readl(ohci->regs->periodicstart); + regs.lsthresh = readl(ohci->regs->lsthresh); + regs.roothub.a = readl(ohci->regs->roothub.a); + regs.roothub.b = readl(ohci->regs->roothub.b); + regs.roothub.status = readl(ohci->regs->roothub.status); + for (i=0; iregs->roothub.portstatus[i]); + + printk(" ohci revision = 0x%x\n", regs.revision); + printk(" ohci control = 0x%x\n", regs.control); + printk(" ohci cmdstatus = 0x%x\n", regs.cmdstatus); + printk(" ohci intrstatus = 0x%x\n", regs.intrstatus); + printk(" ohci roothub.a = 0x%x\n", regs.roothub.a); + printk(" ohci roothub.b = 0x%x\n", regs.roothub.b); + printk(" ohci root status = 0x%x\n", regs.roothub.status); +} /* show_ohci_status() */ + + +static void show_ohci_ed(struct ohci_ed *ed) +{ + int stat = ed->status; + int skip = (stat & OHCI_ED_SKIP); + int mps = (stat & OHCI_ED_MPS) >> 16; + int isoc = (stat & OHCI_ED_F_ISOC); + int low_speed = (stat & OHCI_ED_S_LOW); + int dir = (stat & OHCI_ED_D); + int endnum = (stat & OHCI_ED_EN) >> 7; + int funcaddr = (stat & OHCI_ED_FA); + int halted = (ed->head_td & 1); + int toggle = (ed->head_td & 2) >> 1; + + printk(" ohci ED:\n"); + printk(" status = 0x%x\n", stat); + printk(" %sMPS %d%s%s%s%s tc%d e%d fa%d\n", + skip ? "Skip " : "", + mps, + isoc ? "Isoc. " : "", + low_speed ? "LowSpd " : "", + (dir == OHCI_ED_D_IN) ? "Input " : + (dir == OHCI_ED_D_OUT) ? "Output " : "", + halted ? "Halted " : "", + toggle, + endnum, + funcaddr); + printk(" tail_td = 0x%x\n", ed->tail_td); + printk(" head_td = 0x%x\n", ed->head_td); + printk(" next_ed = 0x%x\n", ed->next_ed); +} /* show_ohci_ed() */ + + +static void show_ohci_td(struct ohci_td *td) +{ + int td_round = td->info & OHCI_TD_ROUND; + int td_dir = td->info & OHCI_TD_D; + int td_int_delay = td->info & OHCI_TD_IOC_DELAY; + int td_toggle = td->info & OHCI_TD_DT; + int td_errcnt = td_errorcount(td->info); + int td_cc = td->info & OHCI_TD_CC; + + printk(" ohci TD hardware fields:\n"); + printk(" info = 0x%x\n", td->info); + printk(" %s%s%s%d%s%s%d%s%d\n", + td_round ? "Rounding " : "", + (td_dir == OHCI_TD_D_IN) ? "Input " : + (td_dir == OHCI_TD_D_OUT) ? "Output " : + (td_dir == OHCI_TD_D_SETUP) ? "Setup " : "", + "IntDelay ", td_int_delay >> 21, + td_toggle ? "Data1 " : "Data0 ", + "ErrorCnt ", td_errcnt, + "ComplCode ", td_cc); + printk(" %sAccessed, %sActive\n", + td_cc_accessed(td->info) ? "" : "Not ", + td_active(td->info) ? "" : "Not "); + + printk(" cur_buf = 0x%x\n", td->cur_buf); + printk(" next_td = 0x%x\n", td->next_td); + printk(" buf_end = 0x%x\n", td->buf_end); + printk(" ohci TD driver fields:\n"); + printk(" data = %p\n", td->data); + printk(" dev_id = %p\n", td->dev_id); + printk(" ed_bus = %x\n", td->ed_bus); +} /* show_ohci_td() */ + + +void show_ohci_device(struct ohci_device *dev) +{ + int idx; + printk(" ohci_device usb = %p\n", dev->usb); + printk(" ohci_device ohci = %p\n", dev->ohci); + printk(" ohci_device ohci_hcca = %p\n", dev->hcca); + for (idx=0; idx<8 /*NUM_EDS*/; ++idx) { + printk(" [ed num %d] ", idx); + show_ohci_ed(&dev->ed[idx]); + } + for (idx=0; idx<8 /*NUM_TDS*/; ++idx) { + printk(" [td num %d] ", idx); + show_ohci_td(&dev->td[idx]); + } + printk(" ohci_device data\n "); + for (idx=0; idx<4; ++idx) { + printk(" %08lx", dev->data[idx]); + } + printk("\n"); +} /* show_ohci_device() */ + + +/* vim:sw=8 + */ diff --git a/drivers/usb/ohci.c b/drivers/usb/ohci.c new file mode 100644 index 000000000000..6207dcd98809 --- /dev/null +++ b/drivers/usb/ohci.c @@ -0,0 +1,1040 @@ +/* + * Open Host Controller Interface driver for USB. + * + * (C) Copyright 1999 Gregory P. Smith + * + * This is the "other" host controller interface for USB. You will + * find this on many non-Intel based motherboards, and of course the + * Mac. As Linus hacked his UHCI driver together first, I modeled + * this after his.. (it should be obvious) + * + * From the programming standpoint the OHCI interface seems a little + * prettier and potentially less CPU intensive. This remains to be + * proven. In reality, I don't believe it'll make one darn bit of + * difference. USB v1.1 is a slow bus by today's standards. + * + * OHCI hardware takes care of most of the scheduling of different + * transfer types with the correct prioritization for us. + * + * To get started in USB, I used the "Universal Serial Bus System + * Architecture" book by Mindshare, Inc. It was a reasonable introduction + * and overview of USB and the two dominant host controller interfaces + * however you're better off just reading the real specs available + * from www.usb.org as you'll need them to get enough detailt to + * actually implement a HCD. The book has many typos and omissions + * Beware, the specs are the victim of a committee. + * + * This code was written with Guinness on the brain, xsnow on the desktop + * and Orbital, Orb, Enya & Massive Attack on the CD player. What a life! ;) + * + * No filesystems were harmed in the development of this code. + * + * $Id: ohci.c,v 1.11 1999/04/25 00:18:52 greg Exp $ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "ohci.h" +#include "inits.h" + +#ifdef CONFIG_APM +#include +static int handle_apm_event(apm_event_t event); +static int apm_resume = 0; +#endif + +static struct wait_queue *ohci_configure = NULL; + + +static int ohci_td_result(struct ohci_device *dev, struct ohci_td *td) +{ + unsigned int status; + + status = td->info & OHCI_TD_CC; + + /* TODO Debugging code for TD failures goes here */ + + return status; +} + + +static spinlock_t ohci_edtd_lock = SPIN_LOCK_UNLOCKED; + +/* + * Add a TD to the end of the TD list on a given ED. td->next_td is + * assumed to be set correctly for the situation of no TDs already + * being on the list (ie: pointing to NULL). + */ +static void ohci_add_td_to_ed(struct ohci_td *td, struct ohci_ed *ed) +{ + struct ohci_td *tail = bus_to_virt(ed->tail_td); + struct ohci_td *head = bus_to_virt(ed->head_td); + unsigned long flags; + + spin_lock_irqsave(&ohci_edtd_lock, flags); + + if (tail == head) { /* empty list, put it on the head */ + head = (struct ohci_td *) virt_to_bus(td); + tail = 0; + } else { + if (!tail) { /* no tail, single element list */ + td->next_td = head->next_td; + head->next_td = virt_to_bus(td); + tail = (struct ohci_td *) virt_to_bus(td); + } else { /* append to the list */ + td->next_td = tail->next_td; + tail->next_td = virt_to_bus(td); + tail = (struct ohci_td *) virt_to_bus(td); + } + } + /* save the reverse link */ + td->ed_bus = virt_to_bus(ed); + + spin_unlock_irqrestore(&ohci_edtd_lock, flags); +} /* ohci_add_td_to_ed() */ + + +/* + * Remove a TD from the given EDs TD list + */ +static void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed) +{ + struct ohci_td *head = bus_to_virt(ed->head_td); + struct ohci_td *tmp_td; + unsigned long flags; + + spin_lock_irqsave(&ohci_edtd_lock, flags); + + /* set the "skip me bit" in this ED */ + writel_set(OHCI_ED_SKIP, ed->status); + + /* XXX Assuming this list will never be circular */ + + if (td == head) { + /* unlink this TD; it was at the beginning */ + ed->head_td = head->next_td; + } + + tmp_td = head; + head = (struct ohci_td *) ed->head_td; + + while (head != NULL) { + + if (td == head) { + /* unlink this TD from the middle or end */ + tmp_td->next_td = head->next_td; + } + + tmp_td = head; + head = bus_to_virt(head->next_td); + } + + td->next_td = virt_to_bus(NULL); /* remove links to ED list */ + + /* XXX mark this TD for possible cleanup? */ + + /* unset the "skip me bit" in this ED */ + writel_mask(~(__u32)OHCI_ED_SKIP, ed->status); + + spin_unlock_irqrestore(&ohci_edtd_lock, flags); +} /* ohci_remove_td_from_ed() */ + + +/* + * Get a pointer (virtual) to an available TD from the given device's + * pool. + * + * Return NULL if none are left. + */ +static struct ohci_td *ohci_get_free_td(struct ohci_device *dev) +{ + int idx; + + for (idx=0; idx < NUM_TDS; idx++) { + if (td_done(dev->td[idx].info)) { + /* XXX should this also zero out the structure? */ + /* mark all new TDs as unaccessed */ + dev->td[idx].info = OHCI_TD_CC_NEW; + return &dev->td[idx]; + } + } + + return NULL; +} /* ohci_get_free_td() */ + + +/********************************** + * OHCI interrupt list operations * + **********************************/ +static spinlock_t irqlist_lock = SPIN_LOCK_UNLOCKED; + +static void ohci_add_irq_list(struct ohci *ohci, struct ohci_td *td, usb_device_irq completed, void *dev_id) +{ + unsigned long flags; + + /* save the irq in our private portion of the TD */ + td->completed = completed; + td->dev_id = dev_id; + + spin_lock_irqsave(&irqlist_lock, flags); + list_add(&td->irq_list, &ohci->interrupt_list); + spin_unlock_irqrestore(&irqlist_lock, flags); +} /* ohci_add_irq_list() */ + +static void ohci_remove_irq_list(struct ohci_td *td) +{ + unsigned long flags; + + spin_lock_irqsave(&irqlist_lock, flags); + list_del(&td->irq_list); + spin_unlock_irqrestore(&irqlist_lock, flags); +} /* ohci_remove_irq_list() */ + +/* + * Request an interrupt handler for one "pipe" of a USB device. + * (this function is pretty minimal right now) + * + * At the moment this is only good for input interrupts. (ie: for a + * mouse) + * + * period is desired polling interval in ms. The closest, shorter + * match will be used. Powers of two from 1-32 are supported by OHCI. + */ +static int ohci_request_irq(struct usb_device *usb, unsigned int pipe, + usb_device_irq handler, int period, void *dev_id) +{ + struct ohci_device *dev = usb_to_ohci(usb); + struct ohci_td *td = dev->td; /* */ + struct ohci_ed *interrupt_ed; /* endpoint descriptor for this irq */ + + /* + * Pick a good frequency endpoint based on the requested period + */ + interrupt_ed = &dev->ohci->root_hub->ed[ms_to_ed_int(period)]; + + /* + * Set the max packet size, device speed, endpoint number, usb + * device number (function address), and type of TD. + * + * FIXME: Isochronous transfers need a pool of special 32 byte + * TDs (32 byte aligned) in order to be supported. + */ + interrupt_ed->status = \ + ed_set_maxpacket(usb_maxpacket(pipe)) | + ed_set_speed(usb_pipeslow(pipe)) | + usb_pipe_endpdev(pipe) | + OHCI_ED_F_NORM; + + /* + * Set the not accessed condition code, allow odd sized data, + * and set the data transfer direction. + */ + td->info = OHCI_TD_CC_NEW | OHCI_TD_ROUND | + td_set_dir_out(usb_pipeout(pipe)); + + /* point it to our data buffer */ + td->cur_buf = virt_to_bus(dev->data); + + /* FIXME: we're only using 1 TD right now! */ + td->next_td = virt_to_bus(&td); + + /* + * FIXME: be aware that OHCI won't advance out of the 4kb + * page cur_buf started in. It'll wrap around to the start + * of the page... annoying or useful? you decide. + * + * A pointer to the last *byte* in the buffer (ergh.. we get + * to work around C's pointer arithmatic here with a typecast) + */ + td->buf_end = virt_to_bus(((u8*)(dev->data + DATA_BUF_LEN)) - 1); + + /* does this make sense for ohci?.. time to think.. */ + ohci_add_irq_list(dev->ohci, td, handler, dev_id); + wmb(); /* found in asm/system.h; scary concept... */ + ohci_add_td_to_ed(td, interrupt_ed); + + return 0; +} /* ohci_request_irq() */ + +/* + * Control thread operations: + */ +static struct wait_queue *control_wakeup; + +static int ohci_control_completed(int stats, void *buffer, void *dev_id) +{ + wake_up(&control_wakeup); + return 0; +} /* ohci_control_completed() */ + + +/* + * Run a control transaction from the root hub's control endpoint. + * The passed in TD is the control transfer's Status TD. + */ +static int ohci_run_control(struct ohci_device *dev, struct ohci_td *status_td) +{ + struct wait_queue wait = { current, NULL }; + struct ohci_ed *control_ed = &dev->ohci->root_hub->ed[ED_CONTROL]; + + current->state = TASK_UNINTERRUPTIBLE; + add_wait_queue(&control_wakeup, &wait); + + ohci_add_irq_list(dev->ohci, status_td, ohci_control_completed, NULL); + ohci_add_td_to_ed(status_td, control_ed); + + /* FIXME? isn't this a little gross */ + schedule_timeout(HZ/10); + + ohci_remove_irq_list(status_td); + ohci_remove_td_from_ed(status_td, control_ed); + + return ohci_td_result(dev, status_td); +} /* ohci_run_control() */ + +/* + * Send or receive a control message on a "pipe" + * + * A control message contains: + * - The command itself + * - An optional data phase + * - Status complete phase + * + * The data phase can be an arbitrary number of TD's. Currently since + * we use statically allocated TDs if too many come in we'll just + * start tossing them and printk() some warning goo... Most control + * messages won't have much data anyways. + */ +static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, void *cmd, void *data, int len) +{ + struct ohci_device *dev = usb_to_ohci(usb); + /* + * ideally dev->ed should be linked into the root hub's + * control_ed list and used instead of just using it directly. + * This could present a problem as is with more than one + * device. (but who wants to use a keyboard AND a mouse + * anyways? ;) + */ + struct ohci_ed *control_ed = &dev->ohci->root_hub->ed[ED_CONTROL]; + struct ohci_td *control_td; + struct ohci_td *data_td; + struct ohci_td *last_td; + __u32 data_td_info; + + /* + * Set the max packet size, device speed, endpoint number, usb + * device number (function address), and type of TD. + * + */ + control_ed->status = \ + ed_set_maxpacket(usb_maxpacket(pipe)) | + ed_set_speed(usb_pipeslow(pipe)) | + usb_pipe_endpdev(pipe) | + OHCI_ED_F_NORM; + + /* + * Build the control TD + */ + + /* get a TD to send this control message with */ + control_td = ohci_get_free_td(dev); + /* TODO check for NULL */ + + /* + * Set the not accessed condition code, allow odd sized data, + * and set the data transfer type to SETUP. Setup DATA always + * uses a DATA0 packet. + */ + control_td->info = OHCI_TD_CC_NEW | OHCI_TD_ROUND | + OHCI_TD_D_SETUP | OHCI_TD_IOC_OFF | td_force_toggle(0); + + /* point it to the command */ + control_td->cur_buf = virt_to_bus(cmd); + + /* link to a free TD for the control data input */ + data_td = ohci_get_free_td(dev); /* TODO check for NULL */ + control_td->next_td = virt_to_bus(data_td); + + /* + * Build the DATA TDs + */ + + data_td_info = OHCI_TD_CC_NEW | OHCI_TD_ROUND | OHCI_TD_IOC_OFF | + td_set_dir_out(usb_pipeout(pipe)); + + while (len > 0) { + int pktsize = len; + struct ohci_td *tmp_td; + + if (pktsize > usb_maxpacket(pipe)) + pktsize = usb_maxpacket(pipe); + + /* set the data transaction type */ + data_td->info = data_td_info; + /* point to the current spot in the data buffer */ + data_td->cur_buf = virt_to_bus(data); + /* point to the end of this data */ + data_td->buf_end = virt_to_bus(data+pktsize-1); + + /* allocate the next TD */ + tmp_td = ohci_get_free_td(dev); /* TODO check for NULL */ + data_td->next_td = virt_to_bus(tmp_td); + data_td = tmp_td; + + /* move on.. */ + data += pktsize; + len -= pktsize; + } + + /* point it at the newly allocated TD from above */ + last_td = data_td; + + /* The control status packet always uses a DATA1 */ + last_td->info = OHCI_TD_CC_NEW | OHCI_TD_ROUND | td_force_toggle(1); + last_td->next_td = 0; /* end of TDs */ + last_td->cur_buf = 0; /* no data in this packet */ + last_td->buf_end = 0; + + /* + * Start the control transaction.. give it the last TD so the + * result can be returned. + */ + return ohci_run_control(dev, last_td); +} /* ohci_control_msg() */ + + +static struct usb_device *ohci_usb_allocate(struct usb_device *parent) +{ + struct usb_device *usb_dev; + struct ohci_device *dev; + + usb_dev = kmalloc(sizeof(*usb_dev), GFP_KERNEL); + if (!usb_dev) + return NULL; + + memset(usb_dev, 0, sizeof(*usb_dev)); + + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + kfree(usb_dev); + return NULL; + } + + /* Initialize "dev" */ + memset(dev, 0, sizeof(*dev)); + + usb_dev->hcpriv = dev; + dev->usb = usb_dev; + + usb_dev->parent = parent; + + if (parent) { + usb_dev->bus = parent->bus; + dev->ohci = usb_to_ohci(parent)->ohci; + } + + return usb_dev; +} + +static int ohci_usb_deallocate(struct usb_device *usb_dev) +{ + kfree(usb_to_ohci(usb_dev)); + kfree(usb_dev); + return 0; +} + +/* + * functions for the generic USB driver + */ +struct usb_operations ohci_device_operations = { + ohci_usb_allocate, + ohci_usb_deallocate, + ohci_control_msg, + ohci_request_irq, +}; + +/* + * Reset an OHCI controller + */ +static void reset_hc(struct ohci *ohci) +{ + writel((1<<31), &ohci->regs->intrdisable); /* Disable HC interrupts */ + writel(1, &ohci->regs->cmdstatus); /* HC Reset */ + writel_mask(0x3f, &ohci->regs->control); /* move to UsbReset state */ +} /* reset_hc() */ + + +/* + * Reset and start an OHCI controller + */ +static void start_hc(struct ohci *ohci) +{ + int timeout = 1000; /* used to prevent an infinite loop. */ + + reset_hc(ohci); + + while ((readl(&ohci->regs->control) & 0xc0) == 0) { + if (!--timeout) { + printk("USB HC Reset timed out!\n"); + break; + } + } + + /* Choose the interrupts we care about */ + writel( OHCI_INTR_MIE | OHCI_INTR_RHSC | OHCI_INTR_SF | + OHCI_INTR_WDH | OHCI_INTR_SO | OHCI_INTR_UE | + OHCI_INTR_FNO, + &ohci->regs->intrenable); + + /* Enter the USB Operational state & start the frames a flowing.. */ + writel_set(OHCI_USB_OPER, &ohci->regs->control); + +} /* start_hc() */ + + +/* + * Reset a root hub port + */ +static void ohci_reset_port(struct ohci *ohci, unsigned int port) +{ + short ms; + int status; + + /* Don't allow overflows. */ + if (port >= MAX_ROOT_PORTS) { + printk("Bad port # passed to ohci_reset_port\n"); + port = MAX_ROOT_PORTS-1; + } + + writel(PORT_PRS, &ohci->regs->roothub.portstatus[port]); /* Reset */ + + /* + * Get the time required for a root hub port to reset and wait + * it out (adding 1ms for good measure). + */ + ms = (readl(&ohci->regs->roothub.a) >> 24) * 2 + 1; + wait_ms(ms); + + /* check port status to see that the reset completed */ + status = readl(&ohci->regs->roothub.portstatus[port]); + if (status & PORT_PRS) { + /* reset failed, try harder? */ + printk("usb-ohci: port %d reset failed, retrying\n", port); + writel(PORT_PRS, &ohci->regs->roothub.portstatus[port]); + wait_ms(50); + } + + /* TODO we might need to re-enable the port here or is that + * done elsewhere? */ + +} /* ohci_reset_port */ + + +/* + * This gets called if the connect status on the root hub changes. + */ +static void ohci_connect_change(struct ohci * ohci, int port) +{ + struct usb_device *usb_dev; + struct ohci_device *dev; + /* memory I/O address of the port status register */ + void *portaddr = &ohci->regs->roothub.portstatus[port]; + int portstatus; + + /* + * Because of the status change we have to forget + * everything we think we know about the device + * on this root hub port. It may have changed. + */ + usb_disconnect(ohci->root_hub->usb->children + port); + + portstatus = readl(portaddr); + + /* disable the port if nothing is connected */ + if (!(portstatus & PORT_CCS)) { + writel(PORT_CCS, portaddr); + return; + } + + /* + * Allocate a device for the new thingy that's been attached + */ + usb_dev = ohci_usb_allocate(ohci->root_hub->usb); + dev = usb_dev->hcpriv; + + dev->ohci = ohci; + + usb_connect(dev->usb); + + /* link it into the bus's device tree */ + ohci->root_hub->usb->children[port] = usb_dev; + + wait_ms(200); /* wait for powerup; XXX is this needed? */ + ohci_reset_port(ohci, port); + + /* Get information on speed by using LSD */ + usb_dev->slow = readl(portaddr) & PORT_LSDA ? 1 : 0; + + /* + * Do generic USB device tree processing on the new device. + */ + usb_new_device(usb_dev); +} /* ohci_connect_change() */ + + +/* + * This gets called when the root hub configuration + * has changed. Just go through each port, seeing if + * there is something interesting happening. + */ +static void ohci_check_configuration(struct ohci *ohci) +{ + int num = 0; + int maxport = readl(&ohci->regs->roothub) & 0xff; + + do { + if (readl(ohci->regs->roothub.portstatus[num]) & PORT_CSC) + ohci_connect_change(ohci, num); + } while (++num < maxport); +} /* ohci_check_configuration() */ + + +/* + * Get annoyed at the controller for bothering us. + */ +static void ohci_interrupt(int irq, void *__ohci, struct pt_regs *r) +{ + struct ohci *ohci = __ohci; + struct ohci_regs *regs = ohci->regs; + struct ohci_hcca *hcca = ohci->root_hub->hcca; + __u32 donehead = hcca->donehead; + + /* + * Check the interrupt status register if needed + */ + if (!donehead || (donehead & 1)) { + __u32 intrstatus = readl(®s->intrstatus); + + /* + * XXX eek! printk's in an interrupt handler. shoot me! + */ + if (intrstatus & OHCI_INTR_SO) { + printk(KERN_DEBUG "usb-ohci: scheduling overrun\n"); + } + if (intrstatus & OHCI_INTR_RD) { + printk(KERN_DEBUG "usb-ohci: resume detected\n"); + } + if (intrstatus & OHCI_INTR_UE) { + printk(KERN_DEBUG "usb-ohci: unrecoverable error\n"); + } + if (intrstatus & OHCI_INTR_OC) { + printk(KERN_DEBUG "usb-ohci: ownership change?\n"); + } + + if (intrstatus & OHCI_INTR_RHSC) { + /* TODO Process events on the root hub */ + } + } + + /* + * Process the done list + */ + if (donehead &= ~0x1) { + /* + * TODO See which TD's completed.. + */ + } + + /* Re-enable done queue interrupts and reset the donehead */ + hcca->donehead = 0; + writel(OHCI_INTR_WDH, ®s->intrenable); + +} /* ohci_interrupt() */ + + +/* + * Allocate the resources required for running an OHCI controller. + * Host controller interrupts must not be running while calling this + * function or the penguins will get angry. + * + * The mem_base parameter must be the usable -virtual- address of the + * host controller's memory mapped I/O registers. + */ +static struct ohci *alloc_ohci(void* mem_base) +{ + int i; + struct ohci *ohci; + struct usb_bus *bus; + struct ohci_device *dev; + struct usb_device *usb; + + ohci = kmalloc(sizeof(*ohci), GFP_KERNEL); + if (!ohci) + return NULL; + + memset(ohci, 0, sizeof(*ohci)); + + ohci->irq = -1; + ohci->regs = mem_base; + INIT_LIST_HEAD(&ohci->interrupt_list); + + bus = kmalloc(sizeof(*bus), GFP_KERNEL); + if (!bus) + return NULL; + + memset(bus, 0, sizeof(*bus)); + + ohci->bus = bus; + bus->hcpriv = ohci; + bus->op = &ohci_device_operations; + + /* + * Here we allocate our own root hub and TDs as well as the + * OHCI host controller communications area. The HCCA is just + * a nice pool of memory with pointers to endpoint descriptors + * for the different interrupts. + */ + usb = ohci_usb_allocate(NULL); + if (!usb) + return NULL; + + dev = ohci->root_hub = usb_to_ohci(usb); + + usb->bus = bus; + + /* Initialize the root hub */ + memset(dev, 0, sizeof(*dev)); + dev->ohci = ohci; /* link back to the controller */ + + /* + * Allocate the Host Controller Communications Area + */ + dev->hcca = (struct ohci_hcca *) kmalloc(sizeof(*dev->hcca), GFP_KERNEL); + + /* Tell the controller where the HCCA is */ + writel(virt_to_bus(dev->hcca), &ohci->regs->hcca); + + /* Get the number of ports on the root hub */ + usb->maxchild = readl(&ohci->regs->roothub.a) & 0xff; + if (usb->maxchild > MAX_ROOT_PORTS) { + printk("usb-ohci: Limited to %d ports\n", MAX_ROOT_PORTS); + usb->maxchild = MAX_ROOT_PORTS; + } + if (usb->maxchild < 1) { + printk("usb-ohci: Less than one root hub port? Impossible!\n"); + usb->maxchild = 1; + } + printk("usb-ohci: %d root hub ports found\n", usb->maxchild); + + printk("alloc_ohci() controller\n"); + show_ohci_status(ohci); + printk("alloc_ohci() root_hub device\n"); + show_ohci_device(dev); + + /* + * Initialize the ED polling "tree" (for simplicity's sake in + * this driver many nodes in the tree will be identical) + */ + dev->ed[ED_INT_32].next_ed = virt_to_bus(&dev->ed[ED_INT_16]); + dev->ed[ED_INT_16].next_ed = virt_to_bus(&dev->ed[ED_INT_8]); + dev->ed[ED_INT_8].next_ed = virt_to_bus(&dev->ed[ED_INT_4]); + dev->ed[ED_INT_4].next_ed = virt_to_bus(&dev->ed[ED_INT_2]); + dev->ed[ED_INT_2].next_ed = virt_to_bus(&dev->ed[ED_INT_1]); + + /* + * Initialize the polling table to call interrupts at the + * intended intervals. + */ + for (i = 0; i < NUM_INTS; i++) { + if (i == 0) + dev->hcca->int_table[i] = + virt_to_bus(&dev->ed[ED_INT_32]); + else if (i & 1) + dev->hcca->int_table[i] = + virt_to_bus(&dev->ed[ED_INT_16]); + else if (i & 2) + dev->hcca->int_table[i] = + virt_to_bus(&dev->ed[ED_INT_8]); + else if (i & 4) + dev->hcca->int_table[i] = + virt_to_bus(&dev->ed[ED_INT_4]); + else if (i & 8) + dev->hcca->int_table[i] = + virt_to_bus(&dev->ed[ED_INT_2]); + else if (i & 16) + dev->hcca->int_table[i] = + virt_to_bus(&dev->ed[ED_INT_1]); + } + + /* + * Tell the controller where the control and bulk lists are + */ + writel(virt_to_bus(&dev->ed[ED_CONTROL]), &ohci->regs->ed_controlhead); + writel(virt_to_bus(&dev->ed[ED_BULK]), &ohci->regs->ed_bulkhead); + + return ohci; +} /* alloc_ohci() */ + + +/* + * De-allocate all resoueces.. + */ +static void release_ohci(struct ohci *ohci) +{ + if (ohci->irq >= 0) { + free_irq(ohci->irq, ohci); + ohci->irq = -1; + } + + if (ohci->root_hub) { + /* ensure that HC is stopped before releasing the HCCA */ + writel(OHCI_USB_SUSPEND, &ohci->regs->control); + free_pages((unsigned int) ohci->root_hub->hcca, 1); + free_pages((unsigned int) ohci->root_hub, 1); + ohci->root_hub->hcca = NULL; + ohci->root_hub = NULL; + } + + /* unmap the IO address space */ + iounmap(ohci->regs); + + /* If the ohci itself were dynamic we'd free it here */ + +} /* release_ohci() */ + +/* + * USB OHCI control thread + */ +static int ohci_control_thread(void * __ohci) +{ + struct ohci *ohci = (struct ohci *)__ohci; + + /* + * I'm unfamiliar with the SMP kernel locking.. where should + * this be released? -greg + */ + lock_kernel(); + + /* + * This thread doesn't need any user-level access, + * so get rid of all of our resources.. + */ + printk("ohci_control_thread at %p\n", &ohci_control_thread); + exit_mm(current); + exit_files(current); + exit_fs(current); + + strcpy(current->comm, "ohci-control"); + + /* + * Damn the torpedoes, full speed ahead + */ + start_hc(ohci); + do { + interruptible_sleep_on(&ohci_configure); +#ifdef CONFIG_APM + if (apm_resume) { + apm_resume = 0; + start_hc(ohci); + continue; + } +#endif + ohci_check_configuration(ohci); + } while (!signal_pending(current)); + + reset_hc(ohci); + + release_ohci(ohci); + MOD_DEC_USE_COUNT; + return 0; +} /* ohci_control_thread() */ + + +#ifdef CONFIG_APM +static int handle_apm_event(apm_event_t event) +{ + static int down = 0; + + switch (event) { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + if (down) { + printk(KERN_DEBUG "usb-ohci: received extra suspend event\n"); + break; + } + down = 1; + break; + case APM_NORMAL_RESUME: + case APM_CRITICAL_RESUME: + if (!down) { + printk(KERN_DEBUG "usb-ohci: received bogus resume event\n"); + break; + } + down = 0; + if (waitqueue_active(&ohci_configure)) { + apm_resume = 1; + wake_up(&ohci_configure); + } + break; + } + return 0; +} +#endif + +/* ... */ + +/* + * Increment the module usage count, start the control thread and + * return success if the controller is good. + */ +static int found_ohci(int irq, void* mem_base) +{ + int retval; + struct ohci *ohci; + + /* Allocate the running OHCI structures */ + ohci = alloc_ohci(mem_base); + if (!ohci) + return -ENOMEM; + + printk("usb-ohci: alloc_ohci() = %p\n", ohci); + + reset_hc(ohci); + + retval = -EBUSY; + if (request_irq(irq, ohci_interrupt, SA_SHIRQ, "usb-ohci", ohci) == 0) { + int pid; + + MOD_INC_USE_COUNT; + ohci->irq = irq; + + /* fork off the handler */ + pid = kernel_thread(ohci_control_thread, ohci, + CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + if (pid >= 0) + return 0; + + MOD_DEC_USE_COUNT; + retval = pid; + } + release_ohci(ohci); + return retval; +} /* found_ohci() */ + + +/* + * If this controller is for real, map the IO memory and proceed + */ +static int init_ohci(struct pci_dev *dev) +{ + unsigned int mem_base = dev->base_address[0]; + + printk("usb-ohci: mem_base is %p\n", (void*)mem_base); + + /* If its OHCI, its memory */ + if (mem_base & PCI_BASE_ADDRESS_SPACE_IO) + return -ENODEV; + + /* Get the memory address and map it for IO */ + mem_base &= PCI_BASE_ADDRESS_MEM_MASK; + /* + * FIXME ioremap_nocache isn't implemented on all CPUs (such + * as the Alpha) [?] What should I use instead... + * + * The iounmap() is done on in release_ohci. + */ + mem_base = (unsigned int) ioremap_nocache(mem_base, 4096); + + if (!mem_base) { + printk("Error mapping OHCI memory\n"); + return -EFAULT; + } + + return found_ohci(dev->irq, (void *) mem_base); +} /* init_ohci() */ + + +#ifdef MODULE + +/* + * Clean up when unloading the module + */ +void cleanup_module(void) +{ +#ifdef CONFIG_APM + apm_unregister_callback(&handle_apm_event); +#endif +} + +#define ohci_init init_module + +#endif + + +/* TODO this should be named following Linux convention and go in pci.h */ +#define PCI_CLASS_SERIAL_USB_OHCI ((PCI_CLASS_SERIAL_USB << 8) | 0x0010) + +/* + * Search the PCI bus for an OHCI USB controller and set it up + * + * If anyone wants multiple controllers this will need to be + * updated.. Right now, it just picks the first one it finds. + */ +int ohci_init(void) +{ + int retval; + struct pci_dev *dev = NULL; + /*u8 type;*/ + + if (sizeof(struct ohci_device) > 4096) { + printk("usb-ohci: struct ohci_device to large\n"); + return -ENODEV; + } + + retval = -ENODEV; + for (;;) { + /* Find an OHCI USB controller */ + dev = pci_find_class(PCI_CLASS_SERIAL_USB_OHCI, dev); + if (!dev) + break; + + /* Verify that its OpenHCI by checking for MMIO */ + /* pci_read_config_byte(dev, PCI_CLASS_PROG, &type); + if (!type) + continue; */ + + /* Ok, set it up */ + retval = init_ohci(dev); + if (retval < 0) + continue; + + /* TODO check module params here to determine what to load */ + +/* usb_mouse_init(); */ +/* usb_kbd_init(); + hub_init(); */ +#ifdef CONFIG_APM + apm_register_callback(&handle_apm_event); +#endif + + return 0; /* no error */ + } + return retval; +} /* init_module() */ + +/* vim:sw=8 + */ diff --git a/drivers/usb/ohci.h b/drivers/usb/ohci.h new file mode 100644 index 000000000000..6c94bbc53b5c --- /dev/null +++ b/drivers/usb/ohci.h @@ -0,0 +1,301 @@ +#ifndef __LINUX_OHCI_H +#define __LINUX_OHCI_H + +/* + * Open Host Controller Interface data structures and defines. + * + * (C) Copyright 1999 Gregory P. Smith + * + * $Id: ohci.h,v 1.6 1999/04/24 22:50:06 greg Exp $ + */ + +#include +#include + +#include "usb.h" + +/* + * Each TD must be aligned on a 16-byte boundary. From the OHCI v1.0 spec + * it does not state that TDs must be contiguious in memory (due to the + * use of the next_td field). This gives us extra room at the end of a + * TD for our own driver specific data. + * + * This structure's size must be a multiple of 16 bytes. + */ +struct ohci_td { + /* OHCI Hardware fields */ + __u32 info; + __u32 cur_buf; /* Current Buffer Pointer */ + __u32 next_td; /* Next TD Pointer */ + __u32 buf_end; /* Memory Buffer End Pointer */ + + /* Driver specific fields */ + struct list_head irq_list; /* Active interrupt list */ + usb_device_irq completed; /* Completion handler routine */ + void *data; /* XXX ? */ + void *dev_id; /* XXX ? */ + __u32 ed_bus; /* bus address of original ED */ +} __attribute((aligned(32))); + +#define OHCI_TD_ROUND (1 << 18) /* buffer rounding bit */ +#define OHCI_TD_D (3 << 11) /* direction of xfer: */ +#define OHCI_TD_D_IN (2 << 11) +#define OHCI_TD_D_OUT (1 << 11) +#define OHCI_TD_D_SETUP (0) +#define td_set_dir_in(d) ((d) ? OHCI_TD_D_IN : OHCI_TD_D_OUT ) +#define td_set_dir_out(d) ((d) ? OHCI_TD_D_OUT : OHCI_TD_D_IN ) +#define OHCI_TD_IOC_DELAY (7 << 21) /* frame delay allowed before int. */ +#define OHCI_TD_IOC_OFF (OHCI_TD_IOC_DELAY) /* no interrupt on complete */ +#define OHCI_TD_DT (3 << 24) /* data toggle bits */ +#define td_force_toggle(b) (((b) | 2) << 24) +#define OHCI_TD_ERRCNT (3 << 26) /* error count */ +#define td_errorcount(td) (((td) >> 26) & 3) +#define OHCI_TD_CC (0xf << 28) /* condition code */ +#define OHCI_TD_CC_NEW (OHCI_TD_CC) /* set this on all unaccessed TDs! */ +#define td_cc_notaccessed(td) ((td >> 29) == 7) +#define td_cc_accessed(td) ((td >> 29) != 7) +#define td_cc_noerror(td) (((td) & OHCI_TD_CC) == 0) +#define td_active(td) (!td_cc_noerror((td)) && (td_errorcount((td)) < 3)) +#define td_done(td) (td_cc_noerror((td)) || (td_errorcount((td)) == 3)) + +/* + * The endpoint descriptors also requires 16-byte alignment + */ +struct ohci_ed { + /* OHCI hardware fields */ + __u32 status; + __u32 tail_td; /* TD Queue tail pointer */ + __u32 head_td; /* TD Queue head pointer */ + __u32 next_ed; /* Next ED */ +} __attribute((aligned(16))); + +#define OHCI_ED_SKIP (1 << 14) +#define OHCI_ED_MPS (0x7ff << 16) +/* FIXME: should cap at the USB max packet size [0x4ff] */ +#define ed_set_maxpacket(s) (((s) << 16) & OHCI_ED_MPS) +#define OHCI_ED_F_NORM (0) +#define OHCI_ED_F_ISOC (1 << 15) +#define ed_set_type_isoc(i) ((i) ? OHCI_ED_F_ISOC : OHCI_ED_F_NORM) +#define OHCI_ED_S_LOW (1 << 13) +#define OHCI_ED_S_HIGH (0) +#define ed_set_speed(s) ((s) ? OHCI_ED_S_LOW : OHCI_ED_S_HIGH) +#define OHCI_ED_D (3 << 11) +#define OHCI_ED_D_IN (2 << 11) +#define OHCI_ED_D_OUT (1 << 11) +#define ed_set_dir_in(d) ((d) ? OHCI_ED_D_IN : OHCI_ED_D_OUT) +#define ed_set_dir_out(d) ((d) ? OHCI_ED_D_OUT : OHCI_ED_D_IN) +#define OHCI_ED_EN (0xf << 7) +#define OHCI_ED_FA (0x7f) + + +/* NOTE: bits 27-31 of the status dword are reserved for the driver */ +/* + * We'll use this status flag for the non-predefined EDs to mark if + * they're in use or not. + * + * FIXME: unimplemented (needed?) + */ +#define ED_USED (1 << 31) + +/* + * The HCCA (Host Controller Communications Area) is a 256 byte + * structure defined in the OHCI spec. that the host controller is + * told the base address of. It must be 256-byte aligned. + */ +#define NUM_INTS 32 /* part of the OHCI standard */ +struct ohci_hcca { + __u32 int_table[NUM_INTS]; /* Interrupt ED table */ + __u16 frame_no; /* current frame number */ + __u16 pad1; /* set to 0 on each frame_no change */ + __u32 donehead; /* info returned for an interrupt */ + u8 reserved_for_hc[116]; +} __attribute((aligned(256))); + +/* + * The TD entries here are pre-allocated as Linus did with his simple + * UHCI implementation. With the current state of this driver that + * shouldn't be a problem. However if someone ever connects 127 + * supported devices to this driver and tries to use them all at once: + * a) They're insane! + * b) They should code in dynamic allocation + */ +struct ohci; + +/* + * Warning: These constants must not be so large as to cause the + * ohci_device structure to exceed one 4096 byte page. Or "weird + * things will happen" as the alloc_ohci() function assumes that + * its less than one page. (FIXME) + */ +#define NUM_TDS 32 /* num of preallocated transfer descriptors */ +#define DATA_BUF_LEN 16 /* num of unsigned long's for the data buf */ + +/* + * For this "simple" driver we only support a single ED for each + * polling rate. + * + * Later on this driver should be extended to use a full tree of EDs + * so that there can be 32 different 32ms polling frames, etc. + * Individual devices shouldn't need as many as the root hub in that + * case; complicating how things are done at the moment. + * + * Bulk and Control transfers hang off of their own ED lists. + */ +#define NUM_EDS 16 /* num of preallocated endpoint descriptors */ + +#define ohci_to_usb(ohci) ((ohci)->usb) +#define usb_to_ohci(usb) ((struct ohci_device *)(usb)->hcpriv) + +/* The usb_device must be first! */ +struct ohci_device { + struct usb_device *usb; + + struct ohci *ohci; + struct ohci_hcca *hcca; /* OHCI mem. mapped IO area */ + + struct ohci_ed ed[NUM_EDS]; /* Endpoint Descriptors */ + struct ohci_td td[NUM_TDS]; /* Transfer Descriptors */ + + unsigned long data[DATA_BUF_LEN]; +}; + +/* .... */ + +#define ED_INT_1 0 +#define ED_INT_2 1 +#define ED_INT_4 2 +#define ED_INT_8 3 +#define ED_INT_16 4 +#define ED_INT_32 5 +#define ED_CONTROL 6 +#define ED_BULK 7 +#define ED_ISO ED_INT_1 /* same as 1ms interrupt queue */ +#define ED_FIRST_AVAIL 8 /* first non-reserved ED */ + +/* + * Given a period p in ms, convert it to the closest endpoint + * interrupt frequency; rounding down. I'm sure many feel that this + * is a gross macro. Feel free to toss it for actual code. + */ +#define ms_to_ed_int(p) \ + ((p >= 32) ? ED_INT_32 : \ + ((p & 16) ? ED_INT_16 : \ + ((p & 8) ? ED_INT_8 : \ + ((p & 4) ? ED_INT_4 : \ + ((p & 2) ? ED_INT_2 : \ + ED_INT_1))))) /* hmm.. scheme or lisp anyone? */ + +/* + * This is the maximum number of root hub ports. I don't think we'll + * ever see more than two as that's the space available on an ATX + * motherboard's case, but it could happen. The OHCI spec allows for + * up to 15... (which is insane!) + * + * Although I suppose several "ports" could be connected directly to + * internal laptop devices such as a keyboard, mouse, camera and + * serial/parallel ports. hmm... That'd be neat. + */ +#define MAX_ROOT_PORTS 15 /* maximum OHCI root hub ports */ + +/* + * This is the structure of the OHCI controller's memory mapped I/O + * region. This is Memory Mapped I/O. You must use the readl() and + * writel() macros defined in asm/io.h to access these!! + */ +struct ohci_regs { + /* control and status registers */ + __u32 revision; + __u32 control; + __u32 cmdstatus; + __u32 intrstatus; + __u32 intrenable; + __u32 intrdisable; + /* memory pointers */ + __u32 hcca; + __u32 ed_periodcurrent; + __u32 ed_controlhead; + __u32 ed_controlcurrent; + __u32 ed_bulkhead; + __u32 ed_bulkcurrent; + __u32 current_donehead; /* The driver should get this from the HCCA */ + /* frame counters */ + __u32 fminterval; + __u32 fmremaining; + __u32 fmnumber; + __u32 periodicstart; + __u32 lsthresh; + /* Root hub ports */ + struct ohci_roothub_regs { + __u32 a; + __u32 b; + __u32 status; + __u32 portstatus[MAX_ROOT_PORTS]; + } roothub; +} __attribute((aligned(32))); + +/* + * Read a MMIO register and re-write it after ANDing with (m) + */ +#define writel_mask(m, a) writel( (readl((__u32)(a))) & (__u32)(m), (__u32)(a) ) + +/* + * Read a MMIO register and re-write it after ORing with (b) + */ +#define writel_set(b, a) writel( (readl((__u32)(a))) | (__u32)(b), (__u32)(a) ) + + +#define PORT_CCS (1) /* port current connect status */ +#define PORT_PES (1 << 1) /* port enable status */ +#define PORT_PSS (1 << 2) /* port suspend status */ +#define PORT_POCI (1 << 3) /* port overcurrent indicator */ +#define PORT_PRS (1 << 4) /* port reset status */ +#define PORT_PPS (1 << 8) /* port power status */ +#define PORT_LSDA (1 << 9) /* port low speed dev. attached */ +#define PORT_CSC (1 << 16) /* port connect status change */ +#define PORT_PESC (1 << 17) /* port enable status change */ +#define PORT_PSSC (1 << 18) /* port suspend status change */ +#define PORT_OCIC (1 << 19) /* port over current indicator chg */ +#define PORT_PRSC (1 << 20) /* port reset status change */ + + +/* + * Interrupt register masks + */ +#define OHCI_INTR_SO (1) +#define OHCI_INTR_WDH (1 << 1) +#define OHCI_INTR_SF (1 << 2) +#define OHCI_INTR_RD (1 << 3) +#define OHCI_INTR_UE (1 << 4) +#define OHCI_INTR_FNO (1 << 5) +#define OHCI_INTR_RHSC (1 << 6) +#define OHCI_INTR_OC (1 << 30) +#define OHCI_INTR_MIE (1 << 31) + +/* + * Control register masks + */ +#define OHCI_USB_OPER (2 << 6) +#define OHCI_USB_SUSPEND (3 << 6) + +/* + * This is the full ohci controller description + * + * Note how the "proper" USB information is just + * a subset of what the full implementation needs. (Linus) + */ +struct ohci { + int irq; + struct ohci_regs *regs; /* OHCI controller's memory */ + struct usb_bus *bus; + struct ohci_device *root_hub; /* Root hub & controller */ + struct list_head interrupt_list; /* List of interrupt active TDs for this OHCI */ +}; + +/* Debugging code */ +void show_ed(struct ohci_ed *ed); +void show_td(struct ohci_td *td); +void show_status(struct ohci *ohci); + +#endif +/* vim:sw=8 + */ diff --git a/drivers/usb/restart b/drivers/usb/restart new file mode 100644 index 000000000000..e90e8464a557 --- /dev/null +++ b/drivers/usb/restart @@ -0,0 +1,35 @@ +#!/bin/sh + +ME=`basename $0` + +#UMOD=`lsmod | grep '^bp-mouse' | grep -v grep` +#if test "$UMOD"; then +# echo "$ME: removing bp-mouse.o" +# if ! rmmod bp-mouse; then +# echo "$ME: cannot remove bp-mouse.o" +# exit 1 +# fi +#fi + +UPID=`ps aux | grep uhci-control | grep -v grep | awk '{print $2}'` +if test "$UPID"; then + echo "$ME: killing $UPID" + kill $UPID +fi + +UMOD=`lsmod | grep '^usb-uhci' | grep -v grep` +if test "$UMOD"; then + echo "$ME: removing usb-uhci.o" + sleep 1 + if ! rmmod usb-uhci; then + echo "$ME: cannot remove usb-uhci.o" + exit 1 + fi +fi + +dmesg -c > /dev/null + +echo "$ME: starting usb-uhci.o" +insmod -m usb-uhci.o > usb-uhci.map +#echo "$ME: starting bp-mouse.o" +#insmod -m bp-mouse.o > bp-mouse.map diff --git a/drivers/usb/stopusb b/drivers/usb/stopusb new file mode 100644 index 000000000000..ffd42306b299 --- /dev/null +++ b/drivers/usb/stopusb @@ -0,0 +1,8 @@ +#!/bin/sh + +killall uhci-control +killall khubd + +sleep 1 + +rmmod usb-uhci diff --git a/drivers/usb/uhci-debug.c b/drivers/usb/uhci-debug.c new file mode 100644 index 000000000000..fd2aba6da44a --- /dev/null +++ b/drivers/usb/uhci-debug.c @@ -0,0 +1,168 @@ +/* + * UHCI-specific debugging code. Invaluable when something + * goes wrong, but don't get in my face. + * + * (C) Copyright 1999 Linus Torvalds + */ + +#include +#include + +#include "uhci.h" + +void show_td(struct uhci_td * td) +{ + printk("%08x ", td->link); + printk("%se%d %s%s%s%s%s%s%s%s%s%sLength=%x ", + ((td->status >> 29) & 1) ? "SPD " : "", + ((td->status >> 27) & 3), + ((td->status >> 26) & 1) ? "LS " : "", + ((td->status >> 25) & 1) ? "IOS " : "", + ((td->status >> 24) & 1) ? "IOC " : "", + ((td->status >> 23) & 1) ? "Active " : "", + ((td->status >> 22) & 1) ? "Stalled " : "", + ((td->status >> 21) & 1) ? "DataBufErr " : "", + ((td->status >> 20) & 1) ? "Babble " : "", + ((td->status >> 19) & 1) ? "NAK " : "", + ((td->status >> 18) & 1) ? "CRC/Timeo " : "", + ((td->status >> 17) & 1) ? "BitStuff " : "", + td->status & 0x7ff); + printk("MaxLen=%x %sEndPt=%x Dev=%x, PID=%x ", + td->info >> 21, + ((td->info >> 19) & 1) ? "DT " : "", + (td->info >> 15) & 15, + (td->info >> 8) & 127, + td->info & 0xff); + printk("(buf=%08x)\n", td->buffer); +} + +static void show_sc(int port, unsigned short status) +{ + printk(" stat%d = %04x %s%s%s%s%s%s%s%s\n", + port, + status, + (status & (1 << 12)) ? " PortSuspend" : "", + (status & (1 << 9)) ? " PortReset" : "", + (status & (1 << 8)) ? " LowSpeed" : "", + (status & 0x40) ? " ResumeDetect" : "", + (status & 0x08) ? " EnableChange" : "", + (status & 0x04) ? " PortEnabled" : "", + (status & 0x02) ? " ConnectChange" : "", + (status & 0x01) ? " PortConnected" : ""); +} + +void show_status(struct uhci *uhci) +{ + unsigned int io_addr = uhci->io_addr; + unsigned short usbcmd, usbstat, usbint, usbfrnum; + unsigned int flbaseadd; + unsigned char sof; + unsigned short portsc1, portsc2; + + usbcmd = inw(io_addr + 0); + usbstat = inw(io_addr + 2); + usbint = inw(io_addr + 4); + usbfrnum = inw(io_addr + 6); + flbaseadd = inl(io_addr + 8); + sof = inb(io_addr + 12); + portsc1 = inw(io_addr + 16); + portsc2 = inw(io_addr + 18); + + printk(" usbcmd = %04x %s%s%s%s%s%s%s%s\n", + usbcmd, + (usbcmd & 0x80) ? " Maxp64" : " Maxp32", + (usbcmd & 0x40) ? " CF" : "", + (usbcmd & 0x20) ? " SWDBG" : "", + (usbcmd & 0x10) ? " FGR" : "", + (usbcmd & 0x08) ? " EGSM" : "", + (usbcmd & 0x04) ? " GRESET" : "", + (usbcmd & 0x02) ? " HCRESET" : "", + (usbcmd & 0x01) ? " RS" : ""); + + printk(" usbstat = %04x %s%s%s%s%s%s\n", + usbstat, + (usbstat & 0x20) ? " HCHalted" : "", + (usbstat & 0x10) ? " HostControllerProcessError" : "", + (usbstat & 0x08) ? " HostSystemError" : "", + (usbstat & 0x04) ? " ResumeDetect" : "", + (usbstat & 0x02) ? " USBError" : "", + (usbstat & 0x01) ? " USBINT" : ""); + + printk(" usbint = %04x\n", usbint); + printk(" usbfrnum = (%d)%03x\n", (usbfrnum >> 10) & 1, 0xfff & (4*(unsigned int)usbfrnum)); + printk(" flbaseadd = %08x\n", flbaseadd); + printk(" sof = %02x\n", sof); + show_sc(1, portsc1); + show_sc(2, portsc2); +} + +#define uhci_link_to_qh(x) ((struct uhci_qh *) uhci_link_to_td(x)) + +struct uhci_td * uhci_link_to_td(unsigned int link) +{ + if (link & 1) + return NULL; + + return bus_to_virt(link & ~15); +} + +void show_queue(struct uhci_qh *qh) +{ + struct uhci_td *td; + int i = 0; + +#if 0 + printk(" link = %p, element = %p\n", qh->link, qh->element); +#endif + if(!qh->element) { + printk(" td 0 = NULL\n"); + return; + } + + for(td = uhci_link_to_td(qh->element); td; + td = uhci_link_to_td(td->link)) { + printk(" td %d = %p\n", i++, td); + printk(" "); + show_td(td); + } +} + +int is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh) +{ + int j; + + for (j = 0; j < UHCI_MAXQH; j++) + if (qh == uhci->root_hub->qh + j) + return 1; + + return 0; +} + +static const char *qh_names[] = {"isochronous", "interrupt2", "interrupt4", + "interrupt8", "interrupt16", "interrupt32", + "interrupt64", "interrupt128", "interrupt256", + "control", "bulk0", "bulk1", "bulk2", "bulk3", + "unused", "unused"}; + +void show_queues(struct uhci *uhci) +{ + int i; + struct uhci_qh *qh; + + for (i = 0; i < UHCI_MAXQH; ++i) { + printk(" %s:\n", qh_names[i]); +#if 0 + printk(" qh #%d, %p\n", i, virt_to_bus(uhci->root_hub->qh + i)); + show_queue(uhci->root_hub->qh + i); +#endif + + qh = uhci_link_to_qh(uhci->root_hub->qh[i].link); + for (; qh; qh = uhci_link_to_qh(qh->link)) { + if (is_skeleton_qh(uhci, qh)) + break; + + show_queue(qh); + } + } +} + diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c new file mode 100644 index 000000000000..244cdd9b237b --- /dev/null +++ b/drivers/usb/uhci.c @@ -0,0 +1,1195 @@ +/* + * Universal Host Controller Interface driver for USB. + * + * (C) Copyright 1999 Linus Torvalds + * + * Intel documents this fairly well, and as far as I know there + * are no royalties or anything like that, but even so there are + * people who decided that they want to do the same thing in a + * completely different way. + * + * Oh, well. The intel version is the more common by far. As such, + * that's the one I care about right now. + * + * WARNING! The USB documentation is downright evil. Most of it + * is just crap, written by a committee. You're better off ignoring + * most of it, the important stuff is: + * - the low-level protocol (fairly simple but lots of small details) + * - working around the horridness of the rest + */ + +/* 4/4/1999 added data toggle for interrupt pipes -keryan */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "uhci.h" +#include "inits.h" + +#ifdef CONFIG_APM +#include +static int handle_apm_event(apm_event_t event); +static int apm_resume = 0; +#endif + +#define compile_assert(x) do { switch (0) { case 1: case !(x): } } while (0) + +int usb_mouse_init(void); +int hub_init(void); + +static struct wait_queue *uhci_configure = NULL; + +/* + * Return the result of a TD.. + */ +static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td) +{ + unsigned int status; + + status = (td->status >> 16) & 0xff; + + /* Some debugging code */ + if (status) { + int i = 10; + struct uhci_td *tmp = dev->control_td; + printk("uhci_td_result() failed with status %d\n", status); + show_status(dev->uhci); + do { + show_td(tmp); + tmp++; + if (!--i) + break; + } while (tmp <= td); + } + return status; +} + +/* + * Inserts a td into qh list at the top. + * + * Careful about atomicity: even on UP this + * requires a locked access due to the concurrent + * DMA engine. + * + * NOTE! This assumes that first->last is a valid + * list of TD's with the proper backpointers set + * up and all.. + */ +static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct uhci_td *first, struct uhci_td *last) +{ + unsigned int link = qh->element; + unsigned int new = 4 | virt_to_bus(first); + + for (;;) { + unsigned char success; + + last->link = link; + first->backptr = &qh->element; + asm volatile("lock ; cmpxchg %4,%2 ; sete %0" + :"=q" (success), "=a" (link) + :"m" (qh->element), "1" (link), "r" (new) + :"memory"); + if (success) { + /* Was there a successor entry? Fix it's backpointer.. */ + if ((link & 1) == 0) { + struct uhci_td *next = bus_to_virt(link & ~15); + next->backptr = &last->link; + } + break; + } + } +} + +static inline void uhci_insert_td_in_qh(struct uhci_qh *qh, struct uhci_td *td) +{ + uhci_insert_tds_in_qh(qh, td, td); +} + +static void uhci_insert_qh(struct uhci_qh *qh, struct uhci_qh *newqh) +{ + newqh->link = qh->link; + qh->link = virt_to_bus(newqh) | 2; +} + +static void uhci_remove_qh(struct uhci_qh *qh, struct uhci_qh *remqh) +{ + unsigned int remphys = virt_to_bus(remqh); + struct uhci_qh *lqh = qh; + + while ((lqh->link & ~0xF) != remphys) { + if (lqh->link & 1) + break; + + lqh = bus_to_virt(lqh->link & ~0xF); + } + + if (lqh->link & 1) { + printk("couldn't find qh in chain!\n"); + return; + } + + lqh->link = remqh->link; +} + +/* + * Removes td from qh if present. + * + * NOTE! We keep track of both forward and back-pointers, + * so this should be trivial, right? + * + * Wrong. While all TD insert/remove operations are synchronous + * on the CPU, the UHCI controller can (and does) play with the + * very first forward pointer. So we need to validate the backptr + * before we change it, so that we don't by mistake reset the QH + * head to something old. + */ +static void uhci_remove_td(struct uhci_td *td) +{ + unsigned int *backptr = td->backptr; + unsigned int link = td->link; + unsigned int me; + + if (!backptr) + return; + + td->backptr = NULL; + + /* + * This is the easy case: the UHCI will never change "td->link", + * so we can always just look at that and fix up the backpointer + * of any next element.. + */ + if (!(link & 1)) { + struct uhci_td *next = bus_to_virt(link & ~15); + next->backptr = backptr; + } + + /* + * The nasty case is "backptr->next", which we need to + * update to "link" _only_ if "backptr" still points + * to us (it may not: maybe backptr is a QH->element + * pointer and the UHCI has changed the value). + */ + me = virt_to_bus(td) | (0xe & *backptr); + asm volatile("lock ; cmpxchg %0,%1" + : + :"r" (link), "m" (*backptr), "a" (me) + :"memory"); +} + +static struct uhci_qh *uhci_qh_allocate(struct uhci_device *dev) +{ + struct uhci_qh *qh; + int inuse; + + qh = dev->qh; + for (; (inuse = test_and_set_bit(0, &qh->inuse)) != 0 && qh < &dev->qh[UHCI_MAXQH]; qh++) + ; + + if (!inuse) + return(qh); + + printk("ran out of qh's for dev %p\n", dev); + return(NULL); +} + +static void uhci_qh_deallocate(struct uhci_qh *qh) +{ + if (qh->element != 1) + printk("qh %p leaving dangling entries? (%X)\n", qh, qh->element); + + qh->element = 1; + qh->link = 1; + + clear_bit(0, &qh->inuse); +} + +static struct uhci_td *uhci_td_allocate(struct uhci_device *dev) +{ + struct uhci_td *td; + int inuse; + + td = dev->td; + for (; (inuse = test_and_set_bit(0, &td->inuse)) != 0 && td < &dev->td[UHCI_MAXTD]; td++) + ; + + if (!inuse) + return(td); + + printk("ran out of td's for dev %p\n", dev); + return(NULL); +} + +/* + * This MUST only be called when it has been removed from a QH already (or + * the QH has been removed from the skeleton + */ +static void uhci_td_deallocate(struct uhci_td *td) +{ + td->link = 1; + + clear_bit(0, &td->inuse); +} + +/* + * UHCI interrupt list operations.. + */ +static spinlock_t irqlist_lock = SPIN_LOCK_UNLOCKED; + +static void uhci_add_irq_list(struct uhci *uhci, struct uhci_td *td, usb_device_irq completed, void *dev_id) +{ + unsigned long flags; + + td->completed = completed; + td->dev_id = dev_id; + + spin_lock_irqsave(&irqlist_lock, flags); + list_add(&td->irq_list, &uhci->interrupt_list); + spin_unlock_irqrestore(&irqlist_lock, flags); +} + +static void uhci_remove_irq_list(struct uhci_td *td) +{ + unsigned long flags; + + spin_lock_irqsave(&irqlist_lock, flags); + list_del(&td->irq_list); + spin_unlock_irqrestore(&irqlist_lock, flags); +} + +/* + * Request a interrupt handler.. + */ +static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id) +{ + struct uhci_device *dev = usb_to_uhci(usb_dev); + struct uhci_td *td = uhci_td_allocate(dev); + struct uhci_qh *interrupt_qh = uhci_qh_allocate(dev); + + unsigned int destination, status; + + /* Destination: pipe destination with INPUT */ + destination = (pipe & 0x0007ff00) | 0x69; + + /* Status: slow/fast, Interrupt, Active, Short Packet Detect Infinite Errors */ + status = (pipe & (1 << 26)) | (1 << 24) | (1 << 23) | (1 << 29) | (0 << 27); + + if(interrupt_qh->element != 1) + printk("interrupt_qh->element = 0x%x\n", + interrupt_qh->element); + + td->link = 1; + td->status = status; /* In */ + td->info = destination | (7 << 21); /* 8 bytes of data */ + td->buffer = virt_to_bus(dev->data); + td->qh = interrupt_qh; + interrupt_qh->skel = &dev->uhci->root_hub->skel_int8_qh; + + uhci_add_irq_list(dev->uhci, td, handler, dev_id); + + uhci_insert_td_in_qh(interrupt_qh, td); + + /* Add it into the skeleton */ + uhci_insert_qh(&dev->uhci->root_hub->skel_int8_qh, interrupt_qh); + return 0; +} + +/* + * Control thread operations: we just mark the last TD + * in a control thread as an interrupt TD, and wake up + * the front-end on completion. + * + * We need to remove the TD from the lists (both interrupt + * list and TD lists) by hand if something bad happens! + */ +static struct wait_queue *control_wakeup; + +static int uhci_control_completed(int status, void *buffer, void *dev_id) +{ + wake_up(&control_wakeup); + return 0; /* Don't re-instate */ +} + +/* td points to the last td in the list, which interrupts on completion */ +static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last) +{ + struct wait_queue wait = { current, NULL }; + struct uhci_qh *ctrl_qh = uhci_qh_allocate(dev); + struct uhci_td *curtd; + + current->state = TASK_UNINTERRUPTIBLE; + add_wait_queue(&control_wakeup, &wait); + + uhci_add_irq_list(dev->uhci, last, uhci_control_completed, NULL); + + /* FIXME: This is kinda kludged */ + /* Walk the TD list and update the QH pointer */ + { + int maxcount = 100; + + curtd = first; + do { + curtd->qh = ctrl_qh; + if (curtd->link & 1) + break; + + curtd = bus_to_virt(curtd->link & ~0xF); + if (!--maxcount) { + printk("runaway tds!\n"); + break; + } + } while (1); + } + + uhci_insert_tds_in_qh(ctrl_qh, first, last); + + /* Add it into the skeleton */ + uhci_insert_qh(&dev->uhci->root_hub->skel_control_qh, ctrl_qh); + + schedule_timeout(HZ/10); + + remove_wait_queue(&control_wakeup, &wait); + + /* Clean up in case it failed.. */ + uhci_remove_irq_list(last); + +#if 0 + printk("Looking for tds [%p, %p]\n", dev->control_td, td); +#endif + + /* Remove it from the skeleton */ + uhci_remove_qh(&dev->uhci->root_hub->skel_control_qh, ctrl_qh); + + uhci_qh_deallocate(ctrl_qh); + + return uhci_td_result(dev, last); +} + +/* + * Send or receive a control message on a pipe. + * + * Note that the "pipe" structure is set up to map + * easily to the uhci destination fields. + * + * A control message is built up from three parts: + * - The command itself + * - [ optional ] data phase + * - Status complete phase + * + * The data phase can be an arbitrary number of TD's + * although we currently had better not have more than + * 29 TD's here (we have 31 TD's allocated for control + * operations, and two of them are used for command and + * status). + * + * 29 TD's is a minimum of 232 bytes worth of control + * information, that's just ridiculously high. Most + * control messages have just a few bytes of data. + */ +static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void *cmd, void *data, int len) +{ + struct uhci_device *dev = usb_to_uhci(usb_dev); + struct uhci_td *first, *td, *prevtd; + unsigned long destination, status; + int ret; + + if (len > usb_maxpacket(usb_dev->maxpacketsize) * 29) + printk("Warning, too much data for a control packet, crashing\n"); + + first = td = uhci_td_allocate(dev); + + /* The "pipe" thing contains the destination in bits 8--18, 0x2D is SETUP */ + destination = (pipe & 0x0007ff00) | 0x2D; + + /* Status: slow/fast, Active, Short Packet Detect Three Errors */ + status = (pipe & (1 << 26)) | (1 << 23) | (1 << 29) | (3 << 27); + + /* + * Build the TD for the control request + */ + td->status = status; /* Try forever */ + td->info = destination | (7 << 21); /* 8 bytes of data */ + td->buffer = virt_to_bus(cmd); + + /* + * If direction is "send", change the frame from SETUP (0x2D) + * to OUT (0xE1). Else change it from SETUP to IN (0x69) + */ + destination ^= (0x2D ^ 0x69); /* SETUP -> IN */ + if (usb_pipeout(pipe)) + destination ^= (0xE1 ^ 0x69); /* IN -> OUT */ + + prevtd = td; + td = uhci_td_allocate(dev); + prevtd->link = 4 | virt_to_bus(td); + + /* + * Build the DATA TD's + */ + while (len > 0) { + /* Build the TD for control status */ + int pktsze = len; + int maxsze = usb_maxpacket(pipe); + + if (pktsze > maxsze) + pktsze = maxsze; + + /* Alternate Data0/1 (start with Data1) */ + destination ^= 1 << 19; + + td->status = status; /* Status */ + td->info = destination | ((pktsze-1) << 21); /* pktsze bytes of data */ + td->buffer = virt_to_bus(data); + td->backptr = &prevtd->link; + + prevtd = td; + td = uhci_td_allocate(dev); + prevtd->link = 4 | virt_to_bus(td); /* Update previous TD */ + + data += maxsze; + len -= maxsze; + } + + /* + * Build the final TD for control status + */ + destination ^= (0xE1 ^ 0x69); /* OUT -> IN */ + destination |= 1 << 19; /* End in Data1 */ + + td->link = 1; /* Terminate */ + td->status = status | (1 << 24); /* IOC */ + td->info = destination | (0x7ff << 21); /* 0 bytes of data */ + td->buffer = 0; + td->backptr = &prevtd->link; + + /* Start it up.. */ + ret = uhci_run_control(dev, first, td); + + { + int maxcount = 100; + struct uhci_td *curtd = first; + unsigned int nextlink; + + do { + nextlink = curtd->link; + uhci_remove_td(curtd); + uhci_td_deallocate(curtd); + if (nextlink & 1) /* Tail? */ + break; + + curtd = bus_to_virt(nextlink & ~0xF); + if (!--maxcount) { + printk("runaway td's!?\n"); + break; + } + } while (1); + } + + return ret; +} + +static struct usb_device *uhci_usb_allocate(struct usb_device *parent) +{ + struct usb_device *usb_dev; + struct uhci_device *dev; + int i; + + usb_dev = kmalloc(sizeof(*usb_dev), GFP_KERNEL); + if (!usb_dev) + return NULL; + + memset(usb_dev, 0, sizeof(*usb_dev)); + + dev = kmalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) { + kfree(usb_dev); + return NULL; + } + + /* Initialize "dev" */ + memset(dev, 0, sizeof(*dev)); + + usb_dev->hcpriv = dev; + dev->usb = usb_dev; + + usb_dev->parent = parent; + + if (parent) { + usb_dev->bus = parent->bus; + dev->uhci = usb_to_uhci(parent)->uhci; + } + + /* Reset the QH's and TD's */ + for (i = 0; i < UHCI_MAXQH; i++) { + dev->qh[i].link = 1; + dev->qh[i].element = 1; + dev->qh[i].inuse = 0; + } + + for (i = 0; i < UHCI_MAXTD; i++) { + dev->td[i].link = 1; + dev->td[i].inuse = 0; + } + + return usb_dev; +} + +static int uhci_usb_deallocate(struct usb_device *usb_dev) +{ + struct uhci_device *dev = usb_to_uhci(usb_dev); + int i; + + /* There are UHCI_MAXTD preallocated tds */ + for (i = 0; i < UHCI_MAXTD; ++i) { + struct uhci_td *td = dev->td + i; + + /* And remove it from the irq list, if it's active */ + if (td->status & (1 << 23)) + uhci_remove_irq_list(td); + + if (td->inuse) + uhci_remove_td(td); + } + + /* Remove the td from any queues */ + for (i = 0; i < UHCI_MAXQH; ++i) { + struct uhci_qh *qh = dev->qh + i; + + if (qh->inuse) + uhci_remove_qh(qh->skel, qh); + } + + kfree(dev); + kfree(usb_dev); + + return 0; +} + +struct usb_operations uhci_device_operations = { + uhci_usb_allocate, + uhci_usb_deallocate, + uhci_control_msg, + uhci_request_irq, +}; + +/* + * This is just incredibly fragile. The timings must be just + * right, and they aren't really documented very well. + * + * Note the short delay between disabling reset and enabling + * the port.. + */ +static void uhci_reset_port(unsigned int port) +{ + unsigned short status; + + status = inw(port); + outw(status | USBPORTSC_PR, port); /* reset port */ + wait_ms(10); + outw(status & ~USBPORTSC_PR, port); + udelay(5); + + status = inw(port); + outw(status | USBPORTSC_PE, port); /* enable port */ + wait_ms(10); + + status = inw(port); + if(!(status & USBPORTSC_PE)) { + outw(status | USBPORTSC_PE, port); /* one more try at enabling port */ + wait_ms(50); + } + +} + + +/* + * This gets called if the connect status on the root + * hub (and the root hub only) changes. + */ +static void uhci_connect_change(struct uhci *uhci, unsigned int port, unsigned int nr) +{ + struct usb_device *usb_dev; + struct uhci_device *dev; + unsigned short status; + + printk("uhci_connect_change: called for %d\n", nr); + + /* + * Even if the status says we're connected, + * the fact that the status bits changed may + * that we got disconnected and then reconnected. + * + * So start off by getting rid of any old devices.. + */ + usb_disconnect(&uhci->root_hub->usb->children[nr]); + + status = inw(port); + + /* If we have nothing connected, then clear change status and disable the port */ + status = (status & ~USBPORTSC_PE) | USBPORTSC_PEC; + if (!(status & USBPORTSC_CCS)) { + outw(status, port); + return; + } + + /* + * Ok, we got a new connection. Allocate a device to it, + * and find out what it wants to do.. + */ + usb_dev = uhci_usb_allocate(uhci->root_hub->usb); + dev = usb_dev->hcpriv; + + dev->uhci = uhci; + + usb_connect(usb_dev); + + uhci->root_hub->usb->children[nr] = usb_dev; + + wait_ms(200); /* wait for powerup */ + uhci_reset_port(port); + + /* Get speed information */ + usb_dev->slow = (inw(port) & USBPORTSC_LSDA) ? 1 : 0; + + /* + * Ok, all the stuff specific to the root hub has been done. + * The rest is generic for any new USB attach, regardless of + * hub type. + */ + usb_new_device(usb_dev); +} + +/* + * This gets called when the root hub configuration + * has changed. Just go through each port, seeing if + * there is something interesting happening. + */ +static void uhci_check_configuration(struct uhci *uhci) +{ + unsigned int io_addr = uhci->io_addr + USBPORTSC1; + int maxchild = uhci->root_hub->usb->maxchild; + int nr = 0; + + do { + unsigned short status = inw(io_addr); + + if (status & USBPORTSC_CSC) + uhci_connect_change(uhci, io_addr, nr); + + nr++; io_addr += 2; + } while (nr < maxchild); +} + +static void uhci_interrupt_notify(struct uhci *uhci) +{ + struct list_head *head = &uhci->interrupt_list; + struct list_head *tmp; + + spin_lock(&irqlist_lock); + tmp = head->next; + while (tmp != head) { + struct uhci_td *td = list_entry(tmp, struct uhci_td, irq_list); + struct list_head *next; + + next = tmp->next; + + if (!(td->status & (1 << 23))) { /* No longer active? */ + /* remove from IRQ list */ + __list_del(tmp->prev, next); + INIT_LIST_HEAD(tmp); + if (td->completed(td->status, bus_to_virt(td->buffer), td->dev_id)) { + struct uhci_qh *interrupt_qh = td->qh; + + list_add(&td->irq_list, &uhci->interrupt_list); + td->info ^= 1 << 19; /* toggle between data0 and data1 */ + td->status = (td->status & 0x2f000000) | (1 << 23) | (1 << 24); /* active */ + + /* Remove then readd? Is that necessary */ + uhci_remove_td(td); + uhci_insert_td_in_qh(interrupt_qh, td); + } + /* If completed wants to not reactivate, then it's */ + /* responsible for free'ing the TD's and QH's */ + /* or another function (such as run_control) */ + } + tmp = next; + } + spin_unlock(&irqlist_lock); +} + +/* + * Check port status - Connect Status Change - for + * each of the attached ports (defaults to two ports, + * but at least in theory there can be more of them). + * + * Wake up the configurator if something happened, we + * can't really do much at interrupt time. + */ +static void uhci_root_hub_events(struct uhci *uhci, unsigned int io_addr) +{ + if (waitqueue_active(&uhci_configure)) { + int ports = uhci->root_hub->usb->maxchild; + io_addr += USBPORTSC1; + do { + if (inw(io_addr) & USBPORTSC_CSC) { + wake_up(&uhci_configure); + return; + } + io_addr += 2; + } while (--ports > 0); + } +} + +static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs) +{ + struct uhci *uhci = __uhci; + unsigned int io_addr = uhci->io_addr; + unsigned short status; + + /* + * Read the interrupt status, and write it back to clear the interrupt cause + */ + status = inw(io_addr + USBSTS); + outw(status, io_addr + USBSTS); + + /* Walk the list of pending TD's to see which ones completed.. */ + uhci_interrupt_notify(uhci); + + /* Check if there are any events on the root hub.. */ + uhci_root_hub_events(uhci, io_addr); +} + +/* + * We init one packet, and mark it just IOC and _not_ + * active. Which will result in no actual USB traffic, + * but _will_ result in an interrupt every second. + * + * Which is exactly what we want. + */ +static void uhci_init_ticktd(struct uhci *uhci) +{ + struct uhci_device *dev = uhci->root_hub; + struct uhci_td *td = uhci_td_allocate(dev); + + td->link = 1; + td->status = (1 << 24); /* interrupt on completion */ + td->info = (15 << 21) | 0x7f69; /* (ignored) input packet, 16 bytes, device 127 */ + td->buffer = 0; + td->qh = NULL; + + uhci->fl->frame[0] = virt_to_bus(td); +} + +static void reset_hc(struct uhci *uhci) +{ + unsigned int io_addr = uhci->io_addr; + + /* Global reset for 50ms */ + outw(USBCMD_GRESET, io_addr+USBCMD); + wait_ms(50); + outw(0, io_addr+USBCMD); + wait_ms(10); +} + +static void start_hc(struct uhci *uhci) +{ + unsigned int io_addr = uhci->io_addr; + int timeout = 1000; + + uhci_init_ticktd(uhci); + + /* + * Reset the HC - this will force us to get a + * new notification of any already connected + * ports due to the virtual disconnect that it + * implies. + */ + outw(USBCMD_HCRESET, io_addr + USBCMD); + while (inw(io_addr + USBCMD) & USBCMD_HCRESET) { + if (!--timeout) { + printk("USBCMD_HCRESET timed out!\n"); + break; + } + } + + outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, io_addr + USBINTR); + outw(0, io_addr + USBFRNUM); + outl(virt_to_bus(uhci->fl), io_addr + USBFLBASEADD); + + /* Run and mark it configured with a 64-byte max packet */ + outw(USBCMD_RS | USBCMD_CF, io_addr + USBCMD); +} + +/* + * Allocate a frame list, and four regular queues. + * + * The hardware doesn't really know any difference + * in the queues, but the order does matter for the + * protocols higher up. The order is: + * + * - any isochronous events handled before any + * of the queues. We don't do that here, because + * we'll create the actual TD entries on demand. + * - The first queue is the "interrupt queue". + * - The second queue is the "control queue". + * - The third queue is "bulk data". + * + * We could certainly have multiple queues of the same + * type, and maybe we should. We could have per-device + * queues, for example. We begin small. + */ +static struct uhci *alloc_uhci(unsigned int io_addr) +{ + int i; + struct uhci *uhci; + struct usb_bus *bus; + struct uhci_device *dev; + struct usb_device *usb; + + uhci = kmalloc(sizeof(*uhci), GFP_KERNEL); + if (!uhci) + return NULL; + + memset(uhci, 0, sizeof(*uhci)); + + uhci->irq = -1; + uhci->io_addr = io_addr; + INIT_LIST_HEAD(&uhci->interrupt_list); + + /* We need exactly one page (per UHCI specs), how convenient */ + uhci->fl = (void *)__get_free_page(GFP_KERNEL); + + bus = kmalloc(sizeof(*bus), GFP_KERNEL); + if (!bus) + return NULL; + + memset(bus, 0, sizeof(*bus)); + + uhci->bus = bus; + bus->hcpriv = uhci; + bus->op = &uhci_device_operations; + + /* + * We allocate a 8kB area for the UHCI hub. The area + * is described by the uhci_device structure, and basically + * contains everything needed for normal operation. + * + * The first page is the actual device descriptor for the + * hub. + * + * The second page is used for the frame list. + */ + usb = uhci_usb_allocate(NULL); + if (!usb) + return NULL; + + dev = uhci->root_hub = usb_to_uhci(usb); + + usb->bus = bus; + + /* Initialize the root hub */ + /* UHCI specs says devices must have 2 ports, but goes on to say */ + /* they may have more but give no way to determine how many they */ + /* have, so default to 2 */ + usb->maxchild = 2; + usb_init_root_hub(usb); + + /* + * Initialize the queues. They all start out empty, + * linked to each other in the proper order. + */ + for (i = 1 ; i < 9; i++) { + dev->qh[i].link = 2 | virt_to_bus(&dev->skel_control_qh); + dev->qh[i].element = 1; + } + + dev->skel_control_qh.link = 2 | virt_to_bus(&dev->skel_bulk0_qh); + dev->skel_control_qh.element = 1; + + dev->skel_bulk0_qh.link = 2 | virt_to_bus(&dev->skel_bulk1_qh); + dev->skel_bulk0_qh.element = 1; + + dev->skel_bulk1_qh.link = 2 | virt_to_bus(&dev->skel_bulk2_qh); + dev->skel_bulk1_qh.element = 1; + + dev->skel_bulk2_qh.link = 2 | virt_to_bus(&dev->skel_bulk3_qh); + dev->skel_bulk2_qh.element = 1; + + dev->skel_bulk3_qh.link = 1; + dev->skel_bulk3_qh.element = 1; + + /* + * Fill the frame list: make all entries point to + * the proper interrupt queue. + * + * This is probably silly, but it's a simple way to + * scatter the interrupt queues in a way that gives + * us a reasonable dynamic range for irq latencies. + */ + for (i = 0; i < 1024; i++) { + struct uhci_qh * irq = &dev->skel_int2_qh; + if (i & 1) { + irq++; + if (i & 2) { + irq++; + if (i & 4) { + irq++; + if (i & 8) { + irq++; + if (i & 16) { + irq++; + if (i & 32) { + irq++; + if (i & 64) { + irq++; + } + } + } + } + } + } + } + uhci->fl->frame[i] = 2 | virt_to_bus(irq); + } + + return uhci; +} + + +/* + * De-allocate all resources.. + */ +static void release_uhci(struct uhci *uhci) +{ + if (uhci->irq >= 0) { + free_irq(uhci->irq, uhci); + uhci->irq = -1; + } + +#if 0 + if (uhci->root_hub) { + uhci_usb_deallocate(uhci_to_usb(uhci->root_hub)); + uhci->root_hub = NULL; + } +#endif + + if (uhci->fl) { + free_page((unsigned long)uhci->fl); + uhci->fl = NULL; + } + + kfree(uhci->bus); + kfree(uhci); +} + +static int uhci_control_thread(void * __uhci) +{ + struct uhci *uhci = (struct uhci *)__uhci; + + lock_kernel(); + request_region(uhci->io_addr, 32, "usb-uhci"); + + /* + * This thread doesn't need any user-level access, + * so get rid of all our resources.. + */ + printk("uhci_control_thread at %p\n", &uhci_control_thread); + exit_mm(current); + exit_files(current); + exit_fs(current); + + strcpy(current->comm, "uhci-control"); + + /* + * Ok, all systems are go.. + */ + start_hc(uhci); + for(;;) { + siginfo_t info; + int unsigned long signr; + + interruptible_sleep_on(&uhci_configure); +#ifdef CONFIG_APM + if (apm_resume) { + apm_resume = 0; + start_hc(uhci); + continue; + } +#endif + uhci_check_configuration(uhci); + + if(signal_pending(current)) { + /* sending SIGUSR1 makes us print out some info */ + spin_lock_irq(¤t->sigmask_lock); + signr = dequeue_signal(¤t->blocked, &info); + spin_unlock_irq(¤t->sigmask_lock); + + if(signr == SIGUSR1) { + printk("UHCI queue dump:\n"); + show_queues(uhci); + } else { + break; + } + } + } + +#if 0 + if(uhci->root_hub) + for(i = 0; i < uhci->root_hub->usb->maxchild; i++) + usb_disconnect(uhci->root_hub->usb->children + i); +#endif + + reset_hc(uhci); + release_region(uhci->io_addr, 32); + + release_uhci(uhci); + MOD_DEC_USE_COUNT; + + printk("uhci_control_thread exiting\n"); + + return 0; +} + +/* + * If we've successfully found a UHCI, now is the time to increment the + * module usage count, start the control thread, and return success.. + */ +static int found_uhci(int irq, unsigned int io_addr) +{ + int retval; + struct uhci *uhci; + + uhci = alloc_uhci(io_addr); + if (!uhci) + return -ENOMEM; + + reset_hc(uhci); + + retval = -EBUSY; + if (request_irq(irq, uhci_interrupt, SA_SHIRQ, "usb", uhci) == 0) { + int pid; + + MOD_INC_USE_COUNT; + uhci->irq = irq; + pid = kernel_thread(uhci_control_thread, uhci, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); + if (pid >= 0) + return 0; + + MOD_DEC_USE_COUNT; + retval = pid; + } + release_uhci(uhci); + return retval; +} + +static int start_uhci(struct pci_dev *dev) +{ + int i; + + /* Search for the IO base address.. */ + for (i = 0; i < 6; i++) { + unsigned int io_addr = dev->base_address[i]; + + /* IO address? */ + if (!(io_addr & 1)) + continue; + + io_addr &= PCI_BASE_ADDRESS_IO_MASK; + + /* Is it already in use? */ + if (check_region(io_addr, 32)) + break; + + return found_uhci(dev->irq, io_addr); + } + return -1; +} + +#ifdef CONFIG_APM +static int handle_apm_event(apm_event_t event) +{ + static int down = 0; + + switch (event) { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + if (down) { + printk(KERN_DEBUG "uhci: received extra suspend event\n"); + break; + } + down = 1; + break; + case APM_NORMAL_RESUME: + case APM_CRITICAL_RESUME: + if (!down) { + printk(KERN_DEBUG "uhci: received bogus resume event\n"); + break; + } + down = 0; + if (waitqueue_active(&uhci_configure)) { + apm_resume = 1; + wake_up(&uhci_configure); + } + break; + } + return 0; +} +#endif + +#ifdef MODULE + +void cleanup_module(void) +{ +#ifdef CONFIG_APM + apm_unregister_callback(&handle_apm_event); +#endif +} + +#define uhci_init init_module + +#endif + +int uhci_init(void) +{ + int retval; + struct pci_dev *dev = NULL; + u8 type; + + retval = -ENODEV; + for (;;) { + dev = pci_find_class(PCI_CLASS_SERIAL_USB<<8, dev); + if (!dev) + break; + /* Is it UHCI */ + pci_read_config_byte(dev, PCI_CLASS_PROG, &type); + if(type != 0) + continue; + /* Ok set it up */ + retval = start_uhci(dev); + if (retval < 0) + continue; + + usb_mouse_init(); + usb_kbd_init(); + hub_init(); +#ifdef CONFIG_APM + apm_register_callback(&handle_apm_event); +#endif + + return 0; + } + return retval; +} diff --git a/drivers/usb/uhci.h b/drivers/usb/uhci.h new file mode 100644 index 000000000000..0c351f1f6b93 --- /dev/null +++ b/drivers/usb/uhci.h @@ -0,0 +1,229 @@ +#ifndef __LINUX_UHCI_H +#define __LINUX_UHCI_H + +#include + +#include "usb.h" + +/* + * Universal Host Controller Interface data structures and defines + */ + +/* Command register */ +#define USBCMD 0 +#define USBCMD_RS 0x0001 /* Run/Stop */ +#define USBCMD_HCRESET 0x0002 /* Host reset */ +#define USBCMD_GRESET 0x0004 /* Global reset */ +#define USBCMD_EGSM 0x0008 /* Global Suspend Mode */ +#define USBCMD_FGR 0x0010 /* Force Global Resume */ +#define USBCMD_SWDBG 0x0020 /* SW Debug mode */ +#define USBCMD_CF 0x0040 /* Config Flag (sw only) */ +#define USBCMD_MAXP 0x0080 /* Max Packet (0 = 32, 1 = 64) */ + +/* Status register */ +#define USBSTS 2 +#define USBSTS_USBINT 0x0001 /* Interrupt due to IOC */ +#define USBSTS_ERROR 0x0002 /* Interrupt due to error */ +#define USBSTS_RD 0x0004 /* Resume Detect */ +#define USBSTS_HSE 0x0008 /* Host System Error - basically PCI problems */ +#define USBSTS_HCPE 0x0010 /* Host Controller Process Error - the scripts were buggy */ +#define USBSTS_HCH 0x0020 /* HC Halted */ + +/* Interrupt enable register */ +#define USBINTR 4 +#define USBINTR_TIMEOUT 0x0001 /* Timeout/CRC error enable */ +#define USBINTR_RESUME 0x0002 /* Resume interrupt enable */ +#define USBINTR_IOC 0x0004 /* Interrupt On Complete enable */ +#define USBINTR_SP 0x0008 /* Short packet interrupt enable */ + +#define USBFRNUM 6 +#define USBFLBASEADD 8 +#define USBSOF 12 + +/* USB port status and control registers */ +#define USBPORTSC1 16 +#define USBPORTSC2 18 +#define USBPORTSC_CCS 0x0001 /* Current Connect Status ("device present") */ +#define USBPORTSC_CSC 0x0002 /* Connect Status Change */ +#define USBPORTSC_PE 0x0004 /* Port Enable */ +#define USBPORTSC_PEC 0x0008 /* Port Enable Change */ +#define USBPORTSC_LS 0x0030 /* Line Status */ +#define USBPORTSC_RD 0x0040 /* Resume Detect */ +#define USBPORTSC_LSDA 0x0100 /* Low Speed Device Attached */ +#define USBPORTSC_PR 0x0200 /* Port Reset */ +#define USBPORTSC_SUSP 0x1000 /* Suspend */ + +struct uhci_qh { + unsigned int link; /* Next queue */ + unsigned int element; /* Queue element pointer */ + int inuse; /* Inuse? */ + struct uhci_qh *skel; /* Skeleton head */ +} __attribute__((aligned(16))); + +struct uhci_framelist { + unsigned int frame[1024]; +} __attribute__((aligned(4096))); + +/* + * The documentation says "4 words for hardware, 4 words for software". + * + * That's silly, the hardware doesn't care. The hardware only cares that + * the hardware words are 16-byte aligned, and we can have any amount of + * sw space after the TD entry as far as I can tell. + * + * But let's just go with the documentation, at least for 32-bit machines. + * On 64-bit machines we probably want to take advantage of the fact that + * hw doesn't really care about the size of the sw-only area. + * + * Alas, not anymore, we have more than 4 words of software, woops + */ +struct uhci_td { + /* Hardware fields */ + __u32 link; + __u32 status; + __u32 info; + __u32 buffer; + + /* Software fields */ + struct list_head irq_list; /* Active interrupt list.. */ + usb_device_irq completed; /* Completion handler routine */ + unsigned int *backptr; /* Where to remove this from.. */ + void *dev_id; + int inuse; /* Inuse? */ + struct uhci_qh *qh; +} __attribute__((aligned(32))); + +/* + * Note the alignment requirements of the entries + * + * Each UHCI device has pre-allocated QH and TD entries. + * You can use more than the pre-allocated ones, but I + * don't see you usually needing to. + */ +struct uhci; + +#define UHCI_MAXTD 32 + +#define UHCI_MAXQH 16 + +/* The usb device part must be first! */ +struct uhci_device { + struct usb_device *usb; + + struct uhci *uhci; + struct uhci_qh qh[UHCI_MAXQH]; /* These are the "common" qh's for each device */ + struct uhci_td td[UHCI_MAXTD]; + + unsigned long data[16]; +}; + +#define uhci_to_usb(uhci) ((uhci)->usb) +#define usb_to_uhci(usb) ((struct uhci_device *)(usb)->hcpriv) + +/* + * The root hub pre-allocated QH's and TD's have + * some special global uses.. + */ +#define control_td td /* Td's 0-30 */ +/* This is only for the root hub's TD list */ +#define tick_td td[31] + +/* + * There are various standard queues. We set up several different + * queues for each of the three basic queue types: interrupt, + * control, and bulk. + * + * - There are various different interrupt latencies: ranging from + * every other USB frame (2 ms apart) to every 256 USB frames (ie + * 256 ms apart). Make your choice according to how obnoxious you + * want to be on the wire, vs how critical latency is for you. + * - The control list is done every frame. + * - There are 4 bulk lists, so that up to four devices can have a + * bulk list of their own and when run concurrently all four lists + * will be be serviced. + * + * This is a bit misleading, there are various interrupt latencies, but they + * vary a bit, interrupt2 isn't exactly 2ms, it can vary up to 4ms since the + * other queues can "override" it. interrupt4 can vary up to 8ms, etc. Minor + * problem + * + * In the case of the root hub, these QH's are just head's of qh's. Don't + * be scared, it kinda makes sense. Look at this wonderful picture care of + * Linus: + * + * generic-iso-QH -> dev1-iso-QH -> generic-irq-QH -> dev1-irq-QH -> ... + * | | | | + * End dev1-iso-TD1 End dev1-irq-TD1 + * | + * dev1-iso-TD2 + * | + * .... + * + * This may vary a bit (the UHCI docs don't explicitly say you can put iso + * transfers in QH's and all of their pictures don't have that either) but + * other than that, that is what we're doing now + * + * To keep with Linus' nomenclature, this is called the qh skeleton. These + * labels (below) are only signficant to the root hub's qh's + */ +#define skel_iso_qh qh[0] + +#define skel_int2_qh qh[1] +#define skel_int4_qh qh[2] +#define skel_int8_qh qh[3] +#define skel_int16_qh qh[4] +#define skel_int32_qh qh[5] +#define skel_int64_qh qh[6] +#define skel_int128_qh qh[7] +#define skel_int256_qh qh[8] + +#define skel_control_qh qh[9] + +#define skel_bulk0_qh qh[10] +#define skel_bulk1_qh qh[11] +#define skel_bulk2_qh qh[12] +#define skel_bulk3_qh qh[13] + +/* + * These are significant to the devices allocation of QH's + */ +#if 0 +#define iso_qh qh[0] +#define int_qh qh[1] /* We have 2 "common" interrupt QH's */ +#define control_qh qh[3] +#define bulk_qh qh[4] /* We have 4 "common" bulk QH's */ +#define extra_qh qh[8] /* The rest, anything goes */ +#endif + +/* + * This describes the full uhci information. + * + * Note how the "proper" USB information is just + * a subset of what the full implementation needs. + */ +struct uhci { + int irq; + unsigned int io_addr; + + struct usb_bus *bus; + +#if 0 + /* These are "standard" QH's for the entire bus */ + struct uhci_qh qh[UHCI_MAXQH]; +#endif + struct uhci_device *root_hub; /* Root hub device descriptor.. */ + + struct uhci_framelist *fl; /* Frame list */ + struct list_head interrupt_list; /* List of interrupt-active TD's for this uhci */ +}; + +/* needed for the debugging code */ +struct uhci_td *uhci_link_to_td(unsigned int element); + +/* Debugging code */ +void show_td(struct uhci_td * td); +void show_status(struct uhci *uhci); +void show_queues(struct uhci *uhci); + +#endif + diff --git a/drivers/usb/usb-debug.c b/drivers/usb/usb-debug.c new file mode 100644 index 000000000000..86d08cd787f1 --- /dev/null +++ b/drivers/usb/usb-debug.c @@ -0,0 +1,127 @@ +/* + * debug.c - USB debug helper routines. + * + * I just want these out of the way where they aren't in your + * face, but so that you can still use them.. + */ +#include + +#include "usb.h" + +static void usb_show_endpoint(struct usb_endpoint_descriptor *endpoint) +{ + usb_show_endpoint_descriptor(endpoint); +} + +static void usb_show_interface(struct usb_interface_descriptor *interface) +{ + int i; + + usb_show_interface_descriptor(interface); + for (i = 0 ; i < interface->bNumEndpoints; i++) + usb_show_endpoint(interface->endpoint + i); +} + +static void usb_show_config(struct usb_config_descriptor *config) +{ + int i; + + usb_show_config_descriptor(config); + for (i = 0 ; i < config->bNumInterfaces; i++) + usb_show_interface(config->interface + i); +} + +void usb_show_device(struct usb_device *dev) +{ + int i; + + usb_show_device_descriptor(&dev->descriptor); + for (i = 0; i < dev->descriptor.bNumConfigurations; i++) + usb_show_config(dev->config + i); +} + + +/* + * Parse and show the different USB descriptors. + */ +void usb_show_device_descriptor(struct usb_device_descriptor *desc) +{ + printk(" USB version %x.%02x\n", desc->bcdUSB >> 8, desc->bcdUSB & 0xff); + printk(" Vendor: %04x\n", desc->idVendor); + printk(" Product: %04x\n", desc->idProduct); + printk(" Configurations: %d\n", desc->bNumConfigurations); + + printk(" Device Class: %d\n", desc->bDeviceClass); + switch (desc->bDeviceClass) { + case 0: + printk(" Per-interface classes\n"); + break; + case 9: + printk(" Hub device class\n"); + break; + case 0xff: + printk(" Vendor class\n"); + break; + default: + printk(" Unknown class\n"); + } +} + +void usb_show_config_descriptor(struct usb_config_descriptor * desc) +{ + printk("Configuration:\n"); + printk(" bLength = %4d%s\n", desc->bLength, + desc->bLength == 9 ? "" : " (!!!)"); + printk(" bDescriptorType = %02x\n", desc->bDescriptorType); + printk(" wTotalLength = %04x\n", desc->wTotalLength); + printk(" bNumInterfaces = %02x\n", desc->bNumInterfaces); + printk(" bConfigurationValue = %02x\n", desc->bConfigurationValue); + printk(" iConfiguration = %02x\n", desc->iConfiguration); + printk(" bmAttributes = %02x\n", desc->bmAttributes); + printk(" MaxPower = %4dmA\n", desc->MaxPower * 2); +} + +void usb_show_interface_descriptor(struct usb_interface_descriptor * desc) +{ + printk(" Interface:\n"); + printk(" bLength = %4d%s\n", desc->bLength, + desc->bLength == 9 ? "" : " (!!!)"); + printk(" bDescriptorType = %02x\n", desc->bDescriptorType); + printk(" bInterfaceNumber = %02x\n", desc->bInterfaceNumber); + printk(" bAlternateSetting = %02x\n", desc->bAlternateSetting); + printk(" bNumEndpoints = %02x\n", desc->bNumEndpoints); + printk(" bInterfaceClass = %02x\n", desc->bInterfaceClass); + printk(" bInterfaceSubClass = %02x\n", desc->bInterfaceSubClass); + printk(" bInterfaceProtocol = %02x\n", desc->bInterfaceProtocol); + printk(" iInterface = %02x\n", desc->iInterface); +} + +void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor * desc) +{ + char *EndpointType[4] = { "Control", "Isochronous", "Bulk", "Interrupt" }; + printk(" Endpoint:\n"); + printk(" bLength = %4d%s\n", desc->bLength, + desc->bLength == 7 ? "" : " (!!!)"); + printk(" bDescriptorType = %02x\n", desc->bDescriptorType); + printk(" bEndpointAddress = %02x (%s)\n", desc->bEndpointAddress, + (desc->bEndpointAddress & 0x80) ? "in" : "out"); + printk(" bmAttributes = %02x (%s)\n", desc->bmAttributes, + EndpointType[3 & desc->bmAttributes]); + printk(" wMaxPacketSize = %04x\n", desc->wMaxPacketSize); + printk(" bInterval = %02x\n", desc->bInterval); +} + +void usb_show_hub_descriptor(struct usb_hub_descriptor * desc) +{ + int len = 7; + unsigned char *ptr = (unsigned char *) desc; + + printk("Interface:"); + while (len) { + printk(" %02x", *ptr); + ptr++; len--; + } + printk("\n"); +} + + diff --git a/drivers/usb/usb.c b/drivers/usb/usb.c new file mode 100644 index 000000000000..cc6ed027c6ab --- /dev/null +++ b/drivers/usb/usb.c @@ -0,0 +1,546 @@ +/* + * driver/usb/usb.c + * + * (C) Copyright Linus Torvalds 1999 + * + * NOTE! This is not actually a driver at all, rather this is + * just a collection of helper routines that implement the + * generic USB things that the real drivers can use.. + * + * Think of this as a "USB library" rather than anything else. + * It should be considered a slave, with no callbacks. Callbacks + * are evil. + */ + +/* + * Table 9-2 + * + * Offset Field Size Value Desc + * 0 bmRequestType 1 Bitmap D7: Direction + * 0 = Host-to-device + * 1 = Device-to-host + * D6..5: Type + * 0 = Standard + * 1 = Class + * 2 = Vendor + * 3 = Reserved + * D4..0: Recipient + * 0 = Device + * 1 = Interface + * 2 = Endpoint + * 3 = Other + * 4..31 = Reserved + * 1 bRequest 1 Value Specific request (9-3) + * 2 wValue 2 Value Varies + * 4 wIndex 2 Index/Offset Varies + * 6 wLength 2 Count Bytes for data + */ + +#include +#include +#include + +#include "usb.h" + +/* + * We have a per-interface "registered driver" list. + */ +static LIST_HEAD(usb_driver_list); + +int usb_register(struct usb_driver *new_driver) +{ + /* Add it to the list of known drivers */ + list_add(&new_driver->driver_list, &usb_driver_list); + + /* + * We should go through all existing devices, and see if any of + * them would be acceptable to the new driver.. Let's do that + * in version 2.0. + */ + return 0; +} + +void usb_deregister(struct usb_driver *driver) +{ + list_del(&driver->driver_list); +} + +/* + * This entrypoint gets called for each new device. + * + * We now walk the list of registered USB drivers, + * looking for one that will accept this device as + * his.. + */ +void usb_device_descriptor(struct usb_device *dev) +{ + struct list_head *tmp = usb_driver_list.next; + + while (tmp != &usb_driver_list) { + struct usb_driver *driver = list_entry(tmp, struct usb_driver, driver_list); + tmp = tmp->next; + if (driver->probe(dev)) + continue; + dev->driver = driver; + return; + } + + /* + * Ok, no driver accepted the device, so show the info + * for debugging.. + */ + printk("Unknown new USB device:\n"); + usb_show_device(dev); +} + +/* + * Parse the fairly incomprehensible output of + * the USB configuration data, and build up the + * USB device database. + */ +static int usb_expect_descriptor(unsigned char *ptr, int len, unsigned char desctype, unsigned char descindex) +{ + int parsed = 0; + + for (;;) { + unsigned short n_desc; + int n_len, i; + + if (len < descindex) + return -1; + n_desc = *(unsigned short *)ptr; + if (n_desc == ((desctype << 8) + descindex)) + return parsed; + printk( + "Expected descriptor %02X/%02X, got %02X/%02X - skipping\n", + desctype, descindex, + (n_desc >> 8) & 0xFF, n_desc & 0xFF); + n_len = n_desc & 0xff; + if (n_len < 2 || n_len > len) + return -1; + for (i = 0 ; i < n_len; i++) + printk(" %d %02x\n", i, ptr[i]); + len -= n_len; + ptr += n_len; + parsed += n_len; + } +} + +static int usb_parse_endpoint(struct usb_endpoint_descriptor *endpoint, unsigned char *ptr, int len) +{ + int parsed = usb_expect_descriptor(ptr, len, USB_DT_ENDPOINT, 7); + + if (parsed < 0) + return parsed; + + memcpy(endpoint, ptr + parsed, 7); + return parsed + 7; +} + +static int usb_parse_interface(struct usb_interface_descriptor *interface, unsigned char *ptr, int len) +{ + int i; + int parsed = usb_expect_descriptor(ptr, len, USB_DT_INTERFACE, 9); + int retval; + + if (parsed < 0) + return parsed; + + memcpy(interface, ptr + parsed, 9); + len -= 9; + parsed += 9; + + if (interface->bNumEndpoints > USB_MAXENDPOINTS) + return -1; + + for (i = 0; i < interface->bNumEndpoints; i++) { + if(((USB_DT_HID << 8) | 9) == *(unsigned short*)(ptr + parsed)) { + parsed += 9; /* skip over the HID descriptor for now */ + len -= 9; + } + retval = usb_parse_endpoint(interface->endpoint + i, ptr + parsed, len); + if (retval < 0) return retval; + parsed += retval; + len -= retval; + } + return parsed; +} + +static int usb_parse_config(struct usb_config_descriptor *config, unsigned char *ptr, int len) +{ + int i; + int parsed = usb_expect_descriptor(ptr, len, USB_DT_CONFIG, 9); + + if (parsed < 0) + return parsed; + + memcpy(config, ptr + parsed, 9); + len -= 9; + parsed += 9; + + if (config->bNumInterfaces > USB_MAXINTERFACES) + return -1; + + for (i = 0; i < config->bNumInterfaces; i++) { + int retval = usb_parse_interface(config->interface + i, ptr + parsed, len); + if (retval < 0) + return retval; + parsed += retval; + len -= retval; + } + return parsed; +} + +int usb_parse_configuration(struct usb_device *dev, void *__buf, int bytes) +{ + int i; + unsigned char *ptr = __buf; + + if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG) + return -1; + + for (i = 0; i < dev->descriptor.bNumConfigurations; i++) { + int retval = usb_parse_config(dev->config + i, ptr, bytes); + if (retval < 0) + return retval; + ptr += retval; + bytes += retval; + } + return 0; +} + +void usb_init_root_hub(struct usb_device *dev) +{ + dev->devnum = -1; + dev->slow = 0; +} + +/* + * Something got disconnected. Get rid of it, and all of its children. + */ +void usb_disconnect(struct usb_device **pdev) +{ + struct usb_device * dev = *pdev; + + if (dev) { + int i; + + *pdev = NULL; + + printk("USB disconnect on device %d\n", dev->devnum); + + if(dev->driver) dev->driver->disconnect(dev); + + /* Free up all the children.. */ + for (i = 0; i < USB_MAXCHILDREN; i++) { + struct usb_device **child = dev->children + i; + usb_disconnect(child); + } + + /* Free up the device itself, including its device number */ + if (dev->devnum > 0) + clear_bit(dev->devnum, &dev->bus->devmap.devicemap); + dev->bus->op->deallocate(dev); + } +} + + +/* + * Connect a new USB device. This basically just initializes + * the USB device information and sets up the topology - it's + * up to the low-level driver to reset the port and actually + * do the setup (the upper levels don't know how to do that). + */ +void usb_connect(struct usb_device *dev) +{ + int devnum; + + dev->descriptor.bMaxPacketSize0 = 8; /* XXX fixed 8 bytes for now */ + + devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1); + if (devnum < 128) { + set_bit(devnum, dev->bus->devmap.devicemap); + dev->devnum = devnum; + } +} + +/* + * These are the actual routines to send + * and receive control messages. + */ +int usb_set_address(struct usb_device *dev) +{ + devrequest dr; + + dr.requesttype = 0; + dr.request = USB_REQ_SET_ADDRESS; + dr.value = dev->devnum; + dr.index = 0; + dr.length = 0; + + return dev->bus->op->control_msg(dev, usb_snddefctrl(dev), &dr, NULL, 0); +} + +int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size) +{ + devrequest dr; + + dr.requesttype = 0x80; + dr.request = USB_REQ_GET_DESCRIPTOR; + dr.value = (type << 8) + index; + dr.index = 0; + dr.length = size; + + return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size); +} + +int usb_get_device_descriptor(struct usb_device *dev) +{ + return usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, sizeof(dev->descriptor)); +} + +int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size) +{ + devrequest dr; + + dr.requesttype = USB_RT_HUB | 0x80; + dr.request = USB_REQ_GET_DESCRIPTOR; + dr.value = (USB_DT_HUB << 8); + dr.index = 0; + dr.length = size; + + return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, size); +} + +int usb_clear_port_feature(struct usb_device *dev, int port, int feature) +{ + devrequest dr; + + dr.requesttype = USB_RT_PORT; + dr.request = USB_REQ_CLEAR_FEATURE; + dr.value = feature; + dr.index = port; + dr.length = 0; + + return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); +} + +int usb_set_port_feature(struct usb_device *dev, int port, int feature) +{ + devrequest dr; + + dr.requesttype = USB_RT_PORT; + dr.request = USB_REQ_SET_FEATURE; + dr.value = feature; + dr.index = port; + dr.length = 0; + + return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0); +} + +int usb_get_hub_status(struct usb_device *dev, void *data) +{ + devrequest dr; + + dr.requesttype = USB_RT_HUB | 0x80; + dr.request = USB_REQ_GET_STATUS; + dr.value = 0; + dr.index = 0; + dr.length = 4; + + return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, 4); +} + +int usb_get_port_status(struct usb_device *dev, int port, void *data) +{ + devrequest dr; + + dr.requesttype = USB_RT_PORT | 0x80; + dr.request = USB_REQ_GET_STATUS; + dr.value = 0; + dr.index = port; + dr.length = 4; + + return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, 4); +} + +int usb_get_protocol(struct usb_device *dev) +{ + unsigned char buf[8]; + devrequest dr; + + dr.requesttype = USB_RT_HIDD | 0x80; + dr.request = USB_REQ_GET_PROTOCOL; + dr.value = 0; + dr.index = 1; + dr.length = 1; + + if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, 1)) + return -1; + + return buf[0]; +} + +int usb_set_protocol(struct usb_device *dev, int protocol) +{ + devrequest dr; + + dr.requesttype = USB_RT_HIDD; + dr.request = USB_REQ_SET_PROTOCOL; + dr.value = protocol; + dr.index = 1; + dr.length = 0; + + if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0)) + return -1; + + return 0; +} + +/* keyboards want a nonzero duration according to HID spec, but + mice should use infinity (0) -keryan */ +int usb_set_idle(struct usb_device *dev, int duration, int report_id) +{ + devrequest dr; + + dr.requesttype = USB_RT_HIDD; + dr.request = USB_REQ_SET_IDLE; + dr.value = (duration << 8) | report_id; + dr.index = 1; + dr.length = 0; + + if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0)) + return -1; + + return 0; +} + +int usb_set_configuration(struct usb_device *dev, int configuration) +{ + devrequest dr; + + dr.requesttype = 0; + dr.request = USB_REQ_SET_CONFIGURATION; + dr.value = configuration; + dr.index = 0; + dr.length = 0; + + if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0)) + return -1; + + return 0; +} + +int usb_get_report(struct usb_device *dev) +{ + unsigned char buf[8]; + devrequest dr; + + dr.requesttype = USB_RT_HIDD | 0x80; + dr.request = USB_REQ_GET_REPORT; + dr.value = 0x100; + dr.index = 1; + dr.length = 3; + + if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, 3)) + return -1; + + return buf[0]; +} + +int usb_get_configuration(struct usb_device *dev) +{ + unsigned int size; + unsigned char buffer[128]; + + /* Get the first 8 bytes - guaranteed */ + if (usb_get_descriptor(dev, USB_DT_CONFIG, 0, buffer, 8)) + return -1; + + /* Get the full buffer */ + size = *(unsigned short *)(buffer+2); + if (size > sizeof(buffer)) + size = sizeof(buffer); + + if (usb_get_descriptor(dev, USB_DT_CONFIG, 0, buffer, size)) + return -1; + + return usb_parse_configuration(dev, buffer, size); +} + +/* + * By the time we get here, the device has gotten a new device ID + * and is in the default state. We need to identify the thing and + * get the ball rolling.. + */ +void usb_new_device(struct usb_device *dev) +{ + int addr, i; + + printk("USB new device connect, assigned device number %d\n", + dev->devnum); + + dev->maxpacketsize = 0; /* Default to 8 byte max packet size */ + + addr = dev->devnum; + dev->devnum = 0; + + /* Slow devices */ + for (i = 0; i < 5; i++) { + if (!usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8)) + break; + + printk("get_descriptor failed, waiting\n"); + wait_ms(200); + } + if (i == 5) { + printk("giving up\n"); + return; + } + +#if 0 + printk("maxpacketsize: %d\n", dev->descriptor.bMaxPacketSize0); +#endif + switch (dev->descriptor.bMaxPacketSize0) { + case 8: dev->maxpacketsize = 0; break; + case 16: dev->maxpacketsize = 1; break; + case 32: dev->maxpacketsize = 2; break; + case 64: dev->maxpacketsize = 3; break; + } +#if 0 + printk("dev->mps: %d\n", dev->maxpacketsize); +#endif + + dev->devnum = addr; + + if (usb_set_address(dev)) { + printk("Unable to set address\n"); + /* FIXME: We should disable the port */ + return; + } + + wait_ms(10); /* Let the SET_ADDRESS settle */ + + if (usb_get_device_descriptor(dev)) { + printk("Unable to get device descriptor\n"); + return; + } + + if (usb_get_configuration(dev)) { + printk("Unable to get configuration\n"); + return; + } + +#if 0 + printk("Vendor: %X\n", dev->descriptor.idVendor); + printk("Product: %X\n", dev->descriptor.idProduct); +#endif + + usb_device_descriptor(dev); +} + +int usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id) +{ + return dev->bus->op->request_irq(dev, pipe, handler, period, dev_id); +} + diff --git a/drivers/usb/usb.h b/drivers/usb/usb.h new file mode 100644 index 000000000000..b317acfc5997 --- /dev/null +++ b/drivers/usb/usb.h @@ -0,0 +1,359 @@ +#ifndef __LINUX_USB_H +#define __LINUX_USB_H + +#include +#include +#include + +static __inline__ void wait_ms(unsigned int ms) +{ + current->state = TASK_UNINTERRUPTIBLE; + schedule_timeout(1 + ms / 10); +} + + +typedef struct { + unsigned char requesttype; + unsigned char request; + unsigned short value; + unsigned short index; + unsigned short length; +} devrequest; + +/* + * Class codes + */ +#define USB_CLASS_HUB 9 + +/* + * Descriptor types + */ +#define USB_DT_DEVICE 0x01 +#define USB_DT_CONFIG 0x02 +#define USB_DT_STRING 0x03 +#define USB_DT_INTERFACE 0x04 +#define USB_DT_ENDPOINT 0x05 + +#define USB_DT_HUB 0x29 +#define USB_DT_HID 0x21 + +/* + * Standard requests + */ +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +/* 0x02 is reserved */ +#define USB_REQ_SET_FEATURE 0x03 +/* 0x04 is reserved */ +#define USB_REQ_SET_ADDRESS 0x05 +#define USB_REQ_GET_DESCRIPTOR 0x06 +#define USB_REQ_SET_DESCRIPTOR 0x07 +#define USB_REQ_GET_CONFIGURATION 0x08 +#define USB_REQ_SET_CONFIGURATION 0x09 +#define USB_REQ_GET_INTERFACE 0x0A +#define USB_REQ_SET_INTERFACE 0x0B +#define USB_REQ_SYNCH_FRAME 0x0C + +/* + * HIDD requests + */ +#define USB_REQ_GET_REPORT 0x01 +#define USB_REQ_GET_IDLE 0x02 +#define USB_REQ_GET_PROTOCOL 0x03 +#define USB_REQ_SET_REPORT 0x09 +#define USB_REQ_SET_IDLE 0x0A +#define USB_REQ_SET_PROTOCOL 0x0B + +#define USB_TYPE_STANDARD (0x00 << 5) +#define USB_TYPE_CLASS (0x01 << 5) +#define USB_TYPE_VENDOR (0x02 << 5) +#define USB_TYPE_RESERVED (0x03 << 5) + +#define USB_RECIP_DEVICE 0x00 +#define USB_RECIP_INTERFACE 0x01 +#define USB_RECIP_ENDPOINT 0x02 +#define USB_RECIP_OTHER 0x03 + +/* + * Request target types. + */ +#define USB_RT_DEVICE 0x00 +#define USB_RT_INTERFACE 0x01 +#define USB_RT_ENDPOINT 0x02 + +#define USB_RT_HUB (USB_TYPE_CLASS | USB_RECIP_DEVICE) +#define USB_RT_PORT (USB_TYPE_CLASS | USB_RECIP_OTHER) + +#define USB_RT_HIDD (USB_TYPE_CLASS | USB_RECIP_INTERFACE) + +/* + * USB device number allocation bitmap. There's one bitmap + * per USB tree. + */ +struct usb_devmap { + unsigned long devicemap[128 / (8*sizeof(unsigned long))]; +}; + +/* + * This is a USB device descriptor. + * + * USB device information + * + * Make this MUCH dynamic, right now + * it contains enough information for + * a USB floppy controller, and nothing + * else. + * + * I'm not proud. I just want this dang + * thing to start working. + */ +#define USB_MAXCONFIG 1 +#define USB_MAXINTERFACES 3 +#define USB_MAXENDPOINTS 3 + +struct usb_device_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u16 bcdUSB; + __u8 bDeviceClass; + __u8 bDeviceSubClass; + __u8 bDeviceProtocol; + __u8 bMaxPacketSize0; + __u16 idVendor; + __u16 idProduct; + __u16 bcdDevice; + __u8 iManufacturer; + __u8 iProduct; + __u8 iSerialNumber; + __u8 bNumConfigurations; +}; + +/* Endpoint descriptor */ +struct usb_endpoint_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u8 bEndpointAddress; + __u8 bmAttributes; + __u16 wMaxPacketSize; + __u8 bInterval; +}; + +/* Interface descriptor */ +struct usb_interface_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u8 bInterfaceNumber; + __u8 bAlternateSetting; + __u8 bNumEndpoints; + __u8 bInterfaceClass; + __u8 bInterfaceSubClass; + __u8 bInterfaceProtocol; + __u8 iInterface; + + struct usb_endpoint_descriptor endpoint[USB_MAXENDPOINTS]; +}; + +/* Configuration descriptor information.. */ +struct usb_config_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u16 wTotalLength; + __u8 bNumInterfaces; + __u8 bConfigurationValue; + __u8 iConfiguration; + __u8 bmAttributes; + __u8 MaxPower; + + struct usb_interface_descriptor interface[USB_MAXINTERFACES]; +}; + +/* String descriptor */ +struct usb_string_descriptor { + __u8 bLength; + __u8 bDescriptorType; +}; + +/* Hub descriptor */ +struct usb_hub_descriptor { + __u8 bLength; + __u8 bDescriptorType; + __u8 bNbrPorts; + __u16 wHubCharacteristics; + __u8 bPwrOn2PwrGood; + __u8 bHubContrCurrent; + /* DeviceRemovable and PortPwrCtrlMask want to be variable-length + bitmaps that hold max 256 entries, but for now they're ignored */ + __u8 filler; +}; + +struct usb_device; + +struct usb_driver { + const char * name; + int (*probe)(struct usb_device *); + void (*disconnect)(struct usb_device *); + struct list_head driver_list; +}; + +/* + * Pointer to a device endpoint interrupt function -greg + */ +typedef int (*usb_device_irq)(int, void *, void *); + +struct usb_operations { + struct usb_device *(*allocate)(struct usb_device *); + int (*deallocate)(struct usb_device *); + int (*control_msg)(struct usb_device *, unsigned int, void *, void *, int); + int (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *); +}; + +/* + * Allocated per bus we have + */ +struct usb_bus { + struct usb_devmap devmap; /* Device map */ + struct usb_operations *op; /* Operations (specific to the HC) */ + struct usb_device *root_hub; /* Root hub */ + void *hcpriv; /* Host Controller private data */ +}; + + +#define USB_MAXCHILDREN (8) + +struct usb_device { + int devnum; /* Device number on USB bus */ + int slow; /* Slow device? */ + int maxpacketsize; /* Maximum packet size */ + + struct usb_bus *bus; /* Bus we're apart of */ + struct usb_driver *driver; /* Driver */ + struct usb_device_descriptor descriptor; /* Descriptor */ + struct usb_config_descriptor config[USB_MAXCONFIG]; /* All of the configs */ + struct usb_device *parent; + + /* + * Child devices - these can be either new devices + * (if this is a hub device), or different instances + * of this same device. + * + * Each instance needs its own set of data structuctures. + */ + + int maxchild; /* Number of ports if hub */ + struct usb_device *children[USB_MAXCHILDREN]; + + void *hcpriv; /* Host Controller private data */ + void *private; /* Upper layer private data */ +}; + +extern int usb_register(struct usb_driver *); +extern void usb_deregister(struct usb_driver *); + +extern int usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *); + +extern void usb_init_root_hub(struct usb_device *dev); +extern void usb_connect(struct usb_device *dev); +extern void usb_disconnect(struct usb_device **); +extern void usb_device_descriptor(struct usb_device *dev); + +extern int usb_parse_configuration(struct usb_device *dev, void *buf, int len); + +/* + * Calling this entity a "pipe" is glorifying it. A USB pipe + * is something embarrassingly simple: it basically consists + * of the following information: + * - device number (7 bits) + * - endpoint number (4 bits) + * - current Data0/1 state (1 bit) + * - direction (1 bit) + * - speed (1 bit) + * - max packet size (2 bits: 8, 16, 32 or 64) + * - pipe type (2 bits: control, interrupt, bulk, isochronous) + * + * That's 18 bits. Really. Nothing more. And the USB people have + * documented these eighteen bits as some kind of glorious + * virtual data structure. + * + * Let's not fall in that trap. We'll just encode it as a simple + * unsigned int. The encoding is: + * + * - device: bits 8-14 + * - endpoint: bits 15-18 + * - Data0/1: bit 19 + * - direction: bit 7 (0 = Host-to-Device, 1 = Device-to-Host) + * - speed: bit 26 (0 = High, 1 = Low Speed) + * - max size: bits 0-1 (00 = 8, 01 = 16, 10 = 32, 11 = 64) + * - pipe type: bits 30-31 (00 = isochronous, 01 = interrupt, 10 = control, 11 = bulk) + * + * Why? Because it's arbitrary, and whatever encoding we select is really + * up to us. This one happens to share a lot of bit positions with the UCHI + * specification, so that much of the uhci driver can just mask the bits + * appropriately. + */ + +#define usb_maxpacket(pipe) (8 << ((pipe) & 3)) +#define usb_packetid(pipe) (((pipe) & 0x80) ? 0x69 : 0xE1) + +#define usb_pipedevice(pipe) (((pipe) >> 8) & 0x7f) +#define usb_pipeendpoint(pipe) (((pipe) >> 15) & 0xf) +#define usb_pipedata(pipe) (((pipe) >> 19) & 1) +#define usb_pipeout(pipe) (((pipe) & 0x80) == 0) +#define usb_pipeslow(pipe) (((pipe) >> 26) & 1) + +#define usb_pipetype(pipe) (((pipe) >> 30) & 3) +#define usb_pipeisoc(pipe) (usb_pipetype((pipe)) == 0) +#define usb_pipeint(pipe) (usb_pipetype((pipe)) == 1) +#define usb_pipecontrol(pipe) (usb_pipetype((pipe)) == 2) +#define usb_pipebulk(pipe) (usb_pipetype((pipe)) == 3) + +#define usb_pipe_endpdev(pipe) (((pipe) >> 8) & 0x7ff) + +static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint) +{ + return (dev->devnum << 8) | (endpoint << 15) | (dev->slow << 26) | dev->maxpacketsize; +} + +static inline unsigned int __default_pipe(struct usb_device *dev) +{ + return (dev->slow << 26); +} + +/* Create control pipes.. */ +#define usb_sndctrlpipe(dev,endpoint) ((2 << 30) | __create_pipe(dev,endpoint)) +#define usb_rcvctrlpipe(dev,endpoint) ((2 << 30) | __create_pipe(dev,endpoint) | 0x80) +#define usb_snddefctrl(dev) ((2 << 30) | __default_pipe(dev)) +#define usb_rcvdefctrl(dev) ((2 << 30) | __default_pipe(dev) | 0x80) + +/* Create .. */ + +/* + * Send and receive control messages.. + */ +void usb_new_device(struct usb_device *dev); +int usb_set_address(struct usb_device *dev); +int usb_get_descriptor(struct usb_device *dev, unsigned char desctype, unsigned +char descindex, void *buf, int size); +int usb_get_device_descriptor(struct usb_device *dev); +int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size); +int usb_clear_port_feature(struct usb_device *dev, int port, int feature); +int usb_set_port_feature(struct usb_device *dev, int port, int feature); +int usb_get_hub_status(struct usb_device *dev, void *data); +int usb_get_port_status(struct usb_device *dev, int port, void *data); +int usb_get_protocol(struct usb_device *dev); +int usb_set_protocol(struct usb_device *dev, int protocol); +int usb_set_idle(struct usb_device *dev, int duration, int report_id); +int usb_set_configuration(struct usb_device *dev, int configuration); +int usb_get_report(struct usb_device *dev); + +/* + * Debugging helpers.. + */ +void usb_show_device_descriptor(struct usb_device_descriptor *); +void usb_show_config_descriptor(struct usb_config_descriptor *); +void usb_show_interface_descriptor(struct usb_interface_descriptor *); +void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *); +void usb_show_hub_descriptor(struct usb_hub_descriptor *); +void usb_show_device(struct usb_device *); + +#endif + diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c index 12f7f6f6d99a..ac81954d7b6c 100644 --- a/fs/adfs/dir.c +++ b/fs/adfs/dir.c @@ -280,8 +280,6 @@ static int adfs_readdir (struct file *filp, void *dirent, filldir_t filldir) unsigned long parent_object_id, dir_object_id; int buffers, pos; - if (!inode || !S_ISDIR(inode->i_mode)) - return -EBADF; sb = inode->i_sb; if (filp->f_pos > ADFS_NUM_DIR_ENTRIES + 2) diff --git a/fs/adfs/namei.c b/fs/adfs/namei.c index 24f0565d92e3..4f6e066845f1 100644 --- a/fs/adfs/namei.c +++ b/fs/adfs/namei.c @@ -98,22 +98,22 @@ static int adfs_find_entry (struct inode *dir, const char * const name, int name return 0; } -int adfs_lookup (struct inode *dir, struct dentry *dentry) +struct dentry *adfs_lookup (struct inode *dir, struct dentry *dentry) { struct inode *inode = NULL; struct adfs_idir_entry de; unsigned long ino; if (dentry->d_name.len > ADFS_NAME_LEN) - return -ENAMETOOLONG; + return ERR_PTR(-ENAMETOOLONG); if (adfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de)) { ino = de.inode_no; inode = iget (dir->i_sb, ino); if (!inode) - return -EACCES; + return ERR_PTR(-EACCES); } d_add(dentry, inode); - return 0; + return NULL; } diff --git a/fs/affs/dir.c b/fs/affs/dir.c index 51e45b682be0..3a1c78ef0901 100644 --- a/fs/affs/dir.c +++ b/fs/affs/dir.c @@ -90,9 +90,6 @@ affs_readdir(struct file *filp, void *dirent, filldir_t filldir) pr_debug("AFFS: readdir(ino=%lu,f_pos=%lu)\n",inode->i_ino,(unsigned long)filp->f_pos); - if (!inode || !S_ISDIR(inode->i_mode)) - return -EBADF; - stored = 0; dir_bh = NULL; fh_bh = NULL; diff --git a/fs/affs/namei.c b/fs/affs/namei.c index b2ebb98d7f26..48e95180000f 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -201,7 +201,7 @@ affs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino) return bh; } -int +struct dentry * affs_lookup(struct inode *dir, struct dentry *dentry) { unsigned long ino; @@ -218,11 +218,11 @@ affs_lookup(struct inode *dir, struct dentry *dentry) affs_brelse(bh); inode = iget(dir->i_sb,ino); if (!inode) - return -EACCES; + return ERR_PTR(-EACCES); } dentry->d_op = &affs_dentry_operations; d_add(dentry,inode); - return 0; + return NULL; } int diff --git a/fs/autofs/dir.c b/fs/autofs/dir.c index 63efe9b87025..d6944e889d4f 100644 --- a/fs/autofs/dir.c +++ b/fs/autofs/dir.c @@ -38,10 +38,10 @@ static int autofs_dir_readdir(struct file *filp, /* * No entries except for "." and "..", both of which are handled by the VFS layer */ -static int autofs_dir_lookup(struct inode *dir, struct dentry * dentry) +static struct dentry *autofs_dir_lookup(struct inode *dir,struct dentry *dentry) { d_add(dentry, NULL); - return 0; + return NULL; } static struct file_operations autofs_dir_operations = { diff --git a/fs/autofs/root.c b/fs/autofs/root.c index 396f32131876..c860f13ebce2 100644 --- a/fs/autofs/root.c +++ b/fs/autofs/root.c @@ -16,7 +16,7 @@ #include "autofs_i.h" static int autofs_root_readdir(struct file *,void *,filldir_t); -static int autofs_root_lookup(struct inode *,struct dentry *); +static struct dentry *autofs_root_lookup(struct inode *,struct dentry *); static int autofs_root_symlink(struct inode *,struct dentry *,const char *); static int autofs_root_unlink(struct inode *,struct dentry *); static int autofs_root_rmdir(struct inode *,struct dentry *); @@ -209,7 +209,7 @@ static struct dentry_operations autofs_dentry_operations = { NULL, /* d_compare */ }; -static int autofs_root_lookup(struct inode *dir, struct dentry *dentry) +static struct dentry *autofs_root_lookup(struct inode *dir, struct dentry *dentry) { struct autofs_sb_info *sbi; int oz_mode; @@ -217,11 +217,8 @@ static int autofs_root_lookup(struct inode *dir, struct dentry *dentry) DPRINTK(("autofs_root_lookup: name = ")); autofs_say(dentry->d_name.name,dentry->d_name.len); - if (!S_ISDIR(dir->i_mode)) - return -ENOTDIR; - if (dentry->d_name.len > NAME_MAX) - return -ENOENT; /* File name too long to exist */ + return ERR_PTR(-ENOENT);/* File name too long to exist */ sbi = autofs_sbi(dir->i_sb); @@ -253,7 +250,7 @@ static int autofs_root_lookup(struct inode *dir, struct dentry *dentry) */ if (dentry->d_flags & DCACHE_AUTOFS_PENDING) { if (signal_pending(current)) - return -ERESTARTNOINTR; + return ERR_PTR(-ERESTARTNOINTR); } /* @@ -263,9 +260,9 @@ static int autofs_root_lookup(struct inode *dir, struct dentry *dentry) * be OK for the operations we permit from an autofs. */ if ( dentry->d_inode && list_empty(&dentry->d_hash) ) - return -ENOENT; + return ERR_PTR(-ENOENT); - return 0; + return NULL; } static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const char *symname) diff --git a/fs/buffer.c b/fs/buffer.c index dbbff73d4af4..0abf18949405 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -804,6 +804,7 @@ void __brelse(struct buffer_head * buf) /* If dirty, mark the time this buffer should be written back. */ set_writetime(buf, 0); refile_buffer(buf); + touch_buffer(buf); if (buf->b_count) { buf->b_count--; @@ -839,7 +840,6 @@ struct buffer_head * bread(kdev_t dev, int block, int size) struct buffer_head * bh; bh = getblk(dev, block, size); - touch_buffer(bh); if (buffer_uptodate(bh)) return bh; ll_rw_block(READ, 1, &bh); @@ -876,7 +876,6 @@ struct buffer_head * breada(kdev_t dev, int block, int bufsize, bh = getblk(dev, block, bufsize); index = BUFSIZE_INDEX(bh->b_size); - touch_buffer(bh); if (buffer_uptodate(bh)) return(bh); else ll_rw_block(READ, 1, &bh); diff --git a/fs/coda/dir.c b/fs/coda/dir.c index b87728d7bbbe..136c817be85f 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -29,7 +29,7 @@ /* dir inode-ops */ static int coda_create(struct inode *dir, struct dentry *new, int mode); static int coda_mknod(struct inode *dir, struct dentry *new, int mode, int rdev); -static int coda_lookup(struct inode *dir, struct dentry *target); +static struct dentry *coda_lookup(struct inode *dir, struct dentry *target); static int coda_link(struct dentry *old_dentry, struct inode *dir_inode, struct dentry *entry); static int coda_unlink(struct inode *dir_inode, struct dentry *entry); @@ -107,7 +107,7 @@ struct file_operations coda_dir_operations = { /* inode operations for directories */ /* acces routines: lookup, readlink, permission */ -static int coda_lookup(struct inode *dir, struct dentry *entry) +static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry) { struct coda_inode_info *dircnp; struct inode *res_inode = NULL; @@ -125,16 +125,9 @@ static int coda_lookup(struct inode *dir, struct dentry *entry) if ( length > CODA_MAXNAMLEN ) { printk("name too long: lookup, %s (%*s)\n", coda_f2s(&dircnp->c_fid), length, name); - return -ENAMETOOLONG; + return ERR_PTR(-ENAMETOOLONG); } - - if (!dir || !S_ISDIR(dir->i_mode)) { - printk("coda_lookup: inode is NULL or not a directory\n"); - return -ENOTDIR; - } - - CDEBUG(D_INODE, "name %s, len %d in ino %ld, fid %s\n", name, length, dir->i_ino, coda_f2s(&dircnp->c_fid)); @@ -160,11 +153,11 @@ static int coda_lookup(struct inode *dir, struct dentry *entry) } error = coda_cnode_make(&res_inode, &resfid, dir->i_sb); if (error) - return error; + return ERR_PTR(error); } else if (error != -ENOENT) { CDEBUG(D_INODE, "error for %s(%*s)%d\n", coda_f2s(&dircnp->c_fid), length, name, error); - return error; + return ERR_PTR(error); } CDEBUG(D_INODE, "lookup: %s is (%s), type %d result %d, dropme %d\n", name, coda_f2s(&resfid), type, error, dropme); @@ -178,7 +171,7 @@ exit: ITOC(res_inode)->c_flags |= C_VATTR; } EXIT; - return 0; + return NULL; } @@ -236,11 +229,6 @@ static int coda_create(struct inode *dir, struct dentry *de, int mode) CDEBUG(D_INODE, "name: %s, length %d, mode %o\n",name, length, mode); - if (!dir || !S_ISDIR(dir->i_mode)) { - printk("coda_create: inode is null or not a directory\n"); - return -ENOENT; - } - if (coda_isroot(dir) && coda_iscontrol(name, length)) return -EPERM; @@ -286,11 +274,6 @@ static int coda_mknod(struct inode *dir, struct dentry *de, int mode, int rdev) CDEBUG(D_INODE, "name: %s, length %d, mode %o, rdev %x\n",name, length, mode, rdev); - if (!dir || !S_ISDIR(dir->i_mode)) { - printk("coda_mknod: inode is null or not a directory\n"); - return -ENOENT; - } - if (coda_isroot(dir) && coda_iscontrol(name, length)) return -EPERM; @@ -332,11 +315,6 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, int mode) ENTRY; coda_vfs_stat.mkdir++; - if (!dir || !S_ISDIR(dir->i_mode)) { - printk("coda_mkdir: inode is NULL or not a directory\n"); - return -ENOENT; - } - if (coda_isroot(dir) && coda_iscontrol(name, len)) return -EPERM; @@ -490,10 +468,6 @@ int coda_rmdir(struct inode *dir, struct dentry *de) ENTRY; coda_vfs_stat.rmdir++; - if (!dir || !S_ISDIR(dir->i_mode)) { - printk("coda_rmdir: inode is NULL or not a directory\n"); - return -ENOENT; - } dircnp = ITOC(dir); if (!list_empty(&de->d_hash)) @@ -572,11 +546,6 @@ int coda_readdir(struct file *file, void *dirent, filldir_t filldir) ENTRY; coda_vfs_stat.readdir++; - if (!inode || !inode->i_sb || !S_ISDIR(inode->i_mode)) { - printk("coda_readdir: inode is NULL or not a directory\n"); - return -EBADF; - } - cnp = ITOC(inode); if ( !cnp->c_ovp ) { CDEBUG(D_FILE, "open inode pointer = NULL.\n"); diff --git a/fs/dcache.c b/fs/dcache.c index 279f3d5dd52c..aa299f61ed11 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -471,8 +471,12 @@ void shrink_dcache_parent(struct dentry * parent) */ void shrink_dcache_memory(int priority, unsigned int gfp_mask) { - if (gfp_mask & __GFP_IO) - prune_dcache(0); + if (gfp_mask & __GFP_IO) { + int count = 0; + if (priority) + count = dentry_stat.nr_unused / priority; + prune_dcache(count); + } } #define NAME_ALLOC_LEN(len) ((len+16) & ~15) diff --git a/fs/devpts/root.c b/fs/devpts/root.c index f517367b950f..84388c763722 100644 --- a/fs/devpts/root.c +++ b/fs/devpts/root.c @@ -17,7 +17,7 @@ #include "devpts_i.h" static int devpts_root_readdir(struct file *,void *,filldir_t); -static int devpts_root_lookup(struct inode *,struct dentry *); +static struct dentry *devpts_root_lookup(struct inode *,struct dentry *); static int devpts_revalidate(struct dentry *); static struct file_operations devpts_root_operations = { @@ -81,9 +81,6 @@ static int devpts_root_readdir(struct file *filp, void *dirent, filldir_t filldi off_t nr; char numbuf[16]; - if (!inode || !S_ISDIR(inode->i_mode)) - return -ENOTDIR; - nr = filp->f_pos; switch(nr) @@ -131,42 +128,39 @@ static int devpts_revalidate(struct dentry * dentry) return ( sbi->inodes[dentry->d_inode->i_ino - 2] == dentry->d_inode ); } -static int devpts_root_lookup(struct inode * dir, struct dentry * dentry) +static struct dentry *devpts_root_lookup(struct inode * dir, struct dentry * dentry) { struct devpts_sb_info *sbi = SBI(dir->i_sb); unsigned int entry; int i; const char *p; - if (!S_ISDIR(dir->i_mode)) - return -ENOTDIR; - dentry->d_inode = NULL; /* Assume failure */ dentry->d_op = &devpts_dentry_operations; if ( dentry->d_name.len == 1 && dentry->d_name.name[0] == '0' ) { entry = 0; } else if ( dentry->d_name.len < 1 ) { - return 0; + return NULL; } else { p = dentry->d_name.name; if ( *p < '1' || *p > '9' ) - return 0; + return NULL; entry = *p++ - '0'; for ( i = dentry->d_name.len-1 ; i ; i-- ) { unsigned int nentry = *p++ - '0'; if ( nentry > 9 ) - return 0; + return NULL; nentry += entry * 10; if (nentry < entry) - return 0; + return NULL; entry = nentry; } } if ( entry >= sbi->max_ptys ) - return 0; + return NULL; dentry->d_inode = sbi->inodes[entry]; if ( dentry->d_inode ) @@ -174,5 +168,5 @@ static int devpts_root_lookup(struct inode * dir, struct dentry * dentry) d_add(dentry, dentry->d_inode); - return 0; + return NULL; } diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index 22af55334244..a6753d27682f 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -115,8 +115,6 @@ static int ext2_readdir(struct file * filp, int err; struct inode *inode = filp->f_dentry->d_inode; - if (!inode || !S_ISDIR(inode->i_mode)) - return -EBADF; sb = inode->i_sb; stored = 0; diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index 674d8b6d62fa..762ef1df749d 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -168,14 +168,14 @@ failure: return NULL; } -int ext2_lookup(struct inode * dir, struct dentry *dentry) +struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry) { struct inode * inode; struct ext2_dir_entry_2 * de; struct buffer_head * bh; if (dentry->d_name.len > EXT2_NAME_LEN) - return -ENAMETOOLONG; + return ERR_PTR(-ENAMETOOLONG); bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de); inode = NULL; @@ -185,10 +185,10 @@ int ext2_lookup(struct inode * dir, struct dentry *dentry) inode = iget(dir->i_sb, ino); if (!inode) - return -EACCES; + return ERR_PTR(-EACCES); } d_add(dentry, inode); - return 0; + return NULL; } /* diff --git a/fs/fat/dir.c b/fs/fat/dir.c index 1c44247a00a5..b6d6fb4052c3 100644 --- a/fs/fat/dir.c +++ b/fs/fat/dir.c @@ -9,6 +9,7 @@ * * VFAT extensions by Gordon Chaffee * Merged with msdos fs by Henrik Storner + * Plugged buffer overrun in readdir(). AV */ #define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S)) @@ -59,6 +60,7 @@ struct file_operations fat_dir_operations = { * characters are a sort of uuencoded 16 bit Unicode value. This lets * us do a full dump and restore of Unicode filenames. We could get * into some trouble with long Unicode names, but ignore that right now. + * Ahem... Stack smashing in ring 0 isn't fun. Fixed. */ static int uni16_to_x8(unsigned char *ascii, unsigned char *uni, int uni_xlate, @@ -93,6 +95,11 @@ uni16_to_x8(unsigned char *ascii, unsigned char *uni, int uni_xlate, *op++ = '?'; } } + /* We have some slack there, so it's OK */ + if (op>ascii+256) { + op = ascii + 256; + break; + } } *op = 0; return (op - ascii); @@ -138,8 +145,6 @@ int fat_readdirx( unsigned char *unicode = NULL; struct nls_table *nls = MSDOS_SB(sb)->nls_io; - if (!inode || !S_ISDIR(inode->i_mode)) - return -EBADF; /* Fake . and .. for the root directory. */ if (inode->i_ino == MSDOS_ROOT_INO) { while (oldpos < 2) { @@ -186,9 +191,17 @@ int fat_readdirx( id = ds->id; if (id & 0x40) { slots = id & ~0x40; - long_slots = slots; - is_long = 1; - alias_checksum = ds->alias_checksum; + /* + * Dirty, but not dirtier than the original, + * and plugs the hole. + */ + if (slots > 20) + slots = 0; + else { + long_slots = slots; + is_long = 1; + alias_checksum = ds->alias_checksum; + } } get_new_entry = 1; diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 39067dd1c848..339bcb6f6014 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -332,7 +332,6 @@ fat_read_super(struct super_block *sb, void *data, int silent) fat_brelse (sb, bh); goto out_no_bread; } - set_blocksize(sb->s_dev, blksize); /* * The DOS3 partition size limit is *not* 32M as many people think. @@ -423,6 +422,7 @@ fat_read_super(struct super_block *sb, void *data, int silent) || !b->secs_track || !b->heads; } fat_brelse(sb, bh); + set_blocksize(sb->s_dev, blksize); /* This must be done after the brelse because the bh is a dummy allocated by fat_bread (see buffer.c) diff --git a/fs/hfs/dir_cap.c b/fs/hfs/dir_cap.c index 03fa7f7ae202..0ab81d966332 100644 --- a/fs/hfs/dir_cap.c +++ b/fs/hfs/dir_cap.c @@ -27,7 +27,7 @@ /*================ Forward declarations ================*/ -static int cap_lookup(struct inode *, struct dentry *); +static struct dentry *cap_lookup(struct inode *, struct dentry *); static int cap_readdir(struct file *, void *, filldir_t); /*================ Global variables ================*/ @@ -147,7 +147,7 @@ struct inode_operations hfs_cap_rdir_inode_operations = { * inode corresponding to an entry in a directory, given the inode for * the directory and the name (and its length) of the entry. */ -static int cap_lookup(struct inode * dir, struct dentry *dentry) +static struct dentry *cap_lookup(struct inode * dir, struct dentry *dentry) { ino_t dtype; struct hfs_name cname; @@ -155,10 +155,6 @@ static int cap_lookup(struct inode * dir, struct dentry *dentry) struct hfs_cat_key key; struct inode *inode = NULL; - if (!dir || !S_ISDIR(dir->i_mode)) { - return -ENOENT; - } - dentry->d_op = &hfs_dentry_operations; entry = HFS_I(dir)->entry; dtype = HFS_ITYPE(dir->i_ino); @@ -207,7 +203,7 @@ static int cap_lookup(struct inode * dir, struct dentry *dentry) done: d_add(dentry, inode); - return 0; + return NULL; } /* diff --git a/fs/hfs/dir_dbl.c b/fs/hfs/dir_dbl.c index 4e4e6fcc3d2e..80e990627351 100644 --- a/fs/hfs/dir_dbl.c +++ b/fs/hfs/dir_dbl.c @@ -23,7 +23,7 @@ /*================ Forward declarations ================*/ -static int dbl_lookup(struct inode *, struct dentry *); +static struct dentry *dbl_lookup(struct inode *, struct dentry *); static int dbl_readdir(struct file *, void *, filldir_t); static int dbl_create(struct inode *, struct dentry *, int); static int dbl_mkdir(struct inode *, struct dentry *, int); @@ -130,17 +130,13 @@ static int is_hdr(struct inode *dir, const char *name, int len) * the inode for the directory and the name (and its length) of the * entry. */ -static int dbl_lookup(struct inode * dir, struct dentry *dentry) +static struct dentry *dbl_lookup(struct inode * dir, struct dentry *dentry) { struct hfs_name cname; struct hfs_cat_entry *entry; struct hfs_cat_key key; struct inode *inode = NULL; - if (!dir || !S_ISDIR(dir->i_mode)) { - return -ENOENT; - } - dentry->d_op = &hfs_dentry_operations; entry = HFS_I(dir)->entry; @@ -173,7 +169,7 @@ static int dbl_lookup(struct inode * dir, struct dentry *dentry) done: d_add(dentry, inode); - return 0; + return NULL; } /* diff --git a/fs/hfs/dir_nat.c b/fs/hfs/dir_nat.c index a4078e891ab7..5cff9d814263 100644 --- a/fs/hfs/dir_nat.c +++ b/fs/hfs/dir_nat.c @@ -29,7 +29,7 @@ /*================ Forward declarations ================*/ -static int nat_lookup(struct inode *, struct dentry *); +static struct dentry *nat_lookup(struct inode *, struct dentry *); static int nat_readdir(struct file *, void *, filldir_t); static int nat_rmdir(struct inode *, struct dentry *); static int nat_hdr_unlink(struct inode *, struct dentry *); @@ -136,7 +136,7 @@ struct inode_operations hfs_nat_hdir_inode_operations = { * the inode corresponding to an entry in a directory, given the inode * for the directory and the name (and its length) of the entry. */ -static int nat_lookup(struct inode * dir, struct dentry *dentry) +static struct dentry *nat_lookup(struct inode * dir, struct dentry *dentry) { ino_t dtype; struct hfs_name cname; @@ -144,10 +144,6 @@ static int nat_lookup(struct inode * dir, struct dentry *dentry) struct hfs_cat_key key; struct inode *inode = NULL; - if (!dir || !S_ISDIR(dir->i_mode)) { - return -ENOENT; - } - dentry->d_op = &hfs_dentry_operations; entry = HFS_I(dir)->entry; dtype = HFS_ITYPE(dir->i_ino); @@ -199,7 +195,7 @@ static int nat_lookup(struct inode * dir, struct dentry *dentry) done: d_add(dentry, inode); - return 0; + return NULL; } /* diff --git a/fs/hpfs/hpfs_fs.c b/fs/hpfs/hpfs_fs.c index feafa2861cad..cb1d0215be8a 100644 --- a/fs/hpfs/hpfs_fs.c +++ b/fs/hpfs/hpfs_fs.c @@ -192,7 +192,7 @@ static ssize_t hpfs_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos); static int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir); -static int hpfs_lookup(struct inode *, struct dentry *); +static struct dentry *hpfs_lookup(struct inode *, struct dentry *); static const struct file_operations hpfs_dir_ops = { @@ -1119,7 +1119,7 @@ static secno bplus_lookup(struct inode *inode, struct bplus_header *b, * the boondocks.) */ -static int hpfs_lookup(struct inode *dir, struct dentry *dentry) +static struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry) { const char *name = dentry->d_name.name; int len = dentry->d_name.len; @@ -1129,14 +1129,6 @@ static int hpfs_lookup(struct inode *dir, struct dentry *dentry) int retval; struct quad_buffer_head qbh; - /* In case of madness */ - - retval = -ENOTDIR; - if (dir == 0) - goto out; - if (!S_ISDIR(dir->i_mode)) - goto out; - /* * Read in the directory entry. "." is there under the name ^A^A . * Always read the dir even for . and .. in case we need the dates. @@ -1208,7 +1200,7 @@ static int hpfs_lookup(struct inode *dir, struct dentry *dentry) brelse4(&qbh); out: - return retval; + return ERR_PTR(retval); } /* @@ -1374,11 +1366,6 @@ static int hpfs_readdir(struct file *filp, void * dirent, long old_pos; struct inode *inode = filp->f_dentry->d_inode; - if (inode == 0 - || inode->i_sb == 0 - || !S_ISDIR(inode->i_mode)) - return -EBADF; - tempname = (char *) __get_free_page(GFP_KERNEL); if (!tempname) return -ENOMEM; diff --git a/fs/inode.c b/fs/inode.c index 3eab050e6c90..930e18826b12 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -359,10 +359,8 @@ static int free_inodes(void) found = 1; } - if (found) { + if (found) dispose_list(freeable); - found = 1; /* silly compiler */ - } return found; } @@ -750,7 +748,7 @@ int bmap(struct inode * inode, int block) * Initialize the hash tables and default * value for max inodes */ -#define MAX_INODE (12288) +#define MAX_INODE (16384) void __init inode_init(void) { diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c index a57f9680c637..23ca159c75a2 100644 --- a/fs/isofs/dir.c +++ b/fs/isofs/dir.c @@ -295,9 +295,6 @@ static int isofs_readdir(struct file *filp, struct iso_directory_record * tmpde; struct inode *inode = filp->f_dentry->d_inode; - if (!inode || !S_ISDIR(inode->i_mode)) - return -EBADF; - tmpname = (char *) __get_free_page(GFP_KERNEL); if (!tmpname) return -ENOMEM; diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c index 364698dc28de..e265a7304784 100644 --- a/fs/isofs/namei.c +++ b/fs/isofs/namei.c @@ -228,7 +228,7 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino) return retval; } -int isofs_lookup(struct inode * dir, struct dentry * dentry) +struct dentry *isofs_lookup(struct inode * dir, struct dentry * dentry) { unsigned long ino; struct buffer_head * bh; @@ -237,12 +237,6 @@ int isofs_lookup(struct inode * dir, struct dentry * dentry) #ifdef DEBUG printk("lookup: %x %s\n",dir->i_ino, dentry->d_name.name); #endif - if (!dir) - return -ENOENT; - - if (!S_ISDIR(dir->i_mode)) - return -ENOENT; - dentry->d_op = dir->i_sb->s_root->d_op; bh = isofs_find_entry(dir, dentry, &ino); @@ -253,8 +247,8 @@ int isofs_lookup(struct inode * dir, struct dentry * dentry) inode = iget(dir->i_sb,ino); if (!inode) - return -EACCES; + return ERR_PTR(-EACCES); } d_add(dentry, inode); - return 0; + return NULL; } diff --git a/fs/minix/dir.c b/fs/minix/dir.c index d7db754ffdfc..187925903b5a 100644 --- a/fs/minix/dir.c +++ b/fs/minix/dir.c @@ -68,8 +68,6 @@ static int minix_readdir(struct file * filp, struct minix_sb_info * info; struct inode *inode = filp->f_dentry->d_inode; - if (!inode || !inode->i_sb || !S_ISDIR(inode->i_mode)) - return -EBADF; info = &inode->i_sb->u.minix_sb; if (filp->f_pos & (info->s_dirsize - 1)) return -EBADF; diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 382a869b1cf5..60032292c3cb 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -38,14 +38,13 @@ static void minix_delete_inode(struct inode *inode) minix_free_inode(inode); } -static void minix_commit_super (struct super_block * sb, - struct minix_super_block * ms) +static void minix_commit_super(struct super_block * sb) { mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1); sb->s_dirt = 0; } -static void minix_write_super (struct super_block * sb) +static void minix_write_super(struct super_block * sb) { struct minix_super_block * ms; @@ -54,7 +53,7 @@ static void minix_write_super (struct super_block * sb) if (ms->s_state & MINIX_VALID_FS) ms->s_state &= ~MINIX_VALID_FS; - minix_commit_super (sb, ms); + minix_commit_super(sb); } sb->s_dirt = 0; } @@ -106,7 +105,7 @@ static int minix_remount (struct super_block * sb, int * flags, char * data) ms->s_state = sb->u.minix_sb.s_mount_state; mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1); sb->s_dirt = 1; - minix_commit_super (sb, ms); + minix_commit_super(sb); } else { /* Mount a partition which is read-only, read-write. */ diff --git a/fs/minix/namei.c b/fs/minix/namei.c index 3bf0f22dc48c..e26967d615c5 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -116,7 +116,7 @@ struct dentry_operations minix_dentry_operations = { 0 /* compare */ }; -int minix_lookup(struct inode * dir, struct dentry *dentry) +struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry) { struct inode * inode = NULL; struct minix_dir_entry * de; @@ -132,10 +132,10 @@ int minix_lookup(struct inode * dir, struct dentry *dentry) inode = iget(dir->i_sb, ino); if (!inode) - return -EACCES; + return ERR_PTR(-EACCES); } d_add(dentry, inode); - return 0; + return NULL; } /* @@ -221,8 +221,6 @@ int minix_create(struct inode * dir, struct dentry *dentry, int mode) struct buffer_head * bh; struct minix_dir_entry * de; - if (!dir) - return -ENOENT; inode = minix_new_inode(dir); if (!inode) return -ENOSPC; @@ -251,8 +249,6 @@ int minix_mknod(struct inode * dir, struct dentry *dentry, int mode, int rdev) struct buffer_head * bh; struct minix_dir_entry * de; - if (!dir) - return -ENOENT; bh = minix_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); if (bh) { @@ -298,8 +294,6 @@ int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode) struct minix_dir_entry * de; struct minix_sb_info * info; - if (!dir || !dir->i_sb) - return -EINVAL; info = &dir->i_sb->u.minix_sb; bh = minix_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c index a364faf2117f..dc9faa9a15a9 100644 --- a/fs/msdos/namei.c +++ b/fs/msdos/namei.c @@ -250,7 +250,7 @@ out_fail: /***** Get inode using directory and name */ -int msdos_lookup(struct inode *dir,struct dentry *dentry) +struct dentry *msdos_lookup(struct inode *dir,struct dentry *dentry) { struct super_block *sb = dir->i_sb; struct inode *inode = NULL; @@ -292,7 +292,7 @@ add: d_add(dentry, inode); res = 0; out: - return res; + return ERR_PTR(res); } diff --git a/fs/namei.c b/fs/namei.c index 21de93da4ad8..512fc9be5c08 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -263,12 +263,11 @@ static struct dentry * real_lookup(struct dentry * parent, struct qstr * name) struct dentry * dentry = d_alloc(parent, name); result = ERR_PTR(-ENOMEM); if (dentry) { - int error = dir->i_op->lookup(dir, dentry); - result = dentry; - if (error) { + result = dir->i_op->lookup(dir, dentry); + if (result) dput(dentry); - result = ERR_PTR(error); - } + else + result = dentry; } } up(&dir->i_sem); diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 7a284742e3f1..5648f6725553 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -50,7 +50,7 @@ static ssize_t ncp_dir_read(struct file *, char *, size_t, loff_t *); static int ncp_readdir(struct file *, void *, filldir_t); static int ncp_create(struct inode *, struct dentry *, int); -static int ncp_lookup(struct inode *, struct dentry *); +static struct dentry *ncp_lookup(struct inode *, struct dentry *); static int ncp_unlink(struct inode *, struct dentry *); static int ncp_mkdir(struct inode *, struct dentry *, int); static int ncp_rmdir(struct inode *, struct dentry *); @@ -440,11 +440,6 @@ static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir) DDPRINTK(KERN_DEBUG "ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n", inode->i_ino, c_ino); - result = -EBADF; - if (!inode || !S_ISDIR(inode->i_mode)) { - printk(KERN_WARNING "ncp_readdir: inode is NULL or not a directory\n"); - goto out; - } result = -EIO; if (!ncp_conn_valid(server)) goto out; @@ -744,7 +739,7 @@ out: return result; } -static int ncp_lookup(struct inode *dir, struct dentry *dentry) +static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry) { struct ncp_server *server; struct inode *inode = NULL; @@ -754,11 +749,6 @@ static int ncp_lookup(struct inode *dir, struct dentry *dentry) struct ncpfs_inode_info finfo; __u8 __name[dentry->d_name.len + 1]; - error = -ENOENT; - if (!dir || !S_ISDIR(dir->i_mode)) { - printk(KERN_WARNING "ncp_lookup: inode is NULL or not a directory.\n"); - goto finished; - } server = NCP_SERVER(dir); error = -EIO; @@ -831,7 +821,7 @@ dentry->d_parent->d_name.name, __name, res); if (res != 0) { goto add_entry; } else vol2io(server, finfo.nw_info.i.entryName, - ncp_preserve_entry_case(dir, + !ncp_preserve_entry_case(dir, finfo.nw_info.i.NSCreator)); } @@ -854,7 +844,7 @@ finished: #ifdef NCPFS_PARANOIA printk(KERN_DEBUG "ncp_lookup: result=%d\n", error); #endif - return error; + return ERR_PTR(error); } /* @@ -897,10 +887,6 @@ int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode, printk(KERN_DEBUG "ncp_create_new: creating %s/%s, mode=%x\n", dentry->d_parent->d_name.name, dentry->d_name.name, mode); #endif - if (!dir || !S_ISDIR(dir->i_mode)) { - printk(KERN_WARNING "ncp_create_new: inode is NULL or not a directory\n"); - return -ENOENT; - } error = -EIO; if (!ncp_conn_valid(NCP_SERVER(dir))) goto out; @@ -940,11 +926,6 @@ static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode) DPRINTK(KERN_DEBUG "ncp_mkdir: making %s/%s\n", dentry->d_parent->d_name.name, dentry->d_name.name); - error = -ENOTDIR; - if (!dir || !S_ISDIR(dir->i_mode)) { - printk(KERN_WARNING "ncp_mkdir: inode is NULL or not a directory\n"); - goto out; - } error = -EIO; if (!ncp_conn_valid(NCP_SERVER(dir))) goto out; @@ -971,13 +952,6 @@ static int ncp_rmdir(struct inode *dir, struct dentry *dentry) DPRINTK(KERN_DEBUG "ncp_rmdir: removing %s/%s\n", dentry->d_parent->d_name.name, dentry->d_name.name); - - error = -ENOENT; - if (!dir || !S_ISDIR(dir->i_mode)) - { - printk(KERN_WARNING "ncp_rmdir: inode is NULL or not a directory\n"); - goto out; - } error = -EIO; if (!ncp_conn_valid(NCP_SERVER(dir))) @@ -1030,11 +1004,6 @@ static int ncp_unlink(struct inode *dir, struct dentry *dentry) DPRINTK(KERN_DEBUG "ncp_unlink: unlinking %s/%s\n", dentry->d_parent->d_name.name, dentry->d_name.name); - error = -ENOTDIR; - if (!dir || !S_ISDIR(dir->i_mode)) { - printk(KERN_WARNING "ncp_unlink: inode is NULL or not a directory\n"); - goto out; - } error = -EIO; if (!ncp_conn_valid(NCP_SERVER(dir))) goto out; @@ -1102,15 +1071,6 @@ static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry, old_dentry->d_parent->d_name.name, old_dentry->d_name.name, new_dentry->d_parent->d_name.name, new_dentry->d_name.name); - error = -ENOTDIR; - if (!old_dir || !S_ISDIR(old_dir->i_mode)) { - printk(KERN_WARNING "ncp_rename: old inode is NULL or not a directory\n"); - goto out; - } - if (!new_dir || !S_ISDIR(new_dir->i_mode)) { - printk(KERN_WARNING "ncp_rename: new inode is NULL or not a directory\n"); - goto out; - } error = -EIO; if (!ncp_conn_valid(NCP_SERVER(old_dir))) goto out; diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 5f06f787d160..4bc541f9a9a0 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -51,10 +51,9 @@ struct nfs_dirent { static int nfs_safe_remove(struct dentry *); -static int nfs_dir_open(struct inode *, struct file *); static ssize_t nfs_dir_read(struct file *, char *, size_t, loff_t *); static int nfs_readdir(struct file *, void *, filldir_t); -static int nfs_lookup(struct inode *, struct dentry *); +static struct dentry *nfs_lookup(struct inode *, struct dentry *); static int nfs_create(struct inode *, struct dentry *, int); static int nfs_mkdir(struct inode *, struct dentry *, int); static int nfs_rmdir(struct inode *, struct dentry *); @@ -73,7 +72,7 @@ static struct file_operations nfs_dir_operations = { NULL, /* select - default */ NULL, /* ioctl - default */ NULL, /* mmap */ - nfs_dir_open, /* open - revalidate */ + NULL, /* no special open is needed */ NULL, /* flush */ NULL, /* no special release code */ NULL /* fsync */ @@ -102,16 +101,6 @@ struct inode_operations nfs_dir_inode_operations = { nfs_revalidate, /* revalidate */ }; -static int -nfs_dir_open(struct inode *dir, struct file *file) -{ - struct dentry *dentry = file->f_dentry; - - dfprintk(VFS, "NFS: nfs_dir_open(%s/%s)\n", - dentry->d_parent->d_name.name, dentry->d_name.name); - return _nfs_revalidate_inode(NFS_DSERVER(dentry), dentry); -} - static ssize_t nfs_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos) { @@ -147,11 +136,6 @@ static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir) dfprintk(VFS, "NFS: nfs_readdir(%s/%s)\n", dentry->d_parent->d_name.name, dentry->d_name.name); - result = -EBADF; - if (!inode || !S_ISDIR(inode->i_mode)) { - printk("nfs_readdir: inode is NULL or not a directory\n"); - goto out; - } result = nfs_revalidate_inode(NFS_DSERVER(dentry), dentry); if (result < 0) @@ -397,7 +381,6 @@ static int nfs_lookup_revalidate(struct dentry * dentry) { struct dentry * parent = dentry->d_parent; struct inode * inode = dentry->d_inode; - unsigned long time = jiffies - dentry->d_time; int error; struct nfs_fh fhandle; struct nfs_fattr fattr; @@ -406,31 +389,36 @@ static int nfs_lookup_revalidate(struct dentry * dentry) * If we don't have an inode, let's just assume * a 5-second "live" time for negative dentries. */ - if (!inode) { - if (time < NFS_REVALIDATE_INTERVAL) - goto out_valid; - goto out_bad; - } + if (!inode) + goto do_lookup; if (is_bad_inode(inode)) { -#ifdef NFS_PARANOIA -printk("nfs_lookup_validate: %s/%s has dud inode\n", -parent->d_name.name, dentry->d_name.name); -#endif + dfprintk(VFS, "nfs_lookup_validate: %s/%s has dud inode\n", + parent->d_name.name, dentry->d_name.name); goto out_bad; } - if (time < NFS_ATTRTIMEO(inode)) + if (_nfs_revalidate_inode(NFS_DSERVER(dentry), dentry)) + goto out_bad; + + if (time_before(jiffies,dentry->d_time+NFS_ATTRTIMEO(inode))) goto out_valid; if (IS_ROOT(dentry)) goto out_valid; +do_lookup: /* * Do a new lookup and check the dentry attributes. */ error = nfs_proc_lookup(NFS_DSERVER(parent), NFS_FH(parent), dentry->d_name.name, &fhandle, &fattr); + if (dentry->d_inode == NULL) { + if (error == -ENOENT && + time_before(jiffies,dentry->d_time+NFS_REVALIDATE_INTERVAL)) + goto out_valid; + goto out_bad; + } if (error) goto out_bad; @@ -440,7 +428,7 @@ parent->d_name.name, dentry->d_name.name); /* Filehandle matches? */ if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh))) { - if (dentry->d_count < 2 || nfs_revalidate(dentry)) + if (dentry->d_count < 2) goto out_bad; } @@ -451,6 +439,10 @@ parent->d_name.name, dentry->d_name.name); out_valid: return 1; out_bad: + if (dentry->d_parent->d_inode) + nfs_invalidate_dircache(dentry->d_parent->d_inode); + if (inode && S_ISDIR(inode->i_mode)) + nfs_invalidate_dircache(inode); return 0; } @@ -535,7 +527,7 @@ static void show_dentry(struct list_head * dlist) } #endif -static int nfs_lookup(struct inode *dir, struct dentry * dentry) +static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry) { struct inode *inode; int error; @@ -581,7 +573,7 @@ show_dentry(&inode->i_dentry); } } out: - return error; + return ERR_PTR(error); } /* @@ -766,7 +758,7 @@ struct dentry *nfs_silly_lookup(struct dentry *parent, char *silly, int slen) { struct qstr sqstr; struct dentry *sdentry; - int error; + struct dentry *res; sqstr.name = silly; sqstr.len = slen; @@ -776,10 +768,10 @@ struct dentry *nfs_silly_lookup(struct dentry *parent, char *silly, int slen) sdentry = d_alloc(parent, &sqstr); if (sdentry == NULL) return ERR_PTR(-ENOMEM); - error = nfs_lookup(parent->d_inode, sdentry); - if (error) { + res = nfs_lookup(parent->d_inode, sdentry); + if (res) { dput(sdentry); - return ERR_PTR(error); + return res; } } return sdentry; diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 5d3262271e1e..c5dc24b83413 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -37,7 +37,6 @@ static ssize_t nfs_file_read(struct file *, char *, size_t, loff_t *); static ssize_t nfs_file_write(struct file *, const char *, size_t, loff_t *); static int nfs_file_flush(struct file *); static int nfs_fsync(struct file *, struct dentry *dentry); -static int nfs_file_open(struct inode *inode, struct file *filp); static struct file_operations nfs_file_operations = { NULL, /* lseek - default */ @@ -47,7 +46,7 @@ static struct file_operations nfs_file_operations = { NULL, /* select - default */ NULL, /* ioctl - default */ nfs_file_mmap, /* mmap */ - nfs_file_open, /* open */ + NULL, /* no special open is needed */ nfs_file_flush, /* flush */ NULL, /* release */ nfs_fsync, /* fsync */ @@ -105,19 +104,6 @@ nfs_file_flush(struct file *file) return status; } -/* - * Open the file. - * Just checks the cache is synchronized. - */ -static int -nfs_file_open(struct inode *inode, struct file *filp) -{ - struct dentry *dentry = filp->f_dentry; - - return _nfs_revalidate_inode(NFS_DSERVER(dentry), dentry); -} - - static ssize_t nfs_file_read(struct file * file, char * buf, size_t count, loff_t *ppos) { diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 0b832e1a56ed..5efe7d898844 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -37,6 +37,8 @@ #define NFS_PARANOIA 1 static struct inode * __nfs_fhget(struct super_block *, struct nfs_fattr *); +static void nfs_zap_caches(struct inode *); +static void nfs_invalidate_inode(struct inode *); static void nfs_read_inode(struct inode *); static void nfs_put_inode(struct inode *); @@ -393,25 +395,61 @@ nfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) * could cause file corruption. But since the dentry * count is 0 and all pending IO for a dentry has been * flushed when the count went to 0, we're safe here. + * Also returns the number of unhashed dentries */ -void nfs_free_dentries(struct inode *inode) +static int +nfs_free_dentries(struct inode *inode) { struct list_head *tmp, *head = &inode->i_dentry; + int unhashed; restart: tmp = head; + unhashed = 0; while ((tmp = tmp->next) != head) { struct dentry *dentry = list_entry(tmp, struct dentry, d_alias); -printk("nfs_free_dentries: found %s/%s, d_count=%d, hashed=%d\n", -dentry->d_parent->d_name.name, dentry->d_name.name, -dentry->d_count, !list_empty(&dentry->d_hash)); + dprintk("nfs_free_dentries: found %s/%s, d_count=%d, hashed=%d\n", + dentry->d_parent->d_name.name, dentry->d_name.name, + dentry->d_count, !list_empty(&dentry->d_hash)); if (!dentry->d_count) { dget(dentry); d_drop(dentry); dput(dentry); goto restart; } + if (!list_empty(&dentry->d_hash)) + unhashed++; } + return unhashed; +} + +/* + * Invalidate the local caches + */ +static void +nfs_zap_caches(struct inode *inode) +{ + NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); + NFS_CACHEINV(inode); + + if (S_ISDIR(inode->i_mode)) + nfs_invalidate_dircache(inode); + else + invalidate_inode_pages(inode); +} + +/* + * Invalidate, but do not unhash, the inode + */ +static void +nfs_invalidate_inode(struct inode *inode) +{ + umode_t save_mode = inode->i_mode; + + make_bad_inode(inode); + inode->i_mode = save_mode; + nfs_inval(inode); + nfs_zap_caches(inode); } /* @@ -513,7 +551,7 @@ static struct inode * __nfs_fhget(struct super_block *sb, struct nfs_fattr *fattr) { struct inode *inode; - int max_count; + int max_count, stale_inode, unhashed = 0; retry: inode = iget(sb, fattr->fileid); @@ -532,27 +570,30 @@ retry: * as the inode may have become a different object. * (We can probably handle modes changes here, too.) */ + stale_inode = inode->i_mode && + ((fattr->mode ^ inode->i_mode) & S_IFMT); + stale_inode |= inode->i_count && inode->i_count == unhashed; max_count = S_ISDIR(fattr->mode) ? 1 : fattr->nlink; - if (inode->i_count > max_count) { -printk("__nfs_fhget: inode %ld busy, i_count=%d, i_nlink=%d\n", -inode->i_ino, inode->i_count, inode->i_nlink); - nfs_free_dentries(inode); - if (inode->i_count > max_count) { -printk("__nfs_fhget: inode %ld still busy, i_count=%d\n", -inode->i_ino, inode->i_count); + if (stale_inode || inode->i_count > max_count + unhashed) { + dprintk("__nfs_fhget: inode %ld busy, i_count=%d, i_nlink=%d\n", + inode->i_ino, inode->i_count, inode->i_nlink); + unhashed = nfs_free_dentries(inode); + if (stale_inode || inode->i_count > max_count + unhashed) { + printk("__nfs_fhget: inode %ld still busy, i_count=%d\n", + inode->i_ino, inode->i_count); if (!list_empty(&inode->i_dentry)) { struct dentry *dentry; dentry = list_entry(inode->i_dentry.next, struct dentry, d_alias); -printk("__nfs_fhget: killing %s/%s filehandle\n", -dentry->d_parent->d_name.name, dentry->d_name.name); - memset(dentry->d_fsdata, 0, + printk("__nfs_fhget: killing %s/%s filehandle\n", + dentry->d_parent->d_name.name, + dentry->d_name.name); + memset(dentry->d_fsdata, 0, sizeof(struct nfs_fh)); - } else - printk("NFS: inode %ld busy, no aliases?\n", - inode->i_ino); - make_bad_inode(inode); + } remove_inode_hash(inode); + nfs_invalidate_inode(inode); + unhashed = 0; } iput(inode); goto retry; @@ -673,10 +714,9 @@ _nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry) int error; u32 *fh; struct nfs_fh fhandle; -#ifdef NFS_PARANOIA -printk("nfs_revalidate_inode: %s/%s getattr failed, ino=%ld, error=%d\n", -dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino, status); -#endif + dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s getattr failed, ino=%ld, error=%d\n", + dentry->d_parent->d_name.name, + dentry->d_name.name, inode->i_ino, status); if (status != -ESTALE) goto out; /* @@ -684,26 +724,25 @@ dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino, status); * and find out what the filehandle should be. */ fh = (u32 *) NFS_FH(dentry); - printk("NFS: bad fh %08x%08x%08x%08x%08x%08x%08x%08x\n", + dfprintk(PAGECACHE, "NFS: bad fh %08x%08x%08x%08x%08x%08x%08x%08x\n", fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]); error = nfs_proc_lookup(server, NFS_FH(dentry->d_parent), dentry->d_name.name, &fhandle, &fattr); if (error) { - printk("NFS: lookup failed, error=%d\n", error); + dfprintk(PAGECACHE, "NFS: lookup failed, error=%d\n", error); goto out; } fh = (u32 *) &fhandle; - printk(" %08x%08x%08x%08x%08x%08x%08x%08x\n", + dfprintk(PAGECACHE, " %08x%08x%08x%08x%08x%08x%08x%08x\n", fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]); goto out; } status = nfs_refresh_inode(inode, &fattr); if (status) { -#ifdef NFS_PARANOIA -printk("nfs_revalidate_inode: %s/%s refresh failed, ino=%ld, error=%d\n", -dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino, status); -#endif + dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s refresh failed, ino=%ld, error=%d\n", + dentry->d_parent->d_name.name, + dentry->d_name.name, inode->i_ino, status); goto out; } dfprintk(PAGECACHE, "NFS: %s/%s revalidation complete\n", @@ -809,29 +848,18 @@ out_changed: printk("nfs_refresh_inode: inode %ld mode changed, %07o to %07o\n", inode->i_ino, inode->i_mode, fattr->mode); #endif - fattr->mode = inode->i_mode; /* save mode */ - make_bad_inode(inode); - nfs_inval(inode); - inode->i_mode = fattr->mode; /* restore mode */ /* * No need to worry about unhashing the dentry, as the * lookup validation will know that the inode is bad. - * (But we fall through to invalidate the caches.) */ + nfs_invalidate_inode(inode); + goto out; out_invalid: - /* - * Invalidate the local caches - */ #ifdef NFS_DEBUG_VERBOSE printk("nfs_refresh_inode: invalidating %ld pages\n", inode->i_nrpages); #endif - if (!S_ISDIR(inode->i_mode)) - invalidate_inode_pages(inode); - else - nfs_invalidate_dircache(inode); - NFS_CACHEINV(inode); - NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); + nfs_zap_caches(inode); goto out; } diff --git a/fs/ntfs/fs.c b/fs/ntfs/fs.c index c38214bae730..f34de38d30ad 100644 --- a/fs/ntfs/fs.c +++ b/fs/ntfs/fs.c @@ -215,7 +215,6 @@ static int ntfs_readdir(struct file* filp, void *dirent, filldir_t filldir) ntfs_debug(DEBUG_OTHER, "ntfs_readdir ino %x mode %x\n", (unsigned)dir->i_ino,(unsigned int)dir->i_mode); - if(!dir || (dir->i_ino==0) || !S_ISDIR(dir->i_mode))return -EBADF; ntfs_debug(DEBUG_OTHER, "readdir: Looking for file %x dircount %d\n", (unsigned)filp->f_pos,dir->i_count); @@ -373,7 +372,7 @@ static int parse_options(ntfs_volume* vol,char *opt) return 0; } -static int ntfs_lookup(struct inode *dir, struct dentry *d) +static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *d) { struct inode *res=0; char *item=0; @@ -385,10 +384,10 @@ static int ntfs_lookup(struct inode *dir, struct dentry *d) error=ntfs_decodeuni(NTFS_INO2VOL(dir),(char*)d->d_name.name, d->d_name.len,&walk.name,&walk.namelen); if(error) - return error; + return ERR_PTR(-error); item=ntfs_malloc(ITEM_SIZE); if( !item ) - return ENOMEM; + return ERR_PTR(-ENOMEM); /* ntfs_getdir will place the directory entry into item, and the first long long is the MFT record number */ walk.type=BY_NAME; @@ -402,7 +401,7 @@ static int ntfs_lookup(struct inode *dir, struct dentry *d) ntfs_free(item); ntfs_free(walk.name); /* Always return success, the dcache will handle negative entries. */ - return 0; + return NULL; } static struct file_operations ntfs_file_operations_nommap = { @@ -829,7 +828,7 @@ static int ntfs_statfs(struct super_block *sb, struct statfs *sf, int bufsize) error = ntfs_get_volumesize( NTFS_SB2VOL( sb ), &fs.f_blocks ); if( error ) - return error; + return -error; fs.f_bfree=ntfs_get_free_cluster_count(vol->bitmap); fs.f_bavail=fs.f_bfree; diff --git a/fs/ntfs/inode.c b/fs/ntfs/inode.c index fd975ffbb30b..7fcc86754b11 100644 --- a/fs/ntfs/inode.c +++ b/fs/ntfs/inode.c @@ -150,6 +150,8 @@ ntfs_extend_mft(ntfs_volume *vol) ntfs_insert_fixups(buf,vol->blocksize); io.param=buf; io.size=vol->mft_recordsize; + io.fn_put = ntfs_put; + io.fn_get = ntfs_get; error=ntfs_write_attr(vol->mft_ino,vol->at_data,0, (rcount-1)*vol->mft_recordsize,&io); if(error)return error; diff --git a/fs/proc/fd.c b/fs/proc/fd.c index 8db99f7f4d80..1defdbae1195 100644 --- a/fs/proc/fd.c +++ b/fs/proc/fd.c @@ -19,7 +19,7 @@ #include static int proc_readfd(struct file *, void *, filldir_t); -static int proc_lookupfd(struct inode *, struct dentry *); +static struct dentry *proc_lookupfd(struct inode *, struct dentry *); static struct file_operations proc_fd_operations = { NULL, /* lseek - default */ @@ -67,7 +67,7 @@ struct inode_operations proc_fd_inode_operations = { * * Thus just return -ENOENT instead. */ -static int proc_lookupfd(struct inode * dir, struct dentry * dentry) +static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry) { unsigned int ino, pid, fd, c; struct task_struct * p; @@ -77,13 +77,11 @@ static int proc_lookupfd(struct inode * dir, struct dentry * dentry) int len, err; err = -ENOENT; - if (!dir) - goto out; ino = dir->i_ino; pid = ino >> 16; ino &= 0x0000ffff; - if (!pid || ino != PROC_PID_FD || !S_ISDIR(dir->i_mode)) + if (!pid || ino != PROC_PID_FD) goto out; fd = 0; @@ -121,10 +119,10 @@ static int proc_lookupfd(struct inode * dir, struct dentry * dentry) if (inode) { dentry->d_op = &proc_dentry_operations; d_add(dentry, inode); - err = 0; + return NULL; } out: - return err; + return ERR_PTR(err); } #define NUMBUF 10 @@ -137,10 +135,6 @@ static int proc_readfd(struct file * filp, void * dirent, filldir_t filldir) int retval; char buf[NUMBUF]; - retval = -EBADF; - if (!inode || !S_ISDIR(inode->i_mode)) - goto out; - retval = 0; ino = inode->i_ino; pid = ino >> 16; diff --git a/fs/proc/openpromfs.c b/fs/proc/openpromfs.c index 2c2c84784e4c..09844e156ba9 100644 --- a/fs/proc/openpromfs.c +++ b/fs/proc/openpromfs.c @@ -842,7 +842,6 @@ static int openpromfs_readdir(struct file * filp, void * dirent, filldir_t filld struct openpromfs_dev *d; char buffer2[64]; - if (!inode || !S_ISDIR (inode->i_mode)) return -ENOTDIR; ino = inode->i_ino; i = filp->f_pos; switch (i) { diff --git a/fs/proc/root.c b/fs/proc/root.c index e28338ab4336..2c4fbe8dc775 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -28,7 +28,7 @@ #define FIRST_PROCESS_ENTRY 256 static int proc_root_readdir(struct file *, void *, filldir_t); -static int proc_root_lookup(struct inode *,struct dentry *); +static struct dentry *proc_root_lookup(struct inode *,struct dentry *); static int proc_unlink(struct inode *, struct dentry *); static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8] = {0}; @@ -769,16 +769,12 @@ struct dentry_operations proc_dentry_operations = * Don't create negative dentries here, return -ENOENT by hand * instead. */ -int proc_lookup(struct inode * dir, struct dentry *dentry) +struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry) { struct inode *inode; struct proc_dir_entry * de; int error; - error = -ENOTDIR; - if (!dir || !S_ISDIR(dir->i_mode)) - goto out; - error = -ENOENT; inode = NULL; de = (struct proc_dir_entry *) dir->u.generic_ip; @@ -800,13 +796,12 @@ int proc_lookup(struct inode * dir, struct dentry *dentry) if (inode) { dentry->d_op = &proc_dentry_operations; d_add(dentry, inode); - error = 0; + return NULL; } -out: - return error; + return ERR_PTR(error); } -static int proc_root_lookup(struct inode * dir, struct dentry * dentry) +static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry) { unsigned int pid, c; struct task_struct *p; @@ -826,7 +821,7 @@ static int proc_root_lookup(struct inode * dir, struct dentry * dentry) } if (!proc_lookup(dir, dentry)) - return 0; + return NULL; pid = 0; name = dentry->d_name.name; @@ -853,13 +848,13 @@ static int proc_root_lookup(struct inode * dir, struct dentry * dentry) unsigned long ino = (pid << 16) + PROC_PID_INO; inode = proc_get_inode(dir->i_sb, ino, &proc_pid); if (!inode) - return -EINVAL; + return ERR_PTR(-EINVAL); inode->i_flags|=S_IMMUTABLE; } dentry->d_op = &proc_dentry_operations; d_add(dentry, inode); - return 0; + return NULL; } /* @@ -879,8 +874,6 @@ int proc_readdir(struct file * filp, int i; struct inode *inode = filp->f_dentry->d_inode; - if (!inode || !S_ISDIR(inode->i_mode)) - return -ENOTDIR; ino = inode->i_ino; de = (struct proc_dir_entry *) inode->u.generic_ip; if (!de) diff --git a/fs/qnx4/dir.c b/fs/qnx4/dir.c index 119930667393..029fd9061b13 100644 --- a/fs/qnx4/dir.c +++ b/fs/qnx4/dir.c @@ -35,9 +35,6 @@ static int qnx4_readdir(struct file *filp, void *dirent, filldir_t filldir) blknum = inode->u.qnx4_i.i_first_xtnt.xtnt_blk - 1 + ((filp->f_pos >> 6) >> 3); - if (!inode || !inode->i_sb || !S_ISDIR(inode->i_mode)) { - return -EBADF; - } QNX4DEBUG(("qnx4_readdir:i_size = %ld\n", (long) inode->i_size)); QNX4DEBUG(("filp->f_pos = %ld\n", (long) filp->f_pos)); QNX4DEBUG(("BlkNum = %ld\n", (long) blknum)); diff --git a/fs/qnx4/namei.c b/fs/qnx4/namei.c index 267ecb1107d6..7765bbb9b75f 100644 --- a/fs/qnx4/namei.c +++ b/fs/qnx4/namei.c @@ -108,7 +108,7 @@ static struct buffer_head *qnx4_find_entry(int len, struct inode *dir, return NULL; } -int qnx4_lookup(struct inode *dir, struct dentry *dentry) +struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry) { int ino; struct qnx4_inode_entry *de; @@ -116,17 +116,10 @@ int qnx4_lookup(struct inode *dir, struct dentry *dentry) struct buffer_head *bh; const char *name = dentry->d_name.name; int len = dentry->d_name.len; - struct inode *foundinode; + struct inode *foundinode = NULL; - if (!dir) { - return -EBADF; - } - if (!S_ISDIR(dir->i_mode)) { - return -EBADF; - } - if (!(bh = qnx4_find_entry(len, dir, name, &de, &ino))) { - return -ENOENT; - } + if (!(bh = qnx4_find_entry(len, dir, name, &de, &ino))) + goto out; /* The entry is linked, let's get the real info */ if ((de->di_status & QNX4_FILE_LINK) == QNX4_FILE_LINK) { lnk = (struct qnx4_link_info *) de; @@ -137,11 +130,12 @@ int qnx4_lookup(struct inode *dir, struct dentry *dentry) if ((foundinode = iget(dir->i_sb, ino)) == NULL) { QNX4DEBUG(("qnx4: lookup->iget -> NULL\n")); - return -EACCES; + return ERR_PTR(-EACCES); } +out: d_add(dentry, foundinode); - return 0; + return NULL; } #ifdef CONFIG_QNX4FS_RW diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c index 211563b1c963..fd374842eeaf 100644 --- a/fs/romfs/inode.c +++ b/fs/romfs/inode.c @@ -267,9 +267,6 @@ romfs_readdir(struct file *filp, void *dirent, filldir_t filldir) int stored = 0; char fsname[ROMFS_MAXFN]; /* XXX dynamic? */ - if (!i || !S_ISDIR(i->i_mode)) - return -EBADF; - maxoff = i->i_sb->u.romfs_sb.s_maxsize; offset = filp->f_pos; @@ -312,7 +309,7 @@ romfs_readdir(struct file *filp, void *dirent, filldir_t filldir) } } -static int +static struct dentry * romfs_lookup(struct inode *dir, struct dentry *dentry) { unsigned long offset, maxoff; @@ -323,10 +320,6 @@ romfs_lookup(struct inode *dir, struct dentry *dentry) const char *name; /* got from dentry */ int len; - res = -EBADF; - if (!dir || !S_ISDIR(dir->i_mode)) - goto out; - res = 0; /* instead of ENOENT */ offset = dir->i_ino & ROMFH_MASK; if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0) @@ -379,7 +372,7 @@ romfs_lookup(struct inode *dir, struct dentry *dentry) } out: - return res; + return ERR_PTR(res); } /* diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c index 370d0ea6e5b9..b6d0364fc6ca 100644 --- a/fs/smbfs/dir.c +++ b/fs/smbfs/dir.c @@ -22,7 +22,7 @@ static ssize_t smb_dir_read(struct file *, char *, size_t, loff_t *); static int smb_readdir(struct file *, void *, filldir_t); static int smb_dir_open(struct inode *, struct file *); -static int smb_lookup(struct inode *, struct dentry *); +static struct dentry *smb_lookup(struct inode *, struct dentry *); static int smb_create(struct inode *, struct dentry *, int); static int smb_mkdir(struct inode *, struct dentry *, int); static int smb_rmdir(struct inode *, struct dentry *); @@ -324,7 +324,7 @@ smb_renew_times(struct dentry * dentry) } } -static int +static struct dentry * smb_lookup(struct inode *dir, struct dentry *dentry) { struct smb_fattr finfo; @@ -360,7 +360,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name, error); } } out: - return error; + return ERR_PTR(error); } /* diff --git a/fs/sysv/dir.c b/fs/sysv/dir.c index 9a1acc19e690..a28a7ba8e9ae 100644 --- a/fs/sysv/dir.c +++ b/fs/sysv/dir.c @@ -69,14 +69,12 @@ struct inode_operations sysv_dir_inode_operations = { static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir) { struct inode *inode = filp->f_dentry->d_inode; - struct super_block * sb; + struct super_block * sb = inode->i_sb; unsigned int offset,i; struct buffer_head * bh; char* bh_data; struct sysv_dir_entry * de, sde; - if (!inode || !(sb = inode->i_sb) || !S_ISDIR(inode->i_mode)) - return -EBADF; if ((unsigned long)(filp->f_pos) % SYSV_DIRSIZE) return -EBADF; while (filp->f_pos < inode->i_size) { diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index a06ee181c879..38aebe9a9b80 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c @@ -103,17 +103,12 @@ static struct buffer_head * sysv_find_entry(struct inode * dir, return NULL; } -int sysv_lookup(struct inode * dir, struct dentry * dentry) +struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry) { struct inode * inode = NULL; struct sysv_dir_entry * de; struct buffer_head * bh; - if (!dir) - return -ENOENT; - if (!S_ISDIR(dir->i_mode)) { - return -ENOENT; - } bh = sysv_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); if (bh) { @@ -122,10 +117,10 @@ int sysv_lookup(struct inode * dir, struct dentry * dentry) inode = iget(dir->i_sb, ino); if (!inode) - return -EACCES; + return ERR_PTR(-EACCES); } d_add(dentry, inode); - return 0; + return NULL; } /* @@ -209,8 +204,6 @@ int sysv_create(struct inode * dir, struct dentry * dentry, int mode) struct buffer_head * bh; struct sysv_dir_entry * de; - if (!dir) - return -ENOENT; inode = sysv_new_inode(dir); if (!inode) return -ENOSPC; @@ -239,8 +232,6 @@ int sysv_mknod(struct inode * dir, struct dentry * dentry, int mode, int rdev) struct buffer_head * bh; struct sysv_dir_entry * de; - if (!dir) - return -ENOENT; bh = sysv_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); if (bh) { @@ -286,8 +277,6 @@ int sysv_mkdir(struct inode * dir, struct dentry *dentry, int mode) struct buffer_head * bh, *dir_block; struct sysv_dir_entry * de; - if (!dir) - return -EINVAL; bh = sysv_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); if (bh) { diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c index 24810fe48629..6a79c4a5e96f 100644 --- a/fs/ufs/dir.c +++ b/fs/ufs/dir.c @@ -43,13 +43,6 @@ ufs_readdir (struct file * filp, void * dirent, filldir_t filldir) int de_reclen; unsigned flags, swab; - - /* Isn't that already done in the upper layer??? - * the VFS layer really needs some explicit documentation! - */ - if (!inode || !S_ISDIR(inode->i_mode)) - return -EBADF; - sb = inode->i_sb; swab = sb->u.ufs_sb.s_swab; flags = sb->u.ufs_sb.s_flags; diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index 0ad0b9201dc7..a30b187d390a 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -185,7 +185,7 @@ failed: return NULL; } -int ufs_lookup(struct inode * dir, struct dentry *dentry) +struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry) { struct super_block * sb; struct inode * inode; @@ -199,7 +199,7 @@ int ufs_lookup(struct inode * dir, struct dentry *dentry) swab = sb->u.ufs_sb.s_swab; if (dentry->d_name.len > UFS_MAXNAMLEN) - return -ENAMETOOLONG; + return ERR_PTR(-ENAMETOOLONG); bh = ufs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de); inode = NULL; @@ -208,11 +208,11 @@ int ufs_lookup(struct inode * dir, struct dentry *dentry) brelse (bh); inode = iget(sb, ino); if (!inode) - return -EACCES; + return ERR_PTR(-EACCES); } d_add(dentry, inode); UFSD(("EXIT\n")) - return 0; + return NULL; } /* diff --git a/fs/umsdos/dir.c b/fs/umsdos/dir.c index e5e1723638f1..07a12a6a4b5c 100644 --- a/fs/umsdos/dir.c +++ b/fs/umsdos/dir.c @@ -210,8 +210,8 @@ filp->f_dentry->d_name.name, entry.name); /* * Do a real lookup on the short name. */ - dret = umsdos_lookup_dentry(filp->f_dentry, info.fake.fname, - info.fake.len, 1); + dret = umsdos_covered(filp->f_dentry, info.fake.fname, + info.fake.len); ret = PTR_ERR(dret); if (IS_ERR(dret)) break; @@ -459,7 +459,7 @@ int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry) * entry from the EMD file, and return ENOENT. */ -int umsdos_lookup_x (struct inode *dir, struct dentry *dentry, int nopseudo) +struct dentry *umsdos_lookup_x (struct inode *dir, struct dentry *dentry, int nopseudo) { struct dentry *dret = NULL; struct inode *inode; @@ -500,8 +500,7 @@ Printk (("lookup %.*s pos %lu ret %d len %d ", info.fake.len, info.fake.fname, info.f_pos, ret, info.fake.len)); /* do a real lookup to get the short name ... */ - dret = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, - info.fake.len, 1); + dret = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len); ret = PTR_ERR(dret); if (IS_ERR(dret)) { printk("umsdos_lookup_x: %s/%s real lookup failed, ret=%d\n", @@ -563,7 +562,7 @@ out_dput: dput(dret); out: umsdos_endlookup (dir); - return ret; + return ERR_PTR(ret); out_remove: printk(KERN_WARNING "UMSDOS: entry %s/%s out of sync, erased\n", @@ -581,19 +580,19 @@ out_remove: * Called by VFS; should fill dentry->d_inode via d_add. */ -int UMSDOS_lookup (struct inode *dir, struct dentry *dentry) +struct dentry *UMSDOS_lookup (struct inode *dir, struct dentry *dentry) { - int ret; + struct dentry *ret; ret = umsdos_lookup_x (dir, dentry, 0); /* Create negative dentry if not found. */ - if (ret == -ENOENT) { + if (ret == ERR_PTR(-ENOENT)) { Printk ((KERN_DEBUG "UMSDOS_lookup: converting -ENOENT to negative\n")); d_add (dentry, NULL); dentry->d_op = &umsdos_dentry_operations; - ret = 0; + ret = NULL; } return ret; } @@ -601,7 +600,6 @@ int UMSDOS_lookup (struct inode *dir, struct dentry *dentry) struct dentry *umsdos_covered(struct dentry *parent, char *name, int len) { struct dentry *result, *dentry; - int error; struct qstr qstr; qstr.name = name; @@ -610,19 +608,18 @@ struct dentry *umsdos_covered(struct dentry *parent, char *name, int len) result = ERR_PTR(-ENOMEM); dentry = d_alloc(parent, &qstr); if (dentry) { - result = dentry; /* XXXXXXXXXXXXXXXXXXX Race alert! */ - error = UMSDOS_rlookup(parent->d_inode, result); - d_drop(result); - if (error) + result = UMSDOS_rlookup(parent->d_inode, dentry); + d_drop(dentry); + if (result) goto out_fail; + return dentry; } out: return result; out_fail: - dput(result); - result = ERR_PTR(error); + dput(dentry); goto out; } @@ -636,7 +633,6 @@ struct dentry *umsdos_lookup_dentry(struct dentry *parent, char *name, int len, int real) { struct dentry *result, *dentry; - int error; struct qstr qstr; qstr.name = name; @@ -647,20 +643,19 @@ struct dentry *umsdos_lookup_dentry(struct dentry *parent, char *name, int len, result = ERR_PTR(-ENOMEM); dentry = d_alloc(parent, &qstr); if (dentry) { - result = dentry; - error = real ? - UMSDOS_rlookup(parent->d_inode, result) : - UMSDOS_lookup(parent->d_inode, result); - if (error) + result = real ? + UMSDOS_rlookup(parent->d_inode, dentry) : + UMSDOS_lookup(parent->d_inode, dentry); + if (result) goto out_fail; + return dentry; } } out: return result; out_fail: - dput(result); - result = ERR_PTR(error); + dput(dentry); goto out; } diff --git a/fs/umsdos/namei.c b/fs/umsdos/namei.c index 3303da1ba932..444e9ffae2cd 100644 --- a/fs/umsdos/namei.c +++ b/fs/umsdos/namei.c @@ -175,18 +175,6 @@ void umsdos_endlookup (struct inode *dir) #endif -/* - * Check whether we can delete from the directory. - */ -static int is_sticky(struct inode *dir, int uid) -{ - return !((dir->i_mode & S_ISVTX) == 0 || - current->fsuid == uid || - current->fsuid == dir->i_uid || - capable (CAP_FOWNER)); -} - - static int umsdos_nevercreat (struct inode *dir, struct dentry *dentry, int errcod) { @@ -696,9 +684,8 @@ Printk(("UMSDOS_link: hard link %s/%s, fake=%s\n", olddentry->d_parent->d_name.name, olddentry->d_name.name, old_info.fake.fname)); /* Do a real lookup to get the short name dentry */ - temp = umsdos_lookup_dentry(olddentry->d_parent, - old_info.fake.fname, - old_info.fake.len, 1); + temp = umsdos_covered(olddentry->d_parent, old_info.fake.fname, + old_info.fake.len); ret = PTR_ERR(temp); if (IS_ERR(temp)) goto out_unlock; @@ -784,16 +771,11 @@ int UMSDOS_mkdir (struct inode *dir, struct dentry *dentry, int mode) goto out; /* lookup the short name dentry */ - temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, - info.fake.len, 1); + temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len); ret = PTR_ERR(temp); if (IS_ERR(temp)) goto out_remove; - /* Keep the short name dentry anonymous */ - if (temp != dentry) - d_drop(temp); - /* Make sure the short name doesn't exist */ ret = -EEXIST; if (temp->d_inode) { @@ -812,16 +794,9 @@ dentry->d_parent->d_name.name, info.fake.fname); inode = temp->d_inode; down(&inode->i_sem); - /* - * Note! The long and short name might be the same, - * so check first before doing the instantiate ... - */ - if (dentry != temp) { -if (dentry->d_inode) -printk("umsdos_mkdir: dentry not negative!\n"); - inode->i_count++; - d_instantiate(dentry, inode); - } + inode->i_count++; + d_instantiate(dentry, inode); + /* N.B. this should have an option to create the EMD ... */ umsdos_lookup_patch_new(dentry, &info); @@ -921,20 +896,10 @@ demd->d_parent->d_name.name, demd->d_name.name, err); umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info); /* Call findentry to complete the mangling */ umsdos_findentry (dentry->d_parent, &info, 2); - temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, - info.fake.len, 1); + temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len); ret = PTR_ERR(temp); if (IS_ERR(temp)) goto out; - /* - * If the short name is an alias, dput() it now; - * otherwise d_drop() it to keep it anonymous. - */ - if (temp == dentry) - dput(temp); - else - d_drop(temp); - /* * Attempt to remove the msdos name. */ @@ -951,8 +916,7 @@ printk("umsdos_rmdir: delentry %s failed, ret=%d\n", info.entry.name, ret); /* dput() temp if we didn't do it above */ out_dput: - if (temp != dentry) - dput(temp); + dput(temp); out: Printk (("umsdos_rmdir %d\n", ret)); @@ -999,14 +963,6 @@ dentry->d_parent->d_name.name, dentry->d_name.name, ret); Printk (("UMSDOS_unlink %.*s ", info.fake.len, info.fake.fname)); - ret = -EPERM; - /* check sticky bit */ - if (is_sticky(dir, info.entry.uid)) { -printk("umsdos_unlink: %s/%s is sticky\n", -dentry->d_parent->d_name.name, dentry->d_name.name); - goto out_unlock; - } - /* * Note! If this is a hardlink and the names are aliased, * the short-name lookup will return the hardlink dentry. @@ -1018,8 +974,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name); } /* Do a real lookup to get the short name dentry */ - temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, - info.fake.len, 1); + temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len); ret = PTR_ERR(temp); if (IS_ERR(temp)) goto out_unlock; @@ -1031,13 +986,6 @@ dentry->d_parent->d_name.name, dentry->d_name.name); link = umsdos_solve_hlink(dget(temp)); } - /* - * If the short and long names are aliased, - * dput() it now so the dentry isn't busy. - */ - if (temp == dentry) - dput(temp); - /* Delete the EMD entry */ ret = umsdos_delentry (dentry->d_parent, &info, 0); if (ret && ret != -ENOENT) { @@ -1046,7 +994,7 @@ dentry->d_parent->d_name.name, dentry->d_name.name); goto out_dput; } - ret = msdos_unlink_umsdos (dir, temp); + ret = msdos_unlink(dir, temp); #ifdef UMSDOS_PARANOIA if (ret) printk("umsdos_unlink: %s/%s unlink failed, ret=%d\n", @@ -1055,12 +1003,9 @@ temp->d_parent->d_name.name, temp->d_name.name, ret); /* dput() temp if we didn't do it above */ out_dput: - if (temp != dentry) { - d_drop(temp); - dput(temp); - if (!ret) - d_delete (dentry); - } + dput(temp); + if (!ret) + d_delete (dentry); out_unlock: umsdos_unlockcreate (dir); diff --git a/fs/umsdos/rdir.c b/fs/umsdos/rdir.c index 10ff145b7c66..3f5d109533a0 100644 --- a/fs/umsdos/rdir.c +++ b/fs/umsdos/rdir.c @@ -79,9 +79,9 @@ static int UMSDOS_rreaddir (struct file *filp, void *dirbuf, filldir_t filldir) * In the real root directory (c:\), the directory .. * is the pseudo root (c:\linux). */ -int umsdos_rlookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo) +struct dentry *umsdos_rlookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo) { - int ret; + struct dentry *ret; if (saved_root && dir == saved_root->d_inode && !nopseudo && dentry->d_name.len == UMSDOS_PSDROOT_LEN && @@ -91,15 +91,16 @@ int umsdos_rlookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo) * /linux won't show */ - ret = -ENOENT; + ret = ERR_PTR(-ENOENT); goto out; } ret = msdos_lookup (dir, dentry); if (ret) { printk(KERN_WARNING - "umsdos_rlookup_x: %s/%s failed, ret=%d\n", - dentry->d_parent->d_name.name, dentry->d_name.name,ret); + "umsdos_rlookup_x: %s/%s failed, ret=%ld\n", + dentry->d_parent->d_name.name, dentry->d_name.name, + PTR_ERR(ret)); goto out; } if (dentry->d_inode) { @@ -119,7 +120,7 @@ out: } -int UMSDOS_rlookup ( struct inode *dir, struct dentry *dentry) +struct dentry *UMSDOS_rlookup ( struct inode *dir, struct dentry *dentry) { return umsdos_rlookup_x (dir, dentry, 0); } diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index 347aced2dc14..25a11251b95f 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -1140,11 +1140,30 @@ cleanup: return res; } -int vfat_lookup(struct inode *dir,struct dentry *dentry) +/* Find a hashed dentry for inode; NULL if there are none */ +static struct dentry *find_alias(struct inode *inode) +{ + struct list_head *head, *next, *tmp; + struct dentry *alias; + + head = &inode->i_dentry; + next = inode->i_dentry.next; + while (next != head) { + tmp = next; + next = tmp->next; + alias = list_entry(tmp, struct dentry, d_alias); + if (!list_empty(&alias->d_hash)) + return dget(alias); + } + return NULL; +} + +struct dentry *vfat_lookup(struct inode *dir,struct dentry *dentry) { int res; struct vfat_slot_info sinfo; struct inode *result; + struct dentry *alias; int table; PRINTK2(("vfat_lookup: name=%s, len=%d\n", @@ -1161,7 +1180,7 @@ int vfat_lookup(struct inode *dir,struct dentry *dentry) } PRINTK3(("vfat_lookup 4.5\n")); if (!(result = iget(dir->i_sb,sinfo.ino))) - return -EACCES; + return ERR_PTR(-EACCES); PRINTK3(("vfat_lookup 5\n")); if (MSDOS_I(result)->i_busy) { /* mkdir in progress */ iput(result); @@ -1169,6 +1188,15 @@ int vfat_lookup(struct inode *dir,struct dentry *dentry) table++; goto error; } + alias = find_alias(result); + if (alias) { + if (d_invalidate(alias)==0) + dput(alias); + else { + iput(result); + return alias; + } + } PRINTK3(("vfat_lookup 6\n")); error: dentry->d_op = &vfat_dentry_ops[table]; @@ -1397,28 +1425,6 @@ static int vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo, return 0; } -/* Drop all aliases */ -static void drop_aliases(struct dentry *dentry) -{ - struct list_head *head, *next, *tmp; - struct dentry *alias; - - PRINTK1(("drop_replace_inodes: dentry=%p, inode=%p\n", dentry, inode)); - head = &dentry->d_inode->i_dentry; - if (dentry->d_inode) { - next = dentry->d_inode->i_dentry.next; - while (next != head) { - tmp = next; - next = tmp->next; - alias = list_entry(tmp, struct dentry, d_alias); - if (alias == dentry) - continue; - - d_drop(alias); - } - } -} - static int vfat_rmdirx(struct inode *dir,struct dentry* dentry) { int res; @@ -1430,12 +1436,6 @@ static int vfat_rmdirx(struct inode *dir,struct dentry* dentry) if (res >= 0 && sinfo.total_slots > 0) { if (!list_empty(&dentry->d_hash)) return -EBUSY; - /* Take care of aliases */ - if (dentry->d_inode->i_count > 1) { - shrink_dcache_parent(dentry->d_parent); - if (dentry->d_inode->i_count > 1) - return -EBUSY; - } res = vfat_empty(dentry->d_inode); if (res) return res; @@ -1535,10 +1535,8 @@ int vfat_unlink(struct inode *dir,struct dentry* dentry) PRINTK1(("vfat_unlink: dentry=%p, inode=%p\n", dentry, dentry->d_inode)); res = vfat_unlinkx (dir,dentry,1); - if (res >= 0) { - drop_aliases(dentry); + if (res >= 0) d_delete(dentry); - } return res; } @@ -1561,7 +1559,6 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry, loff_t old_offset,new_offset,old_longname_offset; int old_slots,old_ino,new_ino,dotdot_ino; struct inode *old_inode, *new_inode, *dotdot_inode; - struct dentry *walk; int res, is_dir, i; int locked = 0; struct vfat_slot_info sinfo; @@ -1589,16 +1586,6 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry, old_inode = old_dentry->d_inode; is_dir = S_ISDIR(old_inode->i_mode); - if (is_dir) { - /* We can't use is_subdir() here. Even now. Arrgh. */ - for (walk=new_dentry;walk!=walk->d_parent;walk=walk->d_parent) { - if (walk->d_inode != old_dentry->d_inode) - continue; - res = -EINVAL; - goto rename_done; - } - } - fat_lock_creation(); locked = 1; if (new_dentry->d_inode) { @@ -1620,25 +1607,9 @@ int vfat_rename(struct inode *old_dir,struct dentry *old_dentry, } if (is_dir) { - /* - * Target is a directory. No other owners will - * be tolerated. - */ - res = -EBUSY; - /* - * OK, let's try to get rid of other dentries. - * No need to do it if i_count is 1. - */ - if (new_inode->i_count>1) { - shrink_dcache_parent(new_dentry->d_parent); - if (new_inode->i_count>1) - goto rename_done; - } res = vfat_empty(new_inode); if (res) goto rename_done; - } else { - drop_aliases(new_dentry); } res = vfat_remove_entry(new_dir,&sinfo,new_inode); if (res) diff --git a/include/asm-alpha/keyboard.h b/include/asm-alpha/keyboard.h index 34390e362a24..e62205f37b86 100644 --- a/include/asm-alpha/keyboard.h +++ b/include/asm-alpha/keyboard.h @@ -18,7 +18,6 @@ extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); -extern int pckbd_pretranslate(unsigned char scancode, char raw_mode); extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode); extern char pckbd_unexpected_up(unsigned char keycode); @@ -28,7 +27,6 @@ extern unsigned char pckbd_sysrq_xlate[128]; #define kbd_setkeycode pckbd_setkeycode #define kbd_getkeycode pckbd_getkeycode -#define kbd_pretranslate pckbd_pretranslate #define kbd_translate pckbd_translate #define kbd_unexpected_up pckbd_unexpected_up #define kbd_leds pckbd_leds diff --git a/include/asm-alpha/semaphore.h b/include/asm-alpha/semaphore.h index 0e7cc71d457c..30f1372eac53 100644 --- a/include/asm-alpha/semaphore.h +++ b/include/asm-alpha/semaphore.h @@ -53,24 +53,31 @@ extern inline void down(struct semaphore * sem) it's return address in $28. The pv is loaded as usual. The gp is clobbered (in the module case) as usual. */ + /* This little bit of silliness is to get the GP loaded for + a function that ordinarily wouldn't. Otherwise we could + have it done by the macro directly, which can be optimized + the linker. */ + register void *pv __asm__("$27") = __down_failed; + __asm__ __volatile__ ( "/* semaphore down operation */\n" - "1: ldl_l $27,%0\n" - " subl $27,1,$27\n" - " mov $27,$28\n" - " stl_c $28,%0\n" + "1: ldl_l $24,%1\n" + " subl $24,1,$24\n" + " mov $24,$28\n" + " stl_c $28,%1\n" " beq $28,2f\n" - " blt $27,3f\n" + " blt $24,3f\n" "4: mb\n" ".section .text2,\"ax\"\n" "2: br 1b\n" - "3: lda $24,%0\n" - " jsr $28,__down_failed\n" + "3: lda $24,%1\n" + " jsr $28,($27),__down_failed\n" " ldgp $29,0($28)\n" " br 4b\n" ".previous" - : : "m"(sem->count) - : "$24", "$27", "$28", "memory"); + : "=r"(pv) + : "m"(sem->count), "r"(pv) + : "$24", "$28", "memory"); } extern inline int down_interruptible(struct semaphore * sem) @@ -81,27 +88,28 @@ extern inline int down_interruptible(struct semaphore * sem) value is in $24. */ register int ret __asm__("$24"); + register void *pv __asm__("$27") = __down_failed_interruptible; __asm__ __volatile__ ( "/* semaphore down interruptible operation */\n" - "1: ldl_l $27,%1\n" - " subl $27,1,$27\n" - " mov $27,$28\n" - " stl_c $28,%1\n" + "1: ldl_l $24,%2\n" + " subl $24,1,$24\n" + " mov $24,$28\n" + " stl_c $28,%2\n" " beq $28,2f\n" - " blt $27,3f\n" + " blt $24,3f\n" " mov $31,%0\n" "4: mb\n" ".section .text2,\"ax\"\n" "2: br 1b\n" - "3: lda $24,%1\n" - " jsr $28,__down_failed_interruptible\n" + "3: lda $24,%2\n" + " jsr $28,($27),__down_failed_interruptible\n" " ldgp $29,0($28)\n" " br 4b\n" ".previous" - : "=r"(ret) - : "m"(sem->count) - : "$27", "$28", "memory"); + : "=r"(ret), "=r"(pv) + : "m"(sem->count), "r"(pv) + : "$28", "memory"); return ret; } @@ -171,26 +179,29 @@ extern inline void up(struct semaphore * sem) it's return address in $28. The pv is loaded as usual. The gp is clobbered (in the module case) as usual. */ + register void *pv __asm__("$27") = __up_wakeup; + __asm__ __volatile__ ( "/* semaphore up operation */\n" " mb\n" - "1: ldl_l $27,%0\n" - " addl $27,1,$27\n" - " mov $27,$28\n" - " stl_c $28,%0\n" + "1: ldl_l $24,%1\n" + " addl $24,1,$24\n" + " mov $24,$28\n" + " stl_c $28,%1\n" " beq $28,2f\n" " mb\n" " ble $27,3f\n" "4:\n" ".section .text2,\"ax\"\n" "2: br 1b\n" - "3: lda $24,%0\n" - " jsr $28,__up_wakeup\n" + "3: lda $24,%1\n" + " jsr $28,($27),__up_wakeup\n" " ldgp $29,0($28)\n" " br 4b\n" ".previous" - : : "m"(sem->count) - : "$24", "$27", "$28", "memory"); + : "=r"(pv) + : "m"(sem->count), "r"(pv) + : "$24", "$28", "memory"); } #endif diff --git a/include/asm-alpha/uaccess.h b/include/asm-alpha/uaccess.h index f44914e3e36a..f615339f8856 100644 --- a/include/asm-alpha/uaccess.h +++ b/include/asm-alpha/uaccess.h @@ -160,7 +160,7 @@ struct __large_struct { unsigned long buf[100]; }; : "=r"(__gu_val), "=r"(__gu_err) \ : "m"(__m(addr)), "1"(__gu_err)) -#ifdef __HAVE_CPU_BWX +#ifdef __alpha_bwx__ /* Those lucky bastards with ev56 and later CPUs can do byte/word moves. */ #define __get_user_16(addr) \ @@ -274,7 +274,7 @@ __asm__ __volatile__("1: stl %r2,%1\n" \ : "=r"(__pu_err) \ : "m"(__m(addr)), "rJ"(x), "0"(__pu_err)) -#ifdef __HAVE_CPU_BWX +#ifdef __alpha_bwx__ /* Those lucky bastards with ev56 and later CPUs can do byte/word moves. */ #define __put_user_16(x,addr) \ @@ -363,15 +363,21 @@ extern void __copy_user(void); extern inline long __copy_tofrom_user_nocheck(void *to, const void *from, long len) { + /* This little bit of silliness is to get the GP loaded for + a function that ordinarily wouldn't. Otherwise we could + have it done by the macro directly, which can be optimized + the linker. */ + register void * pv __asm__("$27") = __copy_user; + register void * __cu_to __asm__("$6") = to; register const void * __cu_from __asm__("$7") = from; register long __cu_len __asm__("$0") = len; __asm__ __volatile__( - "jsr $28,__copy_user" - : "=r" (__cu_len), "=r" (__cu_from), "=r" (__cu_to) - : "0" (__cu_len), "1" (__cu_from), "2" (__cu_to) - : "$1","$2","$3","$4","$5","$27","$28","memory"); + "jsr $28,(%3),__copy_user\n\tldgp $29,0($28)" + : "=r" (__cu_len), "=r" (__cu_from), "=r" (__cu_to), "=r"(pv) + : "0" (__cu_len), "1" (__cu_from), "2" (__cu_to), "3"(pv) + : "$1","$2","$3","$4","$5","$28","memory"); return __cu_len; } @@ -380,14 +386,17 @@ extern inline long __copy_tofrom_user(void *to, const void *from, long len, const void *validate) { if (__access_ok((long)validate, len, get_fs())) { + register void * pv __asm__("$27") = __copy_user; register void * __cu_to __asm__("$6") = to; register const void * __cu_from __asm__("$7") = from; register long __cu_len __asm__("$0") = len; __asm__ __volatile__( - "jsr $28,__copy_user" - : "=r" (__cu_len), "=r" (__cu_from), "=r" (__cu_to) - : "0" (__cu_len), "1" (__cu_from), "2" (__cu_to) - : "$1","$2","$3","$4","$5","$27","$28","memory"); + "jsr $28,(%3),__copy_user\n\tldgp $29,0($28)" + : "=r"(__cu_len), "=r"(__cu_from), "=r"(__cu_to), + "=r" (pv) + : "0" (__cu_len), "1" (__cu_from), "2" (__cu_to), + "3" (pv) + : "$1","$2","$3","$4","$5","$28","memory"); len = __cu_len; } return len; @@ -423,13 +432,19 @@ extern void __do_clear_user(void); extern inline long __clear_user(void *to, long len) { + /* This little bit of silliness is to get the GP loaded for + a function that ordinarily wouldn't. Otherwise we could + have it done by the macro directly, which can be optimized + the linker. */ + register void * pv __asm__("$27") = __do_clear_user; + register void * __cl_to __asm__("$6") = to; register long __cl_len __asm__("$0") = len; __asm__ __volatile__( - "jsr $28,__do_clear_user" - : "=r"(__cl_len), "=r"(__cl_to) - : "0"(__cl_len), "1"(__cl_to) - : "$1","$2","$3","$4","$5","$27","$28","memory"); + "jsr $28,(%2),__do_clear_user\n\tldgp $29,0($28)" + : "=r"(__cl_len), "=r"(__cl_to), "=r"(pv) + : "0"(__cl_len), "1"(__cl_to), "2"(pv) + : "$1","$2","$3","$4","$5","$28","memory"); return __cl_len; } @@ -437,13 +452,14 @@ extern inline long clear_user(void *to, long len) { if (__access_ok((long)to, len, get_fs())) { + register void * pv __asm__("$27") = __do_clear_user; register void * __cl_to __asm__("$6") = to; register long __cl_len __asm__("$0") = len; __asm__ __volatile__( - "jsr $28,__do_clear_user" - : "=r"(__cl_len), "=r"(__cl_to) - : "0"(__cl_len), "1"(__cl_to) - : "$1","$2","$3","$4","$5","$27","$28","memory"); + "jsr $28,(%2),__do_clear_user\n\tldgp $29,0($28)" + : "=r"(__cl_len), "=r"(__cl_to), "=r"(pv) + : "0"(__cl_len), "1"(__cl_to), "2"(pv) + : "$1","$2","$3","$4","$5","$28","memory"); len = __cl_len; } return len; diff --git a/include/asm-arm/arch-arc/keyboard.h b/include/asm-arm/arch-arc/keyboard.h index 388014703703..4962defb5a2b 100644 --- a/include/asm-arm/arch-arc/keyboard.h +++ b/include/asm-arm/arch-arc/keyboard.h @@ -19,11 +19,6 @@ extern unsigned char a5kkbd_sysrq_xlate[NR_SCANCODES]; #define kbd_setkeycode(sc,kc) (-EINVAL) #define kbd_getkeycode(sc) (-EINVAL) -/* Prototype: int kbd_pretranslate(scancode, raw_mode) - * Returns : 0 to ignore scancode - */ -#define kbd_pretranslate(sc,rm) (1) - /* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode) * Returns : 0 to ignore scancode, *keycode set to keycode, *up_flag * set to 0200 if scancode indicates release diff --git a/include/asm-arm/arch-ebsa285/keyboard.h b/include/asm-arm/arch-ebsa285/keyboard.h index ad6eb0e5a572..a5ccd590236d 100644 --- a/include/asm-arm/arch-ebsa285/keyboard.h +++ b/include/asm-arm/arch-ebsa285/keyboard.h @@ -19,7 +19,6 @@ extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); -extern int pckbd_pretranslate(unsigned char scancode, char raw_mode); extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode); extern char pckbd_unexpected_up(unsigned char keycode); @@ -29,7 +28,6 @@ extern unsigned char pckbd_sysrq_xlate[128]; #define kbd_setkeycode pckbd_setkeycode #define kbd_getkeycode pckbd_getkeycode -#define kbd_pretranslate pckbd_pretranslate #define kbd_translate(sc, kcp, ufp, rm) ({ *ufp = sc & 0200; \ pckbd_translate(sc & 0x7f, kcp, rm);}) @@ -50,11 +48,6 @@ extern unsigned char pckbd_sysrq_xlate[128]; #define kbd_setkeycode(sc,kc) (-EINVAL) #define kbd_getkeycode(sc) (-EINVAL) -/* Prototype: int kbd_pretranslate(scancode, raw_mode) - * Returns : 0 to ignore scancode - */ -#define kbd_pretranslate(sc,rm) (1) - /* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode) * Returns : 0 to ignore scancode, *keycode set to keycode, *up_flag * set to 0200 if scancode indicates release diff --git a/include/asm-arm/arch-rpc/keyboard.h b/include/asm-arm/arch-rpc/keyboard.h index 6c04cf07495d..d0d1667a68f0 100644 --- a/include/asm-arm/arch-rpc/keyboard.h +++ b/include/asm-arm/arch-rpc/keyboard.h @@ -10,7 +10,6 @@ #define NR_SCANCODES 128 -extern int ps2kbd_pretranslate(unsigned char scancode); extern int ps2kbd_translate(unsigned char scancode, unsigned char *keycode_p, char *up_flag_p); extern void ps2kbd_leds(unsigned char leds); extern void ps2kbd_init_hw(void); @@ -19,11 +18,6 @@ extern unsigned char ps2kbd_sysrq_xlate[NR_SCANCODES]; #define kbd_setkeycode(sc,kc) (-EINVAL) #define kbd_getkeycode(sc) (-EINVAL) -/* Prototype: int kbd_pretranslate(scancode, raw_mode) - * Returns : 0 to ignore scancode - */ -#define kbd_pretranslate(sc,rm) ps2kbd_pretranslate(sc) - /* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode) * Returns : 0 to ignore scancode, *keycode set to keycode, *up_flag * set to 0200 if scancode indicates release diff --git a/include/asm-arm/arch-vnc/keyboard.h b/include/asm-arm/arch-vnc/keyboard.h index 2fa371ff9728..ad2007d7e87b 100644 --- a/include/asm-arm/arch-vnc/keyboard.h +++ b/include/asm-arm/arch-vnc/keyboard.h @@ -14,7 +14,6 @@ extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); -extern int pckbd_pretranslate(unsigned char scancode, char raw_mode); extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode); extern char pckbd_unexpected_up(unsigned char keycode); @@ -24,7 +23,6 @@ extern unsigned char pckbd_sysrq_xlate[128]; #define kbd_setkeycode pckbd_setkeycode #define kbd_getkeycode pckbd_getkeycode -#define kbd_pretranslate pckbd_pretranslate #define kbd_translate(sc, kcp, ufp, rm) ({ *ufp = sc & 0200; \ pckbd_translate(sc & 0x7f, kcp, rm);}) diff --git a/include/asm-i386/keyboard.h b/include/asm-i386/keyboard.h index 103bc0417b15..f5f7471424ec 100644 --- a/include/asm-i386/keyboard.h +++ b/include/asm-i386/keyboard.h @@ -18,7 +18,6 @@ extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); -extern int pckbd_pretranslate(unsigned char scancode, char raw_mode); extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode); extern char pckbd_unexpected_up(unsigned char keycode); @@ -28,7 +27,6 @@ extern unsigned char pckbd_sysrq_xlate[128]; #define kbd_setkeycode pckbd_setkeycode #define kbd_getkeycode pckbd_getkeycode -#define kbd_pretranslate pckbd_pretranslate #define kbd_translate pckbd_translate #define kbd_unexpected_up pckbd_unexpected_up #define kbd_leds pckbd_leds diff --git a/include/asm-m68k/keyboard.h b/include/asm-m68k/keyboard.h index eccadf2e35b6..d14dd3ed5eeb 100644 --- a/include/asm-m68k/keyboard.h +++ b/include/asm-m68k/keyboard.h @@ -27,11 +27,6 @@ static __inline__ int kbd_getkeycode(unsigned int scancode) return scancode > 127 ? -EINVAL : scancode; } -static __inline__ int kbd_pretranslate(unsigned char scancode, char raw_mode) -{ - return 1; -} - static __inline__ int kbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode) { diff --git a/include/asm-mips/keyboard.h b/include/asm-mips/keyboard.h index 00ed32f06d5c..5d04572814a0 100644 --- a/include/asm-mips/keyboard.h +++ b/include/asm-mips/keyboard.h @@ -19,7 +19,6 @@ extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); -extern int pckbd_pretranslate(unsigned char scancode, char raw_mode); extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode); extern char pckbd_unexpected_up(unsigned char keycode); @@ -29,7 +28,6 @@ extern unsigned char pckbd_sysrq_xlate[128]; #define kbd_setkeycode pckbd_setkeycode #define kbd_getkeycode pckbd_getkeycode -#define kbd_pretranslate pckbd_pretranslate #define kbd_translate pckbd_translate #define kbd_unexpected_up pckbd_unexpected_up #define kbd_leds pckbd_leds diff --git a/include/asm-ppc/keyboard.h b/include/asm-ppc/keyboard.h index cc9262059409..28a5a6761773 100644 --- a/include/asm-ppc/keyboard.h +++ b/include/asm-ppc/keyboard.h @@ -28,7 +28,6 @@ extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int mackbd_getkeycode(unsigned int scancode); -extern int mackbd_pretranslate(unsigned char scancode, char raw_mode); extern int mackbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode); extern int mackbd_unexpected_up(unsigned char keycode); @@ -37,7 +36,6 @@ extern void mackbd_init_hw(void); extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pckbd_getkeycode(unsigned int scancode); -extern int pckbd_pretranslate(unsigned char scancode, char raw_mode); extern int pckbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode); extern char pckbd_unexpected_up(unsigned char keycode); @@ -84,23 +82,6 @@ static inline int kbd_getkeycode(unsigned int x) return mackbd_getkeycode(x); } -static inline int kbd_pretranslate(unsigned char x,char y) -{ - if ( is_prep || (_machine == _MACH_mbx) ) - return pckbd_pretranslate(x,y); - else if ( is_chrp ) -#ifndef CONFIG_MAC_KEYBOARD - return pckbd_pretranslate(x,y); -#else - if ( adb_hardware == ADB_NONE ) - return pckbd_pretranslate(x,y); - else - return mackbd_pretranslate(x,y); -#endif - else - return mackbd_pretranslate(x,y); -} - static inline int kbd_translate(unsigned char keycode, unsigned char *keycodep, char raw_mode) { diff --git a/include/asm-sparc/keyboard.h b/include/asm-sparc/keyboard.h index 9dd63c3cb90d..9821385fab8c 100644 --- a/include/asm-sparc/keyboard.h +++ b/include/asm-sparc/keyboard.h @@ -18,7 +18,6 @@ extern int pcikbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pcikbd_getkeycode(unsigned int scancode); -extern int pcikbd_pretranslate(unsigned char scancode, char raw_mode); extern int pcikbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode); extern char pcikbd_unexpected_up(unsigned char keycode); @@ -28,7 +27,6 @@ extern unsigned char pcikbd_sysrq_xlate[128]; #define kbd_setkeycode pcikbd_setkeycode #define kbd_getkeycode pcikbd_getkeycode -#define kbd_pretranslate pcikbd_pretranslate #define kbd_translate pcikbd_translate #define kbd_unexpected_up pcikbd_unexpected_up #define kbd_leds pcikbd_leds diff --git a/include/asm-sparc64/keyboard.h b/include/asm-sparc64/keyboard.h index 1bc97d59792b..d7b5bc400d90 100644 --- a/include/asm-sparc64/keyboard.h +++ b/include/asm-sparc64/keyboard.h @@ -18,7 +18,6 @@ extern int pcikbd_setkeycode(unsigned int scancode, unsigned int keycode); extern int pcikbd_getkeycode(unsigned int scancode); -extern int pcikbd_pretranslate(unsigned char scancode, char raw_mode); extern int pcikbd_translate(unsigned char scancode, unsigned char *keycode, char raw_mode); extern char pcikbd_unexpected_up(unsigned char keycode); @@ -28,7 +27,6 @@ extern unsigned char pcikbd_sysrq_xlate[128]; #define kbd_setkeycode pcikbd_setkeycode #define kbd_getkeycode pcikbd_getkeycode -#define kbd_pretranslate pcikbd_pretranslate #define kbd_translate pcikbd_translate #define kbd_unexpected_up pcikbd_unexpected_up #define kbd_leds pcikbd_leds diff --git a/include/linux/adfs_fs.h b/include/linux/adfs_fs.h index fe4e79e4b082..f6ed2d3b1e7c 100644 --- a/include/linux/adfs_fs.h +++ b/include/linux/adfs_fs.h @@ -155,7 +155,7 @@ extern void adfs_read_inode (struct inode *inode); extern int adfs_map_lookup (struct super_block *sb, int frag_id, int offset); /* namei.c */ -extern int adfs_lookup (struct inode *dir, struct dentry *dentry); +extern struct dentry *adfs_lookup (struct inode *dir, struct dentry *dentry); /* super.c */ extern int init_adfs_fs (void); diff --git a/include/linux/affs_fs.h b/include/linux/affs_fs.h index 6361a82a1cee..342ac2648c30 100644 --- a/include/linux/affs_fs.h +++ b/include/linux/affs_fs.h @@ -60,7 +60,7 @@ extern void affs_make_zones(struct super_block *sb); /* namei.c */ extern int affs_hash_name(const unsigned char *name, int len, int intl, int hashsize); -extern int affs_lookup(struct inode *dir, struct dentry *dentry); +extern struct dentry *affs_lookup(struct inode *dir, struct dentry *dentry); extern int affs_unlink(struct inode *dir, struct dentry *dentry); extern int affs_create(struct inode *dir, struct dentry *dentry, int mode); extern int affs_mkdir(struct inode *dir, struct dentry *dentry, int mode); diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h index 96b1d19557e4..b1352dc021df 100644 --- a/include/linux/ext2_fs.h +++ b/include/linux/ext2_fs.h @@ -572,7 +572,7 @@ extern int ext2_ioctl (struct inode *, struct file *, unsigned int, /* namei.c */ extern void ext2_release (struct inode *, struct file *); -extern int ext2_lookup (struct inode *, struct dentry *); +extern struct dentry *ext2_lookup (struct inode *, struct dentry *); extern int ext2_create (struct inode *,struct dentry *,int); extern int ext2_mkdir (struct inode *,struct dentry *,int); extern int ext2_rmdir (struct inode *,struct dentry *); diff --git a/include/linux/fb.h b/include/linux/fb.h index d4bb4ae7882d..f084ca0366b1 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -31,6 +31,7 @@ #define FB_TYPE_PLANES 1 /* Non interleaved planes */ #define FB_TYPE_INTERLEAVED_PLANES 2 /* Interleaved planes */ #define FB_TYPE_TEXT 3 /* Text/attributes */ +#define FB_TYPE_VGA_PLANES 4 /* EGA/VGA planes */ #define FB_AUX_TEXT_MDA 0 /* Monochrome text */ #define FB_AUX_TEXT_CGA 1 /* CGA/EGA/VGA Color text */ @@ -297,7 +298,7 @@ struct display { struct fb_info { char modename[40]; /* default video mode */ - int node; + kdev_t node; int flags; #define FBINFO_FLAG_MODULE 1 /* Low-level driver is a module */ struct fb_ops *fbops; diff --git a/include/linux/fs.h b/include/linux/fs.h index b6ecebbbe2da..4d658c33eb9e 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -254,18 +254,8 @@ static inline int buffer_protected(struct buffer_head * bh) return test_bit(BH_Protected, &bh->b_state); } -/* - * Deprecated - we don't keep per-buffer reference flags - * any more. - * - * We _could_ try to update the page reference, but that - * doesn't seem to really be worth it either. If we did, - * it would look something like this: - * - * #define buffer_page(bh) (mem_map + MAP_NR((bh)->b_data)) - * #define touch_buffer(bh) set_bit(PG_referenced, &buffer_page(bh)->flags) - */ -#define touch_buffer(bh) do { } while (0) +#define buffer_page(bh) (mem_map + MAP_NR((bh)->b_data)) +#define touch_buffer(bh) set_bit(PG_referenced, &buffer_page(bh)->flags) #include #include @@ -607,7 +597,7 @@ struct file_operations { struct inode_operations { struct file_operations * default_file_ops; int (*create) (struct inode *,struct dentry *,int); - int (*lookup) (struct inode *,struct dentry *); + struct dentry * (*lookup) (struct inode *,struct dentry *); int (*link) (struct dentry *,struct inode *,struct dentry *); int (*unlink) (struct inode *,struct dentry *); int (*symlink) (struct inode *,struct dentry *,const char *); diff --git a/include/linux/irda.h b/include/linux/irda.h new file mode 100644 index 000000000000..275d82fc9a36 --- /dev/null +++ b/include/linux/irda.h @@ -0,0 +1,120 @@ +/********************************************************************* + * + * Filename: irda.h + * Version: + * Description: + * Status: Experimental. + * Author: Dag Brattli + * Created at: Mon Mar 8 14:06:12 1999 + * Modified at: Mon Mar 22 14:14:54 1999 + * Modified by: Dag Brattli + * + * Copyright (c) 1999 Dag Brattli, All Rights Reserved. + * + * 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. + * + * Neither Dag Brattli nor University of Tromsø admit liability nor + * provide warranty for any of this software. This material is + * provided "AS-IS" and at no charge. + * + ********************************************************************/ + +#ifndef KERNEL_IRDA_H +#define KERNEL_IRDA_H + +/* Hint bit positions for first hint byte */ +#define HINT_PNP 0x01 +#define HINT_PDA 0x02 +#define HINT_COMPUTER 0x04 +#define HINT_PRINTER 0x08 +#define HINT_MODEM 0x10 +#define HINT_FAX 0x20 +#define HINT_LAN 0x40 +#define HINT_EXTENSION 0x80 + +/* Hint bit positions for second hint byte (first extension byte) */ +#define HINT_TELEPHONY 0x01 +#define HINT_FILE_SERVER 0x02 +#define HINT_COMM 0x04 +#define HINT_MESSAGE 0x08 +#define HINT_HTTP 0x10 +#define HINT_OBEX 0x20 + +/* IrLMP character code values */ +#define CS_ASCII 0x00 +#define CS_ISO_8859_1 0x01 +#define CS_ISO_8859_2 0x02 +#define CS_ISO_8859_3 0x03 +#define CS_ISO_8859_4 0x04 +#define CS_ISO_8859_5 0x05 +#define CS_ISO_8859_6 0x06 +#define CS_ISO_8859_7 0x07 +#define CS_ISO_8859_8 0x08 +#define CS_ISO_8859_9 0x09 +#define CS_UNICODE 0xff + +#define SOL_IRLMP 266 /* Same as SOL_IRDA for now */ +#define SOL_IRTTP 266 /* Same as SOL_IRDA for now */ + +#define IRLMP_ENUMDEVICES 1 +#define IRLMP_IAS_SET 2 +#define IRLMP_IAS_QUERY 3 +#define IRLMP_DISCOVERY_MASK_SET 4 + +#define IRTTP_QOS_SET 5 +#define IRTTP_QOS_GET 6 +#define IRTTP_MAX_SDU_SIZE 7 + +#define IAS_MAX_STRING 256 +#define IAS_MAX_OCTET_STRING 1024 +#define IAS_MAX_CLASSNAME 64 +#define IAS_MAX_ATTRIBNAME 256 + +#define LSAP_ANY 0xff + +struct sockaddr_irda { + sa_family_t sir_family; /* AF_IRDA */ + unsigned char sir_lsap_sel; /* LSAP/TSAP selector */ + unsigned int sir_addr; /* Device address */ + char sir_name[25]; /* Usually :IrDA:TinyTP */ +}; + +struct irda_device_info { + unsigned int saddr; /* Address of remote device */ + unsigned int daddr; /* Link where it was discovered */ + char info[22]; /* Description */ + unsigned char charset; /* Charset used for description */ + unsigned char hints[2]; /* Hint bits */ +}; + +struct irda_device_list { + unsigned int len; + struct irda_device_info dev[0]; +}; + +struct irda_ias_set { + char irda_class_name[IAS_MAX_CLASSNAME]; + char irda_attrib_name[IAS_MAX_ATTRIBNAME]; + unsigned int irda_attrib_type; + union { + unsigned int irda_attrib_int; + struct { + unsigned short len; + u_char OctetSeq[IAS_MAX_OCTET_STRING]; + } irda_attrib_octet_seq; + struct { + unsigned char len; + unsigned char charset; + unsigned char string[IAS_MAX_STRING]; + } irda_attrib_string; + } attribute; +}; + +#endif /* KERNEL_IRDA_H */ + + + + diff --git a/include/linux/iso_fs.h b/include/linux/iso_fs.h index 30a14b169ac5..0fcb4b822498 100644 --- a/include/linux/iso_fs.h +++ b/include/linux/iso_fs.h @@ -189,7 +189,7 @@ int get_acorn_filename(struct iso_directory_record *, char *, struct inode *); extern int isofs_open(struct inode * inode, struct file * filp); extern void isofs_release(struct inode * inode, struct file * filp); -extern int isofs_lookup(struct inode * dir, struct dentry *); +extern struct dentry *isofs_lookup(struct inode * dir, struct dentry *); extern unsigned long isofs_count_free_inodes(struct super_block *sb); extern int isofs_new_block(int dev); extern int isofs_free_block(int dev, int block); diff --git a/include/linux/kbd_ll.h b/include/linux/kbd_ll.h index d83f9ea8ac71..02ebf8ec8c55 100644 --- a/include/linux/kbd_ll.h +++ b/include/linux/kbd_ll.h @@ -7,6 +7,6 @@ extern struct pt_regs *kbd_pt_regs; -void handle_scancode(unsigned char scancode); +void handle_scancode(unsigned char scancode, int down); #endif /* _KBD_LL_H */ diff --git a/include/linux/minix_fs.h b/include/linux/minix_fs.h index 3a06359468c7..4682ee56e49c 100644 --- a/include/linux/minix_fs.h +++ b/include/linux/minix_fs.h @@ -89,7 +89,7 @@ struct minix_dir_entry { #ifdef __KERNEL__ -extern int minix_lookup(struct inode * dir, struct dentry *dentry); +extern struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry); extern int minix_create(struct inode * dir, struct dentry *dentry, int mode); extern int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode); extern int minix_rmdir(struct inode * dir, struct dentry *dentry); diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h index ab699c4edb53..7e27f1ac66df 100644 --- a/include/linux/msdos_fs.h +++ b/include/linux/msdos_fs.h @@ -271,7 +271,7 @@ extern struct super_block *msdos_read_super(struct super_block *sb,void *data, i /* msdos.c - these are for Umsdos */ extern void msdos_read_inode(struct inode *inode); -extern int msdos_lookup(struct inode *dir,struct dentry *); +extern struct dentry *msdos_lookup(struct inode *dir,struct dentry *); extern int msdos_create(struct inode *dir,struct dentry *dentry,int mode); extern int msdos_rmdir(struct inode *dir,struct dentry *dentry); extern int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode); @@ -312,7 +312,7 @@ extern void vfat_put_super(struct super_block *sb); extern struct super_block *vfat_read_super(struct super_block *sb,void *data, int silent); extern void vfat_read_inode(struct inode *inode); -extern int vfat_lookup(struct inode *dir,struct dentry *); +extern struct dentry *vfat_lookup(struct inode *dir,struct dentry *); /* vfat/vfatfs_syms.c */ extern struct file_system_type vfat_fs_type; diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 21ed45afc140..c8b5731df72e 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -382,7 +382,7 @@ extern int proc_match(int, const char *,struct proc_dir_entry *); * of the /proc/ subdirectories. */ extern int proc_readdir(struct file *, void *, filldir_t); -extern int proc_lookup(struct inode *, struct dentry *); +extern struct dentry *proc_lookup(struct inode *, struct dentry *); struct openpromfs_dev { struct openpromfs_dev *next; diff --git a/include/linux/qnx4_fs.h b/include/linux/qnx4_fs.h index eb2b3dc08299..c5a010394a91 100644 --- a/include/linux/qnx4_fs.h +++ b/include/linux/qnx4_fs.h @@ -95,7 +95,7 @@ struct qnx4_super_block { #define QNX4DEBUG(X) (void) 0 #endif -extern int qnx4_lookup(struct inode *dir, struct dentry *dentry); +extern struct dentry *qnx4_lookup(struct inode *dir, struct dentry *dentry); extern unsigned long qnx4_count_free_inodes(struct super_block *sb); extern unsigned long qnx4_count_free_blocks(struct super_block *sb); diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h index 9b615ac1be10..db74f03be22e 100644 --- a/include/linux/sysctl.h +++ b/include/linux/sysctl.h @@ -56,9 +56,15 @@ enum CTL_PROC=4, /* Process info */ CTL_FS=5, /* Filesystems */ CTL_DEBUG=6, /* Debugging */ - CTL_DEV=7 /* Devices */ + CTL_DEV=7, /* Devices */ + CTL_BUS=8 /* Buses */ }; +/* CTL_BUS names: */ +enum +{ + BUS_ISA=1 /* ISA */ +}; /* CTL_KERN names: */ enum @@ -133,9 +139,17 @@ enum NET_IPV6=12, NET_X25=13, NET_TR=14, - NET_DECNET=15 + NET_DECNET=15, + NET_ECONET=16 }; +/* /proc/sys/bus/isa */ +enum +{ + BUS_ISA_MEM_BASE=1, + BUS_ISA_PORT_BASE=2, + BUS_ISA_PORT_SHIFT=3 +}; /* /proc/sys/net/core */ enum diff --git a/include/linux/sysv_fs.h b/include/linux/sysv_fs.h index 7c8016886b29..49d9d24f163d 100644 --- a/include/linux/sysv_fs.h +++ b/include/linux/sysv_fs.h @@ -367,7 +367,7 @@ sv_bread (struct super_block *sb, kdev_t dev, unsigned int block) * Function prototypes */ -extern int sysv_lookup(struct inode * dir, struct dentry * dentry); +extern struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry); extern int sysv_create(struct inode * dir, struct dentry * dentry, int mode); extern int sysv_mkdir(struct inode * dir, struct dentry * dentry, int mode); extern int sysv_rmdir(struct inode * dir, struct dentry * dentry); diff --git a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h index d15d578b1e79..e36ceba9e9ea 100644 --- a/include/linux/ufs_fs.h +++ b/include/linux/ufs_fs.h @@ -540,7 +540,7 @@ extern struct buffer_head * ufs_getfrag (struct inode *, unsigned, int, int *); extern struct buffer_head * ufs_bread (struct inode *, unsigned, int, int *); /* namei.c */ -extern int ufs_lookup (struct inode *, struct dentry *); +extern struct dentry *ufs_lookup (struct inode *, struct dentry *); extern int ufs_mkdir(struct inode *, struct dentry *, int); extern int ufs_rmdir (struct inode *, struct dentry *); extern int ufs_unlink (struct inode *, struct dentry *); diff --git a/include/linux/umsdos_fs.p b/include/linux/umsdos_fs.p index e244069303bb..de436f0e8ff3 100644 --- a/include/linux/umsdos_fs.p +++ b/include/linux/umsdos_fs.p @@ -9,8 +9,8 @@ int dummy_dir_read ( struct file *filp, char * umsdos_d_path(struct dentry *, char *, int); void umsdos_lookup_patch_new(struct dentry *, struct umsdos_info *); int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry); -int umsdos_lookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo); -int UMSDOS_lookup(struct inode *, struct dentry *); +struct dentry *umsdos_lookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo); +struct dentry *UMSDOS_lookup(struct inode *, struct dentry *); struct dentry *umsdos_lookup_dentry(struct dentry *, char *, int, int); struct dentry *umsdos_covered(struct dentry *, char *, int); @@ -106,8 +106,8 @@ int UMSDOS_rename (struct inode *old_dir, struct dentry *new_dentry); /* rdir.c 22/03/95 03.31.42 */ -int umsdos_rlookup_x (struct inode *dir, struct dentry *dentry, int nopseudo); -int UMSDOS_rlookup (struct inode *dir, struct dentry *dentry); +struct dentry *umsdos_rlookup_x (struct inode *dir, struct dentry *dentry, int nopseudo); +struct dentry *UMSDOS_rlookup (struct inode *dir, struct dentry *dentry); /* symlink.c 23/01/95 03.38.30 */ diff --git a/include/linux/wireless.h b/include/linux/wireless.h index b81d92f9881a..d3c59fff5a67 100644 --- a/include/linux/wireless.h +++ b/include/linux/wireless.h @@ -1,7 +1,7 @@ /* * This file define a set of standard wireless extensions * - * Version : 6 18.2.99 + * Version : 7 23.4.99 * * Authors : Jean Tourrilhes - HPLB - */ @@ -85,7 +85,11 @@ * * V5 to V6 * -------- - * - 802.11 support + * - 802.11 support (ESSID ioctls) + * + * V6 to V7 + * -------- + * - define IW_ESSID_MAX_SIZE and IW_MAX_AP */ /* -------------------------- IOCTL LIST -------------------------- */ @@ -123,6 +127,7 @@ /* As the ESSID is a string up to 32 bytes long, it doesn't fit within the * 'iwreq' structure, so we need to use the 'data' member to point to a * string in user space, like it is done for RANGE... + * The "flags" member indicate if the ESSID is active or not. */ /* ------------------------- IOCTL STUFF ------------------------- */ @@ -169,6 +174,13 @@ /* Maximum of address that you may set with SPY */ #define IW_MAX_SPY 8 +/* Maximum of address that you may get in the + list of access points in range */ +#define IW_MAX_AP 8 + +/* Maximum size of the ESSID string */ +#define IW_ESSID_MAX_SIZE 32 + /****************************** TYPES ******************************/ /* --------------------------- SUBTYPES --------------------------- */ @@ -278,7 +290,7 @@ struct iwreq caddr_t pointer; /* Pointer to the data * (in user space) */ __u16 length; /* fields or byte size */ - __u16 flags; /* Unused */ + __u16 flags; /* Optional params */ } data; } u; }; diff --git a/include/net/irda/discovery.h b/include/net/irda/discovery.h index 99e4704b49d7..15e254b33feb 100644 --- a/include/net/irda/discovery.h +++ b/include/net/irda/discovery.h @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Tue Apr 6 16:53:53 1999 - * Modified at: Tue Apr 6 20:44:35 1999 + * Modified at: Thu Apr 22 11:04:56 1999 * Modified by: Dag Brattli * * Copyright (c) 1999 Dag Brattli, All Rights Reserved. @@ -37,6 +37,7 @@ #include #define DISCOVERY_EXPIRE_TIMEOUT 6*HZ +#define DISCOVERY_DEFAULT_SLOTS 0 /* * The DISCOVERY structure is used for both discovery requests and responses diff --git a/include/net/irda/ircomm_common.h b/include/net/irda/ircomm_common.h index e2b2ae507c57..cd1c41f86818 100644 --- a/include/net/irda/ircomm_common.h +++ b/include/net/irda/ircomm_common.h @@ -28,8 +28,12 @@ #include typedef enum { - COMM_DISCOVERY, COMM_IDLE, + + COMM_DISCOVERY_WAIT, + COMM_QUERYPARAM_WAIT, + COMM_QUERYLSAP_WAIT, + COMM_WAITI, COMM_WAITR, COMM_CONN, @@ -53,6 +57,12 @@ typedef enum { IRCOMM_DATA_REQUEST, LMP_DATA_INDICATION, IRCOMM_CONTROL_REQUEST, + + DISCOVERY_INDICATION, + GOT_PARAMETERS, + GOT_LSAPSEL, + QUERYIAS_ERROR, + } IRCOMM_EVENT; typedef enum { @@ -172,6 +182,9 @@ struct ircomm_cb{ __u32 daddr; /* Device address of the peer device */ __u32 saddr; + __u32 skey; + __u32 ckey; + int queryias_lock; int ias_type; int disconnect_priority; /* P_NORMAL or P_HIGH. see irttp.h */ struct notify_t notify; /* container of callbacks */ @@ -206,6 +219,7 @@ struct ircomm_cb{ __u8 peer_port_type; __u8 servicetype; + __u8 peer_servicetype; __u8 data_format; __u8 peer_data_format; __u8 flow_ctrl; @@ -241,8 +255,7 @@ struct ircomm_cb{ -int ircomm_query_ias_and_connect(struct ircomm_cb *self, __u8 servicetype); -void ircomm_connect_request(struct ircomm_cb *self); +void ircomm_connect_request(struct ircomm_cb *self, __u8 servicetype); void ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata, __u32 maxsdusize); void ircomm_disconnect_request(struct ircomm_cb *self, diff --git a/include/net/irda/irda.h b/include/net/irda/irda.h index d51e159f5b24..35c15fadc272 100644 --- a/include/net/irda/irda.h +++ b/include/net/irda/irda.h @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Tue Dec 9 21:13:12 1997 - * Modified at: Tue Apr 6 20:31:08 1999 + * Modified at: Wed Apr 21 17:49:00 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli, All Rights Reserved. @@ -43,14 +43,15 @@ #define ALIGN __attribute__((aligned)) #define PACK __attribute__((packed)) -/* use 0 for production, 1 for verification, >2 for debug */ + #ifdef CONFIG_IRDA_DEBUG extern __u32 irda_debug; -#define IRDA_DEBUG 0 +/* use 0 for production, 1 for verification, >2 for debug */ +#define IRDA_DEBUG_LEVEL 0 -#define DEBUG(n, args...) if (irda_debug >= (n)) printk( KERN_DEBUG args) +#define DEBUG(n, args...) if (irda_debug >= (n)) printk(KERN_DEBUG args) #define ASSERT(expr, func) \ if(!(expr)) { \ printk( "Assertion failed! %s,%s,%s,line=%d\n",\ @@ -61,6 +62,12 @@ if(!(expr)) { \ #define ASSERT(expr, func) #endif /* CONFIG_IRDA_DEBUG */ +#define WARNING(args...) printk(KERN_WARNING args) +#define MESSAGE(args...) printk(KERN_INFO args) +#define ERROR(args...) printk(KERN_ERR args) + +#define MSECS_TO_JIFFIES(ms) (ms*HZ/1000) + /* * Magic numbers used by Linux/IR. Random numbers which must be unique to * give the best protection @@ -112,6 +119,8 @@ struct irda_sock { int nslots; /* Number of slots to use for discovery */ + int errno; + struct sock *sk; struct wait_queue *ias_wait; /* Wait for LM-IAS answer */ diff --git a/include/net/irda/irda_device.h b/include/net/irda/irda_device.h index 3f61a4e71b29..a3dcf2d6e78f 100644 --- a/include/net/irda/irda_device.h +++ b/include/net/irda/irda_device.h @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Haris Zukanovic * Created at: Tue Apr 14 12:41:42 1998 - * Modified at: Wed Apr 7 17:17:16 1999 + * Modified at: Tue Apr 20 11:06:28 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Haris Zukanovic, @@ -36,15 +36,18 @@ #include #include #include +#include /* Some non-standard interface flags (should not conflict with any in if.h) */ -#define IFF_SIR 0x01 /* Supports SIR speeds */ -#define IFF_MIR 0x02 /* Supports MIR speeds */ -#define IFF_FIR 0x04 /* Supports FIR speeds */ -#define IFF_PIO 0x08 /* Supports PIO transfer of data */ -#define IFF_DMA 0x10 /* Supports DMA transfer of data */ -#define IFF_SHM 0x20 /* Supports shared memory data transfers */ -#define IFF_DONGLE 0x40 /* Interface has a dongle attached */ +#define IFF_SIR 0x0001 /* Supports SIR speeds */ +#define IFF_MIR 0x0002 /* Supports MIR speeds */ +#define IFF_FIR 0x0004 /* Supports FIR speeds */ +#define IFF_VFIR 0x0008 /* Supports VFIR speeds */ +#define IFF_PIO 0x0010 /* Supports PIO transfer of data */ +#define IFF_DMA 0x0020 /* Supports DMA transfer of data */ +#define IFF_SHM 0x0040 /* Supports shared memory data transfers */ +#define IFF_DONGLE 0x0080 /* Interface has a dongle attached */ +#define IFF_AIR 0x0100 /* Supports A(dvanced)IR standards */ #define IO_XMIT 0x01 #define IO_RECV 0x02 @@ -65,18 +68,17 @@ struct chipio_t { int dongle_id; /* Dongle or transceiver currently used */ }; -/* Buffer specific info */ +/* IO buffer specific info (inspired by struct sk_buff) */ struct iobuff_t { int state; /* Receiving state (transmit state not used) */ int in_frame; /* True if receiving frame */ - __u8 *data; /* the buffer */ - __u8 *head; /* start of data in buffer */ + __u8 *head; /* start of buffer */ + __u8 *data; /* start of data in buffer */ __u8 *tail; /* end of data in buffer */ - int offset; /* Usually data + offset = head */ - int len; /* currently used bytes in buffer */ - int truesize; /* total size of the data area */ + int len; /* length of data */ + int truesize; /* total size of buffer */ __u16 fcs; int flags; /* Allocation flags (GFP_KERNEL | GFP_DMA ) */ @@ -89,7 +91,7 @@ struct iobuff_t { * stuff from IrDA port implementations. */ struct irda_device { - QUEUE q; /* Must be first */ + QUEUE q; /* Must be first */ int magic; /* Our magic bullet */ char name[16]; /* Name of device "irda0" */ @@ -109,18 +111,18 @@ struct irda_device { struct iobuff_t tx_buff; struct iobuff_t rx_buff; - int xbofs; - int media_busy; /* spinlock_t lock; */ /* For serializing operations */ /* Media busy stuff */ + int media_busy; struct timer_list media_busy_timer; - /* Driver specific implementation */ + /* Callbacks for driver specific implementation */ void (*change_speed)(struct irda_device *driver, int baud); - int (*is_receiving)(struct irda_device *); /* receiving? */ + int (*is_receiving)(struct irda_device *); /* receiving? */ /* int (*is_tbusy)(struct irda_device *); */ /* transmitting? */ void (*wait_until_sent)(struct irda_device *); + void (*set_caddr)(struct irda_device *); /* Set connection addr */ }; extern hashbin_t *irda_device; @@ -143,8 +145,28 @@ int irda_device_txqueue_empty(struct irda_device *self); int irda_device_setup(struct device *dev); -inline unsigned short irda_get_mtt(struct sk_buff *skb); - void setup_dma(int channel, char *buffer, int count, int mode); +/* + * Function irda_get_mtt (skb) + * + * Utility function for getting the minimum turnaround time out of + * the skb, where it has been hidden in the cb field. + */ +inline static __u16 irda_get_mtt(struct sk_buff *skb) +{ + __u16 mtt; + + if (((struct irlap_skb_cb *)(skb->cb))->magic != LAP_MAGIC) + mtt = 10000; + else + mtt = ((struct irlap_skb_cb *)(skb->cb))->mtt; + + ASSERT(mtt <= 10000, return 10000;); + + return mtt; +} + #endif + + diff --git a/include/net/irda/iriap.h b/include/net/irda/iriap.h index 470a9477be5a..071ed8561b0c 100644 --- a/include/net/irda/iriap.h +++ b/include/net/irda/iriap.h @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Thu Aug 21 00:02:07 1997 - * Modified at: Mon Mar 22 13:15:04 1999 + * Modified at: Wed Apr 21 16:37:21 1999 * Modified by: Dag Brattli * * Copyright (c) 1997 Dag Brattli , All Rights Reserved. @@ -51,9 +51,10 @@ #define IAS_SUCCESS 0 #define IAS_CLASS_UNKNOWN 1 #define IAS_ATTRIB_UNKNOWN 2 +#define IAS_DISCONNECT 10 -typedef void (*CONFIRM_CALLBACK)( __u16 obj_id, struct ias_value *value, - void *priv); +typedef void (*CONFIRM_CALLBACK)(int result, __u16 obj_id, + struct ias_value *value, void *priv); struct iriap_cb { QUEUE queue; /* Must be first */ diff --git a/include/net/irda/irkbd.h b/include/net/irda/irkbd.h deleted file mode 100644 index 819df24fca4c..000000000000 --- a/include/net/irda/irkbd.h +++ /dev/null @@ -1,91 +0,0 @@ -/********************************************************************* - * - * Filename: irkbd.h - * Version: 0.2 - * Description: IrDA Keyboard/Mouse driver (Tekram IR-660) - * Status: Experimental. - * Author: Dag Brattli - * Created at: Mon Mar 1 00:24:19 1999 - * Modified at: Thu Mar 11 14:54:00 1999 - * Modified by: Dag Brattli - * - * Copyright (c) 1999 Dag Brattli, All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef IRKBD_H -#define IRKBD_H - -/* Some commands */ -#define IRKBD_CMD_INIT_KBD 0xfe -#define IRKBD_CMD_INIT_MOUSE 0xff -#define IRKBD_CMD_ENABLE 0x41 -#define IRKBD_CMD_LED 0x31 -#define IRKBD_CMD_KDB_SPEED 0x33 - -/* Some responses */ -#define IRKBD_RSP_KBDOK 0x11 -#define IRKBD_RSP_KBDERR 0x12 -#define IRKBD_RSP_MSOK 0x21 -#define IRKBD_RSP_MSERR 0x22 -#define IRKBD_RSP_LEDOK 0x31 -#define IRKBD_RSP_KBDSPEEDOK 0x33 -#define IRKBD_RSP_RSPN41 0x41 - -#define IRKBD_RATE 2 /* Polling rate, should be 15 ms */ -#define IRKBD_TIMEOUT 100 /* 1000 ms */ - -#define SUBFRAME_MASK 0xc0 -#define SUBFRAME_MOUSE 0x80 -#define SUBFRAME_KEYBOARD 0x40 -#define SUBFRAME_RESPONSE 0x00 - -#define IRKBD_MAX_HEADER (TTP_HEADER+LMP_HEADER+LAP_HEADER) - -#define IRKBD_BUF_SIZE 4096 /* Must be power of 2! */ - -enum { - IRKBD_IDLE, /* Not connected */ - IRKBD_INIT_KBD, /* Initializing keyboard */ - IRKBD_INIT_MOUSE, /* Initializing mouse */ - IRKBD_POLLING, /* Polling device */ -}; - -/* Main structure */ -struct irkbd_cb { - struct miscdevice dev; - char devname[9]; /* name of the registered device */ - int state; - - int count; /* Open count */ - - __u32 saddr; /* my local address */ - __u32 daddr; /* peer address */ - - struct tsap_cb *tsap; - __u8 dtsap_sel; /* remote TSAP address */ - __u8 stsap_sel; /* local TSAP address */ - - struct timer_list watchdog_timer; - - LOCAL_FLOW tx_flow; - LOCAL_FLOW rx_flow; - - __u8 scancodes[IRKBD_BUF_SIZE]; /* Buffer for mouse events */ - int head; - int tail; - - struct wait_queue *read_wait; - struct fasync_struct *async; -}; - -#endif /* IRKBD_H */ diff --git a/include/net/irda/irlan_client.h b/include/net/irda/irlan_client.h index a2d65155712d..62ea6157a708 100644 --- a/include/net/irda/irlan_client.h +++ b/include/net/irda/irlan_client.h @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sun Aug 31 20:14:37 1997 - * Modified at: Thu Feb 25 21:05:53 1999 + * Modified at: Thu Apr 22 14:13:34 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli , All Rights Reserved. @@ -30,6 +30,7 @@ #include #include +#include #include void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout); @@ -38,7 +39,7 @@ void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr); void irlan_client_open_ctrl_tsap( struct irlan_cb *self); -void irlan_client_extract_params(struct irlan_cb *self, struct sk_buff *skb); -void irlan_client_get_value_confirm( __u16 obj_id, struct ias_value *value, - void *priv); +void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb); +void irlan_client_get_value_confirm(int result, __u16 obj_id, + struct ias_value *value, void *priv); #endif diff --git a/include/net/irda/irlan_common.h b/include/net/irda/irlan_common.h index f3103628e4c7..35d83096faf5 100644 --- a/include/net/irda/irlan_common.h +++ b/include/net/irda/irlan_common.h @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sun Aug 31 20:14:37 1997 - * Modified at: Tue Apr 6 16:19:41 1999 + * Modified at: Thu Apr 22 14:30:37 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli , All Rights Reserved. @@ -121,7 +121,6 @@ struct irlan_client_cb { int broadcast_open; struct timer_list kick_timer; - int start_new_provider; }; /* @@ -183,6 +182,10 @@ struct irlan_cb { struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr, int netdev); void irlan_close(struct irlan_cb *self); +void irlan_close_tsaps(struct irlan_cb *self); +void irlan_mod_inc_use_count(void); +void irlan_mod_dec_use_count(void); + int irlan_register_netdev(struct irlan_cb *self); void irlan_ias_register(struct irlan_cb *self, __u8 tsap_sel); void irlan_start_watchdog_timer(struct irlan_cb *self, int timeout); @@ -204,7 +207,7 @@ int irlan_insert_string_param(struct sk_buff *skb, char *param, char *value); int irlan_insert_array_param(struct sk_buff *skb, char *name, __u8 *value, __u16 value_len); -int irlan_get_param(__u8 *buf, char *name, char *value, __u16 *len); +int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len); void print_ret_code(__u8 code); extern hashbin_t *irlan; diff --git a/include/net/irda/irlan_eth.h b/include/net/irda/irlan_eth.h index 257a719f4603..6ad33ee48982 100644 --- a/include/net/irda/irlan_eth.h +++ b/include/net/irda/irlan_eth.h @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Thu Oct 15 08:36:58 1998 - * Modified at: Mon Mar 22 12:57:11 1999 + * Modified at: Thu Apr 22 14:09:37 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli, All Rights Reserved. @@ -25,6 +25,9 @@ #ifndef IRLAN_ETH_H #define IRLAN_ETH_H +int irlan_eth_init(struct device *dev); +int irlan_eth_open(struct device *dev); +int irlan_eth_close(struct device *dev); int irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb); int irlan_eth_xmit(struct sk_buff *skb, struct device *dev); diff --git a/include/net/irda/irlan_provider.h b/include/net/irda/irlan_provider.h index 05b6736173ea..aafbf9141245 100644 --- a/include/net/irda/irlan_provider.h +++ b/include/net/irda/irlan_provider.h @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sun Aug 31 20:14:37 1997 - * Modified at: Mon Mar 8 15:32:35 1999 + * Modified at: Thu Apr 22 14:29:16 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli , All Rights Reserved. @@ -46,12 +46,12 @@ void irlan_provider_connect_indication(void *instance, void *sap, void irlan_provider_connect_response(struct irlan_cb *, struct tsap_cb *); int irlan_parse_open_data_cmd(struct irlan_cb *self, struct sk_buff *skb); -int irlan_provider_extract_params(struct irlan_cb *self, int cmd, - struct sk_buff *skb); +int irlan_provider_parse_command(struct irlan_cb *self, int cmd, + struct sk_buff *skb); void irlan_provider_send_reply(struct irlan_cb *self, int command, int ret_code); -void irlan_provider_open_ctrl_tsap( struct irlan_cb *self); +int irlan_provider_open_ctrl_tsap(struct irlan_cb *self); #endif diff --git a/include/net/irda/irlap.h b/include/net/irda/irlap.h index 1de71bfd118b..f3b26110f646 100644 --- a/include/net/irda/irlap.h +++ b/include/net/irda/irlap.h @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Mon Aug 4 20:40:53 1997 - * Modified at: Fri Mar 26 15:15:17 1999 + * Modified at: Fri Apr 23 09:51:15 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli , All Rights Reserved. @@ -219,12 +219,12 @@ int irlap_validate_ns_received( struct irlap_cb *, int ns); int irlap_generate_rand_time_slot( int S, int s); void irlap_initiate_connection_state( struct irlap_cb *); -void irlap_flush_all_queues( struct irlap_cb *); -void irlap_change_speed( struct irlap_cb *, int); -void irlap_wait_min_turn_around( struct irlap_cb *, struct qos_info *); +void irlap_flush_all_queues(struct irlap_cb *); +void irlap_change_speed(struct irlap_cb *, int); +void irlap_wait_min_turn_around(struct irlap_cb *, struct qos_info *); -void irlap_init_qos_capabilities( struct irlap_cb *, struct qos_info *); -void irlap_apply_default_connection_parameters( struct irlap_cb *self); -void irlap_apply_connection_parameters( struct irlap_cb *, struct qos_info *); +void irlap_init_qos_capabilities(struct irlap_cb *, struct qos_info *); +void irlap_apply_default_connection_parameters(struct irlap_cb *self); +void irlap_apply_connection_parameters(struct irlap_cb *, struct qos_info *); #endif diff --git a/include/net/irda/irlap_frame.h b/include/net/irda/irlap_frame.h index 7db0825f7d76..7425b41b4cf4 100644 --- a/include/net/irda/irlap_frame.h +++ b/include/net/irda/irlap_frame.h @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Tue Aug 19 10:27:26 1997 - * Modified at: Fri Mar 26 14:10:53 1999 + * Modified at: Fri Apr 23 09:33:55 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli , All Rights Reserved. @@ -117,8 +117,6 @@ struct irlap_skb_cb { int vr; /* next frame to receive */ }; -__inline__ void irlap_insert_mtt( struct irlap_cb *self, struct sk_buff *skb); - void irlap_send_discovery_xid_frame( struct irlap_cb *, int S, __u8 s, __u8 command, discovery_t *discovery); void irlap_send_snrm_frame( struct irlap_cb *, struct qos_info *); diff --git a/include/net/irda/irlmp.h b/include/net/irda/irlmp.h index b5c9daae41c8..31785883a584 100644 --- a/include/net/irda/irlmp.h +++ b/include/net/irda/irlmp.h @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sun Aug 17 20:54:32 1997 - * Modified at: Tue Apr 6 20:05:14 1999 + * Modified at: Fri Apr 23 09:15:07 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli , All Rights Reserved. @@ -202,12 +202,12 @@ int irlmp_update_client(__u32 handle, __u16 hint_mask, void irlmp_register_link(struct irlap_cb *, __u32 saddr, struct notify_t *); void irlmp_unregister_link(__u32 saddr); -int irlmp_connect_request( struct lsap_cb *, __u8 dlsap_sel, - __u32 saddr, __u32 daddr, - struct qos_info *, struct sk_buff *); -void irlmp_connect_indication( struct lsap_cb *self, struct sk_buff *skb); -void irlmp_connect_response( struct lsap_cb *, struct sk_buff *); -void irlmp_connect_confirm( struct lsap_cb *, struct sk_buff *); +int irlmp_connect_request(struct lsap_cb *, __u8 dlsap_sel, + __u32 saddr, __u32 daddr, + struct qos_info *, struct sk_buff *); +void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb); +void irlmp_connect_response(struct lsap_cb *, struct sk_buff *); +void irlmp_connect_confirm(struct lsap_cb *, struct sk_buff *); struct lsap_cb *irlmp_dup(struct lsap_cb *self, void *instance); void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason, @@ -219,17 +219,17 @@ void irlmp_discovery_request(int nslots); void irlmp_do_discovery(int nslots); discovery_t *irlmp_get_discovery_response(void); -void irlmp_data_request( struct lsap_cb *, struct sk_buff *); -void irlmp_udata_request( struct lsap_cb *, struct sk_buff *); -void irlmp_data_indication( struct lsap_cb *, struct sk_buff *); -void irlmp_udata_indication( struct lsap_cb *, struct sk_buff *); +void irlmp_data_request(struct lsap_cb *, struct sk_buff *); +inline void irlmp_udata_request(struct lsap_cb *, struct sk_buff *); +inline void irlmp_data_indication(struct lsap_cb *, struct sk_buff *); +inline void irlmp_udata_indication(struct lsap_cb *, struct sk_buff *); void irlmp_status_request(void); -void irlmp_status_indication( LINK_STATUS link, LOCK_STATUS lock); +void irlmp_status_indication(LINK_STATUS link, LOCK_STATUS lock); -int irlmp_slsap_inuse( __u8 slsap); +int irlmp_slsap_inuse(__u8 slsap); __u8 irlmp_find_free_slsap(void); -LM_REASON irlmp_convert_lap_reason( LAP_REASON); +LM_REASON irlmp_convert_lap_reason(LAP_REASON); __u32 irlmp_get_saddr(struct lsap_cb *self); __u32 irlmp_get_daddr(struct lsap_cb *self); diff --git a/include/net/irda/irlpt_cli.h b/include/net/irda/irlpt_cli.h index cd0807dd2a84..ab3178885e82 100644 --- a/include/net/irda/irlpt_cli.h +++ b/include/net/irda/irlpt_cli.h @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sat Feb 21 18:54:38 1998 - * Modified at: Mon Jan 11 15:58:16 1999 + * Modified at: Wed Apr 21 16:46:26 1999 * Modified by: Dag Brattli * * Copyright (c) 1998, Thomas Davis, @@ -34,7 +34,7 @@ * if it's static, it doesn't go in here. */ -void irlpt_client_get_value_confirm(__u16 obj_id, +void irlpt_client_get_value_confirm(int result, __u16 obj_id, struct ias_value *value, void *priv); void irlpt_client_connect_indication( void *instance, diff --git a/include/net/irda/irmod.h b/include/net/irda/irmod.h index 4605b1b7799a..651e87dbcca0 100644 --- a/include/net/irda/irmod.h +++ b/include/net/irda/irmod.h @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Mon Dec 15 13:58:52 1997 - * Modified at: Tue Mar 16 22:27:41 1999 + * Modified at: Fri Apr 9 11:13:39 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli, All Rights Reserved. @@ -101,7 +101,22 @@ struct irda_cb { int irmod_init_module(void); void irmod_cleanup_module(void); -inline int irda_lock(int *lock); +/* + * Function irda_lock (lock) + * + * Lock variable. Returns false if the lock is already set. + * + */ +static inline int irda_lock(int *lock) +{ + if (test_and_set_bit( 0, (void *) lock)) { + DEBUG(3, __FUNCTION__ + "(), Trying to lock, already locked variable!\n"); + return FALSE; + } + return TRUE; +} + inline int irda_unlock(int *lock); void irda_notify_init(struct notify_t *notify); diff --git a/include/net/irda/irobex.h b/include/net/irda/irobex.h deleted file mode 100644 index 0a5adcfbb42a..000000000000 --- a/include/net/irda/irobex.h +++ /dev/null @@ -1,114 +0,0 @@ -/********************************************************************* - * - * Filename: irobex.h - * Version: 0.8 - * Description: - * Status: Experimental. - * Author: Dag Brattli - * Created at: Sat Jul 4 22:43:57 1998 - * Modified at: Thu Mar 11 16:11:54 1999 - * Modified by: Dag Brattli - * - * Copyright (c) 1998 Dag Brattli, All Rights Reserved. - * - * 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. - * - * Neither Dag Brattli nor University of Tromsø admit liability nor - * provide warranty for any of this software. This material is - * provided "AS-IS" and at no charge. - * - ********************************************************************/ - -#ifndef IROBEX_H -#define IROBEX_H - -#include -#include -#include -#include - -#include -#include -#include - -#define LOW_THRESHOLD 4 -#define HIGH_THRESHOLD 8 -#define IROBEX_MAX_QUEUE 12 - -/* Small structure to be used by the IOCTL call */ -struct irobex_ioc_t { - __u32 daddr; -}; - -#define IROBEX_IOC_MAGIC 'k' - -#define IROBEX_IOCSCONNECT _IOW(IROBEX_IOC_MAGIC, 1, 4) -#define IROBEX_IOCSDISCONNECT _IOW(IROBEX_IOC_MAGIC, 2, 4) -#define IROBEX_IOC_MAXNR 2 - -#define IROBEX_MAX_HEADER (TTP_HEADER+LMP_HEADER+LAP_HEADER) - -typedef enum { - OBEX_IDLE, /* Doing nothing */ - OBEX_DISCOVER, /* Trying to discovery remote device */ - OBEX_QUERY, /* Querying remote LM-IAS */ - OBEX_CONN, /* Trying to connect to remote device */ - OBEX_DATA, /* Data transfer ready */ -} OBEX_STATE; - -struct irobex_cb { - QUEUE queue; /* Must be first! */ - - int magic; /* magic used to detect corruption of the struct */ - - OBEX_STATE state; /* Current state */ - - __u32 saddr; /* my local address */ - __u32 daddr; /* peer address */ - unsigned long time_discovered; - - __u32 ckey; /* IrLMP client handle */ - __u32 skey; /* IrLMP service handle */ - - char devname[9]; /* name of the registered device */ - struct tsap_cb *tsap; - int eof; - - __u8 dtsap_sel; /* remote TSAP address */ - __u8 stsap_sel; /* local TSAP address */ - - int irlap_data_size; - - struct miscdevice dev; - - int count; /* open count */ - - struct sk_buff_head rx_queue; /* Receive queue */ - - struct wait_queue *read_wait; - struct wait_queue *write_wait; - - struct fasync_struct *async; - - struct timer_list watchdog_timer; - - LOCAL_FLOW tx_flow; - LOCAL_FLOW rx_flow; -}; - -int irobex_init(void); - -void irobex_watchdog_timer_expired( unsigned long data); - -inline void irobex_start_watchdog_timer( struct irobex_cb *self, int timeout) -{ - irda_start_timer( &self->watchdog_timer, timeout, (unsigned long) self, - irobex_watchdog_timer_expired); -} - -extern struct irobex_cb *irobex; - -#endif diff --git a/include/net/irda/irttp.h b/include/net/irda/irttp.h index 78fab8a88447..aec1d57dc157 100644 --- a/include/net/irda/irttp.h +++ b/include/net/irda/irttp.h @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sun Aug 31 20:14:31 1997 - * Modified at: Mon Mar 22 13:17:30 1999 + * Modified at: Sat Apr 10 10:19:56 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli , All Rights Reserved. @@ -93,7 +93,7 @@ struct tsap_cb { __u32 rx_max_sdu_size; /* Max receive user data size */ int tx_sdu_busy; /* TxSdu.busy */ - int tx_max_sdu_size; /* Max transmit user data size */ + __u32 tx_max_sdu_size; /* Max transmit user data size */ int close_pend; /* Close, but disconnect_pend */ int disconnect_pend; /* Disconnect, but still data to send */ diff --git a/init/main.c b/init/main.c index 81d01003ffd7..5128e512bd11 100644 --- a/init/main.c +++ b/init/main.c @@ -184,6 +184,7 @@ extern void eata2x_setup(char *str, int *ints); extern void u14_34f_setup(char *str, int *ints); extern void fdomain_setup(char *str, int *ints); extern void ibmmca_scsi_setup(char *str, int *ints); +extern void fd_mcs_setup(char *str, int *ints); extern void in2000_setup(char *str, int *ints); extern void NCR53c406a_setup(char *str, int *ints); extern void sym53c416_setup(char *str, int *ints); @@ -709,6 +710,9 @@ static struct kernel_param cooked_params[] __initdata = { #ifdef CONFIG_SCSI_IBMMCA { "ibmmcascsi=", ibmmca_scsi_setup }, #endif +#ifdef CONFIG_SCSI_FD_MCS + { "fd_mcs=", fd_mcs_setup }, +#endif #if defined(CONFIG_SCSI_DC390T) && ! defined(CONFIG_SCSI_DC390T_NOGENSUPP) { "tmscsim=", dc390_setup }, #endif diff --git a/net/802/tr.c b/net/802/tr.c index a8f77970efb0..9047eaa49108 100644 --- a/net/802/tr.c +++ b/net/802/tr.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -68,6 +67,8 @@ struct rif_cache_s { rif_cache rif_table[RIF_TABLE_SIZE]={ NULL, }; +static spinlock_t rif_lock = SPIN_LOCK_UNLOCKED; + #define RIF_TIMEOUT 60*10*HZ #define RIF_CHECK_INTERVAL 60*HZ @@ -230,6 +231,9 @@ static void tr_source_route(struct sk_buff *skb,struct trh_hdr *trh,struct devic unsigned int hash; rif_cache entry; unsigned char *olddata; + unsigned long flags; + + spin_lock_irqsave(&rif_lock, flags); /* * Broadcasts are single route as stated in RFC 1042 @@ -298,6 +302,8 @@ printk("source routing for %02X %02X %02X %02X %02X %02X\n",trh->daddr[0], else slack = 18 - ((ntohs(trh->rcf) & TR_RCF_LEN_MASK)>>8); olddata = skb->data; + spin_unlock_irqrestore(&rif_lock, flags); + skb_pull(skb, slack); memmove(skb->data, olddata, sizeof(struct trh_hdr) - slack); } @@ -312,7 +318,11 @@ static void tr_add_rif_info(struct trh_hdr *trh, struct device *dev) int i; unsigned int hash, rii_p = 0; rif_cache entry; + unsigned long flags; + + spin_lock_irqsave(&rif_lock, flags); + /* * Firstly see if the entry exists */ @@ -350,6 +360,7 @@ printk("adding rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n", if(!entry) { printk(KERN_DEBUG "tr.c: Couldn't malloc rif cache entry !\n"); + spin_unlock_irqrestore(&rif_lock, flags); return; } @@ -391,6 +402,7 @@ printk("updating rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n", } entry->last_used=jiffies; } + spin_unlock_irqrestore(&rif_lock, flags); } /* @@ -402,9 +414,8 @@ static void rif_check_expire(unsigned long dummy) int i; unsigned long now=jiffies,flags; - save_flags(flags); - cli(); - + spin_lock_irqsave(&rif_lock, flags); + for(i=0; i < RIF_TABLE_SIZE;i++) { rif_cache entry, *pentry=rif_table+i; @@ -422,7 +433,8 @@ static void rif_check_expire(unsigned long dummy) pentry=&entry->next; } } - restore_flags(flags); + + spin_unlock_irqrestore(&rif_lock, flags); /* * Reset the timer diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c index 180701ad2463..6dd118024871 100644 --- a/net/irda/af_irda.c +++ b/net/irda/af_irda.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sun May 31 10:12:43 1998 - * Modified at: Wed Apr 7 17:32:27 1999 + * Modified at: Thu Apr 22 12:08:04 1999 * Modified by: Dag Brattli * Sources: af_netroom.c, af_ax25.c, af_rose.c, af_x25.c etc. * @@ -39,6 +39,7 @@ #include #include #include +#include extern int irda_init(void); extern void irda_cleanup(void); @@ -237,8 +238,8 @@ static void irda_flow_indication(void *instance, void *sap, LOCAL_FLOW flow) * Got answer from remote LM-IAS * */ -static void irda_get_value_confirm(__u16 obj_id, struct ias_value *value, - void *priv) +static void irda_get_value_confirm(int result, __u16 obj_id, + struct ias_value *value, void *priv) { struct irda_sock *self; @@ -251,11 +252,14 @@ static void irda_get_value_confirm(__u16 obj_id, struct ias_value *value, return; /* Check if request succeeded */ - if (!value) { + if (result != IAS_SUCCESS) { DEBUG(0, __FUNCTION__ "(), IAS query failed!\n"); + self->errno = result; + /* Wake up any processes waiting for result */ wake_up_interruptible(&self->ias_wait); + return; } @@ -673,7 +677,7 @@ static int irda_create(struct socket *sock, int protocol) self->mask = 0xffff; self->rx_flow = self->tx_flow = FLOW_START; self->max_sdu_size_rx = SAR_DISABLE; /* Default value */ - self->nslots = 6; /* Default for now */ + self->nslots = DISCOVERY_DEFAULT_SLOTS; /* Notify that we are using the irda module, so nobody removes it */ irda_mod_inc_use_count(); @@ -857,6 +861,12 @@ static int irda_recvmsg(struct socket *sock, struct msghdr *msg, int size, return copied; } +/* + * Function irda_shutdown (sk, how) + * + * + * + */ static int irda_shutdown( struct socket *sk, int how) { DEBUG( 0, __FUNCTION__ "()\n"); @@ -866,6 +876,12 @@ static int irda_shutdown( struct socket *sk, int how) } +/* + * Function irda_poll (file, sock, wait) + * + * + * + */ unsigned int irda_poll(struct file *file, struct socket *sock, struct poll_table_struct *wait) { diff --git a/net/irda/discovery.c b/net/irda/discovery.c index f6561db8b301..22def3a1e89c 100644 --- a/net/irda/discovery.c +++ b/net/irda/discovery.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Tue Apr 6 15:33:50 1999 - * Modified at: Tue Apr 6 20:26:46 1999 + * Modified at: Sun Apr 11 00:41:58 1999 * Modified by: Dag Brattli * * Copyright (c) 1999 Dag Brattli, All Rights Reserved. @@ -46,7 +46,7 @@ void irlmp_add_discovery(hashbin_t *cachelog, discovery_t *discovery) { discovery_t *old; - DEBUG(2, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); /* Check if we have discovered this device before */ old = hashbin_remove(cachelog, discovery->daddr, NULL); @@ -67,7 +67,7 @@ void irlmp_add_discovery_log(hashbin_t *cachelog, hashbin_t *log) { discovery_t *discovery; - DEBUG(2, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); /* * If log is missing this means that IrLAP was unable to perform the @@ -100,7 +100,7 @@ void irlmp_expire_discoveries(hashbin_t *log, int saddr, int force) { discovery_t *discovery, *curr; - DEBUG(3, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); discovery = (discovery_t *) hashbin_get_first(log); while (discovery != NULL) { diff --git a/net/irda/ircomm/ircomm_common.c b/net/irda/ircomm/ircomm_common.c index 5796ced173ab..c7e805242b83 100644 --- a/net/irda/ircomm/ircomm_common.c +++ b/net/irda/ircomm/ircomm_common.c @@ -41,13 +41,21 @@ #include -static char *revision_date = "Tue Mar 2 02:03:58 1999"; +static char *revision_date = "Sun Apr 18 00:40:19 1999"; -static void ircomm_state_discovery(struct ircomm_cb *self, - IRCOMM_EVENT event, struct sk_buff *skb ); static void ircomm_state_idle( struct ircomm_cb *self, IRCOMM_EVENT event, struct sk_buff *skb ); + +static void ircomm_state_discoverywait( struct ircomm_cb *self, IRCOMM_EVENT event, + struct sk_buff *skb ); + +static void ircomm_state_queryparamwait( struct ircomm_cb *self, IRCOMM_EVENT event, + struct sk_buff *skb ); + +static void ircomm_state_querylsapwait( struct ircomm_cb *self, IRCOMM_EVENT event, + struct sk_buff *skb ); + static void ircomm_state_waiti( struct ircomm_cb *self, IRCOMM_EVENT event, struct sk_buff *skb ); static void ircomm_state_waitr( struct ircomm_cb *self, IRCOMM_EVENT event, @@ -63,13 +71,14 @@ static void ircomm_tx_controlchannel(struct ircomm_cb *self ); static int ircomm_proc_read(char *buf, char **start, off_t offset, int len, int unused); +static void start_discovering(struct ircomm_cb *self); static void query_lsapsel(struct ircomm_cb * self); -static void ircomm_getvalue_confirm( __u16 obj_id, struct ias_value *value, - void *priv); +static void query_parameters(struct ircomm_cb *self); +static void queryias_done(struct ircomm_cb *self); +static void ircomm_getvalue_confirm(int result, __u16 obj_id, + struct ias_value *value, void *priv); -static __u32 ckey; -static __u32 skey; struct ircomm_cb *discovering_instance; /* @@ -86,8 +95,12 @@ MODULE_PARM(ircomm_cs, "i"); static char *ircommstate[] = { - "DISCOVERY", "IDLE", + + "DISCOVERY_WAIT", + "QUERYPARAM_WAIT", + "QUERYLSAP_WAIT", + "WAITI", "WAITR", "CONN", @@ -126,6 +139,11 @@ static char *ircommevent[] = { "IRCOMM_DATA_REQUEST", "LMP_DATA_INDICATION", "IRCOMM_CONTROL_REQUEST", + + "DISCOVERY_INDICATION", + "GOT_PARAMETERS", + "GOT_LSAPSEL", + "QUERYIAS_ERROR", }; #ifdef CONFIG_PROC_FS @@ -141,8 +159,12 @@ struct proc_dir_entry proc_ircomm = { static void (*state[])( struct ircomm_cb *self, IRCOMM_EVENT event, struct sk_buff *skb) = { - ircomm_state_discovery, ircomm_state_idle, + + ircomm_state_discoverywait, + ircomm_state_queryparamwait, + ircomm_state_querylsapwait, + ircomm_state_waiti, ircomm_state_waitr, ircomm_state_conn, @@ -376,6 +398,146 @@ static void ircomm_accept_flow_indication( void *instance, void *sap, } + +/* + * ircomm_discovery_indication() + * Remote device is discovered, try query the remote IAS to see which + * device it is, and which services it has. + */ + +static void ircomm_discovery_indication(discovery_t *discovery) +{ + struct ircomm_cb *self; + + self = discovering_instance; + if(self == NULL) + return; + ASSERT(self->magic == IRCOMM_MAGIC, return;); + + self->daddr = discovery->daddr; + self->saddr = discovery->saddr; + + DEBUG( 0, __FUNCTION__"():daddr=%08x\n", self->daddr); + + ircomm_do_event(self, DISCOVERY_INDICATION, NULL); + return; +} + +/* + * ircomm_getvalue_confirm() + * handler for iriap_getvaluebyclass_request() + */ +static void ircomm_getvalue_confirm(int result, __u16 obj_id, + struct ias_value *value, void *priv) +{ + struct ircomm_cb *self = (struct ircomm_cb *) priv; + struct sk_buff *skb= NULL; + __u8 *frame; + __u8 servicetype = 0 ; + ASSERT( self != NULL, return;); + ASSERT( self->magic == IRCOMM_MAGIC, return;); + + /* Check if request succeeded */ + if (result != IAS_SUCCESS) { + DEBUG( 0, __FUNCTION__ "(), got NULL value!\n"); + ircomm_do_event(self, QUERYIAS_ERROR, NULL); + return; + } + + DEBUG(4, __FUNCTION__"():type(%d)\n", value->type); + + self->ias_type = value->type; + switch(value->type){ + case IAS_OCT_SEQ: + + DEBUG(4, __FUNCTION__"():got octet sequence:\n"); +#if 0 + { + int i; + for ( i=0;ilen;i++) + printk("%02x", + (__u8)(*(value->t.oct_seq + i))); + printk("\n"); + } +#endif + skb = dev_alloc_skb((value->len) + 2); + ASSERT(skb != NULL, ircomm_do_event(self, QUERYIAS_ERROR, NULL);return;); + frame = skb_put(skb,2); + /* MSB first */ + frame[0] = ( value->len >> 8 ) & 0xff; + frame[1] = value->len & 0xff; + + frame = skb_put(skb,value->len); + memcpy(frame, value->t.oct_seq, value->len); + ircomm_parse_tuples(self, skb, IAS_PARAM); + kfree_skb(skb); + + /* + * check if servicetype we want is available + */ + + DEBUG(0,__FUNCTION__"():peer capability is:\n"); + DEBUG(0,"3wire raw: %s\n", + ((self->peer_servicetype & THREE_WIRE_RAW) ? "yes":"no")); + DEBUG(0,"3wire : %s\n", + ((self->peer_servicetype & THREE_WIRE) ? "yes":"no")); + DEBUG(0,"9wire : %s\n", + ((self->peer_servicetype & NINE_WIRE) ? "yes":"no")); + DEBUG(0,"IEEE1284 : %s\n", + ((self->peer_servicetype & CENTRONICS) ? "yes":"no")); + + self->servicetype &= self->peer_servicetype; + if(!(self->servicetype)){ + DEBUG(0,__FUNCTION__"(): servicetype mismatch!\n"); + ircomm_do_event(self, QUERYIAS_ERROR, NULL); + break; + } + + /* + * then choose better one + */ + if(self->servicetype & THREE_WIRE_RAW) + servicetype = THREE_WIRE_RAW; + if(self->servicetype & THREE_WIRE) + servicetype = THREE_WIRE; + if(self->servicetype & NINE_WIRE) + servicetype = NINE_WIRE; + if(self->servicetype & CENTRONICS) + servicetype = CENTRONICS; + + self->servicetype = servicetype; + + /* enter next state */ + ircomm_do_event(self, GOT_PARAMETERS, NULL); + break; + + case IAS_INTEGER: + /* LsapSel seems to be sent to me */ + DEBUG(0, __FUNCTION__"():got lsapsel = %d\n", value->t.integer); + + if ( value->t.integer == -1){ + DEBUG( 0, __FUNCTION__"():invalid value!\n"); + ircomm_do_event(self, QUERYIAS_ERROR, NULL); + return; + } + self->dlsap = value->t.integer; + ircomm_do_event(self, GOT_LSAPSEL, NULL); + break; + + case IAS_MISSING: + DEBUG( 0, __FUNCTION__":got IAS_MISSING\n"); + ircomm_do_event(self, QUERYIAS_ERROR, NULL); + break; + + default: + DEBUG( 0, __FUNCTION__":got unknown (strange?)type!\n"); + ircomm_do_event(self, QUERYIAS_ERROR, NULL); + break; + } +} + + + /* * ---------------------------------------------------------------------- * Impl. of actions (descrived in section 7.4 of the reference) @@ -583,19 +745,6 @@ static void ircomm_next_state( struct ircomm_cb *self, IRCOMM_STATE state) } -/* - * we currently need dummy (discovering) state for debugging, - * which state is not defined in the reference. - */ - -static void ircomm_state_discovery( struct ircomm_cb *self, - IRCOMM_EVENT event, struct sk_buff *skb ) -{ - printk(KERN_ERR __FUNCTION__"():why call me? something is wrong..\n"); - if(skb) - dev_kfree_skb( skb); -} - /* * ircomm_state_idle @@ -607,8 +756,11 @@ static void ircomm_state_idle( struct ircomm_cb *self, IRCOMM_EVENT event, switch(event){ case IRCOMM_CONNECT_REQUEST: - ircomm_next_state(self, COMM_WAITI); - issue_connect_request( self, skb ); + /* ircomm_next_state(self, COMM_WAITI); */ + /* issue_connect_request( self, skb ); */ + + ircomm_next_state(self, COMM_DISCOVERY_WAIT); + start_discovering(self); break; case TTP_CONNECT_INDICATION: @@ -630,6 +782,121 @@ static void ircomm_state_idle( struct ircomm_cb *self, IRCOMM_EVENT event, } } +/* + * ircomm_state_discoverywait + */ +static void ircomm_state_discoverywait(struct ircomm_cb *self, IRCOMM_EVENT event, + struct sk_buff *skb ) +{ + switch(event){ + + case TTP_CONNECT_INDICATION: + + ircomm_next_state(self, COMM_WAITR); + queryias_done(self); + connect_indication( self, self->qos, skb); + break; + + case DISCOVERY_INDICATION: + ircomm_next_state(self, COMM_QUERYPARAM_WAIT); + query_parameters(self); + break; + + case IRCOMM_DISCONNECT_REQUEST: + ircomm_next_state(self, COMM_IDLE); + queryias_done(self); + break; + + case QUERYIAS_ERROR: + ircomm_next_state(self, COMM_IDLE); + disconnect_indication(self, NULL); + queryias_done(self); + break; + + default: + DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n", + event, ircommevent[event]); + } +} + +/* + * ircomm_state_queryparamwait + */ + +static void ircomm_state_queryparamwait(struct ircomm_cb *self, IRCOMM_EVENT event, + struct sk_buff *skb ) +{ + switch(event){ + + case TTP_CONNECT_INDICATION: + + ircomm_next_state(self, COMM_WAITR); + connect_indication( self, self->qos, skb); + break; + + case GOT_PARAMETERS: + + ircomm_next_state(self, COMM_QUERYLSAP_WAIT); + query_lsapsel( self ); + break; + + case IRCOMM_DISCONNECT_REQUEST: + ircomm_next_state(self, COMM_IDLE); + queryias_done(self); + break; + + case QUERYIAS_ERROR: + ircomm_next_state(self, COMM_IDLE); + disconnect_indication(self, NULL); + queryias_done(self); + break; + + default: + DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n", + event, ircommevent[event]); + } +} + +/* + * ircomm_state_querylsapwait + */ + +static void ircomm_state_querylsapwait(struct ircomm_cb *self, IRCOMM_EVENT event, + struct sk_buff *skb ) +{ + switch(event){ + + case TTP_CONNECT_INDICATION: + + ircomm_next_state(self, COMM_WAITR); + connect_indication( self, self->qos, skb); + break; + + case GOT_LSAPSEL: + + ircomm_next_state(self, COMM_WAITI); + queryias_done(self); + issue_connect_request( self, skb ); + break; + + case IRCOMM_DISCONNECT_REQUEST: + ircomm_next_state(self, COMM_IDLE); + queryias_done(self); + break; + + case QUERYIAS_ERROR: + ircomm_next_state(self, COMM_IDLE); + disconnect_indication(self, NULL); + queryias_done(self); + break; + + + default: + DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n", + event, ircommevent[event]); + } +} + /* * ircomm_state_waiti */ @@ -688,6 +955,7 @@ static void ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event, case IRCOMM_DISCONNECT_REQUEST: ircomm_next_state(self, COMM_IDLE); issue_disconnect_request(self, skb); + queryias_done(self); break; case TTP_DISCONNECT_INDICATION: @@ -695,6 +963,19 @@ static void ircomm_state_waitr(struct ircomm_cb *self, IRCOMM_EVENT event, disconnect_indication(self, skb); break; + case DISCOVERY_INDICATION: + DEBUG(0, __FUNCTION__"():DISCOVERY_INDICATION\n"); + queryias_done(self); + break; + case GOT_PARAMETERS: + DEBUG(0, __FUNCTION__"():GOT_PARAMETERS\n"); + queryias_done(self); + break; + case GOT_LSAPSEL: + DEBUG(0, __FUNCTION__"():GOT_LSAPSEL\n"); + queryias_done(self); + break; + /* case LMP_DISCONNECT_INDICATION: */ /* disconnect_indication(); */ /* ircomm_next_state(self, COMM_IDLE); */ @@ -732,11 +1013,26 @@ static void ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event, case IRCOMM_DISCONNECT_REQUEST: ircomm_next_state(self, COMM_IDLE); issue_disconnect_request(self, skb); + queryias_done(self); break; /* case LM_DISCONNECT_INDICATION: */ /* disconnect_indication(); */ /* ircomm_next_state(self, COMM_IDLE); */ /* break; */ + + case DISCOVERY_INDICATION: + DEBUG(0, __FUNCTION__"():DISCOVERY_INDICATION\n"); + queryias_done(self); + break; + case GOT_PARAMETERS: + DEBUG(0, __FUNCTION__"():GOT_PARAMETERS\n"); + queryias_done(self); + break; + case GOT_LSAPSEL: + DEBUG(0, __FUNCTION__"():GOT_LSAPSEL\n"); + queryias_done(self); + break; + default: DEBUG(0,"ircomm_state_conn:unknown event =%d(%s)\n", event, ircommevent[event]); @@ -744,6 +1040,7 @@ static void ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event, } + /* * ---------------------------------------------------------------------- * IrCOMM service interfaces and supporting functions @@ -751,172 +1048,97 @@ static void ircomm_state_conn(struct ircomm_cb *self, IRCOMM_EVENT event, * ---------------------------------------------------------------------- */ -int ircomm_query_ias_and_connect(struct ircomm_cb *self, __u8 servicetype) -{ - int retval=0; - __u16 hints; - - ASSERT( self != NULL, return -EFAULT;); - ASSERT( self->magic == IRCOMM_MAGIC, return -EFAULT;); - DEBUG(4,__FUNCTION__"():servicetype = %d\n",servicetype); +/* + * start_discovering() + * + * start discovering and enter DISCOVERY_WAIT state + */ - /* - * wait if another instance is discovering now - */ - if(discovering_instance){ - interruptible_sleep_on( &self->discovery_wait); - if(signal_pending(current)){ - return -EINTR; /* cought a signal */ - } - if(self->state == COMM_CONN) - return 0; /* got connected */ - } - ASSERT(discovering_instance == NULL, return -EFAULT;); - discovering_instance = self; +static void start_discovering(struct ircomm_cb *self) +{ + __u16 hints; + ASSERT( self != NULL, return;); + ASSERT( self->magic == IRCOMM_MAGIC, return;); + DEBUG(4,__FUNCTION__"():servicetype = %d\n",self->servicetype); - /* - * start discovering - */ + hints = irlmp_service_to_hint(S_COMM); DEBUG(0,__FUNCTION__"():start discovering..\n"); switch (ircomm_cs) { case 0: - skey = irlmp_register_service(hints); - ckey = irlmp_register_client(hints, ircomm_discovery_indication, + MOD_INC_USE_COUNT; + self->queryias_lock = 1; + discovering_instance = self; + self->skey = irlmp_register_service(hints); + self->ckey = irlmp_register_client(hints, ircomm_discovery_indication, NULL); break; case 1: /* client only */ + MOD_INC_USE_COUNT; + self->queryias_lock = 1; + discovering_instance = self; DEBUG( 0, __FUNCTION__"():client only mode\n"); - ckey = irlmp_register_client(hints, ircomm_discovery_indication, + self->ckey = irlmp_register_client(hints, ircomm_discovery_indication, NULL); break; case 2: /* server only */ default: DEBUG( 0, __FUNCTION__"():server only mode\n"); - skey = irlmp_register_service(hints); + self->skey = irlmp_register_service(hints); discovering_instance = NULL; - return 0; + break; } + + return; +} +/* + * queryias_done(self) + * + * called when discovery process got wrong results, completed, or terminated. + */ - /* - * waiting for discovery - */ - interruptible_sleep_on( &self->discovery_wait); - if(signal_pending(current)){ - retval = -EINTR; goto bailout; /* cought a signal */ +static void queryias_done(struct ircomm_cb *self) +{ + DEBUG(0, __FUNCTION__"():\n"); + if(self->queryias_lock){ + self->queryias_lock = 0; + discovering_instance = NULL; + MOD_DEC_USE_COUNT; + irlmp_unregister_client(self->ckey); } - if(self->state == COMM_CONN) - goto bailout; /* got connected */ + if(ircomm_cs != 1) + irlmp_unregister_service(self->skey); + return; +} - /* - * query Parameters field of IAS and waiting for answer - */ - self->servicetype = 0; + +static void query_parameters(struct ircomm_cb *self) +{ + DEBUG(0, __FUNCTION__"():querying IAS: Parameters..\n"); iriap_getvaluebyclass_request( "IrDA:IrCOMM", "Parameters", self->saddr, self->daddr, ircomm_getvalue_confirm, self ); - - interruptible_sleep_on( &self->ias_wait); - if(signal_pending(current)){ - retval = -EINTR; goto bailout; /* cought a signal */ - } - if(self->state == COMM_CONN) - goto bailout; /* got connected */ +} - /* really got Parameters field? */ - if(self->ias_type != IAS_OCT_SEQ){ - retval = -EFAULT; - goto bailout; - } - - /* - * check if servicetype we want is available - */ - self->peer_cap = self->servicetype; - - DEBUG(0,__FUNCTION__"():peer capability is:\n"); - DEBUG(0,"3wire raw: %s\n",((self->servicetype & THREE_WIRE_RAW) ? "yes":"no")); - DEBUG(0,"3wire : %s\n",((self->servicetype & THREE_WIRE) ? "yes":"no")); - DEBUG(0,"9wire : %s\n",((self->servicetype & NINE_WIRE) ? "yes":"no")); - DEBUG(0,"IEEE1284 : %s\n",((self->servicetype & CENTRONICS) ? "yes":"no")); - - self->servicetype &= servicetype; - if(!(self->servicetype)){ - retval = -ENODEV; - goto bailout; - } - - /* - * then choose better one - */ +static void query_lsapsel(struct ircomm_cb * self) +{ + DEBUG(0, __FUNCTION__"():querying IAS: Lsapsel...\n"); - if(self->servicetype & THREE_WIRE_RAW) - servicetype = THREE_WIRE_RAW; - if(self->servicetype & THREE_WIRE) - servicetype = THREE_WIRE; - if(self->servicetype & NINE_WIRE) - servicetype = NINE_WIRE; - if(self->servicetype & CENTRONICS) - servicetype = CENTRONICS; - - self->servicetype = servicetype; -#if 1 - /* - * waiting for discovery again - */ - interruptible_sleep_on( &self->discovery_wait); - if(signal_pending(current)){ - retval = -EINTR; goto bailout; /* cought a signal */ - } - if(self->state == COMM_CONN) - goto bailout; /* got connected */ -#endif - /* - * query lsapsel field and waiting for answer - */ - query_lsapsel(self); - interruptible_sleep_on( &self->ias_wait); - if(signal_pending(current)){ - retval = -EINTR; goto bailout; /* cought a signal */ - } - if(self->state == COMM_CONN) - goto bailout; /* got connected */ - - /* really got Lsapsel field? */ - if(self->ias_type != IAS_INTEGER){ - retval = -EFAULT; - goto bailout; - } -#if 1 - /* - * waiting for discovery again... - */ - interruptible_sleep_on( &self->discovery_wait); - if(signal_pending(current)){ - retval = -EINTR; goto bailout; /* cought a signal */ + if (!(self->servicetype & THREE_WIRE_RAW)) { + iriap_getvaluebyclass_request( + "IrDA:IrCOMM", "IrDA:TinyTP:LsapSel", + self->saddr, self->daddr, + ircomm_getvalue_confirm, self ); + } else { + DEBUG(0, __FUNCTION__ "THREE_WIRE_RAW is not implemented!\n"); } - if(self->state == COMM_CONN) - goto bailout; /* got connected */ -#endif - - /* succeed! ready to connect */ - discovering_instance = NULL; - ircomm_connect_request(self); - return 0; - - bailout: - /* failed. not ready to connect */ - discovering_instance = NULL; - irlmp_unregister_service(skey); - irlmp_unregister_client(ckey); - return retval; } /* @@ -926,7 +1148,7 @@ int ircomm_query_ias_and_connect(struct ircomm_cb *self, __u8 servicetype) */ -void ircomm_connect_request(struct ircomm_cb *self) +void ircomm_connect_request(struct ircomm_cb *self, __u8 servicetype) { /* * TODO:build a packet which contains "initial control parameters" @@ -939,7 +1161,8 @@ void ircomm_connect_request(struct ircomm_cb *self) DEBUG(0, __FUNCTION__"():sending connect_request...\n"); - ircomm_control_request(self, SERVICETYPE); /*servictype*/ + self->servicetype= servicetype; + /* ircomm_control_request(self, SERVICETYPE); */ /*servictype*/ self->maxsdusize = SAR_DISABLE; ircomm_do_event( self, IRCOMM_CONNECT_REQUEST, NULL); @@ -986,6 +1209,7 @@ void ircomm_disconnect_request(struct ircomm_cb *self, ASSERT( self->magic == IRCOMM_MAGIC, return;); DEBUG(0,__FUNCTION__"()\n"); +#if 0 /* unregister layer */ switch (ircomm_cs) { case 1: /* client only */ @@ -1001,6 +1225,7 @@ void ircomm_disconnect_request(struct ircomm_cb *self, irlmp_unregister_service(skey); break; } +#endif self->disconnect_priority = priority; if(priority != P_HIGH) @@ -1353,7 +1578,7 @@ void ircomm_parse_tuples(struct ircomm_cb *self, struct sk_buff *skb, int type) break; case SERVICETYPE: - self->servicetype = data[2]; + self->peer_servicetype = data[2]; break; case PORT_TYPE: @@ -1482,128 +1707,6 @@ void ircomm_parse_tuples(struct ircomm_cb *self, struct sk_buff *skb, int type) -/* - * ircomm_getvalue_confirm() - * handler for iriap_getvaluebyclass_request() - */ - -static void ircomm_getvalue_confirm( __u16 obj_id, struct ias_value *value, - void *priv) -{ - struct ircomm_cb *self = (struct ircomm_cb *) priv; - struct sk_buff *skb= NULL; - __u8 *frame; - ASSERT( self != NULL, return;); - ASSERT( self->magic == IRCOMM_MAGIC, return;); - - /* Check if request succeeded */ - if ( !value) { - DEBUG( 0, __FUNCTION__ "(), got NULL value!\n"); - return; - } - - DEBUG(4, __FUNCTION__"():type(%d)\n", value->type); - - self->ias_type = value->type; - switch(value->type){ - case IAS_OCT_SEQ: - - DEBUG(4, __FUNCTION__"():got octet sequence:\n"); -#if 0 - { - int i; - for ( i=0;ilen;i++) - printk("%02x", - (__u8)(*(value->t.oct_seq + i))); - printk("\n"); - } -#endif - skb = dev_alloc_skb((value->len) + 2); - ASSERT(skb != NULL, return;); - frame = skb_put(skb,2); - /* MSB first */ - frame[0] = ( value->len >> 8 ) & 0xff; - frame[1] = value->len & 0xff; - - frame = skb_put(skb,value->len); - memcpy(frame, value->t.oct_seq, value->len); - ircomm_parse_tuples(self, skb, IAS_PARAM); - kfree_skb(skb); - - wake_up_interruptible( &self->ias_wait); - break; - - case IAS_INTEGER: - /* LsapSel seems to be sent to me */ - DEBUG(0, __FUNCTION__"():got lsapsel = %d\n", value->t.integer); - - if ( value->t.integer == -1){ - DEBUG( 0, __FUNCTION__"():invalid value!\n"); - return; - } - - if(self->state == COMM_IDLE){ - self->dlsap = value->t.integer; - - wake_up_interruptible( &self->ias_wait); - } - break; - - case IAS_MISSING: - DEBUG( 0, __FUNCTION__":got IAS_MISSING\n"); - break; - - default: - DEBUG( 0, __FUNCTION__":got unknown (strange?)type!\n"); - break; - } -} - - -/* - * query_lsapsel() - * quering the remote IAS to ask which - * dlsap we should use - */ - -static void query_lsapsel(struct ircomm_cb * self) -{ - DEBUG(0, __FUNCTION__"():querying IAS: Lsapsel...\n"); - - if (!(self->servicetype & THREE_WIRE_RAW)) { - iriap_getvaluebyclass_request( - "IrDA:IrCOMM", "IrDA:TinyTP:LsapSel", - self->saddr, self->daddr, - ircomm_getvalue_confirm, self ); - } else { - DEBUG(0, __FUNCTION__ "THREE_WIRE_RAW is not implemented!\n"); - } -} - -/* - * ircomm_discovery_indication() - * Remote device is discovered, try query the remote IAS to see which - * device it is, and which services it has. - */ - -static void ircomm_discovery_indication(discovery_t *discovery) -{ - struct ircomm_cb *self; - - self = discovering_instance; - ASSERT(self != NULL, return;); - ASSERT(self->magic == IRCOMM_MAGIC, return;); - - self->daddr = discovery->daddr; - self->saddr = discovery->saddr; - - DEBUG( 0, __FUNCTION__"():daddr=%08x\n", self->daddr); - - wake_up_interruptible( &self->discovery_wait); - return; -} - - struct ircomm_cb * ircomm_open_instance( struct notify_t client_notify) { int i; diff --git a/net/irda/ircomm/irvtd_driver.c b/net/irda/ircomm/irvtd_driver.c index 9e468ba90d9b..2df2fdd6015d 100644 --- a/net/irda/ircomm/irvtd_driver.c +++ b/net/irda/ircomm/irvtd_driver.c @@ -51,7 +51,7 @@ struct termios *irvtd_termios_locked[COMM_MAX_TTY]; static int irvtd_refcount; struct irvtd_cb **irvtd = NULL; -static char *revision_date = "Wed Mar 10 15:33:03 1999"; +static char *revision_date = "Sun Apr 18 17:31:53 1999"; /* @@ -74,6 +74,7 @@ void irvtd_stop(struct tty_struct *tty); void irvtd_start(struct tty_struct *tty); void irvtd_hangup(struct tty_struct *tty); void irvtd_flush_buffer(struct tty_struct *tty); +void irvtd_flush_chars(struct tty_struct *tty); static void change_speed(struct irvtd_cb *driver); static void irvtd_write_to_tty( struct irvtd_cb *); @@ -90,14 +91,6 @@ static int irvtd_read_proc(char *buf, char **start, off_t offset, int len, int *eof, void *unused); -/* - * ---------------------------------------------------------------------- - * - * - - * ---------------------------------------------------------------------- - */ - /* ********************************************************************** * @@ -122,11 +115,13 @@ static void irvtd_write_to_tty( struct irvtd_cb *driver) struct sk_buff *skb; struct tty_struct *tty = driver->tty; + if(driver->rx_disable) + return; + skb = skb_dequeue(&driver->rxbuff); if(skb == NULL) return; /* there's nothing */ - /* * we should parse controlchannel field here. * (see process_data() in ircomm.c) @@ -244,6 +239,7 @@ static int irvtd_receive_data(void *instance, void *sap, struct sk_buff *skb) irttp_flow_request(driver->comm->tsap, FLOW_STOP); driver->ttp_stoprx = 1; } + irvtd_write_to_tty(driver); return 0; } @@ -268,7 +264,7 @@ static void irvtd_start_timer( struct irvtd_cb *driver) driver->timer.data = (unsigned long) driver; driver->timer.function = &irvtd_timer_expired; - driver->timer.expires = jiffies + (HZ / 20); /* 50msec */ + driver->timer.expires = jiffies + (HZ / 5); /* 200msec */ add_timer( &driver->timer); } @@ -282,13 +278,10 @@ static void irvtd_timer_expired(unsigned long data) ASSERT(driver->magic == IRVTD_MAGIC,return;); DEBUG(4, __FUNCTION__"()\n"); - if(!(driver->tty->hw_stopped) && !(driver->tx_disable)) - irvtd_send_data_request(driver); + irvtd_send_data_request(driver); + + irvtd_write_to_tty(driver); - if(!(driver->rx_disable)){ - irvtd_write_to_tty(driver); - } - /* start our timer again and again */ irvtd_start_timer(driver); } @@ -302,6 +295,8 @@ static void irvtd_send_data_request(struct irvtd_cb *driver) ASSERT(skb != NULL,return;); DEBUG(4, __FUNCTION__"()\n"); + if(driver->tty->hw_stopped || driver->tx_disable) + return; if(!skb->len) return; /* no data to send */ @@ -315,7 +310,7 @@ static void irvtd_send_data_request(struct irvtd_cb *driver) } #endif - DEBUG(4, __FUNCTION__"():sending %d bytes\n",(int)skb->len ); + DEBUG(1, __FUNCTION__"():sending %d octets\n",(int)skb->len ); driver->icount.tx += skb->len; err = ircomm_data_request(driver->comm, driver->txbuff); if (err){ @@ -327,7 +322,7 @@ static void irvtd_send_data_request(struct irvtd_cb *driver) /* allocate a new frame */ skb = driver->txbuff = dev_alloc_skb(driver->comm->max_txbuff_size); if (skb == NULL){ - printk(__FUNCTION__"():flush_txbuff():alloc_skb failed!\n"); + printk(__FUNCTION__"():alloc_skb failed!\n"); } else { skb_reserve(skb, COMM_HEADER_SIZE); } @@ -369,10 +364,11 @@ void irvtd_connect_confirm(void *instance, void *sap, struct qos_info *qos, /* * sending initial control parameters here */ -#if 1 if(driver->comm->servicetype == THREE_WIRE_RAW) return; /* do nothing */ + driver->comm->dte |= (MCR_DTR | MCR_RTS | DELTA_DTR | DELTA_RTS); + ircomm_control_request(driver->comm, SERVICETYPE); ircomm_control_request(driver->comm, DATA_RATE); ircomm_control_request(driver->comm, DATA_FORMAT); @@ -389,7 +385,6 @@ void irvtd_connect_confirm(void *instance, void *sap, struct qos_info *qos, break; default: } -#endif driver->tx_disable = 0; wake_up_interruptible(&driver->open_wait); @@ -414,15 +409,27 @@ void irvtd_connect_indication(void *instance, void *sap, struct qos_info *qos, DEBUG(4,"irvtd_connect_indication:sending connect_response...\n"); - /*TODO: connect_response should send initialcontrolparameters! TH*/ - ircomm_connect_response(comm, NULL, SAR_DISABLE ); + driver->tx_disable = 0; + /* - * set default value + * send initial control parameters */ + if(driver->comm->servicetype == THREE_WIRE_RAW) + return; /* do nothing */ + + driver->comm->dte |= (MCR_DTR | MCR_RTS | DELTA_DTR | DELTA_RTS); + + switch(driver->comm->servicetype){ + case NINE_WIRE: + ircomm_control_request(driver->comm, DTELINE_STATE); + break; + default: + } + + driver->msr |= (MSR_DCD|MSR_RI|MSR_DSR|MSR_CTS); - driver->tx_disable = 0; wake_up_interruptible(&driver->open_wait); } @@ -445,7 +452,13 @@ void irvtd_disconnect_indication(void *instance, void *sap , LM_REASON reason, DEBUG(4,"irvtd_disconnect_indication:\n"); driver->tx_disable = 1; - driver->disconnect_pend = 1; + if(skb_queue_empty(&driver->rxbuff)){ + /* disconnect */ + driver->rx_disable = 1; + tty_hangup(driver->tty); + } else { + driver->disconnect_pend = 1; + } } /* @@ -559,6 +572,12 @@ void irvtd_control_indication(void *instance, void *sap, IRCOMM_CMD cmd) } break; + case FLOW_CONTROL: + case DATA_RATE: + case XON_XOFF_CHAR: + case DTELINE_STATE: + /* (maybe) nothing to do */ + break; default: DEBUG(0,__FUNCTION__"():PI = 0x%02x is not implemented\n", (int)driver->comm->pi); @@ -624,19 +643,6 @@ static int irvtd_block_til_ready(struct tty_struct *tty, struct file * filp, while (1) { current->state = TASK_INTERRUPTIBLE; - if (driver->comm->state == COMM_CONN){ - /* - * signal DTR and RTS - */ - driver->comm->dte = driver->mcr |= (MCR_DTR | - MCR_RTS | - DELTA_DTR| - DELTA_RTS ); - - ircomm_control_request(driver->comm, DTELINE_STATE); - } - - if (tty_hung_up_p(filp) || !(driver->flags & ASYNC_INITIALIZED)) { #ifdef DO_RESTART @@ -755,7 +761,6 @@ static void change_speed(struct irvtd_cb *driver) static int irvtd_startup(struct irvtd_cb *driver) { - int retval = 0; struct ias_object* obj; struct notify_t irvtd_notify; @@ -805,17 +810,13 @@ static int irvtd_startup(struct irvtd_cb *driver) irias_insert_object( obj); driver->flags |= ASYNC_INITIALIZED; + /* * discover a peer device * TODO: other servicetype(i.e. 3wire,3wireraw) support */ - retval = ircomm_query_ias_and_connect(driver->comm, NINE_WIRE); - if(retval){ - DEBUG(0, __FUNCTION__"(): ircomm_query_ias returns %d\n", - retval); - return retval; - } - + ircomm_connect_request(driver->comm, NINE_WIRE); + /* * TODO:we have to initialize control-channel here! * i.e.set something into RTS,CTS and so on.... @@ -931,7 +932,7 @@ static void irvtd_wait_until_sent(struct tty_struct *tty, int timeout) ASSERT(driver->magic == IRVTD_MAGIC, return;); ASSERT(driver->comm != NULL, return;); - DEBUG(0, __FUNCTION__"():\n"); + DEBUG(1, __FUNCTION__"():\n"); if(!tty->closing) return; /* nothing to do */ @@ -944,7 +945,7 @@ static void irvtd_wait_until_sent(struct tty_struct *tty, int timeout) orig_jiffies = jiffies; while (driver->comm->tsap->disconnect_pend) { - DEBUG(0, __FUNCTION__"():wait..\n"); + DEBUG(1, __FUNCTION__"():wait..\n"); current->state = TASK_INTERRUPTIBLE; current->counter = 0; /* make us low-priority */ schedule_timeout(HZ); /* 1sec */ @@ -964,7 +965,7 @@ static void irvtd_shutdown(struct irvtd_cb * driver) if (!(driver->flags & ASYNC_INITIALIZED)) return; - DEBUG(0,__FUNCTION__"()\n"); + DEBUG(1,__FUNCTION__"()\n"); /* * This comment is written in serial.c: @@ -1017,7 +1018,7 @@ void irvtd_close(struct tty_struct * tty, struct file * filp) int line; unsigned long flags; - DEBUG(0, __FUNCTION__"():refcount= %d\n",irvtd_refcount); + DEBUG(1, __FUNCTION__"():refcount= %d\n",irvtd_refcount); ASSERT(driver != NULL, return;); ASSERT(driver->magic == IRVTD_MAGIC, return;); @@ -1030,7 +1031,7 @@ void irvtd_close(struct tty_struct * tty, struct file * filp) * upper tty layer caught a HUP signal and called irvtd_hangup() * before. so we do nothing here. */ - DEBUG(0, __FUNCTION__"():tty_hung_up_p.\n"); + DEBUG(1, __FUNCTION__"():tty_hung_up_p.\n"); MOD_DEC_USE_COUNT; restore_flags(flags); return; @@ -1142,7 +1143,6 @@ int irvtd_write(struct tty_struct * tty, int from_user, DEBUG(4, __FUNCTION__"()\n"); - save_flags(flags); while(1){ cli(); @@ -1164,11 +1164,23 @@ int irvtd_write(struct tty_struct * tty, int from_user, wrote += c; count -= c; buf += c; + irvtd_send_data_request(driver); } restore_flags(flags); return (wrote); } +void irvtd_flush_chars(struct tty_struct *tty) +{ + struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data; + ASSERT( driver != NULL, return;); + ASSERT( driver->magic == IRVTD_MAGIC, return;); + + DEBUG(4, __FUNCTION__"()\n"); + irvtd_send_data_request(driver); +} + + /* * Function irvtd_put_char (tty, ch) * @@ -1606,14 +1618,14 @@ void irvtd_set_termios(struct tty_struct *tty, struct termios * old_termios){ static void irvtd_send_xchar(struct tty_struct *tty, char ch){ - DEBUG(0, __FUNCTION__"():\n"); + DEBUG(1, __FUNCTION__"():\n"); irvtd_put_char(tty, ch); } void irvtd_throttle(struct tty_struct *tty){ struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data; - DEBUG(0, "irvtd_throttle:\n"); + DEBUG(1, "irvtd_throttle:\n"); if (I_IXOFF(tty)) irvtd_put_char(tty, STOP_CHAR(tty)); @@ -1628,7 +1640,7 @@ void irvtd_throttle(struct tty_struct *tty){ void irvtd_unthrottle(struct tty_struct *tty){ struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data; - DEBUG(0, "irvtd_unthrottle:\n"); + DEBUG(1, "irvtd_unthrottle:\n"); if (I_IXOFF(tty)) irvtd_put_char(tty, START_CHAR(tty)); @@ -1760,7 +1772,7 @@ int irvtd_register_ttydriver(void){ irvtd_drv.close = irvtd_close; irvtd_drv.write = irvtd_write; irvtd_drv.put_char = irvtd_put_char; - irvtd_drv.flush_chars = NULL; + irvtd_drv.flush_chars = irvtd_flush_chars; irvtd_drv.write_room = irvtd_write_room; irvtd_drv.chars_in_buffer = irvtd_chars_in_buffer; irvtd_drv.flush_buffer = irvtd_flush_buffer; @@ -1916,7 +1928,7 @@ __initfunc(int irvtd_init(void)) memset( irvtd[i], 0, sizeof(struct irvtd_cb)); irvtd[i]->magic = IRVTD_MAGIC; irvtd[i]->line = i; - irvtd[i]->closing_wait = 30*HZ ; + irvtd[i]->closing_wait = 10*HZ ; irvtd[i]->close_delay = 5*HZ/10 ; } diff --git a/net/irda/irda_device.c b/net/irda/irda_device.c index eaf9f2cd4bce..cf9e6ea3441d 100644 --- a/net/irda/irda_device.c +++ b/net/irda/irda_device.c @@ -1,12 +1,12 @@ /********************************************************************* * * Filename: irda_device.c - * Version: 0.4 + * Version: 0.5 * Description: Abstract device driver layer and helper functions * Status: Experimental. * Author: Dag Brattli * Created at: Wed Sep 2 20:22:08 1998 - * Modified at: Wed Apr 7 17:16:54 1999 + * Modified at: Wed Apr 21 09:48:19 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli, All Rights Reserved. @@ -129,26 +129,28 @@ int irda_device_open(struct irda_device *self, char *name, void *priv) /* Allocate memory if needed */ if (self->rx_buff.truesize > 0) { - self->rx_buff.data = ( __u8 *) kmalloc(self->rx_buff.truesize, + self->rx_buff.head = ( __u8 *) kmalloc(self->rx_buff.truesize, self->rx_buff.flags); - if (self->rx_buff.data == NULL) + if (self->rx_buff.head == NULL) return -ENOMEM; - memset(self->rx_buff.data, 0, self->rx_buff.truesize); + memset(self->rx_buff.head, 0, self->rx_buff.truesize); } if (self->tx_buff.truesize > 0) { - self->tx_buff.data = ( __u8 *) kmalloc(self->tx_buff.truesize, + self->tx_buff.head = ( __u8 *) kmalloc(self->tx_buff.truesize, self->tx_buff.flags); - if (self->tx_buff.data == NULL) + if (self->tx_buff.head == NULL) return -ENOMEM; - memset(self->tx_buff.data, 0, self->tx_buff.truesize); + memset(self->tx_buff.head, 0, self->tx_buff.truesize); } self->magic = IRDA_DEVICE_MAGIC; self->rx_buff.in_frame = FALSE; self->rx_buff.state = OUTSIDE_FRAME; + self->tx_buff.data = self->tx_buff.head; + self->rx_buff.data = self->rx_buff.head; /* Initialize timers */ init_timer(&self->media_busy_timer); @@ -184,7 +186,7 @@ int irda_device_open(struct irda_device *self, char *name, void *priv) /* Open network device */ dev_open(&self->netdev); - printk("IrDA device %s registered.\n", self->name); + MESSAGE("IrDA: Registred device %s\n", self->name); irda_device_set_media_busy(self, FALSE); @@ -197,8 +199,6 @@ int irda_device_open(struct irda_device *self, char *name, void *priv) /* It's now safe to initilize the saddr */ memcpy(self->netdev.dev_addr, &self->irlap->saddr, 4); - DEBUG(4, __FUNCTION__ "()->\n"); - return 0; } @@ -226,11 +226,11 @@ void __irda_device_close(struct irda_device *self) /* Stop timers */ del_timer(&self->media_busy_timer); - if (self->tx_buff.data) - kfree(self->tx_buff.data); + if (self->tx_buff.head) + kfree(self->tx_buff.head); - if (self->rx_buff.data) - kfree(self->rx_buff.data); + if (self->rx_buff.head) + kfree(self->rx_buff.head); self->magic = 0; } @@ -462,26 +462,6 @@ int irda_device_txqueue_empty( struct irda_device *self) return TRUE; } -/* - * Function irda_get_mtt (skb) - * - * Utility function for getting the minimum turnaround time out of - * the skb, where it has been hidden in the cb field. - */ -inline unsigned short irda_get_mtt(struct sk_buff *skb) -{ - unsigned short mtt; - - if (((struct irlap_skb_cb *)(skb->cb))->magic != LAP_MAGIC) - mtt = 10000; - else - mtt = ((struct irlap_skb_cb *)(skb->cb))->mtt; - - ASSERT(mtt <= 10000, return 10000;); - - return mtt; -} - /* * Function setup_dma (idev, buffer, count, mode) * @@ -561,7 +541,6 @@ int irda_device_proc_read(char *buf, char **start, off_t offset, int len, self->description); len += irda_device_print_flags(self, buf+len); - len += sprintf(buf+len, "\tbps\tmaxtt\tdsize\twinsize\taddbofs\tmintt\tldisc\n"); len += sprintf(buf+len, "\t%d\t", diff --git a/net/irda/iriap.c b/net/irda/iriap.c index d0264377920e..b87ccbd02814 100644 --- a/net/irda/iriap.c +++ b/net/irda/iriap.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Thu Aug 21 00:02:07 1997 - * Modified at: Tue Mar 23 19:38:46 1999 + * Modified at: Fri Apr 23 09:57:12 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli , @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -172,6 +173,7 @@ struct iriap_cb *iriap_open( __u8 slsap_sel, int mode) DEBUG( 0, "iriap_open: Unable to allocated LSAP!\n"); return NULL; } + slsap_sel = lsap->slsap_sel; DEBUG( 4, __FUNCTION__ "(), source LSAP sel=%02x\n", slsap_sel); self->magic = IAS_MAGIC; @@ -179,7 +181,7 @@ struct iriap_cb *iriap_open( __u8 slsap_sel, int mode) self->slsap_sel = slsap_sel; self->mode = mode; - /* init_timer( &self->watchdog_timer); */ + init_timer( &self->watchdog_timer); hashbin_insert( iriap, (QUEUE*) self, slsap_sel, NULL); @@ -204,7 +206,7 @@ static void __iriap_close( struct iriap_cb *self) ASSERT( self != NULL, return;); ASSERT( self->magic == IAS_MAGIC, return;); - /* del_timer( &self->watchdog_timer); */ + del_timer( &self->watchdog_timer); self->magic = 0; @@ -258,7 +260,7 @@ static void iriap_disconnect_indication( void *instance, void *sap, ASSERT( iriap != NULL, return;); - /* del_timer( &self->watchdog_timer); */ + del_timer( &self->watchdog_timer); if ( self->mode == IAS_CLIENT) { DEBUG( 4, __FUNCTION__ "(), disconnect as client\n"); @@ -267,8 +269,8 @@ static void iriap_disconnect_indication( void *instance, void *sap, * Inform service user that the request failed by sending * it a NULL value. */ - if ( self->confirm) - self->confirm( 0, NULL, self->priv); + if (self->confirm) + self->confirm(IAS_DISCONNECT, 0, NULL, self->priv); iriap_do_client_event( self, IAP_LM_DISCONNECT_INDICATION, @@ -348,9 +350,9 @@ void iriap_getvalue(void) * Retreive all values from attribute in all objects with given class * name */ -void iriap_getvaluebyclass_request( char *name, char *attr, - __u32 saddr, __u32 daddr, - CONFIRM_CALLBACK callback, void *priv) +void iriap_getvaluebyclass_request(char *name, char *attr, + __u32 saddr, __u32 daddr, + CONFIRM_CALLBACK callback, void *priv) { struct sk_buff *skb; struct iriap_cb *self; @@ -358,9 +360,9 @@ void iriap_getvaluebyclass_request( char *name, char *attr, int name_len, attr_len; __u8 slsap = LSAP_ANY; /* Source LSAP to use */ - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - self = iriap_open( slsap, IAS_CLIENT); + self = iriap_open(slsap, IAS_CLIENT); if (!self) return; @@ -376,29 +378,29 @@ void iriap_getvaluebyclass_request( char *name, char *attr, */ self->operation = GET_VALUE_BY_CLASS; - /* Give ourselves 7 secs to finish this operation */ - /* iriap_start_watchdog_timer( self, 700); */ + /* Give ourselves 10 secs to finish this operation */ + iriap_start_watchdog_timer(self, 10*HZ); skb = dev_alloc_skb( 64); if (!skb) return; - name_len = strlen( name); - attr_len = strlen( attr); + name_len = strlen(name); + attr_len = strlen(attr); /* Reserve space for MUX and LAP header */ - skb_reserve( skb, LMP_CONTROL_HEADER+LAP_HEADER); - skb_put( skb, 3+name_len+attr_len); + skb_reserve(skb, LMP_CONTROL_HEADER+LAP_HEADER); + skb_put(skb, 3+name_len+attr_len); frame = skb->data; /* Build frame */ frame[0] = IAP_LST | GET_VALUE_BY_CLASS; frame[1] = name_len; /* Insert length of name */ - memcpy( frame+2, name, name_len); /* Insert name */ + memcpy(frame+2, name, name_len); /* Insert name */ frame[2+name_len] = attr_len; /* Insert length of attr */ - memcpy( frame+3+name_len, attr, attr_len); /* Insert attr */ + memcpy(frame+3+name_len, attr, attr_len); /* Insert attr */ - iriap_do_client_event( self, IAP_CALL_REQUEST_GVBC, skb); + iriap_do_client_event(self, IAP_CALL_REQUEST_GVBC, skb); } /* @@ -415,7 +417,6 @@ void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb) int charset; __u32 value_len; __u32 tmp_cpu32; - __u16 tmp_cpu16; __u16 obj_id; __u16 len; __u8 type; @@ -430,14 +431,14 @@ void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb) n = 2; /* Get length, MSB first */ - memcpy(&len, fp+n, 2); n += 2; - be16_to_cpus(&len); + len = be16_to_cpu(get_unaligned((__u16 *)(fp+n))); n += 2; DEBUG(4, __FUNCTION__ "(), len=%d\n", len); /* Get object ID, MSB first */ - memcpy(&obj_id, fp+n, 2); n += 2; - be16_to_cpus(&obj_id); + obj_id = be16_to_cpu(get_unaligned((__u16 *)(fp+n))); n += 2; +/* memcpy(&obj_id, fp+n, 2); n += 2; */ +/* be16_to_cpus(&obj_id); */ type = fp[n++]; DEBUG( 4, __FUNCTION__ "(), Value type = %d\n", type); @@ -484,9 +485,8 @@ void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb) value = irias_new_string_value(fp+n); break; case IAS_OCT_SEQ: - memcpy(&tmp_cpu16, fp+n, 2); n += 2; - be16_to_cpus(&tmp_cpu16); - value_len = tmp_cpu16; + value_len = be16_to_cpu(get_unaligned((__u16 *)(fp+n))); + n += 2; /* FIXME:should be 1024, but.... */ DEBUG(0, __FUNCTION__ "():octet sequence:len=%d\n", value_len); @@ -499,11 +499,11 @@ void iriap_getvaluebyclass_confirm(struct iriap_cb *self, struct sk_buff *skb) break; } - if (self->confirm) - self->confirm(obj_id, value, self->priv); - /* Finished, close connection! */ iriap_disconnect_request(self); + + if (self->confirm) + self->confirm(IAS_SUCCESS, obj_id, value, self->priv); } /* @@ -550,7 +550,7 @@ void iriap_getvaluebyclass_response(struct iriap_cb *self, __u16 obj_id, fp[n++] = ret_code; /* Insert list length (MSB first) */ - tmp_be16 = __constant_htons( 0x0001); + tmp_be16 = __constant_htons(0x0001); memcpy(fp+n, &tmp_be16, 2); n += 2; /* Insert object identifier ( MSB first) */ @@ -703,17 +703,17 @@ void iriap_connect_confirm(void *instance, void *sap, struct qos_info *qos, { struct iriap_cb *self; - self = ( struct iriap_cb *) instance; + self = (struct iriap_cb *) instance; - ASSERT( self != NULL, return;); - ASSERT( self->magic == IAS_MAGIC, return;); - ASSERT( userdata != NULL, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == IAS_MAGIC, return;); + ASSERT(userdata != NULL, return;); - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); /* del_timer( &self->watchdog_timer); */ - iriap_do_client_event( self, IAP_LM_CONNECT_CONFIRM, userdata); + iriap_do_client_event(self, IAP_LM_CONNECT_CONFIRM, userdata); } /* @@ -778,7 +778,7 @@ static int iriap_data_indication(void *instance, void *sap, } if (~opcode & IAP_ACK) { - DEBUG(0, __FUNCTION__ "() Got ack frame!\n"); + DEBUG(2, __FUNCTION__ "() Got ack frame!\n"); /* return; */ } @@ -797,9 +797,21 @@ static int iriap_data_indication(void *instance, void *sap, break; case IAS_CLASS_UNKNOWN: printk(KERN_WARNING "IrIAP No such class!\n"); + /* Finished, close connection! */ + iriap_disconnect_request(self); + + if (self->confirm) + self->confirm(IAS_CLASS_UNKNOWN, 0, NULL, + self->priv); break; case IAS_ATTRIB_UNKNOWN: printk(KERN_WARNING "IrIAP No such attribute!\n"); + /* Finished, close connection! */ + iriap_disconnect_request(self); + + if (self->confirm) + self->confirm(IAS_CLASS_UNKNOWN, 0, NULL, + self->priv); break; } iriap_do_call_event( self, IAP_RECV_F_LST, skb); @@ -854,18 +866,20 @@ void iriap_call_indication( struct iriap_cb *self, struct sk_buff *skb) } } +/* + * Function iriap_watchdog_timer_expired (data) + * + * + * + */ void iriap_watchdog_timer_expired( unsigned long data) { struct iriap_cb *self = ( struct iriap_cb *) data; - DEBUG( 0, __FUNCTION__ "()\n"); - - return; - - ASSERT( self != NULL, return;); - ASSERT( self->magic == IAS_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == IAS_MAGIC, return;); - DEBUG( 0, __FUNCTION__ "() Timeout! closing myself!\n"); + DEBUG(0, __FUNCTION__ "() Timeout! closing myself!\n"); iriap_close( self); } diff --git a/net/irda/irlan/irlan_client.c b/net/irda/irlan/irlan_client.c index d679d86e3511..f2f8271cf5a0 100644 --- a/net/irda/irlan/irlan_client.c +++ b/net/irda/irlan/irlan_client.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sun Aug 31 20:14:37 1997 - * Modified at: Wed Apr 7 16:56:35 1999 + * Modified at: Thu Apr 22 23:03:55 1999 * Modified by: Dag Brattli * Sources: skeleton.c by Donald Becker * slip.c by Laurence Culhane, @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -106,7 +105,7 @@ void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr) { struct irmanager_event mgr_event; - DEBUG(2, __FUNCTION__ "()\n"); + DEBUG(0, __FUNCTION__ "()\n"); ASSERT(self != NULL, return;); ASSERT(self->magic == IRLAN_MAGIC, return;); @@ -122,8 +121,8 @@ void irlan_client_wakeup(struct irlan_cb *self, __u32 saddr, __u32 daddr) if (self->dev.start) { /* Open TSAPs */ irlan_client_open_ctrl_tsap(self); - irlan_provider_open_ctrl_tsap(self); - irlan_open_data_tsap(self); + irlan_provider_open_ctrl_tsap(self); + irlan_open_data_tsap(self); irlan_do_client_event(self, IRLAN_DISCOVERY_INDICATION, NULL); } else if (self->notify_irmanager) { @@ -162,7 +161,7 @@ void irlan_client_discovery_indication(discovery_t *discovery) struct irlan_cb *self, *entry; __u32 saddr, daddr; - DEBUG(2, __FUNCTION__"()\n"); + DEBUG(0, __FUNCTION__"()\n"); ASSERT(irlan != NULL, return;); ASSERT(discovery != NULL, return;); @@ -171,8 +170,7 @@ void irlan_client_discovery_indication(discovery_t *discovery) daddr = discovery->daddr; /* - * Check if we already have an instance for dealing with this - * provider. + * Check if we already dealing with this provider. */ self = (struct irlan_cb *) hashbin_find(irlan, daddr, NULL); if (self) { @@ -190,7 +188,7 @@ void irlan_client_discovery_indication(discovery_t *discovery) */ self = hashbin_find(irlan, DEV_ADDR_ANY, NULL); if (self) { - DEBUG(2, __FUNCTION__ "(), Found instance with DEV_ADDR_ANY!\n"); + DEBUG(0, __FUNCTION__ "(), Found instance with DEV_ADDR_ANY!\n"); /* * Rehash instance, now we have a client (daddr) to serve. */ @@ -200,27 +198,16 @@ void irlan_client_discovery_indication(discovery_t *discovery) self->daddr = daddr; self->saddr = saddr; - DEBUG(2, __FUNCTION__ "(), daddr=%08x\n", self->daddr); + DEBUG(0, __FUNCTION__ "(), daddr=%08x\n", self->daddr); hashbin_insert(irlan, (QUEUE*) self, self->daddr, NULL); /* Check if network device has been registered */ if (!self->netdev_registered) irlan_register_netdev(self); - /* Remember that we might have to start a new provider */ - self->client.start_new_provider = TRUE; - } else { - DEBUG(2, __FUNCTION__ "(), Found none, starting new one!\n"); - /* No instance available, so we have to start one! */ - self = irlan_open(saddr, daddr, TRUE); - if (!self) { - DEBUG(2, __FUNCTION__ "(), irlan_open failed!\n"); - return; - } - ASSERT( self != NULL, return;); + /* Restart watchdog timer */ + irlan_start_watchdog_timer(self, IRLAN_TIMEOUT); } - /* Restart watchdog timer */ - irlan_start_watchdog_timer(self, IRLAN_TIMEOUT); } /* @@ -367,13 +354,12 @@ void irlan_client_reconnect_data_channel(struct irlan_cb *self) } /* - * Function irlan_client_extract_params (skb) + * Function irlan_client_parse_response (self, skb) * * Extract all parameters from received buffer, then feed them to * check_params for parsing - * */ -void irlan_client_extract_params(struct irlan_cb *self, struct sk_buff *skb) +void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb) { __u8 *frame; __u8 *ptr; @@ -392,7 +378,7 @@ void irlan_client_extract_params(struct irlan_cb *self, struct sk_buff *skb) ASSERT(self->magic == IRLAN_MAGIC, return;); if (!skb) { - DEBUG(2, __FUNCTION__ "(), Got NULL skb!\n"); + ERROR( __FUNCTION__ "(), Got NULL skb!\n"); return; } frame = skb->data; @@ -423,7 +409,7 @@ void irlan_client_extract_params(struct irlan_cb *self, struct sk_buff *skb) /* For all parameters */ for (i=0; idev.dev_addr[i] = bytes[i]; - -#ifdef CONFIG_IRLAN_GRATUITOUS_ARP - /* - * When we get a new MAC address do a gratuitous ARP. This - * is useful if we have changed access points on the same - * subnet. - */ - DEBUG(4, "IrLAN: Sending gratuitous ARP\n"); - in_dev = self->dev.ip_ptr; - arp_send(ARPOP_REQUEST, ETH_P_ARP, - in_dev->ifa_list->ifa_address, - &self->dev, - in_dev->ifa_list->ifa_address, - NULL, self->dev.dev_addr, NULL); -#endif } } @@ -574,8 +542,8 @@ static void irlan_check_response_param(struct irlan_cb *self, char *param, * Got results from remote LM-IAS * */ -void irlan_client_get_value_confirm(__u16 obj_id, struct ias_value *value, - void *priv) +void irlan_client_get_value_confirm(int result, __u16 obj_id, + struct ias_value *value, void *priv) { struct irlan_cb *self; @@ -587,7 +555,7 @@ void irlan_client_get_value_confirm(__u16 obj_id, struct ias_value *value, ASSERT(self->magic == IRLAN_MAGIC, return;); /* Check if request succeeded */ - if (!value) { + if (result != IAS_SUCCESS) { DEBUG(2, __FUNCTION__ "(), got NULL value!\n"); irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL, NULL); diff --git a/net/irda/irlan/irlan_client_event.c b/net/irda/irlan/irlan_client_event.c index ec666c3d2c45..1544c093e14d 100644 --- a/net/irda/irlan/irlan_client_event.c +++ b/net/irda/irlan/irlan_client_event.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sun Aug 31 20:14:37 1997 - * Modified at: Thu Feb 4 16:08:07 1999 + * Modified at: Thu Apr 22 12:23:22 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli , @@ -226,7 +226,7 @@ static int irlan_client_state_info(struct irlan_cb *self, IRLAN_EVENT event, case IRLAN_DATA_INDICATION: ASSERT(skb != NULL, return -1;); - irlan_client_extract_params(self, skb); + irlan_client_parse_response(self, skb); irlan_next_client_state(self, IRLAN_MEDIA); @@ -266,7 +266,7 @@ static int irlan_client_state_media(struct irlan_cb *self, IRLAN_EVENT event, switch(event) { case IRLAN_DATA_INDICATION: - irlan_client_extract_params(self, skb); + irlan_client_parse_response(self, skb); irlan_open_data_channel(self); irlan_next_client_state(self, IRLAN_OPEN); break; @@ -305,7 +305,7 @@ static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event, switch(event) { case IRLAN_DATA_INDICATION: - irlan_client_extract_params(self, skb); + irlan_client_parse_response(self, skb); /* * Check if we have got the remote TSAP for data @@ -336,11 +336,6 @@ static int irlan_client_state_open(struct irlan_cb *self, IRLAN_EVENT event, IRLAN_MTU, NULL); irlan_next_client_state(self, IRLAN_DATA); - - if (self->client.start_new_provider) { - irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY, FALSE); - self->client.start_new_provider = FALSE; - } break; default: DEBUG(2, __FUNCTION__ "(), unknown access type!\n"); @@ -468,7 +463,7 @@ static int irlan_client_state_data(struct irlan_cb *self, IRLAN_EVENT event, switch(event) { case IRLAN_DATA_INDICATION: - irlan_client_extract_params(self, skb); + irlan_client_parse_response(self, skb); break; case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */ case IRLAN_LAP_DISCONNECT: diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c index 607c71c39879..00619cf44c99 100644 --- a/net/irda/irlan/irlan_common.c +++ b/net/irda/irlan/irlan_common.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sun Aug 31 20:14:37 1997 - * Modified at: Wed Apr 7 17:03:21 1999 + * Modified at: Thu Apr 22 23:13:47 1999 * Modified by: Dag Brattli * * Copyright (c) 1997 Dag Brattli , All Rights Reserved. @@ -112,9 +112,11 @@ struct proc_dir_entry proc_irlan = { void irlan_watchdog_timer_expired(unsigned long data) { struct irmanager_event mgr_event; - struct irlan_cb *self = (struct irlan_cb *) data; + struct irlan_cb *self, *entry; - DEBUG(2, __FUNCTION__ "()\n"); + DEBUG(0, __FUNCTION__ "()\n"); + + self = (struct irlan_cb *) data; ASSERT(self != NULL, return;); ASSERT(self->magic == IRLAN_MAGIC, return;); @@ -132,147 +134,38 @@ void irlan_watchdog_timer_expired(unsigned long data) * by the user. */ self->notify_irmanager = FALSE; - } else - irlan_close(self); -} - -void irlan_start_watchdog_timer(struct irlan_cb *self, int timeout) -{ - DEBUG(4, __FUNCTION__ "()\n"); - - irda_start_timer(&self->watchdog_timer, timeout, (unsigned long) self, - irlan_watchdog_timer_expired); + } else { + DEBUG(0, __FUNCTION__ "(), recycling instance!\n"); + if (self->netdev_registered) { + DEBUG(0, __FUNCTION__ "(), removing netdev!\n"); + unregister_netdev(&self->dev); + self->netdev_registered = FALSE; + } + + /* Unbind from daddr */ + entry = hashbin_remove(irlan, self->daddr, NULL); + ASSERT(entry == self, return;); + + self->daddr = DEV_ADDR_ANY; + self->saddr = DEV_ADDR_ANY; + + DEBUG(2, __FUNCTION__ "(), daddr=%08x\n", self->daddr); + hashbin_insert(irlan, (QUEUE*) self, self->daddr, NULL); + } } /* - * Function irlan_eth_open (dev) + * Function irlan_start_watchdog_timer (self, timeout) * - * Network device has been opened by user - * - */ -static int irlan_eth_open(struct device *dev) -{ - struct irlan_cb *self; - - DEBUG(4, __FUNCTION__ "()\n"); - - ASSERT(dev != NULL, return -1;); - - self = (struct irlan_cb *) dev->priv; - - ASSERT(self != NULL, return -1;); - - /* Ready to play! */ -/* dev->tbusy = 0; */ /* Wait until data link is ready */ - dev->interrupt = 0; - dev->start = 1; - - self->notify_irmanager = TRUE; - - /* We are now open, so time to do some work */ - irlan_client_wakeup(self, self->saddr, self->daddr); - - MOD_INC_USE_COUNT; - - return 0; -} - -/* - * Function irlan_eth_close (dev) + * * - * Stop the ether network device, his function will usually be called by - * ifconfig down. We should now disconnect the link, We start the - * close timer, so that the instance will be removed if we are unable - * to discover the remote device after the disconnect. */ -static int irlan_eth_close(struct device *dev) +void irlan_start_watchdog_timer(struct irlan_cb *self, int timeout) { - struct irlan_cb *self = (struct irlan_cb *) dev->priv; - DEBUG(4, __FUNCTION__ "()\n"); - /* Stop device */ - dev->tbusy = 1; - dev->start = 0; - - MOD_DEC_USE_COUNT; - - irlan_close_data_channel(self); - - irlan_close_tsaps(self); - - irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL); - irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL); - - irlan_start_watchdog_timer(self, IRLAN_TIMEOUT); - - /* Device closed by user! */ - if (self->notify_irmanager) - self->notify_irmanager = FALSE; - else - self->notify_irmanager = TRUE; - - return 0; -} -/* - * Function irlan_eth_init (dev) - * - * The network device initialization function. - * - */ -int irlan_eth_init(struct device *dev) -{ - struct irmanager_event mgr_event; - struct irlan_cb *self; - - DEBUG(4, __FUNCTION__"()\n"); - - ASSERT(dev != NULL, return -1;); - - self = (struct irlan_cb *) dev->priv; - - dev->open = irlan_eth_open; - dev->stop = irlan_eth_close; - dev->hard_start_xmit = irlan_eth_xmit; - dev->get_stats = irlan_eth_get_stats; - dev->set_multicast_list = irlan_eth_set_multicast_list; - - dev->tbusy = 1; - - ether_setup(dev); - - dev->tx_queue_len = TTP_MAX_QUEUE; - -#if 0 - /* - * OK, since we are emulating an IrLAN sever we will have to give - * ourself an ethernet address! - * FIXME: this must be more dynamically - */ - dev->dev_addr[0] = 0x40; - dev->dev_addr[1] = 0x00; - dev->dev_addr[2] = 0x00; - dev->dev_addr[3] = 0x00; - dev->dev_addr[4] = 0x23; - dev->dev_addr[5] = 0x45; -#endif - /* - * Network device has now been registered, so tell irmanager about - * it, so it can be configured with network parameters - */ - mgr_event.event = EVENT_IRLAN_START; - sprintf(mgr_event.devname, "%s", self->ifname); - irmanager_notify(&mgr_event); - - /* - * We set this so that we only notify once, since if - * configuration of the network device fails, the user - * will have to sort it out first anyway. No need to - * try again. - */ - self->notify_irmanager = FALSE; - - return 0; + irda_start_timer(&self->watchdog_timer, timeout, (unsigned long) self, + irlan_watchdog_timer_expired); } /* @@ -312,8 +205,12 @@ __initfunc(int irlan_init(void)) /* Start the first IrLAN instance */ new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY, FALSE); + irlan_open_data_tsap(new); + irlan_client_open_ctrl_tsap(new); + irlan_provider_open_ctrl_tsap(new); + /* Do some fast discovery! */ - irlmp_discovery_request(8); + irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS); return 0; } @@ -345,7 +242,7 @@ int irlan_register_netdev(struct irlan_cb *self) { int i=0; - DEBUG(4, __FUNCTION__ "()\n"); + DEBUG(0, __FUNCTION__ "()\n"); /* Check if we should call the device eth or irlan */ if (!eth) { @@ -416,10 +313,6 @@ struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr, int netdev) irlan_next_client_state(self, IRLAN_IDLE); irlan_next_provider_state(self, IRLAN_IDLE); - irlan_open_data_tsap(self); - irlan_provider_open_ctrl_tsap(self); - irlan_client_open_ctrl_tsap(self); - /* Register network device now, or wait until some later time? */ if (netdev) irlan_register_netdev(self); @@ -436,7 +329,7 @@ struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr, int netdev) */ static void __irlan_close(struct irlan_cb *self) { - DEBUG(2, __FUNCTION__ "()\n"); + DEBUG(0, __FUNCTION__ "()\n"); ASSERT(self != NULL, return;); ASSERT(self->magic == IRLAN_MAGIC, return;); @@ -447,11 +340,13 @@ static void __irlan_close(struct irlan_cb *self) /* Close all open connections and remove TSAPs */ irlan_close_tsaps(self); - if (self->netdev_registered) + if (self->netdev_registered) { unregister_netdev(&self->dev); + self->netdev_registered = FALSE; + } self->magic = 0; - kfree(self); + kfree(self); } /* @@ -464,7 +359,7 @@ void irlan_close(struct irlan_cb *self) { struct irlan_cb *entry; - DEBUG(2, __FUNCTION__ "()\n"); + DEBUG(0, __FUNCTION__ "()\n"); ASSERT(self != NULL, return;); ASSERT(self->magic == IRLAN_MAGIC, return;); @@ -572,7 +467,7 @@ void irlan_disconnect_indication(void *instance, void *sap, LM_REASON reason, switch(reason) { case LM_USER_REQUEST: /* User request */ - irlan_close(self); + //irlan_close(self); break; case LM_LAP_DISCONNECT: /* Unexpected IrLAP disconnect */ irlan_start_watchdog_timer(self, IRLAN_TIMEOUT); @@ -636,7 +531,7 @@ void irlan_open_data_tsap(struct irlan_cb *self) self->stsap_sel_data = self->tsap_data->stsap_sel; } -static void irlan_close_tsaps(struct irlan_cb *self) +void irlan_close_tsaps(struct irlan_cb *self) { DEBUG(4, __FUNCTION__ "()\n"); @@ -1122,12 +1017,12 @@ static int __irlan_insert_param(struct sk_buff *skb, char *param, int type, } /* - * Function irlan_get_response_param (buf, param, value) + * Function irlan_extract_param (buf, name, value, len) * * Extracts a single parameter name/value pair from buffer and updates * the buffer pointer to point to the next name/value pair. */ -int irlan_get_param(__u8 *buf, char *name, char *value, __u16 *len) +int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len) { __u8 name_len; __u16 val_len; @@ -1276,6 +1171,20 @@ void print_ret_code(__u8 code) } } +void irlan_mod_inc_use_count(void) +{ +#ifdef MODULE + MOD_INC_USE_COUNT; +#endif +} + +void irlan_mod_dec_use_count(void) +{ +#ifdef MODULE + MOD_DEC_USE_COUNT; +#endif +} + #ifdef MODULE MODULE_AUTHOR("Dag Brattli "); diff --git a/net/irda/irlan/irlan_eth.c b/net/irda/irlan/irlan_eth.c index 19aea4d10518..c1965a11714f 100644 --- a/net/irda/irlan/irlan_eth.c +++ b/net/irda/irlan/irlan_eth.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Thu Oct 15 08:37:58 1998 - * Modified at: Mon Mar 22 17:41:59 1999 + * Modified at: Thu Apr 22 14:26:39 1999 * Modified by: Dag Brattli * Sources: skeleton.c by Donald Becker * slip.c by Laurence Culhane, @@ -27,14 +27,149 @@ #include #include +#include #include #include #include #include #include +#include +#include #include +/* + * Function irlan_eth_init (dev) + * + * The network device initialization function. + * + */ +int irlan_eth_init(struct device *dev) +{ + struct irmanager_event mgr_event; + struct irlan_cb *self; + + DEBUG(0, __FUNCTION__"()\n"); + + ASSERT(dev != NULL, return -1;); + + self = (struct irlan_cb *) dev->priv; + + dev->open = irlan_eth_open; + dev->stop = irlan_eth_close; + dev->hard_start_xmit = irlan_eth_xmit; + dev->get_stats = irlan_eth_get_stats; + dev->set_multicast_list = irlan_eth_set_multicast_list; + + dev->tbusy = 1; + + ether_setup(dev); + + dev->tx_queue_len = TTP_MAX_QUEUE; + +#if 0 + /* + * OK, since we are emulating an IrLAN sever we will have to give + * ourself an ethernet address! + * FIXME: this must be more dynamically + */ + dev->dev_addr[0] = 0x40; + dev->dev_addr[1] = 0x00; + dev->dev_addr[2] = 0x00; + dev->dev_addr[3] = 0x00; + dev->dev_addr[4] = 0x23; + dev->dev_addr[5] = 0x45; +#endif + /* + * Network device has now been registered, so tell irmanager about + * it, so it can be configured with network parameters + */ + mgr_event.event = EVENT_IRLAN_START; + sprintf(mgr_event.devname, "%s", self->ifname); + irmanager_notify(&mgr_event); + + /* + * We set this so that we only notify once, since if + * configuration of the network device fails, the user + * will have to sort it out first anyway. No need to + * try again. + */ + self->notify_irmanager = FALSE; + + return 0; +} + +/* + * Function irlan_eth_open (dev) + * + * Network device has been opened by user + * + */ +int irlan_eth_open(struct device *dev) +{ + struct irlan_cb *self; + + DEBUG(0, __FUNCTION__ "()\n"); + + ASSERT(dev != NULL, return -1;); + + self = (struct irlan_cb *) dev->priv; + + ASSERT(self != NULL, return -1;); + + /* Ready to play! */ +/* dev->tbusy = 0; */ /* Wait until data link is ready */ + dev->interrupt = 0; + dev->start = 1; + + self->notify_irmanager = TRUE; + + /* We are now open, so time to do some work */ + irlan_client_wakeup(self, self->saddr, self->daddr); + + irlan_mod_inc_use_count(); + + return 0; +} + +/* + * Function irlan_eth_close (dev) + * + * Stop the ether network device, his function will usually be called by + * ifconfig down. We should now disconnect the link, We start the + * close timer, so that the instance will be removed if we are unable + * to discover the remote device after the disconnect. + */ +int irlan_eth_close(struct device *dev) +{ + struct irlan_cb *self = (struct irlan_cb *) dev->priv; + + DEBUG(0, __FUNCTION__ "()\n"); + + /* Stop device */ + dev->tbusy = 1; + dev->start = 0; + + irlan_mod_dec_use_count(); + + irlan_close_data_channel(self); + + irlan_close_tsaps(self); + + irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL); + irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL); + + irlan_start_watchdog_timer(self, IRLAN_TIMEOUT); + + /* Device closed by user! */ + if (self->notify_irmanager) + self->notify_irmanager = FALSE; + else + self->notify_irmanager = TRUE; + + return 0; +} + /* * Function irlan_eth_tx (skb) * @@ -219,6 +354,30 @@ void irlan_eth_rebuild_header(void *buff, struct device *dev, /* return 0; */ } +/* + * Function irlan_etc_send_gratuitous_arp (dev) + * + * Send gratuitous ARP to announce that we have changed + * hardware address, so that all peers updates their ARP tables + */ +void irlan_etc_send_gratuitous_arp(struct device *dev) +{ + struct in_device *in_dev; + + /* + * When we get a new MAC address do a gratuitous ARP. This + * is useful if we have changed access points on the same + * subnet. + */ + DEBUG(4, "IrLAN: Sending gratuitous ARP\n"); + in_dev = dev->ip_ptr; + arp_send(ARPOP_REQUEST, ETH_P_ARP, + in_dev->ifa_list->ifa_address, + &dev, + in_dev->ifa_list->ifa_address, + NULL, dev->dev_addr, NULL); +} + /* * Function set_multicast_list (dev) * diff --git a/net/irda/irlan/irlan_provider.c b/net/irda/irlan/irlan_provider.c index e60a70439b3a..8e2c3c25ab89 100644 --- a/net/irda/irlan/irlan_provider.c +++ b/net/irda/irlan/irlan_provider.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sun Aug 31 20:14:37 1997 - * Modified at: Tue Apr 6 19:08:20 1999 + * Modified at: Thu Apr 22 14:28:52 1999 * Modified by: Dag Brattli * Sources: skeleton.c by Donald Becker * slip.c by Laurence Culhane, @@ -129,7 +129,7 @@ void irlan_provider_connect_indication(void *instance, void *sap, ASSERT(tsap == self->provider.tsap_ctrl,return;); ASSERT(self->provider.state == IRLAN_IDLE, return;); - /* Check if this provider is unused */ + /* Check if this provider is currently unused */ if (self->daddr == DEV_ADDR_ANY) { /* * Rehash instance, now we have a client (daddr) to serve. @@ -168,14 +168,6 @@ void irlan_provider_connect_indication(void *instance, void *sap, if ((self->access_type == ACCESS_PEER) && (self->client.state == IRLAN_IDLE)) irlan_client_wakeup(self, self->saddr, self->daddr); - - /* - * This provider is now in use, so start a new provider instance to - * serve other clients. This will also change the LM-IAS entry so that - * other clients don't try to connect to us, now that we are busy. - */ - new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY, FALSE); - self->client.start_new_provider = FALSE; } /* @@ -231,20 +223,20 @@ int irlan_parse_open_data_cmd(struct irlan_cb *self, struct sk_buff *skb) { int ret; - ret = irlan_provider_extract_params(self, CMD_OPEN_DATA_CHANNEL, skb); + ret = irlan_provider_parse_command(self, CMD_OPEN_DATA_CHANNEL, skb); return ret; } /* - * Function extract_params (skb) + * Function parse_command (skb) * * Extract all parameters from received buffer, then feed them to * check_params for parsing * */ -int irlan_provider_extract_params(struct irlan_cb *self, int cmd, - struct sk_buff *skb) +int irlan_provider_parse_command(struct irlan_cb *self, int cmd, + struct sk_buff *skb) { __u8 *frame; __u8 *ptr; @@ -285,7 +277,7 @@ int irlan_provider_extract_params(struct irlan_cb *self, int cmd, /* For all parameters */ for (i=0; imagic == IRLAN_MAGIC, return;); + ASSERT(self != NULL, return -1;); + ASSERT(self->magic == IRLAN_MAGIC, return -1;); /* Check if already open */ if (self->provider.tsap_ctrl) - return; + return -1; /* * First register well known control TSAP @@ -421,11 +413,13 @@ void irlan_provider_open_ctrl_tsap(struct irlan_cb *self) tsap = irttp_open_tsap(LSAP_ANY, 1, ¬ify); if (!tsap) { DEBUG(2, __FUNCTION__ "(), Got no tsap!\n"); - return; + return -1; } self->provider.tsap_ctrl = tsap; /* Register with LM-IAS */ - irlan_ias_register(self,tsap->stsap_sel); + irlan_ias_register(self, tsap->stsap_sel); + + return 0; } diff --git a/net/irda/irlan/irlan_provider_event.c b/net/irda/irlan/irlan_provider_event.c index c8dc9b44cccd..6bdf503f1075 100644 --- a/net/irda/irlan/irlan_provider_event.c +++ b/net/irda/irlan/irlan_provider_event.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sun Aug 31 20:14:37 1997 - * Modified at: Wed Feb 3 21:43:06 1999 + * Modified at: Thu Apr 22 10:46:28 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli , All Rights Reserved. @@ -108,8 +108,15 @@ static int irlan_provider_state_info(struct irlan_cb *self, IRLAN_EVENT event, switch(event) { case IRLAN_GET_INFO_CMD: /* Be sure to use 802.3 in case of peer mode */ - if (self->access_type == ACCESS_PEER) + if (self->access_type == ACCESS_PEER) { self->media = MEDIA_802_3; + + /* Check if client has started yet */ + if (self->client.state == IRLAN_IDLE) { + /* This should get the client going */ + irlmp_discovery_request(8); + } + } irlan_provider_send_reply(self, CMD_GET_PROVIDER_INFO, RSP_SUCCESS); @@ -165,7 +172,7 @@ static int irlan_provider_state_open(struct irlan_cb *self, IRLAN_EVENT event, switch(event) { case IRLAN_FILTER_CONFIG_CMD: - irlan_provider_extract_params(self, CMD_FILTER_OPERATION, skb); + irlan_provider_parse_command(self, CMD_FILTER_OPERATION, skb); irlan_provider_send_reply(self, CMD_FILTER_OPERATION, RSP_SUCCESS); /* Keep state */ @@ -207,7 +214,7 @@ static int irlan_provider_state_data(struct irlan_cb *self, IRLAN_EVENT event, switch(event) { case IRLAN_FILTER_CONFIG_CMD: - irlan_provider_extract_params(self, CMD_FILTER_OPERATION, skb); + irlan_provider_parse_command(self, CMD_FILTER_OPERATION, skb); irlan_provider_send_reply(self, CMD_FILTER_OPERATION, RSP_SUCCESS); break; diff --git a/net/irda/irlap.c b/net/irda/irlap.c index ec0610b55635..d24923652a58 100644 --- a/net/irda/irlap.c +++ b/net/irda/irlap.c @@ -6,7 +6,7 @@ * Status: Stable. * Author: Dag Brattli * Created at: Mon Aug 4 20:40:53 1997 - * Modified at: Tue Apr 6 21:07:08 1999 + * Modified at: Fri Apr 23 10:12:29 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli , @@ -44,9 +44,9 @@ #include hashbin_t *irlap = NULL; -int sysctl_slot_timeout = SLOT_TIMEOUT; +int sysctl_slot_timeout = SLOT_TIMEOUT * 1000 / HZ; -static void __irlap_close( struct irlap_cb *self); +static void __irlap_close(struct irlap_cb *self); static char *lap_reasons[] = { "ERROR, NOT USED", @@ -301,27 +301,21 @@ void irlap_connect_confirm(struct irlap_cb *self, struct sk_buff *skb) * IrLMP for further processing * */ -inline void irlap_data_indication( struct irlap_cb *self, struct sk_buff *skb) +inline void irlap_data_indication(struct irlap_cb *self, struct sk_buff *skb) { - DEBUG( 4, __FUNCTION__ "()\n"); - - ASSERT( self != NULL, return;); - ASSERT( self->magic == LAP_MAGIC, return;); - ASSERT( skb != NULL, return;); - /* Hide LAP header from IrLMP layer */ - skb_pull( skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER); + skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER); #ifdef CONFIG_IRDA_COMPRESSION - if ( self->qos_tx.compression.value) { - skb = irlap_decompress_frame( self, skb); - if ( !skb) { - DEBUG( 1, __FUNCTION__ "(), Decompress error!\n"); + if (self->qos_tx.compression.value) { + skb = irlap_decompress_frame(self, skb); + if (!skb) { + DEBUG(1, __FUNCTION__ "(), Decompress error!\n"); return; } } #endif - irlmp_link_data_indication( self->notify.instance, LAP_RELIABLE, skb); + irlmp_link_data_indication(self->notify.instance, LAP_RELIABLE, skb); } /* @@ -515,22 +509,22 @@ void irlap_discovery_request(struct irlap_cb *self, discovery_t *discovery) info.discovery = discovery; /* Check if the slot timeout is within limits */ - if ( sysctl_slot_timeout < 2) { - DEBUG( 1, __FUNCTION__ - "(), to low value for slot timeout!\n"); - sysctl_slot_timeout = 2; + if (sysctl_slot_timeout < 20) { + ERROR(__FUNCTION__ + "(), to low value for slot timeout!\n"); + sysctl_slot_timeout = 20; } /* * Highest value is actually 8, but we allow higher since * some devices seems to require it. */ - if ( sysctl_slot_timeout > 16) { - DEBUG( 1, __FUNCTION__ - "(), to high value for slot timeout!\n"); - sysctl_slot_timeout = 16; + if (sysctl_slot_timeout > 160) { + ERROR(__FUNCTION__ + "(), to high value for slot timeout!\n"); + sysctl_slot_timeout = 160; } - self->slot_timeout = sysctl_slot_timeout; + self->slot_timeout = sysctl_slot_timeout * HZ / 1000; irlap_do_event( self, DISCOVERY_REQUEST, NULL, &info); } else { @@ -807,24 +801,18 @@ void irlap_wait_min_turn_around(struct irlap_cb *self, struct qos_info *qos) { int usecs; int speed; - int bytes = 0; + int bytes ; - ASSERT( self != NULL, return;); - ASSERT( self->magic == LAP_MAGIC, return;); - ASSERT( qos != NULL, return;); - /* Get QoS values. */ speed = qos->baud_rate.value; usecs = qos->min_turn_time.value; /* No need to calculate XBOFs for speeds over 115200 bps */ - if ( speed > 115200) { + if (speed > 115200) { self->mtt_required = usecs; return; } - DEBUG( 4, __FUNCTION__ "(), delay=%d usecs\n", usecs); - /* * Send additional BOF's for the next frame for the requested * min turn time, so now we must calculate how many chars (XBOF's) we @@ -832,8 +820,6 @@ void irlap_wait_min_turn_around(struct irlap_cb *self, struct qos_info *qos) */ bytes = speed * usecs / 10000000; - DEBUG( 4, __FUNCTION__ "(), xbofs delay = %d\n", bytes); - self->xbofs_delay = bytes; } @@ -1028,7 +1014,7 @@ void irlap_apply_default_connection_parameters( struct irlap_cb *self) self->qos_tx.data_size.value = 64; self->qos_tx.additional_bofs.value = 11; - irlap_flush_all_queues( self); + irlap_flush_all_queues(self); self->disconnect_pending = FALSE; } @@ -1079,11 +1065,10 @@ void irlap_apply_connection_parameters(struct irlap_cb *self, /* * Initialize timeout values, some of the rules are listed on - * page 92 in IrLAP. Divide by 10 since the kernel timers has a - * resolution of 10 ms. + * page 92 in IrLAP. */ - self->poll_timeout = qos->max_turn_time.value / 10; - self->final_timeout = qos->max_turn_time.value / 10; + self->poll_timeout = qos->max_turn_time.value * HZ / 1000; + self->final_timeout = qos->max_turn_time.value * HZ / 1000; self->wd_timeout = self->poll_timeout * 2; #ifdef CONFIG_IRDA_COMPRESSION diff --git a/net/irda/irlap_event.c b/net/irda/irlap_event.c index 99dd1783062f..a2fbadf65045 100644 --- a/net/irda/irlap_event.c +++ b/net/irda/irlap_event.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sat Aug 16 00:59:29 1997 - * Modified at: Fri Mar 26 14:24:09 1999 + * Modified at: Fri Apr 23 11:55:12 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli , @@ -40,36 +40,40 @@ #include -static int irlap_state_ndm ( struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_query ( struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_reply ( struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_conn ( struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_setup ( struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_offline( struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_xmit_p ( struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_pclose ( struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_nrm_p ( struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); +#if CONFIG_IRDA_FAST_RR +int sysctl_fast_poll_increase = 50; +#endif + +static int irlap_state_ndm (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_query (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_reply (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_conn (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_setup (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_offline(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_xmit_p (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_pclose (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_nrm_p (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); static int irlap_state_reset_wait(struct irlap_cb *self, IRLAP_EVENT event, struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_reset ( struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_nrm_s ( struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_xmit_s ( struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_sclose ( struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info); -static int irlap_state_reset_check( struct irlap_cb *, IRLAP_EVENT event, - struct sk_buff *, struct irlap_info *); +static int irlap_state_reset (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_nrm_s (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_xmit_s (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_sclose (struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info); +static int irlap_state_reset_check(struct irlap_cb *, IRLAP_EVENT event, + struct sk_buff *, struct irlap_info *); static const char *irlap_event[] = { "DISCOVERY_REQUEST", @@ -145,37 +149,37 @@ static int (*state[])( struct irlap_cb *self, IRLAP_EVENT event, /* * Function irda_poll_timer_expired (data) * - * - * + * Poll timer has expired. Normally we must now send a RR frame to the + * remote device */ -static void irlap_poll_timer_expired( unsigned long data) +static void irlap_poll_timer_expired(unsigned long data) { struct irlap_cb *self = (struct irlap_cb *) data; - ASSERT( self != NULL, return;); - ASSERT( self->magic == LAP_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == LAP_MAGIC, return;); - irlap_do_event( self, POLL_TIMER_EXPIRED, NULL, NULL); + irlap_do_event(self, POLL_TIMER_EXPIRED, NULL, NULL); } -void irlap_start_poll_timer( struct irlap_cb *self, int timeout) +void irlap_start_poll_timer(struct irlap_cb *self, int timeout) { - ASSERT( self != NULL, return;); - ASSERT( self->magic == LAP_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == LAP_MAGIC, return;); #ifdef CONFIG_IRDA_FAST_RR - if ( skb_queue_len( &self->tx_list) == 0) { - if ( self->fast_RR == TRUE) { + if (skb_queue_len(&self->tx_list) == 0) { + if (self->fast_RR == TRUE) { /* * Assert that the fast poll timer has not reached the * normal poll timer yet */ - if ( self->fast_RR_timeout < timeout) { + if (self->fast_RR_timeout < timeout) { /* * FIXME: this should be a more configurable * function */ - self->fast_RR_timeout += 15; + self->fast_RR_timeout += (sysctl_fast_poll_increase * HZ/1000); /* Use this fast(er) timeout instead */ timeout = self->fast_RR_timeout; @@ -183,17 +187,20 @@ void irlap_start_poll_timer( struct irlap_cb *self, int timeout) } else { self->fast_RR = TRUE; - /* Start with just 1 ms */ - self->fast_RR_timeout = 1; - timeout = 1; + /* Start with just 0 ms */ + self->fast_RR_timeout = 0; + timeout = 0; } } else self->fast_RR = FALSE; - DEBUG( 4, __FUNCTION__ "(), Timeout=%d\n", timeout); + DEBUG(4, __FUNCTION__ "(), Timeout=%d\n", timeout); #endif - irda_start_timer( &self->poll_timer, timeout, - (unsigned long) self, irlap_poll_timer_expired); + if (timeout == 0) + irlap_do_event(self, POLL_TIMER_EXPIRED, NULL, NULL); + else + irda_start_timer(&self->poll_timer, timeout, + (unsigned long) self, irlap_poll_timer_expired); } /* @@ -338,25 +345,25 @@ static int irlap_state_ndm( struct irlap_cb *self, IRLAP_EVENT event, case DISCOVERY_REQUEST: ASSERT( info != NULL, return -1;); - if ( irda_device_is_media_busy( self->irdev)) { + if (irda_device_is_media_busy(self->irdev)) { DEBUG(0, __FUNCTION__ "(), media busy!\n"); /* irlap->log.condition = MEDIA_BUSY; */ /* Always switch state before calling upper layers */ - irlap_next_state( self, LAP_NDM); + irlap_next_state(self, LAP_NDM); /* This will make IrLMP try again */ - irlap_discovery_confirm( self, NULL); + irlap_discovery_confirm(self, NULL); return 0; } self->S = info->S; self->s = info->s; - irlap_send_discovery_xid_frame( self, info->S, info->s, TRUE, - info->discovery); + irlap_send_discovery_xid_frame(self, info->S, info->s, TRUE, + info->discovery); self->s++; - irlap_start_slot_timer( self, self->slot_timeout); + irlap_start_slot_timer(self, self->slot_timeout); irlap_next_state(self, LAP_QUERY); break; @@ -440,38 +447,38 @@ static int irlap_state_query( struct irlap_cb *self, IRLAP_EVENT event, irlap_next_state( self, LAP_QUERY); break; case SLOT_TIMER_EXPIRED: - if ( self->s < self->S) { - irlap_send_discovery_xid_frame( self, self->S, - self->s, TRUE, - self->discovery_cmd); + if (self->s < self->S) { + irlap_send_discovery_xid_frame(self, self->S, + self->s, TRUE, + self->discovery_cmd); self->s++; - irlap_start_slot_timer( self, self->slot_timeout); + irlap_start_slot_timer(self, self->slot_timeout); /* Keep state */ - irlap_next_state( self, LAP_QUERY); + irlap_next_state(self, LAP_QUERY); } else { /* This is the final slot! */ - irlap_send_discovery_xid_frame( self, self->S, 0xff, - TRUE, - self->discovery_cmd); + irlap_send_discovery_xid_frame(self, self->S, 0xff, + TRUE, + self->discovery_cmd); /* Always switch state before calling upper layers */ - irlap_next_state( self, LAP_NDM); + irlap_next_state(self, LAP_NDM); /* * We are now finished with the discovery procedure, * so now we must return the results */ - irlap_discovery_confirm( self, self->discovery_log); + irlap_discovery_confirm(self, self->discovery_log); } break; default: DEBUG(2, __FUNCTION__ "(), Unknown event %d, %s\n", event, irlap_event[event]); - if ( skb != NULL) { + if (skb) dev_kfree_skb( skb); - } + ret = -1; break; } @@ -485,37 +492,37 @@ static int irlap_state_query( struct irlap_cb *self, IRLAP_EVENT event, * are waiting for the right time slot to send a response XID frame * */ -static int irlap_state_reply( struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) +static int irlap_state_reply(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info) { discovery_t *discovery_rsp; int ret=0; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - ASSERT( self != NULL, return -1;); - ASSERT( self->magic == LAP_MAGIC, return -1;); + ASSERT(self != NULL, return -1;); + ASSERT(self->magic == LAP_MAGIC, return -1;); - switch( event) { + switch(event) { case QUERY_TIMER_EXPIRED: DEBUG(2, __FUNCTION__ "(), QUERY_TIMER_EXPIRED <%ld>\n", jiffies); - irlap_next_state( self, LAP_NDM); + irlap_next_state(self, LAP_NDM); break; case RECV_DISCOVERY_XID_CMD: - ASSERT( info != NULL, return -1;); + ASSERT(info != NULL, return -1;); /* * Last frame? */ - if ( info->s == 0xff) { - del_timer( &self->query_timer); + if (info->s == 0xff) { + del_timer(&self->query_timer); /* info->log.condition = REMOTE; */ /* Always switch state before calling upper layers */ - irlap_next_state( self, LAP_NDM); + irlap_next_state(self, LAP_NDM); - irlap_discovery_indication( self, info->discovery); + irlap_discovery_indication(self, info->discovery); } else if ((info->s >= self->slot) && (!self->frame_sent)) { discovery_rsp = irlmp_get_discovery_response(); discovery_rsp->daddr = info->daddr; @@ -549,17 +556,17 @@ static int irlap_state_reply( struct irlap_cb *self, IRLAP_EVENT event, * layer to accept or refuse connection * */ -static int irlap_state_conn( struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) +static int irlap_state_conn(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info) { int ret = 0; - DEBUG( 4, __FUNCTION__ "(), event=%s\n", irlap_event[ event]); + DEBUG(4, __FUNCTION__ "(), event=%s\n", irlap_event[ event]); - ASSERT( self != NULL, return -1;); - ASSERT( self->magic == LAP_MAGIC, return -1;); + ASSERT(self != NULL, return -1;); + ASSERT(self->magic == LAP_MAGIC, return -1;); - switch( event) { + switch (event) { case CONNECT_RESPONSE: skb_pull( skb, 11); @@ -762,7 +769,7 @@ static int irlap_state_xmit_p( struct irlap_cb *self, IRLAP_EVENT event, DEBUG( 4, __FUNCTION__ "(), event=%s, vs=%d, vr=%d", irlap_event[ event], self->vs, self->vr); - switch( event) { + switch (event) { case SEND_I_CMD: ASSERT( skb != NULL, return -1;); DEBUG( 4, __FUNCTION__ "(), Window=%d\n", self->window); @@ -822,7 +829,7 @@ static int irlap_state_xmit_p( struct irlap_cb *self, IRLAP_EVENT event, } else { DEBUG( 4, __FUNCTION__ "(), Unable to send! remote busy?\n"); - skb_queue_head( &self->tx_list, skb); + skb_queue_head(&self->tx_list, skb); /* * The next ret is important, because it tells @@ -831,19 +838,19 @@ static int irlap_state_xmit_p( struct irlap_cb *self, IRLAP_EVENT event, ret = -EPROTO; } break; + case POLL_TIMER_EXPIRED: + irlap_send_rr_frame(self, CMD_FRAME); + irlap_start_final_timer(self, self->final_timeout); + irlap_next_state(self, LAP_NRM_P); + break; case DISCONNECT_REQUEST: - del_timer( &self->poll_timer); - irlap_wait_min_turn_around( self, &self->qos_tx); - irlap_send_disc_frame( self); - irlap_flush_all_queues( self); - irlap_start_final_timer( self, self->final_timeout); + del_timer(&self->poll_timer); + irlap_wait_min_turn_around(self, &self->qos_tx); + irlap_send_disc_frame(self); + irlap_flush_all_queues(self); + irlap_start_final_timer(self, self->final_timeout); self->retry_count = 0; - irlap_next_state( self, LAP_PCLOSE); - break; - case POLL_TIMER_EXPIRED: - irlap_send_rr_frame( self, CMD_FRAME); - irlap_start_final_timer( self, self->final_timeout); - irlap_next_state( self, LAP_NRM_P); + irlap_next_state(self, LAP_PCLOSE); break; default: DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", @@ -916,117 +923,18 @@ static int irlap_state_pclose( struct irlap_cb *self, IRLAP_EVENT event, * transmit any frames and is expecting to receive frames only from the * secondary to which transmission permissions has been given. */ -static int irlap_state_nrm_p( struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) +static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info) { int ret = 0; int ns_status; int nr_status; - ASSERT( self != NULL, return -1;); - ASSERT( self->magic == LAP_MAGIC, return -1;); + ASSERT(self != NULL, return -1;); + ASSERT(self->magic == LAP_MAGIC, return -1;); - switch( event) { - case RECV_RR_RSP: - DEBUG( 4, __FUNCTION__ "(), RECV_RR_FRAME: " - "Retrans:%d, nr=%d, va=%d, vs=%d, vr=%d\n", - self->retry_count, info->nr, self->va, self->vs, - self->vr); - - ASSERT( info != NULL, return -1;); - - /* - * If you get a RR, the remote isn't busy anymore, - * no matter what the NR - */ - self->remote_busy = FALSE; - - /* - * Nr as expected? - */ - ret = irlap_validate_nr_received( self, info->nr); - if ( ret == NR_EXPECTED) { - /* Stop final timer */ - del_timer( &self->final_timer); - - /* Update Nr received */ - irlap_update_nr_received( self, info->nr); - - /* - * Got expected NR, so reset the retry_count. This - * is not done by the IrLAP standard , which is - * strange! DB. - */ - self->retry_count = 0; - irlap_wait_min_turn_around( self, &self->qos_tx); - - /* Start poll timer */ - irlap_start_poll_timer( self, self->poll_timeout); - - irlap_next_state( self, LAP_XMIT_P); - } else if ( ret == NR_UNEXPECTED) { - ASSERT( info != NULL, return -1;); - /* - * Unexpected nr! - */ - - /* Update Nr received */ - irlap_update_nr_received( self, info->nr); - - DEBUG( 4, "RECV_RR_FRAME: Retrans:%d, nr=%d, va=%d, " - "vs=%d, vr=%d\n", - self->retry_count, info->nr, self->va, - self->vs, self->vr); - - /* Resend rejected frames */ - irlap_resend_rejected_frames( self, CMD_FRAME); - - /* - * Start only if not running, DB - * TODO: Should this one be here? - */ - /* if ( !self->final_timer.prev) */ -/* irda_start_timer( FINAL_TIMER, self->final_timeout); */ - - /* Keep state */ - irlap_next_state( self, LAP_NRM_P); - } else if ( ret == NR_INVALID) { - DEBUG(1, "irlap_state_nrm_p: received RR with " - "invalid nr !\n"); - del_timer( &self->final_timer); - - irlap_next_state( self, LAP_RESET_WAIT); - - irlap_disconnect_indication( self, - LAP_RESET_INDICATION); - self->xmitflag = TRUE; - } - if (skb) - dev_kfree_skb( skb); - break; - case RECV_RNR_FRAME: - DEBUG( 4, "irlap_state_nrm_p: RECV_RNR_FRAME: Retrans:%d, " - "nr=%d, va=%d, vs=%d, vr=%d\n", - self->retry_count, info->nr, self->va, self->vs, - self->vr); - - ASSERT( info != NULL, return -1;); - - /* Stop final timer */ - del_timer( &self->final_timer); - self->remote_busy = TRUE; - - /* Update Nr received */ - irlap_update_nr_received( self, info->nr); - - /* Start poll timer */ - irlap_start_poll_timer( self, self->poll_timeout); - - irlap_next_state( self, LAP_XMIT_P); - - dev_kfree_skb( skb); - break; - case RECV_I_RSP: + switch (event) { + case RECV_I_RSP: /* Optimize for the common case */ /* FIXME: must check for remote_busy below */ #ifdef CONFIG_IRDA_FAST_RR /* @@ -1039,8 +947,8 @@ static int irlap_state_nrm_p( struct irlap_cb *self, IRLAP_EVENT event, ASSERT( info != NULL, return -1;); - ns_status = irlap_validate_ns_received( self, info->ns); - nr_status = irlap_validate_nr_received( self, info->nr); + ns_status = irlap_validate_ns_received(self, info->ns); + nr_status = irlap_validate_nr_received(self, info->nr); /* * Check for expected I(nformation) frame @@ -1049,7 +957,7 @@ static int irlap_state_nrm_p( struct irlap_cb *self, IRLAP_EVENT event, /* * poll bit cleared? */ - if ( !info->pf) { + if (!info->pf) { self->vr = (self->vr + 1) % 8; /* Update Nr received */ @@ -1058,16 +966,16 @@ static int irlap_state_nrm_p( struct irlap_cb *self, IRLAP_EVENT event, self->ack_required = TRUE; /* Keep state, do not move this line */ - irlap_next_state( self, LAP_NRM_P); + irlap_next_state(self, LAP_NRM_P); - irlap_data_indication( self, skb); + irlap_data_indication(self, skb); } else { - del_timer( &self->final_timer); + del_timer(&self->final_timer); self->vr = (self->vr + 1) % 8; /* Update Nr received */ - irlap_update_nr_received( self, info->nr); + irlap_update_nr_received(self, info->nr); /* * Got expected NR, so reset the @@ -1077,13 +985,17 @@ static int irlap_state_nrm_p( struct irlap_cb *self, IRLAP_EVENT event, self->retry_count = 0; self->ack_required = TRUE; - /* This is the last frame */ - irlap_start_poll_timer( self, self->poll_timeout); - irlap_wait_min_turn_around( self, &self->qos_tx); - /* Do not move this line */ - irlap_next_state( self, LAP_XMIT_P); + irlap_wait_min_turn_around(self, &self->qos_tx); + /* + * Important to switch state before calling + * upper layers + */ + irlap_next_state(self, LAP_XMIT_P); - irlap_data_indication( self, skb); + irlap_data_indication(self, skb); + + /* This is the last frame */ + irlap_start_poll_timer(self, self->poll_timeout); } break; @@ -1091,8 +1003,7 @@ static int irlap_state_nrm_p( struct irlap_cb *self, IRLAP_EVENT event, /* * Unexpected next to send (Ns) */ - if (( ns_status == NS_UNEXPECTED) && - ( nr_status == NR_EXPECTED)) + if ((ns_status == NS_UNEXPECTED) && (nr_status == NR_EXPECTED)) { if ( !info->pf) { irlap_update_nr_received( self, info->nr); @@ -1125,8 +1036,7 @@ static int irlap_state_nrm_p( struct irlap_cb *self, IRLAP_EVENT event, /* * Unexpected next to receive (Nr) */ - if (( ns_status == NS_EXPECTED) && - ( nr_status == NR_UNEXPECTED)) + if ((ns_status == NS_EXPECTED) && (nr_status == NR_UNEXPECTED)) { if ( info->pf) { self->vr = (self->vr + 1) % 8; @@ -1169,8 +1079,8 @@ static int irlap_state_nrm_p( struct irlap_cb *self, IRLAP_EVENT event, * Unexpected next to send (Ns) and next to receive (Nr) * Not documented by IrLAP! */ - if (( ns_status == NS_UNEXPECTED) && - ( nr_status == NR_UNEXPECTED)) + if ((ns_status == NS_UNEXPECTED) && + (nr_status == NR_UNEXPECTED)) { DEBUG( 4, "IrLAP: unexpected nr and ns!\n"); if ( info->pf) { @@ -1194,37 +1104,137 @@ static int irlap_state_nrm_p( struct irlap_cb *self, IRLAP_EVENT event, /* * Invalid NR or NS */ - if (( nr_status == NR_INVALID) || ( ns_status == NS_INVALID)) { - if ( info->pf) { - del_timer( &self->final_timer); + if ((nr_status == NR_INVALID) || (ns_status == NS_INVALID)) { + if (info->pf) { + del_timer(&self->final_timer); - irlap_next_state( self, LAP_RESET_WAIT); + irlap_next_state(self, LAP_RESET_WAIT); - irlap_disconnect_indication( self, LAP_RESET_INDICATION); + irlap_disconnect_indication(self, LAP_RESET_INDICATION); self->xmitflag = TRUE; } else { - del_timer( &self->final_timer); + del_timer(&self->final_timer); - irlap_disconnect_indication( self, LAP_RESET_INDICATION); + irlap_disconnect_indication(self, LAP_RESET_INDICATION); self->xmitflag = FALSE; } break; } DEBUG(1, __FUNCTION__ "(), Not implemented!\n"); - DEBUG(1, __FUNCTION__ "(), event=%s, ns_status=%d, nr_status=%d\n", - irlap_event[ event], ns_status, nr_status); + DEBUG(1, __FUNCTION__ + "(), event=%s, ns_status=%d, nr_status=%d\n", + irlap_event[ event], ns_status, nr_status); break; case RECV_UI_FRAME: /* poll bit cleared? */ - if ( !info->pf) { - irlap_unit_data_indication( self, skb); - irlap_next_state( self, LAP_NRM_P); + if (!info->pf) { + irlap_unit_data_indication(self, skb); + irlap_next_state(self, LAP_NRM_P); } else { + del_timer(&self->final_timer); + irlap_unit_data_indication(self, skb); + irlap_start_poll_timer(self, self->poll_timeout); + } + break; + case RECV_RR_RSP: + DEBUG(4, __FUNCTION__ "(), RECV_RR_FRAME: " + "Retrans:%d, nr=%d, va=%d, vs=%d, vr=%d\n", + self->retry_count, info->nr, self->va, self->vs, + self->vr); + + ASSERT(info != NULL, return -1;); + + /* + * If you get a RR, the remote isn't busy anymore, + * no matter what the NR + */ + self->remote_busy = FALSE; + + /* + * Nr as expected? + */ + ret = irlap_validate_nr_received(self, info->nr); + if (ret == NR_EXPECTED) { + /* Stop final timer */ + del_timer(&self->final_timer); + + /* Update Nr received */ + irlap_update_nr_received(self, info->nr); + + /* + * Got expected NR, so reset the retry_count. This + * is not done by the IrLAP standard , which is + * strange! DB. + */ + self->retry_count = 0; + irlap_wait_min_turn_around(self, &self->qos_tx); + + irlap_next_state(self, LAP_XMIT_P); + + /* Start poll timer */ + irlap_start_poll_timer(self, self->poll_timeout); + } else if (ret == NR_UNEXPECTED) { + ASSERT( info != NULL, return -1;); + /* + * Unexpected nr! + */ + + /* Update Nr received */ + irlap_update_nr_received( self, info->nr); + + DEBUG( 4, "RECV_RR_FRAME: Retrans:%d, nr=%d, va=%d, " + "vs=%d, vr=%d\n", + self->retry_count, info->nr, self->va, + self->vs, self->vr); + + /* Resend rejected frames */ + irlap_resend_rejected_frames( self, CMD_FRAME); + + /* + * Start only if not running, DB + * TODO: Should this one be here? + */ + /* if ( !self->final_timer.prev) */ +/* irda_start_timer( FINAL_TIMER, self->final_timeout); */ + + /* Keep state */ + irlap_next_state( self, LAP_NRM_P); + } else if (ret == NR_INVALID) { + DEBUG(1, "irlap_state_nrm_p: received RR with " + "invalid nr !\n"); del_timer( &self->final_timer); - irlap_unit_data_indication( self, skb); - irlap_start_poll_timer( self, self->poll_timeout); + + irlap_next_state( self, LAP_RESET_WAIT); + + irlap_disconnect_indication( self, + LAP_RESET_INDICATION); + self->xmitflag = TRUE; } + if (skb) + dev_kfree_skb( skb); + break; + case RECV_RNR_FRAME: + DEBUG( 4, "irlap_state_nrm_p: RECV_RNR_FRAME: Retrans:%d, " + "nr=%d, va=%d, vs=%d, vr=%d\n", + self->retry_count, info->nr, self->va, self->vs, + self->vr); + + ASSERT( info != NULL, return -1;); + + /* Stop final timer */ + del_timer( &self->final_timer); + self->remote_busy = TRUE; + + /* Update Nr received */ + irlap_update_nr_received( self, info->nr); + + irlap_next_state( self, LAP_XMIT_P); + + /* Start poll timer */ + irlap_start_poll_timer( self, self->poll_timeout); + + dev_kfree_skb( skb); break; case RECV_FRMR_RSP: del_timer( &self->final_timer); @@ -1322,8 +1332,8 @@ static int irlap_state_nrm_p( struct irlap_cb *self, IRLAP_EVENT event, * awaiting reset of disconnect request. * */ -int irlap_state_reset_wait( struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) +static int irlap_state_reset_wait(struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info) { int ret = 0; @@ -1368,19 +1378,19 @@ int irlap_state_reset_wait( struct irlap_cb *self, IRLAP_EVENT event, * reply. * */ -int irlap_state_reset( struct irlap_cb *self, IRLAP_EVENT event, - struct sk_buff *skb, struct irlap_info *info) +static int irlap_state_reset( struct irlap_cb *self, IRLAP_EVENT event, + struct sk_buff *skb, struct irlap_info *info) { int ret = 0; - DEBUG( 3, __FUNCTION__ "(), event = %s\n", irlap_event[event]); + DEBUG(3, __FUNCTION__ "(), event = %s\n", irlap_event[event]); - ASSERT( self != NULL, return -1;); - ASSERT( self->magic == LAP_MAGIC, return -1;); + ASSERT(self != NULL, return -1;); + ASSERT(self->magic == LAP_MAGIC, return -1;); - switch( event) { + switch(event) { case RECV_DISC_FRAME: - del_timer( &self->final_timer); + del_timer(&self->final_timer); irlap_apply_default_connection_parameters( self); @@ -1398,8 +1408,10 @@ int irlap_state_reset( struct irlap_cb *self, IRLAP_EVENT event, irlap_reset_confirm(); self->remote_busy = FALSE; - irlap_start_poll_timer( self, self->poll_timeout); + irlap_next_state( self, LAP_XMIT_P); + + irlap_start_poll_timer( self, self->poll_timeout); break; case FINAL_TIMER_EXPIRED: if ( self->retry_count < 3) { @@ -1540,53 +1552,8 @@ static int irlap_state_nrm_s( struct irlap_cb *self, IRLAP_EVENT event, ASSERT( self != NULL, return -1;); ASSERT( self->magic == LAP_MAGIC, return -1;); - switch( event) { - case RECV_RR_CMD: - self->retry_count = 0; - - /* - * Nr as expected? - */ - nr_status = irlap_validate_nr_received( self, info->nr); - if ( nr_status == NR_EXPECTED) { - if (( skb_queue_len( &self->tx_list) > 0) && - ( self->window > 0)) { - self->remote_busy = FALSE; - - /* Update Nr received */ - irlap_update_nr_received( self, info->nr); - del_timer( &self->wd_timer); - - irlap_wait_min_turn_around( self, &self->qos_tx); - irlap_next_state( self, LAP_XMIT_S); - } else { - self->remote_busy = FALSE; - /* Update Nr received */ - irlap_update_nr_received( self, info->nr); - irlap_wait_min_turn_around( self, &self->qos_tx); - - irlap_send_rr_frame( self, RSP_FRAME); - - irlap_start_wd_timer( self, self->wd_timeout); - irlap_next_state( self, LAP_NRM_S); - } - } else if ( nr_status == NR_UNEXPECTED) { - self->remote_busy = FALSE; - irlap_update_nr_received( self, info->nr); - irlap_resend_rejected_frames( self, RSP_FRAME); - - irlap_start_wd_timer( self, self->wd_timeout); - - /* Keep state */ - irlap_next_state( self, LAP_NRM_S); - } else { - DEBUG(1, __FUNCTION__ "(), invalid nr not implemented!\n"); - } - if ( skb) - dev_kfree_skb( skb); - - break; - case RECV_I_CMD: + switch(event) { + case RECV_I_CMD: /* Optimize for the common case */ /* FIXME: must check for remote_busy below */ DEBUG( 4, __FUNCTION__ "(), event=%s nr=%d, vs=%d, ns=%d, " "vr=%d, pf=%d\n", irlap_event[event], info->nr, @@ -1764,6 +1731,51 @@ static int irlap_state_nrm_s( struct irlap_cb *self, IRLAP_EVENT event, irlap_next_state( self, LAP_NRM_S); } } + break; + case RECV_RR_CMD: + self->retry_count = 0; + + /* + * Nr as expected? + */ + nr_status = irlap_validate_nr_received( self, info->nr); + if ( nr_status == NR_EXPECTED) { + if (( skb_queue_len( &self->tx_list) > 0) && + ( self->window > 0)) { + self->remote_busy = FALSE; + + /* Update Nr received */ + irlap_update_nr_received( self, info->nr); + del_timer( &self->wd_timer); + + irlap_wait_min_turn_around( self, &self->qos_tx); + irlap_next_state( self, LAP_XMIT_S); + } else { + self->remote_busy = FALSE; + /* Update Nr received */ + irlap_update_nr_received( self, info->nr); + irlap_wait_min_turn_around( self, &self->qos_tx); + + irlap_send_rr_frame( self, RSP_FRAME); + + irlap_start_wd_timer( self, self->wd_timeout); + irlap_next_state( self, LAP_NRM_S); + } + } else if ( nr_status == NR_UNEXPECTED) { + self->remote_busy = FALSE; + irlap_update_nr_received( self, info->nr); + irlap_resend_rejected_frames( self, RSP_FRAME); + + irlap_start_wd_timer( self, self->wd_timeout); + + /* Keep state */ + irlap_next_state( self, LAP_NRM_S); + } else { + DEBUG(1, __FUNCTION__ "(), invalid nr not implemented!\n"); + } + if ( skb) + dev_kfree_skb( skb); + break; case RECV_SNRM_CMD: del_timer( &self->wd_timer); @@ -1897,7 +1909,3 @@ static int irlap_state_reset_check( struct irlap_cb *self, IRLAP_EVENT event, return ret; } - - - - diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c index 1ace3038e856..cda78e7f1d53 100644 --- a/net/irda/irlap_frame.c +++ b/net/irda/irlap_frame.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Tue Aug 19 10:27:26 1997 - * Modified at: Tue Apr 6 16:35:21 1999 + * Modified at: Fri Apr 23 09:30:42 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli , All Rights Resrved. @@ -48,13 +48,10 @@ * need to do this since it's per packet relevant information. * */ -void irlap_insert_mtt( struct irlap_cb *self, struct sk_buff *skb) +static inline void irlap_insert_mtt(struct irlap_cb *self, struct sk_buff *skb) { struct irlap_skb_cb *cb; - ASSERT( self != NULL, return;); - ASSERT( self->magic == LAP_MAGIC, return;); - cb = (struct irlap_skb_cb *) skb->cb; cb->magic = LAP_MAGIC; @@ -71,8 +68,6 @@ void irlap_insert_mtt( struct irlap_cb *self, struct sk_buff *skb) /* Reset XBOF's delay (used only for getting min turn time) */ self->xbofs_delay = 0; - - DEBUG( 4, __FUNCTION__ "(), using %d xbofs\n", cb->xbofs); } /* @@ -83,10 +78,11 @@ void irlap_insert_mtt( struct irlap_cb *self, struct sk_buff *skb) */ void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb) { - /* Some init stuff */ + /* Some common init stuff */ skb->dev = self->netdev; skb->h.raw = skb->nh.raw = skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); + skb->priority = TC_PRIO_BESTEFFORT; /* * Insert MTT (min. turn time) into skb, so that the device driver @@ -534,13 +530,10 @@ static void irlap_recv_discovery_xid_cmd( struct irlap_cb *self, * Build and transmit RR (Receive Ready) frame. Notice that it is currently * only possible to send RR frames with the poll bit set. */ -void irlap_send_rr_frame( struct irlap_cb *self, int command) +void irlap_send_rr_frame(struct irlap_cb *self, int command) { - struct sk_buff *skb = NULL; + struct sk_buff *skb; __u8 *frame; - - ASSERT( self != NULL, return;); - ASSERT( self->magic == LAP_MAGIC, return;); skb = dev_alloc_skb(32); if (!skb) @@ -553,8 +546,6 @@ void irlap_send_rr_frame( struct irlap_cb *self, int command) frame[1] = RR | PF_BIT | (self->vr << 5); - DEBUG(4, __FUNCTION__ "(), vr=%d, %ld\n", self->vr, jiffies); - irlap_queue_xmit(self, skb); } @@ -569,27 +560,7 @@ static inline void irlap_recv_rr_frame(struct irlap_cb *self, struct sk_buff *skb, struct irlap_info *info, int command) { - __u8 *frame; - - frame = skb->data; - info->nr = frame[1] >> 5; - - DEBUG(4, __FUNCTION__ "(), nr=%d, %ld\n", info->nr, jiffies); - - /* - * Make sure the state-machine is in the right state for receiving, - * if not, then we just discard the received frame for now! - * TODO: check if we should queue this frame, or make tty tell that - * it is receiving frames until the frame is delivered instead of - * until it is outside a frame. - */ -#if 0 - if ((self->state != LAP_NRM_P) && (self->state != LAP_NRM_S)) { - DEBUG(0, __FUNCTION__ "(), Wrong state, dropping frame!\n"); - dev_kfree_skb(skb); - return; - } -#endif + info->nr = skb->data[1] >> 5; /* Check if this is a command or a response frame */ if (command) @@ -676,16 +647,7 @@ void irlap_send_data_primary( struct irlap_cb *self, struct sk_buff *skb) { struct sk_buff *tx_skb; - DEBUG( 4, __FUNCTION__ "()\n"); - - ASSERT( self != NULL, return;); - ASSERT( self->magic == LAP_MAGIC, return;); - ASSERT( skb != NULL, return;); - - /* Initialize variables */ - tx_skb = NULL; - - if ( skb->data[1] == I_FRAME) { + if (skb->data[1] == I_FRAME) { /* * Insert frame sequence number (Vs) in control field before @@ -693,10 +655,10 @@ void irlap_send_data_primary( struct irlap_cb *self, struct sk_buff *skb) */ skb->data[1] = I_FRAME | (self->vs << 1); - /* * Copy buffer */ - tx_skb = skb_clone( skb, GFP_ATOMIC); - if ( tx_skb == NULL) { - dev_kfree_skb( skb); + /* Copy buffer */ + tx_skb = skb_clone(skb, GFP_ATOMIC); + if (tx_skb == NULL) { + dev_kfree_skb(skb); return; } @@ -704,12 +666,12 @@ void irlap_send_data_primary( struct irlap_cb *self, struct sk_buff *skb) * make sure the skb->sk accounting of memory usage is sane */ if (skb->sk != NULL) - skb_set_owner_w( tx_skb, skb->sk); + skb_set_owner_w(tx_skb, skb->sk); /* * Insert frame in store, in case of retransmissions */ - skb_queue_tail( &self->wx_list, skb); + skb_queue_tail(&self->wx_list, skb); self->vs = (self->vs + 1) % 8; self->ack_required = FALSE; @@ -718,7 +680,7 @@ void irlap_send_data_primary( struct irlap_cb *self, struct sk_buff *skb) irlap_send_i_frame( self, tx_skb, CMD_FRAME); } else { DEBUG( 4, __FUNCTION__ "(), sending unreliable frame\n"); - irlap_send_ui_frame( self, skb, CMD_FRAME); + irlap_send_ui_frame(self, skb, CMD_FRAME); self->window -= 1; } } @@ -731,17 +693,8 @@ void irlap_send_data_primary_poll( struct irlap_cb *self, struct sk_buff *skb) { struct sk_buff *tx_skb; - DEBUG( 4, __FUNCTION__ "()\n"); - - ASSERT( self != NULL, return;); - ASSERT( self->magic == LAP_MAGIC, return;); - ASSERT( skb != NULL, return;); - - /* Initialize variables */ - tx_skb = NULL; - /* Is this reliable or unreliable data? */ - if ( skb->data[1] == I_FRAME) { + if (skb->data[1] == I_FRAME) { /* * Insert frame sequence number (Vs) in control field before @@ -750,9 +703,9 @@ void irlap_send_data_primary_poll( struct irlap_cb *self, struct sk_buff *skb) skb->data[1] = I_FRAME | (self->vs << 1); /* Copy buffer */ - tx_skb = skb_clone( skb, GFP_ATOMIC); - if ( tx_skb == NULL) { - dev_kfree_skb( skb); + tx_skb = skb_clone(skb, GFP_ATOMIC); + if (tx_skb == NULL) { + dev_kfree_skb(skb); return; } @@ -760,20 +713,20 @@ void irlap_send_data_primary_poll( struct irlap_cb *self, struct sk_buff *skb) * make sure the skb->sk accounting of memory usage is sane */ if (skb->sk != NULL) - skb_set_owner_w( tx_skb, skb->sk); + skb_set_owner_w(tx_skb, skb->sk); /* * Insert frame in store, in case of retransmissions */ - skb_queue_tail( &self->wx_list, skb); + skb_queue_tail(&self->wx_list, skb); /* * Set poll bit if necessary. We do this to the copied * skb, since retransmitted need to set or clear the poll - * bit depending on when * they are sent. + * bit depending on when they are sent. */ /* Stop P timer */ - del_timer( &self->poll_timer); + del_timer(&self->poll_timer); tx_skb->data[1] |= PF_BIT; @@ -781,24 +734,24 @@ void irlap_send_data_primary_poll( struct irlap_cb *self, struct sk_buff *skb) self->ack_required = FALSE; self->window = self->window_size; - irlap_start_final_timer( self, self->final_timeout); + irlap_start_final_timer(self, self->final_timeout); - irlap_send_i_frame( self, tx_skb, CMD_FRAME); + irlap_send_i_frame(self, tx_skb, CMD_FRAME); } else { - DEBUG( 4, __FUNCTION__ "(), sending unreliable frame\n"); + DEBUG(4, __FUNCTION__ "(), sending unreliable frame\n"); - del_timer( &self->poll_timer); + del_timer(&self->poll_timer); - if ( self->ack_required) { - irlap_send_ui_frame( self, skb, CMD_FRAME); - irlap_send_rr_frame( self, CMD_FRAME); + if (self->ack_required) { + irlap_send_ui_frame(self, skb, CMD_FRAME); + irlap_send_rr_frame(self, CMD_FRAME); self->ack_required = FALSE; } else { skb->data[1] |= PF_BIT; - irlap_send_ui_frame( self, skb, CMD_FRAME); + irlap_send_ui_frame(self, skb, CMD_FRAME); } self->window = self->window_size; - irlap_start_final_timer( self, self->final_timeout); + irlap_start_final_timer(self, self->final_timeout); } } @@ -926,7 +879,7 @@ void irlap_resend_rejected_frames( struct irlap_cb *self, int command) ASSERT( self != NULL, return;); ASSERT( self->magic == LAP_MAGIC, return;); - DEBUG( 4, __FUNCTION__ "(), retry_count=%d\n", self->retry_count); + DEBUG(2, __FUNCTION__ "(), retry_count=%d\n", self->retry_count); /* Initialize variables */ skb = tx_skb = NULL; @@ -939,7 +892,11 @@ void irlap_resend_rejected_frames( struct irlap_cb *self, int command) while ( skb != NULL) { irlap_wait_min_turn_around( self, &self->qos_tx); - tx_skb = skb_clone( skb, GFP_ATOMIC); + /* We copy the skb to be retransmitted since we will have to + * modify it. Cloning will confuse packet sniffers + */ + /* tx_skb = skb_clone( skb, GFP_ATOMIC); */ + tx_skb = skb_copy(skb, GFP_ATOMIC); if ( tx_skb == NULL) { /* Unlink tx_skb from list */ tx_skb->next = tx_skb->prev = NULL; @@ -997,12 +954,12 @@ void irlap_resend_rejected_frames( struct irlap_cb *self, int command) * If send window > 1 then send frame with pf * bit cleared */ - if (( self->window > 1) && - skb_queue_len( &self->tx_list) > 0) + if ((self->window > 1) && + skb_queue_len(&self->tx_list) > 0) { - irlap_send_data_primary( self, skb); + irlap_send_data_primary(self, skb); } else { - irlap_send_data_primary_poll( self, skb); + irlap_send_data_primary_poll(self, skb); } } } @@ -1057,6 +1014,15 @@ void irlap_send_i_frame(struct irlap_cb *self, struct sk_buff *skb, /* Insert next to receive (Vr) */ frame[1] |= (self->vr << 5); /* insert nr */ +#if 0 + { + int ns; + ns = (frame[1] >> 1) & 0x07; /* Next to send */ + + DEBUG(0, __FUNCTION__ "(), ns=%d\n", ns); + } +#endif + irlap_queue_xmit(self, skb); } @@ -1070,30 +1036,13 @@ static inline void irlap_recv_i_frame(struct irlap_cb *self, struct sk_buff *skb, struct irlap_info *info, int command) { - __u8 *frame; - - frame = skb->data; - - info->nr = frame[1] >> 5; /* Next to receive */ - info->pf = frame[1] & PF_BIT; /* Final bit */ - info->ns = (frame[1] >> 1) & 0x07; /* Next to send */ + info->nr = skb->data[1] >> 5; /* Next to receive */ + info->pf = skb->data[1] & PF_BIT; /* Final bit */ + info->ns = (skb->data[1] >> 1) & 0x07; /* Next to send */ DEBUG(4, __FUNCTION__"(), ns=%d, nr=%d, pf=%d, %ld\n", info->ns, info->nr, info->pf>>4, jiffies); - /* - * Make sure the state-machine is in the right state for receiving, - * if not, then we just discard the received frame for now! - * TODO: check if we should queue this frame, or make tty tell that - * it is receiving frames until the frame is delivered instead of - * until it is outside a frame. - */ - if ((self->state != LAP_NRM_P) && ( self->state != LAP_NRM_S)) { - DEBUG(0, __FUNCTION__ "(), Wrong state, dropping frame!\n"); - dev_kfree_skb(skb); - return; - } - /* Check if this is a command or a response frame */ if (command) irlap_do_event(self, RECV_I_CMD, skb, info); @@ -1266,7 +1215,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct device *dev, ASSERT( self != NULL, return -1;); ASSERT( self->magic == LAP_MAGIC, return -1;); - ASSERT(( skb != NULL) && (skb->len > 1), return -1;); + ASSERT( skb->len > 1, return -1;); frame = skb->data; diff --git a/net/irda/irlmp.c b/net/irda/irlmp.c index c2f57aea65b7..d76661b6cf1e 100644 --- a/net/irda/irlmp.c +++ b/net/irda/irlmp.c @@ -6,7 +6,7 @@ * Status: Stable. * Author: Dag Brattli * Created at: Sun Aug 17 20:54:32 1997 - * Modified at: Wed Apr 7 17:31:48 1999 + * Modified at: Fri Apr 23 09:13:24 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli , @@ -719,9 +719,12 @@ void irlmp_do_discovery(int nslots) */ void irlmp_discovery_request(int nslots) { - DEBUG(4, __FUNCTION__ "(), nslots=%d\n", nslots); + /* Check if user wants to override the default */ + if (nslots == DISCOVERY_DEFAULT_SLOTS) + nslots = sysctl_discovery_slots; + /* * If discovery is already running, then just return the current * discovery log @@ -877,10 +880,8 @@ discovery_t *irlmp_get_discovery_response() * Send some data to peer device * */ -void irlmp_data_request( struct lsap_cb *self, struct sk_buff *skb) +void irlmp_data_request(struct lsap_cb *self, struct sk_buff *skb) { - DEBUG(4, __FUNCTION__ "()\n"); - ASSERT(skb != NULL, return;); ASSERT(self != NULL, return;); ASSERT(self->magic == LMP_LSAP_MAGIC, return;); @@ -898,14 +899,8 @@ void irlmp_data_request( struct lsap_cb *self, struct sk_buff *skb) * Got data from LAP layer so pass it up to upper layer * */ -void irlmp_data_indication(struct lsap_cb *self, struct sk_buff *skb) +inline void irlmp_data_indication(struct lsap_cb *self, struct sk_buff *skb) { - DEBUG(4, __FUNCTION__ "()\n"); - - ASSERT(self != NULL, return;); - ASSERT(self->magic == LMP_LSAP_MAGIC, return;); - ASSERT(skb != NULL, return;); - /* Hide LMP header from layer above */ skb_pull(skb, LMP_HEADER); diff --git a/net/irda/irlmp_event.c b/net/irda/irlmp_event.c index 3f61d4db0418..20a2dff352c3 100644 --- a/net/irda/irlmp_event.c +++ b/net/irda/irlmp_event.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Mon Aug 4 20:40:53 1997 - * Modified at: Thu Apr 8 16:26:41 1999 + * Modified at: Fri Apr 23 08:57:23 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli , @@ -114,16 +114,16 @@ static void (*lsap_state[])( struct lsap_cb *, IRLMP_EVENT, struct sk_buff *) = }; /* Do connection control events */ -void irlmp_do_lsap_event( struct lsap_cb *self, IRLMP_EVENT event, - struct sk_buff *skb) +void irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event, + struct sk_buff *skb) { - ASSERT( self != NULL, return;); - ASSERT( self->magic == LMP_LSAP_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == LMP_LSAP_MAGIC, return;); - DEBUG( 4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n", - irlmp_event[ event], irlmp_state[ self->lsap_state]); + DEBUG(4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n", + irlmp_event[ event], irlmp_state[ self->lsap_state]); - (*lsap_state[ self->lsap_state]) ( self, event, skb); + (*lsap_state[self->lsap_state]) (self, event, skb); } /* @@ -132,23 +132,21 @@ void irlmp_do_lsap_event( struct lsap_cb *self, IRLMP_EVENT event, * Do IrLAP control events * */ -void irlmp_do_lap_event( struct lap_cb *self, IRLMP_EVENT event, - struct sk_buff *skb) +void irlmp_do_lap_event(struct lap_cb *self, IRLMP_EVENT event, + struct sk_buff *skb) { - ASSERT( self != NULL, return;); - ASSERT( self->magic == LMP_LAP_MAGIC, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == LMP_LAP_MAGIC, return;); - DEBUG( 4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n", - irlmp_event[event], - irlmp_state[self->lap_state]); + DEBUG(4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n", + irlmp_event[event], + irlmp_state[self->lap_state]); - (*lap_state[ self->lap_state]) ( self, event, skb); + (*lap_state[self->lap_state]) (self, event, skb); } void irlmp_discovery_timer_expired( unsigned long data) { -/* struct irlmp_cb *self = ( struct irlmp_cb *) data; */ - DEBUG(4, "IrLMP, discovery timer expired!\n"); if (sysctl_discovery) @@ -306,8 +304,8 @@ static void irlmp_state_u_connect( struct lap_cb *self, IRLMP_EVENT event, * ACTIVE, IrLAP connection is active * */ -static void irlmp_state_active( struct lap_cb *self, IRLMP_EVENT event, - struct sk_buff *skb) +static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event, + struct sk_buff *skb) { struct lsap_cb *lsap; struct lsap_cb *lsap_current; @@ -343,7 +341,7 @@ static void irlmp_state_active( struct lap_cb *self, IRLMP_EVENT event, /* Keep state */ break; case LM_LAP_DISCONNECT_REQUEST: - DEBUG( 4, __FUNCTION__ "(), LM_LAP_DISCONNECT_REQUEST\n"); + DEBUG(4, __FUNCTION__ "(), LM_LAP_DISCONNECT_REQUEST\n"); /* * Need to find out if we should close IrLAP or not. If there @@ -357,7 +355,7 @@ static void irlmp_state_active( struct lap_cb *self, IRLMP_EVENT event, break; case LM_LAP_IDLE_TIMEOUT: if (hashbin_get_size(self->lsaps) == 0) { - DEBUG(0, __FUNCTION__ + DEBUG(2, __FUNCTION__ "(), no more LSAPs so time to close IrLAP\n"); irlmp_next_lap_state(self, LAP_STANDBY); @@ -365,7 +363,7 @@ static void irlmp_state_active( struct lap_cb *self, IRLMP_EVENT event, } break; case LM_LAP_DISCONNECT_INDICATION: - DEBUG( 4, __FUNCTION__ "(), IRLAP_DISCONNECT_INDICATION\n"); + DEBUG(4, __FUNCTION__ "(), IRLAP_DISCONNECT_INDICATION\n"); irlmp_next_lap_state( self, LAP_STANDBY); @@ -525,18 +523,36 @@ static void irlmp_state_connect_pend(struct lsap_cb *self, IRLMP_EVENT event, * DATA_TRANSFER_READY * */ -static void irlmp_state_dtr( struct lsap_cb *self, IRLMP_EVENT event, - struct sk_buff *skb) +static void irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event, + struct sk_buff *skb) { LM_REASON reason; - DEBUG( 4, __FUNCTION__ "()\n"); + DEBUG(4, __FUNCTION__ "()\n"); - ASSERT( self != NULL, return;); - ASSERT( self->magic == LMP_LSAP_MAGIC, return;); - ASSERT( self->lap != NULL, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == LMP_LSAP_MAGIC, return;); + ASSERT(self->lap != NULL, return;); - switch( event) { + switch (event) { + case LM_DATA_REQUEST: /* Optimize for the common case */ + irlmp_send_data_pdu(self->lap, self->dlsap_sel, + self->slsap_sel, FALSE, skb); + /* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/ + break; + case LM_DATA_INDICATION: /* Optimize for the common case */ + irlmp_data_indication(self, skb); + /* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/ + break; + case LM_UDATA_REQUEST: + ASSERT(skb != NULL, return;); + irlmp_send_data_pdu(self->lap, self->dlsap_sel, + self->slsap_sel, TRUE, skb); + break; + case LM_UDATA_INDICATION: + irlmp_udata_indication(self, skb); + /* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/ + break; case LM_CONNECT_REQUEST: DEBUG(0, __FUNCTION__ "(), LM_CONNECT_REQUEST, " "error, LSAP already connected\n"); @@ -548,65 +564,45 @@ static void irlmp_state_dtr( struct lsap_cb *self, IRLMP_EVENT event, /* Keep state */ break; case LM_DISCONNECT_REQUEST: - ASSERT( skb != NULL, return;); + ASSERT(skb != NULL, return;); - irlmp_send_lcf_pdu( self->lap, self->dlsap_sel, - self->slsap_sel, DISCONNECT, skb); - irlmp_next_lsap_state( self, LSAP_DISCONNECTED); + irlmp_send_lcf_pdu(self->lap, self->dlsap_sel, + self->slsap_sel, DISCONNECT, skb); + irlmp_next_lsap_state(self, LSAP_DISCONNECTED); /* Try to close the LAP connection if its still there */ - if ( self->lap) { - DEBUG( 4, __FUNCTION__ "(), trying to close IrLAP\n"); - irlmp_do_lap_event( self->lap, - LM_LAP_DISCONNECT_REQUEST, - NULL); + if (self->lap) { + DEBUG(4, __FUNCTION__ "(), trying to close IrLAP\n"); + irlmp_do_lap_event(self->lap, + LM_LAP_DISCONNECT_REQUEST, + NULL); } - - break; - case LM_DATA_REQUEST: - ASSERT( skb != NULL, return;); - irlmp_send_data_pdu( self->lap, self->dlsap_sel, - self->slsap_sel, FALSE, skb); - /* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/ - break; - case LM_UDATA_REQUEST: - ASSERT( skb != NULL, return;); - irlmp_send_data_pdu( self->lap, self->dlsap_sel, - self->slsap_sel, TRUE, skb); - break; - case LM_DATA_INDICATION: - irlmp_data_indication( self, skb); - /* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/ - break; - case LM_UDATA_INDICATION: - irlmp_udata_indication( self, skb); - /* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/ break; case LM_LAP_DISCONNECT_INDICATION: - irlmp_next_lsap_state( self, LSAP_DISCONNECTED); + irlmp_next_lsap_state(self, LSAP_DISCONNECTED); - reason = irlmp_convert_lap_reason( self->lap->reason); + reason = irlmp_convert_lap_reason(self->lap->reason); - irlmp_disconnect_indication( self, reason, NULL); + irlmp_disconnect_indication(self, reason, NULL); break; case LM_DISCONNECT_INDICATION: - irlmp_next_lsap_state( self, LSAP_DISCONNECTED); + irlmp_next_lsap_state(self, LSAP_DISCONNECTED); - ASSERT( self->lap != NULL, return;); - ASSERT( self->lap->magic == LMP_LAP_MAGIC, return;); + ASSERT(self->lap != NULL, return;); + ASSERT(self->lap->magic == LMP_LAP_MAGIC, return;); ASSERT(skb != NULL, return;); ASSERT(skb->len > 3, return;); reason = skb->data[3]; /* Try to close the LAP connection */ - DEBUG( 4, __FUNCTION__ "(), trying to close IrLAP\n"); + DEBUG(4, __FUNCTION__ "(), trying to close IrLAP\n"); irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL); - irlmp_disconnect_indication( self, reason, skb); + irlmp_disconnect_indication(self, reason, skb); break; default: - DEBUG( 4, __FUNCTION__ "(), Unknown event %d\n", event); + DEBUG(4, __FUNCTION__ "(), Unknown event %d\n", event); break; } } diff --git a/net/irda/irlmp_frame.c b/net/irda/irlmp_frame.c index 14a9141f05f9..bf1bab31ecf7 100644 --- a/net/irda/irlmp_frame.c +++ b/net/irda/irlmp_frame.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Tue Aug 19 02:09:59 1997 - * Modified at: Tue Apr 6 18:31:11 1999 + * Modified at: Fri Apr 23 09:12:23 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli @@ -34,30 +34,24 @@ #include #include -static struct lsap_cb *irlmp_find_lsap( struct lap_cb *self, __u8 dlsap, - __u8 slsap, int status, hashbin_t *); +static struct lsap_cb *irlmp_find_lsap(struct lap_cb *self, __u8 dlsap, + __u8 slsap, int status, hashbin_t *); -inline void irlmp_send_data_pdu( struct lap_cb *self, __u8 dlsap, __u8 slsap, - int expedited, struct sk_buff *skb) +inline void irlmp_send_data_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap, + int expedited, struct sk_buff *skb) { __u8 *frame; - ASSERT( self != NULL, return;); - ASSERT( self->magic == LMP_LAP_MAGIC, return;); - ASSERT( skb != NULL, return;); - frame = skb->data; frame[0] = dlsap; frame[1] = slsap; - if ( expedited) { + if (expedited) { DEBUG( 4, __FUNCTION__ "(), sending expedited data\n"); irlap_data_request( self->irlap, skb, FALSE); - } else { - DEBUG( 4, __FUNCTION__ "(), sending reliable data\n"); - irlap_data_request( self->irlap, skb, TRUE); - } + } else + irlap_data_request( self->irlap, skb, TRUE); } /* @@ -98,18 +92,17 @@ void irlmp_send_lcf_pdu( struct lap_cb *self, __u8 dlsap, __u8 slsap, * Used by IrLAP to pass received data frames to IrLMP layer * */ -void irlmp_link_data_indication( struct lap_cb *self, int reliable, - struct sk_buff *skb) +void irlmp_link_data_indication(struct lap_cb *self, int reliable, + struct sk_buff *skb) { - __u8 *fp; - __u8 slsap_sel; /* Source (this) LSAP address */ - __u8 dlsap_sel; /* Destination LSAP address */ struct lsap_cb *lsap; + __u8 slsap_sel; /* Source (this) LSAP address */ + __u8 dlsap_sel; /* Destination LSAP address */ + __u8 *fp; - ASSERT( self != NULL, return;); - ASSERT( self->magic == LMP_LAP_MAGIC, return;); - ASSERT( skb != NULL, return;); - ASSERT( skb->len > 2, return;); + ASSERT(self != NULL, return;); + ASSERT(self->magic == LMP_LAP_MAGIC, return;); + ASSERT(skb->len > 2, return;); fp = skb->data; @@ -124,7 +117,7 @@ void irlmp_link_data_indication( struct lap_cb *self, int reliable, * Check if this is an incoming connection, since we must deal with * it in a different way than other established connections. */ - if ((fp[0] & CONTROL_BIT) && ( fp[2] == CONNECT_CMD)) { + if ((fp[0] & CONTROL_BIT) && (fp[2] == CONNECT_CMD)) { DEBUG(3,"Incoming connection, source LSAP=%d, dest LSAP=%d\n", slsap_sel, dlsap_sel); @@ -184,10 +177,17 @@ void irlmp_link_data_indication( struct lap_cb *self, int reliable, break; } } else if (reliable == LAP_RELIABLE) { - /* Must be pure data */ - irlmp_do_lsap_event( lsap, LM_DATA_INDICATION, skb); + /* Optimize and bypass the state machine if possible */ + if (lsap->lsap_state == LSAP_DATA_TRANSFER_READY) + irlmp_data_indication(lsap, skb); + else + irlmp_do_lsap_event(lsap, LM_DATA_INDICATION, skb); } else if (reliable == LAP_UNRELIABLE) { - irlmp_do_lsap_event( lsap, LM_UDATA_INDICATION, skb); + /* Optimize and bypass the state machine if possible */ + if (lsap->lsap_state == LSAP_DATA_TRANSFER_READY) + irlmp_data_indication(lsap, skb); + else + irlmp_do_lsap_event(lsap, LM_UDATA_INDICATION, skb); } } @@ -297,8 +297,6 @@ void irlmp_link_discovery_confirm(struct lap_cb *self, hashbin_t *log) irlmp_add_discovery_log(irlmp->cachelog, log); irlmp_do_lap_event(self, LM_LAP_DISCOVERY_CONFIRM, NULL); - - DEBUG( 4, __FUNCTION__ "() -->\n"); } #ifdef CONFIG_IRDA_CACHE_LAST_LSAP @@ -324,36 +322,31 @@ static struct lsap_cb *irlmp_find_lsap(struct lap_cb *self, __u8 dlsap_sel, { struct lsap_cb *lsap; - ASSERT( self != NULL, return NULL;); - ASSERT( self->magic == LMP_LAP_MAGIC, return NULL;); - /* * Optimize for the common case. We assume that the last frame * received is in the same connection as the last one, so check in * cache first to avoid the linear search */ #ifdef CONFIG_IRDA_CACHE_LAST_LSAP - if (( irlmp->cache.valid) && - ( irlmp->cache.slsap_sel == slsap_sel) && - ( irlmp->cache.dlsap_sel == dlsap_sel)) + if ((irlmp->cache.valid) && + (irlmp->cache.slsap_sel == slsap_sel) && + (irlmp->cache.dlsap_sel == dlsap_sel)) { return (irlmp->cache.lsap); } #endif - lsap = ( struct lsap_cb *) hashbin_get_first(queue); - while ( lsap != NULL) { + lsap = (struct lsap_cb *) hashbin_get_first(queue); + while (lsap != NULL) { /* * If this is an incomming connection, then the destination * LSAP selector may have been specified as LM_ANY so that * any client can connect. In that case we only need to check * if the source LSAP (in our view!) match! */ - if (( status == CONNECT_CMD) && - ( lsap->slsap_sel == slsap_sel) && - ( lsap->dlsap_sel == LSAP_ANY)) + if ((status == CONNECT_CMD) && + (lsap->slsap_sel == slsap_sel) && + (lsap->dlsap_sel == LSAP_ANY)) { - DEBUG( 4,"Incoming connection: Setting dlsap_sel=%d\n", - dlsap_sel); lsap->dlsap_sel = dlsap_sel; #ifdef CONFIG_IRDA_CACHE_LAST_LSAP @@ -364,15 +357,15 @@ static struct lsap_cb *irlmp_find_lsap(struct lap_cb *self, __u8 dlsap_sel, /* * Check if source LSAP and dest LSAP selectors match. */ - if (( lsap->slsap_sel == slsap_sel) && - ( lsap->dlsap_sel == dlsap_sel)) + if ((lsap->slsap_sel == slsap_sel) && + (lsap->dlsap_sel == dlsap_sel)) { #ifdef CONFIG_IRDA_CACHE_LAST_LSAP - irlmp_update_cache( lsap); + irlmp_update_cache(lsap); #endif return lsap; } - lsap = ( struct lsap_cb *) hashbin_get_next( queue); + lsap = ( struct lsap_cb *) hashbin_get_next(queue); } /* Sorry not found! */ diff --git a/net/irda/irlpt/irlpt_cli.c b/net/irda/irlpt/irlpt_cli.c index ba8150d06788..6ccd7a3d903a 100644 --- a/net/irda/irlpt/irlpt_cli.c +++ b/net/irda/irlpt/irlpt_cli.c @@ -518,8 +518,8 @@ static int irlpt_client_data_indication(void *instance, void *sap, * Fixed to match changes in iriap.h, DB. * */ -void irlpt_client_get_value_confirm(__u16 obj_id, struct ias_value *value, - void *priv) +void irlpt_client_get_value_confirm(int result, __u16 obj_id, + struct ias_value *value, void *priv) { struct irlpt_info info; struct irlpt_cb *self; @@ -534,7 +534,7 @@ void irlpt_client_get_value_confirm(__u16 obj_id, struct ias_value *value, ASSERT( self->magic == IRLPT_MAGIC, return;); /* Check if request succeeded */ - if ( !value) { + if (result != IAS_SUCCESS) { DEBUG( 0, __FUNCTION__ "(), got NULL value!\n"); irlpt_client_do_event( self, IAS_PROVIDER_NOT_AVAIL, NULL, &info); diff --git a/net/irda/irmod.c b/net/irda/irmod.c index ba49eb3a5310..88d61c2cd62b 100644 --- a/net/irda/irmod.c +++ b/net/irda/irmod.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Mon Dec 15 13:55:39 1997 - * Modified at: Mon Mar 29 09:06:52 1999 + * Modified at: Mon Apr 12 11:31:01 1999 * Modified by: Dag Brattli * * Copyright (c) 1997 Dag Brattli, All Rights Reserved. @@ -50,12 +50,12 @@ extern struct proc_dir_entry proc_irda; struct irda_cb irda; /* One global instance */ #ifdef CONFIG_IRDA_DEBUG -__u32 irda_debug = IRDA_DEBUG; +__u32 irda_debug = IRDA_DEBUG_LEVEL; #endif extern void irda_proc_register(void); extern void irda_proc_unregister(void); -extern int irda_sysctl_register(void); +extern int irda_sysctl_register(void); extern void irda_sysctl_unregister(void); extern void irda_proto_init(struct net_proto *pro); @@ -266,22 +266,6 @@ void irda_cleanup(void) } #endif /* MODULE */ -/* - * Function irda_lock (lock) - * - * Lock variable. Returns false if the lock is already set. - * - */ -inline int irda_lock(int *lock) -{ - if (test_and_set_bit( 0, (void *) lock)) { - DEBUG(3, __FUNCTION__ - "(), Trying to lock, already locked variable!\n"); - return FALSE; - } - return TRUE; -} - /* * Function irda_unlock (lock) * diff --git a/net/irda/irsysctl.c b/net/irda/irsysctl.c index 7565138e9476..0b9a4f1893cf 100644 --- a/net/irda/irsysctl.c +++ b/net/irda/irsysctl.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sun May 24 22:12:06 1998 - * Modified at: Mon Jan 25 13:55:54 1999 + * Modified at: Fri Apr 23 09:46:38 1999 * Modified by: Dag Brattli * * Copyright (c) 1997 Dag Brattli, All Rights Reserved. @@ -36,6 +36,7 @@ enum { DISCOVERY=1, DEVNAME, COMPRESSION, DEBUG, SLOTS, SLOT_TIMEOUT }; extern int sysctl_discovery; extern int sysctl_discovery_slots; extern int sysctl_slot_timeout; +extern int sysctl_fast_poll_increase; int sysctl_compression = 0; extern char sysctl_devname[]; @@ -52,7 +53,11 @@ static ctl_table irda_table[] = { { COMPRESSION, "compression", &sysctl_compression, sizeof(int), 0644, NULL, &proc_dointvec }, #ifdef CONFIG_IRDA_DEBUG - { DEBUG, "debug", &irda_debug, + { DEBUG, "debug", &irda_debug, + sizeof(int), 0644, NULL, &proc_dointvec }, +#endif +#ifdef CONFIG_IRDA_FAST_RR + { SLOTS, "fast_poll_increase", &sysctl_fast_poll_increase, sizeof(int), 0644, NULL, &proc_dointvec }, #endif { SLOTS, "discovery_slots", &sysctl_discovery_slots, diff --git a/net/irda/irttp.c b/net/irda/irttp.c index 77380ca0b78b..bf0624eee0f9 100644 --- a/net/irda/irttp.c +++ b/net/irda/irttp.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Sun Aug 31 20:14:31 1997 - * Modified at: Thu Mar 25 10:27:08 1999 + * Modified at: Sat Apr 10 10:32:21 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli , @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -639,7 +640,6 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel, struct sk_buff *userdata) { struct sk_buff *skb; - __u16 tmp_be; __u8 *frame; __u8 n; @@ -703,8 +703,8 @@ int irttp_connect_request(struct tsap_cb *self, __u8 dtsap_sel, frame[2] = 0x01; /* MaxSduSize */ frame[3] = 0x02; /* Value length */ - tmp_be = cpu_to_be16((__u16) max_sdu_size); - memcpy(frame+4, &tmp_be, 2); + put_unaligned(cpu_to_be16((__u16) max_sdu_size), + (__u16 *)(frame+4)); } else { /* Insert plain TTP header */ frame = skb_push(skb, TTP_HEADER); @@ -728,11 +728,10 @@ void irttp_connect_confirm(void *instance, void *sap, struct qos_info *qos, __u32 max_seg_size, struct sk_buff *skb) { struct tsap_cb *self; - __u16 tmp_cpu; - __u8 *frame; - __u8 n; int parameters; + __u8 *frame; __u8 plen, pi, pl; + __u8 n; DEBUG(4, __FUNCTION__ "()\n"); @@ -770,14 +769,26 @@ void irttp_connect_confirm(void *instance, void *sap, struct qos_info *qos, pi = frame[2]; pl = frame[3]; - ASSERT(pl == 2, return;); - - memcpy(&tmp_cpu, frame+4, 2); /* Align value */ - be16_to_cpus(&tmp_cpu); /* Convert to host order */ - self->tx_max_sdu_size = tmp_cpu; + switch (pl) { + case 1: + self->tx_max_sdu_size = *(frame+4); + break; + case 2: + self->tx_max_sdu_size = + be16_to_cpu(get_unaligned((__u16 *)(frame+4))); + break; + case 4: + self->tx_max_sdu_size = + be32_to_cpu(get_unaligned((__u32 *)(frame+4))); + break; + default: + printk(KERN_ERR __FUNCTION__ + "() illegal value length for max_sdu_size!\n"); + self->tx_max_sdu_size = 0; + }; DEBUG(4, __FUNCTION__ "(), RxMaxSduSize=%d\n", - self->tx_max_sdu_size); + self->tx_max_sdu_size); } DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", @@ -804,11 +815,10 @@ void irttp_connect_indication(void *instance, void *sap, { struct tsap_cb *self; struct lsap_cb *lsap; - __u16 tmp_cpu; - __u8 *frame; int parameters; - int n; + __u8 *frame; __u8 plen, pi, pl; + __u8 n; self = (struct tsap_cb *) instance; @@ -818,9 +828,6 @@ void irttp_connect_indication(void *instance, void *sap, lsap = (struct lsap_cb *) sap; - /* FIXME: just remove this when we know its working */ - ASSERT(max_seg_size == qos->data_size.value, return;); - self->max_seg_size = max_seg_size-LMP_HEADER-LAP_HEADER; DEBUG(4, __FUNCTION__ "(), TSAP sel=%02x\n", self->stsap_sel); @@ -836,18 +843,31 @@ void irttp_connect_indication(void *instance, void *sap, parameters = frame[0] & 0x80; if (parameters) { - DEBUG(4, __FUNCTION__ "(), Contains parameters!\n"); + DEBUG(3, __FUNCTION__ "(), Contains parameters!\n"); plen = frame[1]; pi = frame[2]; pl = frame[3]; - ASSERT(pl == 2, return;); - - memcpy(&tmp_cpu, frame+4, 2); /* Align value */ - be16_to_cpus(&tmp_cpu); /* Convert to host order */ - - self->tx_max_sdu_size = tmp_cpu; - DEBUG(4, __FUNCTION__ "(), MaxSduSize=%d\n", + switch (pl) { + case 1: + self->tx_max_sdu_size = *(frame+4); + break; + case 2: + self->tx_max_sdu_size = + be16_to_cpu(get_unaligned((__u16 *)(frame+4))); + break; + case 4: + self->tx_max_sdu_size = + be32_to_cpu(get_unaligned((__u32 *)(frame+4))); + break; + default: + printk(KERN_ERR __FUNCTION__ + "() illegal value length for max_sdu_size!\n"); + self->tx_max_sdu_size = 0; + }; + + + DEBUG(3, __FUNCTION__ "(), MaxSduSize=%d\n", self->tx_max_sdu_size); } @@ -873,7 +893,6 @@ void irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, struct sk_buff *userdata) { struct sk_buff *skb; - __u32 tmp_be; __u8 *frame; __u8 n; @@ -932,8 +951,8 @@ void irttp_connect_response(struct tsap_cb *self, __u32 max_sdu_size, frame[2] = 0x01; /* MaxSduSize */ frame[3] = 0x02; /* Value length */ - tmp_be = cpu_to_be16((__u16)max_sdu_size); - memcpy(frame+4, &tmp_be, 2); + put_unaligned(cpu_to_be16((__u16) max_sdu_size), + (__u16 *)(frame+4)); } else { /* Insert TTP header */ frame = skb_push(skb, TTP_HEADER); diff --git a/net/irda/qos.c b/net/irda/qos.c index 015d7559f592..7b226dfa6481 100644 --- a/net/irda/qos.c +++ b/net/irda/qos.c @@ -6,7 +6,7 @@ * Status: Experimental. * Author: Dag Brattli * Created at: Tue Sep 9 00:00:26 1997 - * Modified at: Mon Feb 1 09:56:21 1999 + * Modified at: Mon Apr 12 11:49:24 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli , All Rights Reserved. @@ -70,7 +70,7 @@ void irda_qos_compute_intersection( struct qos_info *qos, struct qos_info *new) qos->compression.bits &= new->compression.bits; #endif - irda_qos_bits_to_value( qos); + irda_qos_bits_to_value(qos); } /* diff --git a/net/irda/wrapper.c b/net/irda/wrapper.c index 03abf24ed8f0..c4822e2c6e86 100644 --- a/net/irda/wrapper.c +++ b/net/irda/wrapper.c @@ -1,12 +1,12 @@ /********************************************************************* * * Filename: wrapper.c - * Version: 1.0 + * Version: 1.1 * Description: SIR wrapper layer * Status: Experimental. * Author: Dag Brattli * Created at: Mon Aug 4 20:40:53 1997 - * Modified at: Fri Mar 26 21:52:53 1999 + * Modified at: Wed Apr 21 12:45:55 1999 * Modified by: Dag Brattli * * Copyright (c) 1998 Dag Brattli , @@ -34,9 +34,7 @@ #include #include -#define MIN_LENGTH 14 - -inline static int stuff_byte( __u8 byte, __u8 *buf); +inline static int stuff_byte(__u8 byte, __u8 *buf); /* * Function async_wrap (skb, *tx_buff) @@ -44,17 +42,17 @@ inline static int stuff_byte( __u8 byte, __u8 *buf); * Makes a new buffer with wrapping and stuffing, should check that * we don't get tx buffer overflow. */ -int async_wrap_skb( struct sk_buff *skb, __u8 *tx_buff, int buffsize) +int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize) { - __u8 byte; - int i, n; + int i; + int n; int xbofs; union { __u16 value; __u8 bytes[2]; } fcs; - ASSERT( skb != NULL, return 0;); + ASSERT(skb != NULL, return 0;); /* Initialize variables */ fcs.value = INIT_FCS; @@ -72,33 +70,31 @@ int async_wrap_skb( struct sk_buff *skb, __u8 *tx_buff, int buffsize) */ if (((struct irlap_skb_cb *)(skb->cb))->magic != LAP_MAGIC) { DEBUG(1, __FUNCTION__ "(), wrong magic in skb!\n"); - xbofs = 11; + xbofs = 10; } else xbofs = ((struct irlap_skb_cb *)(skb->cb))->xbofs; - for (i=0; ilen; i++) { - byte = skb->data[i]; - /* * Check for the possibility of tx buffer overflow. We use * bufsize-5 since the maximum number of bytes that can be * transmitted after this point is 5. */ - if ( n > buffsize-5) { - printk( KERN_WARNING - "IrDA Wrapper: TX-buffer overflow!\n"); - return n; - } - n+=stuff_byte( byte, tx_buff+n); - fcs.value = IR_FCS( fcs.value, byte); + ASSERT(n < (buffsize-5), return n;); + + n += stuff_byte(skb->data[i], tx_buff+n); + fcs.value = IR_FCS(fcs.value, skb->data[i]); } /* Insert CRC in little endian format (LSB first) */ @@ -111,7 +107,16 @@ int async_wrap_skb( struct sk_buff *skb, __u8 *tx_buff, int buffsize) n += stuff_byte(fcs.bytes[0], tx_buff+n); #endif tx_buff[n++] = EOF; - + +#if 0 + { + int i; + + for (i=0;istats.rx_dropped++; @@ -132,18 +137,14 @@ static inline void async_bump( struct irda_device *idev, __u8 *buf, int len) } /* Align IP header to 20 bytes */ - skb_reserve( skb, 1); + skb_reserve(skb, 1); - ASSERT( len-2 > 0, return;); - /* Copy data without CRC */ - skb_put( skb, len-2); - memcpy( skb->data, buf, len-2); + memcpy(skb_put(skb, len-2), buf, len-2); /* * Feed it to IrLAP layer */ - /* memcpy(skb_put(skb,count), ax->rbuff, count); */ skb->dev = &idev->netdev; skb->mac.raw = skb->data; skb->protocol = htons(ETH_P_IRDA); @@ -159,18 +160,18 @@ static inline void async_bump( struct irda_device *idev, __u8 *buf, int len) * Parse and de-stuff frame received from the IR-port * */ -void async_unwrap_char( struct irda_device *idev, __u8 byte) +void async_unwrap_char(struct irda_device *idev, __u8 byte) { /* State machine for receiving frames */ - switch( idev->rx_buff.state) { + switch (idev->rx_buff.state) { case OUTSIDE_FRAME: - switch( byte) { + switch(byte) { case BOF: idev->rx_buff.state = BEGIN_FRAME; idev->rx_buff.in_frame = TRUE; break; case XBOF: - idev->xbofs++; + /* idev->xbofs++; */ break; case EOF: irda_device_set_media_busy( idev, TRUE); @@ -180,9 +181,8 @@ void async_unwrap_char( struct irda_device *idev, __u8 byte) } break; case BEGIN_FRAME: - switch ( byte) { + switch (byte) { case BOF: - /* Continue */ break; case CE: @@ -198,28 +198,29 @@ void async_unwrap_char( struct irda_device *idev, __u8 byte) break; default: /* Got first byte of frame */ - idev->rx_buff.data[ idev->rx_buff.len++] = byte; + idev->rx_buff.data = idev->rx_buff.head; + idev->rx_buff.len = 0; + + idev->rx_buff.data[idev->rx_buff.len++] = byte; - idev->rx_buff.fcs = IR_FCS( INIT_FCS, byte); + idev->rx_buff.fcs = IR_FCS(INIT_FCS, byte); idev->rx_buff.state = INSIDE_FRAME; break; } break; case LINK_ESCAPE: - switch ( byte) { + switch (byte) { case BOF: /* New frame? */ idev->rx_buff.state = BEGIN_FRAME; - idev->rx_buff.len = 0; - irda_device_set_media_busy( idev, TRUE); + irda_device_set_media_busy(idev, TRUE); break; case CE: - DEBUG( 4, "WARNING: State not defined\n"); + DEBUG(4, "WARNING: State not defined\n"); break; case EOF: /* Abort frame */ idev->rx_buff.state = OUTSIDE_FRAME; - idev->rx_buff.len = 0; break; default: /* @@ -227,28 +228,25 @@ void async_unwrap_char( struct irda_device *idev, __u8 byte) * following CE, IrLAP p.114 */ byte ^= IR_TRANS; - if ( idev->rx_buff.len < idev->rx_buff.truesize) { - idev->rx_buff.data[ idev->rx_buff.len++] = byte; - + if (idev->rx_buff.len < idev->rx_buff.truesize) { + idev->rx_buff.data[idev->rx_buff.len++] = byte; idev->rx_buff.fcs = IR_FCS(idev->rx_buff.fcs, byte); idev->rx_buff.state = INSIDE_FRAME; } else { - DEBUG( 1, __FUNCTION__ + DEBUG(1, __FUNCTION__ "(), Rx buffer overflow, aborting\n"); idev->rx_buff.state = OUTSIDE_FRAME; - idev->rx_buff.len = 0; } break; } break; case INSIDE_FRAME: - switch ( byte) { + switch (byte) { case BOF: /* New frame? */ idev->rx_buff.state = BEGIN_FRAME; - idev->rx_buff.len = 0; - irda_device_set_media_busy( idev, TRUE); + irda_device_set_media_busy(idev, TRUE); break; case CE: /* Stuffed char */ @@ -262,14 +260,12 @@ void async_unwrap_char( struct irda_device *idev, __u8 byte) /* * Test FCS and deliver frame if it's good */ - if ( idev->rx_buff.fcs == GOOD_FCS) { - async_bump( idev, idev->rx_buff.data, - idev->rx_buff.len); - idev->rx_buff.len = 0; + if (idev->rx_buff.fcs == GOOD_FCS) { + async_bump(idev, idev->rx_buff.data, + idev->rx_buff.len); } else { /* Wrong CRC, discard frame! */ - irda_device_set_media_busy( idev, TRUE); - idev->rx_buff.len = 0; + irda_device_set_media_busy(idev, TRUE); idev->stats.rx_errors++; idev->stats.rx_crc_errors++; @@ -277,16 +273,14 @@ void async_unwrap_char( struct irda_device *idev, __u8 byte) break; default: /* Next byte of frame */ - if ( idev->rx_buff.len < idev->rx_buff.truesize) { - idev->rx_buff.data[ idev->rx_buff.len++] = byte; - - idev->rx_buff.fcs = IR_FCS( idev->rx_buff.fcs, - byte); + if (idev->rx_buff.len < idev->rx_buff.truesize) { + idev->rx_buff.data[idev->rx_buff.len++] = byte; + idev->rx_buff.fcs = IR_FCS(idev->rx_buff.fcs, + byte); } else { - DEBUG( 1, __FUNCTION__ - "(), Rx buffer overflow, aborting\n"); + DEBUG(1, __FUNCTION__ + "(), Rx buffer overflow, aborting\n"); idev->rx_buff.state = OUTSIDE_FRAME; - idev->rx_buff.len = 0; } break; } @@ -301,9 +295,9 @@ void async_unwrap_char( struct irda_device *idev, __u8 byte) * buf. The buffer must at all times be able to have two bytes inserted. * */ -inline static int stuff_byte( __u8 byte, __u8 *buf) +inline static int stuff_byte(__u8 byte, __u8 *buf) { - switch ( byte) { + switch (byte) { case BOF: /* FALLTHROUGH */ case EOF: /* FALLTHROUGH */ case CE: diff --git a/net/netsyms.c b/net/netsyms.c index 9cc89e362d1d..764900d50f74 100644 --- a/net/netsyms.c +++ b/net/netsyms.c @@ -21,6 +21,9 @@ #include #include #include +#ifdef CONFIG_HIPPI +#include +#endif #include #ifdef CONFIG_BRIDGE @@ -45,6 +48,8 @@ #include extern struct net_proto_family inet_family_ops; +extern __u32 sysctl_wmem_max; +extern __u32 sysctl_rmem_max; #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) #include @@ -475,6 +480,15 @@ EXPORT_SYMBOL(kill_fasync); EXPORT_SYMBOL(if_port_text); +#ifdef CONFIG_HIPPI +EXPORT_SYMBOL(hippi_type_trans); +EXPORT_SYMBOL(init_hippi_dev); +EXPORT_SYMBOL(unregister_hipdev); +#endif + +EXPORT_SYMBOL(sysctl_wmem_max); +EXPORT_SYMBOL(sysctl_rmem_max); + #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) #include EXPORT_SYMBOL(ltalk_setup); diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 052ea8eea31c..c8094a882641 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index 74d45fe96880..8baf254ebf8a 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include